Closed Bug 1801379 Opened 2 years ago Closed 2 years ago

Migrate Sinon.jsm to an ES module

Categories

(Testing :: General, task)

Default
task

Tracking

(firefox113 fixed)

RESOLVED FIXED
113 Branch
Tracking Status
firefox113 --- fixed

People

(Reporter: standard8, Assigned: canadahonk)

References

(Blocks 1 open bug)

Details

(Whiteboard: [esmification-timeline])

Attachments

(1 file)

As part of the ongoing migration work, we should migrate Sinon.jsm to be a module file, or possibly change sinon.js to be a module.

One difficult part here is dealing with how sinon.js overrides/uses setTimeout and other functions, and how we currently deal with overriding them.

Attempting to do a simple conversion of the jsm file to sys.mjs fails due to:

Unexpected exception ReferenceError: setTimeout is not defined at resource://testing-common/sinon-7.2.7.js:3777

I suspect that's something to do with loadSubScript being called inside a system module, but I'm not sure.

sinon-7.2.7.js expects setTimout being defined as global variable:

https://searchfox.org/mozilla-central/rev/e39e74df85a2dc942e0012c1c99bb9637a787459/testing/modules/sinon-7.2.7.js#3777

setTimeout: setTimeout,

but it's loaded with an object only with global property:

https://searchfox.org/mozilla-central/rev/e39e74df85a2dc942e0012c1c99bb9637a787459/testing/modules/Sinon.jsm#21-22,30-35

const obj = {
  global: {
...
  },
};
Services.scriptloader.loadSubScript(
  "resource://testing-common/sinon-7.2.7.js",
  obj
);

so, the lookup for setTimeout goes to the enclosing scope, and in this case,
the lexical variable in Sinon.jsm is used:

https://searchfox.org/mozilla-central/rev/e39e74df85a2dc942e0012c1c99bb9637a787459/testing/modules/Sinon.jsm#12,17,19

const {
...
  setTimeout,
...
} = ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs");

This is the following case, where WithEnvironmentObject holds the obj, and the NonSyntacticLexicalEnvironmentObject[this=nsvo] holds setTimeout.

https://searchfox.org/mozilla-central/rev/e39e74df85a2dc942e0012c1c99bb9637a787459/js/src/vm/EnvironmentObject.h#247-266

* B.2 Subscript loading (Shared-global JSM)
*
* The target object of a subscript load may be in a JSM with a shared global,
* in which case we will also have the NonSyntacticVariablesObject on the
* chain.
* NonSyntacticLexicalEnvironmentObject for target object holds lexical
* variables and WithEnvironmentObject holds qualified variables.
* Unqualified names goes to NonSyntacticVariablesObject.
*
*   Target object's global
*       |
*   GlobalLexicalEnvironmentObject[this=global]
*       |
*   NonSyntacticVariablesObject (unqualified names)
*       |
*   NonSyntacticLexicalEnvironmentObject[this=nsvo]
*       |
*   WithEnvironmentObject wrapping target (qualified 'var's)
*       |
*   NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars)

NonSyntacticVariablesObject and NonSyntacticLexicalEnvironmentObject[this=nsvo] are created because JSM uses non-syntactic scope.

then, if Sinon.jsm is ESMified, ESM does not use non-syntactic scope, and NonSyntacticLexicalEnvironmentObject[this=nsvo] is not created for global lexical variable, which means setTimeout lookup cannot find setTimeout lexical variable there.
Only global variables defined on the shared global is accessible from the subscript.

https://searchfox.org/mozilla-central/rev/e39e74df85a2dc942e0012c1c99bb9637a787459/js/src/vm/EnvironmentObject.h#231-245

* B.1 Subscript loading
*
* Subscripts may be loaded into a target object and it's associated global.
* NonSyntacticLexicalEnvironmentObject holds lexical variables and
* WithEnvironmentObject holds qualified variables. Unqualified names goes
* to the target object's global.
* They have the following env chain:
*
*   Target object's global (unqualified names)
*       |
*   GlobalLexicalEnvironmentObject[this=global]
*       |
*   WithEnvironmentObject wrapping target (qualified 'var's)
*       |
*   NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars)

Possible workaround is to pass setTimeout and other variables sinon-7.2.7.js expects as obj's property, in the same way as global property there.

const obj = {
  global: {
...
  },
  clearInterval,
  clearTimeout,
  setInterval,
  setIntervalWithTarget,
  setTimeout,
  setTimeoutWithTarget,
  // and maybe some more?
};
Services.scriptloader.loadSubScript(
  "resource://testing-common/sinon-7.2.7.js",
  obj
);

Migrated testing/modules/Sinon.sys.mjs to an ES module.

testing should now be 100% ESM :tada:

Assignee: nobody → oj
Status: NEW → ASSIGNED
Pushed by mbanner@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/429f4ff8576a Migrate Sinon.jsm to an ES module r=extension-reviewers,application-update-reviewers,pip-reviewers,credential-management-reviewers,fxview-reviewers,devtools-reviewers,Standard8,nchevobbe,sclements,dimi,mconley,bytesized,robwu
Regressions: 1825228
Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 113 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: