xtrm-tools 2.1.4 → 2.1.6

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 (29) hide show
  1. package/README.md +10 -4
  2. package/cli/dist/index.cjs +1562 -1392
  3. package/cli/dist/index.cjs.map +1 -1
  4. package/config/hooks.json +4 -4
  5. package/hooks/README.md +3 -3
  6. package/hooks/main-guard.mjs +10 -1
  7. package/package.json +8 -3
  8. package/project-skills/py-quality-gate/.claude/hooks/quality-check.py +15 -2
  9. package/project-skills/py-quality-gate/.claude/settings.json +1 -1
  10. package/project-skills/service-skills-set/.claude/settings.json +2 -2
  11. package/project-skills/service-skills-set/install-service-skills.py +43 -13
  12. package/project-skills/tdd-guard/.claude/hooks/tdd-guard-pretool-bridge.cjs +87 -0
  13. package/project-skills/tdd-guard/.claude/settings.json +2 -2
  14. package/project-skills/tdd-guard/README.md +6 -4
  15. package/project-skills/tdd-guard/docs/linting.md +2 -2
  16. package/project-skills/tdd-guard/reporters/jest/src/JestReporter.test-data.ts +199 -0
  17. package/project-skills/tdd-guard/reporters/jest/src/JestReporter.test.ts +302 -0
  18. package/project-skills/tdd-guard/reporters/jest/src/JestReporter.ts +201 -0
  19. package/project-skills/tdd-guard/reporters/jest/src/index.ts +4 -0
  20. package/project-skills/tdd-guard/reporters/jest/src/types.ts +42 -0
  21. package/project-skills/tdd-guard/reporters/jest/tsconfig.json +11 -0
  22. package/project-skills/tdd-guard/reporters/vitest/src/VitestReporter.test-data.ts +85 -0
  23. package/project-skills/tdd-guard/reporters/vitest/src/VitestReporter.test.ts +446 -0
  24. package/project-skills/tdd-guard/reporters/vitest/src/VitestReporter.ts +110 -0
  25. package/project-skills/tdd-guard/reporters/vitest/src/index.ts +4 -0
  26. package/project-skills/tdd-guard/reporters/vitest/src/types.ts +39 -0
  27. package/project-skills/tdd-guard/reporters/vitest/tsconfig.json +11 -0
  28. package/project-skills/ts-quality-gate/.claude/hooks/quality-check.cjs +36 -1
  29. package/project-skills/ts-quality-gate/.claude/settings.json +1 -1
