-
Notifications
You must be signed in to change notification settings - Fork 175
Expand file tree
/
Copy pathsnap-test.ts
More file actions
executable file
·127 lines (108 loc) · 4.32 KB
/
snap-test.ts
File metadata and controls
executable file
·127 lines (108 loc) · 4.32 KB
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
125
126
127
import cp from 'node:child_process';
import { randomUUID } from 'node:crypto';
import fs from 'node:fs';
import fsPromises from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { debuglog, parseArgs, promisify } from 'node:util';
import { isPassThroughEnv, replaceUnstableOutput } from './utils';
const debug = debuglog('vite-plus/snap-test');
const cpExec = promisify(cp.exec);
const exec = async (command: string, options: cp.ExecOptionsWithStringEncoding) =>
cpExec(
command,
process.platform === 'win32' ? { ...options, shell: 'pwsh.exe' } : options,
);
export async function snapTest() {
const { positionals } = parseArgs({
allowPositionals: true,
args: process.argv.slice(3),
});
const filter = positionals[0] ?? ''; // Optional filter to run specific test cases
// Create a unique temporary directory for testing
// On macOS, `tmpdir()` is a symlink. Resolve it so that we can replace the resolved cwd in outputs.
const tempTmpDir = `${fs.realpathSync(tmpdir())}/vite-plus-test-${randomUUID()}`;
fs.mkdirSync(tempTmpDir, { recursive: true });
// Make dependencies available in the test cases
fs.symlinkSync(
path.resolve('node_modules'),
path.join(tempTmpDir, 'node_modules'),
process.platform === 'win32' ? 'junction' : 'dir',
);
// Clean up the temporary directory on exit
process.on('exit', () => fs.rmSync(tempTmpDir, { recursive: true, force: true }));
const casesDir = path.resolve('snap-tests');
const tasks: Promise<void>[] = [];
for (const caseName of fs.readdirSync(casesDir)) {
if (caseName.startsWith('.')) continue; // Skip hidden files like .DS_Store
if (caseName.includes(filter)) {
tasks.push(runTestCase(caseName, tempTmpDir, casesDir));
}
}
if (tasks.length > 0) {
await Promise.all(tasks);
}
}
interface Steps {
ignoredPlatforms?: string[];
env: Record<string, string>;
commands: string[];
}
async function runTestCase(name: string, tempTmpDir: string, casesDir: string) {
const steps: Steps = JSON.parse(await fsPromises.readFile(`${casesDir}/${name}/steps.json`, 'utf-8'));
if (steps.ignoredPlatforms !== undefined && steps.ignoredPlatforms.includes(process.platform)) {
console.log('%s skipped on platform %s', name, process.platform);
return;
}
console.log('%s started', name);
const caseTmpDir = `${tempTmpDir}/${name}`;
await fsPromises.cp(`${casesDir}/${name}`, caseTmpDir, { recursive: true, errorOnExist: true });
const passThroughEnvs = Object.fromEntries(Object.entries(process.env).filter(([key]) => isPassThroughEnv(key)));
const env: Record<string, string> = {
...passThroughEnvs,
// Indicate CLI is running in test mode, so that it prints more detailed outputs.
VITE_PLUS_CLI_TEST: '1',
NO_COLOR: 'true',
// set CI=true make sure snap-tests are stable on GitHub Actions
CI: 'true',
// A test case can override/unset environment variables above.
// For example, VITE_PLUS_CLI_TEST/CI can be unset to test the real-world outputs.
...steps.env,
};
// Sometimes on Windows, the PATH variable is named 'Path'
if ('Path' in env && !('PATH' in env)) {
env['PATH'] = env['Path'];
delete env['Path'];
}
env['PATH'] = [
// Extend PATH to include the package's bin directory
path.resolve('bin'),
...env['PATH']!.split(path.delimiter),
].join(path.delimiter);
const newSnap: string[] = [];
for (const command of steps.commands) {
debug('running command: %s, cwd: %s, env: %o', command, caseTmpDir, env);
try {
const { stdout, stderr } = await exec(command, { env, cwd: caseTmpDir, encoding: 'utf-8' });
newSnap.push(`> ${command}`);
if (stdout) {
newSnap.push(replaceUnstableOutput(stdout, caseTmpDir));
}
if (stderr) {
newSnap.push(replaceUnstableOutput(stderr, caseTmpDir));
}
} catch (error: any) {
// add error exit code to the command
newSnap.push(`[${error.code}]> ${command}`);
if (error.stdout) {
newSnap.push(replaceUnstableOutput(error.stdout, caseTmpDir));
}
if (error.stderr) {
newSnap.push(replaceUnstableOutput(error.stderr, caseTmpDir));
}
}
}
const newSnapContent = newSnap.join('\n');
await fsPromises.writeFile(`${casesDir}/${name}/snap.txt`, newSnapContent);
console.log('%s finished', name);
}