Skip to content

Commit 449bcb8

Browse files
committed
Remove benchmark test and fix lint errors
- Remove benchmark.test.mts to exclude from unit test runs - Fix line-comment-position lint errors in test.mjs - Add newline buffer before npm lifecycle errors in check.mjs - Update affected-test-mapper to handle staged changes properly - Add new unified test runner script - Fix test-affected.mjs to handle new return format
1 parent ab12c64 commit 449bcb8

File tree

7 files changed

+313
-81
lines changed

7 files changed

+313
-81
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@
5555
"prepare": "husky",
5656
"prepublishOnly": "echo 'ERROR: Use GitHub Actions workflow for publishing' && exit 1",
5757
"pretest:unit": "pnpm run build",
58-
"test": "run-s check test:*",
58+
"test": "node scripts/test.mjs",
59+
"test:quick": "node scripts/test.mjs --skip-checks",
60+
"test:coverage": "node scripts/test.mjs --coverage",
61+
"test:old": "run-s check test:*",
5962
"test:affected": "node scripts/test-affected.mjs",
6063
"test:unit": "dotenvx -q run -f .env.test -- vitest --config .config/vitest.config.mts --run",
6164
"test:unit:coverage": "dotenvx -q run -f .env.test -- vitest --config .config/vitest.config.mts run --coverage",

scripts/check.mjs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* node scripts/check.mjs
1010
*/
1111

12+
import colors from 'yoctocolors-cjs'
13+
1214
import { logger } from '@socketsecurity/registry/lib/logger'
1315

1416
import { runSequence } from './utils/run-command.mjs'
@@ -35,10 +37,12 @@ async function main() {
3537
])
3638

