[tests][be] Clean up fixture selection logic
--- Refactor selection logic to be easier to read; add support for .jsx test files (feels a bit weird adding a `.jsx` fixture and not seeing it get run)
Mofei Zhang committed
Nov 9, 2023 at 16:50 UTC
b25c14feb133ffad247cf5cb8358ecaebd75d962
4 files changed
+81
-54
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/tsconfig.json
+1
@@ -20,6 +20,7 @@
20
},
21
"include": [
22
"./compiler/**/*.js",
23
+ "./compiler/**/*.jsx",
24
"./compiler/**/*.ts",
25
"./compiler/**/*.tsx"
26
]
compiler/packages/fixture-test-utils/src/fixture-utils.ts
+75
-46
@@ -7,6 +7,7 @@
7
8
import fs from "fs/promises";
9
import glob from "glob";
10
+import invariant from "invariant";
11
import path from "path";
12
import { FILTER_PATH, FIXTURES_PATH } from "./constants";
13
@@ -32,6 +33,35 @@ async function exists(file: string): Promise<boolean> {
33
}
34
}
35
36
+function stripExtension(filename: string, extensions: Array<string>): string {
37
+ for (const ext of extensions) {
38
+ if (filename.endsWith(ext)) {
39
+ return filename.slice(0, -ext.length);
40
+ }
41
+ }
42
+ return filename;
43
+}
44
+
45
+function shouldSkip(
46
+ filter: TestFilter | null,
47
+ filterId: string,
48
+ filename: string
49
+) {
50
+ if (filter) {
51
+ if (filter.kind === "only" && filter.paths.indexOf(filterId) === -1) {
52
+ return true;
53
+ } else if (
54
+ filter.kind === "skip" &&
55
+ filter.paths.indexOf(filterId) !== -1
56
+ ) {
57
+ return true;
58
+ }
59
+ } else if (filename.startsWith("todo.")) {
60
+ return true;
61
+ }
62
+ return false;
63
+}
64
+
65
export async function readTestFilter(): Promise<TestFilter | null> {
66
if (!(await exists(FILTER_PATH))) {
67
throw new Error(`testfilter file not found at ${FILTER_PATH}`);
@@ -71,71 +101,70 @@ export async function readTestFilter(): Promise<TestFilter | null> {
101
102
export type TestFixture = {
103
basename: string;
74
- inputPath: string;
75
- inputExists: boolean;
104
+ inputPath: string | null;
105
outputPath: string;
106
outputExists: boolean;
107
};
108
109
+const INPUT_EXTENSIONS = [".js", ".ts", ".jsx", ".tsx"];
110
+const OUTPUT_EXTENSION = ".expect.md";
111
export function getFixtures(
112
filter: TestFilter | null
113
): Map<string, TestFixture> {
114
// search for fixtures within nested directories
84
- const files = glob.sync(`**/*.{js,ts,tsx,md}`, {
115
+ const inputFiles = glob.sync(`**/*{${INPUT_EXTENSIONS.join(",")}}`, {
116
cwd: FIXTURES_PATH,
117
});
118
const fixtures: Map<string, TestFixture> = new Map();
88
-
89
- for (const filePath of files) {
90
- const basename = path.basename(
91
- path.basename(
92
- path.basename(path.basename(filePath, ".js"), ".ts"),
93
- ".tsx"
94
- ),
95
- ".expect.md"
96
- );
97
- // "partial" paths do not include suffixes
98
- const partialRelativePath = path.join(path.dirname(filePath), basename);
99
- // Replicate jest test behavior
100
- if (basename.startsWith("todo.")) {
119
+ for (const filePath of inputFiles) {
120
+ const filename = path.basename(filePath);
121
+ // Do not include extensions in unique identifier for fixture
122
+ const partialPath = stripExtension(filePath, INPUT_EXTENSIONS);
123
+ if (shouldSkip(filter, partialPath, filename)) {
124
continue;
125
}
103
- if (filter) {
104
- if (
105
- filter.kind === "only" &&
106
- filter.paths.indexOf(partialRelativePath) === -1
107
- ) {
108
- continue;
109
- } else if (
110
- filter.kind === "skip" &&
111
- filter.paths.indexOf(partialRelativePath) !== -1
112
- ) {
113
- continue;
114
- }
115
- }
126
117
- let fixtureInfo = fixtures.get(partialRelativePath);
127
+ const fixtureInfo = fixtures.get(partialPath);
128
if (fixtureInfo === undefined) {
119
- const partialAbsolutePath = path.join(FIXTURES_PATH, partialRelativePath);
120
- fixtureInfo = {
121
- basename,
122
- inputPath: `${partialAbsolutePath}.js`,
123
- inputExists: false,
124
- outputPath: `${partialAbsolutePath}.expect.md`,
129
+ fixtures.set(partialPath, {
130
+ basename: path.basename(partialPath),
131
+ inputPath: path.join(FIXTURES_PATH, filePath),
132
+ outputPath: path.join(FIXTURES_PATH, partialPath) + OUTPUT_EXTENSION,
133
outputExists: false,
126
- };
127
- fixtures.set(partialRelativePath, fixtureInfo);
134
+ });
135
+ } else {
136
+ console.warn(
137
+ "Found duplicate fixture files: ",
138
+ fixtureInfo.inputPath,
139
+ filePath
140
+ );
141
}
142
+ }
143
130
- if (
131
- filePath.endsWith(".js") ||
132
- filePath.endsWith(".ts") ||
133
- filePath.endsWith(".tsx")
134
- ) {
135
- // inputPath may have a different file extension than the .js default
136
- fixtureInfo.inputPath = path.join(FIXTURES_PATH, filePath);
137
- fixtureInfo.inputExists = true;
144
+ const outputFiles = glob.sync(`**/*${OUTPUT_EXTENSION}`, {
145
+ cwd: FIXTURES_PATH,
146
+ });
147
+ for (const filePath of outputFiles) {
148
+ const filename = path.basename(filePath);
149
+ // Do not include extensions in unique identifier for fixture
150
+ const partialPath = stripExtension(filePath, [OUTPUT_EXTENSION]);
151
+ if (shouldSkip(filter, partialPath, filename)) {
152
+ continue;
153
+ }
154
+
155
+ const fixtureInfo = fixtures.get(partialPath);
156
+ if (fixtureInfo === undefined) {
157
+ fixtures.set(partialPath, {
158
+ basename: path.basename(partialPath),
159
+ inputPath: null,
160
+ outputPath: path.join(FIXTURES_PATH, filePath),
161
+ outputExists: true,
162
+ });
163
} else {
164
+ invariant(
165
+ fixtureInfo.outputPath === path.join(FIXTURES_PATH, filePath),
166
+ "Unexpected output filepath"
167
+ );
168
fixtureInfo.outputExists = true;
169
}
170
}
compiler/packages/snap/src/compiler-worker.ts
+2
-5
@@ -30,7 +30,6 @@ export function clearRequireCache() {
30
}
31
32
export type TestResult = {
33
- inputPath: string;
33
outputPath: string;
34
actual: string | null; // null == input did not exist
35
expected: string | null; // null == output did not exist
@@ -54,16 +53,15 @@ export async function compile(
53
clearRequireCache();
54
}
55
version = compilerVersion;
57
- const { inputPath, inputExists, outputPath, outputExists, basename } =
56
+ const { inputPath, outputPath, outputExists, basename } =
57
fixture;
59
- const input = inputExists ? await fs.readFile(inputPath, "utf8") : null;
58
+ const input = inputPath != null ? await fs.readFile(inputPath, "utf8") : null;
59
const expected = outputExists ? await fs.readFile(outputPath, "utf8") : null;
60
61
// Input will be null if the input file did not exist, in which case the output file
62
// is stale
63
if (input === null) {
64
return {
66
- inputPath,
65
outputPath,
66
actual: null,
67
expected,
@@ -128,7 +126,6 @@ export async function compile(
126
console.error = originalConsoleError;
127
128
return {
131
- inputPath,
129
outputPath,
130
actual: output,
131
expected,
compiler/packages/sprout/src/runner-worker.ts
+3
-3
@@ -191,12 +191,12 @@ export async function run(fixture: TestFixture): Promise<TestResult> {
191
console.error = (...messages: Array<string>) => {
192
seenConsoleErrors.push(...messages);
193
};
194
- const { inputPath, inputExists } = fixture;
195
- if (!inputExists) {
194
+ const { inputPath } = fixture;
195
+ if (inputPath == null) {
196
return {
197
nonForgetResult: null,
198
forgetResult: null,
199
- unexpectedError: "file did not exist!",
199
+ unexpectedError: "No input for fixture " + fixture.outputPath,
200
};
201
}
202
const inputRaw = await fs.readFile(inputPath, "utf8");