40

I am writing a (client-side) JavaScript library (a node/angular module). In this library, I make use of the URLSearchParams class.

const form = new URLSearchParams();
form.set('username', data.username);
form.set('password', data.pass);

As this is a shared library, it is packed as an npm module. However, when running a mocha unit test, I get the error that URLSearchParams is not defined. The reason seems to be that node does not have URLSearchParams at the global scope, but has to be imported using require('url'):

$ node
> new URLSearchParams()
ReferenceError: URLSearchParams is not defined
    at repl:1:5
    at sigintHandlersWrap (vm.js:22:35)
    at sigintHandlersWrap (vm.js:73:12)
    at ContextifyScript.Script.runInThisContext (vm.js:21:12)
    at REPLServer.defaultEval (repl.js:340:29)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:538:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)

How can I make URLSearchParams available to the client-side code within node, so that I can test the library using mocha?

This is not working:

> global.URLSearchParams = require('url').URLSearchParams
undefined
> new URLSearchParams()
TypeError: URLSearchParams is not a constructor
    at repl:1:1
    at sigintHandlersWrap (vm.js:22:35)
    at sigintHandlersWrap (vm.js:73:12)
    at ContextifyScript.Script.runInThisContext (vm.js:21:12)
    at REPLServer.defaultEval (repl.js:340:29)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:538:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
Martin Nyolt
  • 4,463
  • 3
  • 28
  • 36

4 Answers4

46

Update: Node v10 has built-in availability of URLSearchParams on the global object so it can be used directly as anticipated in the question.

Older versions of Node:

One option is to set it as a global in the start-up script of the test runner:

import { URLSearchParams } from 'url';
global.URLSearchParams = URLSearchParams

With Jest, for example, you would use the setupTestFrameworkScriptFile to point to the above start-up script.

As a side note, if you wanted to achieve a similar outcome when creating a server-side Webpack bundle of universal code you can achieve this with the Webpack ProvidePlugin:

{
  name: 'server',
  target: 'node',
  // ...
  plugins: [
    // ...
    new webpack.ProvidePlugin({
      URLSearchParams: ['url', 'URLSearchParams'],
      fetch: 'node-fetch',
    }),
  ],
}
marnusw
  • 855
  • 1
  • 9
  • 18
  • 8
    Node v10 has built-in availability of `URLSearchParams` on the `global` object so it can be used without the setups above. – marnusw Jun 14 '18 at 13:04
  • I have not tested this solution, but thanks for pointing out that Node v10 has this now built in. This solves the question. If you update your answer, I can accept it. – Martin Nyolt Jan 25 '19 at 07:12
  • @MartinNyolt I have updated the answer. If that is what you were after I would appreciate you accepting it. – marnusw Feb 05 '19 at 16:41
10

In AWS Lambda which uses Node8.10, I had to do:

const {URLSearchParams} = require('url')
const sp = new URLSearchParams(request.querystring)

or

const url = require('url')
const sp = new url.URLSearchParams(request.querystring)
Bruno Bronosky
  • 66,273
  • 12
  • 162
  • 149
1

If we want to support big range of nodejs versions in our application , we could use some dirty code like this :

if(typeof URLSearchParams === 'undefined'){
    URLSearchParams = require('url').URLSearchParams;
}

Note: It is not best practice to require with a condition.

SayJeyHi
  • 1,559
  • 4
  • 19
  • 39
1

You may use polifill @ungap/url-search-params https://www.npmjs.com/package/@ungap/url-search-params and for webpack may use @ungap/url-search-params/cjs

Old NodeJS 8 (which isused in AWS and GCloud) does not support URLSearchParams so this polifill helps.

In Node 10 when using TypeScript you may enable library dom which includes URLSearchParams implementation. Change tsconfig.json:

{
  "compilerOptions": {
    "lib": [
      ...
      "dom"
      ...
    ]
  }
}
Viacheslav Dobromyslov
  • 3,168
  • 1
  • 33
  • 45