Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support runner extensions via CLI #162

Merged
merged 1 commit into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,22 @@ In your `package.json` add a new script to invoke the `replay` command:
}
```

Set the `PUPPETEER_HEADLESS` environment variable to control whether the browser is start in a headful or headless mode. For example,
Set the `PUPPETEER_HEADLESS` environment variable or `--headless` CLI flag to control whether the browser is start in a headful or headless mode. For example,

```
PUPPETEER_HEADLESS=true npx @puppeteer/replay recording.json # runs in headless mode, the default mode.
PUPPETEER_HEADLESS=false npx @puppeteer/replay recording.json # runs in headful mode.
PUPPETEER_HEADLESS=chrome npx @puppeteer/replay recording.json # runs in the new experimental headless mode.
```

Use the `--extension` CLI flag to provide a [custom replay extension](https://github.com/puppeteer/replay#2-customize-replay) for running the recording. For [example](https://github.com/puppeteer/replay/blob/main/examples/cli-extension/extension.js),

```sh
npx @puppeteer/replay --extension examples/cli-extension/extension.js recording.json
```

Run `npx @puppeteer/replay --help` to see all CLI options.

Using [the replay lib API](/examples/replay-from-file-using-puppeteer/main.js):

```js
Expand Down
24 changes: 24 additions & 0 deletions examples/cli-extension/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { PuppeteerRunnerExtension } from '../../lib/main.js';

export default class Extension extends PuppeteerRunnerExtension {
async beforeAllSteps(flow) {
await super.beforeAllSteps(flow);
console.log('starting');
}

async beforeEachStep(step, flow) {
await super.beforeEachStep(step, flow);
console.log('before', step);
}

async afterEachStep(step, flow) {
await super.afterEachStep(step, flow);
console.log('after', step);
}

async afterAllSteps(flow) {
await super.afterAllSteps(flow);
console.log('done');
await this.browser.close();
}
}
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@types/chai": "4.3.1",
"@types/mocha": "9.1.1",
"@types/node": "17.0.36",
"@types/yargs": "17.0.10",
"@typescript-eslint/eslint-plugin": "5.26.0",
"@typescript-eslint/parser": "5.27.0",
"c8": "7.11.3",
Expand Down Expand Up @@ -68,5 +69,8 @@
"puppeteer": {
"optional": true
}
},
"dependencies": {
"yargs": "17.5.1"
}
}
25 changes: 16 additions & 9 deletions src/CLIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@

import { parse, createRunner } from './main.js';
import { readFileSync } from 'fs';
import { join, isAbsolute } from 'path';
import { pathToFileURL } from 'url';
import { cwd } from 'process';
import { PuppeteerRunnerOwningBrowserExtension } from './PuppeteerRunnerExtension.js';

export function getFilenames(argv: string[]) {
return argv.slice(2);
}

export function getHeadlessEnvVar(headless?: string) {
if (!headless) {
return true;
Expand All @@ -42,11 +41,22 @@ export function getHeadlessEnvVar(headless?: string) {

export async function runFiles(
files: string[],
opts: { log: boolean; headless: boolean | 'chrome' } = {
opts: { log: boolean; headless: boolean | 'chrome'; extension?: string } = {
log: false,
headless: true,
}
): Promise<boolean> {
let Extension = PuppeteerRunnerOwningBrowserExtension;
if (opts.extension) {
const module = await import(
pathToFileURL(
isAbsolute(opts.extension)
? opts.extension
: join(cwd(), opts.extension)
).toString()
);
Extension = module.default;
}
for (const file of files) {
opts.log && console.log(`Running ${file}...`);
try {
Expand All @@ -58,10 +68,7 @@ export async function runFiles(
headless: opts.headless,
});
const page = await browser.newPage();
const extension = new PuppeteerRunnerOwningBrowserExtension(
browser,
page
);
const extension = new Extension(browser, page);
const runner = await createRunner(recording, extension);
await runner.run();
opts.log && console.log(`Finished running ${file}`);
Expand Down
44 changes: 36 additions & 8 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,41 @@
limitations under the License.
*/

import { getFilenames, getHeadlessEnvVar, runFiles } from './CLIUtils.js';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

const recordings = getFilenames(process.argv);
if (!recordings.length) {
console.log(`Usage: replay filename [filename...]`);
import { getHeadlessEnvVar, runFiles } from './CLIUtils.js';

interface Arguments {
files: string[];
extension?: string;
headless?: string;
}
await runFiles(recordings, {
log: true,
headless: getHeadlessEnvVar(process.env.PUPPETEER_HEADLESS),
});

await yargs(hideBin(process.argv))
.command(
'$0 <files..>',
'run files',
() => {},
async (argv) => {
const args = argv as unknown as Arguments;
await runFiles(args.files, {
log: true,
headless: getHeadlessEnvVar(
args.headless || process.env.PUPPETEER_HEADLESS
),
extension: args.extension,
});
}
)
.option('headless', {
type: 'string',
description: "Run using the browser's headless mode.",
choices: ['chrome', 'true', '1', '0', 'false'],
})
.option('extension', {
alias: 'ext',
type: 'string',
description: 'Run using an extension identified by the path.',
})
.parse();
25 changes: 11 additions & 14 deletions test/cli_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,14 @@
limitations under the License.
*/

import { getFilenames, runFiles, getHeadlessEnvVar } from '../src/CLIUtils.js';
import { runFiles, getHeadlessEnvVar } from '../src/CLIUtils.js';
import { assert } from 'chai';
import path from 'path';
import url from 'url';

const __dirname = path.dirname(url.fileURLToPath(import.meta.url));

describe('cli', () => {
describe('getFilenames', () => {
it('extracts filenames from process.argv', () => {
assert.deepStrictEqual(getFilenames(['node', 'script.js']), []);
assert.deepStrictEqual(getFilenames(['node', 'script.js', 'file1']), [
'file1',
]);
assert.deepStrictEqual(
getFilenames(['node', 'script.js', 'file1', 'file2', 'file3']),
['file1', 'file2', 'file3']
);
});
});

describe('getHeadlessEnvVar', () => {
it('extracts the headless parameter from process.argv', () => {
assert.strictEqual(getHeadlessEnvVar(undefined), true);
Expand All @@ -54,5 +41,15 @@ describe('cli', () => {
await runFiles([path.join(__dirname, 'resources', 'replay.json')])
);
});

it('is able to run successfully with an extension', async () => {
assert.isTrue(
await runFiles([path.join(__dirname, 'resources', 'replay.json')], {
extension: path.join('examples', 'cli-extension', 'extension.js'),
headless: true,
log: false,
})
);
});
});
});