@qualflare/cucumberjs 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/runtime/qualflare-api.ts","../src/shared/constants.ts","../src/shared/logger.ts"],"sourcesContent":["// Public entry point — safe to import from step-definition/support files.\nexport { qualflare } from './runtime/qualflare-api.js';\nexport type {\n ApiErrorResponse,\n ApiFieldError,\n Attachment,\n Case,\n CasePriority,\n CaseStatus,\n Collect,\n CollectResult,\n FrameworkCategory,\n Label,\n Link,\n LinkType,\n Metadata,\n NanosecondDuration,\n Parameter,\n Platform,\n Step,\n Suite,\n} from './shared/types.js';\n","import { world } from '@cucumber/cucumber';\n\nimport { RESERVED_MESSAGE_MEDIA_TYPE } from '../shared/constants.js';\nimport { logger } from '../shared/logger.js';\nimport type { CasePriority, LinkType } from '../shared/types.js';\nimport type { RuntimeMessage } from './message-types.js';\n\n/**\n * `@cucumber/cucumber` exports a `world` proxy (`AsyncLocalStorage`-backed,\n * added in cucumber-js 10.8.0 — this package's peer-dependency floor is\n * pinned exactly to that version because of this) that resolves to the\n * currently-executing scenario's World from anywhere — no `BeforeAll`\n * singleton registration needed. Calling it outside a step/hook body (e.g.\n * at module-load time, or from `BeforeAll`/`AfterAll`, which have no \"current\n * test case\") throws — caught here and logged once, mirroring\n * `@qualflare/cypress`'s \"warn, never throw, never abort the run\" philosophy\n * for a misplaced `qualflare.*()` call.\n */\nfunction send(message: RuntimeMessage): void {\n try {\n world.attach(JSON.stringify(message), RESERVED_MESSAGE_MEDIA_TYPE);\n } catch (err) {\n logger.warn(\n `qualflare.* was called outside a running scenario (e.g. from a Before/After hook, ` +\n `BeforeAll/AfterAll, or at module-load time) — this call had no effect. (${(err as Error).message})`,\n );\n }\n}\n\nfunction utf8ToBase64(text: string): string {\n return Buffer.from(text, 'utf8').toString('base64');\n}\n\nexport const qualflare = {\n label(name: string, value: string): void {\n send({ type: 'label', name, value });\n },\n\n link(url: string, opts?: { type?: LinkType; name?: string }): void {\n send({ type: 'link', url, linkType: opts?.type, name: opts?.name });\n },\n\n tag(...tags: string[]): void {\n send({ type: 'tag', tags });\n },\n\n description(text: string): void {\n send({ type: 'description', text });\n },\n\n priority(value: CasePriority): void {\n send({ type: 'priority', value });\n },\n\n /** Placed on the currently-open `step()`, if any; otherwise on the Case\n * itself (`Case.properties`). `masked` is a DISPLAY HINT ONLY — the\n * server does not redact the value; see `docs/METADATA-API.md`. */\n parameter(name: string, value?: string, opts?: { masked?: boolean }): void {\n send({ type: 'parameter', name, value, masked: opts?.masked });\n },\n\n attachment(name: string, content: string, opts?: { encoding?: 'utf8' | 'base64'; mimeType?: string }): void {\n const contentBase64 = opts?.encoding === 'base64' ? content : utf8ToBase64(content);\n send({ type: 'attachment', name, contentBase64, mimeType: opts?.mimeType });\n },\n\n attachmentFromFile(name: string, path: string, opts?: { mimeType?: string }): void {\n send({ type: 'attachment_from_file', name, path, mimeType: opts?.mimeType });\n },\n\n /** Wraps `fn` as a manually-declared step, nested under any currently-open\n * `qualflare.step()` call. Unlike `@qualflare/cypress` (whose step\n * definitions are Mocha test bodies executed synchronously ahead of\n * Cypress's own deferred command queue, requiring a `Chainable`-detection\n * trick to time the end of a step correctly), a cucumber-js step\n * definition is already a plain `async function` — so this is a\n * straightforward `try/finally`-wrapped call, with EXACT timing (real\n * `Date.now()` deltas around the awaited body), not an approximation. */\n async step<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n send({ type: 'step_start', name, timestamp: Date.now() });\n try {\n const result = await fn();\n send({ type: 'step_stop', status: 'passed', timestamp: Date.now() });\n return result;\n } catch (err) {\n send({ type: 'step_stop', status: 'failed', error: (err as Error).message, timestamp: Date.now() });\n throw err;\n }\n },\n};\n","/**\n * Shared constants used across the formatter and the author-facing runtime\n * API.\n */\n\n/** Reserved `World.attach()` media type used to smuggle structured\n * `qualflare.*()` calls (label/tag/step/etc.) from step-definition and hook\n * code back to the formatter process — the only data channel CucumberJS\n * gives user code back to a running formatter. The formatter's attachment\n * handler recognizes this exact media type and replays the message as a\n * model mutation instead of rendering it as a literal attachment. */\nexport const RESERVED_MESSAGE_MEDIA_TYPE = 'application/vnd.qualflare.message+json';\n\n/** Server-side caps this client should respect defensively (see\n * `api-service/internal/core/domain/launch/launch.go`). */\nexport const MAX_SUITES_PER_LAUNCH = 2000;\nexport const MAX_CASES_PER_SUITE = 5000;\nexport const MAX_STEPS_PER_CASE = 1000;\nexport const MAX_PARAMETERS_PER_STEP = 50;\nexport const MAX_ATTACHMENTS_PER_CASE = 50;\nexport const MAX_LABELS_PER_CASE = 100;\nexport const MAX_LINKS_PER_CASE = 20;\nexport const MAX_TAGS_PER_CASE = 64;\nexport const MAX_TAG_LENGTH = 255;\n\n/** Mirrors `launch.MaxAttachmentUploadFileSize` — the server's hard cap on a\n * single `POST /api/v1/attachments/upload-url` request (video). */\nexport const MAX_VIDEO_UPLOAD_BYTES = 50 * 1024 * 1024;\n\n/** Client-side SOFT cap on steps recorded per scenario attempt — well under\n * the server's 1000-per-case hard cap (`MAX_STEPS_PER_CASE`). Once hit,\n * further steps within that attempt are dropped (with a one-time warning),\n * not queued and truncated later. */\nexport const MAX_STEPS_PER_TEST_ATTEMPT = 300;\n","/**\n * A minimal logger writing to stderr. Deliberately avoids stdout, since\n * that's typically `cucumber-js`'s own test-output stream and shouldn't be\n * polluted with reporter diagnostics.\n */\n\nconst PREFIX = '[qualflare-cucumberjs]';\n\nexport const logger = {\n debug(...args: unknown[]): void {\n console.debug(PREFIX, ...args);\n },\n info(...args: unknown[]): void {\n console.log(PREFIX, ...args);\n },\n warn(...args: unknown[]): void {\n console.warn(PREFIX, ...args);\n },\n error(...args: unknown[]): void {\n console.error(PREFIX, ...args);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,sBAAsB;;;ACWf,IAAM,8BAA8B;AAgBpC,IAAM,yBAAyB,KAAK,OAAO;;;ACrBlD,IAAM,SAAS;AAER,IAAM,SAAS;AAAA,EACpB,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,IAAI,QAAQ,GAAG,IAAI;AAAA,EAC7B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,KAAK,QAAQ,GAAG,IAAI;AAAA,EAC9B;AAAA,EACA,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AACF;;;AFHA,SAAS,KAAK,SAA+B;AAC3C,MAAI;AACF,0BAAM,OAAO,KAAK,UAAU,OAAO,GAAG,2BAA2B;AAAA,EACnE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,kKAC8E,IAAc,OAAO;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAAsB;AAC1C,SAAO,OAAO,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ;AACpD;AAEO,IAAM,YAAY;AAAA,EACvB,MAAM,MAAc,OAAqB;AACvC,SAAK,EAAE,MAAM,SAAS,MAAM,MAAM,CAAC;AAAA,EACrC;AAAA,EAEA,KAAK,KAAa,MAAiD;AACjE,SAAK,EAAE,MAAM,QAAQ,KAAK,UAAU,MAAM,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,EACpE;AAAA,EAEA,OAAO,MAAsB;AAC3B,SAAK,EAAE,MAAM,OAAO,KAAK,CAAC;AAAA,EAC5B;AAAA,EAEA,YAAY,MAAoB;AAC9B,SAAK,EAAE,MAAM,eAAe,KAAK,CAAC;AAAA,EACpC;AAAA,EAEA,SAAS,OAA2B;AAClC,SAAK,EAAE,MAAM,YAAY,MAAM,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAc,OAAgB,MAAmC;AACzE,SAAK,EAAE,MAAM,aAAa,MAAM,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,EAC/D;AAAA,EAEA,WAAW,MAAc,SAAiB,MAAkE;AAC1G,UAAM,gBAAgB,MAAM,aAAa,WAAW,UAAU,aAAa,OAAO;AAClF,SAAK,EAAE,MAAM,cAAc,MAAM,eAAe,UAAU,MAAM,SAAS,CAAC;AAAA,EAC5E;AAAA,EAEA,mBAAmB,MAAc,MAAc,MAAoC;AACjF,SAAK,EAAE,MAAM,wBAAwB,MAAM,MAAM,UAAU,MAAM,SAAS,CAAC;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAQ,MAAc,IAAsC;AAChE,SAAK,EAAE,MAAM,cAAc,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AACxD,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,WAAW,KAAK,IAAI,EAAE,CAAC;AACnE,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,OAAQ,IAAc,SAAS,WAAW,KAAK,IAAI,EAAE,CAAC;AAClG,YAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/runtime/qualflare-api.ts","../src/shared/constants.ts","../src/shared/logger.ts"],"sourcesContent":["// Public entry point — safe to import from step-definition/support files.\nexport { qualflare } from './runtime/qualflare-api.js';\nexport type {\n ApiErrorResponse,\n ApiFieldError,\n Attachment,\n Case,\n CasePriority,\n CaseStatus,\n Collect,\n CollectResult,\n FrameworkCategory,\n Label,\n Link,\n LinkType,\n Metadata,\n NanosecondDuration,\n Parameter,\n Platform,\n Step,\n Suite,\n} from './shared/types.js';\n","import { world } from '@cucumber/cucumber';\n\nimport { RESERVED_MESSAGE_MEDIA_TYPE } from '../shared/constants.js';\nimport { logger } from '../shared/logger.js';\nimport type { CasePriority, LinkType } from '../shared/types.js';\nimport type { RuntimeMessage } from './message-types.js';\n\n/**\n * `@cucumber/cucumber` exports a `world` proxy (`AsyncLocalStorage`-backed,\n * added in cucumber-js 10.8.0 — this package's peer-dependency floor is\n * pinned exactly to that version because of this) that resolves to the\n * currently-executing scenario's World from anywhere — no `BeforeAll`\n * singleton registration needed. Calling it outside a step/hook body (e.g.\n * at module-load time, or from `BeforeAll`/`AfterAll`, which have no \"current\n * test case\") throws — caught here and logged once, mirroring\n * `@qualflare/cypress`'s \"warn, never throw, never abort the run\" philosophy\n * for a misplaced `qualflare.*()` call.\n */\nfunction send(message: RuntimeMessage): void {\n try {\n world.attach(JSON.stringify(message), RESERVED_MESSAGE_MEDIA_TYPE);\n } catch (err) {\n logger.warn(\n `qualflare.* was called outside a running scenario (e.g. from a Before/After hook, ` +\n `BeforeAll/AfterAll, or at module-load time) — this call had no effect. (${(err as Error).message})`,\n );\n }\n}\n\nfunction utf8ToBase64(text: string): string {\n return Buffer.from(text, 'utf8').toString('base64');\n}\n\nexport const qualflare = {\n label(name: string, value: string): void {\n send({ type: 'label', name, value });\n },\n\n link(url: string, opts?: { type?: LinkType; name?: string }): void {\n send({ type: 'link', url, linkType: opts?.type, name: opts?.name });\n },\n\n tag(...tags: string[]): void {\n send({ type: 'tag', tags });\n },\n\n description(text: string): void {\n send({ type: 'description', text });\n },\n\n priority(value: CasePriority): void {\n send({ type: 'priority', value });\n },\n\n /** Placed on the currently-open `step()`, if any; otherwise on the Case\n * itself (`Case.properties`). `masked` is a DISPLAY HINT ONLY — the\n * server does not redact the value; see `docs/METADATA-API.md`. */\n parameter(name: string, value?: string, opts?: { masked?: boolean }): void {\n send({ type: 'parameter', name, value, masked: opts?.masked });\n },\n\n attachment(name: string, content: string, opts?: { encoding?: 'utf8' | 'base64'; mimeType?: string }): void {\n const contentBase64 = opts?.encoding === 'base64' ? content : utf8ToBase64(content);\n send({ type: 'attachment', name, contentBase64, mimeType: opts?.mimeType });\n },\n\n attachmentFromFile(name: string, path: string, opts?: { mimeType?: string }): void {\n send({ type: 'attachment_from_file', name, path, mimeType: opts?.mimeType });\n },\n\n /** Wraps `fn` as a manually-declared step, nested under any currently-open\n * `qualflare.step()` call. Unlike `@qualflare/cypress` (whose step\n * definitions are Mocha test bodies executed synchronously ahead of\n * Cypress's own deferred command queue, requiring a `Chainable`-detection\n * trick to time the end of a step correctly), a cucumber-js step\n * definition is already a plain `async function` — so this is a\n * straightforward `try/finally`-wrapped call, with EXACT timing (real\n * `Date.now()` deltas around the awaited body), not an approximation. */\n async step<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n send({ type: 'step_start', name, timestamp: Date.now() });\n try {\n const result = await fn();\n send({ type: 'step_stop', status: 'passed', timestamp: Date.now() });\n return result;\n } catch (err) {\n send({ type: 'step_stop', status: 'failed', error: (err as Error).message, timestamp: Date.now() });\n throw err;\n }\n },\n};\n","/**\n * Shared constants used across the formatter and the author-facing runtime\n * API.\n */\n\n/** Reserved `World.attach()` media type used to smuggle structured\n * `qualflare.*()` calls (label/tag/step/etc.) from step-definition and hook\n * code back to the formatter process — the only data channel CucumberJS\n * gives user code back to a running formatter. The formatter's attachment\n * handler recognizes this exact media type and replays the message as a\n * model mutation instead of rendering it as a literal attachment. */\nexport const RESERVED_MESSAGE_MEDIA_TYPE = 'application/vnd.qualflare.message+json';\n\n/** Server-side caps this client should respect defensively (see\n * `api-service/internal/core/domain/launch/launch.go`). */\nexport const MAX_SUITES_PER_LAUNCH = 2000;\nexport const MAX_CASES_PER_SUITE = 5000;\nexport const MAX_STEPS_PER_CASE = 1000;\nexport const MAX_PARAMETERS_PER_STEP = 50;\nexport const MAX_ATTACHMENTS_PER_CASE = 50;\nexport const MAX_LABELS_PER_CASE = 100;\nexport const MAX_LINKS_PER_CASE = 20;\nexport const MAX_TAGS_PER_CASE = 64;\nexport const MAX_TAG_LENGTH = 255;\n\n/** Mirrors `launch.MaxCaseAttempts`. Beyond this the server keeps the first\n * 49 attempts plus the final one and drops the middle, so sending more is\n * wasted payload rather than an error. */\nexport const MAX_ATTEMPTS_PER_CASE = 50;\n\n/** Mirrors the server's per-attempt text bounds (`launch.MaxAttempt*Runes`).\n *\n * Clamped CLIENT-side, not left to the server, because attempts are the only\n * repeated-per-case payload with no size budget of its own. Measured: one\n * retried test with a deep stack and a chatty log serializes to ~630KB\n * unclamped — most of it text the server discards on write — against a 10MB\n * request body limit that, once exceeded, loses the ENTIRE launch. Sending\n * bytes the server will throw away is pure risk. */\nexport const MAX_ATTEMPT_MESSAGE_RUNES = 8192;\nexport const MAX_ATTEMPT_TRACE_RUNES = 32768;\nexport const MAX_ATTEMPT_SNIPPET_RUNES = 4096;\nexport const MAX_ATTEMPT_OUTPUT_RUNES = 16384;\nexport const MAX_ATTEMPT_OUTPUT_LINES = 200;\n\n/** Mirrors `launch.MaxAttachmentUploadFileSize` — the server's hard cap on a\n * single `POST /api/v1/attachments/upload-url` request (video). */\nexport const MAX_VIDEO_UPLOAD_BYTES = 50 * 1024 * 1024;\n\n/** Client-side SOFT cap on steps recorded per scenario attempt — well under\n * the server's 1000-per-case hard cap (`MAX_STEPS_PER_CASE`). Once hit,\n * further steps within that attempt are dropped (with a one-time warning),\n * not queued and truncated later. */\nexport const MAX_STEPS_PER_TEST_ATTEMPT = 300;\n","/**\n * A minimal logger writing to stderr. Deliberately avoids stdout, since\n * that's typically `cucumber-js`'s own test-output stream and shouldn't be\n * polluted with reporter diagnostics.\n */\n\nconst PREFIX = '[qualflare-cucumberjs]';\n\nexport const logger = {\n debug(...args: unknown[]): void {\n console.debug(PREFIX, ...args);\n },\n info(...args: unknown[]): void {\n console.log(PREFIX, ...args);\n },\n warn(...args: unknown[]): void {\n console.warn(PREFIX, ...args);\n },\n error(...args: unknown[]): void {\n console.error(PREFIX, ...args);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,sBAAsB;;;ACWf,IAAM,8BAA8B;AAmCpC,IAAM,yBAAyB,KAAK,OAAO;;;ACxClD,IAAM,SAAS;AAER,IAAM,SAAS;AAAA,EACpB,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,IAAI,QAAQ,GAAG,IAAI;AAAA,EAC7B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,KAAK,QAAQ,GAAG,IAAI;AAAA,EAC9B;AAAA,EACA,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AACF;;;AFHA,SAAS,KAAK,SAA+B;AAC3C,MAAI;AACF,0BAAM,OAAO,KAAK,UAAU,OAAO,GAAG,2BAA2B;AAAA,EACnE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,kKAC8E,IAAc,OAAO;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAAsB;AAC1C,SAAO,OAAO,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ;AACpD;AAEO,IAAM,YAAY;AAAA,EACvB,MAAM,MAAc,OAAqB;AACvC,SAAK,EAAE,MAAM,SAAS,MAAM,MAAM,CAAC;AAAA,EACrC;AAAA,EAEA,KAAK,KAAa,MAAiD;AACjE,SAAK,EAAE,MAAM,QAAQ,KAAK,UAAU,MAAM,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,EACpE;AAAA,EAEA,OAAO,MAAsB;AAC3B,SAAK,EAAE,MAAM,OAAO,KAAK,CAAC;AAAA,EAC5B;AAAA,EAEA,YAAY,MAAoB;AAC9B,SAAK,EAAE,MAAM,eAAe,KAAK,CAAC;AAAA,EACpC;AAAA,EAEA,SAAS,OAA2B;AAClC,SAAK,EAAE,MAAM,YAAY,MAAM,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAc,OAAgB,MAAmC;AACzE,SAAK,EAAE,MAAM,aAAa,MAAM,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,EAC/D;AAAA,EAEA,WAAW,MAAc,SAAiB,MAAkE;AAC1G,UAAM,gBAAgB,MAAM,aAAa,WAAW,UAAU,aAAa,OAAO;AAClF,SAAK,EAAE,MAAM,cAAc,MAAM,eAAe,UAAU,MAAM,SAAS,CAAC;AAAA,EAC5E;AAAA,EAEA,mBAAmB,MAAc,MAAc,MAAoC;AACjF,SAAK,EAAE,MAAM,wBAAwB,MAAM,MAAM,UAAU,MAAM,SAAS,CAAC;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAQ,MAAc,IAAsC;AAChE,SAAK,EAAE,MAAM,cAAc,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AACxD,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,WAAW,KAAK,IAAI,EAAE,CAAC;AACnE,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,OAAQ,IAAc,SAAS,WAAW,KAAK,IAAI,EAAE,CAAC;AAClG,YAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
package/dist/index.d.cts CHANGED
@@ -34,6 +34,14 @@ interface Metadata {
34
34
  version: string;
35
35
  timestamp: string;
36
36
  cliName: string;
37
+ /** Identifier every shard of ONE run shares. `qualflare-cli collect` groups
38
+ * the report files in a directory by this and refuses to upload when more
39
+ * than one distinct run is present, so a file left over from an earlier run
40
+ * cannot be merged silently into this launch.
41
+ *
42
+ * Optional because reports written by earlier releases have none; the CLI
43
+ * treats those as "unknown run" and never blocks on them. */
44
+ runId?: string;
37
45
  }
