diff --git a/new-docs/puppeteer.evaluatefn.md b/new-docs/puppeteer.evaluatefn.md
index 8647ef2b7d3..75904473880 100644
--- a/new-docs/puppeteer.evaluatefn.md
+++ b/new-docs/puppeteer.evaluatefn.md
@@ -8,5 +8,5 @@
Signature:
```typescript
-export declare type EvaluateFn = string | ((arg1: T, ...args: any[]) => any);
+export declare type EvaluateFn = string | ((arg1: T, ...args: unknown[]) => unknown);
```
diff --git a/new-docs/puppeteer.evaluatefnreturntype.md b/new-docs/puppeteer.evaluatefnreturntype.md
index 471823e316e..67bad36a77a 100644
--- a/new-docs/puppeteer.evaluatefnreturntype.md
+++ b/new-docs/puppeteer.evaluatefnreturntype.md
@@ -8,5 +8,5 @@
Signature:
```typescript
-export declare type EvaluateFnReturnType = T extends (...args: any[]) => infer R ? R : unknown;
+export declare type EvaluateFnReturnType = T extends (...args: unknown[]) => infer R ? R : unknown;
```
diff --git a/new-docs/puppeteer.frame.evaluate.md b/new-docs/puppeteer.frame.evaluate.md
index bd06acd2eaf..53e102eabf0 100644
--- a/new-docs/puppeteer.frame.evaluate.md
+++ b/new-docs/puppeteer.frame.evaluate.md
@@ -7,19 +7,19 @@
Signature:
```typescript
-evaluate(pageFunction: Function | string, ...args: unknown[]): Promise;
+evaluate(pageFunction: T, ...args: SerializableOrJSHandle[]): Promise>>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| pageFunction | Function \| string | a function that is run within the frame |
-| args | unknown\[\] | arguments to be passed to the pageFunction |
+| pageFunction | T | a function that is run within the frame |
+| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | arguments to be passed to the pageFunction |
Returns:
-Promise<ReturnType>
+Promise<[UnwrapPromiseLike](./puppeteer.unwrappromiselike.md)<[EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md)<T>>>
## Remarks
diff --git a/new-docs/puppeteer.jshandle.evaluate.md b/new-docs/puppeteer.jshandle.evaluate.md
index c8cd3227e22..d30e34dc314 100644
--- a/new-docs/puppeteer.jshandle.evaluate.md
+++ b/new-docs/puppeteer.jshandle.evaluate.md
@@ -9,7 +9,7 @@ This method passes this handle as the first argument to `pageFunction`.
Signature:
```typescript
-evaluate(pageFunction: T | string, ...args: SerializableOrJSHandle[]): Promise>;
+evaluate(pageFunction: T | string, ...args: SerializableOrJSHandle[]): Promise>>;
```
## Parameters
@@ -21,7 +21,7 @@ evaluate(pageFunction: T | string, ...args: SerializableOr
Returns:
-Promise<[EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md)<T>>
+Promise<[UnwrapPromiseLike](./puppeteer.unwrappromiselike.md)<[EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md)<T>>>
## Example
diff --git a/new-docs/puppeteer.md b/new-docs/puppeteer.md
index ad2d130b346..f8c728372ee 100644
--- a/new-docs/puppeteer.md
+++ b/new-docs/puppeteer.md
@@ -109,5 +109,6 @@
| [Serializable](./puppeteer.serializable.md) | |
| [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md) | |
| [UnwrapElementHandle](./puppeteer.unwrapelementhandle.md) | Unwraps a DOM element out of an ElementHandle instance |
+| [UnwrapPromiseLike](./puppeteer.unwrappromiselike.md) | |
| [WrapElementHandle](./puppeteer.wrapelementhandle.md) | Wraps a DOM element into an ElementHandle instance |
diff --git a/new-docs/puppeteer.page.evaluate.md b/new-docs/puppeteer.page.evaluate.md
index 7f87a9e5962..3308520e936 100644
--- a/new-docs/puppeteer.page.evaluate.md
+++ b/new-docs/puppeteer.page.evaluate.md
@@ -7,19 +7,19 @@
Signature:
```typescript
-evaluate(pageFunction: Function | string, ...args: unknown[]): Promise;
+evaluate(pageFunction: T, ...args: SerializableOrJSHandle[]): Promise>>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| pageFunction | Function \| string | a function that is run within the page |
-| args | unknown\[\] | arguments to be passed to the pageFunction |
+| pageFunction | T | a function that is run within the page |
+| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | arguments to be passed to the pageFunction |
Returns:
-Promise<ReturnType>
+Promise<[UnwrapPromiseLike](./puppeteer.unwrappromiselike.md)<[EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md)<T>>>
the return value of `pageFunction`.
@@ -47,6 +47,12 @@ You can pass a string instead of a function (although functions are recommended
```
const aHandle = await page.evaluate('1 + 2');
+```
+To get the best TypeScript experience, you should pass in as the generic the type of `pageFunction`:
+
+```
+const aHandle = await page.evaluate<() => number>(() => 2);
+
```
## Example 3
diff --git a/new-docs/puppeteer.serializable.md b/new-docs/puppeteer.serializable.md
index 8b7a7df8bf1..b8abdb01038 100644
--- a/new-docs/puppeteer.serializable.md
+++ b/new-docs/puppeteer.serializable.md
@@ -8,5 +8,5 @@
Signature:
```typescript
-export declare type Serializable = number | string | boolean | null | JSONArray | JSONObject;
+export declare type Serializable = number | string | boolean | null | BigInt | JSONArray | JSONObject;
```
diff --git a/new-docs/puppeteer.unwrappromiselike.md b/new-docs/puppeteer.unwrappromiselike.md
new file mode 100644
index 00000000000..c1b8e6459b4
--- /dev/null
+++ b/new-docs/puppeteer.unwrappromiselike.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [puppeteer](./puppeteer.md) > [UnwrapPromiseLike](./puppeteer.unwrappromiselike.md)
+
+## UnwrapPromiseLike type
+
+Signature:
+
+```typescript
+export declare type UnwrapPromiseLike = T extends PromiseLike ? U : T;
+```
diff --git a/src/common/DOMWorld.ts b/src/common/DOMWorld.ts
index 933ceef6db5..28f37b9c658 100644
--- a/src/common/DOMWorld.ts
+++ b/src/common/DOMWorld.ts
@@ -28,6 +28,9 @@ import {
SerializableOrJSHandle,
EvaluateHandleFn,
WrapElementHandle,
+ EvaluateFn,
+ EvaluateFnReturnType,
+ UnwrapPromiseLike,
} from './EvalTypes';
import { isNode } from '../environment';
@@ -118,12 +121,15 @@ export class DOMWorld {
return context.evaluateHandle(pageFunction, ...args);
}
- async evaluate(
- pageFunction: Function | string,
- ...args: unknown[]
- ): Promise {
+ async evaluate(
+ pageFunction: T,
+ ...args: SerializableOrJSHandle[]
+ ): Promise>> {
const context = await this.executionContext();
- return context.evaluate(pageFunction, ...args);
+ return context.evaluate>>(
+ pageFunction,
+ ...args
+ );
}
async $(selector: string): Promise {
@@ -206,7 +212,7 @@ export class DOMWorld {
} = options;
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
- await this.evaluate((html) => {
+ await this.evaluate<(x: string) => void>((html) => {
document.open();
document.write(html);
document.close();
diff --git a/src/common/EvalTypes.ts b/src/common/EvalTypes.ts
index 11f7d35ece8..95b4039be4c 100644
--- a/src/common/EvalTypes.ts
+++ b/src/common/EvalTypes.ts
@@ -19,12 +19,17 @@ import { JSHandle, ElementHandle } from './JSHandle';
/**
* @public
*/
-export type EvaluateFn = string | ((arg1: T, ...args: any[]) => any);
+export type EvaluateFn =
+ | string
+ | ((arg1: T, ...args: unknown[]) => unknown);
+
+export type UnwrapPromiseLike = T extends PromiseLike ? U : T;
+
/**
* @public
*/
export type EvaluateFnReturnType = T extends (
- ...args: any[]
+ ...args: unknown[]
) => infer R
? R
: unknown;
@@ -42,6 +47,7 @@ export type Serializable =
| string
| boolean
| null
+ | BigInt
| JSONArray
| JSONObject;
diff --git a/src/common/FrameManager.ts b/src/common/FrameManager.ts
index 29a86fdd8cc..366f7bedd90 100644
--- a/src/common/FrameManager.ts
+++ b/src/common/FrameManager.ts
@@ -32,6 +32,9 @@ import {
SerializableOrJSHandle,
EvaluateHandleFn,
WrapElementHandle,
+ EvaluateFn,
+ EvaluateFnReturnType,
+ UnwrapPromiseLike,
} from './EvalTypes';
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';
@@ -684,11 +687,11 @@ export class Frame {
* @param pageFunction - a function that is run within the frame
* @param args - arguments to be passed to the pageFunction
*/
- async evaluate(
- pageFunction: Function | string,
- ...args: unknown[]
- ): Promise {
- return this._mainWorld.evaluate(pageFunction, ...args);
+ async evaluate(
+ pageFunction: T,
+ ...args: SerializableOrJSHandle[]
+ ): Promise>> {
+ return this._mainWorld.evaluate(pageFunction, ...args);
}
/**
diff --git a/src/common/JSHandle.ts b/src/common/JSHandle.ts
index f5a0c18b283..ffb0c6b2c7e 100644
--- a/src/common/JSHandle.ts
+++ b/src/common/JSHandle.ts
@@ -29,6 +29,7 @@ import {
EvaluateFnReturnType,
EvaluateHandleFn,
WrapElementHandle,
+ UnwrapPromiseLike,
} from './EvalTypes';
export interface BoxModel {
@@ -153,12 +154,10 @@ export class JSHandle {
async evaluate(
pageFunction: T | string,
...args: SerializableOrJSHandle[]
- ): Promise> {
- return await this.executionContext().evaluate>(
- pageFunction,
- this,
- ...args
- );
+ ): Promise>> {
+ return await this.executionContext().evaluate<
+ UnwrapPromiseLike>
+ >(pageFunction, this, ...args);
}
/**
@@ -620,7 +619,9 @@ export class ElementHandle<
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
*/
async focus(): Promise {
- await this.evaluate((element) => element.focus());
+ await this.evaluate<(element: HTMLElement) => void>((element) =>
+ element.focus()
+ );
}
/**
diff --git a/src/common/Page.ts b/src/common/Page.ts
index 257784a09bf..a58f9fbfd4e 100644
--- a/src/common/Page.ts
+++ b/src/common/Page.ts
@@ -45,6 +45,9 @@ import {
SerializableOrJSHandle,
EvaluateHandleFn,
WrapElementHandle,
+ EvaluateFn,
+ EvaluateFnReturnType,
+ UnwrapPromiseLike,
} from './EvalTypes';
const writeFileAsync = promisify(fs.writeFile);
@@ -1516,6 +1519,13 @@ export class Page extends EventEmitter {
* const aHandle = await page.evaluate('1 + 2');
* ```
*
+ * To get the best TypeScript experience, you should pass in as the
+ * generic the type of `pageFunction`:
+ *
+ * ```
+ * const aHandle = await page.evaluate<() => number>(() => 2);
+ * ```
+ *
* @example
*
* {@link ElementHandle} instances (including {@link JSHandle}s) can be passed
@@ -1532,13 +1542,11 @@ export class Page extends EventEmitter {
*
* @returns the return value of `pageFunction`.
*/
- async evaluate(
- pageFunction: Function | string,
- ...args: unknown[]
- ): Promise {
- return this._frameManager
- .mainFrame()
- .evaluate(pageFunction, ...args);
+ async evaluate(
+ pageFunction: T,
+ ...args: SerializableOrJSHandle[]
+ ): Promise>> {
+ return this._frameManager.mainFrame().evaluate(pageFunction, ...args);
}
async evaluateOnNewDocument(
diff --git a/test/browsercontext.spec.ts b/test/browsercontext.spec.ts
index b8f4cfcf0be..98502654c65 100644
--- a/test/browsercontext.spec.ts
+++ b/test/browsercontext.spec.ts
@@ -66,7 +66,10 @@ describe('BrowserContext', function () {
await page.goto(server.EMPTY_PAGE);
const [popupTarget] = await Promise.all([
utils.waitEvent(browser, 'targetcreated'),
- page.evaluate((url) => window.open(url), server.EMPTY_PAGE),
+ page.evaluate<(url: string) => void>(
+ (url) => window.open(url),
+ server.EMPTY_PAGE
+ ),
]);
expect(popupTarget.browserContext()).toBe(context);
await context.close();
diff --git a/test/cookies.spec.ts b/test/cookies.spec.ts
index 63092f2aa39..e2c41f2b947 100644
--- a/test/cookies.spec.ts
+++ b/test/cookies.spec.ts
@@ -389,9 +389,9 @@ describe('Cookie specs', () => {
await page.goto(server.PREFIX + '/grid.html');
await page.setCookie({ name: 'localhost-cookie', value: 'best' });
- await page.evaluate((src) => {
+ await page.evaluate<(src: string) => Promise>((src) => {
let fulfill;
- const promise = new Promise((x) => (fulfill = x));
+ const promise = new Promise((x) => (fulfill = x));
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.onload = fulfill;
@@ -454,9 +454,9 @@ describe('Cookie specs', () => {
try {
await page.goto(httpsServer.PREFIX + '/grid.html');
- await page.evaluate((src) => {
+ await page.evaluate<(src: string) => Promise>((src) => {
let fulfill;
- const promise = new Promise((x) => (fulfill = x));
+ const promise = new Promise((x) => (fulfill = x));
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.onload = fulfill;
diff --git a/test/coverage.spec.ts b/test/coverage.spec.ts
index a75a6a8770c..bc92938d939 100644
--- a/test/coverage.spec.ts
+++ b/test/coverage.spec.ts
@@ -264,7 +264,7 @@ describe('Coverage specs', function () {
const { page, server } = getTestState();
await page.coverage.startCSSCoverage();
- await page.evaluate(async (url) => {
+ await page.evaluate<(url: string) => Promise>(async (url) => {
document.body.textContent = 'hello, world';
const link = document.createElement('link');
diff --git a/test/elementhandle.spec.ts b/test/elementhandle.spec.ts
index fe6252b4039..bfcef439f9c 100644
--- a/test/elementhandle.spec.ts
+++ b/test/elementhandle.spec.ts
@@ -67,7 +67,7 @@ describe('ElementHandle specs', function () {
'hello
'
);
const elementHandle = await page.$('div');
- await page.evaluate(
+ await page.evaluate<(element: HTMLElement) => void>(
(element) => (element.style.height = '200px'),
elementHandle
);
@@ -84,7 +84,7 @@ describe('ElementHandle specs', function () {
`);
const element = await page.$('#therect');
const pptrBoundingBox = await element.boundingBox();
- const webBoundingBox = await page.evaluate((e) => {
+ const webBoundingBox = await page.evaluate((e: HTMLElement) => {
const rect = e.getBoundingClientRect();
return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
}, element);
@@ -211,7 +211,7 @@ describe('ElementHandle specs', function () {
await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button');
- await page.evaluate((button) => button.remove(), button);
+ await page.evaluate((button: HTMLElement) => button.remove(), button);
let error = null;
await button.click().catch((error_) => (error = error_));
expect(error.message).toBe('Node is detached from document');
@@ -221,7 +221,10 @@ describe('ElementHandle specs', function () {
await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button');
- await page.evaluate((button) => (button.style.display = 'none'), button);
+ await page.evaluate(
+ (button: HTMLElement) => (button.style.display = 'none'),
+ button
+ );
const error = await button.click().catch((error_) => error_);
expect(error.message).toBe(
'Node is either not visible or not an HTMLElement'
@@ -233,7 +236,7 @@ describe('ElementHandle specs', function () {
await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button');
await page.evaluate(
- (button) => (button.parentElement.style.display = 'none'),
+ (button: HTMLElement) => (button.parentElement.style.display = 'none'),
button
);
const error = await button.click().catch((error_) => error_);
@@ -295,7 +298,12 @@ describe('ElementHandle specs', function () {
(element, selector) => document.querySelector(`[id="${selector}"]`)
);
const element = await page.$('getById/foo');
- expect(await page.evaluate((element) => element.id, element)).toBe('foo');
+ expect(
+ await page.evaluate<(element: HTMLElement) => string>(
+ (element) => element.id,
+ element
+ )
+ ).toBe('foo');
// Unregister.
puppeteer.__experimental_unregisterCustomQueryHandler('getById');
@@ -340,7 +348,10 @@ describe('ElementHandle specs', function () {
const classNames = await Promise.all(
elements.map(
async (element) =>
- await page.evaluate((element) => element.className, element)
+ await page.evaluate<(element: HTMLElement) => string>(
+ (element) => element.className,
+ element
+ )
)
);
diff --git a/test/emulation.spec.ts b/test/emulation.spec.ts
index cc47ab719b0..a54dbafe282 100644
--- a/test/emulation.spec.ts
+++ b/test/emulation.spec.ts
@@ -138,7 +138,7 @@ describe('Emulation', () => {
await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button');
await page.evaluate(
- (button) => (button.style.marginTop = '200px'),
+ (button: HTMLElement) => (button.style.marginTop = '200px'),
button
);
await button.click();
diff --git a/test/evaluation.spec.ts b/test/evaluation.spec.ts
index a6e1cec95aa..c16cf6547cc 100644
--- a/test/evaluation.spec.ts
+++ b/test/evaluation.spec.ts
@@ -40,7 +40,7 @@ describe('Evaluation specs', function () {
(bigint ? it : xit)('should transfer BigInt', async () => {
const { page } = getTestState();
- const result = await page.evaluate((a) => a, BigInt(42));
+ const result = await page.evaluate((a: BigInt) => a, BigInt(42));
expect(result).toBe(BigInt(42));
});
it('should transfer NaN', async () => {
@@ -155,7 +155,11 @@ describe('Evaluation specs', function () {
// Setup inpage callback, which calls Page.evaluate
await page.exposeFunction('callController', async function (a, b) {
- return await page.evaluate((a, b) => a * b, a, b);
+ return await page.evaluate<(a: number, b: number) => number>(
+ (a, b) => a * b,
+ a,
+ b
+ );
});
const result = await page.evaluate(async function () {
return await globalThis.callController(9, 3);
@@ -277,7 +281,7 @@ describe('Evaluation specs', function () {
.jsonValue()
.catch((error_) => error_.message);
const error = await page
- .evaluate((errorText) => {
+ .evaluate<(errorText: string) => Error>((errorText) => {
throw new Error(errorText);
}, errorText)
.catch((error_) => error_);
@@ -306,7 +310,10 @@ describe('Evaluation specs', function () {
await page.setContent('');
const element = await page.$('section');
- const text = await page.evaluate((e) => e.textContent, element);
+ const text = await page.evaluate<(e: HTMLElement) => string>(
+ (e) => e.textContent,
+ element
+ );
expect(text).toBe('42');
});
it('should throw if underlying element was disposed', async () => {
@@ -318,7 +325,7 @@ describe('Evaluation specs', function () {
await element.dispose();
let error = null;
await page
- .evaluate((e) => e.textContent, element)
+ .evaluate((e: HTMLElement) => e.textContent, element)
.catch((error_) => (error = error_));
expect(error.message).toContain('JSHandle is disposed');
});
@@ -331,7 +338,7 @@ describe('Evaluation specs', function () {
const bodyHandle = await page.frames()[1].$('body');
let error = null;
await page
- .evaluate((body) => body.innerHTML, bodyHandle)
+ .evaluate((body: HTMLElement) => body.innerHTML, bodyHandle)
.catch((error_) => (error = error_));
expect(error).toBeTruthy();
expect(error.message).toContain(
@@ -379,7 +386,7 @@ describe('Evaluation specs', function () {
it('should transfer 100Mb of data from page to node.js', async function () {
const { page } = getTestState();
- const a = await page.evaluate(() =>
+ const a = await page.evaluate<() => string>(() =>
Array(100 * 1024 * 1024 + 1).join('a')
);
expect(a.length).toBe(100 * 1024 * 1024);
diff --git a/test/frame.spec.ts b/test/frame.spec.ts
index 0e51db85be1..8251f1d068d 100644
--- a/test/frame.spec.ts
+++ b/test/frame.spec.ts
@@ -200,7 +200,7 @@ describe('Frame specs', function () {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/shadow.html');
- await page.evaluate(async (url) => {
+ await page.evaluate(async (url: string) => {
const frame = document.createElement('iframe');
frame.src = url;
document.body.shadowRoot.appendChild(frame);
@@ -213,7 +213,7 @@ describe('Frame specs', function () {
const { page, server } = getTestState();
await utils.attachFrame(page, 'theFrameId', server.EMPTY_PAGE);
- await page.evaluate((url) => {
+ await page.evaluate((url: string) => {
const frame = document.createElement('iframe');
frame.name = 'theFrameName';
frame.src = url;
diff --git a/test/input.spec.ts b/test/input.spec.ts
index b5fa2d04e5c..cd2c10339ca 100644
--- a/test/input.spec.ts
+++ b/test/input.spec.ts
@@ -36,7 +36,7 @@ describe('input tests', function () {
await page.goto(server.PREFIX + '/input/fileupload.html');
const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD);
const input = await page.$('input');
- await page.evaluate((e) => {
+ await page.evaluate((e: HTMLElement) => {
globalThis._inputEvents = [];
e.addEventListener('change', (ev) =>
globalThis._inputEvents.push(ev.type)
@@ -46,18 +46,18 @@ describe('input tests', function () {
);
}, input);
await input.uploadFile(filePath);
- expect(await page.evaluate((e) => e.files[0].name, input)).toBe(
- 'file-to-upload.txt'
- );
- expect(await page.evaluate((e) => e.files[0].type, input)).toBe(
- 'text/plain'
- );
+ expect(
+ await page.evaluate((e: HTMLInputElement) => e.files[0].name, input)
+ ).toBe('file-to-upload.txt');
+ expect(
+ await page.evaluate((e: HTMLInputElement) => e.files[0].type, input)
+ ).toBe('text/plain');
expect(await page.evaluate(() => globalThis._inputEvents)).toEqual([
'input',
'change',
]);
expect(
- await page.evaluate((e) => {
+ await page.evaluate((e: HTMLInputElement) => {
const reader = new FileReader();
const promise = new Promise((fulfill) => (reader.onload = fulfill));
reader.readAsText(e.files[0]);
diff --git a/test/jshandle.spec.ts b/test/jshandle.spec.ts
index 276d88b9f58..cdcb7efb24e 100644
--- a/test/jshandle.spec.ts
+++ b/test/jshandle.spec.ts
@@ -37,7 +37,10 @@ describe('JSHandle', function () {
const { page } = getTestState();
const navigatorHandle = await page.evaluateHandle(() => navigator);
- const text = await page.evaluate((e) => e.userAgent, navigatorHandle);
+ const text = await page.evaluate(
+ (e: Navigator) => e.userAgent,
+ navigatorHandle
+ );
expect(text).toContain('Mozilla');
});
it('should accept object handle to primitive types', async () => {
@@ -75,7 +78,9 @@ describe('JSHandle', function () {
globalThis.FOO = 123;
return window;
});
- expect(await page.evaluate((e) => e.FOO, aHandle)).toBe(123);
+ expect(await page.evaluate((e: { FOO: number }) => e.FOO, aHandle)).toBe(
+ 123
+ );
});
it('should work with primitives', async () => {
const { page } = getTestState();
@@ -84,7 +89,9 @@ describe('JSHandle', function () {
globalThis.FOO = 123;
return window;
});
- expect(await page.evaluate((e) => e.FOO, aHandle)).toBe(123);
+ expect(await page.evaluate((e: { FOO: number }) => e.FOO, aHandle)).toBe(
+ 123
+ );
});
});
@@ -193,7 +200,10 @@ describe('JSHandle', function () {
const element = aHandle.asElement();
expect(element).toBeTruthy();
expect(
- await page.evaluate((e) => e.nodeType === Node.TEXT_NODE, element)
+ await page.evaluate(
+ (e: HTMLElement) => e.nodeType === Node.TEXT_NODE,
+ element
+ )
);
});
});
diff --git a/test/keyboard.spec.ts b/test/keyboard.spec.ts
index c90876adeb0..cd13574db54 100644
--- a/test/keyboard.spec.ts
+++ b/test/keyboard.spec.ts
@@ -387,7 +387,15 @@ describe('Keyboard', function () {
});
});
await page.keyboard.press('Meta');
- const [key, code, metaKey] = await page.evaluate('result');
+ // Have to do this because we lose a lot of type info when evaluating a
+ // string not a function. This is why functions are recommended rather than
+ // using strings (although we'll leave this test so we have coverage of both
+ // approaches.)
+ const [key, code, metaKey] = (await page.evaluate('result')) as [
+ string,
+ string,
+ boolean
+ ];
if (isFirefox && os.platform() !== 'darwin') expect(key).toBe('OS');
else expect(key).toBe('Meta');
diff --git a/test/mouse.spec.ts b/test/mouse.spec.ts
index 97aae6b9011..cb114607b1f 100644
--- a/test/mouse.spec.ts
+++ b/test/mouse.spec.ts
@@ -61,7 +61,7 @@ describe('Mouse', function () {
});
});
await page.mouse.click(50, 60);
- const event = await page.evaluate(
+ const event = await page.evaluate<() => MouseEvent>(
() => globalThis.clickPromise
);
expect(event.type).toBe('click');
@@ -75,13 +75,15 @@ describe('Mouse', function () {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html');
- const { x, y, width, height } = await page.evaluate(dimensions);
+ const { x, y, width, height } = await page.evaluate<() => Dimensions>(
+ dimensions
+ );
const mouse = page.mouse;
await mouse.move(x + width - 4, y + height - 4);
await mouse.down();
await mouse.move(x + width + 100, y + height + 100);
await mouse.up();
- const newDimensions = await page.evaluate(dimensions);
+ const newDimensions = await page.evaluate<() => Dimensions>(dimensions);
expect(newDimensions.width).toBe(Math.round(width + 104));
expect(newDimensions.height).toBe(Math.round(height + 104));
});
@@ -163,13 +165,15 @@ describe('Mouse', function () {
for (const [modifier, key] of modifiers) {
await page.keyboard.down(modifier);
await page.click('#button-3');
- if (!(await page.evaluate((mod) => globalThis.lastEvent[mod], key)))
+ if (
+ !(await page.evaluate((mod: string) => globalThis.lastEvent[mod], key))
+ )
throw new Error(key + ' should be true');
await page.keyboard.up(modifier);
}
await page.click('#button-3');
for (const [modifier, key] of modifiers) {
- if (await page.evaluate((mod) => globalThis.lastEvent[mod], key))
+ if (await page.evaluate((mod: string) => globalThis.lastEvent[mod], key))
throw new Error(modifiers[modifier] + ' should be false');
}
});
diff --git a/test/navigation.spec.ts b/test/navigation.spec.ts
index 31c230245b6..c654b4af1fd 100644
--- a/test/navigation.spec.ts
+++ b/test/navigation.spec.ts
@@ -495,7 +495,7 @@ describe('navigation', function () {
const [response] = await Promise.all([
page.waitForNavigation(),
page.evaluate(
- (url) => (window.location.href = url),
+ (url: string) => (window.location.href = url),
server.PREFIX + '/grid.html'
),
]);
@@ -733,7 +733,7 @@ describe('navigation', function () {
const [response] = await Promise.all([
frame.waitForNavigation(),
frame.evaluate(
- (url) => (window.location.href = url),
+ (url: string) => (window.location.href = url),
server.PREFIX + '/grid.html'
),
]);
diff --git a/test/page.spec.ts b/test/page.spec.ts
index a0e6661e5dd..9674948121c 100644
--- a/test/page.spec.ts
+++ b/test/page.spec.ts
@@ -27,6 +27,7 @@ import {
describeFailsFirefox,
} from './mocha-utils';
import { Page, Metrics } from '../src/common/Page';
+import { JSHandle } from '../src/common/JSHandle';
describe('Page', function () {
setupTestBrowserHooks();
@@ -397,7 +398,7 @@ describe('Page', function () {
const prototypeHandle = await page.evaluateHandle(() => Set.prototype);
const objectsHandle = await page.queryObjects(prototypeHandle);
const count = await page.evaluate(
- (objects) => objects.length,
+ (objects: JSHandle[]) => objects.length,
objectsHandle
);
expect(count).toBe(1);
@@ -416,7 +417,7 @@ describe('Page', function () {
const prototypeHandle = await page.evaluateHandle(() => Set.prototype);
const objectsHandle = await page.queryObjects(prototypeHandle);
const count = await page.evaluate(
- (objects) => objects.length,
+ (objects: JSHandle[]) => objects.length,
objectsHandle
);
expect(count).toBe(1);
@@ -515,7 +516,7 @@ describe('Page', function () {
const [message] = await Promise.all([
waitEvent(page, 'console'),
page.evaluate(
- async (url) => fetch(url).catch(() => {}),
+ async (url: string) => fetch(url).catch(() => {}),
server.EMPTY_PAGE
),
]);
@@ -887,8 +888,8 @@ describe('Page', function () {
await page.exposeFunction('complexObject', function (a, b) {
return { x: a.x + b.x };
});
- const result = await page.evaluate<{ x: number }>(async () =>
- globalThis.complexObject({ x: 5 }, { x: 2 })
+ const result = await page.evaluate<() => Promise<{ x: number }>>(
+ async () => globalThis.complexObject({ x: 5 }, { x: 2 })
);
expect(result.x).toBe(7);
});
@@ -1334,7 +1335,7 @@ describe('Page', function () {
});
const styleHandle = await page.$('style');
const styleContent = await page.evaluate(
- (style) => style.innerHTML,
+ (style: HTMLStyleElement) => style.innerHTML,
styleHandle
);
expect(styleContent).toContain(path.join('assets', 'injectedstyle.css'));
diff --git a/test/queryselector.spec.ts b/test/queryselector.spec.ts
index df484e0b554..3beb03de371 100644
--- a/test/queryselector.spec.ts
+++ b/test/queryselector.spec.ts
@@ -103,7 +103,7 @@ describe('querySelector', function () {
const elements = await page.$$('div');
expect(elements.length).toBe(2);
const promises = elements.map((element) =>
- page.evaluate((e) => e.textContent, element)
+ page.evaluate((e: HTMLElement) => e.textContent, element)
);
expect(await Promise.all(promises)).toEqual(['A', 'B']);
});
@@ -151,7 +151,10 @@ describe('querySelector', function () {
const html = await page.$('html');
const second = await html.$('.second');
const inner = await second.$('.inner');
- const content = await page.evaluate((e) => e.textContent, inner);
+ const content = await page.evaluate(
+ (e: HTMLElement) => e.textContent,
+ inner
+ );
expect(content).toBe('A');
});
@@ -263,7 +266,7 @@ describe('querySelector', function () {
const elements = await html.$$('div');
expect(elements.length).toBe(2);
const promises = elements.map((element) =>
- page.evaluate((e) => e.textContent, element)
+ page.evaluate((e: HTMLElement) => e.textContent, element)
);
expect(await Promise.all(promises)).toEqual(['A', 'B']);
});
@@ -291,7 +294,10 @@ describe('querySelector', function () {
const html = await page.$('html');
const second = await html.$x(`./body/div[contains(@class, 'second')]`);
const inner = await second[0].$x(`./div[contains(@class, 'inner')]`);
- const content = await page.evaluate((e) => e.textContent, inner[0]);
+ const content = await page.evaluate(
+ (e: HTMLElement) => e.textContent,
+ inner[0]
+ );
expect(content).toBe('A');
});
diff --git a/test/requestinterception.spec.ts b/test/requestinterception.spec.ts
index 9d4d60fb327..024824aa831 100644
--- a/test/requestinterception.spec.ts
+++ b/test/requestinterception.spec.ts
@@ -384,7 +384,7 @@ describe('request interception', function () {
});
const dataURL = 'data:text/html,yo
';
const text = await page.evaluate(
- (url) => fetch(url).then((r) => r.text()),
+ (url: string) => fetch(url).then((r) => r.text()),
dataURL
);
expect(text).toBe('yo
');
diff --git a/test/screenshot.spec.ts b/test/screenshot.spec.ts
index c2cf043144b..3687e185805 100644
--- a/test/screenshot.spec.ts
+++ b/test/screenshot.spec.ts
@@ -281,7 +281,10 @@ describe('Screenshots', function () {
await page.setContent('remove this
');
const elementHandle = await page.$('h1');
- await page.evaluate((element) => element.remove(), elementHandle);
+ await page.evaluate(
+ (element: HTMLElement) => element.remove(),
+ elementHandle
+ );
const screenshotError = await elementHandle
.screenshot()
.catch((error) => error);
diff --git a/test/target.spec.ts b/test/target.spec.ts
index 54e0fa2854b..bc6deb006b2 100644
--- a/test/target.spec.ts
+++ b/test/target.spec.ts
@@ -81,7 +81,7 @@ describe('Target', function () {
)
.then((target) => target.page()),
page.evaluate(
- (url) => window.open(url),
+ (url: string) => window.open(url),
server.CROSS_PROCESS_PREFIX + '/empty.html'
),
]);
@@ -215,7 +215,7 @@ describe('Target', function () {
// Open a new page. Use window.open to connect to the page later.
await Promise.all([
page.evaluate(
- (url) => window.open(url),
+ (url: string) => window.open(url),
server.PREFIX + '/one-style.html'
),
server.waitForRequest('/one-style.css'),
diff --git a/test/waittask.spec.ts b/test/waittask.spec.ts
index 9c216c10685..d31e9523344 100644
--- a/test/waittask.spec.ts
+++ b/test/waittask.spec.ts
@@ -264,7 +264,7 @@ describe('waittask specs', function () {
.waitForFunction((element) => !element.parentElement, {}, div)
.then(() => (resolved = true));
expect(resolved).toBe(false);
- await page.evaluate((element) => element.remove(), div);
+ await page.evaluate((element: HTMLElement) => element.remove(), div);
await waitForFunction;
});
it('should respect timeout', async () => {
@@ -351,9 +351,9 @@ describe('waittask specs', function () {
page.waitForSelector('.zombo'),
page.setContent(`anything
`),
]);
- expect(await page.evaluate((x) => x.textContent, handle)).toBe(
- 'anything'
- );
+ expect(
+ await page.evaluate((x: HTMLElement) => x.textContent, handle)
+ ).toBe('anything');
});
it('should resolve promise when node is added', async () => {
@@ -588,7 +588,10 @@ describe('waittask specs', function () {
const waitForSelector = page.waitForSelector('.zombo');
await page.setContent(`anything
`);
expect(
- await page.evaluate((x) => x.textContent, await waitForSelector)
+ await page.evaluate(
+ (x: HTMLElement) => x.textContent,
+ await waitForSelector
+ )
).toBe('anything');
});
it('should have correct stack trace for timeout', async () => {
@@ -616,7 +619,10 @@ describe('waittask specs', function () {
'//p[normalize-space(.)="hello world"]'
);
expect(
- await page.evaluate((x) => x.textContent, await waitForXPath)
+ await page.evaluate(
+ (x: HTMLElement) => x.textContent,
+ await waitForXPath
+ )
).toBe('hello world ');
});
it('should respect timeout', async () => {
@@ -683,7 +689,10 @@ describe('waittask specs', function () {
const waitForXPath = page.waitForXPath('//*[@class="zombo"]');
await page.setContent(`anything
`);
expect(
- await page.evaluate((x) => x.textContent, await waitForXPath)
+ await page.evaluate(
+ (x: HTMLElement) => x.textContent,
+ await waitForXPath
+ )
).toBe('anything');
});
it('should allow you to select a text node', async () => {
@@ -701,7 +710,10 @@ describe('waittask specs', function () {
await page.setContent(`some text
`);
const waitForXPath = page.waitForXPath('/html/body/div');
expect(
- await page.evaluate((x) => x.textContent, await waitForXPath)
+ await page.evaluate(
+ (x: HTMLElement) => x.textContent,
+ await waitForXPath
+ )
).toBe('some text');
});
});
diff --git a/test/worker.spec.ts b/test/worker.spec.ts
index 86aba8ca289..1f070df6510 100644
--- a/test/worker.spec.ts
+++ b/test/worker.spec.ts
@@ -60,7 +60,10 @@ describeFailsFirefox('Workers', function () {
const workerDestroyedPromise = new Promise((x) =>
page.once('workerdestroyed', x)
);
- await page.evaluate((workerObj) => workerObj.terminate(), workerObj);
+ await page.evaluate(
+ (workerObj: Worker) => workerObj.terminate(),
+ workerObj
+ );
expect(await workerDestroyedPromise).toBe(worker);
const error = await workerThisObj
.getProperty('self')