11#!/usr/bin/env bun
22
33/**
4- * Runs Hunk's default tests concurrently without Bun's isolated parallel worker mode.
4+ * Runs Hunk's test groups concurrently without Bun's isolated parallel worker mode.
55 *
66 * Bun 1.3.14's `--parallel` implies `--isolate`, which makes OpenTUI's native FFI
77 * renderer fail to initialize with "Cannot access 'default' before initialization."
88 * Independent `--shard=N/M` processes avoid that failure, but Bun runs only the one
9- * requested shard, so this module launches and supervises every shard. Sharding stays
10- * Linux-only because the complete multi-process suite is validated and benchmarked there.
9+ * requested shard, so this module launches and supervises every shard. The default suite
10+ * shards automatically on Linux; resource-intensive PTY tests and non-Linux platforms
11+ * stay serial unless CI or a developer explicitly chooses a validated shard count.
1112 */
1213
1314import { availableParallelism } from "node:os" ;
1415
15- export const DEFAULT_TEST_PATTERNS = [
16- "./packages" ,
17- "./scripts" ,
18- "./examples" ,
19- "./test/cli" ,
20- "./test/session" ,
21- ] as const ;
16+ export const TEST_PATTERN_GROUPS = {
17+ default : [ "./packages" , "./scripts" , "./examples" , "./test/cli" , "./test/session" ] ,
18+ integration : [ "./test/pty" ] ,
19+ } as const ;
20+
21+ export const DEFAULT_TEST_PATTERNS = TEST_PATTERN_GROUPS . default ;
22+ export type TestPatternGroup = keyof typeof TEST_PATTERN_GROUPS ;
2223
2324const MAX_AUTOMATIC_TEST_SHARDS = 2 ;
2425const MAX_EXPLICIT_TEST_SHARDS = 64 ;
@@ -28,14 +29,12 @@ type KillableProcess = {
2829 kill ( signal ?: number | NodeJS . Signals ) : void ;
2930} ;
3031
31- /** Resolve a Linux shard override or choose a bounded count from the available CPUs. */
32+ /** Resolve an explicit shard override or choose a bounded Linux count from available CPUs. */
3233export function resolveTestShardCount (
3334 cpuCount : number ,
3435 override ?: string ,
3536 platform : NodeJS . Platform = process . platform ,
3637) {
37- if ( platform !== "linux" ) return 1 ;
38-
3938 if ( override !== undefined ) {
4039 const count = Number ( override ) ;
4140 if ( ! / ^ \d + $ / . test ( override ) || ! Number . isSafeInteger ( count ) || count < 1 ) {
@@ -47,23 +46,66 @@ export function resolveTestShardCount(
4746 return count ;
4847 }
4948
49+ if ( platform !== "linux" ) return 1 ;
5050 return Math . min ( MAX_AUTOMATIC_TEST_SHARDS , Math . max ( 1 , Math . floor ( cpuCount ) ) ) ;
5151}
5252
53+ /** Keep resource-intensive PTY tests serial unless the caller explicitly chooses a shard count. */
54+ export function resolveTestGroupShardCount (
55+ cpuCount : number ,
56+ override : string | undefined ,
57+ platform : NodeJS . Platform ,
58+ group : TestPatternGroup ,
59+ ) {
60+ if ( group === "integration" && override === undefined ) return 1 ;
61+ return resolveTestShardCount ( cpuCount , override , platform ) ;
62+ }
63+
64+ /** Resolve the selected test group while preserving arguments meant for Bun's test runner. */
65+ export function resolveTestInvocation ( args : string [ ] ) {
66+ const groupArguments = args . filter ( ( arg ) => arg . startsWith ( "--group=" ) ) ;
67+ if ( groupArguments . length > 1 ) {
68+ throw new Error ( "Only one --group argument may be provided" ) ;
69+ }
70+
71+ const group = ( groupArguments [ 0 ] ?. slice ( "--group=" . length ) ?? "default" ) as TestPatternGroup ;
72+ if ( ! Object . hasOwn ( TEST_PATTERN_GROUPS , group ) ) {
73+ throw new Error ( `Unknown test group: ${ group } ` ) ;
74+ }
75+
76+ return {
77+ forwardedArgs : args . filter ( ( arg ) => ! arg . startsWith ( "--group=" ) ) ,
78+ group,
79+ patterns : TEST_PATTERN_GROUPS [ group ] ,
80+ } ;
81+ }
82+
83+ /** Keep filtered runs and shared coverage output on one process. */
84+ export function requiresSerialTestExecution ( args : string [ ] ) {
85+ return args . some (
86+ ( arg ) =>
87+ arg === "-t" ||
88+ arg === "--only" ||
89+ arg . startsWith ( "--test-name-pattern" ) ||
90+ arg . startsWith ( "--coverage" ) ,
91+ ) ;
92+ }
93+
5394/** Build one Bun test command for an independent file shard. */
5495export function buildTestShardCommand (
5596 bunExecutable : string ,
5697 shard : number ,
5798 shardCount : number ,
5899 forwardedArgs : string [ ] = [ ] ,
59100 platform : NodeJS . Platform = process . platform ,
101+ patterns : readonly string [ ] = DEFAULT_TEST_PATTERNS ,
60102) {
61103 return [
62104 bunExecutable ,
63105 "test" ,
64106 ...( platform === "win32" ? [ ] : [ "--no-orphans" ] ) ,
65107 ...( shardCount > 1 ? [ `--shard=${ shard } /${ shardCount } ` ] : [ ] ) ,
66- ...DEFAULT_TEST_PATTERNS ,
108+ ...patterns ,
67109 ...forwardedArgs ,
68110 ] ;
69111}
@@ -79,19 +121,35 @@ export function terminateTestShardProcesses(processes: KillableProcess[], signal
79121 }
80122}
81123
82- /** Run the default suite in independent Bun processes without enabling Bun's isolate mode. */
124+ /** Run one test group in independent Bun processes without enabling Bun's isolate mode. */
83125export async function main ( args = Bun . argv . slice ( 2 ) ) {
84- const shardCount = resolveTestShardCount ( availableParallelism ( ) , process . env . HUNK_TEST_SHARDS ) ;
126+ const { forwardedArgs, group, patterns } = resolveTestInvocation ( args ) ;
127+ const resolvedShardCount = resolveTestGroupShardCount (
128+ availableParallelism ( ) ,
129+ process . env . HUNK_TEST_SHARDS ,
130+ process . platform ,
131+ group ,
132+ ) ;
133+ const shardCount = requiresSerialTestExecution ( forwardedArgs ) ? 1 : resolvedShardCount ;
85134 const bunExecutable = process . execPath ;
86135
87- console . error ( `Running the test suite in ${ shardCount } shard${ shardCount === 1 ? "" : "s" } ...` ) ;
136+ console . error (
137+ `Running the ${ group } test group in ${ shardCount } shard${ shardCount === 1 ? "" : "s" } ...` ,
138+ ) ;
88139
89140 const shards : Array < { proc : ReturnType < typeof Bun . spawn > ; shard : number } > = [ ] ;
90141 try {
91142 for ( let index = 0 ; index < shardCount ; index += 1 ) {
92143 const shard = index + 1 ;
93144 const proc = Bun . spawn (
94- buildTestShardCommand ( bunExecutable , shard , shardCount , args , process . platform ) ,
145+ buildTestShardCommand (
146+ bunExecutable ,
147+ shard ,
148+ shardCount ,
149+ forwardedArgs ,
150+ process . platform ,
151+ patterns ,
152+ ) ,
95153 {
96154 cwd : process . cwd ( ) ,
97155 env : { ...process . env , npm_execpath : bunExecutable } ,
0 commit comments