3739
if (exitCode !== 0) {
38-
logger.error('Some checks failed')
40+
logger.error('Checks failed')
41+
// Add newline buffer before npm lifecycle error
42+
console.log('')
3943
process.exitCode = exitCode
4044
} else {
41-
logger.log('All checks passed')
45+
logger.log(colors.green('✓ All checks passed'))
4246
}
4347
} catch (error) {
4448
logger.error('Check failed:', error.message)

scripts/clean.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ async function main() {
8989

9090
if (hadError) {
9191
process.exitCode = 1
92-
} else {
93-
logger.log('Clean complete')
9492
}
9593
} catch (error) {
9694
logger.error('Clean failed:', error.message)

scripts/test-affected.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ async function main() {
6060
}
6161

6262
// Get tests to run
63-
const testsToRun = getTestsToRun({ staged, all: runAll })
63+
const testInfo = getTestsToRun({ staged, all: runAll })
64+
const { reason, tests: testsToRun } = testInfo
6465

6566
// No tests needed
6667
if (testsToRun === null) {
@@ -81,7 +82,8 @@ async function main() {
8182

8283
// Add test patterns if not running all
8384
if (testsToRun === 'all') {
84-
logger.info('Running all tests')
85+
const reasonText = reason ? ` (${reason})` : ''
86+
logger.info(`Running all tests${reasonText}`)
8587
} else {
8688
logger.info(`Running affected tests: ${testsToRun.join(', ')}`)
8789
vitestArgs.push(...testsToRun)

scripts/test.mjs

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
2+
/**
3+
* @fileoverview Unified test runner that provides a smooth, single-script experience.
4+
* Combines check, build, and test steps with clean, consistent output.
5+
*/
6+
7+
import { spawn } from 'node:child_process'
8+
import { existsSync } from 'node:fs'
9+
import path from 'node:path'
10+
import { fileURLToPath } from 'node:url'
11+
import { parseArgs } from 'node:util'
12+
13+
import colors from 'yoctocolors-cjs'
14+
15+
import WIN32 from '@socketsecurity/registry/lib/constants/WIN32'
16+
17+
import { getTestsToRun } from './utils/affected-test-mapper.mjs'
18+
19+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
20+
const rootPath = path.join(__dirname, '..')
21+
const nodeModulesBinPath = path.join(rootPath, 'node_modules', '.bin')
22+
23+
// Simple clean logging without prefixes
24+
const log = {
25+
info: msg => console.log(msg),
26+
error: msg => console.error(`${colors.red('✗')} ${msg}`),
27+
success: msg => console.log(`${colors.green('✓')} ${msg}`),
28+
step: msg => console.log(`\n${msg}`),
29+
substep: msg => console.log(` ${msg}`),
30+
progress: msg => {
31+
// Write progress message without newline for in-place updates
32+
process.stdout.write(` ∴ ${msg}`)
33+
},
34+
done: msg => {
35+
// Clear current line and write success message
36+
// Carriage return + clear line
37+
process.stdout.write('\r\x1b[K')
38+
console.log(` ${colors.green('✓')} ${msg}`)
39+
},
40+
failed: msg => {
41+
// Clear current line and write failure message
42+
// Carriage return + clear line
43+
process.stdout.write('\r\x1b[K')
44+
console.log(` ${colors.red('✗')} ${msg}`)
45+
}
46+
}
47+
48+
async function runCommand(command, args = [], options = {}) {
49+
return new Promise((resolve, reject) => {
50+
const child = spawn(command, args, {
51+
stdio: 'inherit',
52+
...(WIN32 && { shell: true }),
53+
...options,
54+
})
55+
56+
child.on('exit', code => {
57+
resolve(code || 0)
58+
})
59+
60+
child.on('error', error => {
61+
reject(error)
62+
})
63+
})
64+
}
65+
66+
async function runCheck() {
67+
log.step('Running checks')
68+
69+
// Run fix (auto-format) quietly since it has its own output
70+
log.progress('Formatting code')
71+
let exitCode = await runCommand('pnpm', ['run', 'fix'], {
72+
stdio: 'pipe'
73+
})
74+
if (exitCode !== 0) {
75+
log.failed('Formatting failed')
76+
// Re-run with output to show errors
77+
await runCommand('pnpm', ['run', 'fix'])
78+
return exitCode
79+
}
80+
log.done('Code formatted')
81+
82+
// Run ESLint to check for remaining issues
83+
log.progress('Checking ESLint')
84+
exitCode = await runCommand('eslint', [
85+
'--config',
86+
'.config/eslint.config.mjs',
87+
'--report-unused-disable-directives',
88+
'.'
89+
], {
90+
stdio: 'pipe'
91+
})
92+
if (exitCode !== 0) {
93+
log.failed('ESLint failed')
94+
// Re-run with output to show errors
95+
await runCommand('eslint', [
96+
'--config',
97+
'.config/eslint.config.mjs',
98+
'--report-unused-disable-directives',
99+
'.'
100+
])
101+
return exitCode
102+
}
103+
log.done('ESLint passed')
104+
105+
// Run TypeScript check
106+
log.progress('Checking TypeScript')
107+
exitCode = await runCommand('tsgo', [
108+
'--noEmit',
109+
'-p',
110+
'.config/tsconfig.check.json'
111+
], {
112+
stdio: 'pipe'
113+
})
114+
if (exitCode !== 0) {
115+
log.failed('TypeScript check failed')
116+
// Re-run with output to show errors
117+
await runCommand('tsgo', [
118+
'--noEmit',
119+
'-p',
120+
'.config/tsconfig.check.json'
121+
])
122+
return exitCode
123+
}
124+
log.done('TypeScript check passed')
125+
126+
return exitCode
127+
}
128+
129+
async function runBuild() {
130+
const distIndexPath = path.join(rootPath, 'dist', 'index.js')
131+
if (!existsSync(distIndexPath)) {
132+
log.step('Building project')
133+
return runCommand('pnpm', ['run', 'build'])
134+
}
135+
return 0
136+
}
137+
138+
async function runTests(options) {
139+
const { all, coverage, force, staged } = options
140+
const runAll = all || force
141+
142+
// Get tests to run
143+
const testInfo = getTestsToRun({ staged, all: runAll })
144+
const { reason, tests: testsToRun } = testInfo
145+
146+
// No tests needed
147+
if (testsToRun === null) {
148+
log.substep('No relevant changes detected, skipping tests')
149+
return 0
150+
}
151+
152+
// Prepare vitest command
153+
const vitestCmd = WIN32 ? 'vitest.cmd' : 'vitest'
154+
const vitestPath = path.join(nodeModulesBinPath, vitestCmd)
155+
156+
const vitestArgs = ['--config', '.config/vitest.config.mts', 'run']
157+
158+
// Add coverage if requested
159+
if (coverage) {
160+
vitestArgs.push('--coverage')
161+
}
162+
163+
// Add test patterns if not running all
164+
if (testsToRun === 'all') {
165+
const reasonText = reason ? ` (${reason})` : ''
166+
log.step(`Running all tests${reasonText}`)
167+
} else {
168+
log.step(`Running affected tests:`)
169+
testsToRun.forEach(test => log.substep(test))
170+
vitestArgs.push(...testsToRun)
171+
}
172+
173+
const spawnOptions = {
174+
cwd: rootPath,
175+
env: {
176+
...process.env,
177+
NODE_OPTIONS:
178+
`${process.env.NODE_OPTIONS || ''} --max-old-space-size=${process.env.CI ? 8192 : 4096}`.trim(),
179+
},
180+
stdio: 'inherit',
181+
}
182+
183+
// Use dotenvx to load test environment
184+
const dotenvxCmd = WIN32 ? 'dotenvx.cmd' : 'dotenvx'
185+
const dotenvxPath = path.join(nodeModulesBinPath, dotenvxCmd)
186+
187+
return runCommand(dotenvxPath, [
188+
'-q',
189+
'run',
190+
'-f',
191+
'.env.test',
192+
'--',
193+
vitestPath,
194+
...vitestArgs
195+
], spawnOptions)
196+
}
197+
198+
async function main() {
199+
try {
200+
// Parse arguments
201+
const { values } = parseArgs({
202+
options: {
203+
'skip-checks': {
204+
type: 'boolean',
205+
default: false,
206+
},
207+
'skip-build': {
208+
type: 'boolean',
209+
default: false,
210+
},
211+
staged: {
212+
type: 'boolean',
213+
default: false,
214+
},
215+
all: {
216+
type: 'boolean',
217+
default: false,
218+
},
219+
force: {
220+
type: 'boolean',
221+
default: false,
222+
},
223+
coverage: {
224+
type: 'boolean',
225+
default: false,
226+
},
227+
},
228+
allowPositionals: false,
229+
strict: false,
230+
})
231+
232+
console.log('═══════════════════════════════════════════════════════')
233+
console.log(' Socket PackageURL Test Runner')
234+
console.log('═══════════════════════════════════════════════════════')
235+
236+
let exitCode = 0
237+
238+
// Run checks unless skipped
239+
if (!values['skip-checks']) {
240+
exitCode = await runCheck()
241+
if (exitCode !== 0) {
242+
log.error('Checks failed')
243+
process.exitCode = exitCode
244+
return
245+
}
246+
log.success('All checks passed')
247+
}
248+
249+
// Run build unless skipped
250+
if (!values['skip-build']) {
251+
exitCode = await runBuild()
252+
if (exitCode !== 0) {
253+
log.error('Build failed')
254+
process.exitCode = exitCode
255+
return
256+
}
257+
}
258+
259+
// Run tests
260+
exitCode = await runTests(values)
261+
262+
if (exitCode !== 0) {
263+
log.error('Tests failed')
264+
process.exitCode = exitCode
265+
} else {
266+
console.log('\n═══════════════════════════════════════════════════════')
267+
log.success('All tests passed!')
268+
console.log('═══════════════════════════════════════════════════════')
269+
}
270+
} catch (error) {
271+
log.error(`Test runner failed: ${error.message}`)
272+
process.exitCode = 1
273+
}
274+
}
275+
276+
main().catch(console.error)

0 commit comments

Comments
 (0)