Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support develoment environment using Node.js 20 #2917

Closed
yan12125 opened this issue Oct 17, 2023 · 3 comments · Fixed by #3014
Closed

Support develoment environment using Node.js 20 #2917

yan12125 opened this issue Oct 17, 2023 · 3 comments · Fixed by #3014

Comments

@yan12125
Copy link
Contributor

Is this a feature request or a bug?

A feature request

What is the current behavior?

Similar to #2564, I was testing if web-ext works with the latest Node.js or not, and noticed many tests failed

test failures
  1) webExt
       exposes commands
         lazily loads cmd/run:
     TypeError: The "path" argument must be of type string. Received undefined
      at new NodeError (node:internal/errors:406:5)
      at validateString (node:internal/validators:162:11)
      at Object.join (node:path:1175:7)
      at getValidatedManifest (file:///home/yen/tmp/web-ext/src/util/manifest.js:579:55)
      at run (file:///home/yen/tmp/web-ext/src/cmd/run.js:1594:56)
      at run (file:///home/yen/tmp/web-ext/src/cmd/index.js:297:10)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test.web-ext.js:38:24)

  2) webExt
       exposes commands
         lazily loads cmd/lint:
     TypeError: The "paths[0]" argument must be of type string. Received undefined
      at new NodeError (node:internal/errors:406:5)
      at validateString (node:internal/validators:162:11)
      at Object.resolve (node:path:1101:7)
      at new FileFilter (file:///home/yen/tmp/web-ext/src/util/file-filter.js:925:22)
      at createFileFilter (file:///home/yen/tmp/web-ext/src/util/file-filter.js:1021:10)
      at lint (file:///home/yen/tmp/web-ext/src/cmd/lint.js:405:48)
      at lint (file:///home/yen/tmp/web-ext/src/cmd/index.js:289:10)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test.web-ext.js:38:24)

  3) webExt
       exposes commands
         lazily loads cmd/build:
     TypeError: The "paths[0]" argument must be of type string. Received undefined
      at new NodeError (node:internal/errors:406:5)
      at validateString (node:internal/validators:162:11)
      at Object.resolve (node:path:1101:7)
      at new FileFilter (file:///home/yen/tmp/web-ext/src/util/file-filter.js:925:22)
      at createFileFilter (file:///home/yen/tmp/web-ext/src/util/file-filter.js:1021:10)
      at build (file:///home/yen/tmp/web-ext/src/cmd/build.js:2401:45)
      at build (file:///home/yen/tmp/web-ext/src/cmd/index.js:281:10)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test.web-ext.js:38:24)

  4) webExt
       exposes commands
         lazily loads cmd/sign:
     TypeError: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
      at Object.stat (node:fs:1581:10)
      at Object.<anonymous> (node_modules/graceful-fs/polyfills.js:309:16)
      at /home/yen/tmp/web-ext/node_modules/thenify/index.js:72:10
      at new Promise (<anonymous>)
      at Object.stat (node_modules/thenify/index.js:70:12)
      at prepareArtifactsDir (file:///home/yen/tmp/web-ext/src/util/artifacts.js:562:54)
      at file:///home/yen/tmp/web-ext/src/cmd/sign.js:1890:11
      at file:///home/yen/tmp/web-ext/src/util/temp-dir.js:884:12
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test.web-ext.js:38:24)

  5) webExt
       exposes commands
         lazily loads cmd/docs:
     AssertError: expected default to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test.web-ext.js:41:22)

  6) run
       passes a custom Firefox binary when specified:
     AssertError: expected FirefoxDesktopExtensionRunner to be called with match
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledWithMatch] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:98:18)

  7) run
       passes startUrl parameter to Firefox when specified:
     AssertError: expected FirefoxDesktopExtensionRunner to be called with match
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledWithMatch] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:108:18)

  8) run
       passes the expected parameters to the extension runner:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:126:18)

  9) run
       passes the expected dependencies to the extension runner:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:157:18)

  10) run
       creates a Firefox Desktop runner if targets is an empty array:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:249:18)

  11) run
       creates a Firefox Desktop runner if "firefox-desktop" is in target:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:257:18)

  12) run
       creates a Firefox Android runner if "firefox-android" is in target:
     AssertError: expected FirefoxAndroidExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:265:18)

  13) run
       creates a Chromium runner if "chromium" is in target:
     AssertError: expected ChromiumExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:275:18)

  14) run
       provides a chromiumBinary option to the Chromium runner:
     AssertError: expected ChromiumExtensionRunner to be called with match
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledWithMatch] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:286:18)

  15) run
       provides a chromiumProfile option to the Chromium runner:
     AssertError: expected ChromiumExtensionRunner to be called with match
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledWithMatch] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:301:18)

  16) run
       creates multiple extension runners:
     AssertError: expected FirefoxAndroidExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:314:18)

  17) run
       provides a buildSourceDir method to the Firefox Android runner:
     AssertError: expected FirefoxAndroidExtensionRunner to be called with match
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledWithMatch] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:322:18)

  18) run
       profile-create-new option
         creates dir when firefox profile does not exist:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at testCreateProfileIfMissing (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:359:22)

  19) run
       profile-create-new option
         creates dir when chromium profile does not exist:
     AssertError: expected ChromiumExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at testCreateProfileIfMissing (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:353:22)

  20) run
       profile-create-new option
         uses the given firefox profile directory if it does exist:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at testCreateProfileIfMissing (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:359:22)

  21) run
       profile-create-new option
         uses the given chromium profile directory if it does exist:
     AssertError: expected ChromiumExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at testCreateProfileIfMissing (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:353:22)

  22) run
       firefox-preview
         supports the MV3 preview:
     AssertError: expected FirefoxDesktopExtensionRunner to be called once but was called 0 times
      at Object.fail (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:79:27)
      at failAssertion (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:222:20)
      at Object.assert.<computed> [as calledOnce] (file:///home/yen/tmp/web-ext/node_modules/sinon/pkg/sinon-esm.js:251:17)
      at Context.<anonymous> (file:///home/yen/tmp/web-ext/tests/unit/test-cmd/test.run.js:398:20)

  23) util.submit-addon
       Client
         postNewAddon and putVersion
           creates new add-on; downloads the signed xpi:
     TypeError: Cannot read properties of undefined (reading 'status')
      at Client.fetchJson (file:///home/yen/tmp/web-ext/src/util/submit-addon.js:4572:47)
      at Timeout.pollStatus (file:///home/yen/tmp/web-ext/src/util/submit-addon.js:4408:58)

  24) util.submit-addon
       Client
         postNewAddon and putVersion
           creates a new version; then downloads the signed xpi:
     TypeError: Cannot read properties of undefined (reading 'status')
      at Client.fetchJson (file:///home/yen/tmp/web-ext/src/util/submit-addon.js:4572:47)
      at Timeout.pollStatus (file:///home/yen/tmp/web-ext/src/util/submit-addon.js:4408:58)

What is the expected or desired behavior?

web-ext works fine on Node.js 20.x and all tests pass.

Version information (for bug reports)

  • Firefox version: irrelevant, installation issue
  • Your OS and version: Arch Linux latest
  • Paste the output of these commands:
node --version && npm --version && web-ext --version
v20.8.0
10.2.0
7.8.0

Logs are from git-master (08c5cd9). The issue also occurs for 7.8.0.

@yan12125
Copy link
Contributor Author

yan12125 commented Oct 17, 2023

For failures for util.submit-addon, this change works for me:

diff --git tests/unit/test-util/test.submit-addon.js tests/unit/test-util/test.submit-addon.js
index 7085072..faa327f 100644
--- tests/unit/test-util/test.submit-addon.js
+++ tests/unit/test-util/test.submit-addon.js
@@ -29,7 +29,7 @@ class JSONResponse extends Response {
 
 const mockNodeFetch = (nodeFetchStub, url, method, responses) => {
   const stubMatcher = nodeFetchStub.withArgs(
-    url instanceof URL ? url : new URL(url),
+    sinon.match((value) => (value instanceof URL && value.href === (url instanceof URL ? url.href : url))),
     sinon.match.has('method', method),
   );
   for (let i = 0; i < responses.length; i++) {

It seems matching URLs in sinon stubs is tricky with Node.js 20. There are some other reports about URLs (sinonjs/sinon#2527, nodejs/node#48886), and a Node.js developer suggested comparing the href attribute.

Here is a test script using sinon stubs with URLs. The result becomes unexpected with Node.js 20.

$ cat t.js
import * as sinon from 'sinon';

(async () => {
  let func = sinon.stub();

  func.withArgs(new URL("https://example.com/123")).returns("123");
  func.withArgs(new URL("https://example.com/456")).returns("456");

  console.log(func(new URL("https://example.com/123")));
})();

$ node t.js
456

@Rob--W
Copy link
Member

Rob--W commented Nov 13, 2023

The URL issue in Node.js was allegedly resolved in 18.18: nodejs/node#48886 (comment)

The associated PR (nodejs/node#48897) claims that the bug was backported to 18.18.0 and 20.6.0. The landed commit is also on the v21.0.0 branch. So I think that the test should pass without issues. I'll create a PR with a version bump to get a test run.

@yan12125
Copy link
Contributor Author

Thank you for the update. I guess test failures related to util.submit-addon are caused by an issue different from nodejs/node#48886. I mentioned it because my "fix" was imspired by a comment there. Sorry if that's confusing.

Also, after fixing test failures around URLs, there are many other failures on newer Node.js.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants