diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index 36f980e0ce..43396f4957 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -415,42 +415,13 @@ The order of evaluation of multiple scripts installed via [`method: BrowserConte [`method: Page.addInitScript`] is not defined. ::: -**Bundling** - -If you have a complex script split into several files, it needs to be bundled into a single file first. We recommend running [`esbuild`](https://esbuild.github.io/) or [`webpack`](https://webpack.js.org/) to produce a commonjs module and pass [`option: path`] and [`option: arg`]. - -```js browser title="mocks/mockRandom.ts" -// This script can import other files. -import { defaultValue } from './defaultValue'; - -export default function(value?: number) { - window.Math.random = () => value ?? defaultValue; -} -``` - -```sh -# bundle with esbuild -esbuild mocks/mockRandom.ts --bundle --format=cjs --outfile=mocks/mockRandom.js -``` - -```js title="tests/example.spec.ts" -const mockPath = { path: path.resolve(__dirname, '../mocks/mockRandom.js') }; - -// Passing 42 as an argument to the default export function. -await context.addInitScript({ path: mockPath }, 42); - -// Make sure to pass something even if you do not need to pass an argument. -// This instructs Playwright to treat the file as a commonjs module. -await context.addInitScript({ path: mockPath }, ''); -``` - ### param: BrowserContext.addInitScript.script * since: v1.8 * langs: js - `script` <[function]|[string]|[Object]> - `path` ?<[path]> Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to the - current working directory. - - `content` ?<[string]> Raw script content. + current working directory. Optional. + - `content` ?<[string]> Raw script content. Optional. Script to be evaluated in all pages in the browser context. @@ -466,9 +437,7 @@ Script to be evaluated in all pages in the browser context. * langs: js - `arg` ?<[Serializable]> -Optional JSON-serializable argument to pass to [`param: script`]. -* When `script` is a function, the argument is passed to it directly. -* When `script` is a file path, the file is assumed to be a commonjs module. The default export, either `module.exports` or `module.exports.default`, should be a function that's going to be executed with this argument. +Optional argument to pass to [`param: script`] (only supported when passing a function). ### param: BrowserContext.addInitScript.path * since: v1.8 diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index da5d48f906..ea5fe74dfa 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -619,42 +619,13 @@ The order of evaluation of multiple scripts installed via [`method: BrowserConte [`method: Page.addInitScript`] is not defined. ::: -**Bundling** - -If you have a complex script split into several files, it needs to be bundled into a single file first. We recommend running [`esbuild`](https://esbuild.github.io/) or [`webpack`](https://webpack.js.org/) to produce a commonjs module and pass [`option: path`] and [`option: arg`]. - -```js browser title="mocks/mockRandom.ts" -// This script can import other files. -import { defaultValue } from './defaultValue'; - -export default function(value?: number) { - window.Math.random = () => value ?? defaultValue; -} -``` - -```sh -# bundle with esbuild -esbuild mocks/mockRandom.ts --bundle --format=cjs --outfile=mocks/mockRandom.js -``` - -```js title="tests/example.spec.ts" -const mockPath = { path: path.resolve(__dirname, '../mocks/mockRandom.js') }; - -// Passing 42 as an argument to the default export function. -await page.addInitScript({ path: mockPath }, 42); - -// Make sure to pass something even if you do not need to pass an argument. -// This instructs Playwright to treat the file as a commonjs module. -await page.addInitScript({ path: mockPath }, ''); -``` - ### param: Page.addInitScript.script * since: v1.8 * langs: js - `script` <[function]|[string]|[Object]> - `path` ?<[path]> Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to the - current working directory. - - `content` ?<[string]> Raw script content. + current working directory. Optional. + - `content` ?<[string]> Raw script content. Optional. Script to be evaluated in the page. @@ -670,9 +641,7 @@ Script to be evaluated in all pages in the browser context. * langs: js - `arg` ?<[Serializable]> -Optional JSON-serializable argument to pass to [`param: script`]. -* When `script` is a function, the argument is passed to it directly. -* When `script` is a file path, the file is assumed to be a commonjs module. The default export, either `module.exports` or `module.exports.default`, should be a function that's going to be executed with this argument. +Optional argument to pass to [`param: script`] (only supported when passing a function). ### param: Page.addInitScript.path * since: v1.8 diff --git a/packages/playwright-core/src/client/clientHelper.ts b/packages/playwright-core/src/client/clientHelper.ts index 793219f10b..540230a4fc 100644 --- a/packages/playwright-core/src/client/clientHelper.ts +++ b/packages/playwright-core/src/client/clientHelper.ts @@ -28,37 +28,20 @@ export function envObjectToArray(env: types.Env): { name: string, value: string return result; } -export async function evaluationScript(fun: Function | string | { path?: string, content?: string }, arg: any, addSourceUrl: boolean = true): Promise { +export async function evaluationScript(fun: Function | string | { path?: string, content?: string }, arg?: any, addSourceUrl: boolean = true): Promise { if (typeof fun === 'function') { const source = fun.toString(); const argString = Object.is(arg, undefined) ? 'undefined' : JSON.stringify(arg); return `(${source})(${argString})`; } - if (isString(fun)) { - if (arg !== undefined) - throw new Error('Cannot evaluate a string with arguments'); + if (arg !== undefined) + throw new Error('Cannot evaluate a string with arguments'); + if (isString(fun)) return fun; - } - if (fun.content !== undefined) { - if (arg !== undefined) - throw new Error('Cannot evaluate a string with arguments'); + if (fun.content !== undefined) return fun.content; - } if (fun.path !== undefined) { let source = await fs.promises.readFile(fun.path, 'utf8'); - if (arg !== undefined) { - // Assume a CJS module that has a function default export. - source = `(() => { - var exports = {}; var module = { exports }; - ${source} - let __pw_result__ = module.exports; - if (__pw_result__ && typeof __pw_result__ === 'object' && ('default' in __pw_result__)) - __pw_result__ = __pw_result__['default']; - if (typeof __pw_result__ !== 'function') - return __pw_result__; - return __pw_result__(${JSON.stringify(arg)}); - })()`; - } if (addSourceUrl) source = addSourceUrlToScript(source, fun.path); return source; diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index d0424c3024..f7d662dea7 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -288,41 +288,8 @@ export interface Page { * [browserContext.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script) * and [page.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-page#page-add-init-script) is not * defined. - * - * **Bundling** - * - * If you have a complex script split into several files, it needs to be bundled into a single file first. We - * recommend running [`esbuild`](https://esbuild.github.io/) or [`webpack`](https://webpack.js.org/) to produce a - * commonjs module and pass `path` and `arg`. - * - * ```js - * // mocks/mockRandom.ts - * // This script can import other files. - * import { defaultValue } from './defaultValue'; - * - * export default function(value?: number) { - * window.Math.random = () => value ?? defaultValue; - * } - * ``` - * - * ```js - * // tests/example.spec.ts - * const mockPath = { path: path.resolve(__dirname, '../mocks/mockRandom.js') }; - * - * // Passing 42 as an argument to the default export function. - * await page.addInitScript({ path: mockPath }, 42); - * - * // Make sure to pass something even if you do not need to pass an argument. - * // This instructs Playwright to treat the file as a commonjs module. - * await page.addInitScript({ path: mockPath }, ''); - * ``` - * * @param script Script to be evaluated in the page. - * @param arg Optional JSON-serializable argument to pass to `script`. - * - When `script` is a function, the argument is passed to it directly. - * - When `script` is a file path, the file is assumed to be a commonjs module. The default export, either - * `module.exports` or `module.exports.default`, should be a function that's going to be executed with this - * argument. + * @param arg Optional argument to pass to `script` (only supported when passing a function). */ addInitScript(script: PageFunction | { path?: string, content?: string }, arg?: Arg): Promise; @@ -7733,41 +7700,8 @@ export interface BrowserContext { * [browserContext.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script) * and [page.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-page#page-add-init-script) is not * defined. - * - * **Bundling** - * - * If you have a complex script split into several files, it needs to be bundled into a single file first. We - * recommend running [`esbuild`](https://esbuild.github.io/) or [`webpack`](https://webpack.js.org/) to produce a - * commonjs module and pass `path` and `arg`. - * - * ```js - * // mocks/mockRandom.ts - * // This script can import other files. - * import { defaultValue } from './defaultValue'; - * - * export default function(value?: number) { - * window.Math.random = () => value ?? defaultValue; - * } - * ``` - * - * ```js - * // tests/example.spec.ts - * const mockPath = { path: path.resolve(__dirname, '../mocks/mockRandom.js') }; - * - * // Passing 42 as an argument to the default export function. - * await context.addInitScript({ path: mockPath }, 42); - * - * // Make sure to pass something even if you do not need to pass an argument. - * // This instructs Playwright to treat the file as a commonjs module. - * await context.addInitScript({ path: mockPath }, ''); - * ``` - * * @param script Script to be evaluated in all pages in the browser context. - * @param arg Optional JSON-serializable argument to pass to `script`. - * - When `script` is a function, the argument is passed to it directly. - * - When `script` is a file path, the file is assumed to be a commonjs module. The default export, either - * `module.exports` or `module.exports.default`, should be a function that's going to be executed with this - * argument. + * @param arg Optional argument to pass to `script` (only supported when passing a function). */ addInitScript(script: PageFunction | { path?: string, content?: string }, arg?: Arg): Promise; diff --git a/tests/assets/injectedmodule.js b/tests/assets/injectedmodule.js deleted file mode 100644 index bc099f243f..0000000000 --- a/tests/assets/injectedmodule.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// one.ts -var one_exports = {}; -__export(one_exports, { - default: () => one_default -}); -module.exports = __toCommonJS(one_exports); - -// two.ts -var value = 42; - -// one.ts -function one_default(arg) { - window.injected = arg ?? value; -} diff --git a/tests/page/page-add-init-script.spec.ts b/tests/page/page-add-init-script.spec.ts index 2c8234a550..b2b7782eba 100644 --- a/tests/page/page-add-init-script.spec.ts +++ b/tests/page/page-add-init-script.spec.ts @@ -31,12 +31,6 @@ it('should work with a path', async ({ page, server, asset }) => { expect(await page.evaluate(() => window['result'])).toBe(123); }); -it('should assume CJS module with a path and arg', async ({ page, server, asset }) => { - await page.addInitScript({ path: asset('injectedmodule.js') }, 17); - await page.goto(server.EMPTY_PAGE); - expect(await page.evaluate(() => window['injected'])).toBe(17); -}); - it('should work with content @smoke', async ({ page, server }) => { await page.addInitScript({ content: 'window["injected"] = 123' }); await page.goto(server.PREFIX + '/tamperable.html');