@@ -0,0 +1,302 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest'
2
+ import { JestReporter } from './JestReporter'
3
+ import {
4
+ FileStorage,
5
+ MemoryStorage,
6
+ Config as TDDConfig,
7
+ DEFAULT_DATA_DIR,
8
+ } from 'tdd-guard'
9
+ import path from 'node:path'
10
+ import {
11
+ createTest,
12
+ createTestResult,
13
+ createAggregatedResult,
14
+ createUnhandledError,
15
+ createModuleError,
16
+ createTestResultWithModuleError,
17
+ } from './JestReporter.test-data'
18
+
19
+ describe('JestReporter', () => {
20
+ let sut: ReturnType<typeof setupJestReporter>
21
+
22
+ beforeEach(() => {
23
+ sut = setupJestReporter()
24
+ })
25
+
26
+ describe('constructor', () => {
27
+ it('uses FileStorage by default', () => {
28
+ const reporter = new JestReporter()
29
+ expect(reporter['storage']).toBeInstanceOf(FileStorage)
30
+ })
31
+
32
+ it('accepts Storage instance in reporterOptions', () => {
33
+ const storage = new MemoryStorage()
34
+ const globalConfig = undefined
35
+ const reporterOptions = { storage }
36
+ const reporter = new JestReporter(globalConfig, reporterOptions)
37
+ expect(reporter['storage']).toBe(storage)
38
+ })
39
+
40
+ it('accepts projectRoot string in reporterOptions', () => {
41
+ const rootPath = '/some/project/root'
42
+ const globalConfig = undefined
43
+ const reporterOptions = { projectRoot: rootPath }
44
+ const reporter = new JestReporter(globalConfig, reporterOptions)
45
+
46
+ // Verify the storage is configured with the correct path
47
+ const fileStorage = reporter['storage'] as FileStorage
48
+ const config = fileStorage['config'] as TDDConfig
49
+ const expectedDataDir = path.join(
50
+ rootPath,
51
+ ...DEFAULT_DATA_DIR.split('/')
52
+ )
53
+ expect(config.dataDir).toBe(expectedDataDir)
54
+ })
55
+ })
56
+
57
+ describe('onTestResult', () => {
58
+ it('collects test results', () => {
59
+ const test = createTest()
60
+ const testResult = createTestResult()
61
+
62
+ sut.reporter.onTestResult(test, testResult)
63
+
64
+ expect(sut.reporter['testModules'].size).toBe(1)
65
+ })
66
+ })
67
+
68
+ describe('onRunComplete', () => {
69
+ it('saves test results to storage', async () => {
70
+ const test = createTest()
71
+ const testResult = createTestResult()
72
+ const aggregatedResult = createAggregatedResult()
73
+
74
+ // Collect test results first
75
+ sut.reporter.onTestResult(test, testResult)
76
+
77
+ // Run complete
78
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
79
+
80
+ // Verify results were saved
81
+ const parsed = await sut.getParsedData()
82
+ expect(parsed).toBeTruthy()
83
+ expect(parsed.testModules).toHaveLength(1)
84
+ })
85
+
86
+ it('includes test case details in output', async () => {
87
+ const test = createTest()
88
+ const testResult = createTestResult()
89
+ const aggregatedResult = createAggregatedResult()
90
+
91
+ // Collect test results
92
+ sut.reporter.onTestResult(test, testResult)
93
+
94
+ // Run complete
95
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
96
+
97
+ // Verify test details are included
98
+ const parsed = await sut.getParsedData()
99
+ const module = parsed.testModules[0]
100
+ expect(module.tests).toHaveLength(1)
101
+ expect(module.tests[0].name).toBe('should pass')
102
+ expect(module.tests[0].fullName).toBe('Example Suite should pass')
103
+ expect(module.tests[0].state).toBe('passed')
104
+ })
105
+
106
+ it('includes error details for failed tests', async () => {
107
+ const test = createTest()
108
+ const failedTestResult = createTestResult({ numFailingTests: 1 })
109
+ const aggregatedResult = createAggregatedResult()
110
+
111
+ // Collect test results
112
+ sut.reporter.onTestResult(test, failedTestResult)
113
+
114
+ // Run complete
115
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
116
+
117
+ // Verify error details are included
118
+ const parsed = await sut.getParsedData()
119
+ const module = parsed.testModules[0]
120
+ const failedTest = module.tests[0]
121
+ expect(failedTest.state).toBe('failed')
122
+ expect(failedTest.errors).toBeDefined()
123
+ expect(failedTest.errors).toHaveLength(1)
124
+ expect(failedTest.errors[0].message).toBe('expected 2 to be 3')
125
+ })
126
+
127
+ it('handles empty test runs', async () => {
128
+ // Run complete without any tests
129
+ await sut.reporter.onRunComplete(new Set(), createAggregatedResult())
130
+
131
+ // Verify empty output
132
+ const parsed = await sut.getParsedData()
133
+ expect(parsed.testModules).toEqual([])
134
+ })
135
+
136
+ it('includes unhandled errors in output', async () => {
137
+ const error = createUnhandledError()
138
+ const aggregatedResult = createAggregatedResult({
139
+ runExecError: error,
140
+ })
141
+
142
+ // Run complete with unhandled error
143
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
144
+
145
+ // Verify unhandled errors are included
146
+ const parsed = await sut.getParsedData()
147
+ expect(parsed.unhandledErrors).toBeDefined()
148
+ expect(parsed.unhandledErrors).toHaveLength(1)
149
+ expect(parsed.unhandledErrors[0].message).toBe(
150
+ 'Cannot find module "./helpers"'
151
+ )
152
+ expect(parsed.unhandledErrors[0].name).toBe('Error')
153
+ expect(parsed.unhandledErrors[0].stack).toContain('imported from')
154
+ })
155
+
156
+ it('includes test run reason when tests pass', async () => {
157
+ const test = createTest()
158
+ const testResult = createTestResult()
159
+ const aggregatedResult = createAggregatedResult({
160
+ success: true,
161
+ numFailedTests: 0,
162
+ })
163
+
164
+ sut.reporter.onTestResult(test, testResult)
165
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
166
+
167
+ const parsed = await sut.getParsedData()
168
+ expect(parsed.reason).toBe('passed')
169
+ })
170
+
171
+ it('handles SerializableError without name property', async () => {
172
+ const aggregatedResult = createAggregatedResult({
173
+ runExecError: {
174
+ message: 'Module not found',
175
+ stack: 'at test.js:1:1',
176
+ },
177
+ })
178
+
179
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
180
+
181
+ const parsed = await sut.getParsedData()
182
+ expect(parsed.unhandledErrors[0].message).toBe('Module not found')
183
+ expect(parsed.unhandledErrors[0].name).toBe('Error')
184
+ expect(parsed.unhandledErrors[0].stack).toBe('at test.js:1:1')
185
+ })
186
+
187
+ it('includes module import errors as failed tests', async () => {
188
+ const test = createTest()
189
+ const testResult = createTestResultWithModuleError()
190
+ const aggregatedResult = createAggregatedResult()
191
+
192
+ sut.reporter.onTestResult(test, testResult)
193
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
194
+
195
+ const parsed = await sut.getParsedData()
196
+ const module = parsed.testModules[0]
197
+ expect(module.tests).toHaveLength(1)
198
+
199
+ const importErrorTest = module.tests[0]
200
+ expect(importErrorTest.name).toBe('Module failed to load (Error)')
201
+ expect(importErrorTest.fullName).toBe('Module failed to load (Error)')
202
+ expect(importErrorTest.state).toBe('failed')
203
+ expect(importErrorTest.errors).toHaveLength(1)
204
+ expect(importErrorTest.errors[0].message).toBe(
205
+ "Cannot find module './non-existent-module'"
206
+ )
207
+ })
208
+
209
+ it('preserves error stack trace from module import errors', async () => {
210
+ const test = createTest()
211
+ const moduleError = createModuleError({
212
+ message: "Cannot find module './helpers'",
213
+ stack:
214
+ "Error: Cannot find module './helpers'\n at Function.Module._resolveFilename",
215
+ name: 'Error',
216
+ })
217
+ const testResult = createTestResultWithModuleError({
218
+ testExecError: moduleError,
219
+ })
220
+ const aggregatedResult = createAggregatedResult()
221
+
222
+ sut.reporter.onTestResult(test, testResult)
223
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
224
+
225
+ const parsed = await sut.getParsedData()
226
+ const importErrorTest = parsed.testModules[0].tests[0]
227
+
228
+ expect(importErrorTest.errors[0].stack).toBe(
229
+ "Error: Cannot find module './helpers'\n at Function.Module._resolveFilename"
230
+ )
231
+ expect(importErrorTest.errors[0].name).toBe('Error')
232
+ })
233
+
234
+ it('uses error type in test name for module import errors', async () => {
235
+ const test = createTest()
236
+ const testResult = createTestResultWithModuleError({
237
+ testExecError: createModuleError({
238
+ message: 'Module parse failed',
239
+ stack: 'SyntaxError: Unexpected token',
240
+ name: 'SyntaxError',
241
+ }),
242
+ })
243
+ const aggregatedResult = createAggregatedResult()
244
+
245
+ sut.reporter.onTestResult(test, testResult)
246
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
247
+
248
+ const parsed = await sut.getParsedData()
249
+ const importErrorTest = parsed.testModules[0].tests[0]
250
+
251
+ expect(importErrorTest.name).toBe('Module failed to load (SyntaxError)')
252
+ expect(importErrorTest.fullName).toBe(
253
+ 'Module failed to load (SyntaxError)'
254
+ )
255
+ })
256
+
257
+ it('handles SerializableError with type field for module import errors', async () => {
258
+ const test = createTest()
259
+ const testResult = createTestResultWithModuleError({
260
+ testExecError: createModuleError({
261
+ message: 'Module error',
262
+ stack: 'at test.js:1',
263
+ type: 'ReferenceError',
264
+ code: 'ERR_MODULE_NOT_FOUND',
265
+ }),
266
+ })
267
+ const aggregatedResult = createAggregatedResult()
268
+
269
+ sut.reporter.onTestResult(test, testResult)
270
+ await sut.reporter.onRunComplete(new Set(), aggregatedResult)
271
+
272
+ const parsed = await sut.getParsedData()
273
+ const importErrorTest = parsed.testModules[0].tests[0]
274
+
275
+ expect(importErrorTest.name).toBe(
276
+ 'Module failed to load (ReferenceError)'
277
+ )
278
+ expect(importErrorTest.errors[0].name).toBe('ReferenceError')
279
+ expect(importErrorTest.errors[0].operator).toBe('ERR_MODULE_NOT_FOUND')
280
+ })
281
+ })
282
+ })
283
+
284
+ // Test setup helper function
285
+ function setupJestReporter() {
286
+ const storage = new MemoryStorage()
287
+ const globalConfig = undefined
288
+ const reporterOptions = { storage }
289
+ const reporter = new JestReporter(globalConfig, reporterOptions)
290
+
291
+ // Helper to get parsed test data
292
+ const getParsedData = async () => {
293
+ const savedData = await storage.getTest()
294
+ return savedData ? JSON.parse(savedData) : null
295
+ }
296
+
297
+ return {
298
+ reporter,
299
+ storage,
300
+ getParsedData,
301
+ }
302
+ }
@@ -0,0 +1,201 @@
1
+ import { BaseReporter, Config } from '@jest/reporters'
2
+ import type { Test, TestResult, AggregatedResult } from '@jest/reporters'
3
+ import type { AssertionResult } from '@jest/test-result'
4
+ import type { TestContext } from '@jest/test-result'
5
+ import { Storage, FileStorage, Config as TDDConfig } from 'tdd-guard'
6
+ import type {
7
+ TDDGuardReporterOptions,
8
+ CapturedError,
9
+ CapturedTest,
10
+ CapturedTestRun,
11
+ CapturedUnhandledError,
12
+ CapturedModule,
13
+ } from './types'
14
+
15
+ export class JestReporter extends BaseReporter {
16
+ private readonly storage: Storage
17
+ private readonly testModules: Map<
18
+ string,
19
+ { test: Test; testResult: TestResult }
20
+ > = new Map()
21
+
22
+ constructor(
23
+ _globalConfig?: Config.GlobalConfig,
24
+ reporterOptions?: TDDGuardReporterOptions
25
+ ) {
26
+ super()
27
+ this.storage = this.initializeStorage(reporterOptions)
28
+ }
29
+
30
+ private initializeStorage(options?: TDDGuardReporterOptions): Storage {
31
+ if (options?.storage) {
32
+ return options.storage
33
+ }
34
+
35
+ if (options?.projectRoot) {
36
+ const config = new TDDConfig({ projectRoot: options.projectRoot })
37
+ return new FileStorage(config)
38
+ }
39
+
40
+ return new FileStorage()
41
+ }
42
+
43
+ override onTestResult(test: Test, testResult: TestResult): void {
44
+ this.testModules.set(test.path, { test, testResult })
45
+ }
46
+
47
+ override async onRunComplete(
48
+ _contexts: Set<TestContext>,
49
+ results: AggregatedResult
50
+ ): Promise<void> {
51
+ const output: CapturedTestRun = {
52
+ testModules: this.buildTestModules(),
53
+ unhandledErrors: this.buildUnhandledErrors(results),
54
+ reason: this.determineTestRunReason(results),
55
+ }
56
+
57
+ await this.storage.saveTest(JSON.stringify(output, null, 2))
58
+ }
59
+
60
+ private determineTestRunReason(
61
+ results: AggregatedResult
62
+ ): 'passed' | 'failed' | 'interrupted' {
63
+ if (results.wasInterrupted) {
64
+ return 'interrupted'
65
+ }
66
+
67
+ if (results.numFailedTestSuites === 0 && results.numTotalTestSuites > 0) {
68
+ return 'passed'
69
+ }
70
+
71
+ return 'failed'
72
+ }
73
+
74
+ private mapTestResult(test: AssertionResult): CapturedTest {
75
+ const result: CapturedTest = {
76
+ name: test.title,
77
+ fullName: test.fullName,
78
+ state: test.status,
79
+ }
80
+
81
+ // Process failure details if present
82
+ if (test.failureMessages.length > 0) {
83
+ result.errors = this.processTestErrors(test)
84
+ }
85
+
86
+ return result
87
+ }
88
+
89
+ private processTestErrors(test: AssertionResult): CapturedError[] {
90
+ if (test.failureDetails.length === 0) {
91
+ return test.failureMessages.map((message) => ({ message }))
92
+ }
93
+
94
+ return test.failureDetails.map((detail: unknown, index: number) => {
95
+ const message = test.failureMessages[index] || ''
96
+ const error: CapturedError = { message }
97
+
98
+ if (detail && typeof detail === 'object') {
99
+ this.extractErrorDetails(error, detail as Record<string, unknown>)
100
+ this.parseExpectedActualFromMessage(error, message)
101
+ }
102
+
103
+ return error
104
+ })
105
+ }
106
+
107
+ private extractErrorDetails(
108
+ error: CapturedError,
109
+ obj: Record<string, unknown>
110
+ ): void {
111
+ if ('actual' in obj) error.actual = String(obj.actual)
112
+ if ('expected' in obj) error.expected = String(obj.expected)
113
+ if ('showDiff' in obj) error.showDiff = Boolean(obj.showDiff)
114
+ if ('operator' in obj) error.operator = String(obj.operator)
115
+ if ('diff' in obj) error.diff = String(obj.diff)
116
+ if ('name' in obj) error.name = String(obj.name)
117
+ if ('ok' in obj) error.ok = Boolean(obj.ok)
118
+ if ('stack' in obj) error.stack = String(obj.stack)
119
+ }
120
+
121
+ private parseExpectedActualFromMessage(
122
+ error: CapturedError,
123
+ message: string
124
+ ): void {
125
+ if (!error.expected || !error.actual) {
126
+ const expectedMatch = /Expected:\s*(\d+)/.exec(message)
127
+ const receivedMatch = /Received:\s*(\d+)/.exec(message)
128
+ if (expectedMatch && !error.expected) error.expected = expectedMatch[1]
129
+ if (receivedMatch && !error.actual) error.actual = receivedMatch[1]
130
+ }
131
+ }
132
+
133
+ private createTestFromExecError(execError: unknown): CapturedTest {
134
+ const errorObj = execError as Record<string, unknown>
135
+ const message = String(errorObj.message ?? 'Unknown error')
136
+
137
+ const error: CapturedError = {
138
+ message,
139
+ name: typeof errorObj.name === 'string' ? errorObj.name : 'Error',
140
+ stack: typeof errorObj.stack === 'string' ? errorObj.stack : undefined,
141
+ }
142
+
143
+ // Extract additional fields from Jest's SerializableError
144
+ if ('code' in errorObj && errorObj.code !== undefined) {
145
+ error.operator = String(errorObj.code)
146
+ }
147
+ if ('type' in errorObj && typeof errorObj.type === 'string') {
148
+ error.name = errorObj.type
149
+ }
150
+
151
+ const errorType = error.name ?? 'Error'
152
+ const testName = `Module failed to load (${errorType})`
153
+
154
+ return {
155
+ name: testName,
156
+ fullName: testName,
157
+ state: 'failed',
158
+ errors: [error],
159
+ }
160
+ }
161
+
162
+ private buildTestModules(): CapturedModule[] {
163
+ return Array.from(this.testModules.entries()).map(([path, data]) => {
164
+ const { testResult } = data
165
+
166
+ // Handle module/import errors
167
+ if (testResult.testExecError && testResult.testResults.length === 0) {
168
+ return {
169
+ moduleId: path,
170
+ tests: [this.createTestFromExecError(testResult.testExecError)],
171
+ }
172
+ }
173
+
174
+ return {
175
+ moduleId: path,
176
+ tests: testResult.testResults.map((test: AssertionResult) =>
177
+ this.mapTestResult(test)
178
+ ),
179
+ }
180
+ })
181
+ }
182
+
183
+ private buildUnhandledErrors(
184
+ results: AggregatedResult
185
+ ): CapturedUnhandledError[] {
186
+ if (!results.runExecError) {
187
+ return []
188
+ }
189
+
190
+ const error = results.runExecError
191
+ const errorObj = error as Record<string, unknown>
192
+
193
+ return [
194
+ {
195
+ message: String(errorObj.message ?? 'Unknown error'),
196
+ name: typeof errorObj.name === 'string' ? errorObj.name : 'Error',
197
+ stack: typeof errorObj.stack === 'string' ? errorObj.stack : undefined,
198
+ },
199
+ ]
200
+ }
201
+ }
@@ -0,0 +1,4 @@
1
+ import { JestReporter } from './JestReporter'
2
+
3
+ export { JestReporter }
4
+ export default JestReporter
@@ -0,0 +1,42 @@
1
+ import type { Storage } from 'tdd-guard'
2
+
3
+ export interface TDDGuardReporterOptions {
4
+ storage?: Storage
5
+ projectRoot?: string
6
+ }
7
+
8
+ export interface CapturedError {
9
+ message: string
10
+ actual?: string
11
+ expected?: string
12
+ showDiff?: boolean
13
+ operator?: string
14
+ diff?: string
15
+ name?: string
16
+ ok?: boolean
17
+ stack?: string
18
+ }
19
+
20
+ export interface CapturedTest {
21
+ name: string
22
+ fullName: string
23
+ state: string
24
+ errors?: CapturedError[]
25
+ }
26
+
27
+ export interface CapturedModule {
28
+ moduleId: string
29
+ tests: CapturedTest[]
30
+ }
31
+
32
+ export interface CapturedUnhandledError {
33
+ message: string
34
+ name: string
35
+ stack?: string
36
+ }
37
+
38
+ export interface CapturedTestRun {
39
+ testModules: CapturedModule[]
40
+ unhandledErrors?: CapturedUnhandledError[]
41
+ reason?: 'passed' | 'failed' | 'interrupted'
42
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "composite": true,
5
+ "outDir": "./dist",
6
+ "rootDir": "./src",
7
+ "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["**/*.test.ts", "**/*.spec.ts"]
11
+ }
@@ -0,0 +1,85 @@
1
+ import type { TestModule, TestCase, TestResult } from 'vitest/node'
2
+ import type { SerializedError } from '@vitest/utils'
3
+
4
+ const DEFAULT_MODULE_ID = '/test/example.test.ts'
5
+ const DEFAULT_TEST_NAME = 'should pass'
6
+ const DEFAULT_TEST_FULL_NAME = 'Example Suite > should pass'
7
+
8
+ // Helper to create a valid TestResult for a given state
9
+ export function createTestResult(state: TestResult['state']): TestResult {
10
+ switch (state) {
11
+ case 'failed':
12
+ return { state: 'failed', errors: [] }
13
+ case 'passed':
14
+ return { state: 'passed', errors: undefined }
15
+ case 'skipped':
16
+ return { state: 'skipped', errors: undefined, note: undefined }
17
+ case 'pending':
18
+ return { state: 'pending', errors: undefined }
19
+ }
20
+ }
21
+
22
+ // Creates a minimal TestModule mock for testing
23
+ function createTestModule(props: {
24
+ moduleId: string
25
+ errors?: () => SerializedError[]
26
+ }): TestModule {
27
+ return {
28
+ moduleId: props.moduleId,
29
+ errors: props.errors ?? ((): SerializedError[] => []),
30
+ } as TestModule
31
+ }
32
+
33
+ export function testModule(overrides?: {
34
+ moduleId?: string
35
+ errors?: () => SerializedError[]
36
+ }): TestModule {
37
+ return createTestModule({
38
+ moduleId: overrides?.moduleId ?? DEFAULT_MODULE_ID,
39
+ errors: overrides?.errors,
40
+ })
41
+ }
42
+
43
+ export function createTestCase(overrides?: Partial<TestCase>): TestCase {
44
+ const defaultModule = createTestModule({ moduleId: DEFAULT_MODULE_ID })
45
+
46
+ return {
47
+ name: DEFAULT_TEST_NAME,
48
+ fullName: DEFAULT_TEST_FULL_NAME,
49
+ module: defaultModule,
50
+ result: () => ({ state: 'passed', errors: [] }) as TestResult,
51
+ ...overrides,
52
+ } as TestCase
53
+ }
54
+
55
+ export function failedTestCase(overrides?: Partial<TestCase>): TestCase {
56
+ return createTestCase({
57
+ name: 'should fail',
58
+ fullName: 'Example Suite > should fail',
59
+ result: () =>
60
+ ({
61
+ state: 'failed',
62
+ errors: [
63
+ {
64
+ message: 'expected 2 to be 3',
65
+ stack: 'Error: expected 2 to be 3\n at test.ts:7:19',
66
+ expected: '3',
67
+ actual: '2',
68
+ },
69
+ ],
70
+ }) as TestResult,
71
+ ...overrides,
72
+ })
73
+ }
74
+
75
+ export function createUnhandledError(
76
+ overrides: Partial<SerializedError> = {}
77
+ ): SerializedError {
78
+ return {
79
+ name: 'Error',
80
+ message: 'Cannot find module "./helpers"',
81
+ stack:
82
+ "Error: Cannot find module './helpers' imported from '/src/example.test.ts'",
83
+ ...overrides,
84
+ }
85
+ }