diff options
Diffstat (limited to 'remote/test/puppeteer/test/installation')
29 files changed, 886 insertions, 0 deletions
diff --git a/remote/test/puppeteer/test/installation/.mocharc.cjs b/remote/test/puppeteer/test/installation/.mocharc.cjs new file mode 100644 index 0000000000..5a797716e0 --- /dev/null +++ b/remote/test/puppeteer/test/installation/.mocharc.cjs @@ -0,0 +1,13 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @type {import('mocha').MochaOptions} + */ +module.exports = { + spec: ['build/**/*.spec.js'], + timeout: '240000ms', +}; diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer-core/imports.js b/remote/test/puppeteer/test/installation/assets/puppeteer-core/imports.js new file mode 100644 index 0000000000..8f8fb329e7 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer-core/imports.js @@ -0,0 +1,9 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import 'puppeteer-core'; +import 'puppeteer-core/internal/revisions.js'; +import 'puppeteer-core/lib/esm/puppeteer/revisions.js'; diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer-core/launch.js b/remote/test/puppeteer/test/installation/assets/puppeteer-core/launch.js new file mode 100644 index 0000000000..4776d7e261 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer-core/launch.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import puppeteer from 'puppeteer-core'; + +(async () => { + try { + await puppeteer.launch({ + product: '${product}', + executablePath: 'node', + }); + } catch (error) { + if (error.message.includes('Failed to launch the browser process')) { + process.exit(0); + } + console.error(error); + process.exit(1); + } +})(); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer-core/requires.cjs b/remote/test/puppeteer/test/installation/assets/puppeteer-core/requires.cjs new file mode 100644 index 0000000000..f4276f2589 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer-core/requires.cjs @@ -0,0 +1,9 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +require('puppeteer-core'); +require('puppeteer-core/internal/revisions.js'); +require('puppeteer-core/lib/cjs/puppeteer/revisions.js'); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/basic.js b/remote/test/puppeteer/test/installation/assets/puppeteer/basic.js new file mode 100644 index 0000000000..9e6ce241b2 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/basic.js @@ -0,0 +1,15 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import puppeteer from 'puppeteer'; +(async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto('http://example.com'); + await page.$('aria/example'); + await page.screenshot({path: 'example.png'}); + await browser.close(); +})(); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/basic.ts b/remote/test/puppeteer/test/installation/assets/puppeteer/basic.ts new file mode 100644 index 0000000000..28396d0096 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/basic.ts @@ -0,0 +1,15 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import puppeteer from 'puppeteer'; +(async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto('http://example.com'); + await page.$('aria/example'); + await page.screenshot({path: 'example.png'}); + await browser.close(); +})(); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/bidi.js b/remote/test/puppeteer/test/installation/assets/puppeteer/bidi.js new file mode 100644 index 0000000000..3e1df93654 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/bidi.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import puppeteer from 'puppeteer'; +(async () => { + const browser = await puppeteer.launch({ + protocol: 'webDriverBiDi', + }); + const page = await browser.newPage(); + await page.goto('http://example.com'); + await page.$('h1'); + await page.screenshot({path: 'example.png'}); + await browser.close(); +})(); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/configuration/.puppeteerrc.cjs b/remote/test/puppeteer/test/installation/assets/puppeteer/configuration/.puppeteerrc.cjs new file mode 100644 index 0000000000..64a7b96681 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/configuration/.puppeteerrc.cjs @@ -0,0 +1,8 @@ +const {join} = require('path'); + +/** + * @type {import("puppeteer").Configuration} + */ +module.exports = { + cacheDirectory: join(__dirname, '.cache', 'puppeteer'), +}; diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/configuration/puppeteer.config.ts b/remote/test/puppeteer/test/installation/assets/puppeteer/configuration/puppeteer.config.ts new file mode 100644 index 0000000000..5bcb82ffc8 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/configuration/puppeteer.config.ts @@ -0,0 +1,6 @@ +import {type Configuration} from 'puppeteer'; +import {join} from 'path'; + +export default { + cacheDirectory: join(__dirname, '.cache', 'puppeteer'), +} satisfies Configuration; diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/imports.js b/remote/test/puppeteer/test/installation/assets/puppeteer/imports.js new file mode 100644 index 0000000000..cd742bafd5 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/imports.js @@ -0,0 +1,10 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import 'puppeteer'; + +// Should still be reachable. +import 'puppeteer-core/internal/revisions.js'; diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/installCanary.js b/remote/test/puppeteer/test/installation/assets/puppeteer/installCanary.js new file mode 100644 index 0000000000..39a0113de9 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/installCanary.js @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + Browser, + detectBrowserPlatform, + install, + resolveBuildId, +} from '@puppeteer/browsers'; + +(async () => { + await install({ + cacheDir: process.env['PUPPETEER_CACHE_DIR'], + browser: Browser.CHROME, + buildId: await resolveBuildId( + Browser.CHROME, + detectBrowserPlatform(), + 'canary' + ), + }); +})(); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/requires.cjs b/remote/test/puppeteer/test/installation/assets/puppeteer/requires.cjs new file mode 100644 index 0000000000..208eee9021 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/requires.cjs @@ -0,0 +1,10 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +require('puppeteer'); + +// Should still be reachable. +require('puppeteer-core/internal/revisions.js'); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/trimCache.js b/remote/test/puppeteer/test/installation/assets/puppeteer/trimCache.js new file mode 100644 index 0000000000..a810e2aac2 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/trimCache.js @@ -0,0 +1,11 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import puppeteer from 'puppeteer'; + +(async () => { + await puppeteer.trimCache(); +})(); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json b/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json new file mode 100644 index 0000000000..ce77dbf8d9 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + }, +} diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/webpack/webpack.config.js b/remote/test/puppeteer/test/installation/assets/puppeteer/webpack/webpack.config.js new file mode 100644 index 0000000000..30de2a4890 --- /dev/null +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/webpack/webpack.config.js @@ -0,0 +1,16 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +export default { + mode: 'production', + entry: './index.js', + target: 'node', + externals: 'typescript', + output: { + path: process.cwd(), + filename: 'bundle.js', + }, +}; diff --git a/remote/test/puppeteer/test/installation/package.json b/remote/test/puppeteer/test/installation/package.json new file mode 100644 index 0000000000..f5e804d99c --- /dev/null +++ b/remote/test/puppeteer/test/installation/package.json @@ -0,0 +1,50 @@ +{ + "name": "@puppeteer-test/installation", + "version": "latest", + "type": "module", + "private": true, + "scripts": { + "build": "wireit", + "clean": "../../tools/clean.js", + "test": "mocha" + }, + "wireit": { + "build": { + "command": "tsc -b", + "clean": "if-file-deleted", + "dependencies": [ + "build:packages" + ], + "files": [ + "tsconfig.json", + "src/**" + ], + "output": [ + "build/**", + "tsconfig.tsbuildinfo" + ] + }, + "build:packages": { + "command": "npm pack --quiet --workspace puppeteer --workspace puppeteer-core --workspace @puppeteer/browsers", + "dependencies": [ + "../../packages/puppeteer:build", + "../../packages/puppeteer-core:build", + "../../packages/browsers:build" + ], + "files": [], + "output": [ + "puppeteer-*.tgz" + ] + } + }, + "files": [ + ".mocharc.cjs", + "puppeteer-*.tgz", + "build", + "assets" + ], + "dependencies": { + "glob": "10.3.10", + "mocha": "10.2.0" + } +} diff --git a/remote/test/puppeteer/test/installation/src/browsers.spec.ts b/remote/test/puppeteer/test/installation/src/browsers.spec.ts new file mode 100644 index 0000000000..0c91731455 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/browsers.spec.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import {spawnSync} from 'child_process'; + +import {configureSandbox} from './sandbox.js'; + +describe('`@puppeteer/browsers`', () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers'], + }); + + it('can launch CLI', async function () { + const result = spawnSync('npx', ['@puppeteer/browsers', '--help'], { + // npx is not found without the shell flag on Windows. + shell: process.platform === 'win32', + cwd: this.sandbox, + }); + assert.strictEqual(result.status, 0); + assert.ok( + result.stdout + .toString('utf-8') + .startsWith('@puppeteer/browsers <command>') + ); + }); +}); diff --git a/remote/test/puppeteer/test/installation/src/constants.ts b/remote/test/puppeteer/test/installation/src/constants.ts new file mode 100644 index 0000000000..2b66b792d5 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/constants.ts @@ -0,0 +1,25 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {dirname, join, resolve} from 'path'; +import {fileURLToPath} from 'url'; + +import {globSync} from 'glob'; + +export const PUPPETEER_CORE_PACKAGE_PATH = resolve( + globSync('puppeteer-core-*.tgz')[0]! +); +export const PUPPETEER_BROWSERS_PACKAGE_PATH = resolve( + globSync('puppeteer-browsers-[0-9]*.tgz')[0]! +); +export const PUPPETEER_PACKAGE_PATH = resolve( + globSync('puppeteer-[0-9]*.tgz')[0]! +); +export const ASSETS_DIR = join( + dirname(fileURLToPath(import.meta.url)), + '..', + 'assets' +); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer-cli.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer-cli.spec.ts new file mode 100644 index 0000000000..650cbc1832 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer-cli.spec.ts @@ -0,0 +1,58 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import {spawnSync} from 'child_process'; +import {existsSync} from 'fs'; +import {readdir} from 'fs/promises'; +import {join} from 'path'; + +import {configureSandbox} from './sandbox.js'; + +describe('Puppeteer CLI', () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + PUPPETEER_SKIP_DOWNLOAD: 'true', + }; + }, + }); + + it('can launch', async function () { + const result = spawnSync('npx', ['puppeteer', '--help'], { + // npx is not found without the shell flag on Windows. + shell: process.platform === 'win32', + cwd: this.sandbox, + }); + assert.strictEqual(result.status, 0); + assert.ok( + result.stdout.toString('utf-8').startsWith('puppeteer <command>') + ); + }); + + it('can download a browser', async function () { + assert.ok(!existsSync(join(this.sandbox, '.cache', 'puppeteer'))); + const result = spawnSync( + 'npx', + ['puppeteer', 'browsers', 'install', 'chrome'], + { + // npx is not found without the shell flag on Windows. + shell: process.platform === 'win32', + cwd: this.sandbox, + env: { + ...process.env, + PUPPETEER_CACHE_DIR: join(this.sandbox, '.cache', 'puppeteer'), + }, + } + ); + assert.strictEqual(result.status, 0); + const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); + assert.equal(files.length, 1); + assert.equal(files[0], 'chrome'); + }); +}); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer-configuration.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer-configuration.spec.ts new file mode 100644 index 0000000000..1ed5511f6c --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer-configuration.spec.ts @@ -0,0 +1,73 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import {readdir, writeFile} from 'fs/promises'; +import {join} from 'path'; + +import {configureSandbox} from './sandbox.js'; +import {readAsset} from './util.js'; + +describe('`puppeteer` with configuration', () => { + describe('cjs', () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + }; + }, + before: async cwd => { + await writeFile( + join(cwd, '.puppeteerrc.cjs'), + await readAsset('puppeteer', 'configuration', '.puppeteerrc.cjs') + ); + }, + }); + + it('evaluates', async function () { + const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); + assert.equal(files.length, 2); + assert(files.includes('chrome')); + assert(files.includes('chrome-headless-shell')); + + const script = await readAsset('puppeteer', 'basic.js'); + await this.runScript(script, 'mjs'); + }); + }); + + describe('ts', () => { + configureSandbox({ + dependencies: [ + '@puppeteer/browsers', + 'puppeteer-core', + 'puppeteer', + 'typescript', + ], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + }; + }, + before: async cwd => { + await writeFile( + join(cwd, 'puppeteer.config.ts'), + await readAsset('puppeteer', 'configuration', 'puppeteer.config.ts') + ); + }, + }); + + it('evaluates', async function () { + const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); + assert.equal(files.length, 2); + assert(files.includes('chrome')); + assert(files.includes('chrome-headless-shell')); + + const script = await readAsset('puppeteer', 'basic.js'); + await this.runScript(script, 'mjs'); + }); + }); +}); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer-core.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer-core.spec.ts new file mode 100644 index 0000000000..9df19e1c85 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer-core.spec.ts @@ -0,0 +1,34 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {configureSandbox} from './sandbox.js'; +import {readAsset} from './util.js'; + +describe('`puppeteer-core`', () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core'], + }); + + it('evaluates CommonJS', async function () { + const script = await readAsset('puppeteer-core', 'requires.cjs'); + await this.runScript(script, 'cjs'); + }); + + it('evaluates ES modules', async function () { + const script = await readAsset('puppeteer-core', 'imports.js'); + await this.runScript(script, 'mjs'); + }); + + for (const product of ['firefox', 'chrome']) { + it(`\`launch\` for \`${product}\` with a bad \`executablePath\``, async function () { + const script = (await readAsset('puppeteer-core', 'launch.js')).replace( + '${product}', + product + ); + await this.runScript(script, 'mjs'); + }); + } +}); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer-firefox.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer-firefox.spec.ts new file mode 100644 index 0000000000..b599af01dc --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer-firefox.spec.ts @@ -0,0 +1,51 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import {readdir} from 'fs/promises'; +import {platform} from 'os'; +import {join} from 'path'; + +import {configureSandbox} from './sandbox.js'; +import {readAsset} from './util.js'; + +// Skipping this test on Windows as windows runners are much slower. +(platform() === 'win32' ? describe.skip : describe)( + '`puppeteer` with Firefox', + () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + PUPPETEER_PRODUCT: 'firefox', + }; + }, + }); + + describe('with CDP', () => { + it('evaluates CommonJS', async function () { + const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); + assert.equal(files.length, 1); + assert.equal(files[0], 'firefox'); + const script = await readAsset('puppeteer-core', 'requires.cjs'); + await this.runScript(script, 'cjs'); + }); + + it('evaluates ES modules', async function () { + const script = await readAsset('puppeteer-core', 'imports.js'); + await this.runScript(script, 'mjs'); + }); + }); + + describe('with WebDriverBiDi', () => { + it('evaluates ES modules', async function () { + const script = await readAsset('puppeteer', 'bidi.js'); + await this.runScript(script, 'mjs'); + }); + }); + } +); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer-typescript.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer-typescript.spec.ts new file mode 100644 index 0000000000..fc8ff133fb --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer-typescript.spec.ts @@ -0,0 +1,49 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {readFile, writeFile} from 'fs/promises'; +import {platform} from 'os'; +import {join} from 'path'; + +import {configureSandbox} from './sandbox.js'; +import {execFile, readAsset} from './util.js'; + +// Skipping this test on Windows as windows runners are much slower. +(platform() === 'win32' ? describe.skip : describe)( + '`puppeteer` with TypeScript', + () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + devDependencies: ['typescript@4.7.4', '@types/node@16.3.3'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + }; + }, + }); + + it('should work', async function () { + // Write a Webpack configuration. + await writeFile( + join(this.sandbox, 'tsconfig.json'), + await readAsset('puppeteer', 'tsconfig.json') + ); + + // Write the source code. + await writeFile( + join(this.sandbox, 'index.ts'), + await readAsset('puppeteer', 'basic.ts') + ); + + // Compile. + await execFile('npx', ['tsc'], {cwd: this.sandbox, shell: true}); + + const script = await readFile(join(this.sandbox, 'index.js'), 'utf-8'); + + await this.runScript(script, 'cjs'); + }); + } +); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer-webpack.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer-webpack.spec.ts new file mode 100644 index 0000000000..93902aec32 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer-webpack.spec.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {readFile, rm, writeFile} from 'fs/promises'; +import {join} from 'path'; + +import {configureSandbox} from './sandbox.js'; +import {execFile, readAsset} from './util.js'; + +describe('`puppeteer` with Webpack', () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + devDependencies: ['webpack', 'webpack-cli'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + }; + }, + }); + + it('evaluates WebPack Bundles', async function () { + // Write a Webpack configuration. + await writeFile( + join(this.sandbox, 'webpack.config.mjs'), + await readAsset('puppeteer', 'webpack', 'webpack.config.js') + ); + + // Write the source code. + await writeFile( + join(this.sandbox, 'index.js'), + await readAsset('puppeteer', 'basic.js') + ); + + // Bundle. + await execFile('npx', ['webpack'], {cwd: this.sandbox, shell: true}); + + // Remove `node_modules` to test independence. + await rm('node_modules', {recursive: true, force: true}); + + const script = await readFile(join(this.sandbox, 'bundle.js'), 'utf-8'); + + await this.runScript(script, 'cjs'); + }); +}); diff --git a/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts new file mode 100644 index 0000000000..d7b8757284 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts @@ -0,0 +1,104 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import {readdirSync} from 'fs'; +import {readdir} from 'fs/promises'; +import {platform} from 'os'; +import {join} from 'path'; + +import {configureSandbox} from './sandbox.js'; +import {readAsset} from './util.js'; + +describe('`puppeteer`', () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + }; + }, + }); + + it('evaluates CommonJS', async function () { + const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); + assert.equal(files.length, 2); + assert(files.includes('chrome')); + assert(files.includes('chrome-headless-shell')); + + const script = await readAsset('puppeteer-core', 'requires.cjs'); + await this.runScript(script, 'cjs'); + }); + + it('evaluates ES modules', async function () { + const script = await readAsset('puppeteer-core', 'imports.js'); + await this.runScript(script, 'mjs'); + }); +}); + +// Skipping this test on Windows as windows runners are much slower. +(platform() === 'win32' ? describe.skip : describe)( + '`puppeteer` with PUPPETEER_DOWNLOAD_PATH', + () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + env: cwd => { + return { + PUPPETEER_DOWNLOAD_PATH: join(cwd, '.cache', 'puppeteer'), + }; + }, + }); + + it('evaluates', async function () { + const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); + assert.equal(files.length, 2); + assert(files.includes('chrome')); + assert(files.includes('chrome-headless-shell')); + + const script = await readAsset('puppeteer', 'basic.js'); + await this.runScript(script, 'mjs'); + }); + } +); + +// Skipping this test on Windows as windows runners are much slower. +(platform() === 'win32' ? describe.skip : describe)( + '`puppeteer` clears cache', + () => { + configureSandbox({ + dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], + env: cwd => { + return { + PUPPETEER_CACHE_DIR: join(cwd, '.cache', 'puppeteer'), + }; + }, + }); + + it('evaluates', async function () { + assert.equal( + readdirSync(join(this.sandbox, '.cache', 'puppeteer', 'chrome')).length, + 1 + ); + + await this.runScript( + await readAsset('puppeteer', 'installCanary.js'), + 'mjs' + ); + + assert.equal( + readdirSync(join(this.sandbox, '.cache', 'puppeteer', 'chrome')).length, + 2 + ); + + await this.runScript(await readAsset('puppeteer', 'trimCache.js'), 'mjs'); + + assert.equal( + readdirSync(join(this.sandbox, '.cache', 'puppeteer', 'chrome')).length, + 1 + ); + }); + } +); diff --git a/remote/test/puppeteer/test/installation/src/sandbox.ts b/remote/test/puppeteer/test/installation/src/sandbox.ts new file mode 100644 index 0000000000..fde30dfcf9 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/sandbox.ts @@ -0,0 +1,131 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import crypto from 'crypto'; +import {mkdtemp, rm, writeFile} from 'fs/promises'; +import {tmpdir} from 'os'; +import {join} from 'path'; + +import { + PUPPETEER_CORE_PACKAGE_PATH, + PUPPETEER_PACKAGE_PATH, + PUPPETEER_BROWSERS_PACKAGE_PATH, +} from './constants.js'; +import {execFile} from './util.js'; + +const PKG_MANAGER = process.env['PKG_MANAGER'] || 'npm'; + +let ADD_PKG_SUBCOMMAND = 'install'; +if (PKG_MANAGER !== 'npm') { + ADD_PKG_SUBCOMMAND = 'add'; +} + +export interface ItEvaluatesOptions { + commonjs?: boolean; +} + +export interface ItEvaluatesFn { + ( + title: string, + options: ItEvaluatesOptions, + getScriptContent: (cwd: string) => Promise<string> + ): void; + (title: string, getScriptContent: (cwd: string) => Promise<string>): void; +} + +export interface SandboxOptions { + dependencies?: string[]; + devDependencies?: string[]; + /** + * This should be idempotent. + */ + env?: ((cwd: string) => NodeJS.ProcessEnv) | NodeJS.ProcessEnv; + before?: (cwd: string) => Promise<void>; +} + +declare module 'mocha' { + export interface Context { + /** + * The path to the root of the sandbox folder. + */ + sandbox: string; + env: NodeJS.ProcessEnv | undefined; + runScript: (content: string, type: 'cjs' | 'mjs') => Promise<void>; + } +} + +/** + * Configures mocha before/after hooks to create a temp folder and install + * specified dependencies. + */ +export const configureSandbox = (options: SandboxOptions): void => { + before(async function (): Promise<void> { + console.time('before'); + const sandbox = await mkdtemp(join(tmpdir(), 'puppeteer-')); + const dependencies = (options.dependencies ?? []).map(module => { + switch (module) { + case 'puppeteer': + return PUPPETEER_PACKAGE_PATH; + case 'puppeteer-core': + return PUPPETEER_CORE_PACKAGE_PATH; + case '@puppeteer/browsers': + return PUPPETEER_BROWSERS_PACKAGE_PATH; + default: + return module; + } + }); + const devDependencies = options.devDependencies ?? []; + + let getEnv: (cwd: string) => NodeJS.ProcessEnv | undefined; + if (typeof options.env === 'function') { + getEnv = options.env; + } else { + const env = options.env; + getEnv = () => { + return env; + }; + } + const env = {...process.env, ...getEnv(sandbox)}; + + await options.before?.(sandbox); + if (dependencies.length > 0) { + await execFile(PKG_MANAGER, [ADD_PKG_SUBCOMMAND, ...dependencies], { + cwd: sandbox, + env, + shell: true, + }); + } + if (devDependencies.length > 0) { + await execFile( + PKG_MANAGER, + [ADD_PKG_SUBCOMMAND, '-D', ...devDependencies], + { + cwd: sandbox, + env, + shell: true, + } + ); + } + + this.sandbox = sandbox; + this.env = env; + this.runScript = async (content: string, type: 'cjs' | 'mjs') => { + const script = join(sandbox, `script-${crypto.randomUUID()}.${type}`); + await writeFile(script, content); + await execFile('node', [script], {cwd: sandbox, env}); + }; + console.timeEnd('before'); + }); + + after(async function () { + console.time('after'); + if (!process.env['KEEP_SANDBOX']) { + await rm(this.sandbox, {recursive: true, force: true, maxRetries: 5}); + } else { + console.log('sandbox saved in', this.sandbox); + } + console.timeEnd('after'); + }); +}; diff --git a/remote/test/puppeteer/test/installation/src/util.ts b/remote/test/puppeteer/test/installation/src/util.ts new file mode 100644 index 0000000000..c975fd61e3 --- /dev/null +++ b/remote/test/puppeteer/test/installation/src/util.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {execFile as execFileAsync} from 'child_process'; +import {readFile} from 'fs/promises'; +import {join} from 'path'; +import {promisify} from 'util'; + +import {ASSETS_DIR} from './constants.js'; + +export const execFile = promisify(execFileAsync); +export const readAsset = (...components: string[]): Promise<string> => { + return readFile(join(ASSETS_DIR, ...components), 'utf8'); +}; diff --git a/remote/test/puppeteer/test/installation/tsconfig.json b/remote/test/puppeteer/test/installation/tsconfig.json new file mode 100644 index 0000000000..146127b470 --- /dev/null +++ b/remote/test/puppeteer/test/installation/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "build", + "rootDir": "src", + }, + "include": ["src"], +} diff --git a/remote/test/puppeteer/test/installation/tsdoc.json b/remote/test/puppeteer/test/installation/tsdoc.json new file mode 100644 index 0000000000..f5b91f4af6 --- /dev/null +++ b/remote/test/puppeteer/test/installation/tsdoc.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + + "extends": ["@microsoft/api-extractor/extends/tsdoc-base.json"], + "tagDefinitions": [ + { + "tagName": "@license", + "syntaxKind": "modifier", + "allowMultiple": false + } + ], + "supportForTags": { + "@license": true + } +} |