38
46
  interface Label {
39
47
  /** Required, max 128 chars. Allure-style arbitrary label name — epic/feature/story/owner/severity
@@ -103,6 +111,52 @@ interface Attachment {
103
111
  * Omit for a case-level (not step-level) attachment. */
104
112
  stepIndex?: number;
105
113
  }
114
+ /**
115
+ * One execution of a test, when the framework retried it.
116
+ *
117
+ * Sent as `Case.attempts`, persisted per-attempt server-side (see
118
+ * `case_run_attempts`). This is what lets a report answer "what failed on the
119
+ * first try?" rather than only "it was retried twice" — `retryCount`/`isFlaky`
120
+ * are aggregates and cannot.
121
+ *
122
+ * Three rules the server relies on:
123
+ *
124
+ * 1. **Send every attempt, including the final one**, numbered 1..N. The
125
+ * server treats the highest-numbered attempt as the final execution and
126
+ * overwrites its `status`/`duration` from the Case itself, so the two can
127
+ * never disagree — but it keeps this attempt's own `message`/`trace`, which
128
+ * is precisely why the final attempt must be sent rather than inferred.
129
+ * 2. **Fewer than two attempts persists nothing.** A test that ran once has no
130
+ * history worth storing, so omit `attempts` entirely rather than sending a
131
+ * single-element array; it is bytes against the 10MB body limit for a row
132
+ * the server will discard.
133
+ * 3. **`attempt` must be >= 1.** Zero-based numbering is silently dropped.
134
+ */
135
+ interface Attempt {
136
+ /** 1-based. Must be >= 1; the server drops anything lower. */
137
+ attempt: number;
138
+ status: CaseStatus;
139
+ /** NANOSECONDS — see `NanosecondDuration`. */
140
+ duration?: NanosecondDuration;
141
+ /** ISO-8601. When this attempt started. */
142
+ startedAt?: string;
143
+ /** The framework's own id for this attempt, passed through untouched.
144
+ * Max 255 chars server-side. */
145
+ attemptId?: string;
146
+ /** Truncated server-side at 8192 runes, never validation-rejected. */
147
+ message?: string;
148
+ /** Stack trace. Truncated server-side at 32768 runes. */
149
+ trace?: string;
150
+ /** Source snippet. Truncated server-side at 4096 runes. */
151
+ snippet?: string;
152
+ /** 1-based source line the failure points at. */
153
+ line?: number;
154
+ /** Captured stdout, one entry per line. Server keeps the first 200 lines,
155
+ * then truncates to 16384 runes. */
156
+ stdout?: string[];
157
+ /** Captured stderr, same bounds as `stdout`. */
158
+ stderr?: string[];
159
+ }
106
160
  interface Case {
107
161
  /** Required. A stable per-test identifier used for flaky-history matching
108
162
  * across separate runs — must stay the same for what a human would call
@@ -118,6 +172,10 @@ interface Case {
118
172
  /** NANOSECONDS — see `NanosecondDuration`. */
119
173
  duration: NanosecondDuration;
120
174
  retryCount?: number;
175
+ /** Per-attempt execution history, present only when the framework retried
176
+ * this test (>= 2 entries). Omitted otherwise — a single attempt persists
177
+ * nothing server-side. See `Attempt`. */
178
+ attempts?: Attempt[];
121
179
  isFlaky?: boolean;
122
180
  /** Truncated server-side at 65536 runes, never validation-rejected — send
123
181
  * the full error/stack text, don't pre-truncate. */
package/dist/index.d.ts CHANGED
@@ -34,6 +34,14 @@ interface Metadata {
34
34
  version: string;
35
35
  timestamp: string;
36
36
  cliName: string;
37
+ /** Identifier every shard of ONE run shares. `qualflare-cli collect` groups
38
+ * the report files in a directory by this and refuses to upload when more
39
+ * than one distinct run is present, so a file left over from an earlier run
40
+ * cannot be merged silently into this launch.
41
+ *
42
+ * Optional because reports written by earlier releases have none; the CLI
43
+ * treats those as "unknown run" and never blocks on them. */
44
+ runId?: string;
37
45
  }
38
46
  interface Label {
39
47
  /** Required, max 128 chars. Allure-style arbitrary label name — epic/feature/story/owner/severity
@@ -103,6 +111,52 @@ interface Attachment {
103
111
  * Omit for a case-level (not step-level) attachment. */
104
112
  stepIndex?: number;
105
113
  }
114
+ /**
115
+ * One execution of a test, when the framework retried it.
116
+ *
117
+ * Sent as `Case.attempts`, persisted per-attempt server-side (see
118
+ * `case_run_attempts`). This is what lets a report answer "what failed on the
119
+ * first try?" rather than only "it was retried twice" — `retryCount`/`isFlaky`
120
+ * are aggregates and cannot.
121
+ *
122
+ * Three rules the server relies on:
123
+ *
124
+ * 1. **Send every attempt, including the final one**, numbered 1..N. The
125
+ * server treats the highest-numbered attempt as the final execution and
126
+ * overwrites its `status`/`duration` from the Case itself, so the two can
127
+ * never disagree — but it keeps this attempt's own `message`/`trace`, which
128
+ * is precisely why the final attempt must be sent rather than inferred.
129
+ * 2. **Fewer than two attempts persists nothing.** A test that ran once has no
130
+ * history worth storing, so omit `attempts` entirely rather than sending a
131
+ * single-element array; it is bytes against the 10MB body limit for a row
132
+ * the server will discard.
133
+ * 3. **`attempt` must be >= 1.** Zero-based numbering is silently dropped.
134
+ */
135
+ interface Attempt {
136
+ /** 1-based. Must be >= 1; the server drops anything lower. */
137
+ attempt: number;
138
+ status: CaseStatus;
139
+ /** NANOSECONDS — see `NanosecondDuration`. */
140
+ duration?: NanosecondDuration;
141
+ /** ISO-8601. When this attempt started. */
142
+ startedAt?: string;
143
+ /** The framework's own id for this attempt, passed through untouched.
144
+ * Max 255 chars server-side. */
145
+ attemptId?: string;
146
+ /** Truncated server-side at 8192 runes, never validation-rejected. */
147
+ message?: string;
148
+ /** Stack trace. Truncated server-side at 32768 runes. */
149
+ trace?: string;
150
+ /** Source snippet. Truncated server-side at 4096 runes. */
151
+ snippet?: string;
152
+ /** 1-based source line the failure points at. */
153
+ line?: number;
154
+ /** Captured stdout, one entry per line. Server keeps the first 200 lines,
155
+ * then truncates to 16384 runes. */
156
+ stdout?: string[];
157
+ /** Captured stderr, same bounds as `stdout`. */
158
+ stderr?: string[];
159
+ }
106
160
  interface Case {
107
161
  /** Required. A stable per-test identifier used for flaky-history matching
108
162
  * across separate runs — must stay the same for what a human would call
@@ -118,6 +172,10 @@ interface Case {
118
172
  /** NANOSECONDS — see `NanosecondDuration`. */
119
173
  duration: NanosecondDuration;
120
174
  retryCount?: number;
175
+ /** Per-attempt execution history, present only when the framework retried
176
+ * this test (>= 2 entries). Omitted otherwise — a single attempt persists
177
+ * nothing server-side. See `Attempt`. */
178
+ attempts?: Attempt[];
121
179
  isFlaky?: boolean;
122
180
  /** Truncated server-side at 65536 runes, never validation-rejected — send
123
181
  * the full error/stack text, don't pre-truncate. */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runtime/qualflare-api.ts","../src/shared/constants.ts","../src/shared/logger.ts"],"sourcesContent":["import { world } from '@cucumber/cucumber';\n\nimport { RESERVED_MESSAGE_MEDIA_TYPE } from '../shared/constants.js';\nimport { logger } from '../shared/logger.js';\nimport type { CasePriority, LinkType } from '../shared/types.js';\nimport type { RuntimeMessage } from './message-types.js';\n\n/**\n * `@cucumber/cucumber` exports a `world` proxy (`AsyncLocalStorage`-backed,\n * added in cucumber-js 10.8.0 — this package's peer-dependency floor is\n * pinned exactly to that version because of this) that resolves to the\n * currently-executing scenario's World from anywhere — no `BeforeAll`\n * singleton registration needed. Calling it outside a step/hook body (e.g.\n * at module-load time, or from `BeforeAll`/`AfterAll`, which have no \"current\n * test case\") throws — caught here and logged once, mirroring\n * `@qualflare/cypress`'s \"warn, never throw, never abort the run\" philosophy\n * for a misplaced `qualflare.*()` call.\n */\nfunction send(message: RuntimeMessage): void {\n try {\n world.attach(JSON.stringify(message), RESERVED_MESSAGE_MEDIA_TYPE);\n } catch (err) {\n logger.warn(\n `qualflare.* was called outside a running scenario (e.g. from a Before/After hook, ` +\n `BeforeAll/AfterAll, or at module-load time) — this call had no effect. (${(err as Error).message})`,\n );\n }\n}\n\nfunction utf8ToBase64(text: string): string {\n return Buffer.from(text, 'utf8').toString('base64');\n}\n\nexport const qualflare = {\n label(name: string, value: string): void {\n send({ type: 'label', name, value });\n },\n\n link(url: string, opts?: { type?: LinkType; name?: string }): void {\n send({ type: 'link', url, linkType: opts?.type, name: opts?.name });\n },\n\n tag(...tags: string[]): void {\n send({ type: 'tag', tags });\n },\n\n description(text: string): void {\n send({ type: 'description', text });\n },\n\n priority(value: CasePriority): void {\n send({ type: 'priority', value });\n },\n\n /** Placed on the currently-open `step()`, if any; otherwise on the Case\n * itself (`Case.properties`). `masked` is a DISPLAY HINT ONLY — the\n * server does not redact the value; see `docs/METADATA-API.md`. */\n parameter(name: string, value?: string, opts?: { masked?: boolean }): void {\n send({ type: 'parameter', name, value, masked: opts?.masked });\n },\n\n attachment(name: string, content: string, opts?: { encoding?: 'utf8' | 'base64'; mimeType?: string }): void {\n const contentBase64 = opts?.encoding === 'base64' ? content : utf8ToBase64(content);\n send({ type: 'attachment', name, contentBase64, mimeType: opts?.mimeType });\n },\n\n attachmentFromFile(name: string, path: string, opts?: { mimeType?: string }): void {\n send({ type: 'attachment_from_file', name, path, mimeType: opts?.mimeType });\n },\n\n /** Wraps `fn` as a manually-declared step, nested under any currently-open\n * `qualflare.step()` call. Unlike `@qualflare/cypress` (whose step\n * definitions are Mocha test bodies executed synchronously ahead of\n * Cypress's own deferred command queue, requiring a `Chainable`-detection\n * trick to time the end of a step correctly), a cucumber-js step\n * definition is already a plain `async function` — so this is a\n * straightforward `try/finally`-wrapped call, with EXACT timing (real\n * `Date.now()` deltas around the awaited body), not an approximation. */\n async step<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n send({ type: 'step_start', name, timestamp: Date.now() });\n try {\n const result = await fn();\n send({ type: 'step_stop', status: 'passed', timestamp: Date.now() });\n return result;\n } catch (err) {\n send({ type: 'step_stop', status: 'failed', error: (err as Error).message, timestamp: Date.now() });\n throw err;\n }\n },\n};\n","/**\n * Shared constants used across the formatter and the author-facing runtime\n * API.\n */\n\n/** Reserved `World.attach()` media type used to smuggle structured\n * `qualflare.*()` calls (label/tag/step/etc.) from step-definition and hook\n * code back to the formatter process — the only data channel CucumberJS\n * gives user code back to a running formatter. The formatter's attachment\n * handler recognizes this exact media type and replays the message as a\n * model mutation instead of rendering it as a literal attachment. */\nexport const RESERVED_MESSAGE_MEDIA_TYPE = 'application/vnd.qualflare.message+json';\n\n/** Server-side caps this client should respect defensively (see\n * `api-service/internal/core/domain/launch/launch.go`). */\nexport const MAX_SUITES_PER_LAUNCH = 2000;\nexport const MAX_CASES_PER_SUITE = 5000;\nexport const MAX_STEPS_PER_CASE = 1000;\nexport const MAX_PARAMETERS_PER_STEP = 50;\nexport const MAX_ATTACHMENTS_PER_CASE = 50;\nexport const MAX_LABELS_PER_CASE = 100;\nexport const MAX_LINKS_PER_CASE = 20;\nexport const MAX_TAGS_PER_CASE = 64;\nexport const MAX_TAG_LENGTH = 255;\n\n/** Mirrors `launch.MaxAttachmentUploadFileSize` — the server's hard cap on a\n * single `POST /api/v1/attachments/upload-url` request (video). */\nexport const MAX_VIDEO_UPLOAD_BYTES = 50 * 1024 * 1024;\n\n/** Client-side SOFT cap on steps recorded per scenario attempt — well under\n * the server's 1000-per-case hard cap (`MAX_STEPS_PER_CASE`). Once hit,\n * further steps within that attempt are dropped (with a one-time warning),\n * not queued and truncated later. */\nexport const MAX_STEPS_PER_TEST_ATTEMPT = 300;\n","/**\n * A minimal logger writing to stderr. Deliberately avoids stdout, since\n * that's typically `cucumber-js`'s own test-output stream and shouldn't be\n * polluted with reporter diagnostics.\n */\n\nconst PREFIX = '[qualflare-cucumberjs]';\n\nexport const logger = {\n debug(...args: unknown[]): void {\n console.debug(PREFIX, ...args);\n },\n info(...args: unknown[]): void {\n console.log(PREFIX, ...args);\n },\n warn(...args: unknown[]): void {\n console.warn(PREFIX, ...args);\n },\n error(...args: unknown[]): void {\n console.error(PREFIX, ...args);\n },\n};\n"],"mappings":";AAAA,SAAS,aAAa;;;ACWf,IAAM,8BAA8B;AAgBpC,IAAM,yBAAyB,KAAK,OAAO;;;ACrBlD,IAAM,SAAS;AAER,IAAM,SAAS;AAAA,EACpB,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,IAAI,QAAQ,GAAG,IAAI;AAAA,EAC7B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,KAAK,QAAQ,GAAG,IAAI;AAAA,EAC9B;AAAA,EACA,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AACF;;;AFHA,SAAS,KAAK,SAA+B;AAC3C,MAAI;AACF,UAAM,OAAO,KAAK,UAAU,OAAO,GAAG,2BAA2B;AAAA,EACnE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,kKAC8E,IAAc,OAAO;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAAsB;AAC1C,SAAO,OAAO,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ;AACpD;AAEO,IAAM,YAAY;AAAA,EACvB,MAAM,MAAc,OAAqB;AACvC,SAAK,EAAE,MAAM,SAAS,MAAM,MAAM,CAAC;AAAA,EACrC;AAAA,EAEA,KAAK,KAAa,MAAiD;AACjE,SAAK,EAAE,MAAM,QAAQ,KAAK,UAAU,MAAM,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,EACpE;AAAA,EAEA,OAAO,MAAsB;AAC3B,SAAK,EAAE,MAAM,OAAO,KAAK,CAAC;AAAA,EAC5B;AAAA,EAEA,YAAY,MAAoB;AAC9B,SAAK,EAAE,MAAM,eAAe,KAAK,CAAC;AAAA,EACpC;AAAA,EAEA,SAAS,OAA2B;AAClC,SAAK,EAAE,MAAM,YAAY,MAAM,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAc,OAAgB,MAAmC;AACzE,SAAK,EAAE,MAAM,aAAa,MAAM,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,EAC/D;AAAA,EAEA,WAAW,MAAc,SAAiB,MAAkE;AAC1G,UAAM,gBAAgB,MAAM,aAAa,WAAW,UAAU,aAAa,OAAO;AAClF,SAAK,EAAE,MAAM,cAAc,MAAM,eAAe,UAAU,MAAM,SAAS,CAAC;AAAA,EAC5E;AAAA,EAEA,mBAAmB,MAAc,MAAc,MAAoC;AACjF,SAAK,EAAE,MAAM,wBAAwB,MAAM,MAAM,UAAU,MAAM,SAAS,CAAC;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAQ,MAAc,IAAsC;AAChE,SAAK,EAAE,MAAM,cAAc,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AACxD,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,WAAW,KAAK,IAAI,EAAE,CAAC;AACnE,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,OAAQ,IAAc,SAAS,WAAW,KAAK,IAAI,EAAE,CAAC;AAClG,YAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/runtime/qualflare-api.ts","../src/shared/constants.ts","../src/shared/logger.ts"],"sourcesContent":["import { world } from '@cucumber/cucumber';\n\nimport { RESERVED_MESSAGE_MEDIA_TYPE } from '../shared/constants.js';\nimport { logger } from '../shared/logger.js';\nimport type { CasePriority, LinkType } from '../shared/types.js';\nimport type { RuntimeMessage } from './message-types.js';\n\n/**\n * `@cucumber/cucumber` exports a `world` proxy (`AsyncLocalStorage`-backed,\n * added in cucumber-js 10.8.0 — this package's peer-dependency floor is\n * pinned exactly to that version because of this) that resolves to the\n * currently-executing scenario's World from anywhere — no `BeforeAll`\n * singleton registration needed. Calling it outside a step/hook body (e.g.\n * at module-load time, or from `BeforeAll`/`AfterAll`, which have no \"current\n * test case\") throws — caught here and logged once, mirroring\n * `@qualflare/cypress`'s \"warn, never throw, never abort the run\" philosophy\n * for a misplaced `qualflare.*()` call.\n */\nfunction send(message: RuntimeMessage): void {\n try {\n world.attach(JSON.stringify(message), RESERVED_MESSAGE_MEDIA_TYPE);\n } catch (err) {\n logger.warn(\n `qualflare.* was called outside a running scenario (e.g. from a Before/After hook, ` +\n `BeforeAll/AfterAll, or at module-load time) — this call had no effect. (${(err as Error).message})`,\n );\n }\n}\n\nfunction utf8ToBase64(text: string): string {\n return Buffer.from(text, 'utf8').toString('base64');\n}\n\nexport const qualflare = {\n label(name: string, value: string): void {\n send({ type: 'label', name, value });\n },\n\n link(url: string, opts?: { type?: LinkType; name?: string }): void {\n send({ type: 'link', url, linkType: opts?.type, name: opts?.name });\n },\n\n tag(...tags: string[]): void {\n send({ type: 'tag', tags });\n },\n\n description(text: string): void {\n send({ type: 'description', text });\n },\n\n priority(value: CasePriority): void {\n send({ type: 'priority', value });\n },\n\n /** Placed on the currently-open `step()`, if any; otherwise on the Case\n * itself (`Case.properties`). `masked` is a DISPLAY HINT ONLY — the\n * server does not redact the value; see `docs/METADATA-API.md`. */\n parameter(name: string, value?: string, opts?: { masked?: boolean }): void {\n send({ type: 'parameter', name, value, masked: opts?.masked });\n },\n\n attachment(name: string, content: string, opts?: { encoding?: 'utf8' | 'base64'; mimeType?: string }): void {\n const contentBase64 = opts?.encoding === 'base64' ? content : utf8ToBase64(content);\n send({ type: 'attachment', name, contentBase64, mimeType: opts?.mimeType });\n },\n\n attachmentFromFile(name: string, path: string, opts?: { mimeType?: string }): void {\n send({ type: 'attachment_from_file', name, path, mimeType: opts?.mimeType });\n },\n\n /** Wraps `fn` as a manually-declared step, nested under any currently-open\n * `qualflare.step()` call. Unlike `@qualflare/cypress` (whose step\n * definitions are Mocha test bodies executed synchronously ahead of\n * Cypress's own deferred command queue, requiring a `Chainable`-detection\n * trick to time the end of a step correctly), a cucumber-js step\n * definition is already a plain `async function` — so this is a\n * straightforward `try/finally`-wrapped call, with EXACT timing (real\n * `Date.now()` deltas around the awaited body), not an approximation. */\n async step<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n send({ type: 'step_start', name, timestamp: Date.now() });\n try {\n const result = await fn();\n send({ type: 'step_stop', status: 'passed', timestamp: Date.now() });\n return result;\n } catch (err) {\n send({ type: 'step_stop', status: 'failed', error: (err as Error).message, timestamp: Date.now() });\n throw err;\n }\n },\n};\n","/**\n * Shared constants used across the formatter and the author-facing runtime\n * API.\n */\n\n/** Reserved `World.attach()` media type used to smuggle structured\n * `qualflare.*()` calls (label/tag/step/etc.) from step-definition and hook\n * code back to the formatter process — the only data channel CucumberJS\n * gives user code back to a running formatter. The formatter's attachment\n * handler recognizes this exact media type and replays the message as a\n * model mutation instead of rendering it as a literal attachment. */\nexport const RESERVED_MESSAGE_MEDIA_TYPE = 'application/vnd.qualflare.message+json';\n\n/** Server-side caps this client should respect defensively (see\n * `api-service/internal/core/domain/launch/launch.go`). */\nexport const MAX_SUITES_PER_LAUNCH = 2000;\nexport const MAX_CASES_PER_SUITE = 5000;\nexport const MAX_STEPS_PER_CASE = 1000;\nexport const MAX_PARAMETERS_PER_STEP = 50;\nexport const MAX_ATTACHMENTS_PER_CASE = 50;\nexport const MAX_LABELS_PER_CASE = 100;\nexport const MAX_LINKS_PER_CASE = 20;\nexport const MAX_TAGS_PER_CASE = 64;\nexport const MAX_TAG_LENGTH = 255;\n\n/** Mirrors `launch.MaxCaseAttempts`. Beyond this the server keeps the first\n * 49 attempts plus the final one and drops the middle, so sending more is\n * wasted payload rather than an error. */\nexport const MAX_ATTEMPTS_PER_CASE = 50;\n\n/** Mirrors the server's per-attempt text bounds (`launch.MaxAttempt*Runes`).\n *\n * Clamped CLIENT-side, not left to the server, because attempts are the only\n * repeated-per-case payload with no size budget of its own. Measured: one\n * retried test with a deep stack and a chatty log serializes to ~630KB\n * unclamped — most of it text the server discards on write — against a 10MB\n * request body limit that, once exceeded, loses the ENTIRE launch. Sending\n * bytes the server will throw away is pure risk. */\nexport const MAX_ATTEMPT_MESSAGE_RUNES = 8192;\nexport const MAX_ATTEMPT_TRACE_RUNES = 32768;\nexport const MAX_ATTEMPT_SNIPPET_RUNES = 4096;\nexport const MAX_ATTEMPT_OUTPUT_RUNES = 16384;\nexport const MAX_ATTEMPT_OUTPUT_LINES = 200;\n\n/** Mirrors `launch.MaxAttachmentUploadFileSize` — the server's hard cap on a\n * single `POST /api/v1/attachments/upload-url` request (video). */\nexport const MAX_VIDEO_UPLOAD_BYTES = 50 * 1024 * 1024;\n\n/** Client-side SOFT cap on steps recorded per scenario attempt — well under\n * the server's 1000-per-case hard cap (`MAX_STEPS_PER_CASE`). Once hit,\n * further steps within that attempt are dropped (with a one-time warning),\n * not queued and truncated later. */\nexport const MAX_STEPS_PER_TEST_ATTEMPT = 300;\n","/**\n * A minimal logger writing to stderr. Deliberately avoids stdout, since\n * that's typically `cucumber-js`'s own test-output stream and shouldn't be\n * polluted with reporter diagnostics.\n */\n\nconst PREFIX = '[qualflare-cucumberjs]';\n\nexport const logger = {\n debug(...args: unknown[]): void {\n console.debug(PREFIX, ...args);\n },\n info(...args: unknown[]): void {\n console.log(PREFIX, ...args);\n },\n warn(...args: unknown[]): void {\n console.warn(PREFIX, ...args);\n },\n error(...args: unknown[]): void {\n console.error(PREFIX, ...args);\n },\n};\n"],"mappings":";AAAA,SAAS,aAAa;;;ACWf,IAAM,8BAA8B;AAmCpC,IAAM,yBAAyB,KAAK,OAAO;;;ACxClD,IAAM,SAAS;AAER,IAAM,SAAS;AAAA,EACpB,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,IAAI,QAAQ,GAAG,IAAI;AAAA,EAC7B;AAAA,EACA,QAAQ,MAAuB;AAC7B,YAAQ,KAAK,QAAQ,GAAG,IAAI;AAAA,EAC9B;AAAA,EACA,SAAS,MAAuB;AAC9B,YAAQ,MAAM,QAAQ,GAAG,IAAI;AAAA,EAC/B;AACF;;;AFHA,SAAS,KAAK,SAA+B;AAC3C,MAAI;AACF,UAAM,OAAO,KAAK,UAAU,OAAO,GAAG,2BAA2B;AAAA,EACnE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,kKAC8E,IAAc,OAAO;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAAsB;AAC1C,SAAO,OAAO,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ;AACpD;AAEO,IAAM,YAAY;AAAA,EACvB,MAAM,MAAc,OAAqB;AACvC,SAAK,EAAE,MAAM,SAAS,MAAM,MAAM,CAAC;AAAA,EACrC;AAAA,EAEA,KAAK,KAAa,MAAiD;AACjE,SAAK,EAAE,MAAM,QAAQ,KAAK,UAAU,MAAM,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,EACpE;AAAA,EAEA,OAAO,MAAsB;AAC3B,SAAK,EAAE,MAAM,OAAO,KAAK,CAAC;AAAA,EAC5B;AAAA,EAEA,YAAY,MAAoB;AAC9B,SAAK,EAAE,MAAM,eAAe,KAAK,CAAC;AAAA,EACpC;AAAA,EAEA,SAAS,OAA2B;AAClC,SAAK,EAAE,MAAM,YAAY,MAAM,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAc,OAAgB,MAAmC;AACzE,SAAK,EAAE,MAAM,aAAa,MAAM,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,EAC/D;AAAA,EAEA,WAAW,MAAc,SAAiB,MAAkE;AAC1G,UAAM,gBAAgB,MAAM,aAAa,WAAW,UAAU,aAAa,OAAO;AAClF,SAAK,EAAE,MAAM,cAAc,MAAM,eAAe,UAAU,MAAM,SAAS,CAAC;AAAA,EAC5E;AAAA,EAEA,mBAAmB,MAAc,MAAc,MAAoC;AACjF,SAAK,EAAE,MAAM,wBAAwB,MAAM,MAAM,UAAU,MAAM,SAAS,CAAC;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAQ,MAAc,IAAsC;AAChE,SAAK,EAAE,MAAM,cAAc,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AACxD,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,WAAW,KAAK,IAAI,EAAE,CAAC;AACnE,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,EAAE,MAAM,aAAa,QAAQ,UAAU,OAAQ,IAAc,SAAS,WAAW,KAAK,IAAI,EAAE,CAAC;AAClG,YAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qualflare/cucumberjs",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Native CucumberJS reporter for the Qualflare test-management platform.",
5
5
  "keywords": [
6
6
  "qualflare",