From 9648e62c65d2076bb08e1cae3949f39d5dc27639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Lov=C3=A9n?= <23308850+lovenm@users.noreply.github.com> Date: Sat, 29 Jan 2022 12:15:56 +0000 Subject: [PATCH] feat(test-runner-commands): make snapshot file path configurable --- .../src/snapshotPlugin.ts | 47 +++++++++++++------ .../__custom-snapshots__/custom.snap.js | 9 ++++ .../test/snapshot/snapshotPlugin.test.ts | 25 ++++++++++ .../src/__custom-snapshots__/custom.snap.js | 9 ++++ .../src/config/TestRunnerConfig.ts | 2 + .../test-runner/src/config/parseConfig.ts | 11 ++++- 6 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 packages/test-runner-commands/test/snapshot/__custom-snapshots__/custom.snap.js create mode 100644 packages/test-runner-commands/test/snapshot/src/__custom-snapshots__/custom.snap.js diff --git a/packages/test-runner-commands/src/snapshotPlugin.ts b/packages/test-runner-commands/src/snapshotPlugin.ts index 616ab0b9b..88c6e0c69 100644 --- a/packages/test-runner-commands/src/snapshotPlugin.ts +++ b/packages/test-runner-commands/src/snapshotPlugin.ts @@ -36,21 +36,27 @@ function isSaveSnapshotPayload(payload: unknown): payload is SaveSnapshotPayload return true; } -function getSnapshotPath(testFile: string) { - const testDir = path.dirname(testFile); - const testFileName = path.basename(testFile); - const ext = path.extname(testFileName); - const fileWithoutExt = testFileName.substring(0, testFileName.length - ext.length); - return path.join(testDir, '__snapshots__', `${fileWithoutExt}.snap.js`); +function getSnapshotPath(testFile: string, config?: SnapshotPluginConfig) { + let snapshotFilename: string; + + if (config?.fileName) { + snapshotFilename = config.fileName(testFile); + } else { + const testDir = path.dirname(testFile); + const testFileName = path.basename(testFile); + const ext = path.extname(testFileName); + const fileWithoutExt = testFileName.substring(0, testFileName.length - ext.length); + snapshotFilename = path.join(testDir, '__snapshots__', fileWithoutExt); + } + + return `${snapshotFilename}.snap.js`; } class SnapshotStore { private snapshots = new Map(); private readOperations = new Map; resolve: () => void }>(); - async get(testFilePath: string): Promise { - const snapshotPath = getSnapshotPath(testFilePath); - + async get(testFilePath: string, snapshotPath: string): Promise { if (this.readOperations.has(snapshotPath)) { // something else is already reading, wait for it await this.readOperations.get(snapshotPath)?.promise; @@ -79,8 +85,12 @@ class SnapshotStore { return content; } - async saveSnapshot(testFilePath: string, name: string, updatedSnapshot: string) { - const snapshotPath = getSnapshotPath(testFilePath); + async saveSnapshot( + testFilePath: string, + snapshotPath: string, + name: string, + updatedSnapshot: string, + ) { const nameStr = JSON.stringify(name); const startMarker = `snapshots[${nameStr}]`; const endMarker = `/* end snapshot ${name} */\n\n`; @@ -88,7 +98,7 @@ class SnapshotStore { ? `${startMarker} = \n\`${updatedSnapshot}\`;\n${endMarker}` : ''; - const content = await this.get(snapshotPath); + const content = await this.get(testFilePath, snapshotPath); let updatedContent: string; const startIndex = content.indexOf(startMarker); @@ -125,6 +135,13 @@ class SnapshotStore { export interface SnapshotPluginConfig { updateSnapshots?: boolean; + + /** + * Returns the name of the DOM snapshot file. The name is a path + * relative to the baseDir. By default points to a __snapshots__ + * directory next to the original test file. + */ + fileName?: (testFile: string) => string; } export function snapshotPlugin(config?: SnapshotPluginConfig): TestRunnerPlugin { @@ -140,7 +157,8 @@ export function snapshotPlugin(config?: SnapshotPluginConfig): TestRunnerPlugin } if (command === 'get-snapshots') { - const content = await snapshots.get(session.testFile); + const snapshotPath = getSnapshotPath(session.testFile, config); + const content = await snapshots.get(session.testFile, snapshotPath); return { content }; } @@ -149,7 +167,8 @@ export function snapshotPlugin(config?: SnapshotPluginConfig): TestRunnerPlugin throw new Error('Invalid save snapshot payload'); } - await snapshots.saveSnapshot(session.testFile, payload.name, payload.content); + const snapshotPath = getSnapshotPath(session.testFile, config); + await snapshots.saveSnapshot(session.testFile, snapshotPath, payload.name, payload.content); return true; } }, diff --git a/packages/test-runner-commands/test/snapshot/__custom-snapshots__/custom.snap.js b/packages/test-runner-commands/test/snapshot/__custom-snapshots__/custom.snap.js new file mode 100644 index 000000000..7d018e57a --- /dev/null +++ b/packages/test-runner-commands/test/snapshot/__custom-snapshots__/custom.snap.js @@ -0,0 +1,9 @@ +/* @web/test-runner snapshot v1 */ + +export const snapshots = {}; + +snapshots['persistent-a'] = `this is snapshot A`; +/* end snapshot persistent-a */ + +snapshots['persistent-b'] = `this is snapshot B`; +/* end snapshot persistent-b */ diff --git a/packages/test-runner-commands/test/snapshot/snapshotPlugin.test.ts b/packages/test-runner-commands/test/snapshot/snapshotPlugin.test.ts index 45454d66c..6f10cdc0b 100644 --- a/packages/test-runner-commands/test/snapshot/snapshotPlugin.test.ts +++ b/packages/test-runner-commands/test/snapshot/snapshotPlugin.test.ts @@ -28,4 +28,29 @@ describe('snapshotPlugin', function test() { plugins: [snapshotPlugin()], }); }); + + it('passes snapshot tests with a user defined snapshot path', async () => { + const fileName = (testFile: string) => + path.join(path.dirname(testFile), '__custom-snapshots__', 'custom'); + + await runTests({ + files: [path.join(__dirname, 'browser-test.js')], + browsers: [ + playwrightLauncher({ product: 'firefox' }), + playwrightLauncher({ product: 'chromium' }), + playwrightLauncher({ product: 'webkit' }), + ], + plugins: [snapshotPlugin({ fileName })], + }); + + await runTests({ + files: [path.join(__dirname, 'src', 'nested-test.js')], + browsers: [ + playwrightLauncher({ product: 'firefox' }), + playwrightLauncher({ product: 'chromium' }), + playwrightLauncher({ product: 'webkit' }), + ], + plugins: [snapshotPlugin({ fileName })], + }); + }); }); diff --git a/packages/test-runner-commands/test/snapshot/src/__custom-snapshots__/custom.snap.js b/packages/test-runner-commands/test/snapshot/src/__custom-snapshots__/custom.snap.js new file mode 100644 index 000000000..1debf1549 --- /dev/null +++ b/packages/test-runner-commands/test/snapshot/src/__custom-snapshots__/custom.snap.js @@ -0,0 +1,9 @@ +/* @web/test-runner snapshot v1 */ + +export const snapshots = {}; + +snapshots['persistent-a'] = `this is nested snapshot A`; +/* end snapshot persistent-a */ + +snapshots['persistent-b'] = `this is nested snapshot B`; +/* end snapshot persistent-b */ diff --git a/packages/test-runner/src/config/TestRunnerConfig.ts b/packages/test-runner/src/config/TestRunnerConfig.ts index cfc202d19..c78c6184c 100644 --- a/packages/test-runner/src/config/TestRunnerConfig.ts +++ b/packages/test-runner/src/config/TestRunnerConfig.ts @@ -1,5 +1,6 @@ import { TestFramework, TestRunnerCoreConfig, TestRunnerGroupConfig } from '@web/test-runner-core'; import { RollupNodeResolveOptions } from '@web/dev-server'; +import { SnapshotPluginConfig } from '@web/test-runner-commands/plugins.js'; export interface TestRunnerConfig extends Omit { groups?: string | string[] | TestRunnerGroupConfig[]; @@ -7,4 +8,5 @@ export interface TestRunnerConfig extends Omit; + snapshotConfig?: SnapshotPluginConfig; } diff --git a/packages/test-runner/src/config/parseConfig.ts b/packages/test-runner/src/config/parseConfig.ts index 261d402bf..b7fa1b5cb 100644 --- a/packages/test-runner/src/config/parseConfig.ts +++ b/packages/test-runner/src/config/parseConfig.ts @@ -166,6 +166,15 @@ export async function parseConfig( ...finalConfig.coverageConfig, }; + const updateSnapshots = + cliArgs.updateSnapshots !== undefined + ? cliArgs.updateSnapshots + : finalConfig.snapshotConfig?.updateSnapshots; + finalConfig.snapshotConfig = { + ...finalConfig.snapshotConfig, + updateSnapshots, + }; + let groupConfigs = await parseConfigGroups(finalConfig, cliArgs); if (groupConfigs.find(g => g.name === 'default')) { throw new TestRunnerStartError( @@ -254,7 +263,7 @@ export async function parseConfig( filePlugin(), sendKeysPlugin(), sendMousePlugin(), - snapshotPlugin({ updateSnapshots: !!cliArgs.updateSnapshots }), + snapshotPlugin(finalConfig.snapshotConfig), ); if (finalConfig.nodeResolve) {