22 * @fileoverview Vitest configuration for socket-lib
33 */
44
5- import fs from 'node:fs'
65import path from 'node:path'
76import { fileURLToPath } from 'node:url'
87import process from 'node:process'
98import { defineConfig } from 'vitest/config'
109
11- import type { Plugin } from 'vitest/config'
12-
1310const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) )
1411const projectRoot = path . resolve ( __dirname , '..' )
1512
1613// Normalize paths for cross-platform glob patterns (forward slashes on Windows)
1714const toGlobPath = ( pathLike : string ) : string => pathLike . replaceAll ( '\\' , '/' )
1815
19- // Coverage mode detection
20- const isCoverageEnabled =
21- process . env . COVERAGE === 'true' ||
22- process . env . npm_lifecycle_event ?. includes ( 'coverage' ) ||
23- process . argv . some ( arg => arg . includes ( 'coverage' ) )
24-
25- // Vite plugin that resolves @socketsecurity /lib/* imports to src/*.ts source
26- // files and applies module aliases. Vitest's internal config hooks override
27- // resolve.alias and resolve.conditions, so we use a plugin to ensure our
28- // resolution takes effect.
29- function sourceResolverPlugin ( ) : Plugin {
30- const LIB_PREFIX = '@socketsecurity/lib/'
31- const LIB_EXACT = '@socketsecurity/lib'
32- const aliasMap : Record < string , string > = {
33- cacache : path . resolve ( projectRoot , 'src/external/cacache' ) ,
34- 'make-fetch-happen' : path . resolve (
35- projectRoot ,
36- 'src/external/make-fetch-happen' ,
37- ) ,
38- 'fast-sort' : path . resolve ( projectRoot , 'src/external/fast-sort' ) ,
39- pacote : path . resolve ( projectRoot , 'src/external/pacote' ) ,
40- '@socketregistry/scripts' : path . resolve ( projectRoot , 'scripts' ) ,
41- }
42-
43- return {
44- name : 'vitest:source-resolver' ,
45- enforce : 'pre' ,
46- resolveId ( source ) {
47- // Resolve @socketsecurity /lib/* to src/*.ts
48- if ( source . startsWith ( LIB_PREFIX ) ) {
49- const subpath = source . slice ( LIB_PREFIX . length )
50- // Try direct .ts file first, then index.ts in subdirectory
51- const directPath = path . resolve ( projectRoot , 'src' , `${ subpath } .ts` )
52- if ( fs . existsSync ( directPath ) ) return directPath
53- const indexPath = path . resolve ( projectRoot , 'src' , subpath , 'index.ts' )
54- if ( fs . existsSync ( indexPath ) ) return indexPath
55- return undefined
56- }
57- if ( source === LIB_EXACT ) {
58- return path . resolve ( projectRoot , 'src/index.ts' )
59- }
60- // Resolve aliased external dependencies
61- for ( const [ alias , target ] of Object . entries ( aliasMap ) ) {
62- if ( source === alias || source . startsWith ( `${ alias } /` ) ) {
63- const rest = source === alias ? '' : source . slice ( alias . length )
64- return `${ target } ${ rest } `
65- }
66- }
67- return undefined
68- } ,
69- // Inject 'source' export condition into ssr resolve for worker processes
70- config ( ) {
71- if ( ! isCoverageEnabled ) return undefined
72- return {
73- ssr : {
74- resolve : {
75- conditions : [ 'source' ] ,
76- externalConditions : [ 'source' ] ,
77- } ,
78- } ,
79- }
80- } ,
81- }
82- }
83-
8416const vitestConfig = defineConfig ( {
8517 cacheDir : path . resolve ( projectRoot , '.cache/vitest' ) ,
86- plugins : [ sourceResolverPlugin ( ) ] ,
8718 resolve : {
19+ // Use 'source' export condition so @socketsecurity/lib/* imports resolve
20+ // to src/*.ts instead of dist/*.js. This enables proper v8 coverage
21+ // attribution to source files.
22+ conditions : [ 'source' ] ,
8823 preserveSymlinks : false ,
89- extensions : isCoverageEnabled
90- ? [ '.ts' , '.mts' , '.cts' , '.js' , '.mjs' , '.cjs' , '.json' ]
91- : [ '.mts' , '.ts' , '.mjs' , '.js' , '.json' ] ,
24+ alias : {
25+ cacache : path . resolve ( projectRoot , 'src/external/cacache' ) ,
26+ 'make-fetch-happen' : path . resolve (
27+ projectRoot ,
28+ 'src/external/make-fetch-happen' ,
29+ ) ,
30+ 'fast-sort' : path . resolve ( projectRoot , 'src/external/fast-sort' ) ,
31+ pacote : path . resolve ( projectRoot , 'src/external/pacote' ) ,
32+ '@socketregistry/scripts' : path . resolve ( projectRoot , 'scripts' ) ,
33+ '@socketsecurity/lib/stdio/prompts' : path . resolve (
34+ projectRoot ,
35+ 'src/stdio/prompts/index.ts' ,
36+ ) ,
37+ '@socketsecurity/lib' : path . resolve ( projectRoot , 'src' ) ,
38+ } ,
9239 } ,
9340 test : {
9441 globalSetup : [ path . resolve ( __dirname , 'vitest-global-setup.mts' ) ] ,
@@ -118,58 +65,29 @@ const vitestConfig = defineConfig({
11865 : [ toGlobPath ( path . resolve ( projectRoot , 'test/npm/**' ) ) ] ) ,
11966 ] ,
12067 reporters : [ 'default' ] ,
121- // Optimize test execution for speed
122- // Use forks in CI for stability, threads locally for speed
12368 pool : process . env . CI ? 'forks' : 'threads' ,
12469 poolOptions : {
12570 threads : {
12671 maxThreads : 16 ,
12772 minThreads : 4 ,
128- // IMPORTANT: isolate: false for performance and test compatibility
129- //
130- // Tradeoff Analysis:
131- // - isolate: true = Full isolation, slower, breaks nock/module mocking
132- // - isolate: false = Shared worker context, faster, mocking works
133- //
134- // We choose isolate: false because:
135- // 1. Significant performance improvement (faster test runs)
136- // 2. HTTP mocking works correctly across all test files
137- // 3. Vi.mock() module mocking functions properly
138- // 4. Test state pollution is prevented through proper beforeEach/afterEach
139- // 5. Our tests are designed to clean up after themselves
140- // 6. The rewire module uses globalThis singleton to handle coverage module duplication
14173 isolate : false ,
14274 useAtomics : true ,
14375 } ,
14476 forks : {
145- // CI: Use forks for stability (no worker timeout issues)
146- // Limit forks in CI to prevent file system contention on Windows
14777 maxForks : process . env . CI ? 4 : 16 ,
14878 minForks : process . env . CI ? 2 : 4 ,
14979 isolate : true ,
15080 } ,
15181 } ,
152- // Increase timeouts to prevent worker timeout on slow CI environments
15382 teardownTimeout : 30_000 ,
154- // Reduce timeouts for faster failures
15583 testTimeout : 10_000 ,
15684 hookTimeout : 10_000 ,
157- // Speed optimizations
15885 sequence : {
159- // Run tests concurrently within suites locally, but sequentially in CI
160- // to prevent worker timeouts from parallel binary path resolutions
16186 concurrent : ! process . env . CI ,
16287 } ,
163- // Bail early on first failure in CI
16488 bail : process . env . CI ? 1 : 0 ,
16589 server : {
16690 deps : {
167- // Always inline @socketsecurity /lib so that CJS require() calls within
168- // dist/ bundles go through vitest's module system, enabling vi.mock()
169- // to intercept cross-module dependencies. Without inlining, Node.js
170- // native CJS loader handles require() calls, bypassing vi.mock().
171- // The rewire modules use globalThis singletons to share state across
172- // any duplicate module instances that inlining may create.
17391 inline : [ / @ s o c k e t s e c u r i t y \/ l i b / , 'zod' ] ,
17492 } ,
17593 } ,
@@ -187,22 +105,16 @@ const vitestConfig = defineConfig({
187105 'test/**' ,
188106 'packages/**' ,
189107 'perf/**' ,
190- // Exclude all dist directory and its contents
191108 'dist/**' ,
192109 '**/dist/**' ,
193110 '**/{dist,build,out}/**' ,
194- // Exclude external bundled dependencies from both src and dist
195111 'src/external/**' ,
196112 'dist/external/**' ,
197113 '**/external/**' ,
198114 'src/types.ts' ,
199115 'scripts/**' ,
200116 ] ,
201- include : [
202- 'src/**/*.{ts,mts,cts}' ,
203- // Explicitly exclude external from include
204- '!src/external/**' ,
205- ] ,
117+ include : [ 'src/**/*.{ts,mts,cts}' , '!src/external/**' ] ,
206118 excludeAfterRemap : true ,
207119 all : true ,
208120 clean : true ,
0 commit comments