Skip to content

Commit ded874f

Browse files
committed
refactor(test): split binary test suite into separate files for clear CI output
Split single binary-test-suite.test.mts into three separate test files: - js.test.mts - JS Distribution tests (144 tests) - sea.test.mts - SEA Binary tests (144 tests) - smol.test.mts - Smol Binary tests (144 tests) Benefits: - Vitest now shows three distinct test file outputs instead of one combined - Clear visual separation in CI logs showing which binary is being tested - Each binary type shows individual pass/fail/skip status - Easier to identify which binary type has issues Implementation: - Created binary-test-helpers.mts with shared logic (prepareBinary, buildBinary) - Each test file imports helpers and defines its own binary config - All three files share identical test definitions - Removed old binary-test-suite.test.mts CI output will now show: ✓ js.test.mts (144 tests) ✓ sea.test.mts (144 tests) ⊘ smol.test.mts (skipped - not cached) Instead of: ✓ binary-test-suite.test.mts (288 tests)
1 parent e8f17ef commit ded874f

File tree

4 files changed

+5747
-0
lines changed

4 files changed

+5747
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/** @fileoverview Shared helpers for binary integration tests. */
2+
3+
import { existsSync } from 'node:fs'
4+
import path from 'node:path'
5+
import { fileURLToPath } from 'node:url'
6+
7+
import { getDefaultLogger } from '@socketsecurity/lib/logger'
8+
import { spawn } from '@socketsecurity/lib/spawn'
9+
import { confirm } from '@socketsecurity/lib/stdio/prompts'
10+
11+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
12+
13+
export const ROOT_DIR = path.resolve(__dirname, '../../..')
14+
export const MONOREPO_ROOT = path.resolve(ROOT_DIR, '../..')
15+
16+
export const logger = getDefaultLogger()
17+
18+
export interface BinaryConfig {
19+
name: string
20+
path: string
21+
buildCommand: string[] | null
22+
enabled: boolean
23+
}
24+
25+
/**
26+
* Build a binary if needed.
27+
*/
28+
export async function buildBinary(
29+
binary: BinaryConfig,
30+
binaryType: string,
31+
): Promise<boolean> {
32+
if (!binary.buildCommand) {
33+
return false
34+
}
35+
36+
logger.log(`Building ${binary.name}...`)
37+
logger.log(`Running: ${binary.buildCommand.join(' ')}`)
38+
39+
if (binaryType === 'smol') {
40+
logger.log('Note: smol build may take 30-60 minutes on first build')
41+
logger.log(' (subsequent builds are faster with caching)')
42+
}
43+
logger.log('')
44+
45+
try {
46+
const result = await spawn(
47+
binary.buildCommand[0],
48+
binary.buildCommand.slice(1),
49+
{
50+
cwd: MONOREPO_ROOT,
51+
stdio: 'inherit',
52+
},
53+
)
54+
55+
if (result.code !== 0) {
56+
logger.error(`Failed to build ${binary.name}`)
57+
return false
58+
}
59+
60+
logger.log(`Successfully built ${binary.name}`)
61+
return true
62+
} catch (e) {
63+
logger.error(`Error building ${binary.name}:`, e)
64+
return false
65+
}
66+
}
67+
68+
/**
69+
* Check and prepare binary for testing.
70+
*/
71+
export async function prepareBinary(
72+
binary: BinaryConfig,
73+
binaryType: string,
74+
): Promise<boolean> {
75+
// Log which binary we're testing.
76+
logger.log('')
77+
logger.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
78+
logger.log(`Testing: ${binary.name}`)
79+
logger.log(`Path: ${binary.path}`)
80+
logger.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
81+
82+
// Check if binary exists.
83+
let binaryExists = existsSync(binary.path)
84+
logger.log(`Binary exists: ${binaryExists}`)
85+
86+
if (!binaryExists) {
87+
logger.log('')
88+
logger.warn(`Binary not found: ${binary.path}`)
89+
90+
// In CI: Skip building (rely on cache).
91+
if (process.env.CI) {
92+
logger.log('Running in CI - skipping build (binary not in cache)')
93+
if (binaryType === 'sea') {
94+
logger.log('To build SEA binaries, run: gh workflow run build-sea.yml')
95+
} else if (binaryType === 'smol') {
96+
logger.log(
97+
'To build smol binaries, run: gh workflow run build-smol.yml',
98+
)
99+
}
100+
logger.log('')
101+
return false
102+
}
103+
104+
// Locally: Prompt user to build.
105+
const timeWarning = binaryType === 'smol' ? ' (may take 30-60 min)' : ''
106+
const shouldBuild = await confirm({
107+
default: true,
108+
message: `Build ${binary.name}?${timeWarning}`,
109+
})
110+
111+
if (!shouldBuild) {
112+
logger.log('Skipping build. Tests will be skipped.')
113+
logger.log(
114+
`To build manually, run: ${binary.buildCommand?.join(' ') ?? 'N/A'}`,
115+
)
116+
logger.log('')
117+
return false
118+
}
119+
120+
logger.log('Building binary...')
121+
const buildSuccess = await buildBinary(binary, binaryType)
122+
123+
if (buildSuccess) {
124+
binaryExists = existsSync(binary.path)
125+
}
126+
127+
if (!binaryExists) {
128+
logger.log('')
129+
logger.error(`Failed to build ${binary.name}. Tests will be skipped.`)
130+
logger.log('To build this binary manually, run:')
131+
logger.log(` ${binary.buildCommand?.join(' ') ?? 'N/A'}`)
132+
logger.log('')
133+
return false
134+
}
135+
136+
logger.log(`Binary built successfully: ${binary.path}`)
137+
logger.log('')
138+
} else {
139+
// Binary already exists.
140+
logger.log('')
141+
logger.log(`✓ Binary found and ready for testing`)
142+
logger.log('')
143+
}
144+
145+
return true
146+
}

0 commit comments

Comments
 (0)