From 84962fa220f6e2b516136b2153298854663755d6 Mon Sep 17 00:00:00 2001 From: dalvarezmartinez1 Date: Wed, 3 Nov 2021 19:08:01 +0100 Subject: [PATCH] Do not reset global.document before CustomElement:disconnectedCallback has finished running, document should be accessible in this callback function --- CHANGELOG.md | 2 ++ .../src/__tests__/jsdom_environment.test.ts | 24 +++++++++++++++++++ packages/jest-environment-jsdom/src/index.ts | 7 +++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 060fa7e34b7c..147d1ef9c66e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Fixes +- `[jest-environment-jsdom]` Do not reset the global.document too early on teardown ([#11871](https://github.com/facebook/jest/pull/11871)) + ### Chore & Maintenance ### Performance diff --git a/packages/jest-environment-jsdom/src/__tests__/jsdom_environment.test.ts b/packages/jest-environment-jsdom/src/__tests__/jsdom_environment.test.ts index 6253fa99eb77..f10d330a7168 100644 --- a/packages/jest-environment-jsdom/src/__tests__/jsdom_environment.test.ts +++ b/packages/jest-environment-jsdom/src/__tests__/jsdom_environment.test.ts @@ -39,4 +39,28 @@ describe('JSDomEnvironment', () => { expect(env.dom.window.navigator.userAgent).toEqual('foo'); }); + + /** + * When used in conjunction with Custom Elements (part of the WebComponents standard) + * setting the global.document to null too early is problematic because: + * + * CustomElement's disconnectedCallback method is called when a custom element + * is removed from the DOM. The disconnectedCallback could need the document + * in order to remove some listener for example. + * + * global.close calls jsdom's Window.js.close which does this._document.body.innerHTML = "". + * The custom element will be removed from the DOM at this point, therefore disconnectedCallback + * will be called, so please make sure the global.document is still available at this point. + */ + it('should not set the global.document to null too early', () => { + const env = new JSDomEnvironment(makeProjectConfig()); + + const originalCloseFn = env.global.close.bind(env.global); + env.global.close = () => { + originalCloseFn(); + expect(env.global.document).not.toBeNull(); + }; + + return env.teardown(); + }); }); diff --git a/packages/jest-environment-jsdom/src/index.ts b/packages/jest-environment-jsdom/src/index.ts index 39b63efc4607..c358255b4e4f 100644 --- a/packages/jest-environment-jsdom/src/index.ts +++ b/packages/jest-environment-jsdom/src/index.ts @@ -125,9 +125,14 @@ class JSDOMEnvironment implements JestEnvironment { if (this.errorEventListener) { this.global.removeEventListener('error', this.errorEventListener); } + this.global.close(); + // Dispose "document" to prevent "load" event from triggering. + + // Note that this.global.close() will trigger the CustomElement::disconnectedCallback + // Do not reset the document before CustomElement disconnectedCallback function has finished running, + // document should be accessible within disconnectedCallback. Object.defineProperty(this.global, 'document', {value: null}); - this.global.close(); } this.errorEventListener = null; // @ts-expect-error