Skip to content

Commit

Permalink
don't block command when storing snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsDenBakker committed Jun 19, 2022
1 parent eec1182 commit a3d2c81
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 12 deletions.
60 changes: 54 additions & 6 deletions packages/test-runner-commands/src/snapshotPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { TestRunnerPlugin } from '@web/test-runner-core';
import { ServerStartParams } from '@web/dev-server-core';
import path from 'path';
import fs from 'fs';
import { promisify } from 'util';
Expand Down Expand Up @@ -46,6 +47,7 @@ function getSnapshotPath(testFile: string) {

class SnapshotStore {
private snapshots = new Map<string, string>();
private sessionToSnapshotPath = new Map<string, string>();
private readOperations = new Map<string, { promise: Promise<void>; resolve: () => void }>();

async get(testFilePath: string): Promise<string> {
Expand All @@ -56,17 +58,17 @@ class SnapshotStore {
await this.readOperations.get(snapshotPath)?.promise;
}

if (this.snapshots.has(testFilePath)) {
const cachedContent = this.snapshots.get(snapshotPath);
if (cachedContent) {
// return from cache
return this.snapshots.get(testFilePath)!;
return cachedContent;
}

const promiseObj = { resolve: () => {}, promise: Promise.resolve() };
promiseObj.promise = new Promise<void>(resolve => {
promiseObj.resolve = resolve;
});
this.readOperations.set(testFilePath, promiseObj);

// store in cache
const content = (await fileExists(snapshotPath))
? await readFile(snapshotPath, 'utf-8')
Expand All @@ -79,7 +81,12 @@ class SnapshotStore {
return content;
}

async saveSnapshot(testFilePath: string, name: string, updatedSnapshot: string) {
async saveSnapshot(
sessionId: string,
testFilePath: string,
name: string,
updatedSnapshot: string,
) {
const snapshotPath = getSnapshotPath(testFilePath);
const nameStr = JSON.stringify(name);
const startMarker = `snapshots[${nameStr}]`;
Expand All @@ -88,7 +95,7 @@ class SnapshotStore {
? `${startMarker} = \n\`${updatedSnapshot}\`;\n${endMarker}`
: '';

const content = await this.get(snapshotPath);
const content = await this.get(testFilePath);
let updatedContent: string;

const startIndex = content.indexOf(startMarker);
Expand All @@ -107,8 +114,24 @@ class SnapshotStore {
// add new snapshot
updatedContent = `${content}${replacement}`;
}
if (updatedContent === content) {
// snapshot did not actually change, avoid marking snapshot as dirty
return;
}

this.sessionToSnapshotPath.set(sessionId, snapshotPath);
this.snapshots.set(snapshotPath, updatedContent);
}

getSnapshotPathForSession(sessionId: string) {
return this.sessionToSnapshotPath.get(sessionId);
}

async writeSnapshot(snapshotPath: string) {
const updatedContent = this.snapshots.get(snapshotPath);
if (!updatedContent) {
throw new Error('Unexpected error while writing snapshots, could not find snapshot content.');
}
if (updatedContent.includes('/* end snapshot')) {
// update or create snapshot
const fileDir = path.dirname(snapshotPath);
Expand All @@ -130,10 +153,35 @@ export interface SnapshotPluginConfig {
export function snapshotPlugin(config?: SnapshotPluginConfig): TestRunnerPlugin {
const updateSnapshots = config && config.updateSnapshots;
const snapshots = new SnapshotStore();
const writePromises = new Set<Promise<void>>();

return {
name: 'file-commands',

serverStart({ webSockets }: ServerStartParams) {
webSockets!.on('message', async ({ data }) => {
const { type, sessionId } = data;
if (type === 'wtr-session-finished') {
if (typeof sessionId !== 'string') {
throw new Error('Missing session id in wtr-session-finished event');
}
const snapshotPath = snapshots.getSnapshotPathForSession(sessionId);
if (!snapshotPath) {
return;
}
const writePromise = snapshots.writeSnapshot(snapshotPath);
writePromises.add(writePromise);
await writePromise;
writePromises.delete(writePromise);
}
});
},

async serverStop() {
// ensure all write operations are finished
await Promise.all([...writePromises]);
},

async executeCommand({ command, payload, session }) {
if (command === 'get-snapshot-config') {
return { updateSnapshots };
Expand All @@ -149,7 +197,7 @@ export function snapshotPlugin(config?: SnapshotPluginConfig): TestRunnerPlugin
throw new Error('Invalid save snapshot payload');
}

await snapshots.saveSnapshot(session.testFile, payload.name, payload.content);
await snapshots.saveSnapshot(session.id, session.testFile, payload.name, payload.content);
return true;
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* @web/test-runner snapshot v1 */

export const snapshots = {};

snapshots['persistent-a'] = `this is snapshot A`;
Expand Down
7 changes: 5 additions & 2 deletions packages/test-runner-core/src/runner/TestRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,12 @@ export class TestRunner extends EventEmitter<EventMap> {

this.stopped = true;
await this.scheduler.stop();
this.server.stop().catch(error => {

const stopActions = [];
const stopServerAction = this.server.stop().catch(error => {
console.error(error);
});
stopActions.push(stopServerAction);

if (this.config.watch) {
// we only need to stop the browsers in watch mode, in non-watch
Expand All @@ -173,8 +176,8 @@ export class TestRunner extends EventEmitter<EventMap> {
);
}
}
await Promise.all(stopActions);
}
await Promise.all(stopActions);
this.emit('stopped', this.passed);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["snapshot-a"] =
`some snapshot A1`;
/* end snapshot snapshot-a */

snapshots["snapshot-b"] =
`some snapshot B1`;
/* end snapshot snapshot-b */

snapshots["snapshot-c"] =
`some snapshot C1`;
/* end snapshot snapshot-c */

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["snapshot-a"] =
`some snapshot A2`;
/* end snapshot snapshot-a */

snapshots["snapshot-b"] =
`some snapshot B2`;
/* end snapshot snapshot-b */

snapshots["snapshot-c"] =
`some snapshot C2`;
/* end snapshot snapshot-c */

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["snapshot-a"] =
`some snapshot A3`;
/* end snapshot snapshot-a */

snapshots["snapshot-b"] =
`some snapshot B3`;
/* end snapshot snapshot-b */

snapshots["snapshot-c"] =
`some snapshot C3`;
/* end snapshot snapshot-c */

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["snapshot-a"] =
`some snapshot A4`;
/* end snapshot snapshot-a */

snapshots["snapshot-b"] =
`some snapshot B4`;
/* end snapshot snapshot-b */

snapshots["snapshot-c"] =
`some snapshot C4`;
/* end snapshot snapshot-c */

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["snapshot-a"] =
`some snapshot A5`;
/* end snapshot snapshot-a */

snapshots["snapshot-b"] =
`some snapshot B5`;
/* end snapshot snapshot-b */

snapshots["snapshot-c"] =
`some snapshot C5`;
/* end snapshot snapshot-c */

13 changes: 13 additions & 0 deletions packages/test-runner/demo/test/pass-snapshot-1.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { compareSnapshot, removeSnapshot } from '@web/test-runner-commands';

it('can test snapshot A', async () => {
await compareSnapshot({ name: 'snapshot-a', content: 'some snapshot A1' });
});

it('can test snapshot B', async () => {
await compareSnapshot({ name: 'snapshot-b', content: 'some snapshot B1' });
});

it('can test snapshot C', async () => {
await compareSnapshot({ name: 'snapshot-c', content: 'some snapshot C1' });
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { compareSnapshot } from '@web/test-runner-commands';

it('can test snapshot A', async () => {
await compareSnapshot({ name: 'snapshot-a', content: 'some snapshot A' });
await compareSnapshot({ name: 'snapshot-a', content: 'some snapshot A2' });
});

it('can test snapshot B', async () => {
await compareSnapshot({ name: 'snapshot-b', content: 'some snapshot B' });
await compareSnapshot({ name: 'snapshot-b', content: 'some snapshot B2' });
});

it('can test snapshot C', async () => {
await compareSnapshot({ name: 'snapshot-c', content: 'some snapshot B' });
await compareSnapshot({ name: 'snapshot-c', content: 'some snapshot C2' });
});
13 changes: 13 additions & 0 deletions packages/test-runner/demo/test/pass-snapshot-3.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { compareSnapshot } from '@web/test-runner-commands';

it('can test snapshot A', async () => {
await compareSnapshot({ name: 'snapshot-a', content: 'some snapshot A3' });
});

it('can test snapshot B', async () => {
await compareSnapshot({ name: 'snapshot-b', content: 'some snapshot B3' });
});

it('can test snapshot C', async () => {
await compareSnapshot({ name: 'snapshot-c', content: 'some snapshot C3' });
});
13 changes: 13 additions & 0 deletions packages/test-runner/demo/test/pass-snapshot-4.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { compareSnapshot } from '@web/test-runner-commands';

it('can test snapshot A', async () => {
await compareSnapshot({ name: 'snapshot-a', content: 'some snapshot A4' });
});

it('can test snapshot B', async () => {
await compareSnapshot({ name: 'snapshot-b', content: 'some snapshot B4' });
});

it('can test snapshot C', async () => {
await compareSnapshot({ name: 'snapshot-c', content: 'some snapshot C4' });
});
13 changes: 13 additions & 0 deletions packages/test-runner/demo/test/pass-snapshot-5.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { compareSnapshot } from '@web/test-runner-commands';

it('can test snapshot A', async () => {
await compareSnapshot({ name: 'snapshot-a', content: 'some snapshot A5' });
});

it('can test snapshot B', async () => {
await compareSnapshot({ name: 'snapshot-b', content: 'some snapshot B5' });
});

it('can test snapshot C', async () => {
await compareSnapshot({ name: 'snapshot-c', content: 'some snapshot C5' });
});

0 comments on commit a3d2c81

Please sign in to comment.