Skip to content

Commit

Permalink
feat: support runner extensions via CLI (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
OrKoN committed Jun 1, 2022
1 parent 98dafa0 commit 22ae2c9
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 32 deletions.
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,
})
);
});
});
});

0 comments on commit 22ae2c9

Please sign in to comment.