Skip to content

Commit 7e1d172

Browse files
test: globalSetup build once; drop fileParallelism and per-suite beforeAll builds
1 parent 8d1ef97 commit 7e1d172

5 files changed

Lines changed: 39 additions & 22 deletions

File tree

src/lib/credentials.test.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { execSync } from 'node:child_process';
21
import type { ChildProcess } from 'node:child_process';
32
import { spawn } from 'node:child_process';
43
import { mkdtempSync, statSync, readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
54
import { tmpdir } from 'node:os';
65
import { join } from 'node:path';
76
import { fileURLToPath } from 'node:url';
8-
import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
7+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
98
import {
109
DEFAULT_PROFILE,
1110
assertValidProfileName,
@@ -209,10 +208,6 @@ function spawnCredentialsWriter(profile: string, apiKey: string, path: string):
209208
}
210209

211210
describe('credentials write lock', () => {
212-
beforeAll(() => {
213-
execSync('npm run build', { cwd: projectRoot, stdio: 'pipe' });
214-
});
215-
216211
it('serializes cross-process writes so concurrent profile updates are not lost', async () => {
217212
const children = [
218213
spawnCredentialsWriter('dev', 'sk-dev', credentialsPath),

test/cli.subprocess.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,8 @@ let baseUrl: string;
3232
let tmpHome: string;
3333

3434
beforeAll(async () => {
35-
// Always rebuild — `npm run build` is fast and a stale `dist/index.js`
36-
// would silently mask ESM/import regressions in this suite. The
37-
// existsSync skip we used to do here let `dist` rot under
38-
// refactors and gave false-green on `project list` once
39-
// already.
40-
execFileSync('npm', ['run', 'build'], { cwd: REPO_ROOT, stdio: 'pipe' });
35+
// `test/global-setup.mjs` builds dist/ once before workers start (skips when
36+
// dist/index.js is newer than src/). CI also pre-builds before npm test.
4137
server = createServer((req: IncomingMessage, res: ServerResponse) => {
4238
const url = req.url ?? '/';
4339
if (url.startsWith('/api/cli/v1/projects/')) {

test/global-setup.mjs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { execSync } from 'node:child_process';
2+
import { existsSync, readdirSync, statSync } from 'node:fs';
3+
import { join } from 'node:path';
4+
import { fileURLToPath } from 'node:url';
5+
6+
const repoRoot = fileURLToPath(new URL('..', import.meta.url));
7+
const distEntry = join(repoRoot, 'dist', 'index.js');
8+
const srcDir = join(repoRoot, 'src');
9+
10+
function newestMtimeMs(dir) {
11+
let newest = 0;
12+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
13+
const path = join(dir, entry.name);
14+
if (entry.isDirectory()) {
15+
newest = Math.max(newest, newestMtimeMs(path));
16+
} else if (entry.isFile()) {
17+
newest = Math.max(newest, statSync(path).mtimeMs);
18+
}
19+
}
20+
return newest;
21+
}
22+
23+
function needsBuild() {
24+
if (!existsSync(distEntry)) return true;
25+
return newestMtimeMs(srcDir) > statSync(distEntry).mtimeMs;
26+
}
27+
28+
/** Runs once before any test file worker — shared dist/ for subprocess suites. */
29+
export default async function globalSetup() {
30+
if (!needsBuild()) return;
31+
execSync('npm run build', { cwd: repoRoot, stdio: 'inherit' });
32+
}

test/help.snapshot.test.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
*
66
* Lives under `test/`
77
* (not `src/`) to mirror the existing subprocess test pattern — the
8-
* snapshot runs the real built binary and therefore needs a build in
9-
* `beforeAll`, the same way `test/cli.subprocess.test.ts` does.
8+
* snapshot runs the real built binary; `test/global-setup.mjs` builds
9+
* `dist/` once before any worker starts.
1010
*/
1111

1212
import { execFileSync } from 'node:child_process';
1313
import { dirname, join, resolve } from 'node:path';
1414
import { fileURLToPath } from 'node:url';
15-
import { beforeAll, describe, expect, it } from 'vitest';
15+
import { describe, expect, it } from 'vitest';
1616

1717
const __dirname = dirname(fileURLToPath(import.meta.url));
1818
const REPO_ROOT = resolve(__dirname, '..');
@@ -45,10 +45,6 @@ const cases: Array<[string, string[]]> = [
4545
];
4646

4747
describe('--help snapshots', () => {
48-
beforeAll(() => {
49-
execFileSync('npm', ['run', 'build'], { cwd: REPO_ROOT, stdio: 'pipe' });
50-
});
51-
5248
for (const [name, args] of cases) {
5349
it(name, () => {
5450
const out = execFileSync('node', [BIN_PATH, ...args], {

vitest.config.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ export default defineConfig({
44
test: {
55
include: ['src/**/*.{test,spec}.ts', 'test/**/*.{test,spec}.ts'],
66
exclude: ['test/dev-e2e/**', 'test/e2e/**', 'node_modules/**', 'dist/**'],
7-
// Subprocess/snapshot suites each run `npm run build` in beforeAll; parallel
8-
// file workers can race on dist/ and produce a stale binary (exit 1 vs 5 flakes).
9-
fileParallelism: false,
7+
globalSetup: ['./test/global-setup.mjs'],
108
coverage: {
119
provider: 'v8',
1210
reporter: ['text', 'text-summary', 'json-summary', 'html'],

0 commit comments

Comments
 (0)