forked from ChromeDevTools/devtools-frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnapshots.ts
124 lines (105 loc) · 4.12 KB
/
snapshots.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2023 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {assert} from 'chai';
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'fs';
import {dirname} from 'path';
import {GEN_DIR, rebase, SOURCE_ROOT} from '../conductor/paths.js';
import {TestConfig} from '../conductor/test_config.js';
const UPDATE_SNAPSHOTS = TestConfig.onDiff.update;
let currentTestPath: string|undefined;
let currentTestTitle: string|undefined;
let snapshotIndex = 0;
beforeEach(function() {
if (this.currentTest) {
// The test file path is always the coloned beginning part of a test's first title.
const [describeTitle, ...otherParts] = this.currentTest.titlePath();
const [testPath, ...title] = describeTitle.split(':');
// The test path is included for every describe statement, so let's clean them.
currentTestTitle = [title.join(':'), ...otherParts.map(part => part.replaceAll(`${testPath}: `, ''))]
.map(part => part.trim())
.join(' ');
// The ITERATIONS environment variable suffixes tests after the first test,
// so we need to remove the suffix for snapshots to match.
const iterationSuffix = /( \(#[0-9]+\))$/;
const match = iterationSuffix.exec(currentTestTitle);
if (match) {
currentTestTitle = currentTestTitle.slice(0, -match[1].length);
}
currentTestPath = this.currentTest.file;
snapshotIndex = 0;
}
});
after(() => {
if (UPDATE_SNAPSHOTS) {
saveSnapshotsIfTaken();
}
});
let currentSnapshotPath: string|undefined;
let currentSnapshot: Record<string, unknown> = {};
const saveSnapshotsIfTaken = () => {
if (currentSnapshotPath !== undefined && currentSnapshot !== undefined &&
(!Array.isArray(TestConfig.onDiff.update) || TestConfig.onDiff.update.includes(currentSnapshotPath))) {
mkdirSync(dirname(currentSnapshotPath), {recursive: true});
writeFileSync(currentSnapshotPath, JSON.stringify(currentSnapshot, undefined, 2));
}
currentSnapshotPath = undefined;
currentSnapshot = {};
};
const restoreSnapshots = () => {
if (!currentSnapshotPath || !existsSync(currentSnapshotPath)) {
throw new Error(`Could not find snapshot for ${
currentSnapshotPath}. You can update the snapshots by running the tests with --on-diff=update.`);
}
currentSnapshot = JSON.parse(readFileSync(currentSnapshotPath, 'utf-8'));
};
const getSnapshotPath = (testPath: string) => {
return rebase(GEN_DIR, SOURCE_ROOT, testPath, '.json');
};
const getOrUpdateSnapshot = (value: unknown, options: SnapshotOptions) => {
if (!currentTestPath || !currentTestTitle) {
throw new Error('Not using snapshot helper in test');
}
const name = options.name ?? ++snapshotIndex;
const testName = `${currentTestTitle} - ${name}`;
const path = getSnapshotPath(currentTestPath);
if (UPDATE_SNAPSHOTS) {
if (currentSnapshotPath !== path) {
saveSnapshotsIfTaken();
currentSnapshotPath = path;
}
currentSnapshot[testName] = value;
} else {
if (currentSnapshotPath !== path) {
currentSnapshotPath = path;
restoreSnapshots();
}
}
return currentSnapshot[testName];
};
export interface SnapshotOptions {
/**
* Optional. A name to use for this snapshot. Useful for making snapshots
* order independent.
*/
name?: string;
}
/**
* Asserts that the given value matches a saved stringified version of the
* value.
*
* To update the saved version, tests must be run with UPDATE_SNAPSHOTS=1.
*
* Saved snapshots will appear in the `<test-suite-root>/snapshots` directory,
* prefixed with the path of the test.
*
* If multiple snapshots are taken in a single test, snapshots will be numbered
* and thus become order dependent. In this case, using
* {@link SnapshotOptions.name} to create named snapshots is recommended.
*
* @param value - The value to assert.
* @param options - Options to configure snapshot behavior.
*/
export const assertMatchesJSONSnapshot = (value: unknown, options: SnapshotOptions = {}) => {
assert.deepEqual(value, getOrUpdateSnapshot(value, options));
};