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: post process screenshots for deduping #290

Merged
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,8 @@ tmp
__tests__/e2e/tmp/
__tests__/e2e/junit.xml

#Cache data by synthetics
.synthetics

.idea/
seccomp/build
2 changes: 1 addition & 1 deletion __tests__/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ describe('CLI', () => {
'testing',
]);
await cli.waitFor('journey/start');
const output = cli.output();
expect(await cli.exitCode).toBe(0);
const output = cli.output();
expect(JSON.parse(output).payload).toMatchObject({
params: { url: 'non-dev' },
});
Expand Down
10 changes: 3 additions & 7 deletions __tests__/core/runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ describe('runner', () => {
await page.goto(server.TEST_PAGE);
});
});
const runOptions = { metrics: true, screenshots: true };
const runOptions = { metrics: true };
const context = await Runner.createContext(runOptions);
await runner.registerJourney(j1, context);
const result = await runner.runSteps(j1, context, runOptions);
Expand All @@ -162,7 +162,6 @@ describe('runner', () => {
{
status: 'succeeded',
metrics: expect.any(Object),
screenshot: expect.any(String),
url: server.TEST_PAGE,
},
]);
Expand All @@ -174,7 +173,7 @@ describe('runner', () => {
await (page as any).clickkkkkk();
});
});
const runOptions = { screenshots: true };
const runOptions = {};
const context = await Runner.createContext(runOptions);
await runner.registerJourney(j1, context);
const result = await runner.runSteps(j1, context, runOptions);
Expand All @@ -184,7 +183,6 @@ describe('runner', () => {
status: 'failed',
url: 'about:blank',
error: expect.any(Error),
screenshot: expect.any(String),
},
]);
});
Expand Down Expand Up @@ -238,21 +236,19 @@ describe('runner', () => {
throw error;
});
});
const runOptions = { screenshots: true };
const runOptions = {};
const context = await Runner.createContext(runOptions);
await runner.registerJourney(j1, context);
const [step1, step2] = await runner.runSteps(j1, context, runOptions);
await Gatherer.stop();
expect(step1).toEqual({
status: 'succeeded',
url: server.TEST_PAGE,
screenshot: expect.any(String),
});
expect(step2).toEqual({
status: 'failed',
url: server.TEST_PAGE,
error,
screenshot: expect.any(String),
});
});

Expand Down
7 changes: 7 additions & 0 deletions __tests__/fixtures/screenshots/content.json

Large diffs are not rendered by default.

71 changes: 70 additions & 1 deletion __tests__/reporters/__snapshots__/json.test.ts.snap

Large diffs are not rendered by default.

78 changes: 65 additions & 13 deletions __tests__/reporters/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@
*
*/

import fs from 'fs';
import fs, { mkdirSync } from 'fs';
import { join } from 'path';
import snakeCaseKeys from 'snakecase-keys';
import { step, journey } from '../../src/core';
import JSONReporter, { formatNetworkFields } from '../../src/reporters/json';
import JSONReporter, {
formatNetworkFields,
gatherScreenshots,
getScreenshotBlocks,
} from '../../src/reporters/json';
import * as helpers from '../../src/helpers';
import Runner from '../../src/core/runner';
import { NETWORK_INFO } from '../fixtures/networkinfo';
Expand All @@ -47,6 +52,7 @@ describe('json reporter', () => {
let runner: Runner;
const timestamp = 1600300800000000;
const originalProcess = global.process;
const FIXTURES_DIR = join(__dirname, '..', 'fixtures');

beforeAll(() => {
// Mocking the process in node environment
Expand Down Expand Up @@ -75,7 +81,7 @@ describe('json reporter', () => {
/**
* Close the underlying stream writing to FD to read all the contents
*/
stream.end();
stream.once('drain', () => stream.end());
await new Promise(resolve => stream.once('finish', resolve));
const fd = fs.openSync(dest, 'r');
const buffer = fs.readFileSync(fd, 'utf-8');
Expand Down Expand Up @@ -108,7 +114,6 @@ describe('json reporter', () => {
journey: j1,
status: 'succeeded',
step: step('s1', () => {}),
screenshot: 'dummy',
url: 'dummy',
start: 0,
end: 10,
Expand Down Expand Up @@ -169,7 +174,6 @@ describe('json reporter', () => {
journey: j1,
status: 'failed',
step: step('s2', () => {}),
screenshot: 'dummy2',
url: 'dummy2',
start: 11,
end: 20,
Expand Down Expand Up @@ -207,22 +211,70 @@ describe('json reporter', () => {
expect((await readAndCloseStream()).toString()).toMatchSnapshot();
});

it('captures screenshots blob and mime type', async () => {
const data = 'aaaaaaaaaaa';
runner.emit('step:end', {
it('return empty when dir doesnt exists', async () => {
const nonExistDir = join(FIXTURES_DIR, 'blah');
const callback = jest.fn();
await gatherScreenshots(nonExistDir, callback);
expect(callback).not.toHaveBeenCalled();
});

it('idempotent on constructing screenshots blocks', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Love this!

const screenshotsDir = join(FIXTURES_DIR, 'screenshots');
const collectScreenshots = async () => {
const screenshots = [];
await gatherScreenshots(screenshotsDir, async (_, data) => {
const result = await getScreenshotBlocks(Buffer.from(data, 'base64'));
screenshots.push(result);
});
};
const screenshot1 = await collectScreenshots();
const screenshot2 = await collectScreenshots();
expect(screenshot1).toEqual(screenshot2);
});

it('write screenshot blob data', 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',
step: step('s2', () => {}),
screenshot: data,
start: 11,
end: 20,
ssblocks: false,
});
const stepEnd = (await readAndCloseStreamJson()).find(
json => json.type == 'step/screenshot'
);
expect(stepEnd).toMatchObject({
blob: data,
step: {
name: 'launch app',
index: 1,
},
blob: expect.any(String),
blob_mime: 'image/jpeg',
});
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,
});
expect((await readAndCloseStream()).toString()).toMatchSnapshot();
fs.rmdirSync(destDir, { recursive: true });
});
});
Loading