From 5d61e24dea8f96dd3a356e1c47be1d2d45b06465 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 20 Feb 2024 09:29:13 +0100 Subject: [PATCH 1/4] fix: actually add `dispose` Symbols to Node globals --- .../src/__tests__/node_environment.test.ts | 22 ---------------- packages/jest-environment-node/src/index.ts | 26 ++++++------------- packages/jest-environment-node/tsconfig.json | 3 ++- 3 files changed, 10 insertions(+), 41 deletions(-) diff --git a/packages/jest-environment-node/src/__tests__/node_environment.test.ts b/packages/jest-environment-node/src/__tests__/node_environment.test.ts index c2a79ca2e79d..bd29974e2b8f 100644 --- a/packages/jest-environment-node/src/__tests__/node_environment.test.ts +++ b/packages/jest-environment-node/src/__tests__/node_environment.test.ts @@ -72,28 +72,6 @@ describe('NodeEnvironment', () => { } }); - it('should configure dispose symbols', () => { - const env = new NodeEnvironment( - { - globalConfig: makeGlobalConfig(), - projectConfig: makeProjectConfig(), - }, - context, - ); - - if ('asyncDispose' in Symbol) { - expect(env.global.Symbol).toHaveProperty('asyncDispose'); - } else { - expect(env.global.Symbol).not.toHaveProperty('asyncDispose'); - } - - if ('dispose' in Symbol) { - expect(env.global.Symbol).toHaveProperty('dispose'); - } else { - expect(env.global.Symbol).not.toHaveProperty('dispose'); - } - }); - it('has modern fake timers implementation', () => { const env = new NodeEnvironment( { diff --git a/packages/jest-environment-node/src/index.ts b/packages/jest-environment-node/src/index.ts index d7ecd4a06b4d..7b4f46f35f14 100644 --- a/packages/jest-environment-node/src/index.ts +++ b/packages/jest-environment-node/src/index.ts @@ -60,22 +60,6 @@ function isString(value: unknown): value is string { return typeof value === 'string'; } -function setDisposeSymbols(context: Context): void { - if ('asyncDispose' in Symbol) { - runInContext( - 'if (!"asyncDispose" in Symbol) { Symbol.asyncDispose = Symbol.for("nodejs.asyncDispose") }', - context, - ); - } - - if ('dispose' in Symbol) { - runInContext( - 'if (!"dispose" in Symbol) { Symbol.dispose = Symbol.for("nodejs.dispose") }', - context, - ); - } -} - const timerIdToRef = (id: number) => ({ id, ref() { @@ -102,8 +86,6 @@ export default class NodeEnvironment implements JestEnvironment { const {projectConfig} = config; this.context = createContext(); - setDisposeSymbols(this.context); - const global = runInContext( 'this', Object.assign(this.context, projectConfig.testEnvironmentOptions), @@ -170,6 +152,14 @@ export default class NodeEnvironment implements JestEnvironment { installCommonGlobals(global, projectConfig.globals); + if ('asyncDispose' in Symbol && !('asyncDispose' in global.Symbol)) { + const globalSymbol = global.Symbol as unknown as SymbolConstructor; + // @ts-expect-error - it's readonly - but we have checked above that it's not there + globalSymbol.asyncDispose = globalSymbol('nodejs.asyncDispose'); + // @ts-expect-error - it's readonly - but we have checked above that it's not there + globalSymbol.dispose = globalSymbol('nodejs.dispose'); + } + // Node's error-message stack size is limited at 10, but it's pretty useful // to see more than that when a test fails. global.Error.stackTraceLimit = 100; diff --git a/packages/jest-environment-node/tsconfig.json b/packages/jest-environment-node/tsconfig.json index 13971fdd663d..02cdc1552739 100644 --- a/packages/jest-environment-node/tsconfig.json +++ b/packages/jest-environment-node/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "build", - "rootDir": "src" + "rootDir": "src", + "lib": ["es2021", "ESNext.Disposable"] }, "include": ["./src/**/*"], "exclude": ["./**/__tests__/**/*"], From 03d0859308edb697c88eb905583154a9ccede52c Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 20 Feb 2024 09:40:38 +0100 Subject: [PATCH 2/4] add test --- .../__snapshots__/globals.test.ts.snap | 13 ++++++++++++ e2e/__tests__/globals.test.ts | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/e2e/__tests__/__snapshots__/globals.test.ts.snap b/e2e/__tests__/__snapshots__/globals.test.ts.snap index d1ed6b3a51db..8b0ee65961a5 100644 --- a/e2e/__tests__/__snapshots__/globals.test.ts.snap +++ b/e2e/__tests__/__snapshots__/globals.test.ts.snap @@ -124,6 +124,19 @@ Time: <> Ran all test suites." `; +exports[`on node ^18.18.0 ||>=20.4.0 Symbol's \`dispose\` are available 1`] = ` +"PASS __tests__/symbolDispose.test.js + ✓ test" +`; + +exports[`on node ^18.18.0 ||>=20.4.0 Symbol's \`dispose\` are available 2`] = ` +"Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites." +`; + exports[`only 1`] = ` "PASS __tests__/onlyConstructs.test.js ✓ test.only diff --git a/e2e/__tests__/globals.test.ts b/e2e/__tests__/globals.test.ts index 5382e1d517ee..f38f1961fd04 100644 --- a/e2e/__tests__/globals.test.ts +++ b/e2e/__tests__/globals.test.ts @@ -7,6 +7,7 @@ import {tmpdir} from 'os'; import * as path from 'path'; +import {onNodeVersions} from '@jest/test-utils'; import { cleanup, createEmptyPackage, @@ -295,3 +296,23 @@ test('function as it() descriptor', () => { expect(summary).toMatchSnapshot(); expect(exitCode).toBe(0); }); + +onNodeVersions('^18.18.0 ||>=20.4.0', () => { + test("Symbol's `dispose` are available", () => { + const filename = 'symbolDispose.test.js'; + const content = ` + it('test', () => { + expect(Symbol.dispose).toBeDefined(); + expect(Symbol.asyncDispose).toBeDefined(); + }); + `; + + writeFiles(TEST_DIR, {[filename]: content}); + const {stderr, exitCode} = runJest(DIR); + + const {summary, rest} = extractSummary(stderr); + expect(rest).toMatchSnapshot(); + expect(summary).toMatchSnapshot(); + expect(exitCode).toBe(0); + }); +}); From 15dfe5c5361e1f4ca1ed7ca5cd2d84e222d1ee99 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 20 Feb 2024 09:41:21 +0100 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 807bd102a36e..e38bae467009 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ - `[@jest/core, @jest/test-sequencer]` [**BREAKING**] Exposes `globalConfig` & `contexts` to `TestSequencer` ([#14535](https://github.com/jestjs/jest/pull/14535), & [#14543](https://github.com/jestjs/jest/pull/14543)) - `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM to v22 ([#13825](https://github.com/jestjs/jest/pull/13825)) - `[@jest/environment-jsdom-abstract]` Introduce new package which abstracts over the `jsdom` environment, allowing usage of custom versions of JSDOM ([#14717](https://github.com/jestjs/jest/pull/14717)) -- `[jest-environment-node]` Update jest environment with dispose symbols `Symbol` ([#14888](https://github.com/jestjs/jest/pull/14888)) +- `[jest-environment-node]` Update jest environment with dispose symbols `Symbol` ([#14888](https://github.com/jestjs/jest/pull/14888) & [#14909](https://github.com/jestjs/jest/pull/14909)) - `[@jest/fake-timers]` [**BREAKING**] Upgrade `@sinonjs/fake-timers` to v11 ([#14544](https://github.com/jestjs/jest/pull/14544)) - `[@jest/fake-timers]` Exposing new modern timers function `advanceTimersToFrame()` which advances all timers by the needed milliseconds to execute callbacks currently scheduled with `requestAnimationFrame` ([#14598](https://github.com/jestjs/jest/pull/14598)) - `[jest-runtime]` Exposing new modern timers function `jest.advanceTimersToFrame()` from `@jest/fake-timers` ([#14598](https://github.com/jestjs/jest/pull/14598)) From 65c296079397578d5bafa8157b97dced304c399a Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 20 Feb 2024 09:42:06 +0100 Subject: [PATCH 4/4] oops --- e2e/__tests__/__snapshots__/globals.test.ts.snap | 4 ++-- e2e/__tests__/globals.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/__tests__/__snapshots__/globals.test.ts.snap b/e2e/__tests__/__snapshots__/globals.test.ts.snap index 8b0ee65961a5..ce1c4359a507 100644 --- a/e2e/__tests__/__snapshots__/globals.test.ts.snap +++ b/e2e/__tests__/__snapshots__/globals.test.ts.snap @@ -124,12 +124,12 @@ Time: <> Ran all test suites." `; -exports[`on node ^18.18.0 ||>=20.4.0 Symbol's \`dispose\` are available 1`] = ` +exports[`on node ^18.18.0 || >=20.4.0 Symbol's \`dispose\` are available 1`] = ` "PASS __tests__/symbolDispose.test.js ✓ test" `; -exports[`on node ^18.18.0 ||>=20.4.0 Symbol's \`dispose\` are available 2`] = ` +exports[`on node ^18.18.0 || >=20.4.0 Symbol's \`dispose\` are available 2`] = ` "Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total diff --git a/e2e/__tests__/globals.test.ts b/e2e/__tests__/globals.test.ts index f38f1961fd04..9bd6950f1ead 100644 --- a/e2e/__tests__/globals.test.ts +++ b/e2e/__tests__/globals.test.ts @@ -297,7 +297,7 @@ test('function as it() descriptor', () => { expect(exitCode).toBe(0); }); -onNodeVersions('^18.18.0 ||>=20.4.0', () => { +onNodeVersions('^18.18.0 || >=20.4.0', () => { test("Symbol's `dispose` are available", () => { const filename = 'symbolDispose.test.js'; const content = `