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: implement status report #224

Merged
merged 4 commits into from
Jul 28, 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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
}
},
"dependencies": {
"cli-table3": "^0.6.2",
"colors": "^1.4.0",
"yargs": "17.5.1"
}
}
84 changes: 82 additions & 2 deletions src/CLIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@

import { parse, createRunner } from '../lib/main.js';
import { readFileSync, readdirSync, lstatSync } from 'fs';
import { join, isAbsolute, extname } from 'path';
import { join, isAbsolute, extname, relative } from 'path';
import { pathToFileURL } from 'url';
import { cwd } from 'process';
import { PuppeteerRunnerOwningBrowserExtension } from '../lib/main.js';
import { Browser } from 'puppeteer';
import Table from 'cli-table3';
import colors from 'colors';

export function getJSONFilesFromFolder(path: string): string[] {
return readdirSync(path)
Expand Down Expand Up @@ -75,6 +77,60 @@ export function getHeadlessEnvVar(headless?: string) {
}
}

type Result = {
startedAt: Date;
file: string;
finishedAt: Date;
success: boolean;
title: string;
};

export function createStatusReport(results: Result[]): Table.Table {
const table = new Table({
head: ['Title', 'Status', 'File', 'Duration'],
chars: {
top: '═',
'top-mid': '╤',
'top-left': '╔',
'top-right': '╗',
bottom: '═',
'bottom-mid': '╧',
'bottom-left': '╚',
'bottom-right': '╝',
left: '║',
'left-mid': '╟',
mid: '─',
'mid-mid': '┼',
right: '║',
'right-mid': '╢',
middle: '│',
},
style: {
head: ['bold'],
},
});

const resultTextColor = colors.white;
for (const result of results) {
const row: string[] = [];

const duration =
result.finishedAt?.getTime()! - result.startedAt.getTime() || 0;
const status = result.success
? resultTextColor.bgGreen(' Success ')
: resultTextColor.bgRed(' Failure ');

row.push(result.title);
row.push(status);
row.push(relative(process.cwd(), result.file));
row.push(`${duration}ms`);

table.push(row);
}

return table;
}

export async function runFiles(
files: string[],
opts: { log: boolean; headless: boolean | 'chrome'; extension?: string } = {
Expand All @@ -95,12 +151,24 @@ export async function runFiles(
);
Extension = module.default;
}

const results: Result[] = [];
for (const file of files) {
const result: Result = {
title: '',
startedAt: new Date(),
finishedAt: new Date(),
file,
success: true,
};

opts.log && console.log(`Running ${file}...`);
try {
const content = readFileSync(file, 'utf-8');
const object = JSON.parse(content);
const recording = parse(object);
result.title = recording.title;

const { default: puppeteer } = await import('puppeteer');
browser = await puppeteer.launch({
headless: opts.headless,
Expand All @@ -112,9 +180,21 @@ export async function runFiles(
opts.log && console.log(`Finished running ${file}`);
} catch (err) {
opts.log && console.error(`Error running ${file}`, err);
throw err;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change changes the behavior of the CLI:

  • Before: when a replay is failed, we were throwing error from here so that the yargs library was returning the status code 1 to the bash
  • With this change: even though a replay is failed, we now return control to the user with status code 0.

We want to return status code 1 when a replay is failed since this makes the library more useful especially in CI workflows (i.e. if a replay is failed, CI will report the task to be failed as well)

So, can you restore the old behavior of throwing an error? (It's fine running all the results, I guess at the end of all runs, we can check whether there is a replay result with failure and if so throw an error -- though up to you 😂)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your feedback @ergunsh . I've restored old behavior with throwing an error but we continue to run all the recordings 🙏 What do you think about running all the recordings even though a replay has failed? @OrKoN

result.success = false;
} finally {
result.finishedAt = new Date();
results.push(result);

await browser?.close();
}
}

if (opts.log) {
const statusReport = createStatusReport(results);
console.log(statusReport.toString());
}

if (results.every((result) => result.success)) return;

throw new Error('Some recordings have failed to run.');
}
43 changes: 43 additions & 0 deletions test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {
createStatusReport,
runFiles,
getHeadlessEnvVar,
getRecordingPaths,
Expand All @@ -23,6 +24,8 @@ import {
import { assert } from 'chai';
import path from 'path';
import url from 'url';
import { HorizontalTableRow } from 'cli-table3';
import colors from 'colors';

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

Expand Down Expand Up @@ -114,4 +117,44 @@ describe('cli', () => {
assert.isTrue(files.every((file) => file.endsWith('.json')));
});
});

describe('createStatusReport', () => {
it('is able to create a successful status report', () => {
const date = new Date();
const result = {
startedAt: date,
file: path.join(__dirname, 'resources', 'replay-fail.json'),
finishedAt: new Date(date.getTime() + 1000),
success: true,
title: 'Test run',
};
const [statusReport] = createStatusReport([result]);
const [title, status, file, duration] =
statusReport as HorizontalTableRow;

assert.strictEqual(status, colors.white.bgGreen(' Success '));
assert.strictEqual(duration, '1000ms');
assert.isString(file);
assert.strictEqual(title, result.title);
});

it('is able to create a failed status report', () => {
const date = new Date();
const result = {
startedAt: date,
file: path.join(__dirname, 'resources', 'replay-fail.json'),
finishedAt: date,
success: false,
title: 'Test run',
};
const [statusReport] = createStatusReport([result]);
const [title, status, file, duration] =
statusReport as HorizontalTableRow;

assert.strictEqual(status, colors.white.bgRed(' Failure '));
assert.strictEqual(duration, '0ms');
assert.isString(file);
assert.strictEqual(title, result.title);
});
});
});