Repository: capricorn86/happy-dom (ts)

Issue:
setTimeout / setInterval does not pass arguments to callback
**Describe the bug**
Arguments to callback function of setTimeout or setInterval doesn't receivce arguments.

**To Reproduce**
Execute in browser:
```
const callback = (message) => {console.log(message)};
setTimeout(callback, 0, 'hello');

VM154:1 hello
```

Execute in happy-dom:
```
const callback = (message) => {console.log(message)};
setTimeout(callback, 0, 'hello');

VM154:1 undefined
```

**Expected behavior**
Should print hello as the browser.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Device:**
 - Version 8.2.3

Pull request:
#712@patch: fix handling of callback arguments passing given to setTimeout / setInterval
fixes #712 

Patch:
diff --git a/packages/happy-dom/src/window/IWindow.ts b/packages/happy-dom/src/window/IWindow.ts
index 019cfc9b..88e7db41 100644
--- a/packages/happy-dom/src/window/IWindow.ts
+++ b/packages/happy-dom/src/window/IWindow.ts
@@ -302,9 +302,10 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
 	 *
 	 * @param callback Function to be executed.
 	 * @param [delay=0] Delay in ms.
+	 * @param args Arguments passed to the callback function.
 	 * @returns Timeout ID.
 	 */
-	setTimeout(callback: () => void, delay?: number): NodeJS.Timeout;
+	setTimeout(callback: Function, delay?: number, ...args: unknown[]): NodeJS.Timeout;
 
 	/**
 	 * Cancels a timeout previously established by calling setTimeout().
@@ -318,9 +319,10 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
 	 *
 	 * @param callback Function to be executed.
 	 * @param [delay=0] Delay in ms.
+	 * @param args Arguments passed to the callback function.
 	 * @returns Interval ID.
 	 */
-	setInterval(callback: () => void, delay?: number): NodeJS.Timeout;
+	setInterval(callback: Function, delay?: number, ...args: unknown[]): NodeJS.Timeout;
 
 	/**
 	 * Cancels a timed repeating action which was previously established by a call to setInterval().
diff --git a/packages/happy-dom/src/window/Window.ts b/packages/happy-dom/src/window/Window.ts
index 1c1638b8..d7aacb30 100644
--- a/packages/happy-dom/src/window/Window.ts
+++ b/packages/happy-dom/src/window/Window.ts
@@ -622,12 +622,13 @@ export default class Window extends EventTarget implements IWindow {
 	 * @override
 	 * @param callback Function to be executed.
 	 * @param [delay=0] Delay in ms.
+	 * @param args Arguments passed to the callback function.
 	 * @returns Timeout ID.
 	 */
-	public setTimeout(callback: () => void, delay = 0): NodeJS.Timeout {
+	public setTimeout(callback: Function, delay = 0, ...args: unknown[]): NodeJS.Timeout {
 		const id = this._setTimeout(() => {
 			this.happyDOM.asyncTaskManager.endTimer(id);
-			callback();
+			callback(...args);
 		}, delay);
 		this.happyDOM.asyncTaskManager.startTimer(id);
 		return id;
@@ -650,10 +651,11 @@ export default class Window extends EventTarget implements IWindow {
 	 * @override
 	 * @param callback Function to be executed.
 	 * @param [delay=0] Delay in ms.
+	 * @param args Arguments passed to the callback function.
 	 * @returns Interval ID.
 	 */
-	public setInterval(callback: () => void, delay = 0): NodeJS.Timeout {
-		const id = this._setInterval(callback, delay);
+	public setInterval(callback: Function, delay = 0, ...args: unknown[]): NodeJS.Timeout {
+		const id = this._setInterval(callback, delay, ...args);
 		this.happyDOM.asyncTaskManager.startTimer(id);
 		return id;
 	}


Test patch:
diff --git a/packages/happy-dom/test/window/Window.test.ts b/packages/happy-dom/test/window/Window.test.ts
index 99304c20..a87a3843 100644
--- a/packages/happy-dom/test/window/Window.test.ts
+++ b/packages/happy-dom/test/window/Window.test.ts
@@ -387,6 +387,35 @@ describe('Window', () => {
 			const timeoutId = window.setTimeout(() => done());
 			expect(timeoutId.constructor.name).toBe('Timeout');
 		});
+
+		it('Sets a timeout with single argument.', (done) => {
+			const callbackArgumentOne = 'hello';
+			const timeoutId = window.setTimeout(
+				(message: string) => {
+					expect(message).toBe(callbackArgumentOne);
+					done();
+				},
+				0,
+				callbackArgumentOne
+			);
+			expect(timeoutId.constructor.name).toBe('Timeout');
+		});
+
+		it('Sets a timeout with multiple arguments.', (done) => {
+			const callbackArgumentOne = 'hello';
+			const callbackArgumentTwo = 1337;
+			const timeoutId = window.setTimeout(
+				(message: string, num: number) => {
+					expect(message).toBe(callbackArgumentOne);
+					expect(num).toBe(callbackArgumentTwo);
+					done();
+				},
+				0,
+				callbackArgumentOne,
+				callbackArgumentTwo
+			);
+			expect(timeoutId.constructor.name).toBe('Timeout');
+		});
 	});
 
 	describe('clearTimeout()', () => {
@@ -409,6 +438,43 @@ describe('Window', () => {
 				}
 			});
 		});
+
+		it('Sets an interval with single argument.', (done) => {
+			const callbackArgumentOne = 'hello';
+			let count = 0;
+			const intervalId = window.setInterval(
+				(message: string) => {
+					expect(message).toBe(callbackArgumentOne);
+					count++;
+					if (count > 2) {
+						clearInterval(intervalId);
+						done();
+					}
+				},
+				0,
+				callbackArgumentOne
+			);
+		});
+
+		it('Sets an interval with multiple arguments.', (done) => {
+			const callbackArgumentOne = 'hello';
+			const callbackArgumentTwo = 1337;
+			let count = 0;
+			const intervalId = window.setInterval(
+				(message: string, num: number) => {
+					expect(message).toBe(callbackArgumentOne);
+					expect(num).toBe(callbackArgumentTwo);
+					count++;
+					if (count > 2) {
+						clearInterval(intervalId);
+						done();
+					}
+				},
+				0,
+				callbackArgumentOne,
+				callbackArgumentTwo
+			);
+		});
 	});
 
 	describe('clearInterval()', () => {