Skip to content

Commit

Permalink
jest-environment-jsdom: stop setting document to null on teardown (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnajdr committed Mar 1, 2023
1 parent 7cf5006 commit e7eb64c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -18,6 +18,7 @@
- `[jest-circus]` Send test case results for `todo` tests ([#13915](https://github.com/facebook/jest/pull/13915))
- `[jest-circus]` Update message printed on test timeout ([#13830](https://github.com/facebook/jest/pull/13830))
- `[jest-circus]` Avoid creating the word "testfalse" when `takesDoneCallback` is `false` in the message printed on test timeout AND updated timeouts test ([#13954](https://github.com/facebook/jest/pull/13954))
- `[jest-environment-jsdom]` Stop setting `document` to `null` on teardown ([#13972](https://github.com/facebook/jest/pull/13972))
- `[@jest/test-result]` Allow `TestResultsProcessor` type to return a Promise ([#13950](https://github.com/facebook/jest/pull/13950))

### Chore & Maintenance
Expand Down
Expand Up @@ -84,7 +84,7 @@ describe('JSDomEnvironment', () => {

/**
* When used in conjunction with Custom Elements (part of the WebComponents standard)
* setting the global.document to null too early is problematic because:
* setting the `global` and `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
Expand All @@ -94,7 +94,7 @@ describe('JSDomEnvironment', () => {
* 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', () => {
it('should call CE disconnectedCallback with valid globals on teardown', () => {
const env = new JSDomEnvironment(
{
globalConfig: makeGlobalConfig(),
Expand All @@ -103,12 +103,46 @@ describe('JSDomEnvironment', () => {
{console, docblockPragmas: {}, testPath: __filename},
);

const originalCloseFn = env.global.close.bind(env.global);
env.global.close = () => {
originalCloseFn();
expect(env.global.document).not.toBeNull();
};
let hasDisconnected = false;
let documentWhenDisconnected = null;

return env.teardown();
// define a custom element
const {HTMLElement} = env.global;
class MyCustomElement extends HTMLElement {
disconnectedCallback() {
hasDisconnected = true;
documentWhenDisconnected = env.global.document;
}
}

// append an instance of the custom element
env.global.customElements.define('my-custom-element', MyCustomElement);
const instance = env.global.document.createElement('my-custom-element');
env.global.document.body.appendChild(instance);

// teardown will disconnect the custom elements
env.teardown();

expect(hasDisconnected).toBe(true);
expect(documentWhenDisconnected).not.toBeNull();
});

it('should not fire load event after the environment was teared down', async () => {
const env = new JSDomEnvironment(
{
globalConfig: makeGlobalConfig(),
projectConfig: makeProjectConfig(),
},
{console, docblockPragmas: {}, testPath: __filename},
);

const loadHandler = jest.fn();
env.global.document.addEventListener('load', loadHandler);
env.teardown();

// The `load` event is fired in microtasks, wait until the microtask queue is reliably flushed
await new Promise(resolve => setTimeout(resolve, 0));

expect(loadHandler).not.toHaveBeenCalled();
});
});
7 changes: 0 additions & 7 deletions packages/jest-environment-jsdom/src/index.ts
Expand Up @@ -160,13 +160,6 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
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.errorEventListener = null;
// @ts-expect-error: this.global not allowed to be `null`
Expand Down

0 comments on commit e7eb64c

Please sign in to comment.