@rpcbase/test 0.308.0 → 0.310.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/clearDatabase.d.ts +2 -0
  2. package/dist/clearDatabase.d.ts.map +1 -0
  3. package/dist/clearDatabase.js +12 -0
  4. package/dist/clearDatabase.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +785 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/coverage/collect.d.ts +5 -0
  10. package/dist/coverage/collect.d.ts.map +1 -0
  11. package/dist/coverage/collect.js +113 -0
  12. package/dist/coverage/collect.js.map +1 -0
  13. package/dist/coverage/config-loader.d.ts +11 -0
  14. package/dist/coverage/config-loader.d.ts.map +1 -0
  15. package/dist/coverage/config-loader.js +292 -0
  16. package/dist/coverage/config-loader.js.map +1 -0
  17. package/dist/coverage/config.d.ts +3 -0
  18. package/dist/coverage/config.d.ts.map +1 -0
  19. package/dist/coverage/config.js +110 -0
  20. package/dist/coverage/config.js.map +1 -0
  21. package/dist/coverage/files.d.ts +4 -0
  22. package/dist/coverage/files.d.ts.map +1 -0
  23. package/dist/coverage/files.js +52 -0
  24. package/dist/coverage/files.js.map +1 -0
  25. package/dist/coverage/fixtures.d.ts +5 -0
  26. package/dist/coverage/fixtures.d.ts.map +1 -0
  27. package/dist/coverage/fixtures.js +42 -0
  28. package/dist/coverage/fixtures.js.map +1 -0
  29. package/dist/coverage/global-setup.d.ts +3 -0
  30. package/dist/coverage/global-setup.d.ts.map +1 -0
  31. package/dist/coverage/global-setup.js +18 -0
  32. package/dist/coverage/global-setup.js.map +1 -0
  33. package/dist/coverage/index.d.ts +10 -0
  34. package/dist/coverage/index.d.ts.map +1 -0
  35. package/dist/coverage/index.js +62 -0
  36. package/dist/coverage/index.js.map +1 -0
  37. package/dist/coverage/report.d.ts +7 -0
  38. package/dist/coverage/report.d.ts.map +1 -0
  39. package/{src → dist}/coverage/report.js +262 -362
  40. package/dist/coverage/report.js.map +1 -0
  41. package/dist/coverage/reporter.d.ts +16 -0
  42. package/dist/coverage/reporter.d.ts.map +1 -0
  43. package/dist/coverage/reporter.js +57 -0
  44. package/dist/coverage/reporter.js.map +1 -0
  45. package/dist/coverage/types.d.ts +47 -0
  46. package/dist/coverage/types.d.ts.map +1 -0
  47. package/dist/coverage/v8-tracker.d.ts +6 -0
  48. package/dist/coverage/v8-tracker.d.ts.map +1 -0
  49. package/dist/coverage/v8-tracker.js +166 -0
  50. package/dist/coverage/v8-tracker.js.map +1 -0
  51. package/dist/defineConfig.d.ts +3 -0
  52. package/dist/defineConfig.d.ts.map +1 -0
  53. package/dist/index.d.ts +11 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +61 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/serverCoverage.d.ts +8 -0
  58. package/dist/serverCoverage.d.ts.map +1 -0
  59. package/dist/serverCoverage.js +42 -0
  60. package/dist/serverCoverage.js.map +1 -0
  61. package/dist/vitest.config.d.ts +3 -0
  62. package/dist/vitest.config.d.ts.map +1 -0
  63. package/dist/vitest.config.js +83 -0
  64. package/dist/vitest.config.js.map +1 -0
  65. package/package.json +25 -14
  66. package/index.d.ts +0 -64
  67. package/src/clearDatabase.js +0 -19
  68. package/src/cli.js +0 -948
  69. package/src/coverage/collect.js +0 -134
  70. package/src/coverage/config-loader.js +0 -202
  71. package/src/coverage/config.js +0 -134
  72. package/src/coverage/files.js +0 -55
  73. package/src/coverage/fixtures.js +0 -37
  74. package/src/coverage/global-setup.js +0 -19
  75. package/src/coverage/index.js +0 -30
  76. package/src/coverage/reporter.js +0 -65
  77. package/src/coverage/v8-tracker.js +0 -205
  78. package/src/defineConfig.js +0 -129
  79. package/src/index.js +0 -49
  80. package/src/vitest.config.mjs +0 -107
  81. /package/{src → dist}/register-tty.cjs +0 -0
