executable-stories-jest 8.4.8 → 8.5.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.
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/reporter.cjs +17 -0
- package/dist/reporter.cjs.map +1 -1
- package/dist/reporter.d.cts +1 -0
- package/dist/reporter.d.ts +1 -0
- package/dist/reporter.js +17 -0
- package/dist/reporter.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as executable_stories_formatters from 'executable-stories-formatters';
|
|
2
2
|
import { StoryMeta, DocEntry, StepKeyword } from 'executable-stories-formatters';
|
|
3
3
|
export { DocEntry, DocPhase, NormalizedTicket, STORY_META_KEY, StepKeyword, StepMode, StoryMeta, StoryStep } from 'executable-stories-formatters';
|
|
4
4
|
|
|
@@ -309,27 +309,27 @@ type Story = typeof story;
|
|
|
309
309
|
|
|
310
310
|
declare const given: {
|
|
311
311
|
(text: string, docs?: StoryDocs): void;
|
|
312
|
-
(text: string, children:
|
|
312
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
313
313
|
<T>(text: string, body: () => T): T;
|
|
314
314
|
};
|
|
315
315
|
declare const when: {
|
|
316
316
|
(text: string, docs?: StoryDocs): void;
|
|
317
|
-
(text: string, children:
|
|
317
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
318
318
|
<T>(text: string, body: () => T): T;
|
|
319
319
|
};
|
|
320
320
|
declare const then: {
|
|
321
321
|
(text: string, docs?: StoryDocs): void;
|
|
322
|
-
(text: string, children:
|
|
322
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
323
323
|
<T>(text: string, body: () => T): T;
|
|
324
324
|
};
|
|
325
325
|
declare const and: {
|
|
326
326
|
(text: string, docs?: StoryDocs): void;
|
|
327
|
-
(text: string, children:
|
|
327
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
328
328
|
<T>(text: string, body: () => T): T;
|
|
329
329
|
};
|
|
330
330
|
declare const but: {
|
|
331
331
|
(text: string, docs?: StoryDocs): void;
|
|
332
|
-
(text: string, children:
|
|
332
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
333
333
|
<T>(text: string, body: () => T): T;
|
|
334
334
|
};
|
|
335
335
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as executable_stories_formatters from 'executable-stories-formatters';
|
|
2
2
|
import { StoryMeta, DocEntry, StepKeyword } from 'executable-stories-formatters';
|
|
3
3
|
export { DocEntry, DocPhase, NormalizedTicket, STORY_META_KEY, StepKeyword, StepMode, StoryMeta, StoryStep } from 'executable-stories-formatters';
|
|
4
4
|
|
|
@@ -309,27 +309,27 @@ type Story = typeof story;
|
|
|
309
309
|
|
|
310
310
|
declare const given: {
|
|
311
311
|
(text: string, docs?: StoryDocs): void;
|
|
312
|
-
(text: string, children:
|
|
312
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
313
313
|
<T>(text: string, body: () => T): T;
|
|
314
314
|
};
|
|
315
315
|
declare const when: {
|
|
316
316
|
(text: string, docs?: StoryDocs): void;
|
|
317
|
-
(text: string, children:
|
|
317
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
318
318
|
<T>(text: string, body: () => T): T;
|
|
319
319
|
};
|
|
320
320
|
declare const then: {
|
|
321
321
|
(text: string, docs?: StoryDocs): void;
|
|
322
|
-
(text: string, children:
|
|
322
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
323
323
|
<T>(text: string, body: () => T): T;
|
|
324
324
|
};
|
|
325
325
|
declare const and: {
|
|
326
326
|
(text: string, docs?: StoryDocs): void;
|
|
327
|
-
(text: string, children:
|
|
327
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
328
328
|
<T>(text: string, body: () => T): T;
|
|
329
329
|
};
|
|
330
330
|
declare const but: {
|
|
331
331
|
(text: string, docs?: StoryDocs): void;
|
|
332
|
-
(text: string, children:
|
|
332
|
+
(text: string, children: executable_stories_formatters.DocEntry[]): void;
|
|
333
333
|
<T>(text: string, body: () => T): T;
|
|
334
334
|
};
|
|
335
335
|
|
package/dist/reporter.cjs
CHANGED
|
@@ -102,12 +102,14 @@ var StoryReporter = class {
|
|
|
102
102
|
for (const report of reports) {
|
|
103
103
|
const fileResult = fileResults.get(report.testFilePath);
|
|
104
104
|
const sourceFile = toRelativePosix(report.testFilePath, root);
|
|
105
|
+
const matchedFullNames = /* @__PURE__ */ new Set();
|
|
105
106
|
for (const meta of report.scenarios) {
|
|
106
107
|
if (!meta?.scenario) continue;
|
|
107
108
|
const matchingTest = fileResult?.testResults.find((test) => {
|
|
108
109
|
const expectedFullName = meta.suitePath ? [...meta.suitePath, meta.scenario].join(" > ") : meta.scenario;
|
|
109
110
|
return test.fullName === expectedFullName;
|
|
110
111
|
});
|
|
112
|
+
if (matchingTest) matchedFullNames.add(matchingTest.fullName);
|
|
111
113
|
const statusMap = {
|
|
112
114
|
passed: "pass",
|
|
113
115
|
failed: "fail",
|
|
@@ -146,6 +148,21 @@ var StoryReporter = class {
|
|
|
146
148
|
retries: 0
|
|
147
149
|
});
|
|
148
150
|
}
|
|
151
|
+
for (const test of fileResult?.testResults ?? []) {
|
|
152
|
+
if (test.status !== "todo" || matchedFullNames.has(test.fullName)) continue;
|
|
153
|
+
const title = test.title ?? test.fullName;
|
|
154
|
+
rawTestCases.push({
|
|
155
|
+
title,
|
|
156
|
+
titlePath: [title],
|
|
157
|
+
story: { scenario: title, steps: [] },
|
|
158
|
+
sourceFile,
|
|
159
|
+
sourceLine: 1,
|
|
160
|
+
status: "todo",
|
|
161
|
+
durationMs: 0,
|
|
162
|
+
retry: 0,
|
|
163
|
+
retries: 0
|
|
164
|
+
});
|
|
165
|
+
}
|
|
149
166
|
}
|
|
150
167
|
if (rawTestCases.length === 0) return;
|
|
151
168
|
const rawRun = {
|
package/dist/reporter.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["/**\n * Jest reporter for executable-stories.\n * Generates reports using the executable-stories-formatters package.\n *\n * Uses file-based communication: story.init() writes JSON files to\n * .jest-executable-stories/ which this reporter reads.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport fg from \"fast-glob\";\nimport type { StoryMeta } from \"executable-stories-formatters\";\n\n// Import from formatters package\nimport {\n ReportGenerator,\n canonicalizeRun,\n readGitSha,\n readPackageVersion,\n detectCI,\n type RawRun,\n type RawTestCase,\n type RawAttachment,\n type RawStepEvent,\n type FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// Re-export types from formatters for convenience\nexport type {\n OutputFormat,\n OutputMode,\n ColocatedStyle,\n OutputRule,\n FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// ============================================================================\n// Reporter Options (delegates to FormatterOptions)\n// ============================================================================\n\nexport interface StoryReporterOptions extends FormatterOptions {\n /** If set, write raw run JSON (schemaVersion 1) to this path for use with the executable-stories CLI/binary */\n rawRunPath?: string;\n}\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\n/** Shape of JSON files written by story.init() */\ninterface StoryFileReport {\n testFilePath: string;\n scenarios: (StoryMeta & {\n _attachments?: Array<{\n name: string;\n mediaType: string;\n path?: string;\n body?: string;\n encoding?: \"BASE64\" | \"IDENTITY\";\n charset?: string;\n fileName?: string;\n stepIndex?: number;\n stepId?: string;\n }>;\n })[];\n}\n\ninterface JestTestResult {\n testFilePath: string;\n testResults: Array<{\n fullName: string;\n status: \"passed\" | \"failed\" | \"pending\" | \"todo\";\n duration?: number;\n failureMessages?: string[];\n }>;\n}\n\ninterface JestAggregatedResult {\n testResults: JestTestResult[];\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Convert path to relative posix format.\n */\nfunction toRelativePosix(absolutePath: string, projectRoot: string): string {\n return path.relative(projectRoot, absolutePath).split(path.sep).join(\"/\");\n}\n\n// ============================================================================\n// Reporter Implementation\n// ============================================================================\n\nexport default class StoryReporter {\n private options: StoryReporterOptions;\n private startTime = 0;\n private packageVersion: string | undefined;\n private gitSha: string | undefined;\n\n constructor(_globalConfig: unknown, reporterOptions: StoryReporterOptions = {}) {\n this.options = reporterOptions;\n }\n\n /** Get the output directory for story JSON files */\n private getOutputDir(): string {\n const baseDir = process.env.JEST_STORY_DOCS_DIR ?? \".jest-executable-stories\";\n return path.resolve(process.cwd(), baseDir);\n }\n\n /** Reset run artifacts (clear previous story files) */\n private resetRunArtifacts(): void {\n try {\n fs.rmSync(this.getOutputDir(), { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n\n /** Read story reports written by story.init() during test execution */\n private readStoryReports(): StoryFileReport[] {\n const outputDir = this.getOutputDir();\n if (!fs.existsSync(outputDir)) return [];\n const files = fg.sync(\"**/*.json\", {\n cwd: outputDir,\n onlyFiles: true,\n absolute: true,\n });\n const reports: StoryFileReport[] = [];\n for (const file of files) {\n try {\n const raw = fs.readFileSync(file, \"utf8\");\n const parsed = JSON.parse(raw) as StoryFileReport;\n if (!parsed?.testFilePath || !Array.isArray(parsed.scenarios)) continue;\n reports.push(parsed);\n } catch {\n // Ignore unreadable or malformed files\n }\n }\n return reports;\n }\n\n onRunStart(): void {\n this.resetRunArtifacts();\n this.startTime = Date.now();\n const root = process.cwd();\n const includeMetadata = this.options.markdown?.includeMetadata ?? true;\n if (includeMetadata) {\n this.packageVersion = readPackageVersion(root);\n this.gitSha = readGitSha(root);\n }\n }\n\n async onRunComplete(\n _testContexts: Set<unknown>,\n results: JestAggregatedResult\n ): Promise<void> {\n const root = process.cwd();\n\n // Build map of test results by file for status lookup\n const fileResults = new Map<string, JestTestResult>();\n for (const testFileResult of results.testResults) {\n fileResults.set(testFileResult.testFilePath, testFileResult);\n }\n\n // Read story data from JSON files written by story.init()\n const reports = this.readStoryReports();\n\n // Collect test cases\n const rawTestCases: RawTestCase[] = [];\n\n for (const report of reports) {\n const fileResult = fileResults.get(report.testFilePath);\n const sourceFile = toRelativePosix(report.testFilePath, root);\n\n for (const meta of report.scenarios) {\n if (!meta?.scenario) continue;\n\n // Find matching test result\n const matchingTest = fileResult?.testResults.find((test) => {\n const expectedFullName = meta.suitePath\n ? [...meta.suitePath, meta.scenario].join(\" > \")\n : meta.scenario;\n return test.fullName === expectedFullName;\n });\n\n // Map Jest status to raw status\n const statusMap: Record<string, RawTestCase[\"status\"]> = {\n passed: \"pass\",\n failed: \"fail\",\n pending: \"pending\",\n todo: \"pending\",\n };\n\n const status = matchingTest\n ? statusMap[matchingTest.status] ?? \"unknown\"\n : \"pass\";\n\n // Map attachments\n const rawAttachments: RawAttachment[] = (meta._attachments ?? []).map((a: NonNullable<typeof meta._attachments>[number]) => ({\n name: a.name,\n mediaType: a.mediaType,\n path: a.path,\n body: a.body,\n encoding: a.encoding,\n charset: a.charset,\n fileName: a.fileName,\n stepIndex: a.stepIndex,\n stepId: a.stepId,\n }));\n\n // Extract step events (timing)\n const stepEvents: RawStepEvent[] = meta.steps\n .filter((s: { durationMs?: number }) => s.durationMs !== undefined)\n .map((s: { durationMs?: number; text: string }, i: number) => ({\n index: i,\n title: s.text,\n durationMs: s.durationMs,\n }));\n\n rawTestCases.push({\n title: meta.scenario,\n titlePath: meta.suitePath\n ? [...meta.suitePath, meta.scenario]\n : [meta.scenario],\n story: meta,\n sourceFile,\n sourceLine: Math.max(1, meta.sourceOrder ?? 1),\n status,\n durationMs: matchingTest?.duration ?? 0,\n error: matchingTest?.failureMessages?.length\n ? { message: matchingTest.failureMessages.join(\"\\n\") }\n : undefined,\n attachments: rawAttachments.length > 0 ? rawAttachments : undefined,\n stepEvents: stepEvents.length > 0 ? stepEvents : undefined,\n retry: 0,\n retries: 0,\n });\n }\n }\n\n if (rawTestCases.length === 0) return;\n\n // Build RawRun\n const rawRun: RawRun = {\n testCases: rawTestCases,\n startedAtMs: this.startTime,\n finishedAtMs: Date.now(),\n projectRoot: root,\n packageVersion: this.packageVersion,\n gitSha: this.gitSha,\n ci: detectCI(),\n };\n\n // Optionally write raw run JSON for CLI/binary consumption\n const rawRunPath = this.options.rawRunPath;\n if (rawRunPath) {\n const absolutePath = path.isAbsolute(rawRunPath)\n ? rawRunPath\n : path.join(root, rawRunPath);\n const dir = path.dirname(absolutePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const payload = { schemaVersion: 1, ...rawRun };\n fs.writeFileSync(absolutePath, JSON.stringify(payload, null, 2), \"utf8\");\n }\n\n // Canonicalize\n const canonicalRun = canonicalizeRun(rawRun);\n\n // Generate reports\n const generator = new ReportGenerator(this.options);\n try {\n await generator.generate(canonicalRun);\n } catch (err) {\n console.error(\"Failed to generate reports:\", err);\n }\n }\n}\n"],"mappings":"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","names":["fg"]}
|
|
1
|
+
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["/**\n * Jest reporter for executable-stories.\n * Generates reports using the executable-stories-formatters package.\n *\n * Uses file-based communication: story.init() writes JSON files to\n * .jest-executable-stories/ which this reporter reads.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport fg from \"fast-glob\";\nimport type { StoryMeta } from \"executable-stories-formatters\";\n\n// Import from formatters package\nimport {\n ReportGenerator,\n canonicalizeRun,\n readGitSha,\n readPackageVersion,\n detectCI,\n type RawRun,\n type RawTestCase,\n type RawAttachment,\n type RawStepEvent,\n type FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// Re-export types from formatters for convenience\nexport type {\n OutputFormat,\n OutputMode,\n ColocatedStyle,\n OutputRule,\n FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// ============================================================================\n// Reporter Options (delegates to FormatterOptions)\n// ============================================================================\n\nexport interface StoryReporterOptions extends FormatterOptions {\n /** If set, write raw run JSON (schemaVersion 1) to this path for use with the executable-stories CLI/binary */\n rawRunPath?: string;\n}\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\n/** Shape of JSON files written by story.init() */\ninterface StoryFileReport {\n testFilePath: string;\n scenarios: (StoryMeta & {\n _attachments?: Array<{\n name: string;\n mediaType: string;\n path?: string;\n body?: string;\n encoding?: \"BASE64\" | \"IDENTITY\";\n charset?: string;\n fileName?: string;\n stepIndex?: number;\n stepId?: string;\n }>;\n })[];\n}\n\ninterface JestTestResult {\n testFilePath: string;\n testResults: Array<{\n fullName: string;\n title?: string;\n status: \"passed\" | \"failed\" | \"pending\" | \"todo\";\n duration?: number;\n failureMessages?: string[];\n }>;\n}\n\ninterface JestAggregatedResult {\n testResults: JestTestResult[];\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Convert path to relative posix format.\n */\nfunction toRelativePosix(absolutePath: string, projectRoot: string): string {\n return path.relative(projectRoot, absolutePath).split(path.sep).join(\"/\");\n}\n\n// ============================================================================\n// Reporter Implementation\n// ============================================================================\n\nexport default class StoryReporter {\n private options: StoryReporterOptions;\n private startTime = 0;\n private packageVersion: string | undefined;\n private gitSha: string | undefined;\n\n constructor(_globalConfig: unknown, reporterOptions: StoryReporterOptions = {}) {\n this.options = reporterOptions;\n }\n\n /** Get the output directory for story JSON files */\n private getOutputDir(): string {\n const baseDir = process.env.JEST_STORY_DOCS_DIR ?? \".jest-executable-stories\";\n return path.resolve(process.cwd(), baseDir);\n }\n\n /** Reset run artifacts (clear previous story files) */\n private resetRunArtifacts(): void {\n try {\n fs.rmSync(this.getOutputDir(), { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n\n /** Read story reports written by story.init() during test execution */\n private readStoryReports(): StoryFileReport[] {\n const outputDir = this.getOutputDir();\n if (!fs.existsSync(outputDir)) return [];\n const files = fg.sync(\"**/*.json\", {\n cwd: outputDir,\n onlyFiles: true,\n absolute: true,\n });\n const reports: StoryFileReport[] = [];\n for (const file of files) {\n try {\n const raw = fs.readFileSync(file, \"utf8\");\n const parsed = JSON.parse(raw) as StoryFileReport;\n if (!parsed?.testFilePath || !Array.isArray(parsed.scenarios)) continue;\n reports.push(parsed);\n } catch {\n // Ignore unreadable or malformed files\n }\n }\n return reports;\n }\n\n onRunStart(): void {\n this.resetRunArtifacts();\n this.startTime = Date.now();\n const root = process.cwd();\n const includeMetadata = this.options.markdown?.includeMetadata ?? true;\n if (includeMetadata) {\n this.packageVersion = readPackageVersion(root);\n this.gitSha = readGitSha(root);\n }\n }\n\n async onRunComplete(\n _testContexts: Set<unknown>,\n results: JestAggregatedResult\n ): Promise<void> {\n const root = process.cwd();\n\n // Build map of test results by file for status lookup\n const fileResults = new Map<string, JestTestResult>();\n for (const testFileResult of results.testResults) {\n fileResults.set(testFileResult.testFilePath, testFileResult);\n }\n\n // Read story data from JSON files written by story.init()\n const reports = this.readStoryReports();\n\n // Collect test cases\n const rawTestCases: RawTestCase[] = [];\n\n for (const report of reports) {\n const fileResult = fileResults.get(report.testFilePath);\n const sourceFile = toRelativePosix(report.testFilePath, root);\n const matchedFullNames = new Set<string>();\n\n for (const meta of report.scenarios) {\n if (!meta?.scenario) continue;\n\n // Find matching test result\n const matchingTest = fileResult?.testResults.find((test) => {\n const expectedFullName = meta.suitePath\n ? [...meta.suitePath, meta.scenario].join(\" > \")\n : meta.scenario;\n return test.fullName === expectedFullName;\n });\n if (matchingTest) matchedFullNames.add(matchingTest.fullName);\n\n // Map Jest status to raw status\n const statusMap: Record<string, RawTestCase[\"status\"]> = {\n passed: \"pass\",\n failed: \"fail\",\n pending: \"pending\",\n todo: \"pending\",\n };\n\n const status = matchingTest\n ? statusMap[matchingTest.status] ?? \"unknown\"\n : \"pass\";\n\n // Map attachments\n const rawAttachments: RawAttachment[] = (meta._attachments ?? []).map((a: NonNullable<typeof meta._attachments>[number]) => ({\n name: a.name,\n mediaType: a.mediaType,\n path: a.path,\n body: a.body,\n encoding: a.encoding,\n charset: a.charset,\n fileName: a.fileName,\n stepIndex: a.stepIndex,\n stepId: a.stepId,\n }));\n\n // Extract step events (timing)\n const stepEvents: RawStepEvent[] = meta.steps\n .filter((s: { durationMs?: number }) => s.durationMs !== undefined)\n .map((s: { durationMs?: number; text: string }, i: number) => ({\n index: i,\n title: s.text,\n durationMs: s.durationMs,\n }));\n\n rawTestCases.push({\n title: meta.scenario,\n titlePath: meta.suitePath\n ? [...meta.suitePath, meta.scenario]\n : [meta.scenario],\n story: meta,\n sourceFile,\n sourceLine: Math.max(1, meta.sourceOrder ?? 1),\n status,\n durationMs: matchingTest?.duration ?? 0,\n error: matchingTest?.failureMessages?.length\n ? { message: matchingTest.failureMessages.join(\"\\n\") }\n : undefined,\n attachments: rawAttachments.length > 0 ? rawAttachments : undefined,\n stepEvents: stepEvents.length > 0 ? stepEvents : undefined,\n retry: 0,\n retries: 0,\n });\n }\n\n // Bodyless `it.todo(...)` never runs `story.init()`, so it has no story\n // meta — but Jest still reports it with status \"todo\". Emit those as\n // planned scenarios. Only files with story reports reach this loop, so\n // plain (non-story) suites full of todos never leak into the docs.\n for (const test of fileResult?.testResults ?? []) {\n if (test.status !== \"todo\" || matchedFullNames.has(test.fullName)) continue;\n const title = test.title ?? test.fullName;\n rawTestCases.push({\n title,\n titlePath: [title],\n story: { scenario: title, steps: [] },\n sourceFile,\n sourceLine: 1,\n status: \"todo\",\n durationMs: 0,\n retry: 0,\n retries: 0,\n });\n }\n }\n\n if (rawTestCases.length === 0) return;\n\n // Build RawRun\n const rawRun: RawRun = {\n testCases: rawTestCases,\n startedAtMs: this.startTime,\n finishedAtMs: Date.now(),\n projectRoot: root,\n packageVersion: this.packageVersion,\n gitSha: this.gitSha,\n ci: detectCI(),\n };\n\n // Optionally write raw run JSON for CLI/binary consumption\n const rawRunPath = this.options.rawRunPath;\n if (rawRunPath) {\n const absolutePath = path.isAbsolute(rawRunPath)\n ? rawRunPath\n : path.join(root, rawRunPath);\n const dir = path.dirname(absolutePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const payload = { schemaVersion: 1, ...rawRun };\n fs.writeFileSync(absolutePath, JSON.stringify(payload, null, 2), \"utf8\");\n }\n\n // Canonicalize\n const canonicalRun = canonicalizeRun(rawRun);\n\n // Generate reports\n const generator = new ReportGenerator(this.options);\n try {\n await generator.generate(canonicalRun);\n } catch (err) {\n console.error(\"Failed to generate reports:\", err);\n }\n }\n}\n"],"mappings":"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","names":["fg"]}
|
package/dist/reporter.d.cts
CHANGED
package/dist/reporter.d.ts
CHANGED
package/dist/reporter.js
CHANGED
|
@@ -74,12 +74,14 @@ var StoryReporter = class {
|
|
|
74
74
|
for (const report of reports) {
|
|
75
75
|
const fileResult = fileResults.get(report.testFilePath);
|
|
76
76
|
const sourceFile = toRelativePosix(report.testFilePath, root);
|
|
77
|
+
const matchedFullNames = /* @__PURE__ */ new Set();
|
|
77
78
|
for (const meta of report.scenarios) {
|
|
78
79
|
if (!meta?.scenario) continue;
|
|
79
80
|
const matchingTest = fileResult?.testResults.find((test) => {
|
|
80
81
|
const expectedFullName = meta.suitePath ? [...meta.suitePath, meta.scenario].join(" > ") : meta.scenario;
|
|
81
82
|
return test.fullName === expectedFullName;
|
|
82
83
|
});
|
|
84
|
+
if (matchingTest) matchedFullNames.add(matchingTest.fullName);
|
|
83
85
|
const statusMap = {
|
|
84
86
|
passed: "pass",
|
|
85
87
|
failed: "fail",
|
|
@@ -118,6 +120,21 @@ var StoryReporter = class {
|
|
|
118
120
|
retries: 0
|
|
119
121
|
});
|
|
120
122
|
}
|
|
123
|
+
for (const test of fileResult?.testResults ?? []) {
|
|
124
|
+
if (test.status !== "todo" || matchedFullNames.has(test.fullName)) continue;
|
|
125
|
+
const title = test.title ?? test.fullName;
|
|
126
|
+
rawTestCases.push({
|
|
127
|
+
title,
|
|
128
|
+
titlePath: [title],
|
|
129
|
+
story: { scenario: title, steps: [] },
|
|
130
|
+
sourceFile,
|
|
131
|
+
sourceLine: 1,
|
|
132
|
+
status: "todo",
|
|
133
|
+
durationMs: 0,
|
|
134
|
+
retry: 0,
|
|
135
|
+
retries: 0
|
|
136
|
+
});
|
|
137
|
+
}
|
|
121
138
|
}
|
|
122
139
|
if (rawTestCases.length === 0) return;
|
|
123
140
|
const rawRun = {
|
package/dist/reporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["/**\n * Jest reporter for executable-stories.\n * Generates reports using the executable-stories-formatters package.\n *\n * Uses file-based communication: story.init() writes JSON files to\n * .jest-executable-stories/ which this reporter reads.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport fg from \"fast-glob\";\nimport type { StoryMeta } from \"executable-stories-formatters\";\n\n// Import from formatters package\nimport {\n ReportGenerator,\n canonicalizeRun,\n readGitSha,\n readPackageVersion,\n detectCI,\n type RawRun,\n type RawTestCase,\n type RawAttachment,\n type RawStepEvent,\n type FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// Re-export types from formatters for convenience\nexport type {\n OutputFormat,\n OutputMode,\n ColocatedStyle,\n OutputRule,\n FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// ============================================================================\n// Reporter Options (delegates to FormatterOptions)\n// ============================================================================\n\nexport interface StoryReporterOptions extends FormatterOptions {\n /** If set, write raw run JSON (schemaVersion 1) to this path for use with the executable-stories CLI/binary */\n rawRunPath?: string;\n}\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\n/** Shape of JSON files written by story.init() */\ninterface StoryFileReport {\n testFilePath: string;\n scenarios: (StoryMeta & {\n _attachments?: Array<{\n name: string;\n mediaType: string;\n path?: string;\n body?: string;\n encoding?: \"BASE64\" | \"IDENTITY\";\n charset?: string;\n fileName?: string;\n stepIndex?: number;\n stepId?: string;\n }>;\n })[];\n}\n\ninterface JestTestResult {\n testFilePath: string;\n testResults: Array<{\n fullName: string;\n status: \"passed\" | \"failed\" | \"pending\" | \"todo\";\n duration?: number;\n failureMessages?: string[];\n }>;\n}\n\ninterface JestAggregatedResult {\n testResults: JestTestResult[];\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Convert path to relative posix format.\n */\nfunction toRelativePosix(absolutePath: string, projectRoot: string): string {\n return path.relative(projectRoot, absolutePath).split(path.sep).join(\"/\");\n}\n\n// ============================================================================\n// Reporter Implementation\n// ============================================================================\n\nexport default class StoryReporter {\n private options: StoryReporterOptions;\n private startTime = 0;\n private packageVersion: string | undefined;\n private gitSha: string | undefined;\n\n constructor(_globalConfig: unknown, reporterOptions: StoryReporterOptions = {}) {\n this.options = reporterOptions;\n }\n\n /** Get the output directory for story JSON files */\n private getOutputDir(): string {\n const baseDir = process.env.JEST_STORY_DOCS_DIR ?? \".jest-executable-stories\";\n return path.resolve(process.cwd(), baseDir);\n }\n\n /** Reset run artifacts (clear previous story files) */\n private resetRunArtifacts(): void {\n try {\n fs.rmSync(this.getOutputDir(), { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n\n /** Read story reports written by story.init() during test execution */\n private readStoryReports(): StoryFileReport[] {\n const outputDir = this.getOutputDir();\n if (!fs.existsSync(outputDir)) return [];\n const files = fg.sync(\"**/*.json\", {\n cwd: outputDir,\n onlyFiles: true,\n absolute: true,\n });\n const reports: StoryFileReport[] = [];\n for (const file of files) {\n try {\n const raw = fs.readFileSync(file, \"utf8\");\n const parsed = JSON.parse(raw) as StoryFileReport;\n if (!parsed?.testFilePath || !Array.isArray(parsed.scenarios)) continue;\n reports.push(parsed);\n } catch {\n // Ignore unreadable or malformed files\n }\n }\n return reports;\n }\n\n onRunStart(): void {\n this.resetRunArtifacts();\n this.startTime = Date.now();\n const root = process.cwd();\n const includeMetadata = this.options.markdown?.includeMetadata ?? true;\n if (includeMetadata) {\n this.packageVersion = readPackageVersion(root);\n this.gitSha = readGitSha(root);\n }\n }\n\n async onRunComplete(\n _testContexts: Set<unknown>,\n results: JestAggregatedResult\n ): Promise<void> {\n const root = process.cwd();\n\n // Build map of test results by file for status lookup\n const fileResults = new Map<string, JestTestResult>();\n for (const testFileResult of results.testResults) {\n fileResults.set(testFileResult.testFilePath, testFileResult);\n }\n\n // Read story data from JSON files written by story.init()\n const reports = this.readStoryReports();\n\n // Collect test cases\n const rawTestCases: RawTestCase[] = [];\n\n for (const report of reports) {\n const fileResult = fileResults.get(report.testFilePath);\n const sourceFile = toRelativePosix(report.testFilePath, root);\n\n for (const meta of report.scenarios) {\n if (!meta?.scenario) continue;\n\n // Find matching test result\n const matchingTest = fileResult?.testResults.find((test) => {\n const expectedFullName = meta.suitePath\n ? [...meta.suitePath, meta.scenario].join(\" > \")\n : meta.scenario;\n return test.fullName === expectedFullName;\n });\n\n // Map Jest status to raw status\n const statusMap: Record<string, RawTestCase[\"status\"]> = {\n passed: \"pass\",\n failed: \"fail\",\n pending: \"pending\",\n todo: \"pending\",\n };\n\n const status = matchingTest\n ? statusMap[matchingTest.status] ?? \"unknown\"\n : \"pass\";\n\n // Map attachments\n const rawAttachments: RawAttachment[] = (meta._attachments ?? []).map((a: NonNullable<typeof meta._attachments>[number]) => ({\n name: a.name,\n mediaType: a.mediaType,\n path: a.path,\n body: a.body,\n encoding: a.encoding,\n charset: a.charset,\n fileName: a.fileName,\n stepIndex: a.stepIndex,\n stepId: a.stepId,\n }));\n\n // Extract step events (timing)\n const stepEvents: RawStepEvent[] = meta.steps\n .filter((s: { durationMs?: number }) => s.durationMs !== undefined)\n .map((s: { durationMs?: number; text: string }, i: number) => ({\n index: i,\n title: s.text,\n durationMs: s.durationMs,\n }));\n\n rawTestCases.push({\n title: meta.scenario,\n titlePath: meta.suitePath\n ? [...meta.suitePath, meta.scenario]\n : [meta.scenario],\n story: meta,\n sourceFile,\n sourceLine: Math.max(1, meta.sourceOrder ?? 1),\n status,\n durationMs: matchingTest?.duration ?? 0,\n error: matchingTest?.failureMessages?.length\n ? { message: matchingTest.failureMessages.join(\"\\n\") }\n : undefined,\n attachments: rawAttachments.length > 0 ? rawAttachments : undefined,\n stepEvents: stepEvents.length > 0 ? stepEvents : undefined,\n retry: 0,\n retries: 0,\n });\n }\n }\n\n if (rawTestCases.length === 0) return;\n\n // Build RawRun\n const rawRun: RawRun = {\n testCases: rawTestCases,\n startedAtMs: this.startTime,\n finishedAtMs: Date.now(),\n projectRoot: root,\n packageVersion: this.packageVersion,\n gitSha: this.gitSha,\n ci: detectCI(),\n };\n\n // Optionally write raw run JSON for CLI/binary consumption\n const rawRunPath = this.options.rawRunPath;\n if (rawRunPath) {\n const absolutePath = path.isAbsolute(rawRunPath)\n ? rawRunPath\n : path.join(root, rawRunPath);\n const dir = path.dirname(absolutePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const payload = { schemaVersion: 1, ...rawRun };\n fs.writeFileSync(absolutePath, JSON.stringify(payload, null, 2), \"utf8\");\n }\n\n // Canonicalize\n const canonicalRun = canonicalizeRun(rawRun);\n\n // Generate reports\n const generator = new ReportGenerator(this.options);\n try {\n await generator.generate(canonicalRun);\n } catch (err) {\n console.error(\"Failed to generate reports:\", err);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["/**\n * Jest reporter for executable-stories.\n * Generates reports using the executable-stories-formatters package.\n *\n * Uses file-based communication: story.init() writes JSON files to\n * .jest-executable-stories/ which this reporter reads.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport fg from \"fast-glob\";\nimport type { StoryMeta } from \"executable-stories-formatters\";\n\n// Import from formatters package\nimport {\n ReportGenerator,\n canonicalizeRun,\n readGitSha,\n readPackageVersion,\n detectCI,\n type RawRun,\n type RawTestCase,\n type RawAttachment,\n type RawStepEvent,\n type FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// Re-export types from formatters for convenience\nexport type {\n OutputFormat,\n OutputMode,\n ColocatedStyle,\n OutputRule,\n FormatterOptions,\n} from \"executable-stories-formatters\";\n\n// ============================================================================\n// Reporter Options (delegates to FormatterOptions)\n// ============================================================================\n\nexport interface StoryReporterOptions extends FormatterOptions {\n /** If set, write raw run JSON (schemaVersion 1) to this path for use with the executable-stories CLI/binary */\n rawRunPath?: string;\n}\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\n/** Shape of JSON files written by story.init() */\ninterface StoryFileReport {\n testFilePath: string;\n scenarios: (StoryMeta & {\n _attachments?: Array<{\n name: string;\n mediaType: string;\n path?: string;\n body?: string;\n encoding?: \"BASE64\" | \"IDENTITY\";\n charset?: string;\n fileName?: string;\n stepIndex?: number;\n stepId?: string;\n }>;\n })[];\n}\n\ninterface JestTestResult {\n testFilePath: string;\n testResults: Array<{\n fullName: string;\n title?: string;\n status: \"passed\" | \"failed\" | \"pending\" | \"todo\";\n duration?: number;\n failureMessages?: string[];\n }>;\n}\n\ninterface JestAggregatedResult {\n testResults: JestTestResult[];\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Convert path to relative posix format.\n */\nfunction toRelativePosix(absolutePath: string, projectRoot: string): string {\n return path.relative(projectRoot, absolutePath).split(path.sep).join(\"/\");\n}\n\n// ============================================================================\n// Reporter Implementation\n// ============================================================================\n\nexport default class StoryReporter {\n private options: StoryReporterOptions;\n private startTime = 0;\n private packageVersion: string | undefined;\n private gitSha: string | undefined;\n\n constructor(_globalConfig: unknown, reporterOptions: StoryReporterOptions = {}) {\n this.options = reporterOptions;\n }\n\n /** Get the output directory for story JSON files */\n private getOutputDir(): string {\n const baseDir = process.env.JEST_STORY_DOCS_DIR ?? \".jest-executable-stories\";\n return path.resolve(process.cwd(), baseDir);\n }\n\n /** Reset run artifacts (clear previous story files) */\n private resetRunArtifacts(): void {\n try {\n fs.rmSync(this.getOutputDir(), { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n\n /** Read story reports written by story.init() during test execution */\n private readStoryReports(): StoryFileReport[] {\n const outputDir = this.getOutputDir();\n if (!fs.existsSync(outputDir)) return [];\n const files = fg.sync(\"**/*.json\", {\n cwd: outputDir,\n onlyFiles: true,\n absolute: true,\n });\n const reports: StoryFileReport[] = [];\n for (const file of files) {\n try {\n const raw = fs.readFileSync(file, \"utf8\");\n const parsed = JSON.parse(raw) as StoryFileReport;\n if (!parsed?.testFilePath || !Array.isArray(parsed.scenarios)) continue;\n reports.push(parsed);\n } catch {\n // Ignore unreadable or malformed files\n }\n }\n return reports;\n }\n\n onRunStart(): void {\n this.resetRunArtifacts();\n this.startTime = Date.now();\n const root = process.cwd();\n const includeMetadata = this.options.markdown?.includeMetadata ?? true;\n if (includeMetadata) {\n this.packageVersion = readPackageVersion(root);\n this.gitSha = readGitSha(root);\n }\n }\n\n async onRunComplete(\n _testContexts: Set<unknown>,\n results: JestAggregatedResult\n ): Promise<void> {\n const root = process.cwd();\n\n // Build map of test results by file for status lookup\n const fileResults = new Map<string, JestTestResult>();\n for (const testFileResult of results.testResults) {\n fileResults.set(testFileResult.testFilePath, testFileResult);\n }\n\n // Read story data from JSON files written by story.init()\n const reports = this.readStoryReports();\n\n // Collect test cases\n const rawTestCases: RawTestCase[] = [];\n\n for (const report of reports) {\n const fileResult = fileResults.get(report.testFilePath);\n const sourceFile = toRelativePosix(report.testFilePath, root);\n const matchedFullNames = new Set<string>();\n\n for (const meta of report.scenarios) {\n if (!meta?.scenario) continue;\n\n // Find matching test result\n const matchingTest = fileResult?.testResults.find((test) => {\n const expectedFullName = meta.suitePath\n ? [...meta.suitePath, meta.scenario].join(\" > \")\n : meta.scenario;\n return test.fullName === expectedFullName;\n });\n if (matchingTest) matchedFullNames.add(matchingTest.fullName);\n\n // Map Jest status to raw status\n const statusMap: Record<string, RawTestCase[\"status\"]> = {\n passed: \"pass\",\n failed: \"fail\",\n pending: \"pending\",\n todo: \"pending\",\n };\n\n const status = matchingTest\n ? statusMap[matchingTest.status] ?? \"unknown\"\n : \"pass\";\n\n // Map attachments\n const rawAttachments: RawAttachment[] = (meta._attachments ?? []).map((a: NonNullable<typeof meta._attachments>[number]) => ({\n name: a.name,\n mediaType: a.mediaType,\n path: a.path,\n body: a.body,\n encoding: a.encoding,\n charset: a.charset,\n fileName: a.fileName,\n stepIndex: a.stepIndex,\n stepId: a.stepId,\n }));\n\n // Extract step events (timing)\n const stepEvents: RawStepEvent[] = meta.steps\n .filter((s: { durationMs?: number }) => s.durationMs !== undefined)\n .map((s: { durationMs?: number; text: string }, i: number) => ({\n index: i,\n title: s.text,\n durationMs: s.durationMs,\n }));\n\n rawTestCases.push({\n title: meta.scenario,\n titlePath: meta.suitePath\n ? [...meta.suitePath, meta.scenario]\n : [meta.scenario],\n story: meta,\n sourceFile,\n sourceLine: Math.max(1, meta.sourceOrder ?? 1),\n status,\n durationMs: matchingTest?.duration ?? 0,\n error: matchingTest?.failureMessages?.length\n ? { message: matchingTest.failureMessages.join(\"\\n\") }\n : undefined,\n attachments: rawAttachments.length > 0 ? rawAttachments : undefined,\n stepEvents: stepEvents.length > 0 ? stepEvents : undefined,\n retry: 0,\n retries: 0,\n });\n }\n\n // Bodyless `it.todo(...)` never runs `story.init()`, so it has no story\n // meta — but Jest still reports it with status \"todo\". Emit those as\n // planned scenarios. Only files with story reports reach this loop, so\n // plain (non-story) suites full of todos never leak into the docs.\n for (const test of fileResult?.testResults ?? []) {\n if (test.status !== \"todo\" || matchedFullNames.has(test.fullName)) continue;\n const title = test.title ?? test.fullName;\n rawTestCases.push({\n title,\n titlePath: [title],\n story: { scenario: title, steps: [] },\n sourceFile,\n sourceLine: 1,\n status: \"todo\",\n durationMs: 0,\n retry: 0,\n retries: 0,\n });\n }\n }\n\n if (rawTestCases.length === 0) return;\n\n // Build RawRun\n const rawRun: RawRun = {\n testCases: rawTestCases,\n startedAtMs: this.startTime,\n finishedAtMs: Date.now(),\n projectRoot: root,\n packageVersion: this.packageVersion,\n gitSha: this.gitSha,\n ci: detectCI(),\n };\n\n // Optionally write raw run JSON for CLI/binary consumption\n const rawRunPath = this.options.rawRunPath;\n if (rawRunPath) {\n const absolutePath = path.isAbsolute(rawRunPath)\n ? rawRunPath\n : path.join(root, rawRunPath);\n const dir = path.dirname(absolutePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const payload = { schemaVersion: 1, ...rawRun };\n fs.writeFileSync(absolutePath, JSON.stringify(payload, null, 2), \"utf8\");\n }\n\n // Canonicalize\n const canonicalRun = canonicalizeRun(rawRun);\n\n // Generate reports\n const generator = new ReportGenerator(this.options);\n try {\n await generator.generate(canonicalRun);\n } catch (err) {\n console.error(\"Failed to generate reports:\", err);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "executable-stories-jest",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.5.0",
|
|
4
4
|
"description": "BDD-style executable stories for Jest with documentation generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"fast-glob": "^3.3.3",
|
|
36
|
-
"executable-stories-formatters": "1.0
|
|
36
|
+
"executable-stories-formatters": "1.1.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@jest/globals": "^30.4.1",
|