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: add support for screenshot toggle #311

Merged
merged 4 commits into from
Jun 21, 2021
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: 1 addition & 1 deletion __tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('Run', () => {
foo: 'bar',
},
headless: false,
screenshots: true,
screenshots: 'on',
filmstrips: false,
trace: false,
dryRun: true,
Expand Down
2 changes: 1 addition & 1 deletion __tests__/reporters/__snapshots__/json.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ Object {
}
`;

exports[`json reporter write screenshot block & reference docs 1`] = `
exports[`json reporter screenshots write block & reference docs 1`] = `
"{\\"type\\":\\"screenshot/block\\",\\"_id\\":\\"e89af7cc2cae152df54ccf091793db64b3dfe995\\",\\"@timestamp\\":1600300800000000,\\"root_fields\\":{\\"os\\":{\\"platform\\":\\"darwin\\"},\\"package\\":{\\"name\\":\\"@elastic/synthetics\\",\\"version\\":\\"0.0.1\\"}},\\"blob\\":\\"/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCABaAKADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAj/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AKcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//9k=\\",\\"blob_mime\\":\\"image/jpeg\\",\\"package_version\\":\\"0.0.1\\"}
{\\"type\\":\\"screenshot/block\\",\\"_id\\":\\"e89af7cc2cae152df54ccf091793db64b3dfe995\\",\\"@timestamp\\":1600300800000000,\\"root_fields\\":{\\"os\\":{\\"platform\\":\\"darwin\\"},\\"package\\":{\\"name\\":\\"@elastic/synthetics\\",\\"version\\":\\"0.0.1\\"}},\\"blob\\":\\"/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCABaAKADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAj/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AKcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//9k=\\",\\"blob_mime\\":\\"image/jpeg\\",\\"package_version\\":\\"0.0.1\\"}
{\\"type\\":\\"screenshot/block\\",\\"_id\\":\\"e89af7cc2cae152df54ccf091793db64b3dfe995\\",\\"@timestamp\\":1600300800000000,\\"root_fields\\":{\\"os\\":{\\"platform\\":\\"darwin\\"},\\"package\\":{\\"name\\":\\"@elastic/synthetics\\",\\"version\\":\\"0.0.1\\"}},\\"blob\\":\\"/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCABaAKADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAj/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AKcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//9k=\\",\\"blob_mime\\":\\"image/jpeg\\",\\"package_version\\":\\"0.0.1\\"}
Expand Down
1 change: 1 addition & 0 deletions __tests__/reporters/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ describe('base reporter', () => {
error,
start: 0,
end: 1,
options: {},
});
runner.emit('end', 'done');
/**
Expand Down
114 changes: 76 additions & 38 deletions __tests__/reporters/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import JSONReporter, {
import * as helpers from '../../src/helpers';
import Runner from '../../src/core/runner';
import { NETWORK_INFO } from '../fixtures/networkinfo';
import { StatusValue } from '../../src/common_types';

/**
* Mock package version to avoid breaking JSON payload
Expand Down Expand Up @@ -123,6 +124,7 @@ describe('json reporter', () => {
status: 'succeeded',
start: 0,
end: 11,
options: {},
filmstrips: [
{
blob: 'dummy',
Expand Down Expand Up @@ -216,6 +218,7 @@ describe('json reporter', () => {
end: 1,
status: 'failed',
error: myErr,
options: {},
});

const journeyEnd = (await readAndCloseStreamJson()).find(
Expand All @@ -231,6 +234,7 @@ describe('json reporter', () => {
start: 0,
end: 1,
status: 'skipped',
options: {},
});

const journeyEnd = (await readAndCloseStreamJson()).find(
Expand Down Expand Up @@ -268,49 +272,83 @@ describe('json reporter', () => {
expect(screenshot1).toEqual(screenshot2);
});

it('write screenshot blob data', async () => {
describe('screenshots', () => {
const sourceDir = join(FIXTURES_DIR, 'screenshots');
const destDir = join(helpers.CACHE_PATH, 'screenshots');
mkdirSync(destDir, { recursive: true });
fs.copyFileSync(
join(sourceDir, 'content.json'),
join(destDir, 'content.json')
);
runner.emit('journey:end', {
journey: j1,
start: 0,
status: 'failed',
ssblocks: false,
beforeAll(() => {
mkdirSync(destDir, { recursive: true });
fs.copyFileSync(
join(sourceDir, 'content.json'),
join(destDir, 'content.json')
);
});
const stepEnd = (await readAndCloseStreamJson()).find(
json => json.type == 'step/screenshot'
);
expect(stepEnd).toMatchObject({
step: {
name: 'launch app',
index: 1,
},
blob: expect.any(String),
blob_mime: 'image/jpeg',

afterAll(() => {
fs.rmdirSync(destDir, { recursive: true });
});
fs.rmdirSync(destDir, { recursive: true });
});

it('write screenshot block & reference docs', async () => {
const sourceDir = join(FIXTURES_DIR, 'screenshots');
const destDir = join(helpers.CACHE_PATH, 'screenshots');
mkdirSync(destDir, { recursive: true });
fs.copyFileSync(
join(sourceDir, 'content.json'),
join(destDir, 'content.json')
);
runner.emit('journey:end', {
journey: j1,
start: 0,
status: 'failed',
ssblocks: true,
const emitEnd = (options, status = 'failed' as StatusValue) =>
runner.emit('journey:end', {
journey: j1,
start: 0,
status,
options,
});

it('write whole blobs data ', async () => {
emitEnd({
screenshots: 'on',
ssblocks: false,
});
const screenshotJson = (await readAndCloseStreamJson()).find(
json => json.type == 'step/screenshot'
);
expect(screenshotJson).toMatchObject({
step: {
name: 'launch app',
index: 1,
},
blob: expect.any(String),
blob_mime: 'image/jpeg',
});
});

it('write block & reference docs', async () => {
emitEnd({
screenshots: 'on',
ssblocks: true,
});
expect((await readAndCloseStream()).toString()).toMatchSnapshot();
});

it('dont write on only-on-failure for successful journey', async () => {
emitEnd(
{
screenshots: 'only-on-failure',
},
'succeeded'
);
const screenshotJson = (await readAndCloseStreamJson()).find(
json => json.type == 'step/screenshot'
);
expect(screenshotJson).not.toBeDefined();
});

it('write on only-on-failure for failed journey', async () => {
emitEnd({
screenshots: 'only-on-failure',
});
const screenshotJson = (await readAndCloseStreamJson()).find(
json => json.type == 'step/screenshot'
);
expect(screenshotJson).toMatchObject({
step: {
name: 'launch app',
index: 1,
},
blob: expect.any(String),
blob_mime: 'image/jpeg',
});
});
expect((await readAndCloseStream()).toString()).toMatchSnapshot();
fs.rmdirSync(destDir, { recursive: true });
});
});
2 changes: 2 additions & 0 deletions __tests__/reporters/junit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ describe('junit reporter', () => {
journey: j1,
start: 0,
status: 'failed',
options: {},
});
runner.emit('end', 'done');
/**
Expand Down Expand Up @@ -116,6 +117,7 @@ describe('junit reporter', () => {
journey: j1,
start: 0,
status: 'failed',
options: {},
});
runner.emit('end', 'done');
stream.end();
Expand Down
4 changes: 3 additions & 1 deletion src/common_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,15 @@ export type PluginOutput = {
metrics?: PerfMetrics;
};

export type ScreenshotOptions = 'on' | 'off' | 'only-on-failure';

export type CliArgs = {
capability?: Array<string>;
config?: string;
environment?: string;
outfd?: number;
headless?: boolean;
screenshots?: boolean;
screenshots?: ScreenshotOptions;
ssblocks?: boolean;
metrics?: boolean;
filmstrips?: boolean;
Expand Down
52 changes: 30 additions & 22 deletions src/core/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ interface Events {
JourneyResult &
PluginOutput & {
journey: Journey;
ssblocks?: boolean;
options: RunOptions;
};
'journey:end:reported': unknown;
'step:start': { journey: Journey; step: Step };
Expand Down Expand Up @@ -144,6 +144,31 @@ export default class Runner extends EventEmitter {
};
}

async captureScreenshot(page: Driver['page'], step: Step) {
await page.waitForLoadState('load');
const buffer = await page
.screenshot({
type: 'jpeg',
quality: 80,
})
.catch(() => {});
/**
* Write the screenshot image buffer with additional details (step
* information) which could be extracted at the end of
* each journey without impacting the step timing information
*/
if (buffer) {
const fileName = now().toString() + '.json';
writeFileSync(
join(this.screenshotPath, fileName),
JSON.stringify({
step,
data: buffer.toString('base64'),
})
);
}
}

addHook(type: HookType, callback: HooksCallback) {
this.hooks[type].push(callback);
}
Expand Down Expand Up @@ -207,25 +232,8 @@ export default class Runner extends EventEmitter {
data.error = error;
} finally {
data.url ??= driver.page.url();
if (screenshots) {
await driver.page.waitForLoadState('load');
const buffer = await driver.page.screenshot({
type: 'jpeg',
quality: 80,
});
/**
* Write the screenshot image buffer with additional details (step
* information) which could be extracted at the end of
* each journey without impacting the step timing information
*/
const fileName = now().toString() + '.json';
writeFileSync(
join(this.screenshotPath, fileName),
JSON.stringify({
step,
data: buffer.toString('base64'),
})
);
if (screenshots && screenshots !== 'off') {
await this.captureScreenshot(driver.page, step);
}
}
log(`Runner: end step (${step.name})`);
Expand Down Expand Up @@ -292,15 +300,15 @@ export default class Runner extends EventEmitter {
params,
start,
end: monotonicTimeInSeconds(),
ssblocks: options.ssblocks,
options,
...pluginOutput,
browserconsole: status == 'failed' ? pluginOutput.browserconsole : [],
});
/**
* Wait for the all the reported events to be consumed aschronously
* by reporter.
*/
if (options.reporter == 'json') {
if (options.reporter === 'json') {
Copy link
Contributor

Choose a reason for hiding this comment

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

Weird that the linter missed this

await once(this, 'journey:end:reported');
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/parse_args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ program
'--capability <features...>',
'Enable capabilities through feature flags'
)
.option('--screenshots', 'take screenshot for each step')
.addOption(
vigneshshanmugam marked this conversation as resolved.
Show resolved Hide resolved
new Option('--screenshots [flag]', 'take screenshots at end of each step')
.choices(['on', 'off', 'only-on-failure'])
.default('on')
)
.option('--network', 'capture network information for all journeys')
.option(
'--dry-run',
Expand Down Expand Up @@ -98,7 +102,7 @@ const options = command.opts() as CliArgs;
*/
if (options.richEvents) {
options.reporter = options.reporter ?? 'json';
options.screenshots = true;
options.screenshots = 'on';
options.network = true;
}

Expand Down
Loading