Skip to content

Commit 775f265

Browse files
committed
refactor(coverage): simplify coverage config, remove plugin and filter script
Replace the custom sourceResolverPlugin with vitest's built-in resolve.conditions: ['source'] which works with the "source" export conditions already in package.json. Remove the filter.mjs post-processing script and simplify cover.mjs to just run vitest with --coverage. Coverage numbers unchanged: 81% lines, 70% branches, 89% functions.
1 parent d69e116 commit 775f265

3 files changed

Lines changed: 49 additions & 460 deletions

File tree

.config/vitest.config.mts

Lines changed: 20 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -2,93 +2,40 @@
22
* @fileoverview Vitest configuration for socket-lib
33
*/
44

5-
import fs from 'node:fs'
65
import path from 'node:path'
76
import { fileURLToPath } from 'node:url'
87
import process from 'node:process'
98
import { defineConfig } from 'vitest/config'
109

11-
import type { Plugin } from 'vitest/config'
12-
1310
const __dirname = path.dirname(fileURLToPath(import.meta.url))
1411
const projectRoot = path.resolve(__dirname, '..')
1512

1613
// Normalize paths for cross-platform glob patterns (forward slashes on Windows)
1714
const 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-
8416
const 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: [/@socketsecurity\/lib/, '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

Comments
 (0)