@@ -1,134 +0,0 @@
1
- import path from "node:path"
2
-
3
- import picomatch from "picomatch"
4
-
5
-
6
- export function createCollectCoverageMatcher(patterns, rootDir) {
7
- const normalizedRoot = path.resolve(String(rootDir ?? ""))
8
-
9
- const includeMatchers = []
10
- const excludeMatchers = []
11
-
12
- if (Array.isArray(patterns)) {
13
- for (const pattern of patterns) {
14
- const raw = String(pattern ?? "").trim()
15
- if (!raw) {
16
- continue
17
- }
18
-
19
- const isExclude = raw.startsWith("!")
20
- const body = toPosix(isExclude ? raw.slice(1) : raw)
21
- if (!body) {
22
- continue
23
- }
24
-
25
- const matcher = picomatch(body, { dot: true })
26
- if (isExclude) {
27
- excludeMatchers.push(matcher)
28
- } else {
29
- includeMatchers.push(matcher)
30
- }
31
- }
32
- }
33
-
34
- if (includeMatchers.length === 0) {
35
- return () => false
36
- }
37
-
38
- return (absolutePath) => {
39
- const normalizedAbsolute = path.resolve(String(absolutePath ?? ""))
40
- if (!normalizedAbsolute) {
41
- return false
42
- }
43
-
44
- const relativePosix = toPosix(path.relative(normalizedRoot, normalizedAbsolute))
45
- const absolutePosix = toPosix(normalizedAbsolute)
46
- const candidates = new Set([absolutePosix, relativePosix])
47
-
48
- if (relativePosix) {
49
- candidates.add(`./${relativePosix}`)
50
- }
51
-
52
- const candidateList = Array.from(candidates)
53
- const included = includeMatchers.some((matcher) => candidateList.some((candidate) => matcher(candidate)))
54
- if (!included) {
55
- return false
56
- }
57
-
58
- return !excludeMatchers.some((matcher) => candidateList.some((candidate) => matcher(candidate)))
59
- }
60
- }
61
-
62
- export function toPosix(input) {
63
- return String(input ?? "").split(path.sep).join("/")
64
- }
65
-
66
- export function isInsideAnyRoot(absolutePath, roots) {
67
- const normalizedAbsolute = path.resolve(String(absolutePath ?? ""))
68
- return (Array.isArray(roots) ? roots : []).some((root) => {
69
- const normalizedRoot = path.resolve(String(root ?? ""))
70
- const relative = path.relative(normalizedRoot, normalizedAbsolute)
71
- return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))
72
- })
73
- }
74
-
75
- export function resolveCollectCoverageRoots(patterns, rootDir) {
76
- const resolvedRootDir = path.resolve(String(rootDir ?? ""))
77
- const roots = new Set([resolvedRootDir])
78
-
79
- if (!Array.isArray(patterns)) {
80
- return Array.from(roots)
81
- }
82
-
83
- for (const pattern of patterns) {
84
- const raw = String(pattern ?? "").trim()
85
- if (!raw) {
86
- continue
87
- }
88
-
89
- const cleaned = raw.startsWith("!") ? raw.slice(1) : raw
90
- if (!cleaned) {
91
- continue
92
- }
93
-
94
- const prefix = staticGlobPrefix(cleaned)
95
- if (!prefix) {
96
- continue
97
- }
98
-
99
- roots.add(path.resolve(resolvedRootDir, prefix))
100
- }
101
-
102
- return Array.from(roots)
103
- }
104
-
105
- function staticGlobPrefix(pattern) {
106
- const normalized = String(pattern ?? "").trim()
107
- if (!normalized) {
108
- return null
109
- }
110
-
111
- const firstGlobIndex = findFirstGlobIndex(normalized)
112
- const prefix = firstGlobIndex === -1 ? normalized : normalized.slice(0, firstGlobIndex)
113
-
114
- if (!prefix) {
115
- return null
116
- }
117
-
118
- if (prefix.endsWith("/") || prefix.endsWith(path.sep)) {
119
- return prefix
120
- }
121
-
122
- const posix = prefix.split(path.sep).join("/")
123
- return path.posix.dirname(posix)
124
- }
125
-
126
- function findFirstGlobIndex(value) {
127
- for (let i = 0; i < value.length; i += 1) {
128
- const char = value[i]
129
- if (char === "*" || char === "?" || char === "[" || char === "{") {
130
- return i
131
- }
132
- }
133
- return -1
134
- }
@@ -1,202 +0,0 @@
1
- import fs from "node:fs/promises"
2
- import path from "node:path"
3
- import os from "node:os"
4
- import crypto from "node:crypto"
5
- import { pathToFileURL } from "node:url"
6
-
7
- import { build } from "esbuild"
8
-
9
-
10
- const DEFAULT_COVERAGE_CANDIDATES = [
11
- "spec/coverage.config.ts",
12
- "spec/coverage.config.js",
13
- "spec/coverage.config.mjs",
14
- "spec/coverage.config.cjs",
15
- "spec/coverage.config.json",
16
- ]
17
-
18
- const LEGACY_COVERAGE_CANDIDATES = [
19
- "spec/coverage.ts",
20
- "spec/coverage.js",
21
- "spec/coverage.mjs",
22
- "spec/coverage.cjs",
23
- "spec/coverage.json",
24
- ]
25
-
26
- export async function loadCoverageOptions({ optional = false, candidates = DEFAULT_COVERAGE_CANDIDATES, defaultTestResultsDir } = {}) {
27
- const projectRoot = process.cwd()
28
- const legacy = await findCoverageFile(projectRoot, LEGACY_COVERAGE_CANDIDATES)
29
- if (legacy) {
30
- const ext = path.extname(legacy)
31
- const suggested = path.join("spec", `coverage.config${ext}`)
32
- throw new Error(
33
- `Legacy coverage config detected (${path.relative(projectRoot, legacy)}). Rename it to ${suggested}.`,
34
- )
35
- }
36
-
37
- const resolved = await findCoverageFile(projectRoot, candidates)
38
-
39
- if (!resolved) {
40
- if (optional) {
41
- return null
42
- }
43
- throw new Error(
44
- "Coverage config not found. Create `spec/coverage.config.{ts,js,json}` with your coverage settings.",
45
- )
46
- }
47
-
48
- const raw = await importCoverageModule(resolved)
49
- if (!raw || typeof raw !== "object") {
50
- throw new Error(`Coverage config at ${resolved} must export an object.`)
51
- }
52
-
53
- return await normalizeOptions(raw, resolved, defaultTestResultsDir)
54
- }
55
-
56
- async function findCoverageFile(root, candidates) {
57
- for (const relative of candidates) {
58
- const candidate = path.resolve(root, relative)
59
- try {
60
- await fs.access(candidate)
61
- return candidate
62
- } catch {
63
- // continue
64
- }
65
- }
66
- return null
67
- }
68
-
69
- async function importCoverageModule(filePath) {
70
- const ext = path.extname(filePath)
71
-
72
- if (ext === ".json") {
73
- const raw = await fs.readFile(filePath, "utf8")
74
- return JSON.parse(raw)
75
- }
76
-
77
- if (ext === ".ts") {
78
- const compiledUrl = await compileTsModule(filePath)
79
- return loadModule(compiledUrl)
80
- }
81
-
82
- const moduleUrl = pathToFileURL(filePath).href
83
- return loadModule(moduleUrl)
84
- }
85
-
86
- async function compileTsModule(filePath) {
87
- const stat = await fs.stat(filePath)
88
- const hash = crypto
89
- .createHash("sha1")
90
- .update(filePath)
91
- .update(String(stat.mtimeMs))
92
- .digest("hex")
93
-
94
- const outDir = path.join(os.tmpdir(), "rpcbase-test")
95
- await fs.mkdir(outDir, { recursive: true })
96
- const outfile = path.join(outDir, `coverage-${hash}.mjs`)
97
-
98
- await build({
99
- entryPoints: [filePath],
100
- outfile,
101
- platform: "node",
102
- format: "esm",
103
- bundle: false,
104
- sourcemap: "inline",
105
- logLevel: "silent",
106
- })
107
-
108
- return pathToFileURL(outfile).href
109
- }
110
-
111
- async function loadModule(url) {
112
- const imported = await import(url)
113
- if (imported && typeof imported.default === "object") {
114
- return imported.default
115
- }
116
- return imported
117
- }
118
-
119
- const DEFAULT_COLLECT_COVERAGE_EXTENSIONS = "ts,tsx,js,jsx,mjs,cjs"
120
- const DEFAULT_COLLECT_COVERAGE_TEST_EXCLUDE = `!**/*.test.{${DEFAULT_COLLECT_COVERAGE_EXTENSIONS}}`
121
-
122
- async function resolveCollectCoverageFrom(rawPatterns, rootDir) {
123
- const resolvedRootDir = path.resolve(String(rootDir ?? ""))
124
-
125
- const normalized = Array.isArray(rawPatterns)
126
- ? rawPatterns
127
- .map((pattern) => String(pattern ?? "").trim())
128
- .filter((pattern) => pattern.length > 0)
129
- : []
130
-
131
- const excludes = normalized.filter((pattern) => pattern.startsWith("!"))
132
- const hasIncludes = normalized.some((pattern) => !pattern.startsWith("!"))
133
- if (hasIncludes) {
134
- return withDefaultExcludes(normalized)
135
- }
136
-
137
- const defaults = await inferDefaultCollectCoverageFrom(resolvedRootDir)
138
- if (defaults.length === 0) {
139
- throw new Error(
140
- "Coverage config: couldn't infer a default `collectCoverageFrom` (src/ directory missing). Provide `collectCoverageFrom` with at least one positive glob pattern.",
141
- )
142
- }
143
-
144
- return withDefaultExcludes([...defaults, ...excludes])
145
- }
146
-
147
- async function inferDefaultCollectCoverageFrom(rootDir) {
148
- const srcDir = path.join(rootDir, "src")
149
- if (await isDirectory(srcDir)) {
150
- return [`src/**/*.{${DEFAULT_COLLECT_COVERAGE_EXTENSIONS}}`]
151
- }
152
-
153
- return []
154
- }
155
-
156
- function withDefaultExcludes(patterns) {
157
- if (!Array.isArray(patterns) || patterns.length === 0) {
158
- return patterns
159
- }
160
-
161
- const hasTestExclude = patterns.some((pattern) => {
162
- const raw = String(pattern ?? "")
163
- if (!raw.startsWith("!")) {
164
- return false
165
- }
166
- return /\.test(?:\.|\{|$)/.test(raw.slice(1))
167
- })
168
- if (hasTestExclude) {
169
- return patterns
170
- }
171
-
172
- return [...patterns, DEFAULT_COLLECT_COVERAGE_TEST_EXCLUDE]
173
- }
174
-
175
- async function isDirectory(filePath) {
176
- try {
177
- const stat = await fs.stat(filePath)
178
- return stat.isDirectory()
179
- } catch {
180
- return false
181
- }
182
- }
183
-
184
- async function normalizeOptions(rawOptions, filePath, defaultTestResultsDir) {
185
- const options = { ...rawOptions }
186
- const configDir = path.dirname(filePath)
187
- const rootDir = path.resolve(configDir, "..")
188
-
189
- const collectCoverageFrom = await resolveCollectCoverageFrom(options.collectCoverageFrom, rootDir)
190
-
191
- return {
192
- rootDir,
193
- collectCoverageFrom,
194
- testResultsDir: options.testResultsDir ?? defaultTestResultsDir ?? "test-results",
195
- coverageReportSubdir: options.coverageReportSubdir ?? "coverage",
196
- coverageFileName: options.coverageFileName ?? "v8-coverage.json",
197
- includeAllFiles: options.includeAllFiles,
198
- thresholds: options.thresholds ?? {},
199
- }
200
- }
201
-
202
- export { DEFAULT_COVERAGE_CANDIDATES }
@@ -1,134 +0,0 @@
1
- import path from "node:path"
2
-
3
-
4
- const DEFAULT_THRESHOLDS = {
5
- branches: 60,
6
- functions: 75,
7
- lines: 75,
8
- statements: 75,
9
- }
10
-
11
- const THRESHOLD_KEYS = Object.keys(DEFAULT_THRESHOLDS)
12
-
13
- function resolveDir(root, target, fallback) {
14
- if (!target) {
15
- return path.resolve(root, fallback)
16
- }
17
-
18
- if (path.isAbsolute(target)) {
19
- return target
20
- }
21
-
22
- return path.resolve(root, target)
23
- }
24
-
25
- export function createCoverageConfig(options = {}) {
26
- const { rootDir } = options
27
- if (!rootDir) {
28
- throw new Error("createCoverageConfig requires a rootDir")
29
- }
30
-
31
- const resolvedRootDir = path.resolve(rootDir)
32
- const includeAllFiles = options.includeAllFiles !== false
33
-
34
- const collectCoverageFrom = Array.isArray(options.collectCoverageFrom)
35
- ? options.collectCoverageFrom
36
- .map((pattern) => String(pattern ?? "").trim())
37
- .filter((pattern) => pattern.length > 0)
38
- : []
39
-
40
- if (collectCoverageFrom.length === 0) {
41
- throw new Error("createCoverageConfig requires a collectCoverageFrom option")
42
- }
43
-
44
- const testResultsRoot = resolveDir(resolvedRootDir, options.testResultsDir, "test-results")
45
- const coverageReportDir = resolveDir(testResultsRoot, options.coverageReportSubdir, "coverage")
46
- const coverageFileName = options.coverageFileName ?? "v8-coverage.json"
47
- const disabledEnvVar = options.disabledEnvVar ?? "RB_DISABLE_COVERAGE"
48
- const coverageEnabled = process.env[disabledEnvVar] !== "1"
49
-
50
- const { global: thresholds, targets: thresholdTargets } = normalizeThresholdOptions(options.thresholds)
51
-
52
- return {
53
- rootDir: resolvedRootDir,
54
- collectCoverageFrom,
55
- testResultsRoot,
56
- coverageReportDir,
57
- coverageFileName,
58
- thresholds,
59
- thresholdTargets,
60
- coverageEnabled,
61
- disabledEnvVar,
62
- includeAllFiles,
63
- }
64
- }
65
-
66
- function normalizeThresholdOptions(rawThresholds) {
67
- const globalThresholds = { ...DEFAULT_THRESHOLDS }
68
- const targets = []
69
-
70
- if (!isPlainObject(rawThresholds)) {
71
- return { global: globalThresholds, targets }
72
- }
73
-
74
- for (const key of THRESHOLD_KEYS) {
75
- const value = rawThresholds[key]
76
- if (isThresholdValue(value)) {
77
- globalThresholds[key] = value
78
- }
79
- }
80
-
81
- if (Object.prototype.hasOwnProperty.call(rawThresholds, "global")) {
82
- if (!isPlainObject(rawThresholds.global)) {
83
- throw new Error("coverage thresholds: the `global` override must be an object of metric values")
84
- }
85
- Object.assign(globalThresholds, pickThresholdOverrides(rawThresholds.global))
86
- }
87
-
88
- for (const [pattern, overrides] of Object.entries(rawThresholds)) {
89
- if (pattern === "global" || THRESHOLD_KEYS.includes(pattern)) {
90
- continue
91
- }
92
-
93
- if (!isPlainObject(overrides)) {
94
- throw new Error(
95
- `coverage thresholds: override for "${pattern}" must be an object containing coverage metrics`,
96
- )
97
- }
98
-
99
- targets.push({
100
- id: pattern,
101
- pattern,
102
- thresholds: {
103
- ...globalThresholds,
104
- ...pickThresholdOverrides(overrides),
105
- },
106
- })
107
- }
108
-
109
- return { global: globalThresholds, targets }
110
- }
111
-
112
- function pickThresholdOverrides(source) {
113
- const overrides = {}
114
- if (!isPlainObject(source)) {
115
- return overrides
116
- }
117
-
118
- for (const key of THRESHOLD_KEYS) {
119
- const value = source[key]
120
- if (isThresholdValue(value)) {
121
- overrides[key] = value
122
- }
123
- }
124
-
125
- return overrides
126
- }
127
-
128
- function isPlainObject(value) {
129
- return value !== null && typeof value === "object" && !Array.isArray(value)
130
- }
131
-
132
- function isThresholdValue(value) {
133
- return typeof value === "number" && Number.isFinite(value)
134
- }
@@ -1,55 +0,0 @@
1
- import fs from "node:fs/promises"
2
- import path from "node:path"
3
-
4
-
5
- export async function findCoverageFiles(config, root = config.testResultsRoot) {
6
- const files = []
7
-
8
- async function walk(current) {
9
- const entries = await fs.readdir(current, { withFileTypes: true })
10
- await Promise.all(
11
- entries.map(async (entry) => {
12
- const entryPath = path.join(current, entry.name)
13
- if (entry.isDirectory()) {
14
- await walk(entryPath)
15
- } else if (entry.isFile() && entry.name === config.coverageFileName) {
16
- files.push(entryPath)
17
- }
18
- }),
19
- )
20
- }
21
-
22
- try {
23
- const stats = await fs.stat(root)
24
- if (!stats.isDirectory()) {
25
- return []
26
- }
27
- } catch {
28
- return []
29
- }
30
-
31
- await walk(root)
32
- return files.sort()
33
- }
34
-
35
- export async function removeCoverageFiles(config, root = config.testResultsRoot) {
36
- async function walk(current) {
37
- const entries = await fs.readdir(current, { withFileTypes: true })
38
- await Promise.all(
39
- entries.map(async (entry) => {
40
- const entryPath = path.join(current, entry.name)
41
- if (entry.isDirectory()) {
42
- await walk(entryPath)
43
- } else if (entry.isFile() && entry.name === config.coverageFileName) {
44
- await fs.rm(entryPath, { force: true })
45
- }
46
- }),
47
- )
48
- }
49
-
50
- try {
51
- await walk(root)
52
- } catch {
53
- // ignore cleanup errors
54
- }
55
- }
@@ -1,37 +0,0 @@
1
- import { createCoverageTracker } from "./v8-tracker.js"
2
-
3
-
4
- function noopTracker() {
5
- return {
6
- async stop() {
7
- // no-op
8
- },
9
- }
10
- }
11
-
12
- export function createCoverageFixtures(baseTest, config) {
13
- return baseTest.extend({
14
- page: async ({ page }, use, testInfo) => {
15
- let tracker = noopTracker()
16
-
17
- if (config.coverageEnabled) {
18
- try {
19
- tracker = await createCoverageTracker(page, config)
20
- } catch (error) {
21
- console.warn("[coverage] failed to initialize V8 coverage:", error)
22
- }
23
- }
24
-
25
- try {
26
- // eslint-disable-next-line react-hooks/rules-of-hooks
27
- await use(page)
28
- } finally {
29
- try {
30
- await tracker.stop(testInfo)
31
- } catch (error) {
32
- console.warn("[coverage] failed to record V8 coverage:", error)
33
- }
34
- }
35
- },
36
- })
37
- }
@@ -1,19 +0,0 @@
1
- import fs from "node:fs/promises"
2
-
3
- import { removeCoverageFiles } from "./files.js"
4
-
5
-
6
- export function createCoverageGlobalSetup(config) {
7
- return async function globalSetup() {
8
- if (process.env.RB_TEST_COMBINED_COVERAGE === "1") {
9
- return
10
- }
11
-
12
- if (!config.coverageEnabled) {
13
- return
14
- }
15
-
16
- await removeCoverageFiles(config)
17
- await fs.rm(config.coverageReportDir, { recursive: true, force: true })
18
- }
19
- }
@@ -1,30 +0,0 @@
1
- import { fileURLToPath } from "node:url"
2
-
3
- import { createCoverageConfig } from "./config.js"
4
- import { createCoverageGlobalSetup } from "./global-setup.js"
5
- import { createCoverageFixtures } from "./fixtures.js"
6
-
7
-
8
- export function createCoverageHarness(options = {}) {
9
- const config = createCoverageConfig(options)
10
- const globalSetup = createCoverageGlobalSetup(config)
11
-
12
- return {
13
- config,
14
- globalSetup,
15
- extendTest(baseTest) {
16
- return createCoverageFixtures(baseTest, config)
17
- },
18
- reporterEntry() {
19
- const reporterPath = fileURLToPath(new URL("./reporter.js", import.meta.url))
20
- return [reporterPath, { coverageConfig: config }]
21
- },
22
- }
23
- }
24
-
25
- export { CoverageReporter } from "./reporter.js"
26
- export { createCoverageConfig } from "./config.js"
27
- export { generateCoverageReport } from "./report.js"
28
- export { createCoverageFixtures } from "./fixtures.js"
29
- export { createCoverageGlobalSetup } from "./global-setup.js"
30
- export { findCoverageFiles, removeCoverageFiles } from "./files.js"
@@ -1,65 +0,0 @@
1
- import fs from "node:fs/promises"
2
-
3
- import { CoverageThresholdError, generateCoverageReport } from "./report.js"
4
- import { removeCoverageFiles } from "./files.js"
5
-
6
-
7
- class CoverageReporter {
8
- constructor(options = {}) {
9
- this.config = options.coverageConfig
10
- if (!this.config) {
11
- throw new Error("CoverageReporter requires a coverageConfig option")
12
- }
13
- }
14
-
15
- async onBegin() {
16
- if (process.env.RB_TEST_COMBINED_COVERAGE === "1") {
17
- return
18
- }
19
-
20
- if (!this.config.coverageEnabled) {
21
- return
22
- }
23
-
24
- await removeCoverageFiles(this.config)
25
- await fs.rm(this.config.coverageReportDir, { recursive: true, force: true })
26
- }
27
-
28
- async onEnd(result) {
29
- if (process.env.RB_TEST_COMBINED_COVERAGE === "1") {
30
- return
31
- }
32
-
33
- if (!this.config.coverageEnabled) {
34
- return
35
- }
36
-
37
- try {
38
- await generateCoverageReport(this.config)
39
- } catch (error) {
40
- if (error instanceof CoverageThresholdError) {
41
- console.error(error.message)
42
- setFailureExitCode(result)
43
- return
44
- }
45
-
46
- throw error
47
- }
48
- }
49
- }
50
-
51
- export { CoverageReporter }
52
- export default CoverageReporter
53
-
54
- function setFailureExitCode(result) {
55
- if (result && typeof result === "object") {
56
- result.status = "failed"
57
- if (typeof result.exitCode !== "number" || result.exitCode === 0) {
58
- result.exitCode = 1
59
- }
60
- }
61
-
62
- if (!process.exitCode || process.exitCode === 0) {
63
- process.exitCode = 1
64
- }
65
- }