Skip to content

Commit

Permalink
Merge pull request #1211 from capricorn86/task/1210-fixes-issue-relat…
Browse files Browse the repository at this point in the history
…ed-to-using-fake-timers-in-v13

#1210@patch: Fixes issue related to using fake timers in Vitest makin…
  • Loading branch information
capricorn86 committed Jan 14, 2024
2 parents b9d5b65 + b1107d1 commit a3bd6ae
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 29 deletions.
17 changes: 12 additions & 5 deletions packages/happy-dom/src/async-task-manager/AsyncTaskManager.ts
@@ -1,3 +1,10 @@
// We need to set this as a global constant, so that using fake timers in Jest and Vitest won't override this on the global object.
const TIMER = {
setImmediate: setImmediate,
clearImmediate: clearImmediate,
clearTimeout: clearTimeout
};

/**
* Handles async tasks.
*/
Expand Down Expand Up @@ -107,10 +114,10 @@ export default class AsyncTaskManager {
delete this.runningTasks[taskID];
this.runningTaskCount--;
if (this.waitUntilCompleteTimer) {
global.clearImmediate(this.waitUntilCompleteTimer);
TIMER.clearImmediate(this.waitUntilCompleteTimer);
}
if (!this.runningTaskCount && !this.runningTimers.length && !this.runningImmediates.length) {
this.waitUntilCompleteTimer = global.setImmediate(() => {
this.waitUntilCompleteTimer = TIMER.setImmediate(() => {
this.waitUntilCompleteTimer = null;
if (
!this.runningTaskCount &&
Expand Down Expand Up @@ -170,16 +177,16 @@ export default class AsyncTaskManager {
this.runningTimers = [];

if (this.waitUntilCompleteTimer) {
global.clearImmediate(this.waitUntilCompleteTimer);
TIMER.clearImmediate(this.waitUntilCompleteTimer);
this.waitUntilCompleteTimer = null;
}

for (const immediate of runningImmediates) {
global.clearImmediate(immediate);
TIMER.clearImmediate(immediate);
}

for (const timer of runningTimers) {
global.clearTimeout(timer);
TIMER.clearTimeout(timer);
}

for (const key of Object.keys(runningTasks)) {
Expand Down
38 changes: 16 additions & 22 deletions packages/happy-dom/src/window/BrowserWindow.ts
Expand Up @@ -150,11 +150,15 @@ import RequestImplementation from '../fetch/Request.js';
import ResponseImplementation from '../fetch/Response.js';
import RangeImplementation from '../range/Range.js';

const ORIGINAL_SET_TIMEOUT = setTimeout;
const ORIGINAL_CLEAR_TIMEOUT = clearTimeout;
const ORIGINAL_SET_INTERVAL = setInterval;
const ORIGINAL_CLEAR_INTERVAL = clearInterval;
const ORIGINAL_QUEUE_MICROTASK = queueMicrotask;
const TIMER = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
queueMicrotask: queueMicrotask,
setImmediate: setImmediate,
clearImmediate: clearImmediate
};
const IS_NODE_JS_TIMEOUT_ENVIRONMENT = setTimeout.toString().includes('new Timeout');

/**
Expand Down Expand Up @@ -493,11 +497,6 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
public readonly [PropertySymbol.readyStateManager] = new DocumentReadyStateManager(this);

// Private properties
#setTimeout: (callback: Function, delay?: number, ...args: unknown[]) => NodeJS.Timeout;
#clearTimeout: (id: NodeJS.Timeout) => void;
#setInterval: (callback: Function, delay?: number, ...args: unknown[]) => NodeJS.Timeout;
#clearInterval: (id: NodeJS.Timeout) => void;
#queueMicrotask: (callback: Function) => void;
#browserFrame: IBrowserFrame;
#innerWidth: number | null = null;
#innerHeight: number | null = null;
Expand All @@ -516,11 +515,6 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
super();

this.#browserFrame = browserFrame;
this.#setTimeout = ORIGINAL_SET_TIMEOUT;
this.#clearTimeout = ORIGINAL_CLEAR_TIMEOUT;
this.#setInterval = ORIGINAL_SET_INTERVAL;
this.#clearInterval = ORIGINAL_CLEAR_INTERVAL;
this.#queueMicrotask = ORIGINAL_QUEUE_MICROTASK;

this.customElements = new CustomElementRegistry();
this.navigator = new Navigator(this);
Expand Down Expand Up @@ -967,7 +961,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
!settings ||
!settings.disableErrorCapturing ||
settings.errorCapture === BrowserErrorCaptureEnum.tryAndCatch;
const id = this.#setTimeout(() => {
const id = TIMER.setTimeout(() => {
if (useTryCatch) {
WindowErrorUtility.captureError(this, () => callback(...args));
} else {
Expand All @@ -990,7 +984,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
if (IS_NODE_JS_TIMEOUT_ENVIRONMENT && (!id || id.constructor.name !== 'Timeout')) {
return;
}
this.#clearTimeout(id);
TIMER.clearTimeout(id);
this.#browserFrame[PropertySymbol.asyncTaskManager].endTimer(id);
}

Expand All @@ -1008,7 +1002,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
!settings ||
!settings.disableErrorCapturing ||
settings.errorCapture === BrowserErrorCaptureEnum.tryAndCatch;
const id = this.#setInterval(() => {
const id = TIMER.setInterval(() => {
if (useTryCatch) {
WindowErrorUtility.captureError(
this,
Expand All @@ -1034,7 +1028,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
if (IS_NODE_JS_TIMEOUT_ENVIRONMENT && (!id || id.constructor.name !== 'Timeout')) {
return;
}
this.#clearInterval(id);
TIMER.clearInterval(id);
this.#browserFrame[PropertySymbol.asyncTaskManager].endTimer(id);
}

Expand All @@ -1050,7 +1044,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
!settings ||
!settings.disableErrorCapturing ||
settings.errorCapture === BrowserErrorCaptureEnum.tryAndCatch;
const id = global.setImmediate(() => {
const id = TIMER.setImmediate(() => {
if (useTryCatch) {
WindowErrorUtility.captureError(this, () => callback(this.performance.now()));
} else {
Expand All @@ -1073,7 +1067,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
if (IS_NODE_JS_TIMEOUT_ENVIRONMENT && (!id || id.constructor.name !== 'Immediate')) {
return;
}
global.clearImmediate(id);
TIMER.clearImmediate(id);
this.#browserFrame[PropertySymbol.asyncTaskManager].endImmediate(id);
}

Expand All @@ -1092,7 +1086,7 @@ export default class BrowserWindow extends EventTarget implements IBrowserWindow
!settings ||
!settings.disableErrorCapturing ||
settings.errorCapture === BrowserErrorCaptureEnum.tryAndCatch;
this.#queueMicrotask(() => {
TIMER.queueMicrotask(() => {
if (!isAborted) {
if (useTryCatch) {
WindowErrorUtility.captureError(this, <() => unknown>callback);
Expand Down
4 changes: 2 additions & 2 deletions packages/happy-dom/test/nodes/element/Element.test.ts
Expand Up @@ -1117,8 +1117,8 @@ describe('Element', () => {
div.innerHTML =
'<span id="a"></span><span id="b"></span><span id="c"></span><span id="d"></span>';

const a = div.querySelector('#a');
const b = div.querySelector('#b');
const a = <IElement>div.querySelector('#a');
const b = <IElement>div.querySelector('#b');

div.insertBefore(a, b);

Expand Down

0 comments on commit a3bd6ae

Please sign in to comment.