executable-stories-cypress 8.4.15 → 8.5.2

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.cjs CHANGED
@@ -100,6 +100,15 @@ function convertStoryDocsToEntries(docs) {
100
100
  phase: "runtime"
101
101
  });
102
102
  }
103
+ if (docs.state) {
104
+ warnIfStateLarge(docs.state.label, docs.state.value);
105
+ entries.push({
106
+ kind: "state",
107
+ label: docs.state.label,
108
+ value: docs.state.value,
109
+ phase: "runtime"
110
+ });
111
+ }
103
112
  if (docs.table) {
104
113
  entries.push({
105
114
  kind: "table",
@@ -163,6 +172,17 @@ function convertStoryDocsToEntries(docs) {
163
172
  }
164
173
  return entries;
165
174
  }
175
+ function warnIfStateLarge(label, value) {
176
+ try {
177
+ const len = JSON.stringify(value)?.length ?? 0;
178
+ if (len > 1e5) {
179
+ console.warn(
180
+ `[executable-stories] state "${label ?? ""}" is ${Math.round(len / 1024)}KB \u2014 consider capturing a projection`
181
+ );
182
+ }
183
+ } catch {
184
+ }
185
+ }
166
186
  function attachDoc(entry, children) {
167
187
  const ctx = getContext();
168
188
  if (children && children.length > 0) {
@@ -401,6 +421,15 @@ var story = {
401
421
  const content = JSON.stringify(options.value, null, 2);
402
422
  return attachDoc({ kind: "code", label: options.label, content, lang: "json", phase: "runtime" }, children);
403
423
  },
424
+ /**
425
+ * Capture what the world looks like at this step: a JSON-serializable data
426
+ * snapshot that becomes a storyboard frame. Consecutive states with the same
427
+ * label are diffed downstream, so snapshot the same projection at each step.
428
+ */
429
+ state(options, children) {
430
+ warnIfStateLarge(options.label, options.value);
431
+ return attachDoc({ kind: "state", label: options.label, value: options.value, phase: "runtime" }, children);
432
+ },
404
433
  code(options, children) {
405
434
  return attachDoc({ kind: "code", label: options.label, content: options.content, lang: options.lang, phase: "runtime" }, children);
406
435
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts"],"sourcesContent":["/**\n * Cypress Executable Stories\n *\n * BDD-style executable documentation for Cypress.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\n// Story API\nimport { story, doc, getAndClearMeta } from './story-api';\nimport type { StepMarker } from './story-api';\nexport { story, doc, getAndClearMeta };\nexport type { Story, RecordMetaPayload, StepMarker } from './story-api';\n\n// Top-level step helpers (framework contract)\nexport const given: StepMarker = story.given;\nexport const when: StepMarker = story.when;\nexport const then: StepMarker = story.then;\nexport const and: StepMarker = story.and;\nexport const but: StepMarker = story.but;\n\n// Re-export types from local types module\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n","/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts"],"sourcesContent":["/**\n * Cypress Executable Stories\n *\n * BDD-style executable documentation for Cypress.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\n// Story API\nimport { story, doc, getAndClearMeta } from './story-api';\nimport type { StepMarker } from './story-api';\nexport { story, doc, getAndClearMeta };\nexport type { Story, RecordMetaPayload, StepMarker } from './story-api';\n\n// Top-level step helpers (framework contract)\nexport const given: StepMarker = story.given;\nexport const when: StepMarker = story.when;\nexport const then: StepMarker = story.then;\nexport const and: StepMarker = story.and;\nexport const but: StepMarker = story.but;\n\n// Re-export types from local types module\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n","/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n StateOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.state) {\n warnIfStateLarge(docs.state.label, docs.state.value);\n entries.push({\n kind: 'state',\n label: docs.state.label,\n value: docs.state.value,\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\n/**\n * Warn (non-fatal) when a state snapshot serializes past 100KB — the entry is\n * still recorded, but a projection is usually what the storyboard needs.\n */\nfunction warnIfStateLarge(label: string | undefined, value: unknown): void {\n try {\n const len = JSON.stringify(value)?.length ?? 0;\n if (len > 100_000) {\n console.warn(\n `[executable-stories] state \"${label ?? ''}\" is ${Math.round(len / 1024)}KB — consider capturing a projection`,\n );\n }\n } catch {\n // Non-serializable value: recorded as-is, size unknown.\n }\n}\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n /**\n * Capture what the world looks like at this step: a JSON-serializable data\n * snapshot that becomes a storyboard frame. Consecutive states with the same\n * label are diffed downstream, so snapshot the same projection at each step.\n */\n state(options: StateOptions, children?: DocEntry[]): DocEntry {\n warnIfStateLarge(options.label, options.value);\n return attachDoc({ kind: 'state', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -38,6 +38,7 @@ interface StoryDocs {
38
38
  tag?: string | string[];
39
39
  kv?: Record<string, unknown>;
40
40
  json?: JsonOptions;
41
+ state?: StateOptions;
41
42
  table?: TableOptions;
42
43
  link?: LinkOptions;
43
44
  code?: CodeOptions;
@@ -72,6 +73,12 @@ interface JsonOptions {
72
73
  label: string;
73
74
  value: unknown;
74
75
  }
76
+ interface StateOptions {
77
+ /** Optional snapshot name. Consecutive states with the same label are diffed downstream. */
78
+ label?: string;
79
+ /** JSON-serializable snapshot of the world at this step. */
80
+ value: unknown;
81
+ }
75
82
  interface CodeOptions {
76
83
  label: string;
77
84
  content: string;
@@ -196,6 +203,12 @@ declare const story: {
196
203
  tag(name: string | string[], children?: DocEntry[]): DocEntry;
197
204
  kv(options: KvOptions, children?: DocEntry[]): DocEntry;
198
205
  json(options: JsonOptions, children?: DocEntry[]): DocEntry;
206
+ /**
207
+ * Capture what the world looks like at this step: a JSON-serializable data
208
+ * snapshot that becomes a storyboard frame. Consecutive states with the same
209
+ * label are diffed downstream, so snapshot the same projection at each step.
210
+ */
211
+ state(options: StateOptions, children?: DocEntry[]): DocEntry;
199
212
  code(options: CodeOptions, children?: DocEntry[]): DocEntry;
200
213
  table(options: TableOptions, children?: DocEntry[]): DocEntry;
201
214
  link(options: LinkOptions, children?: DocEntry[]): DocEntry;
package/dist/index.d.ts CHANGED
@@ -38,6 +38,7 @@ interface StoryDocs {
38
38
  tag?: string | string[];
39
39
  kv?: Record<string, unknown>;
40
40
  json?: JsonOptions;
41
+ state?: StateOptions;
41
42
  table?: TableOptions;
42
43
  link?: LinkOptions;
43
44
  code?: CodeOptions;
@@ -72,6 +73,12 @@ interface JsonOptions {
72
73
  label: string;
73
74
  value: unknown;
74
75
  }
76
+ interface StateOptions {
77
+ /** Optional snapshot name. Consecutive states with the same label are diffed downstream. */
78
+ label?: string;
79
+ /** JSON-serializable snapshot of the world at this step. */
80
+ value: unknown;
81
+ }
75
82
  interface CodeOptions {
76
83
  label: string;
77
84
  content: string;
@@ -196,6 +203,12 @@ declare const story: {
196
203
  tag(name: string | string[], children?: DocEntry[]): DocEntry;
197
204
  kv(options: KvOptions, children?: DocEntry[]): DocEntry;
198
205
  json(options: JsonOptions, children?: DocEntry[]): DocEntry;
206
+ /**
207
+ * Capture what the world looks like at this step: a JSON-serializable data
208
+ * snapshot that becomes a storyboard frame. Consecutive states with the same
209
+ * label are diffed downstream, so snapshot the same projection at each step.
210
+ */
211
+ state(options: StateOptions, children?: DocEntry[]): DocEntry;
199
212
  code(options: CodeOptions, children?: DocEntry[]): DocEntry;
200
213
  table(options: TableOptions, children?: DocEntry[]): DocEntry;
201
214
  link(options: LinkOptions, children?: DocEntry[]): DocEntry;
package/dist/index.js CHANGED
@@ -67,6 +67,15 @@ function convertStoryDocsToEntries(docs) {
67
67
  phase: "runtime"
68
68
  });
69
69
  }
70
+ if (docs.state) {
71
+ warnIfStateLarge(docs.state.label, docs.state.value);
72
+ entries.push({
73
+ kind: "state",
74
+ label: docs.state.label,
75
+ value: docs.state.value,
76
+ phase: "runtime"
77
+ });
78
+ }
70
79
  if (docs.table) {
71
80
  entries.push({
72
81
  kind: "table",
@@ -130,6 +139,17 @@ function convertStoryDocsToEntries(docs) {
130
139
  }
131
140
  return entries;
132
141
  }
142
+ function warnIfStateLarge(label, value) {
143
+ try {
144
+ const len = JSON.stringify(value)?.length ?? 0;
145
+ if (len > 1e5) {
146
+ console.warn(
147
+ `[executable-stories] state "${label ?? ""}" is ${Math.round(len / 1024)}KB \u2014 consider capturing a projection`
148
+ );
149
+ }
150
+ } catch {
151
+ }
152
+ }
133
153
  function attachDoc(entry, children) {
134
154
  const ctx = getContext();
135
155
  if (children && children.length > 0) {
@@ -368,6 +388,15 @@ var story = {
368
388
  const content = JSON.stringify(options.value, null, 2);
369
389
  return attachDoc({ kind: "code", label: options.label, content, lang: "json", phase: "runtime" }, children);
370
390
  },
391
+ /**
392
+ * Capture what the world looks like at this step: a JSON-serializable data
393
+ * snapshot that becomes a storyboard frame. Consecutive states with the same
394
+ * label are diffed downstream, so snapshot the same projection at each step.
395
+ */
396
+ state(options, children) {
397
+ warnIfStateLarge(options.label, options.value);
398
+ return attachDoc({ kind: "state", label: options.label, value: options.value, phase: "runtime" }, children);
399
+ },
371
400
  code(options, children) {
372
401
  return attachDoc({ kind: "code", label: options.label, content: options.content, lang: options.lang, phase: "runtime" }, children);
373
402
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts","../src/index.ts"],"sourcesContent":["/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n","/**\n * Cypress Executable Stories\n *\n * BDD-style executable documentation for Cypress.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\n// Story API\nimport { story, doc, getAndClearMeta } from './story-api';\nimport type { StepMarker } from './story-api';\nexport { story, doc, getAndClearMeta };\nexport type { Story, RecordMetaPayload, StepMarker } from './story-api';\n\n// Top-level step helpers (framework contract)\nexport const given: StepMarker = story.given;\nexport const when: StepMarker = story.when;\nexport const then: StepMarker = story.then;\nexport const and: StepMarker = story.and;\nexport const but: StepMarker = story.but;\n\n// Re-export types from local types module\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n"],"mappings":";AA0BO,SAAS,kBAAkB,SAAmC;AACnE,QAAM,UAAU,CAAC,QAAQ,MAAM,QAAQ,KAAK,QAAQ,OAAO,EAAE;IAC3D,CAAC,MAAM,MAAM;EACf;AACA,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI;MACR;IACF;EACF;AACA,SAAO;IACL,MAAM;IACN,MAAM,QAAQ;IACd,KAAK,QAAQ;IACb,SAAS,QAAQ;IACjB,OAAO,QAAQ;IACf,QAAQ,QAAQ;IAChB,OAAO;EACT;AACF;;;ACiEA,IAAI,gBAAqC;AAGzC,IAAI,qBAAqB;AAKzB,SAAS,aAA2B;AAClC,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,iBACP,QACgC;AAChC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,MAAM,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AACpD,SAAO,IAAI,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,EAAE,IAAI,EAAE,IAAI,CAAE;AAC/D;AAEA,SAAS,0BAA0B,MAA6B;AAC9D,QAAM,UAAsB,CAAC;AAE7B,MAAI,KAAK,MAAM;AACb,YAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,MAAM,OAAO,UAAU,CAAC;AAAA,EAClE;AACA,MAAI,KAAK,KAAK;AACZ,UAAM,QAAQ,MAAM,QAAQ,KAAK,GAAG,IAAI,KAAK,MAAM,CAAC,KAAK,GAAG;AAC5D,YAAQ,KAAK,EAAE,MAAM,OAAO,OAAO,OAAO,UAAU,CAAC;AAAA,EACvD;AACA,MAAI,KAAK,IAAI;AACX,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,KAAK,EAAE,GAAG;AACpD,cAAQ,KAAK,EAAE,MAAM,MAAM,OAAO,OAAO,OAAO,UAAU,CAAC;AAAA,IAC7D;AAAA,EACF;AACA,MAAI,KAAK,MAAM;AACb,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAO,KAAK,KAAK;AAAA,MACjB,SAAS,KAAK,KAAK;AAAA,MACnB,MAAM,KAAK,KAAK;AAAA,MAChB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,MAAM;AACb,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAO,KAAK,KAAK;AAAA,MACjB,SAAS,KAAK,UAAU,KAAK,KAAK,OAAO,MAAM,CAAC;AAAA,MAChD,MAAM;AAAA,MACN,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,OAAO;AACd,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAO,KAAK,MAAM;AAAA,MAClB,SAAS,KAAK,MAAM;AAAA,MACpB,MAAM,KAAK,MAAM;AAAA,MACjB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,MAAM;AACb,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAO,KAAK,KAAK;AAAA,MACjB,KAAK,KAAK,KAAK;AAAA,MACf,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,SAAS;AAChB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAO,KAAK,QAAQ;AAAA,MACpB,UAAU,KAAK,QAAQ;AAAA,MACvB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,SAAS;AAChB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,KAAK,QAAQ;AAAA,MACnB,OAAO,KAAK,QAAQ;AAAA,MACpB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,YAAY;AACnB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,KAAK,WAAW;AAAA,MACtB,KAAK,KAAK,WAAW;AAAA,MACrB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,OAAO;AACd,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,KAAK,MAAM;AAAA,MACjB,SAAS,KAAK,MAAM;AAAA,MACpB,QAAQ,KAAK,MAAM;AAAA,MACnB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,KAAK,MAAM;AACb,YAAQ,KAAK,kBAAkB,KAAK,IAAI,CAAC;AAAA,EAC3C;AACA,MAAI,KAAK,QAAQ;AACf,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,KAAK,OAAO;AAAA,MAClB,MAAM,KAAK,OAAO;AAAA,MAClB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAGA,SAAS,UAAU,OAAiB,UAAiC;AACnE,QAAM,MAAM,WAAW;AACvB,MAAI,YAAY,SAAS,SAAS,GAAG;AACnC,UAAM,WAAW;AACjB,UAAM,WAAW,IAAI,IAAc,QAAQ;AAC3C,UAAM,aAAa,CAAC,SAAqB,KAAK,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAE5E,QAAI,KAAK,OAAO,WAAW,IAAI,KAAK,QAAQ,CAAC,CAAC;AAC9C,eAAW,QAAQ,IAAI,KAAK,OAAO;AACjC,UAAI,KAAK,KAAM,MAAK,OAAO,WAAW,KAAK,IAAI;AAAA,IACjD;AAAA,EACF;AACA,MAAI,IAAI,aAAa;AACnB,QAAI,YAAY,SAAS,CAAC;AAC1B,QAAI,YAAY,KAAK,KAAK,KAAK;AAAA,EACjC,OAAO;AACL,QAAI,KAAK,SAAS,CAAC;AACnB,QAAI,KAAK,KAAK,KAAK,KAAK;AAAA,EAC1B;AACA,SAAO;AACT;AAMA,SAAS,iBAAiB,WAA2C;AACnE,MAAI,UAAU,UAAU,EAAG,QAAO;AAClC,QAAM,YAAY,UAAU,MAAM,GAAG,EAAE;AACvC,SAAO,UAAU,SAAS,IAAI,YAAY;AAC5C;AAEA,SAAS,wBACP,OACoB;AACpB,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,KAAK;AACpB,QAAI,OAAO,WAAW,YAAY,OAAO,SAAS,EAAG,QAAO;AAE5D,UAAM,UAAU,KAAK;AACrB,QAAI,WAAW,OAAO,YAAY,YAAY,YAAY,MAAM;AAC9D,YAAM,SAAU,QAAkC;AAClD,UAAI,OAAO,WAAW,YAAY,OAAO,SAAS,EAAG,QAAO;AAAA,IAC9D;AAAA,EACF;AACA,SAAO;AACT;AAiBA,SAAS,iBAAiB,SAAsB,MAA6B;AAI3E,WAAS,WAAc,MAAc,YAA2D;AAC9F,UAAM,MAAM,WAAW;AACvB,UAAM,aAAa,OAAO,eAAe;AACzC,UAAM,kBAAkB,MAAM,QAAQ,UAAU;AAEhD,UAAM,mBACH,YAAY,WAAW,YAAY,UAAU,YAAY,WAC1D,IAAI,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO,IAC5C,QACA;AAEN,QAAI,WAAuB,CAAC;AAC5B,QAAI,CAAC,cAAc,CAAC,mBAAmB,YAAY;AACjD,iBAAW,0BAA0B,UAAuB;AAAA,IAC9D;AAEA,UAAM,OAAkB;AAAA,MACtB,IAAI,QAAQ,IAAI,aAAa;AAAA,MAC7B,SAAS;AAAA,MACT;AAAA,MACA,MAAM;AAAA,MACN,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,aAAa,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,IACxC;AAEA,QAAI,KAAK,MAAM,KAAK,IAAI;AACxB,QAAI,cAAc;AAGlB,QAAI,iBAAiB;AACnB,YAAM,WAAW;AACjB,UAAI,SAAS,SAAS,GAAG;AACvB,cAAM,WAAW,IAAI,IAAc,QAAQ;AAE3C,YAAI,KAAK,QAAQ,IAAI,KAAK,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAEpE,mBAAW,YAAY,IAAI,KAAK,OAAO;AACrC,cAAI,aAAa,QAAQ,SAAS,MAAM;AACtC,qBAAS,OAAO,SAAS,KAAK,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAAA,UAC9D;AAAA,QACF;AACA,aAAK,OAAO,CAAC,GAAI,KAAK,QAAQ,CAAC,GAAI,GAAG,QAAQ;AAAA,MAChD;AACA;AAAA,IACF;AAEA,QAAI,CAAC,WAAY;AAEjB,UAAM,OAAO;AACb,UAAM,QAAQ,YAAY,IAAI;AAE9B,QAAI;AACF,YAAM,SAAS,KAAK;AACpB,UAAI,kBAAkB,SAAS;AAC7B,eAAO,OAAO;AAAA,UACZ,CAAC,QAAQ;AAAE,iBAAK,aAAa,YAAY,IAAI,IAAI;AAAO,mBAAO;AAAA,UAAK;AAAA,UACpE,CAAC,QAAQ;AAAE,iBAAK,aAAa,YAAY,IAAI,IAAI;AAAO,kBAAM;AAAA,UAAK;AAAA,QACrE;AAAA,MACF;AACA,WAAK,aAAa,YAAY,IAAI,IAAI;AACtC,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,aAAa,YAAY,IAAI,IAAI;AACtC,YAAM;AAAA,IACR;AAAA,EACF;AACA,QAAM,SAAS;AACf,SAAO,OAAO,OAAO,SAAS,iBAAiB,SAAS,MAAM;AAC9D,SAAO,OAAO,OAAO,SAAS,iBAAiB,SAAS,MAAM;AAC9D,SAAO,OAAO,OAAO,SAAS,iBAAiB,SAAS,MAAM;AAC9D,SAAO,QAAQ,OAAO,SAAS,iBAAiB,SAAS,OAAO;AAChE,SAAO,aAAa,OAAO,SAAS,iBAAiB,SAAS,YAAY;AAC1E,SAAO;AACT;AAMA,SAAS,KAAK,SAAwB,kBAAiC;AACrE,QAAM,cAAc,QAAQ;AAC5B,QAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,uFAAuF;AAAA,EACzG;AAEA,QAAM,YAAY,YAAY,aAAa,CAAC,YAAY,KAAK;AAC7D,QAAM,WAAW,oBAAoB,YAAY;AACjD,QAAM,YAAY,iBAAiB,SAAS;AAC5C,QAAM,eAAe,MAAM,YAAY;AAEvC,QAAM,OAAkB;AAAA,IACtB;AAAA,IACA,OAAO,CAAC;AAAA,IACR;AAAA,IACA,MAAM,SAAS;AAAA,IACf,SAAS,iBAAiB,SAAS,MAAM;AAAA,IACzC,QAAQ,SAAS;AAAA,IACjB,MAAM,SAAS;AAAA,IACf,aAAa;AAAA,EACf;AAEA,kBAAgB;AAAA,IACd;AAAA,IACA,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa,CAAC;AAAA,IACd,cAAc,oBAAI,IAAI;AAAA,IACtB,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA,kBAAkB,SAAS;AAAA,IAC3B,eAAe;AAAA,EACjB;AACF;AAEA,SAAS,YAAY,MAAkC,OAAe,MAAoB,SAAiC;AACzH,QAAM,WAAY,WAA+B;AACjD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,oFAAoF;AAAA,EACtG;AAEA,QAAM,SACJ,SAAS,SACL,SAAS,OACT,SAAS,SACP,SAAS,OACT;AAER,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,aAAa,IAAI,0CAA0C;AAAA,EAC7E;AAEA,SAAO,OAAO,OAAO,MAAM;AACzB,SAAK,OAAO;AACZ,WAAO,KAAK;AAAA,EACd,CAAC;AACH;AAOO,SAAS,kBAA4C;AAC1D,MAAI,CAAC,cAAe,QAAO;AAC3B,QAAM,UAA6B;AAAA,IACjC,cAAc,cAAc;AAAA,IAC5B,WAAW,cAAc;AAAA,IACzB,MAAM,cAAc;AAAA,IACpB,aAAa,cAAc,YAAY,SAAS,IAAI,cAAc,cAAc;AAAA,IAChF,WAAW,cAAc;AAAA,EAC3B;AACA,kBAAgB;AAChB,SAAO;AACT;AAUA,SAAS,GAAM,SAAsB,MAAc,MAAkB;AACnE,QAAM,MAAM,WAAW;AAEvB,QAAM,mBACH,YAAY,WAAW,YAAY,UAAU,YAAY,WAC1D,IAAI,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO,IAC5C,QACA;AAEN,QAAM,OAAkB;AAAA,IACtB,IAAI,QAAQ,IAAI,aAAa;AAAA,IAC7B,SAAS;AAAA,IACT;AAAA,IACA,MAAM,CAAC;AAAA,IACP,SAAS;AAAA,EACX;AACA,MAAI,KAAK,MAAM,KAAK,IAAI;AACxB,MAAI,cAAc;AAElB,QAAM,QAAQ,YAAY,IAAI;AAC9B,MAAI;AACF,UAAM,SAAS,KAAK;AACpB,QAAI,kBAAkB,SAAS;AAC7B,aAAO,OAAO;AAAA,QACZ,CAAC,QAAQ;AACP,eAAK,aAAa,YAAY,IAAI,IAAI;AACtC,iBAAO;AAAA,QACT;AAAA,QACA,CAAC,QAAQ;AACP,eAAK,aAAa,YAAY,IAAI,IAAI;AACtC,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,SAAK,aAAa,YAAY,IAAI,IAAI;AACtC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,SAAK,aAAa,YAAY,IAAI,IAAI;AACtC,UAAM;AAAA,EACR;AACF;AAMA,SAAS,YAAe,MAAc,MAAkB;AACtD,SAAO,GAAG,QAAQ,MAAM,IAAI;AAC9B;AAMO,IAAM,QAAQ;AAAA,EACnB;AAAA,EACA,KAAK,OAAe,MAAoB,SAAiC;AACvE,WAAO,YAAY,QAAQ,OAAO,MAAM,OAAO;AAAA,EACjD;AAAA,EACA,KAAK,OAAe,MAAoB,SAAiC;AACvE,WAAO,YAAY,QAAQ,OAAO,MAAM,OAAO;AAAA,EACjD;AAAA;AAAA,EAGA,OAAO,iBAAiB,OAAO;AAAA,EAC/B,MAAM,iBAAiB,MAAM;AAAA,EAC7B,MAAM,iBAAiB,MAAM;AAAA,EAC7B,KAAK,iBAAiB,KAAK;AAAA,EAC3B,KAAK,iBAAiB,KAAK;AAAA;AAAA,EAG3B,SAAS,iBAAiB,OAAO;AAAA,EACjC,KAAK,iBAAiB,MAAM;AAAA,EAC5B,QAAQ,iBAAiB,MAAM;AAAA;AAAA,EAG/B,OAAO,iBAAiB,OAAO;AAAA,EAC/B,SAAS,iBAAiB,OAAO;AAAA,EACjC,SAAS,iBAAiB,MAAM;AAAA,EAChC,QAAQ,iBAAiB,MAAM;AAAA,EAC/B,QAAQ,iBAAiB,MAAM;AAAA;AAAA,EAG/B,KAAK,MAAc,UAAiC;AAClD,WAAO,UAAU,EAAE,MAAM,QAAQ,MAAM,OAAO,UAAU,GAAG,QAAQ;AAAA,EACrE;AAAA,EAEA,IAAI,MAAyB,UAAiC;AAC5D,UAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAChD,WAAO,UAAU,EAAE,MAAM,OAAO,OAAO,OAAO,UAAU,GAAG,QAAQ;AAAA,EACrE;AAAA,EAEA,GAAG,SAAoB,UAAiC;AACtD,WAAO,UAAU,EAAE,MAAM,MAAM,OAAO,QAAQ,OAAO,OAAO,QAAQ,OAAO,OAAO,UAAU,GAAG,QAAQ;AAAA,EACzG;AAAA,EAEA,KAAK,SAAsB,UAAiC;AAC1D,UAAM,UAAU,KAAK,UAAU,QAAQ,OAAO,MAAM,CAAC;AACrD,WAAO,UAAU,EAAE,MAAM,QAAQ,OAAO,QAAQ,OAAO,SAAS,MAAM,QAAQ,OAAO,UAAU,GAAG,QAAQ;AAAA,EAC5G;AAAA,EAEA,KAAK,SAAsB,UAAiC;AAC1D,WAAO,UAAU,EAAE,MAAM,QAAQ,OAAO,QAAQ,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,MAAM,OAAO,UAAU,GAAG,QAAQ;AAAA,EACnI;AAAA,EAEA,MAAM,SAAuB,UAAiC;AAC5D,WAAO,UAAU,EAAE,MAAM,SAAS,OAAO,QAAQ,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,MAAM,OAAO,UAAU,GAAG,QAAQ;AAAA,EACpI;AAAA,EAEA,KAAK,SAAsB,UAAiC;AAC1D,WAAO,UAAU,EAAE,MAAM,QAAQ,OAAO,QAAQ,OAAO,KAAK,QAAQ,KAAK,OAAO,UAAU,GAAG,QAAQ;AAAA,EACvG;AAAA,EAEA,QAAQ,SAAyB,UAAiC;AAChE,WAAO,UAAU,EAAE,MAAM,WAAW,OAAO,QAAQ,OAAO,UAAU,QAAQ,UAAU,OAAO,UAAU,GAAG,QAAQ;AAAA,EACpH;AAAA,EAEA,QAAQ,SAAyB,UAAiC;AAChE,WAAO,UAAU,EAAE,MAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,QAAQ,OAAO,OAAO,UAAU,GAAG,QAAQ;AAAA,EAC5G;AAAA,EAEA,WAAW,SAA4B,UAAiC;AACtE,WAAO,UAAU,EAAE,MAAM,cAAc,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,OAAO,UAAU,GAAG,QAAQ;AAAA,EAC3G;AAAA,EAEA,MAAM,SAAuB,UAAiC;AAC5D,WAAO,UAAU,EAAE,MAAM,SAAS,MAAM,QAAQ,MAAM,SAAS,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,OAAO,UAAU,GAAG,QAAQ;AAAA,EACtI;AAAA,EAEA,KAAK,SAAsB,UAAiC;AAC1D,WAAO,UAAU,kBAAkB,OAAO,GAAG,QAAQ;AAAA,EACvD;AAAA,EAEA,OAAO,SAAwB,UAAiC;AAC9D,WAAO,UAAU,EAAE,MAAM,UAAU,MAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM,OAAO,UAAU,GAAG,QAAQ;AAAA,EACzG;AAAA;AAAA,EAGA,OAAO,SAAkC;AACvC,UAAM,MAAM,WAAW;AACvB,UAAM,YAAY,IAAI,cAClB,IAAI,KAAK,MAAM,QAAQ,IAAI,WAAW,IACtC;AACJ,QAAI,YAAY,KAAK;AAAA,MACnB,GAAG;AAAA,MACH,WAAW,cAAc,UAAa,aAAa,IAAI,YAAY;AAAA,MACnE,QAAQ,IAAI,aAAa;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,YAAY,OAAqD;AAC/D,UAAM,MAAM,WAAW;AACvB,QAAI,YAAY;AAEhB,QAAI,IAAI,cAAe;AACvB,UAAM,UAAU,wBAAwB,KAAK;AAC7C,QAAI,CAAC,QAAS;AAEd,QAAI,KAAK,OAAO;AAAA,MACd,GAAG,IAAI,KAAK;AAAA,MACZ,MAAM,EAAE,QAAQ;AAAA,IAClB;AACA,QAAI,KAAK,SAAS,CAAC;AACnB,QAAI,KAAK,KAAK,KAAK,EAAE,MAAM,MAAM,OAAO,YAAY,OAAO,SAAS,OAAO,UAAU,CAAC;AAEtF,UAAM,WAAW,IAAI;AACrB,QAAI,UAAU;AACZ,YAAM,MAAM,SAAS,QAAQ,aAAa,OAAO;AACjD,UAAI,KAAK,KAAK,KAAK,EAAE,MAAM,QAAQ,OAAO,cAAc,KAAK,OAAO,UAAU,CAAC;AAAA,IACjF;AACA,QAAI,gBAAgB;AAAA,EACtB;AAAA;AAAA,EAGA,aAAqB;AACnB,UAAM,MAAM,WAAW;AACvB,UAAM,QAAQ,IAAI;AAClB,UAAM,YAAY,IAAI,cAClB,IAAI,KAAK,MAAM,QAAQ,IAAI,WAAW,IACtC;AACJ,QAAI,aAAa,IAAI,OAAO;AAAA,MAC1B,OAAO,YAAY,IAAI;AAAA,MACvB,WAAW,cAAc,UAAa,aAAa,IAAI,YAAY;AAAA,MACnE,QAAQ,IAAI,aAAa;AAAA,MACzB,UAAU;AAAA,IACZ,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,OAAqB;AAC5B,UAAM,MAAM,WAAW;AACvB,UAAM,QAAQ,IAAI,aAAa,IAAI,KAAK;AACxC,QAAI,CAAC,SAAS,MAAM,SAAU;AAE9B,UAAM,WAAW;AACjB,UAAM,aAAa,YAAY,IAAI,IAAI,MAAM;AAE7C,QAAI;AACJ,QAAI,MAAM,QAAQ;AAChB,aAAO,IAAI,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,MAAM;AAAA,IACzD;AACA,QAAI,CAAC,QAAQ,MAAM,cAAc,QAAW;AAC1C,aAAO,IAAI,KAAK,MAAM,MAAM,SAAS;AAAA,IACvC;AAEA,QAAI,MAAM;AACR,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA,EAGA;AAAA,EACA,QAAQ;AACV;AAEA,IAAM,gBAAgB;AAAA,EACpB,OAAO,MAAM;AAAA,EACb,MAAM,MAAM;AAAA,EACZ,MAAM,MAAM;AAAA,EACZ,KAAK,MAAM;AAAA,EACX,KAAK,MAAM;AAAA,EACX,SAAS,MAAM;AAAA,EACf,KAAK,MAAM;AAAA,EACX,QAAQ,MAAM;AAAA,EACd,OAAO,MAAM;AAAA,EACb,SAAS,MAAM;AAAA,EACf,SAAS,MAAM;AAAA,EACf,QAAQ,MAAM;AAAA,EACd,QAAQ,MAAM;AAChB;AAIA,SAAS,SAAS,OAAe,UAAwD;AACvF,OAAK,QAAW,KAAK;AACrB,MAAI,SAAU,UAAS,aAAa;AACtC;AAEO,IAAM,MAAM;AAAA,EACjB,OAAO;AACT;;;ACrqBO,IAAM,QAAoB,MAAM;AAChC,IAAM,OAAmB,MAAM;AAC/B,IAAM,OAAmB,MAAM;AAC/B,IAAM,MAAkB,MAAM;AAC9B,IAAM,MAAkB,MAAM;","names":[]}
1
+ {"version":3,"sources":["../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts","../src/index.ts"],"sourcesContent":["/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n StateOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.state) {\n warnIfStateLarge(docs.state.label, docs.state.value);\n entries.push({\n kind: 'state',\n label: docs.state.label,\n value: docs.state.value,\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\n/**\n * Warn (non-fatal) when a state snapshot serializes past 100KB — the entry is\n * still recorded, but a projection is usually what the storyboard needs.\n */\nfunction warnIfStateLarge(label: string | undefined, value: unknown): void {\n try {\n const len = JSON.stringify(value)?.length ?? 0;\n if (len > 100_000) {\n console.warn(\n `[executable-stories] state \"${label ?? ''}\" is ${Math.round(len / 1024)}KB — consider capturing a projection`,\n );\n }\n } catch {\n // Non-serializable value: recorded as-is, size unknown.\n }\n}\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n /**\n * Capture what the world looks like at this step: a JSON-serializable data\n * snapshot that becomes a storyboard frame. Consecutive states with the same\n * label are diffed downstream, so snapshot the same projection at each step.\n */\n state(options: StateOptions, children?: DocEntry[]): DocEntry {\n warnIfStateLarge(options.label, options.value);\n return attachDoc({ kind: 'state', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n","/**\n * Cypress Executable Stories\n *\n * BDD-style executable documentation for Cypress.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\n// Story API\nimport { story, doc, getAndClearMeta } from './story-api';\nimport type { StepMarker } from './story-api';\nexport { story, doc, getAndClearMeta };\nexport type { Story, RecordMetaPayload, StepMarker } from './story-api';\n\n// Top-level step helpers (framework contract)\nexport const given: StepMarker = story.given;\nexport const when: StepMarker = story.when;\nexport const then: StepMarker = story.then;\nexport const and: StepMarker = story.and;\nexport const but: StepMarker = story.but;\n\n// Re-export types from local types module\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n"],"mappings":"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","names":[]}
package/dist/support.cjs CHANGED
@@ -69,6 +69,15 @@ function convertStoryDocsToEntries(docs) {
69
69
  phase: "runtime"
70
70
  });
71
71
  }
72
+ if (docs.state) {
73
+ warnIfStateLarge(docs.state.label, docs.state.value);
74
+ entries.push({
75
+ kind: "state",
76
+ label: docs.state.label,
77
+ value: docs.state.value,
78
+ phase: "runtime"
79
+ });
80
+ }
72
81
  if (docs.table) {
73
82
  entries.push({
74
83
  kind: "table",
@@ -132,6 +141,17 @@ function convertStoryDocsToEntries(docs) {
132
141
  }
133
142
  return entries;
134
143
  }
144
+ function warnIfStateLarge(label, value) {
145
+ try {
146
+ const len = JSON.stringify(value)?.length ?? 0;
147
+ if (len > 1e5) {
148
+ console.warn(
149
+ `[executable-stories] state "${label ?? ""}" is ${Math.round(len / 1024)}KB \u2014 consider capturing a projection`
150
+ );
151
+ }
152
+ } catch {
153
+ }
154
+ }
135
155
  function attachDoc(entry, children) {
136
156
  const ctx = getContext();
137
157
  if (children && children.length > 0) {
@@ -370,6 +390,15 @@ var story = {
370
390
  const content = JSON.stringify(options.value, null, 2);
371
391
  return attachDoc({ kind: "code", label: options.label, content, lang: "json", phase: "runtime" }, children);
372
392
  },
393
+ /**
394
+ * Capture what the world looks like at this step: a JSON-serializable data
395
+ * snapshot that becomes a storyboard frame. Consecutive states with the same
396
+ * label are diffed downstream, so snapshot the same projection at each step.
397
+ */
398
+ state(options, children) {
399
+ warnIfStateLarge(options.label, options.value);
400
+ return attachDoc({ kind: "state", label: options.label, value: options.value, phase: "runtime" }, children);
401
+ },
373
402
  code(options, children) {
374
403
  return attachDoc({ kind: "code", label: options.label, content: options.content, lang: options.lang, phase: "runtime" }, children);
375
404
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts","../src/support.ts"],"sourcesContent":["/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n","/**\n * Cypress support file for executable-stories.\n * Register this in cypress/support/e2e.ts (or support file) so story meta\n * is sent to Node after each test for the reporter to consume.\n *\n * @example\n * In cypress/support/e2e.ts:\n * import 'executable-stories-cypress/support';\n */\n\nimport { getAndClearMeta } from \"./story-api\";\n\nconst TASK_NAME = \"executableStories:recordMeta\";\n\nafterEach(function () {\n const payload = getAndClearMeta();\n if (payload) {\n cy.task(TASK_NAME, payload);\n }\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts","../src/support.ts"],"sourcesContent":["/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n StateOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.state) {\n warnIfStateLarge(docs.state.label, docs.state.value);\n entries.push({\n kind: 'state',\n label: docs.state.label,\n value: docs.state.value,\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\n/**\n * Warn (non-fatal) when a state snapshot serializes past 100KB — the entry is\n * still recorded, but a projection is usually what the storyboard needs.\n */\nfunction warnIfStateLarge(label: string | undefined, value: unknown): void {\n try {\n const len = JSON.stringify(value)?.length ?? 0;\n if (len > 100_000) {\n console.warn(\n `[executable-stories] state \"${label ?? ''}\" is ${Math.round(len / 1024)}KB — consider capturing a projection`,\n );\n }\n } catch {\n // Non-serializable value: recorded as-is, size unknown.\n }\n}\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n /**\n * Capture what the world looks like at this step: a JSON-serializable data\n * snapshot that becomes a storyboard frame. Consecutive states with the same\n * label are diffed downstream, so snapshot the same projection at each step.\n */\n state(options: StateOptions, children?: DocEntry[]): DocEntry {\n warnIfStateLarge(options.label, options.value);\n return attachDoc({ kind: 'state', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n","/**\n * Cypress support file for executable-stories.\n * Register this in cypress/support/e2e.ts (or support file) so story meta\n * is sent to Node after each test for the reporter to consume.\n *\n * @example\n * In cypress/support/e2e.ts:\n * import 'executable-stories-cypress/support';\n */\n\nimport { getAndClearMeta } from \"./story-api\";\n\nconst TASK_NAME = \"executableStories:recordMeta\";\n\nafterEach(function () {\n const payload = getAndClearMeta();\n if (payload) {\n cy.task(TASK_NAME, payload);\n }\n});\n"],"mappings":"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","names":[]}
package/dist/support.js CHANGED
@@ -67,6 +67,15 @@ function convertStoryDocsToEntries(docs) {
67
67
  phase: "runtime"
68
68
  });
69
69
  }
70
+ if (docs.state) {
71
+ warnIfStateLarge(docs.state.label, docs.state.value);
72
+ entries.push({
73
+ kind: "state",
74
+ label: docs.state.label,
75
+ value: docs.state.value,
76
+ phase: "runtime"
77
+ });
78
+ }
70
79
  if (docs.table) {
71
80
  entries.push({
72
81
  kind: "table",
@@ -130,6 +139,17 @@ function convertStoryDocsToEntries(docs) {
130
139
  }
131
140
  return entries;
132
141
  }
142
+ function warnIfStateLarge(label, value) {
143
+ try {
144
+ const len = JSON.stringify(value)?.length ?? 0;
145
+ if (len > 1e5) {
146
+ console.warn(
147
+ `[executable-stories] state "${label ?? ""}" is ${Math.round(len / 1024)}KB \u2014 consider capturing a projection`
148
+ );
149
+ }
150
+ } catch {
151
+ }
152
+ }
133
153
  function attachDoc(entry, children) {
134
154
  const ctx = getContext();
135
155
  if (children && children.length > 0) {
@@ -368,6 +388,15 @@ var story = {
368
388
  const content = JSON.stringify(options.value, null, 2);
369
389
  return attachDoc({ kind: "code", label: options.label, content, lang: "json", phase: "runtime" }, children);
370
390
  },
391
+ /**
392
+ * Capture what the world looks like at this step: a JSON-serializable data
393
+ * snapshot that becomes a storyboard frame. Consecutive states with the same
394
+ * label are diffed downstream, so snapshot the same projection at each step.
395
+ */
396
+ state(options, children) {
397
+ warnIfStateLarge(options.label, options.value);
398
+ return attachDoc({ kind: "state", label: options.label, value: options.value, phase: "runtime" }, children);
399
+ },
371
400
  code(options, children) {
372
401
  return attachDoc({ kind: "code", label: options.label, content: options.content, lang: options.lang, phase: "runtime" }, children);
373
402
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts","../src/support.ts"],"sourcesContent":["/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n","/**\n * Cypress support file for executable-stories.\n * Register this in cypress/support/e2e.ts (or support file) so story meta\n * is sent to Node after each test for the reporter to consume.\n *\n * @example\n * In cypress/support/e2e.ts:\n * import 'executable-stories-cypress/support';\n */\n\nimport { getAndClearMeta } from \"./story-api\";\n\nconst TASK_NAME = \"executableStories:recordMeta\";\n\nafterEach(function () {\n const payload = getAndClearMeta();\n if (payload) {\n cy.task(TASK_NAME, payload);\n }\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../executable-stories-core/src/utils/doc-builders.ts","../src/story-api.ts","../src/support.ts"],"sourcesContent":["/**\n * Canonical builders for doc entries whose construction carries a rule worth\n * keeping in one place. Adapters import these instead of re-implementing the\n * logic (the `html` exactly-one-of-source rule was previously copied verbatim\n * across the Vitest, Jest, Cypress, and Playwright adapters).\n */\n\nimport type { DocEntry } from \"../types/story.js\";\n\n/** Source/presentation options for an `html` doc entry. */\nexport interface HtmlDocOptions {\n /** Local HTML file path (inlined into the report by default). */\n path?: string;\n /** Remote URL rendered via iframe src. */\n url?: string;\n /** Inline HTML content rendered via iframe srcdoc. */\n content?: string;\n title?: string;\n /** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */\n height?: number | string;\n}\n\n/**\n * Build an `html` DocEntry, enforcing that exactly one of path/url/content is\n * set. Throws otherwise — this is the single source of that rule.\n */\nexport function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry {\n const sources = [options.path, options.url, options.content].filter(\n (v) => v !== undefined,\n );\n if (sources.length !== 1) {\n throw new Error(\n \"story.html() requires exactly one of path, url, or content\",\n );\n }\n return {\n kind: \"html\",\n path: options.path,\n url: options.url,\n content: options.content,\n title: options.title,\n height: options.height,\n phase: \"runtime\",\n };\n}\n","/**\n * Cypress story.* API for executable-stories.\n *\n * Uses native Cypress describe/it with opt-in documentation.\n * Story meta is flushed to Node via cy.task from the support file.\n *\n * @example\n * ```ts\n * import { story } from 'executable-stories-cypress';\n *\n * describe('Calculator', () => {\n * it('adds two numbers', () => {\n * story.init();\n *\n * story.given('two numbers 5 and 3');\n * const a = 5, b = 3;\n *\n * story.when('I add them together');\n * const result = a + b;\n *\n * story.then('the result is 8');\n * expect(result).toBe(8);\n * });\n * });\n * ```\n */\n\nimport type {\n StepKeyword,\n StepMode,\n StoryMeta,\n StoryStep,\n DocEntry,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n ScopedAttachment,\n RecordMetaPayload,\n NormalizedTicket,\n TicketInput,\n KvOptions,\n JsonOptions,\n StateOptions,\n CodeOptions,\n TableOptions,\n LinkOptions,\n SectionOptions,\n MermaidOptions,\n ScreenshotOptions,\n VideoOptions,\n HtmlOptions,\n CustomOptions,\n} from './types';\n// Import from core's browser-safe origin, NOT executable-stories-formatters:\n// this code runs in Cypress's browser bundle, and the formatters package pulls\n// in node:fs/path/stream (fine for the Node-side reporter, fatal for webpack's\n// browser build — UnhandledSchemeError). doc-builders has type-only deps.\nimport { buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';\n\n// Re-export types for consumers\nexport type {\n StoryMeta,\n StoryStep,\n DocEntry,\n StepKeyword,\n StoryDocs,\n StoryOptions,\n AttachmentOptions,\n NormalizedTicket,\n TicketInput,\n} from './types';\n\nexport type { RecordMetaPayload } from './types';\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface TimerEntry {\n start: number;\n stepIndex?: number;\n stepId?: string;\n consumed: boolean;\n}\n\ninterface StoryContext {\n meta: StoryMeta;\n currentStep: StoryStep | null;\n stepCounter: number;\n attachments: ScopedAttachment[];\n activeTimers: Map<number, TimerEntry>;\n timerCounter: number;\n specRelative: string;\n titlePath: string[];\n otelSpans?: ReadonlyArray<Record<string, unknown>>;\n traceUrlTemplate?: string;\n traceDocAdded: boolean;\n}\n\ntype ScenarioBody = () => unknown;\ntype ItLike = ((title: string, body: ScenarioBody) => unknown) & {\n skip?: (title: string, body: ScenarioBody) => unknown;\n only?: (title: string, body: ScenarioBody) => unknown;\n};\n\n// ============================================================================\n// Cypress-specific context\n// ============================================================================\n\n/** Active story context - set by story.init() */\nlet activeContext: StoryContext | null = null;\n\n/** Counter to track source order of stories (increments on each story.init call) */\nlet sourceOrderCounter = 0;\n\n/**\n * Get the current story context. Throws if story.init() wasn't called.\n */\nfunction getContext(): StoryContext {\n if (!activeContext) {\n throw new Error(\n \"story.init() must be called first. Use: it('name', () => { story.init(); ... });\"\n );\n }\n return activeContext;\n}\n\n// ============================================================================\n// Helper functions (inlined from core)\n// ============================================================================\n\nfunction normalizeTickets(\n ticket: TicketInput | TicketInput[] | undefined,\n): NormalizedTicket[] | undefined {\n if (!ticket) return undefined;\n const arr = Array.isArray(ticket) ? ticket : [ticket];\n return arr.map((t) => (typeof t === 'string' ? { id: t } : t));\n}\n\nfunction convertStoryDocsToEntries(docs: StoryDocs): DocEntry[] {\n const entries: DocEntry[] = [];\n\n if (docs.note) {\n entries.push({ kind: 'note', text: docs.note, phase: 'runtime' });\n }\n if (docs.tag) {\n const names = Array.isArray(docs.tag) ? docs.tag : [docs.tag];\n entries.push({ kind: 'tag', names, phase: 'runtime' });\n }\n if (docs.kv) {\n for (const [label, value] of Object.entries(docs.kv)) {\n entries.push({ kind: 'kv', label, value, phase: 'runtime' });\n }\n }\n if (docs.code) {\n entries.push({\n kind: 'code',\n label: docs.code.label,\n content: docs.code.content,\n lang: docs.code.lang,\n phase: 'runtime',\n });\n }\n if (docs.json) {\n entries.push({\n kind: 'code',\n label: docs.json.label,\n content: JSON.stringify(docs.json.value, null, 2),\n lang: 'json',\n phase: 'runtime',\n });\n }\n if (docs.state) {\n warnIfStateLarge(docs.state.label, docs.state.value);\n entries.push({\n kind: 'state',\n label: docs.state.label,\n value: docs.state.value,\n phase: 'runtime',\n });\n }\n if (docs.table) {\n entries.push({\n kind: 'table',\n label: docs.table.label,\n columns: docs.table.columns,\n rows: docs.table.rows,\n phase: 'runtime',\n });\n }\n if (docs.link) {\n entries.push({\n kind: 'link',\n label: docs.link.label,\n url: docs.link.url,\n phase: 'runtime',\n });\n }\n if (docs.section) {\n entries.push({\n kind: 'section',\n title: docs.section.title,\n markdown: docs.section.markdown,\n phase: 'runtime',\n });\n }\n if (docs.mermaid) {\n entries.push({\n kind: 'mermaid',\n code: docs.mermaid.code,\n title: docs.mermaid.title,\n phase: 'runtime',\n });\n }\n if (docs.screenshot) {\n entries.push({\n kind: 'screenshot',\n path: docs.screenshot.path,\n alt: docs.screenshot.alt,\n phase: 'runtime',\n });\n }\n if (docs.video) {\n entries.push({\n kind: 'video',\n path: docs.video.path,\n caption: docs.video.caption,\n poster: docs.video.poster,\n phase: 'runtime',\n });\n }\n if (docs.html) {\n entries.push(buildHtmlDocEntry(docs.html));\n }\n if (docs.custom) {\n entries.push({\n kind: 'custom',\n type: docs.custom.type,\n data: docs.custom.data,\n phase: 'runtime',\n });\n }\n\n return entries;\n}\n\n\n/**\n * Warn (non-fatal) when a state snapshot serializes past 100KB — the entry is\n * still recorded, but a projection is usually what the storyboard needs.\n */\nfunction warnIfStateLarge(label: string | undefined, value: unknown): void {\n try {\n const len = JSON.stringify(value)?.length ?? 0;\n if (len > 100_000) {\n console.warn(\n `[executable-stories] state \"${label ?? ''}\" is ${Math.round(len / 1024)}KB — consider capturing a projection`,\n );\n }\n } catch {\n // Non-serializable value: recorded as-is, size unknown.\n }\n}\n\nfunction attachDoc(entry: DocEntry, children?: DocEntry[]): DocEntry {\n const ctx = getContext();\n if (children && children.length > 0) {\n entry.children = children;\n const childSet = new Set<DocEntry>(children);\n const filterDocs = (docs: DocEntry[]) => docs.filter((d) => !childSet.has(d));\n // Remove children from ALL containers (story-level + every step)\n ctx.meta.docs = filterDocs(ctx.meta.docs ?? []);\n for (const step of ctx.meta.steps) {\n if (step.docs) step.docs = filterDocs(step.docs);\n }\n }\n if (ctx.currentStep) {\n ctx.currentStep.docs ??= [];\n ctx.currentStep.docs.push(entry);\n } else {\n ctx.meta.docs ??= [];\n ctx.meta.docs.push(entry);\n }\n return entry;\n}\n\n/**\n * Extract suite path from Cypress.currentTest.titlePath (describe blocks only).\n * titlePath is [describe1, describe2, ..., testTitle] — we want everything except the last.\n */\nfunction extractSuitePath(titlePath: string[]): string[] | undefined {\n if (titlePath.length <= 1) return undefined;\n const suitePath = titlePath.slice(0, -1);\n return suitePath.length > 0 ? suitePath : undefined;\n}\n\nfunction extractTraceIdFromSpans(\n spans: ReadonlyArray<Record<string, unknown>>,\n): string | undefined {\n for (const span of spans) {\n const direct = span.traceId;\n if (typeof direct === 'string' && direct.length > 0) return direct;\n\n const context = span.context;\n if (context && typeof context === 'object' && context !== null) {\n const nested = (context as { traceId?: unknown }).traceId;\n if (typeof nested === 'string' && nested.length > 0) return nested;\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Step markers\n// ============================================================================\n\nexport type StepMarker = {\n (text: string, docs?: StoryDocs): void;\n (text: string, children: DocEntry[]): void;\n <T>(text: string, body: () => T): T;\n skip: StepMarker;\n only: StepMarker;\n todo: StepMarker;\n fails: StepMarker;\n concurrent: StepMarker;\n};\n\nfunction createStepMarker(keyword: StepKeyword, mode?: StepMode): StepMarker {\n function stepMarker(text: string, docs?: StoryDocs): void;\n function stepMarker(text: string, children: DocEntry[]): void;\n function stepMarker<T>(text: string, body: () => T): T;\n function stepMarker<T>(text: string, docsOrBody?: StoryDocs | DocEntry[] | (() => T)): T | void {\n const ctx = getContext();\n const isCallback = typeof docsOrBody === 'function';\n const isChildrenArray = Array.isArray(docsOrBody);\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n let stepDocs: DocEntry[] = [];\n if (!isCallback && !isChildrenArray && docsOrBody) {\n stepDocs = convertStoryDocsToEntries(docsOrBody as StoryDocs);\n }\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: stepDocs,\n ...(mode ? { mode } : {}),\n ...(isCallback ? { wrapped: true } : {}),\n };\n\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n // Handle DocEntry[] children: attach as step docs and deduplicate from story-level\n if (isChildrenArray) {\n const children = docsOrBody as DocEntry[];\n if (children.length > 0) {\n const childSet = new Set<DocEntry>(children);\n // Deduplicate from story-level docs\n ctx.meta.docs = (ctx.meta.docs ?? []).filter((d) => !childSet.has(d));\n // Deduplicate from step docs of earlier steps\n for (const prevStep of ctx.meta.steps) {\n if (prevStep !== step && prevStep.docs) {\n prevStep.docs = prevStep.docs.filter((d) => !childSet.has(d));\n }\n }\n step.docs = [...(step.docs ?? []), ...children];\n }\n return;\n }\n\n if (!isCallback) return;\n\n const body = docsOrBody as () => T;\n const start = performance.now();\n\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => { step.durationMs = performance.now() - start; return val; },\n (err) => { step.durationMs = performance.now() - start; throw err; },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n }\n const marker = stepMarker as StepMarker;\n marker.skip = mode ? marker : createStepMarker(keyword, 'skip');\n marker.only = mode ? marker : createStepMarker(keyword, 'only');\n marker.todo = mode ? marker : createStepMarker(keyword, 'todo');\n marker.fails = mode ? marker : createStepMarker(keyword, 'fails');\n marker.concurrent = mode ? marker : createStepMarker(keyword, 'concurrent');\n return marker;\n}\n\n// ============================================================================\n// story.init() - Cypress-specific\n// ============================================================================\n\nfunction init(options?: StoryOptions, scenarioOverride?: string): void {\n const currentTest = Cypress.currentTest;\n const spec = Cypress.spec;\n if (!currentTest) {\n throw new Error(\"story.init() must be called inside an it() block so Cypress.currentTest is available.\");\n }\n\n const titlePath = currentTest.titlePath ?? [currentTest.title];\n const scenario = scenarioOverride ?? currentTest.title;\n const suitePath = extractSuitePath(titlePath);\n const specRelative = spec?.relative ?? \"unknown\";\n\n const meta: StoryMeta = {\n scenario,\n steps: [],\n suitePath,\n tags: options?.tags,\n tickets: normalizeTickets(options?.ticket),\n covers: options?.covers,\n meta: options?.meta,\n sourceOrder: sourceOrderCounter++,\n };\n\n activeContext = {\n meta,\n currentStep: null,\n stepCounter: 0,\n attachments: [],\n activeTimers: new Map(),\n timerCounter: 0,\n specRelative,\n titlePath,\n traceUrlTemplate: options?.traceUrlTemplate,\n traceDocAdded: false,\n };\n}\n\nfunction runScenario(mode: 'normal' | 'skip' | 'only', title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n const globalIt = (globalThis as { it?: ItLike }).it;\n if (!globalIt) {\n throw new Error('Global it() is not available. Use story.skip/story.only inside Cypress spec files.');\n }\n\n const runner =\n mode === 'skip'\n ? globalIt.skip\n : mode === 'only'\n ? globalIt.only\n : globalIt;\n\n if (!runner) {\n throw new Error(`Global it.${mode}() is not available in this environment.`);\n }\n\n return runner(title, () => {\n init(options);\n return body();\n });\n}\n\n/**\n * Get the current story meta and clear the active context.\n * Called by the support file after each test to send meta to Node via cy.task.\n * Returns null if story.init() was never called for this test.\n */\nexport function getAndClearMeta(): RecordMetaPayload | null {\n if (!activeContext) return null;\n const payload: RecordMetaPayload = {\n specRelative: activeContext.specRelative,\n titlePath: activeContext.titlePath,\n meta: activeContext.meta,\n attachments: activeContext.attachments.length > 0 ? activeContext.attachments : undefined,\n otelSpans: activeContext.otelSpans,\n };\n activeContext = null;\n return payload;\n}\n\n// ============================================================================\n// story.fn() and story.expect()\n// ============================================================================\n\n/**\n * Wrap a function as a step with timing and error capture.\n * Records the step with `wrapped: true` and `durationMs`.\n */\nfunction fn<T>(keyword: StepKeyword, text: string, body: () => T): T {\n const ctx = getContext();\n\n const resolvedKeyword: StepKeyword =\n (keyword === 'Given' || keyword === 'When' || keyword === 'Then') &&\n ctx.meta.steps.some((s) => s.keyword === keyword)\n ? 'And'\n : keyword;\n\n const step: StoryStep = {\n id: `step-${ctx.stepCounter++}`,\n keyword: resolvedKeyword,\n text,\n docs: [],\n wrapped: true,\n };\n ctx.meta.steps.push(step);\n ctx.currentStep = step;\n\n const start = performance.now();\n try {\n const result = body();\n if (result instanceof Promise) {\n return result.then(\n (val) => {\n step.durationMs = performance.now() - start;\n return val;\n },\n (err) => {\n step.durationMs = performance.now() - start;\n throw err;\n },\n ) as T;\n }\n step.durationMs = performance.now() - start;\n return result;\n } catch (err) {\n step.durationMs = performance.now() - start;\n throw err;\n }\n}\n\n/**\n * Wrap an assertion as a Then step with timing and error capture.\n * Shorthand for `story.fn('Then', text, body)`.\n */\nfunction storyExpect<T>(text: string, body: () => T): T {\n return fn('Then', text, body);\n}\n\n// ============================================================================\n// Export story object\n// ============================================================================\n\nexport const story = {\n init,\n skip(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('skip', title, body, options);\n },\n only(title: string, body: ScenarioBody, options?: StoryOptions): unknown {\n return runScenario('only', title, body, options);\n },\n\n // BDD step markers\n given: createStepMarker('Given'),\n when: createStepMarker('When'),\n then: createStepMarker('Then'),\n and: createStepMarker('And'),\n but: createStepMarker('But'),\n\n // AAA pattern aliases\n arrange: createStepMarker('Given'),\n act: createStepMarker('When'),\n assert: createStepMarker('Then'),\n\n // Additional aliases\n setup: createStepMarker('Given'),\n context: createStepMarker('Given'),\n execute: createStepMarker('When'),\n action: createStepMarker('When'),\n verify: createStepMarker('Then'),\n\n // Standalone doc methods\n note(text: string, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'note', text, phase: 'runtime' }, children);\n },\n\n tag(name: string | string[], children?: DocEntry[]): DocEntry {\n const names = Array.isArray(name) ? name : [name];\n return attachDoc({ kind: 'tag', names, phase: 'runtime' }, children);\n },\n\n kv(options: KvOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'kv', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n json(options: JsonOptions, children?: DocEntry[]): DocEntry {\n const content = JSON.stringify(options.value, null, 2);\n return attachDoc({ kind: 'code', label: options.label, content, lang: 'json', phase: 'runtime' }, children);\n },\n\n /**\n * Capture what the world looks like at this step: a JSON-serializable data\n * snapshot that becomes a storyboard frame. Consecutive states with the same\n * label are diffed downstream, so snapshot the same projection at each step.\n */\n state(options: StateOptions, children?: DocEntry[]): DocEntry {\n warnIfStateLarge(options.label, options.value);\n return attachDoc({ kind: 'state', label: options.label, value: options.value, phase: 'runtime' }, children);\n },\n\n code(options: CodeOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'code', label: options.label, content: options.content, lang: options.lang, phase: 'runtime' }, children);\n },\n\n table(options: TableOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'table', label: options.label, columns: options.columns, rows: options.rows, phase: 'runtime' }, children);\n },\n\n link(options: LinkOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'link', label: options.label, url: options.url, phase: 'runtime' }, children);\n },\n\n section(options: SectionOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'section', title: options.title, markdown: options.markdown, phase: 'runtime' }, children);\n },\n\n mermaid(options: MermaidOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'mermaid', code: options.code, title: options.title, phase: 'runtime' }, children);\n },\n\n screenshot(options: ScreenshotOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'screenshot', path: options.path, alt: options.alt, phase: 'runtime' }, children);\n },\n\n video(options: VideoOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'video', path: options.path, caption: options.caption, poster: options.poster, phase: 'runtime' }, children);\n },\n\n html(options: HtmlOptions, children?: DocEntry[]): DocEntry {\n return attachDoc(buildHtmlDocEntry(options), children);\n },\n\n custom(options: CustomOptions, children?: DocEntry[]): DocEntry {\n return attachDoc({ kind: 'custom', type: options.type, data: options.data, phase: 'runtime' }, children);\n },\n\n // Attachments\n attach(options: AttachmentOptions): void {\n const ctx = getContext();\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.attachments.push({\n ...options,\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n });\n },\n\n // OTel span attachment\n attachSpans(spans: ReadonlyArray<Record<string, unknown>>): void {\n const ctx = getContext();\n ctx.otelSpans = spans;\n\n if (ctx.traceDocAdded) return;\n const traceId = extractTraceIdFromSpans(spans);\n if (!traceId) return;\n\n ctx.meta.meta = {\n ...ctx.meta.meta,\n otel: { traceId },\n };\n ctx.meta.docs ??= [];\n ctx.meta.docs.push({ kind: 'kv', label: 'Trace ID', value: traceId, phase: 'runtime' });\n\n const template = ctx.traceUrlTemplate;\n if (template) {\n const url = template.replace('{traceId}', traceId);\n ctx.meta.docs.push({ kind: 'link', label: 'View Trace', url, phase: 'runtime' });\n }\n ctx.traceDocAdded = true;\n },\n\n // Step timing\n startTimer(): number {\n const ctx = getContext();\n const token = ctx.timerCounter++;\n const stepIndex = ctx.currentStep\n ? ctx.meta.steps.indexOf(ctx.currentStep)\n : undefined;\n ctx.activeTimers.set(token, {\n start: performance.now(),\n stepIndex: stepIndex !== undefined && stepIndex >= 0 ? stepIndex : undefined,\n stepId: ctx.currentStep?.id,\n consumed: false,\n });\n return token;\n },\n\n endTimer(token: number): void {\n const ctx = getContext();\n const entry = ctx.activeTimers.get(token);\n if (!entry || entry.consumed) return;\n\n entry.consumed = true;\n const durationMs = performance.now() - entry.start;\n\n let step: StoryStep | undefined;\n if (entry.stepId) {\n step = ctx.meta.steps.find((s) => s.id === entry.stepId);\n }\n if (!step && entry.stepIndex !== undefined) {\n step = ctx.meta.steps[entry.stepIndex];\n }\n\n if (step) {\n step.durationMs = durationMs;\n }\n },\n\n // Step wrappers\n fn,\n expect: storyExpect,\n};\n\nconst stepCallbacks = {\n given: story.given,\n when: story.when,\n then: story.then,\n and: story.and,\n but: story.but,\n arrange: story.arrange,\n act: story.act,\n assert: story.assert,\n setup: story.setup,\n context: story.context,\n execute: story.execute,\n action: story.action,\n verify: story.verify,\n};\n\nfunction docStory(title: string): void;\nfunction docStory(title: string, callback: (steps: typeof stepCallbacks) => void): void;\nfunction docStory(title: string, callback?: (steps: typeof stepCallbacks) => void): void {\n init(undefined, title);\n if (callback) callback(stepCallbacks);\n}\n\nexport const doc = {\n story: docStory,\n};\n\nexport type Story = typeof story;\n","/**\n * Cypress support file for executable-stories.\n * Register this in cypress/support/e2e.ts (or support file) so story meta\n * is sent to Node after each test for the reporter to consume.\n *\n * @example\n * In cypress/support/e2e.ts:\n * import 'executable-stories-cypress/support';\n */\n\nimport { getAndClearMeta } from \"./story-api\";\n\nconst TASK_NAME = \"executableStories:recordMeta\";\n\nafterEach(function () {\n const payload = getAndClearMeta();\n if (payload) {\n cy.task(TASK_NAME, payload);\n }\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "executable-stories-cypress",
3
- "version": "8.4.15",
3
+ "version": "8.5.2",
4
4
  "license": "Apache-2.0",
5
5
  "description": "BDD-style executable stories for Cypress with documentation generation",
6
6
  "type": "module",
@@ -38,7 +38,7 @@
38
38
  "cypress": ">=13.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "executable-stories-formatters": "1.6.0"
41
+ "executable-stories-formatters": "1.9.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "cypress": "^15.14.2",