Skip to content

Commit

Permalink
feat: cli command to test extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
OrKoN committed Jan 23, 2023
1 parent 78d13b1 commit 3a2bed9
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 63 deletions.
29 changes: 29 additions & 0 deletions examples/extend-stringify/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { PuppeteerStringifyExtension } from '../../lib/main.js';

export default class Extension extends PuppeteerStringifyExtension {
// beforeAllSteps?(out: LineWriter, flow: UserFlow): Promise<void>;
async beforeAllSteps(...args) {
await super.beforeAllSteps(...args);
args[0].appendLine('console.log("starting");');
}

// beforeEachStep?(out: LineWriter, step: Step, flow: UserFlow): Promise<void>;
async beforeEachStep(...args) {
await super.beforeEachStep(...args);
const [out, step] = args;
out.appendLine(`console.log("about to execute step ${step.type}")`);
}

// afterEachStep?(out: LineWriter, step: Step, flow: UserFlow): Promise<void>;
async afterEachStep(...args) {
const [out, step] = args;
out.appendLine(`console.log("finished step ${step.type}")`);
await super.afterEachStep(...args);
}

// afterAllSteps?(out: LineWriter, flow: UserFlow): Promise<void>;
async afterAllSteps(...args) {
args[0].appendLine('console.log("finished");');
await super.afterAllSteps(...args);
}
}
30 changes: 2 additions & 28 deletions examples/extend-stringify/main.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,6 @@
import { stringify, PuppeteerStringifyExtension } from '../../lib/main.js';
import { stringify } from '../../lib/main.js';

class Extension extends PuppeteerStringifyExtension {
// beforeAllSteps?(out: LineWriter, flow: UserFlow): Promise<void>;
async beforeAllSteps(...args) {
await super.beforeAllSteps(...args);
args[0].appendLine('console.log("starting");');
}

// beforeEachStep?(out: LineWriter, step: Step, flow: UserFlow): Promise<void>;
async beforeEachStep(...args) {
await super.beforeEachStep(...args);
const [out, step] = args;
out.appendLine(`console.log("about to execute step ${step.type}")`);
}

// afterEachStep?(out: LineWriter, step: Step, flow: UserFlow): Promise<void>;
async afterEachStep(...args) {
const [out, step] = args;
out.appendLine(`console.log("finished step ${step.type}")`);
await super.afterEachStep(...args);
}

// afterAllSteps?(out: LineWriter, flow: UserFlow): Promise<void>;
async afterAllSteps(...args) {
args[0].appendLine('console.log("finished");');
await super.afterAllSteps(...args);
}
}
import Extension from './extension.js';

console.log(
await stringify(
Expand Down
33 changes: 22 additions & 11 deletions src/Spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,30 @@ export const files = new Map([
<pre id="log"></pre>
<script>
function logStr(str) {
log.innerText += str;
log.innerText += str;
const data = { username: 'example' };
fetch('/log', {
method: 'POST',
headers: {
'Content-Type': 'application/text',
},
body: str,
})
.catch((error) => {
console.error(error);
});
}
function logEvent(event) {
logStr(
'\\n' +
event.type +
' targetId=' +
event.target.id +
' button=' +
event.button +
' value=' +
event.target.value
);
logStr(
'\\n' +
event.type +
' targetId=' +
event.target.id +
' button=' +
event.button +
' value=' +
event.target.value
);
}
logStr(\`window dimensions \${window.innerWidth}x\${window.innerHeight}\`);
input.addEventListener('contextmenu', (e) => e.preventDefault(), false);
Expand Down
99 changes: 76 additions & 23 deletions src/extension-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,68 +16,121 @@

import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { RunnerExtension, createRunner, parse } from '../lib/main.js';
import {
RunnerExtension,
createRunner,
parse,
stringify,
} from '../lib/main.js';
import { importExtensionFromPath } from './CLIUtils.js';
import http from 'http';
import { files, recording } from './Spec.js';
import { files, recording, expectedLog } from './Spec.js';
import assert from 'assert/strict';
import { spawn } from 'node:child_process';

async function startServer() {
// Create an HTTP server
const server = http.createServer((req, res) => {
if (req.method !== 'GET') {
res.writeHead(400);
res.end();
const log = {
contents: '',
};
const server = http.createServer(async (req, res) => {
if (req.method === 'GET') {
for (const [file, content] of files.entries()) {
if (req.url?.endsWith(file)) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content);
return;
}
}
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not found');
return;
}
for (const [file, content] of files.entries()) {
if (req.url?.endsWith(file)) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content);
return;
}
if (req.method === 'POST') {
const body = await new Promise((resolve) => {
const body: any[] = [];
req
.on('data', (chunk) => {
body.push(chunk);
})
.on('end', () => {
resolve(Buffer.concat(body).toString());
});
});
res.writeHead(200);
res.end();
log.contents += body;
return;
}
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not found');
res.writeHead(400);
res.end();
});

return new Promise<http.Server>((resolve) => {
return new Promise<{ server: http.Server; log: typeof log }>((resolve) => {
server.listen(8907, 'localhost', () => {
resolve(server);
resolve({ server, log });
});
});
}

yargs(hideBin(process.argv))
.command(
'$0',
'test an extension implementation',
'Test an extension implementation',
() => {},
async (argv) => {
const args = argv as unknown as { extension: string };
const Extension = await importExtensionFromPath(args.extension);
const ext = new Extension();

let run = async () => {};

if (ext instanceof RunnerExtension) {
console.log('runner');
run = async () => {
const extension = new Extension();
const runner = await createRunner(parse(recording), extension);
await runner.run();
};
} else {
console.log('stringify');
run = async () => {
const exported = await stringify(parse(recording), {
extension: new Extension(),
});

const childProcess = spawn('node', {
stdio: ['pipe', 'pipe', 'inherit'],
shell: true,
});
childProcess.stdin.write(exported);
childProcess.stdin.end();

await new Promise<void>((resolve, reject) => {
childProcess.on('close', (code) =>
code
? reject(new Error(`Running node failed with code ${code}`))
: resolve()
);
});
};
}
const server = await startServer();
const { server, log } = await startServer();

try {
const extension = new Extension();
const runner = await createRunner(parse(recording), extension);
await runner.run();
await run();
} catch (err) {
console.error(err);
} finally {
server.close();
}
assert.equal(log.contents, expectedLog);
console.log('Run matches the expectations');
}
)
.option('extension', {
alias: 'ext',
type: 'string',
description: 'Run using an extension identified by the path.',
description: 'The path to the extension module. The default export will be used as a Stringify or Runner extension based on instanceOf checks.',
demandOption: true,
})
.parse();
2 changes: 1 addition & 1 deletion test/spec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async function createServers() {
return { httpServer, httpsServer };
}

describe('Benchmark test', () => {
describe('Spec test', () => {
let browser: puppeteer.Browser;
let page: puppeteer.Page;
let httpServer: TestServer;
Expand Down

0 comments on commit 3a2bed9

Please sign in to comment.