executable-stories-formatters 1.9.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters.d.cts +183 -1
- package/dist/adapters.d.ts +183 -1
- package/dist/cli.js +2200 -1857
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1679 -1724
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +588 -849
- package/dist/index.d.ts +588 -849
- package/dist/index.js +1624 -1678
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/index-CmEmALo3.d.cts +0 -634
- package/dist/index-CmEmALo3.d.ts +0 -634
package/dist/index.d.cts
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
startedAtMs?: number;
|
|
27
|
-
/** Default finish time (epoch ms). Default: Date.now() */
|
|
28
|
-
finishedAtMs?: number;
|
|
29
|
-
};
|
|
30
|
-
}
|
|
1
|
+
import { TestRunResult, TestCaseResult, TestStatus, Attachment } from 'executable-stories-core/types/test-result';
|
|
2
|
+
export { Attachment, CIInfo, CoverageSummary, StepResult, TestCaseAttempt, TestCaseEvidence, TestCaseResult, TestRunResult, TestStatus } from 'executable-stories-core/types/test-result';
|
|
3
|
+
import { StoryStep, DocEntry, NormalizedTicket, StepKeyword } from 'executable-stories-core/types/story';
|
|
4
|
+
export { DocEntry, DocPhase, NormalizedTicket, STORY_META_KEY, StepKeyword, StepMode, StoryMeta, StoryStep } from 'executable-stories-core/types/story';
|
|
5
|
+
import { CIInfo, CIProvider } from 'executable-stories-core/types/ci';
|
|
6
|
+
export { CIProvider, CIInfo as TypedCIInfo, toCIInfo, toRawCIInfo } from 'executable-stories-core/types/ci';
|
|
7
|
+
import { adaptJestRun, adaptPlaywrightRun, adaptVitestRun } from './adapters.cjs';
|
|
8
|
+
export { JestAdapterOptions, JestAggregatedResult, JestFileResult, JestTestResult, PlaywrightAdapterOptions, PlaywrightAnnotation, PlaywrightAttachment, PlaywrightError, PlaywrightLocation, PlaywrightStatus, PlaywrightTestCase, PlaywrightTestResult, StoryFileReport, VitestAdapterOptions, VitestSerializedError, VitestState, VitestTestCase, VitestTestModule, VitestTestResult } from './adapters.cjs';
|
|
9
|
+
export { OtelAttributeValue, OtelSpan } from 'executable-stories-core/types/otel';
|
|
10
|
+
import { RawCIInfo } from 'executable-stories-core/types/raw';
|
|
11
|
+
export { RawAttachment, RawCIInfo, RawRun, RawStatus, RawStepEvent, RawTestCase } from 'executable-stories-core/types/raw';
|
|
12
|
+
import { StoryReport, TestStatus as TestStatus$1, ReportStep } from 'executable-stories-core/types/story-report';
|
|
13
|
+
export { ReportAttachment, ReportCIInfo, ReportCoverageSummary, ReportDocCode, ReportDocCustom, ReportDocEntry, ReportDocKv, ReportDocLink, ReportDocMermaid, ReportDocNote, ReportDocScreenshot, ReportDocSection, ReportDocTable, ReportDocTag, ReportFeature, ReportScenario, ReportStep, ReportSummary, ReportTicket, STORY_REPORT_SCHEMA_MAJOR, STORY_REPORT_SCHEMA_VERSION, StoryReport, StoryReportSchemaVersion } from 'executable-stories-core/types/story-report';
|
|
14
|
+
export { ES_THEME_TOKENS_CSS, ES_THEME_TOKEN_VALUES } from 'executable-stories-core/theme/tokens';
|
|
15
|
+
export { canonicalizeRun, deriveStepResults, generateRunId, generateTestCaseId, mergeStepResults, normalizeStatus, resolveAttachment, resolveAttachments, slugify } from 'executable-stories-core/converters/acl/index';
|
|
16
|
+
export { ValidationResult, assertValidRun, validateCanonicalRun } from 'executable-stories-core/converters/acl/validate';
|
|
17
|
+
export { RunState, advanceState, initialRunState } from 'executable-stories-core';
|
|
18
|
+
export { toStoryReport } from 'executable-stories-core/converters/story-report';
|
|
19
|
+
import { Envelope } from 'executable-stories-core/types/cucumber-messages';
|
|
20
|
+
export { parseEnvelopes, parseNdjson } from 'executable-stories-core/converters/ndjson-parser';
|
|
21
|
+
export { formatDuration, msToNanoseconds, nanosecondsToMs } from 'executable-stories-core/utils/duration';
|
|
22
|
+
export { OtelTraceContext, resolveTraceUrl, tryGetActiveOtelContext } from 'executable-stories-core/utils/otel-detect';
|
|
23
|
+
export { HtmlDocOptions, buildHtmlDocEntry } from 'executable-stories-core/utils/doc-builders';
|
|
24
|
+
import { CanonicalizeOptions } from 'executable-stories-core/types/canonicalize';
|
|
25
|
+
export { CanonicalizeOptions } from 'executable-stories-core/types/canonicalize';
|
|
31
26
|
|
|
32
27
|
/**
|
|
33
28
|
* Notification types for webhook integrations (Slack, Teams).
|
|
@@ -45,7 +40,7 @@ interface NotificationSummary {
|
|
|
45
40
|
name: string;
|
|
46
41
|
error?: string;
|
|
47
42
|
}>;
|
|
48
|
-
ci?: CIInfo
|
|
43
|
+
ci?: CIInfo;
|
|
49
44
|
reportUrl?: string;
|
|
50
45
|
}
|
|
51
46
|
/** When to send notifications. */
|
|
@@ -560,7 +555,7 @@ interface ScenarioSnapshot {
|
|
|
560
555
|
scenario: string;
|
|
561
556
|
sourceFile: string;
|
|
562
557
|
sourceLine: number;
|
|
563
|
-
status: TestStatus
|
|
558
|
+
status: TestStatus;
|
|
564
559
|
durationMs: number;
|
|
565
560
|
tags: string[];
|
|
566
561
|
titlePath: string[];
|
|
@@ -723,224 +718,576 @@ interface IJsonFeature {
|
|
|
723
718
|
uri: string;
|
|
724
719
|
}
|
|
725
720
|
|
|
726
|
-
|
|
721
|
+
/**
|
|
722
|
+
* The test-management port.
|
|
723
|
+
*
|
|
724
|
+
* One interface, one engine, adapters per provider. Everything the engine does
|
|
725
|
+
* — matching, planning, drift detection, lockfile bookkeeping, reporting — is
|
|
726
|
+
* written once against these types. An adapter's only job is to translate
|
|
727
|
+
* between them and a vendor API.
|
|
728
|
+
*
|
|
729
|
+
* Adding a provider is one file in `adapters/` plus one line in
|
|
730
|
+
* `adapters/index.ts`, with no edits to `engine.ts`. If a new adapter forces an
|
|
731
|
+
* engine change, this port is wrong and gets fixed then, on evidence.
|
|
732
|
+
*
|
|
733
|
+
* Every method except `listCases` is optional. A read-only provider implements
|
|
734
|
+
* `listCases` alone and still produces a full coverage report; the engine
|
|
735
|
+
* reports the missing capabilities in the plan instead of failing.
|
|
736
|
+
*/
|
|
737
|
+
/** A test case as it exists in the provider, normalized. */
|
|
738
|
+
interface RemoteCase {
|
|
739
|
+
/** Provider-native id, e.g. TestRail "1234" or Xray "PROJ-42". */
|
|
740
|
+
id: string;
|
|
741
|
+
/** Canonical URL a human can open. */
|
|
742
|
+
url: string;
|
|
743
|
+
title: string;
|
|
744
|
+
/** Suite, folder, or component — whatever the provider groups by. */
|
|
745
|
+
section?: string;
|
|
746
|
+
/**
|
|
747
|
+
* The content the provider currently holds, when it can supply it.
|
|
748
|
+
*
|
|
749
|
+
* Drift detection hashes this, not what we sent: providers normalize markup
|
|
750
|
+
* on write, so hashing the request would flag every case as human-edited on
|
|
751
|
+
* the very next run.
|
|
752
|
+
*/
|
|
753
|
+
body?: CaseBody;
|
|
754
|
+
}
|
|
755
|
+
/** A story projected into provider-neutral case content. */
|
|
756
|
+
interface CaseBody {
|
|
757
|
+
title: string;
|
|
758
|
+
steps: ReadonlyArray<{
|
|
759
|
+
keyword: string;
|
|
760
|
+
text: string;
|
|
761
|
+
}>;
|
|
762
|
+
/** Story docs rendered to plain text/markdown; adapters convert as needed. */
|
|
763
|
+
description: string;
|
|
764
|
+
links: ReadonlyArray<{
|
|
765
|
+
label: string;
|
|
766
|
+
url: string;
|
|
767
|
+
}>;
|
|
768
|
+
}
|
|
769
|
+
/** Evidence uploaded alongside a result. */
|
|
770
|
+
interface ResultAttachment {
|
|
771
|
+
filename: string;
|
|
772
|
+
mediaType: string;
|
|
773
|
+
body: Uint8Array;
|
|
774
|
+
role?: "screenshot" | "video" | "trace" | "log";
|
|
775
|
+
}
|
|
776
|
+
/** One execution record to push. */
|
|
777
|
+
interface CaseResult {
|
|
778
|
+
caseId: string;
|
|
779
|
+
status: "passed" | "failed" | "skipped";
|
|
780
|
+
durationMs: number;
|
|
781
|
+
message?: string;
|
|
782
|
+
/** Deep link into the generated HTML report for this scenario. */
|
|
783
|
+
url?: string;
|
|
784
|
+
attachments?: ResultAttachment[];
|
|
785
|
+
}
|
|
786
|
+
/** What a provider did with a batch of results. */
|
|
787
|
+
interface RecordResultsSummary {
|
|
788
|
+
/** Provider-native run/execution id, when one was created. */
|
|
789
|
+
runId?: string;
|
|
790
|
+
/** URL of the created run/execution, when the provider exposes one. */
|
|
791
|
+
runUrl?: string;
|
|
792
|
+
recorded: number;
|
|
793
|
+
/** Results the provider declined (e.g. no status mapping configured). */
|
|
794
|
+
skipped: Array<{
|
|
795
|
+
caseId: string;
|
|
796
|
+
reason: string;
|
|
797
|
+
}>;
|
|
798
|
+
attachmentsUploaded: number;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* A test-management system, reduced to what the engine needs.
|
|
802
|
+
*
|
|
803
|
+
* `createCase`/`updateCase` return the resulting {@link RemoteCase} rather than
|
|
804
|
+
* just an id so the engine can hash the provider's own normalized copy.
|
|
805
|
+
*/
|
|
806
|
+
interface SyncProvider {
|
|
807
|
+
/** Stable key used in config, CLI args, and the lockfile. */
|
|
727
808
|
name: string;
|
|
728
|
-
|
|
729
|
-
|
|
809
|
+
listCases(): Promise<RemoteCase[]>;
|
|
810
|
+
createCase?(body: CaseBody): Promise<RemoteCase>;
|
|
811
|
+
updateCase?(id: string, body: CaseBody): Promise<RemoteCase>;
|
|
812
|
+
recordResults?(results: CaseResult[]): Promise<RecordResultsSummary>;
|
|
813
|
+
/**
|
|
814
|
+
* Per-file limit. The engine skips oversized attachments and reports them in
|
|
815
|
+
* the plan, rather than letting an adapter die mid-upload with half a run
|
|
816
|
+
* already pushed.
|
|
817
|
+
*/
|
|
818
|
+
maxAttachmentBytes?: number;
|
|
819
|
+
/** Human-readable target, shown in the plan header (e.g. "ACME / Regression"). */
|
|
820
|
+
describeTarget?(): string;
|
|
730
821
|
}
|
|
731
|
-
|
|
732
|
-
|
|
822
|
+
/** Injectable dependencies shared by every adapter. */
|
|
823
|
+
interface AdapterDeps {
|
|
824
|
+
fetch: typeof globalThis.fetch;
|
|
825
|
+
logger: {
|
|
826
|
+
warn(msg: string): void;
|
|
827
|
+
};
|
|
733
828
|
}
|
|
734
829
|
|
|
735
830
|
/**
|
|
736
|
-
*
|
|
831
|
+
* The sync lockfile: the binding between a behaviour in the codebase and a case
|
|
832
|
+
* in someone else's system.
|
|
737
833
|
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
834
|
+
* Committed to the repo on purpose. When CI creates a case, the lockfile diff
|
|
835
|
+
* shows up in the pull request that caused it, so a reviewer sees the new case
|
|
836
|
+
* and its link before it lands anywhere else.
|
|
741
837
|
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
838
|
+
* Keyed on `behaviourFingerprint` (content-derived) rather than the canonical
|
|
839
|
+
* test-case id (`sha1(sourceFile::scenario)`), which changes the moment someone
|
|
840
|
+
* renames a test or moves a file. Keying on the volatile id would orphan every
|
|
841
|
+
* case on the first rename, which is exactly how these integrations lose trust.
|
|
744
842
|
*/
|
|
745
843
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
844
|
+
declare const DEFAULT_LOCKFILE_PATH = ".executable-stories/sync.lock.json";
|
|
845
|
+
/** One behaviour-to-case binding. */
|
|
846
|
+
interface LockEntry {
|
|
847
|
+
/** Provider-native case id. */
|
|
848
|
+
caseId: string;
|
|
849
|
+
url: string;
|
|
850
|
+
/**
|
|
851
|
+
* Hash of the provider's normalized copy as of our last write. A mismatch on
|
|
852
|
+
* the next run means a human edited the case in the provider's UI.
|
|
853
|
+
*/
|
|
854
|
+
hash: string;
|
|
855
|
+
/** Last known title, so orphan reports are readable without a remote lookup. */
|
|
856
|
+
title: string;
|
|
857
|
+
/**
|
|
858
|
+
* True only for cases this tool created.
|
|
859
|
+
*
|
|
860
|
+
* A case reached through a `story.tickets` id was authored by a human, so we
|
|
861
|
+
* push executions against it and never touch its body. Without this flag the
|
|
862
|
+
* first sync would silently overwrite hand-written cases, which is the single
|
|
863
|
+
* fastest way to lose a QA team.
|
|
864
|
+
*/
|
|
865
|
+
owned: boolean;
|
|
757
866
|
}
|
|
758
|
-
interface
|
|
759
|
-
|
|
760
|
-
|
|
867
|
+
interface Lockfile {
|
|
868
|
+
version: number;
|
|
869
|
+
/** provider name -> behaviour fingerprint -> entry */
|
|
870
|
+
providers: Record<string, Record<string, LockEntry>>;
|
|
761
871
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
872
|
+
declare function emptyLockfile(): Lockfile;
|
|
873
|
+
/**
|
|
874
|
+
* Hash provider-normalized case content.
|
|
875
|
+
*
|
|
876
|
+
* Deliberately excludes `links`: those embed report URLs that change with every
|
|
877
|
+
* CI run (build number, artifact host), and treating that churn as a human edit
|
|
878
|
+
* would make the drift guard fire constantly and get switched off.
|
|
879
|
+
*/
|
|
880
|
+
declare function hashCaseBody(body: CaseBody): string;
|
|
881
|
+
/**
|
|
882
|
+
* Parse lockfile text. `label` names the source in errors, so the caller decides
|
|
883
|
+
* whether that is a path, a URL, or something else entirely.
|
|
884
|
+
*
|
|
885
|
+
* Split from {@link readLockfile} so the CLI can route every read and write
|
|
886
|
+
* through its injected file dependencies and still share these error messages.
|
|
887
|
+
*/
|
|
888
|
+
declare function parseLockfile(contents: string, label: string): Lockfile;
|
|
889
|
+
/** Serialize with sorted keys so the diff a reviewer sees is minimal and stable. */
|
|
890
|
+
declare function serializeLockfile(lock: Lockfile): string;
|
|
891
|
+
declare function readLockfile(file: string): Lockfile;
|
|
892
|
+
declare function writeLockfile(file: string, lock: Lockfile): void;
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Provider-agnostic sync engine.
|
|
896
|
+
*
|
|
897
|
+
* Everything that is not a vendor API call lives here: projecting stories into
|
|
898
|
+
* case bodies, binding them to remote cases, classifying what the provider
|
|
899
|
+
* holds, building the plan, and applying it. Adapters stay thin.
|
|
900
|
+
*
|
|
901
|
+
* Two phases, deliberately separate so `--dry-run` and a real run share one code
|
|
902
|
+
* path: {@link analyzeSync} reads and decides, {@link applySync} writes.
|
|
903
|
+
*
|
|
904
|
+
* fn(args, deps) throughout.
|
|
905
|
+
*/
|
|
906
|
+
|
|
907
|
+
/** Which executions get their evidence uploaded. */
|
|
908
|
+
type AttachPolicy = "failed" | "all" | "none";
|
|
909
|
+
interface SyncEngineConfig {
|
|
910
|
+
/**
|
|
911
|
+
* Ticket-id prefix that marks a `story.tickets` entry as this provider's case
|
|
912
|
+
* id (TestRail's "C1234"). Without it, only the lockfile binds.
|
|
913
|
+
*/
|
|
914
|
+
ticketPrefix?: string;
|
|
915
|
+
/**
|
|
916
|
+
* Whether the prefix is decoration to strip ("C1234" -> "1234", TestRail) or
|
|
917
|
+
* part of the id itself ("PROJ-42" stays whole, Xray/Jira). Default true.
|
|
918
|
+
*/
|
|
919
|
+
ticketPrefixStrip?: boolean;
|
|
920
|
+
/** Base URL of the published HTML report, used for links back from cases. */
|
|
921
|
+
reportUrl?: string;
|
|
922
|
+
/**
|
|
923
|
+
* Turns a scenario into the fragment appended to `reportUrl`, for a link that
|
|
924
|
+
* lands on the scenario rather than the top of the page.
|
|
925
|
+
*
|
|
926
|
+
* Caller-supplied for the same reason the markdown formatter's option is
|
|
927
|
+
* (`types/options.ts`): the correct slug depends on how the docs site routes,
|
|
928
|
+
* and guessing it produces links that 404. Without it, cases link to the
|
|
929
|
+
* report page itself.
|
|
930
|
+
*/
|
|
931
|
+
scenarioAnchor?: (tc: TestCaseResult) => string | undefined;
|
|
932
|
+
/** Default "failed": nobody watches a passing test's video, and quotas are real. */
|
|
933
|
+
attach?: AttachPolicy;
|
|
934
|
+
/** Similarity at or above which an unlinked case is flagged as a possible duplicate. */
|
|
935
|
+
duplicateThreshold?: number;
|
|
936
|
+
}
|
|
937
|
+
/** A story, ready to be a case. */
|
|
938
|
+
interface LocalBehaviour {
|
|
939
|
+
fingerprint: string;
|
|
940
|
+
testCase: TestCaseResult;
|
|
941
|
+
body: CaseBody;
|
|
942
|
+
}
|
|
943
|
+
type CoverageClass = "automated" | "duplicated" | "possible-duplicate" | "manual-only";
|
|
944
|
+
interface ClassifiedCase {
|
|
945
|
+
case: RemoteCase;
|
|
946
|
+
classification: CoverageClass;
|
|
947
|
+
/** Scenario title this case resembles or duplicates, when one was found. */
|
|
948
|
+
resembles?: string;
|
|
949
|
+
/** 0..1, present for "possible-duplicate". */
|
|
950
|
+
similarity?: number;
|
|
951
|
+
}
|
|
952
|
+
interface PlanCreate {
|
|
953
|
+
fingerprint: string;
|
|
954
|
+
scenario: string;
|
|
955
|
+
body: CaseBody;
|
|
767
956
|
}
|
|
768
|
-
interface
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
buildNumber?: string;
|
|
772
|
-
branch?: string;
|
|
773
|
-
commitSha?: string;
|
|
774
|
-
prNumber?: string;
|
|
775
|
-
}
|
|
776
|
-
interface ReportCoverageSummary {
|
|
777
|
-
linesPct?: number;
|
|
778
|
-
branchesPct?: number;
|
|
779
|
-
functionsPct?: number;
|
|
780
|
-
statementsPct?: number;
|
|
781
|
-
}
|
|
782
|
-
type ReportDocEntry = ReportDocNote | ReportDocTag | ReportDocKv | ReportDocCode | ReportDocTable | ReportDocLink | ReportDocSection | ReportDocMermaid | ReportDocScreenshot | ReportDocVideo | ReportDocHtml | ReportDocState | ReportDocCustom;
|
|
783
|
-
interface ReportDocNote {
|
|
784
|
-
kind: "note";
|
|
785
|
-
text: string;
|
|
786
|
-
phase: DocPhase;
|
|
787
|
-
children?: ReportDocEntry[];
|
|
788
|
-
}
|
|
789
|
-
interface ReportDocTag {
|
|
790
|
-
kind: "tag";
|
|
791
|
-
names: string[];
|
|
792
|
-
phase: DocPhase;
|
|
793
|
-
children?: ReportDocEntry[];
|
|
794
|
-
}
|
|
795
|
-
interface ReportDocKv {
|
|
796
|
-
kind: "kv";
|
|
797
|
-
label: string;
|
|
798
|
-
value: unknown;
|
|
799
|
-
phase: DocPhase;
|
|
800
|
-
children?: ReportDocEntry[];
|
|
801
|
-
}
|
|
802
|
-
interface ReportDocCode {
|
|
803
|
-
kind: "code";
|
|
804
|
-
label: string;
|
|
805
|
-
content: string;
|
|
806
|
-
lang?: string;
|
|
807
|
-
phase: DocPhase;
|
|
808
|
-
children?: ReportDocEntry[];
|
|
809
|
-
}
|
|
810
|
-
interface ReportDocTable {
|
|
811
|
-
kind: "table";
|
|
812
|
-
label: string;
|
|
813
|
-
columns: string[];
|
|
814
|
-
rows: string[][];
|
|
815
|
-
phase: DocPhase;
|
|
816
|
-
children?: ReportDocEntry[];
|
|
817
|
-
}
|
|
818
|
-
interface ReportDocLink {
|
|
819
|
-
kind: "link";
|
|
820
|
-
label: string;
|
|
957
|
+
interface PlanUpdate {
|
|
958
|
+
fingerprint: string;
|
|
959
|
+
caseId: string;
|
|
821
960
|
url: string;
|
|
822
|
-
|
|
823
|
-
|
|
961
|
+
scenario: string;
|
|
962
|
+
body: CaseBody;
|
|
824
963
|
}
|
|
825
|
-
interface
|
|
826
|
-
|
|
964
|
+
interface PlanSkip {
|
|
965
|
+
fingerprint: string;
|
|
966
|
+
caseId: string;
|
|
967
|
+
url: string;
|
|
827
968
|
title: string;
|
|
828
|
-
|
|
829
|
-
phase: DocPhase;
|
|
830
|
-
children?: ReportDocEntry[];
|
|
969
|
+
reason: "remote-edited" | "case-missing";
|
|
831
970
|
}
|
|
832
|
-
interface
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
children?: ReportDocEntry[];
|
|
971
|
+
interface PlanOrphan {
|
|
972
|
+
fingerprint: string;
|
|
973
|
+
caseId: string;
|
|
974
|
+
url: string;
|
|
975
|
+
title: string;
|
|
838
976
|
}
|
|
839
|
-
interface
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
977
|
+
interface AttachmentSummary {
|
|
978
|
+
files: number;
|
|
979
|
+
bytes: number;
|
|
980
|
+
oversized: Array<{
|
|
981
|
+
filename: string;
|
|
982
|
+
bytes: number;
|
|
983
|
+
limit: number;
|
|
984
|
+
}>;
|
|
985
|
+
byRole: Record<string, number>;
|
|
986
|
+
}
|
|
987
|
+
interface SyncAnalysis {
|
|
988
|
+
provider: string;
|
|
989
|
+
target?: string;
|
|
990
|
+
local: LocalBehaviour[];
|
|
991
|
+
remote: ClassifiedCase[];
|
|
992
|
+
create: PlanCreate[];
|
|
993
|
+
update: PlanUpdate[];
|
|
994
|
+
unchanged: PlanUpdate[];
|
|
995
|
+
/** Human-authored cases bound via `story.tickets`. Executions only, body untouched. */
|
|
996
|
+
adopted: PlanUpdate[];
|
|
997
|
+
skipped: PlanSkip[];
|
|
998
|
+
orphaned: PlanOrphan[];
|
|
999
|
+
/** Results for behaviours already bound. Newly created cases add theirs at apply time. */
|
|
1000
|
+
results: CaseResult[];
|
|
1001
|
+
attachments: AttachmentSummary;
|
|
1002
|
+
/** Capabilities this provider lacks that the plan would otherwise use. */
|
|
1003
|
+
unsupported: string[];
|
|
1004
|
+
/**
|
|
1005
|
+
* Bound cases the provider would not hand back a body for, so a human edit to
|
|
1006
|
+
* them cannot be detected. Reported rather than assumed safe.
|
|
1007
|
+
*/
|
|
1008
|
+
driftUncheckable: number;
|
|
1009
|
+
/** Set when the orphan count suggests the run was filtered rather than complete. */
|
|
1010
|
+
partialRunWarning?: string;
|
|
1011
|
+
}
|
|
1012
|
+
interface SyncApplyResult {
|
|
1013
|
+
created: Array<{
|
|
1014
|
+
scenario: string;
|
|
1015
|
+
caseId: string;
|
|
1016
|
+
url: string;
|
|
1017
|
+
}>;
|
|
1018
|
+
updated: Array<{
|
|
1019
|
+
scenario: string;
|
|
1020
|
+
caseId: string;
|
|
1021
|
+
url: string;
|
|
1022
|
+
}>;
|
|
1023
|
+
resultsRecorded: number;
|
|
1024
|
+
resultsSkipped: Array<{
|
|
1025
|
+
caseId: string;
|
|
1026
|
+
reason: string;
|
|
1027
|
+
}>;
|
|
1028
|
+
attachmentsUploaded: number;
|
|
1029
|
+
runUrl?: string;
|
|
1030
|
+
errors: string[];
|
|
845
1031
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1032
|
+
/** Project one canonical test case into provider-neutral case content. */
|
|
1033
|
+
declare function toCaseBody(tc: TestCaseResult, config: SyncEngineConfig): CaseBody;
|
|
1034
|
+
/**
|
|
1035
|
+
* Project a run into fingerprinted behaviours.
|
|
1036
|
+
*
|
|
1037
|
+
* `behaviourFingerprint` returns "" for a scenario with no steps and no
|
|
1038
|
+
* `covers`, and two scenarios with identical steps collide. Both fall back to
|
|
1039
|
+
* the canonical test-case id, which is unique within a run — less
|
|
1040
|
+
* rename-resilient, but a stable binding beats a shared one.
|
|
1041
|
+
*/
|
|
1042
|
+
declare function projectBehaviours(run: TestRunResult, config: SyncEngineConfig): LocalBehaviour[];
|
|
1043
|
+
/** Attachments for one test, filtered by policy and the provider's size limit. */
|
|
1044
|
+
declare function collectAttachments(args: {
|
|
1045
|
+
testCase: TestCaseResult;
|
|
1046
|
+
policy: AttachPolicy;
|
|
1047
|
+
maxBytes?: number;
|
|
1048
|
+
}): {
|
|
1049
|
+
attachments: ResultAttachment[];
|
|
1050
|
+
oversized: Array<{
|
|
1051
|
+
filename: string;
|
|
1052
|
+
bytes: number;
|
|
1053
|
+
limit: number;
|
|
1054
|
+
}>;
|
|
1055
|
+
};
|
|
1056
|
+
interface AnalyzeSyncArgs {
|
|
1057
|
+
run: TestRunResult;
|
|
1058
|
+
provider: SyncProvider;
|
|
1059
|
+
lockfile: Lockfile;
|
|
1060
|
+
config: SyncEngineConfig;
|
|
1061
|
+
}
|
|
1062
|
+
declare function analyzeSync(args: AnalyzeSyncArgs): Promise<SyncAnalysis>;
|
|
1063
|
+
interface ApplySyncArgs {
|
|
1064
|
+
analysis: SyncAnalysis;
|
|
1065
|
+
provider: SyncProvider;
|
|
1066
|
+
lockfile: Lockfile;
|
|
1067
|
+
config: SyncEngineConfig;
|
|
1068
|
+
}
|
|
1069
|
+
interface ApplySyncDeps {
|
|
1070
|
+
logger: {
|
|
1071
|
+
warn(msg: string): void;
|
|
1072
|
+
};
|
|
876
1073
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1074
|
+
/**
|
|
1075
|
+
* Execute the plan. Mutates the passed lockfile so the caller can persist it
|
|
1076
|
+
* even when a later stage fails — a created case whose binding was lost would
|
|
1077
|
+
* be re-created on the next run, which is the one duplicate we can actually
|
|
1078
|
+
* cause.
|
|
1079
|
+
*/
|
|
1080
|
+
declare function applySync(args: ApplySyncArgs, deps: ApplySyncDeps): Promise<SyncApplyResult>;
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* TestRail adapter.
|
|
1084
|
+
*
|
|
1085
|
+
* Translates between the sync port and TestRail's API v2. All decisions about
|
|
1086
|
+
* what to write live in the engine; this file only knows how TestRail spells
|
|
1087
|
+
* things.
|
|
1088
|
+
*
|
|
1089
|
+
* Case templates differ per instance, which is why the step and description
|
|
1090
|
+
* field names are configurable. The defaults match TestRail's stock
|
|
1091
|
+
* "Test Case (Steps)" template.
|
|
1092
|
+
*
|
|
1093
|
+
* Auth: basic, with an API key rather than a password. Generate one under
|
|
1094
|
+
* My Settings -> API Keys.
|
|
1095
|
+
*/
|
|
1096
|
+
|
|
1097
|
+
interface TestRailConfig {
|
|
1098
|
+
/** Instance URL, e.g. https://acme.testrail.io */
|
|
1099
|
+
url: string;
|
|
1100
|
+
projectId: number | string;
|
|
1101
|
+
/** Required on multi-suite projects. */
|
|
1102
|
+
suiteId?: number | string;
|
|
1103
|
+
/** Target section for created cases. Without it, creation is refused. */
|
|
1104
|
+
sectionId?: number | string;
|
|
1105
|
+
/** Reuse an existing run instead of creating one per sync. */
|
|
1106
|
+
runId?: number | string;
|
|
1107
|
+
/** Name for created runs. A UTC timestamp is appended. */
|
|
1108
|
+
runName?: string;
|
|
1109
|
+
/** Close the run after recording results. */
|
|
1110
|
+
closeRun?: boolean;
|
|
1111
|
+
/** Case template to create against, when the project uses a non-default one. */
|
|
1112
|
+
templateId?: number;
|
|
1113
|
+
/**
|
|
1114
|
+
* Result status ids. TestRail ships 1=Passed and 5=Failed; there is no stock
|
|
1115
|
+
* "skipped", so skipped results are dropped unless an id is configured.
|
|
1116
|
+
*/
|
|
1117
|
+
statusIds?: {
|
|
1118
|
+
passed?: number;
|
|
1119
|
+
failed?: number;
|
|
1120
|
+
skipped?: number;
|
|
1121
|
+
};
|
|
1122
|
+
/** Field names, for instances with customised case templates. */
|
|
1123
|
+
fields?: {
|
|
1124
|
+
steps?: string;
|
|
1125
|
+
description?: string;
|
|
1126
|
+
};
|
|
1127
|
+
/**
|
|
1128
|
+
* Per-file attachment limit. Conservative by default: instances have storage
|
|
1129
|
+
* quotas, and a surprise 200 MB of video is a support ticket.
|
|
1130
|
+
*/
|
|
1131
|
+
maxAttachmentBytes?: number;
|
|
1132
|
+
}
|
|
1133
|
+
interface TestRailAuth {
|
|
1134
|
+
username: string;
|
|
1135
|
+
apiKey: string;
|
|
1136
|
+
}
|
|
1137
|
+
declare function createTestRailProvider(config: TestRailConfig, auth: TestRailAuth, deps: AdapterDeps): SyncProvider;
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* Xray (Jira Cloud) adapter.
|
|
1141
|
+
*
|
|
1142
|
+
* Xray splits its API in two and this adapter has to speak both: a GraphQL API
|
|
1143
|
+
* for test definitions, and a REST endpoint for importing execution results.
|
|
1144
|
+
* Evidence rides along with the results as base64, so screenshots and video
|
|
1145
|
+
* land on the execution without a separate upload call.
|
|
1146
|
+
*
|
|
1147
|
+
* A case id here is a Jira issue key ("PROJ-42"), not a number, which is why
|
|
1148
|
+
* `ticketPrefixStrip: false` is the right engine setting for this provider.
|
|
1149
|
+
*
|
|
1150
|
+
* Auth: an Xray API key pair (client id + secret) from Jira Settings -> Apps ->
|
|
1151
|
+
* Xray -> API Keys. Updating an existing test's summary or description also
|
|
1152
|
+
* needs Jira credentials, because those are Jira fields Xray does not own.
|
|
1153
|
+
*/
|
|
1154
|
+
|
|
1155
|
+
interface XrayConfig {
|
|
1156
|
+
/** Jira site URL, e.g. https://acme.atlassian.net */
|
|
1157
|
+
jiraBaseUrl: string;
|
|
1158
|
+
projectKey: string;
|
|
1159
|
+
/** Xray Cloud API base. */
|
|
1160
|
+
xrayBaseUrl?: string;
|
|
1161
|
+
/** Selects the existing tests to reconcile against. */
|
|
1162
|
+
jql?: string;
|
|
1163
|
+
/** Xray test type for created tests. */
|
|
1164
|
+
testType?: string;
|
|
1165
|
+
/** Link created executions to this test plan. */
|
|
1166
|
+
testPlanKey?: string;
|
|
1167
|
+
/** Push results into an existing execution instead of creating one. */
|
|
1168
|
+
testExecutionKey?: string;
|
|
1169
|
+
/** Summary for created executions. A UTC timestamp is appended. */
|
|
1170
|
+
executionSummary?: string;
|
|
1171
|
+
statuses?: {
|
|
1172
|
+
passed?: string;
|
|
1173
|
+
failed?: string;
|
|
1174
|
+
skipped?: string;
|
|
1175
|
+
};
|
|
1176
|
+
maxAttachmentBytes?: number;
|
|
883
1177
|
}
|
|
884
|
-
interface
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
errorMessage?: string;
|
|
892
|
-
mode?: StepMode;
|
|
893
|
-
docEntries: ReportDocEntry[];
|
|
1178
|
+
interface XrayAuth {
|
|
1179
|
+
clientId: string;
|
|
1180
|
+
clientSecret: string;
|
|
1181
|
+
/** Atlassian account email, needed only to update Jira summary/description. */
|
|
1182
|
+
jiraEmail?: string;
|
|
1183
|
+
/** Atlassian API token, needed only to update Jira summary/description. */
|
|
1184
|
+
jiraToken?: string;
|
|
894
1185
|
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1186
|
+
declare function createXrayProvider(config: XrayConfig, auth: XrayAuth, deps: AdapterDeps): SyncProvider;
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Provider registry.
|
|
1190
|
+
*
|
|
1191
|
+
* Adding a provider is one file next to this one plus one entry in the map
|
|
1192
|
+
* below. No dynamic import: the CLI ships as a Bun single binary, which cannot
|
|
1193
|
+
* see modules resolved at runtime, so adapters are in-tree by design.
|
|
1194
|
+
*
|
|
1195
|
+
* Credentials come from the environment only, never from the config file, so a
|
|
1196
|
+
* config can be committed without leaking anything.
|
|
1197
|
+
*/
|
|
1198
|
+
|
|
1199
|
+
type ProviderName = "testrail" | "xray";
|
|
1200
|
+
/** Per-provider config as it appears under `sync` in executable-stories.config.mjs. */
|
|
1201
|
+
interface SyncTargets {
|
|
1202
|
+
testrail?: TestRailConfig & Partial<SyncEngineConfig>;
|
|
1203
|
+
xray?: XrayConfig & Partial<SyncEngineConfig>;
|
|
1204
|
+
}
|
|
1205
|
+
interface BuiltProvider {
|
|
1206
|
+
provider: SyncProvider;
|
|
1207
|
+
/** Engine defaults this provider implies, overridable per target in config. */
|
|
1208
|
+
engineDefaults: SyncEngineConfig;
|
|
1209
|
+
}
|
|
1210
|
+
declare const PROVIDER_NAMES: ProviderName[];
|
|
1211
|
+
declare function isProviderName(value: string): value is ProviderName;
|
|
1212
|
+
declare function buildProvider(args: {
|
|
1213
|
+
name: ProviderName;
|
|
1214
|
+
targets: SyncTargets;
|
|
1215
|
+
env: Record<string, string | undefined>;
|
|
1216
|
+
}, deps: AdapterDeps): BuiltProvider;
|
|
1217
|
+
|
|
1218
|
+
interface Formatter {
|
|
1219
|
+
name: string;
|
|
1220
|
+
fileExtension?: string;
|
|
1221
|
+
format(run: TestRunResult): string;
|
|
1222
|
+
}
|
|
1223
|
+
interface ExecutableStoriesConfig {
|
|
1224
|
+
formatters?: Record<string, Formatter>;
|
|
899
1225
|
/**
|
|
900
|
-
*
|
|
901
|
-
*
|
|
902
|
-
* Canonical status stays "pending"; this flags why.
|
|
1226
|
+
* Test-management targets for `coverage` and `sync`. Shape only — credentials
|
|
1227
|
+
* are read from the environment so this file stays committable.
|
|
903
1228
|
*/
|
|
904
|
-
|
|
905
|
-
durationMs: number;
|
|
906
|
-
tags: string[];
|
|
907
|
-
tickets?: ReportTicket[];
|
|
908
|
-
/** Product-code paths/globs this scenario exercises (project-root-relative). */
|
|
909
|
-
covers?: string[];
|
|
910
|
-
sourceLine?: number;
|
|
911
|
-
errorMessage?: string;
|
|
912
|
-
errorStack?: string;
|
|
913
|
-
retry: number;
|
|
914
|
-
retries: number;
|
|
915
|
-
docEntries: ReportDocEntry[];
|
|
916
|
-
steps: ReportStep[];
|
|
917
|
-
attachments: ReportAttachment[];
|
|
918
|
-
/** OTel spans for the trace waterfall (carried through from the run). */
|
|
919
|
-
otelSpans?: OtelSpan[];
|
|
920
|
-
}
|
|
921
|
-
interface ReportFeature {
|
|
922
|
-
id: string;
|
|
923
|
-
title: string;
|
|
924
|
-
sourceFile: string;
|
|
925
|
-
summary: ReportSummary;
|
|
926
|
-
scenarios: ReportScenario[];
|
|
1229
|
+
sync?: SyncTargets;
|
|
927
1230
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Rendering for the two things a human reads: the coverage report and the plan.
|
|
1234
|
+
*
|
|
1235
|
+
* Coverage answers "what does my test-management system hold that my tests
|
|
1236
|
+
* already cover?", which needs no write access and is the whole reason to try
|
|
1237
|
+
* this. The plan borrows `terraform plan` deliberately: the idiom is already in
|
|
1238
|
+
* everyone's head, and it is what makes pointing this at a company's TestRail
|
|
1239
|
+
* feel safe.
|
|
1240
|
+
*
|
|
1241
|
+
* Pure functions of a {@link SyncAnalysis}. No IO here.
|
|
1242
|
+
*/
|
|
1243
|
+
|
|
1244
|
+
interface CoverageSummary {
|
|
1245
|
+
provider: string;
|
|
1246
|
+
target?: string;
|
|
1247
|
+
totalCases: number;
|
|
1248
|
+
automated: number;
|
|
1249
|
+
duplicated: number;
|
|
1250
|
+
possibleDuplicate: number;
|
|
1251
|
+
manualOnly: number;
|
|
1252
|
+
/** Stories with no case in the provider. */
|
|
1253
|
+
untracked: number;
|
|
1254
|
+
/** Stories whose case was reached through a human-authored ticket id. */
|
|
1255
|
+
adopted: number;
|
|
1256
|
+
}
|
|
1257
|
+
interface CoverageJson extends CoverageSummary {
|
|
1258
|
+
schema: "executable-stories/sync-coverage/v1";
|
|
1259
|
+
cases: Array<{
|
|
1260
|
+
id: string;
|
|
1261
|
+
url: string;
|
|
1262
|
+
title: string;
|
|
1263
|
+
section?: string;
|
|
1264
|
+
classification: ClassifiedCase["classification"];
|
|
1265
|
+
resembles?: string;
|
|
1266
|
+
similarity?: number;
|
|
1267
|
+
}>;
|
|
1268
|
+
untrackedScenarios: string[];
|
|
1269
|
+
orphaned: Array<{
|
|
1270
|
+
caseId: string;
|
|
1271
|
+
url: string;
|
|
1272
|
+
title: string;
|
|
1273
|
+
}>;
|
|
1274
|
+
sections: Array<{
|
|
1275
|
+
name: string;
|
|
1276
|
+
total: number;
|
|
1277
|
+
automated: number;
|
|
1278
|
+
}>;
|
|
941
1279
|
}
|
|
942
|
-
|
|
943
|
-
declare
|
|
1280
|
+
/** Human-readable coverage, the first thing anyone sees. */
|
|
1281
|
+
declare function renderCoverageText(analysis: SyncAnalysis): string;
|
|
1282
|
+
/** The same content as Markdown, so it can be pasted, published, or PR-commented. */
|
|
1283
|
+
declare function renderCoverageMarkdown(analysis: SyncAnalysis): string;
|
|
1284
|
+
declare function buildCoverageJson(analysis: SyncAnalysis): CoverageJson;
|
|
1285
|
+
/** terraform-plan-shaped output. Read before anything is written. */
|
|
1286
|
+
declare function renderPlan(analysis: SyncAnalysis, opts: {
|
|
1287
|
+
dryRun: boolean;
|
|
1288
|
+
}): string;
|
|
1289
|
+
/** What actually happened, printed after a real run. */
|
|
1290
|
+
declare function renderApplyResult(result: SyncApplyResult): string;
|
|
944
1291
|
|
|
945
1292
|
/**
|
|
946
1293
|
* Diff types — parsed unified patches and content-anchored annotation targets.
|
|
@@ -1101,7 +1448,7 @@ interface CodeDiffScenarioRef {
|
|
|
1101
1448
|
/** False = the cited scenario is not in this run — render as "unverified reference". */
|
|
1102
1449
|
resolved: boolean;
|
|
1103
1450
|
scenario?: string;
|
|
1104
|
-
status?: TestStatus
|
|
1451
|
+
status?: TestStatus;
|
|
1105
1452
|
}
|
|
1106
1453
|
/** An annotation resolved against the parsed patch and the run. */
|
|
1107
1454
|
interface CodeDiffAnnotation {
|
|
@@ -1135,7 +1482,7 @@ interface ReviewClaim {
|
|
|
1135
1482
|
sourceFile: string;
|
|
1136
1483
|
sourceLine: number;
|
|
1137
1484
|
/** Test outcome. */
|
|
1138
|
-
status: TestStatus
|
|
1485
|
+
status: TestStatus;
|
|
1139
1486
|
/** Derived from file convention / `audience:` tag. */
|
|
1140
1487
|
audience: ReviewAudience;
|
|
1141
1488
|
/** Declared via `change:*` tag (defaults to `unknown`). */
|
|
@@ -1188,239 +1535,6 @@ interface ReviewResult {
|
|
|
1188
1535
|
codeDiffs: CodeDiffEvidence[];
|
|
1189
1536
|
}
|
|
1190
1537
|
|
|
1191
|
-
/**
|
|
1192
|
-
* Canonical executable-stories theme tokens (--es-*).
|
|
1193
|
-
*
|
|
1194
|
-
* Source of truth for the `--es-color-*`, `--es-space-*`, `--es-font-*`,
|
|
1195
|
-
* `--es-size-*`, `--es-radius`, `--es-line`, and `--es-measure` CSS custom
|
|
1196
|
-
* properties consumed by:
|
|
1197
|
-
*
|
|
1198
|
-
* - executable-stories-react (styles.css)
|
|
1199
|
-
* - executable-stories-formatters HTML report (CSS_STYLES, via this module)
|
|
1200
|
-
*
|
|
1201
|
-
* Consumer-side overrides on `:root` or any ancestor of the report cascade
|
|
1202
|
-
* through both: setting `--es-color-failed: red` on body re-colors failures
|
|
1203
|
-
* in both the standalone HTML report and the React component.
|
|
1204
|
-
*
|
|
1205
|
-
* The HTML formatter's pre-existing tokens (--success, --error, etc.)
|
|
1206
|
-
* remain in place for backward compatibility; the --es-* tokens are emitted
|
|
1207
|
-
* alongside them as the public override surface.
|
|
1208
|
-
*/
|
|
1209
|
-
declare const ES_THEME_TOKENS_CSS: string;
|
|
1210
|
-
/**
|
|
1211
|
-
* JS-level mirror of the token values (for cases where TypeScript code needs
|
|
1212
|
-
* to read them — e.g., dynamic style injection or theme generators).
|
|
1213
|
-
*/
|
|
1214
|
-
declare const ES_THEME_TOKEN_VALUES: {
|
|
1215
|
-
readonly light: {
|
|
1216
|
-
readonly "--es-color-bg": "#ffffff";
|
|
1217
|
-
readonly "--es-color-fg": "#111827";
|
|
1218
|
-
readonly "--es-color-muted": "#6b7280";
|
|
1219
|
-
readonly "--es-color-border": "#e5e7eb";
|
|
1220
|
-
readonly "--es-color-surface": "#f9fafb";
|
|
1221
|
-
readonly "--es-color-link": "#2563eb";
|
|
1222
|
-
readonly "--es-color-passed": "#16a34a";
|
|
1223
|
-
readonly "--es-color-failed": "#dc2626";
|
|
1224
|
-
readonly "--es-color-skipped": "#9ca3af";
|
|
1225
|
-
readonly "--es-color-pending": "#d97706";
|
|
1226
|
-
};
|
|
1227
|
-
readonly dark: {
|
|
1228
|
-
readonly "--es-color-bg": "#0b0f17";
|
|
1229
|
-
readonly "--es-color-fg": "#e5e7eb";
|
|
1230
|
-
readonly "--es-color-muted": "#9ca3af";
|
|
1231
|
-
readonly "--es-color-border": "#1f2937";
|
|
1232
|
-
readonly "--es-color-surface": "#111827";
|
|
1233
|
-
readonly "--es-color-link": "#60a5fa";
|
|
1234
|
-
readonly "--es-color-passed": "#4ade80";
|
|
1235
|
-
readonly "--es-color-failed": "#f87171";
|
|
1236
|
-
readonly "--es-color-skipped": "#6b7280";
|
|
1237
|
-
readonly "--es-color-pending": "#fbbf24";
|
|
1238
|
-
};
|
|
1239
|
-
};
|
|
1240
|
-
|
|
1241
|
-
/**
|
|
1242
|
-
* Status mapping from raw framework statuses to canonical TestStatus.
|
|
1243
|
-
*/
|
|
1244
|
-
|
|
1245
|
-
/**
|
|
1246
|
-
* Convert a raw status to canonical TestStatus.
|
|
1247
|
-
*
|
|
1248
|
-
* @param raw - The raw status from a framework
|
|
1249
|
-
* @returns The canonical TestStatus
|
|
1250
|
-
*/
|
|
1251
|
-
declare function normalizeStatus(raw: RawStatus): TestStatus$1;
|
|
1252
|
-
|
|
1253
|
-
/**
|
|
1254
|
-
* ID generation and slug helpers for deterministic, Cucumber-compatible IDs.
|
|
1255
|
-
*/
|
|
1256
|
-
/**
|
|
1257
|
-
* Generate a deterministic test case ID from source file and scenario name.
|
|
1258
|
-
*
|
|
1259
|
-
* @param sourceFile - The source file path
|
|
1260
|
-
* @param scenario - The scenario name
|
|
1261
|
-
* @returns A 12-character hex ID
|
|
1262
|
-
*/
|
|
1263
|
-
declare function generateTestCaseId(sourceFile: string, scenario: string): string;
|
|
1264
|
-
/**
|
|
1265
|
-
* Generate a deterministic run ID from timestamp and project root.
|
|
1266
|
-
*
|
|
1267
|
-
* @param startedAtMs - Run start timestamp
|
|
1268
|
-
* @param projectRoot - Project root directory
|
|
1269
|
-
* @returns A 16-character hex ID
|
|
1270
|
-
*/
|
|
1271
|
-
declare function generateRunId(startedAtMs: number, projectRoot: string): string;
|
|
1272
|
-
/**
|
|
1273
|
-
* Slugify a string for Cucumber JSON IDs.
|
|
1274
|
-
*
|
|
1275
|
-
* Converts to lowercase, replaces path separators/spaces with hyphens,
|
|
1276
|
-
* removes other special chars, and trims leading/trailing hyphens.
|
|
1277
|
-
*
|
|
1278
|
-
* @param text - The text to slugify
|
|
1279
|
-
* @returns A URL-safe slug
|
|
1280
|
-
*/
|
|
1281
|
-
declare function slugify(text: string): string;
|
|
1282
|
-
|
|
1283
|
-
/**
|
|
1284
|
-
* Step fallback rules for deriving step results from scenario status.
|
|
1285
|
-
*
|
|
1286
|
-
* When frameworks don't provide step-level results, we derive them
|
|
1287
|
-
* from the overall scenario status using these rules.
|
|
1288
|
-
*/
|
|
1289
|
-
|
|
1290
|
-
/**
|
|
1291
|
-
* Derive step results from story steps and scenario status.
|
|
1292
|
-
*
|
|
1293
|
-
* Rules:
|
|
1294
|
-
* - Passed: All steps are passed
|
|
1295
|
-
* - Skipped/Pending: All steps are skipped/pending
|
|
1296
|
-
* - Failed: Steps up to failure are passed, failing step is failed, rest are skipped
|
|
1297
|
-
* (Heuristic: last step is the failure, or use error info if available)
|
|
1298
|
-
*
|
|
1299
|
-
* @param steps - Story steps with keywords and text
|
|
1300
|
-
* @param scenarioStatus - Overall scenario status
|
|
1301
|
-
* @param error - Optional error information to help identify failing step
|
|
1302
|
-
* @returns Array of step results
|
|
1303
|
-
*/
|
|
1304
|
-
declare function deriveStepResults(steps: StoryStep[], scenarioStatus: TestStatus$1, error?: {
|
|
1305
|
-
message?: string;
|
|
1306
|
-
stack?: string;
|
|
1307
|
-
}): StepResult[];
|
|
1308
|
-
/**
|
|
1309
|
-
* Merge raw step events with derived step results.
|
|
1310
|
-
*
|
|
1311
|
-
* When we have partial step data from the framework, merge it with
|
|
1312
|
-
* the derived results, preferring actual data over derived.
|
|
1313
|
-
*
|
|
1314
|
-
* @param derived - Derived step results from fallback rules
|
|
1315
|
-
* @param events - Raw step events from framework (if any)
|
|
1316
|
-
* @returns Merged step results
|
|
1317
|
-
*/
|
|
1318
|
-
declare function mergeStepResults(derived: StepResult[], events?: Array<{
|
|
1319
|
-
index?: number;
|
|
1320
|
-
stepId?: string;
|
|
1321
|
-
status?: string;
|
|
1322
|
-
durationMs?: number;
|
|
1323
|
-
errorMessage?: string;
|
|
1324
|
-
}>): StepResult[];
|
|
1325
|
-
|
|
1326
|
-
/**
|
|
1327
|
-
* Attachment resolution: embed vs link decision.
|
|
1328
|
-
*
|
|
1329
|
-
* Attachments can either be embedded inline (base64) or linked to
|
|
1330
|
-
* external files based on size thresholds.
|
|
1331
|
-
*/
|
|
1332
|
-
|
|
1333
|
-
/** Options for attachment resolution */
|
|
1334
|
-
interface AttachmentOptions {
|
|
1335
|
-
/** Max bytes before attachment becomes external link. Default: 512KB */
|
|
1336
|
-
maxEmbedBytes?: number;
|
|
1337
|
-
/** Directory for external attachments */
|
|
1338
|
-
externalDir?: string;
|
|
1339
|
-
/** Project root for relative paths */
|
|
1340
|
-
projectRoot?: string;
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* Resolve a raw attachment to a canonical attachment.
|
|
1344
|
-
*
|
|
1345
|
-
* Decision logic:
|
|
1346
|
-
* 1. If body is already provided, use it (check size for encoding decision)
|
|
1347
|
-
* 2. If path is provided, read file and decide embed vs link
|
|
1348
|
-
* 3. For large files, return a URL reference instead of embedding
|
|
1349
|
-
*
|
|
1350
|
-
* @param raw - Raw attachment from framework
|
|
1351
|
-
* @param options - Resolution options
|
|
1352
|
-
* @returns Resolved canonical attachment
|
|
1353
|
-
*/
|
|
1354
|
-
declare function resolveAttachment(raw: RawAttachment, options?: AttachmentOptions): Attachment;
|
|
1355
|
-
/**
|
|
1356
|
-
* Resolve multiple attachments.
|
|
1357
|
-
*
|
|
1358
|
-
* @param attachments - Raw attachments array
|
|
1359
|
-
* @param options - Resolution options
|
|
1360
|
-
* @returns Resolved canonical attachments
|
|
1361
|
-
*/
|
|
1362
|
-
declare function resolveAttachments(attachments: RawAttachment[] | undefined, options?: AttachmentOptions): Attachment[];
|
|
1363
|
-
|
|
1364
|
-
/**
|
|
1365
|
-
* Anti-Corruption Layer (ACL) - Layer 2.
|
|
1366
|
-
*
|
|
1367
|
-
* Transforms permissive RawRun data from framework adapters into
|
|
1368
|
-
* strict canonical TestRunResult for formatters.
|
|
1369
|
-
*/
|
|
1370
|
-
|
|
1371
|
-
/**
|
|
1372
|
-
* Canonicalize a raw run into a strict TestRunResult.
|
|
1373
|
-
*
|
|
1374
|
-
* This is the main entry point for the ACL. It:
|
|
1375
|
-
* - Enforces required fields with defaults
|
|
1376
|
-
* - Normalizes statuses to TestStatus enum
|
|
1377
|
-
* - Applies step fallback rules
|
|
1378
|
-
* - Resolves attachments (embed vs link)
|
|
1379
|
-
* - Generates deterministic IDs
|
|
1380
|
-
*
|
|
1381
|
-
* @param raw - Raw run data from a framework adapter
|
|
1382
|
-
* @param options - Canonicalization options
|
|
1383
|
-
* @returns Strict canonical TestRunResult
|
|
1384
|
-
*/
|
|
1385
|
-
declare function canonicalizeRun(raw: RawRun, options?: CanonicalizeOptions): TestRunResult;
|
|
1386
|
-
|
|
1387
|
-
/**
|
|
1388
|
-
* Validation helpers for canonical TestRunResult.
|
|
1389
|
-
*
|
|
1390
|
-
* Used in tests to verify ACL output meets all invariants.
|
|
1391
|
-
*/
|
|
1392
|
-
|
|
1393
|
-
/** Validation result */
|
|
1394
|
-
interface ValidationResult {
|
|
1395
|
-
/** Whether the run is valid */
|
|
1396
|
-
valid: boolean;
|
|
1397
|
-
/** List of validation errors */
|
|
1398
|
-
errors: string[];
|
|
1399
|
-
}
|
|
1400
|
-
/**
|
|
1401
|
-
* Validate a canonical TestRunResult.
|
|
1402
|
-
*
|
|
1403
|
-
* Checks:
|
|
1404
|
-
* - All required fields are present
|
|
1405
|
-
* - stepResults length matches story.steps length
|
|
1406
|
-
* - stepResults indexes are valid and unique
|
|
1407
|
-
* - Durations are non-negative
|
|
1408
|
-
* - Timestamps are valid
|
|
1409
|
-
*
|
|
1410
|
-
* @param run - The TestRunResult to validate
|
|
1411
|
-
* @returns Validation result with errors if any
|
|
1412
|
-
*/
|
|
1413
|
-
declare function validateCanonicalRun(run: TestRunResult): ValidationResult;
|
|
1414
|
-
/**
|
|
1415
|
-
* Assert that a run is valid, throwing if not.
|
|
1416
|
-
*
|
|
1417
|
-
* Useful in tests.
|
|
1418
|
-
*
|
|
1419
|
-
* @param run - The TestRunResult to validate
|
|
1420
|
-
* @throws Error if validation fails
|
|
1421
|
-
*/
|
|
1422
|
-
declare function assertValidRun(run: TestRunResult): void;
|
|
1423
|
-
|
|
1424
1538
|
/**
|
|
1425
1539
|
* Cucumber JSON Formatter - Layer 3.
|
|
1426
1540
|
*
|
|
@@ -1546,7 +1660,7 @@ interface ScenarioIndexItem {
|
|
|
1546
1660
|
* `check-explainers` can detect drift. Status is deliberately excluded.
|
|
1547
1661
|
*/
|
|
1548
1662
|
hash: string;
|
|
1549
|
-
status: TestStatus;
|
|
1663
|
+
status: TestStatus$1;
|
|
1550
1664
|
feature: string;
|
|
1551
1665
|
sourceFile: string;
|
|
1552
1666
|
sourceLine?: number;
|
|
@@ -1569,13 +1683,13 @@ interface ScenarioIndexStep {
|
|
|
1569
1683
|
index: number;
|
|
1570
1684
|
keyword: ReportStep["keyword"];
|
|
1571
1685
|
text: string;
|
|
1572
|
-
status: TestStatus;
|
|
1686
|
+
status: TestStatus$1;
|
|
1573
1687
|
durationMs: number;
|
|
1574
1688
|
errorMessage?: string;
|
|
1575
1689
|
docKinds: string[];
|
|
1576
1690
|
}
|
|
1577
1691
|
interface ScenarioIndexFilters {
|
|
1578
|
-
statuses?: TestStatus[];
|
|
1692
|
+
statuses?: TestStatus$1[];
|
|
1579
1693
|
tags?: string[];
|
|
1580
1694
|
sourceFiles?: string[];
|
|
1581
1695
|
}
|
|
@@ -1694,367 +1808,13 @@ interface WatchHandle {
|
|
|
1694
1808
|
*/
|
|
1695
1809
|
declare function startWatch(options: WatchOptions, deps?: WatchDeps): WatchHandle;
|
|
1696
1810
|
|
|
1697
|
-
/**
|
|
1698
|
-
* Cucumber Messages types for NDJSON output.
|
|
1699
|
-
*
|
|
1700
|
-
* Minimal own types (no @cucumber/messages dependency) — consistent with
|
|
1701
|
-
* the project's zero-external-deps-at-runtime approach.
|
|
1702
|
-
*
|
|
1703
|
-
* Based on the Cucumber Messages protocol:
|
|
1704
|
-
* https://github.com/cucumber/messages
|
|
1705
|
-
*/
|
|
1706
|
-
/** Protobuf-style timestamp { seconds, nanos } */
|
|
1707
|
-
interface Timestamp {
|
|
1708
|
-
seconds: number;
|
|
1709
|
-
nanos: number;
|
|
1710
|
-
}
|
|
1711
|
-
/** Protobuf-style duration { seconds, nanos } */
|
|
1712
|
-
interface Duration {
|
|
1713
|
-
seconds: number;
|
|
1714
|
-
nanos: number;
|
|
1715
|
-
}
|
|
1716
|
-
/** Location in a source file */
|
|
1717
|
-
interface Location {
|
|
1718
|
-
line: number;
|
|
1719
|
-
column?: number;
|
|
1720
|
-
}
|
|
1721
|
-
interface Meta {
|
|
1722
|
-
protocolVersion: string;
|
|
1723
|
-
implementation: {
|
|
1724
|
-
name: string;
|
|
1725
|
-
version: string;
|
|
1726
|
-
};
|
|
1727
|
-
runtime: {
|
|
1728
|
-
name: string;
|
|
1729
|
-
version: string;
|
|
1730
|
-
};
|
|
1731
|
-
os: {
|
|
1732
|
-
name: string;
|
|
1733
|
-
};
|
|
1734
|
-
cpu: {
|
|
1735
|
-
name: string;
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
interface Source {
|
|
1739
|
-
uri: string;
|
|
1740
|
-
data: string;
|
|
1741
|
-
mediaType: "text/x.cucumber.gherkin+plain";
|
|
1742
|
-
}
|
|
1743
|
-
interface Tag {
|
|
1744
|
-
location: Location;
|
|
1745
|
-
name: string;
|
|
1746
|
-
id: string;
|
|
1747
|
-
}
|
|
1748
|
-
type KeywordType = "Unknown" | "Context" | "Action" | "Outcome" | "Conjunction";
|
|
1749
|
-
interface DocString {
|
|
1750
|
-
location: Location;
|
|
1751
|
-
mediaType?: string;
|
|
1752
|
-
content: string;
|
|
1753
|
-
delimiter: string;
|
|
1754
|
-
}
|
|
1755
|
-
interface TableCell {
|
|
1756
|
-
location: Location;
|
|
1757
|
-
value: string;
|
|
1758
|
-
}
|
|
1759
|
-
interface TableRow {
|
|
1760
|
-
location: Location;
|
|
1761
|
-
cells: TableCell[];
|
|
1762
|
-
id: string;
|
|
1763
|
-
}
|
|
1764
|
-
interface DataTable {
|
|
1765
|
-
location: Location;
|
|
1766
|
-
rows: TableRow[];
|
|
1767
|
-
}
|
|
1768
|
-
interface Step {
|
|
1769
|
-
location: Location;
|
|
1770
|
-
keyword: string;
|
|
1771
|
-
keywordType: KeywordType;
|
|
1772
|
-
text: string;
|
|
1773
|
-
id: string;
|
|
1774
|
-
docString?: DocString;
|
|
1775
|
-
dataTable?: DataTable;
|
|
1776
|
-
}
|
|
1777
|
-
interface Scenario {
|
|
1778
|
-
location: Location;
|
|
1779
|
-
tags: Tag[];
|
|
1780
|
-
keyword: string;
|
|
1781
|
-
name: string;
|
|
1782
|
-
description: string;
|
|
1783
|
-
steps: Step[];
|
|
1784
|
-
id: string;
|
|
1785
|
-
}
|
|
1786
|
-
interface Background {
|
|
1787
|
-
location: Location;
|
|
1788
|
-
keyword: string;
|
|
1789
|
-
name: string;
|
|
1790
|
-
description: string;
|
|
1791
|
-
steps: Step[];
|
|
1792
|
-
id: string;
|
|
1793
|
-
}
|
|
1794
|
-
type FeatureChild = {
|
|
1795
|
-
background: Background;
|
|
1796
|
-
scenario?: undefined;
|
|
1797
|
-
} | {
|
|
1798
|
-
scenario: Scenario;
|
|
1799
|
-
background?: undefined;
|
|
1800
|
-
};
|
|
1801
|
-
interface Feature {
|
|
1802
|
-
location: Location;
|
|
1803
|
-
tags: Tag[];
|
|
1804
|
-
language: string;
|
|
1805
|
-
keyword: string;
|
|
1806
|
-
name: string;
|
|
1807
|
-
description: string;
|
|
1808
|
-
children: FeatureChild[];
|
|
1809
|
-
}
|
|
1810
|
-
interface GherkinDocument {
|
|
1811
|
-
uri: string;
|
|
1812
|
-
feature: Feature;
|
|
1813
|
-
}
|
|
1814
|
-
type PickleStepType = "Unknown" | "Context" | "Action" | "Outcome";
|
|
1815
|
-
interface PickleDocString {
|
|
1816
|
-
mediaType?: string;
|
|
1817
|
-
content: string;
|
|
1818
|
-
}
|
|
1819
|
-
interface PickleTableCell {
|
|
1820
|
-
value: string;
|
|
1821
|
-
}
|
|
1822
|
-
interface PickleTableRow {
|
|
1823
|
-
cells: PickleTableCell[];
|
|
1824
|
-
}
|
|
1825
|
-
interface PickleTable {
|
|
1826
|
-
rows: PickleTableRow[];
|
|
1827
|
-
}
|
|
1828
|
-
interface PickleStepArgument {
|
|
1829
|
-
docString?: PickleDocString;
|
|
1830
|
-
dataTable?: PickleTable;
|
|
1831
|
-
}
|
|
1832
|
-
interface PickleStep {
|
|
1833
|
-
astNodeIds: string[];
|
|
1834
|
-
id: string;
|
|
1835
|
-
type: PickleStepType;
|
|
1836
|
-
text: string;
|
|
1837
|
-
argument?: PickleStepArgument;
|
|
1838
|
-
}
|
|
1839
|
-
interface PickleTag {
|
|
1840
|
-
name: string;
|
|
1841
|
-
astNodeId: string;
|
|
1842
|
-
}
|
|
1843
|
-
interface Pickle {
|
|
1844
|
-
id: string;
|
|
1845
|
-
uri: string;
|
|
1846
|
-
name: string;
|
|
1847
|
-
language: string;
|
|
1848
|
-
steps: PickleStep[];
|
|
1849
|
-
tags: PickleTag[];
|
|
1850
|
-
astNodeIds: string[];
|
|
1851
|
-
}
|
|
1852
|
-
type TestStepResultStatus = "UNKNOWN" | "PASSED" | "SKIPPED" | "PENDING" | "UNDEFINED" | "AMBIGUOUS" | "FAILED";
|
|
1853
|
-
interface TestStepResult {
|
|
1854
|
-
duration: Duration;
|
|
1855
|
-
status: TestStepResultStatus;
|
|
1856
|
-
message?: string;
|
|
1857
|
-
}
|
|
1858
|
-
interface TestStep {
|
|
1859
|
-
id: string;
|
|
1860
|
-
pickleStepId?: string;
|
|
1861
|
-
stepDefinitionIds?: string[];
|
|
1862
|
-
}
|
|
1863
|
-
interface TestCase {
|
|
1864
|
-
id: string;
|
|
1865
|
-
pickleId: string;
|
|
1866
|
-
testSteps: TestStep[];
|
|
1867
|
-
}
|
|
1868
|
-
interface TestRunStarted {
|
|
1869
|
-
timestamp: Timestamp;
|
|
1870
|
-
}
|
|
1871
|
-
interface TestCaseStarted {
|
|
1872
|
-
id: string;
|
|
1873
|
-
testCaseId: string;
|
|
1874
|
-
timestamp: Timestamp;
|
|
1875
|
-
attempt: number;
|
|
1876
|
-
}
|
|
1877
|
-
interface TestStepStarted {
|
|
1878
|
-
testCaseStartedId: string;
|
|
1879
|
-
testStepId: string;
|
|
1880
|
-
timestamp: Timestamp;
|
|
1881
|
-
}
|
|
1882
|
-
interface TestStepFinished {
|
|
1883
|
-
testCaseStartedId: string;
|
|
1884
|
-
testStepId: string;
|
|
1885
|
-
testStepResult: TestStepResult;
|
|
1886
|
-
timestamp: Timestamp;
|
|
1887
|
-
}
|
|
1888
|
-
interface TestCaseFinished {
|
|
1889
|
-
testCaseStartedId: string;
|
|
1890
|
-
timestamp: Timestamp;
|
|
1891
|
-
willBeRetried: boolean;
|
|
1892
|
-
}
|
|
1893
|
-
interface TestRunFinished {
|
|
1894
|
-
timestamp: Timestamp;
|
|
1895
|
-
success: boolean;
|
|
1896
|
-
}
|
|
1897
|
-
type AttachmentContentEncoding = "IDENTITY" | "BASE64";
|
|
1898
|
-
interface CucumberAttachment {
|
|
1899
|
-
testCaseStartedId: string;
|
|
1900
|
-
testStepId?: string;
|
|
1901
|
-
body: string;
|
|
1902
|
-
mediaType: string;
|
|
1903
|
-
contentEncoding: AttachmentContentEncoding;
|
|
1904
|
-
}
|
|
1905
|
-
/**
|
|
1906
|
-
* Each NDJSON line is one Envelope with exactly one field set.
|
|
1907
|
-
*/
|
|
1908
|
-
type Envelope = {
|
|
1909
|
-
meta: Meta;
|
|
1910
|
-
} | {
|
|
1911
|
-
source: Source;
|
|
1912
|
-
} | {
|
|
1913
|
-
gherkinDocument: GherkinDocument;
|
|
1914
|
-
} | {
|
|
1915
|
-
pickle: Pickle;
|
|
1916
|
-
} | {
|
|
1917
|
-
testRunStarted: TestRunStarted;
|
|
1918
|
-
} | {
|
|
1919
|
-
testCase: TestCase;
|
|
1920
|
-
} | {
|
|
1921
|
-
testCaseStarted: TestCaseStarted;
|
|
1922
|
-
} | {
|
|
1923
|
-
testStepStarted: TestStepStarted;
|
|
1924
|
-
} | {
|
|
1925
|
-
testStepFinished: TestStepFinished;
|
|
1926
|
-
} | {
|
|
1927
|
-
testCaseFinished: TestCaseFinished;
|
|
1928
|
-
} | {
|
|
1929
|
-
testRunFinished: TestRunFinished;
|
|
1930
|
-
} | {
|
|
1931
|
-
attachment: CucumberAttachment;
|
|
1932
|
-
};
|
|
1933
|
-
|
|
1934
|
-
/**
|
|
1935
|
-
* Convert a canonical TestRunResult into a frozen-shape StoryReport for UI renderers.
|
|
1936
|
-
*/
|
|
1937
|
-
declare function toStoryReport(run: TestRunResult): StoryReport;
|
|
1938
|
-
|
|
1939
|
-
/**
|
|
1940
|
-
* NDJSON-to-TestRunResult parser.
|
|
1941
|
-
*
|
|
1942
|
-
* Parses Cucumber Messages NDJSON (one JSON envelope per line) back into
|
|
1943
|
-
* a TestRunResult suitable for rendering by HtmlFormatter or other formatters.
|
|
1944
|
-
*
|
|
1945
|
-
* This is the NDJSON compat path: it produces a minimal but sufficient
|
|
1946
|
-
* TestRunResult. Fields not present in the NDJSON stream are given
|
|
1947
|
-
* sensible defaults.
|
|
1948
|
-
*/
|
|
1949
|
-
|
|
1950
|
-
/**
|
|
1951
|
-
* Parse an NDJSON string into a TestRunResult.
|
|
1952
|
-
*
|
|
1953
|
-
* @param ndjson - NDJSON string (one JSON envelope per line)
|
|
1954
|
-
* @returns TestRunResult reconstructed from the envelopes
|
|
1955
|
-
*/
|
|
1956
|
-
declare function parseNdjson(ndjson: string): TestRunResult;
|
|
1957
|
-
/**
|
|
1958
|
-
* Parse an array of Envelope objects into a TestRunResult.
|
|
1959
|
-
*
|
|
1960
|
-
* @param envelopes - Array of Cucumber Messages envelopes
|
|
1961
|
-
* @returns TestRunResult reconstructed from the envelopes
|
|
1962
|
-
*/
|
|
1963
|
-
declare function parseEnvelopes(envelopes: Envelope[]): TestRunResult;
|
|
1964
|
-
|
|
1965
|
-
/**
|
|
1966
|
-
* Session trajectory primitive — the valuable part of the old `serve.ts`.
|
|
1967
|
-
*
|
|
1968
|
-
* Pins a session baseline (the first run observed) and folds each subsequent run
|
|
1969
|
-
* forward, so a docs/agent loop can show "how this run compares to where the
|
|
1970
|
-
* session started" rather than just the noise between adjacent runs. Pure (no
|
|
1971
|
-
* I/O, no diff engine) so it lives in core and is consumable by the Astro
|
|
1972
|
-
* integration and the CLI alike. Diffing the runs is layered on top by the
|
|
1973
|
-
* consumer (the diff engine lives in the formatters package).
|
|
1974
|
-
*/
|
|
1975
|
-
|
|
1976
|
-
/**
|
|
1977
|
-
* The realtime state a live view renders. The session baseline is pinned to the
|
|
1978
|
-
* first run observed after boot, so the headline tracks the whole loop's
|
|
1979
|
-
* trajectory rather than the noise between any two adjacent iterations.
|
|
1980
|
-
*/
|
|
1981
|
-
interface RunState {
|
|
1982
|
-
/** First run observed this session — the trajectory anchor. */
|
|
1983
|
-
sessionBaseline: TestRunResult | null;
|
|
1984
|
-
/** The run immediately before {@link RunState.current} — the per-iteration anchor. */
|
|
1985
|
-
previous: TestRunResult | null;
|
|
1986
|
-
/** Latest run. */
|
|
1987
|
-
current: TestRunResult | null;
|
|
1988
|
-
/** How many runs have been observed since boot. */
|
|
1989
|
-
runCount: number;
|
|
1990
|
-
}
|
|
1991
|
-
/** The empty state before any run has been observed. */
|
|
1992
|
-
declare const initialRunState: RunState;
|
|
1993
|
-
/**
|
|
1994
|
-
* Fold a freshly-read run into the prior state. The first run pins the session
|
|
1995
|
-
* baseline; later runs shift `previous`/`current` forward. Pure.
|
|
1996
|
-
*/
|
|
1997
|
-
declare function advanceState(prev: RunState, run: TestRunResult): RunState;
|
|
1998
|
-
|
|
1999
|
-
/**
|
|
2000
|
-
* Canonical builders for doc entries whose construction carries a rule worth
|
|
2001
|
-
* keeping in one place. Adapters import these instead of re-implementing the
|
|
2002
|
-
* logic (the `html` exactly-one-of-source rule was previously copied verbatim
|
|
2003
|
-
* across the Vitest, Jest, Cypress, and Playwright adapters).
|
|
2004
|
-
*/
|
|
2005
|
-
|
|
2006
|
-
/** Source/presentation options for an `html` doc entry. */
|
|
2007
|
-
interface HtmlDocOptions {
|
|
2008
|
-
/** Local HTML file path (inlined into the report by default). */
|
|
2009
|
-
path?: string;
|
|
2010
|
-
/** Remote URL rendered via iframe src. */
|
|
2011
|
-
url?: string;
|
|
2012
|
-
/** Inline HTML content rendered via iframe srcdoc. */
|
|
2013
|
-
content?: string;
|
|
2014
|
-
title?: string;
|
|
2015
|
-
/** Iframe height: number → px, string passed through (e.g. '60vh'). Default 400px. */
|
|
2016
|
-
height?: number | string;
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Build an `html` DocEntry, enforcing that exactly one of path/url/content is
|
|
2020
|
-
* set. Throws otherwise — this is the single source of that rule.
|
|
2021
|
-
*/
|
|
2022
|
-
declare function buildHtmlDocEntry(options: HtmlDocOptions): DocEntry;
|
|
2023
|
-
|
|
2024
|
-
/**
|
|
2025
|
-
* Duration formatting utilities.
|
|
2026
|
-
*/
|
|
2027
|
-
/**
|
|
2028
|
-
* Format milliseconds as human-readable duration.
|
|
2029
|
-
*
|
|
2030
|
-
* @param ms - Duration in milliseconds
|
|
2031
|
-
* @returns Formatted string (e.g., "123 ms", "1.5 s", "2m 30s")
|
|
2032
|
-
*/
|
|
2033
|
-
declare function formatDuration(ms: number): string;
|
|
2034
|
-
/**
|
|
2035
|
-
* Convert milliseconds to nanoseconds.
|
|
2036
|
-
*
|
|
2037
|
-
* Used for Cucumber JSON format which expects nanoseconds.
|
|
2038
|
-
*
|
|
2039
|
-
* @param ms - Duration in milliseconds
|
|
2040
|
-
* @returns Duration in nanoseconds
|
|
2041
|
-
*/
|
|
2042
|
-
declare function msToNanoseconds(ms: number): number;
|
|
2043
|
-
/**
|
|
2044
|
-
* Convert nanoseconds to milliseconds.
|
|
2045
|
-
*
|
|
2046
|
-
* @param ns - Duration in nanoseconds
|
|
2047
|
-
* @returns Duration in milliseconds
|
|
2048
|
-
*/
|
|
2049
|
-
declare function nanosecondsToMs(ns: number): number;
|
|
2050
|
-
|
|
2051
1811
|
interface BehaviorDiffEntry {
|
|
2052
1812
|
id: string;
|
|
2053
1813
|
title: string;
|
|
2054
1814
|
sourceFile: string;
|
|
2055
1815
|
kind: ScenarioChangeKind;
|
|
2056
|
-
baselineStatus?: TestStatus;
|
|
2057
|
-
currentStatus?: TestStatus;
|
|
1816
|
+
baselineStatus?: TestStatus$1;
|
|
1817
|
+
currentStatus?: TestStatus$1;
|
|
2058
1818
|
}
|
|
2059
1819
|
interface BehaviorDiff {
|
|
2060
1820
|
schemaVersion: "1.0";
|
|
@@ -2072,7 +1832,7 @@ interface BehaviorDiff {
|
|
|
2072
1832
|
* Classify a single scenario's status transition between two runs.
|
|
2073
1833
|
* Shares the `ScenarioChangeKind` vocabulary with the full compare engine.
|
|
2074
1834
|
*/
|
|
2075
|
-
declare function classifyStatusChange(baseline: TestStatus | undefined, current: TestStatus | undefined): ScenarioChangeKind;
|
|
1835
|
+
declare function classifyStatusChange(baseline: TestStatus$1 | undefined, current: TestStatus$1 | undefined): ScenarioChangeKind;
|
|
2076
1836
|
/**
|
|
2077
1837
|
* Scenario-level diff of two StoryReports, keyed by scenario id. Reports status
|
|
2078
1838
|
* transitions (the agent triage signal), not the full field-by-field diff that
|
|
@@ -2631,27 +2391,6 @@ declare function clearVersionCache(): void;
|
|
|
2631
2391
|
*/
|
|
2632
2392
|
declare function detectCI(env?: Record<string, string | undefined>): RawCIInfo | undefined;
|
|
2633
2393
|
|
|
2634
|
-
/**
|
|
2635
|
-
* OTel trace context detection.
|
|
2636
|
-
*
|
|
2637
|
-
* Detects an active OpenTelemetry span via `@opentelemetry/api` (optional peer).
|
|
2638
|
-
* Uses `createRequire` so the import is lazy and never breaks if OTel isn't installed.
|
|
2639
|
-
*/
|
|
2640
|
-
interface OtelTraceContext {
|
|
2641
|
-
traceId: string;
|
|
2642
|
-
spanId: string;
|
|
2643
|
-
}
|
|
2644
|
-
/**
|
|
2645
|
-
* Try to read trace context from the currently-active OTel span.
|
|
2646
|
-
* Returns `undefined` when `@opentelemetry/api` is not installed or no span is active.
|
|
2647
|
-
*/
|
|
2648
|
-
declare function tryGetActiveOtelContext(): OtelTraceContext | undefined;
|
|
2649
|
-
/**
|
|
2650
|
-
* Replace `{traceId}` in a URL template.
|
|
2651
|
-
* Returns `undefined` when no template is provided.
|
|
2652
|
-
*/
|
|
2653
|
-
declare function resolveTraceUrl(template: string | undefined, traceId: string): string | undefined;
|
|
2654
|
-
|
|
2655
2394
|
/**
|
|
2656
2395
|
* Notification orchestrator.
|
|
2657
2396
|
*
|
|
@@ -2684,7 +2423,7 @@ interface SendNotificationsDeps {
|
|
|
2684
2423
|
logger: {
|
|
2685
2424
|
warn(msg: string): void;
|
|
2686
2425
|
};
|
|
2687
|
-
toCIInfo: (raw?: RawCIInfo) => CIInfo
|
|
2426
|
+
toCIInfo: (raw?: RawCIInfo) => CIInfo | undefined;
|
|
2688
2427
|
env?: Record<string, string | undefined>;
|
|
2689
2428
|
}
|
|
2690
2429
|
/**
|
|
@@ -2952,13 +2691,13 @@ declare function listScenarios(args: ListScenariosArgs, _deps: ListScenariosDeps
|
|
|
2952
2691
|
interface CheckArgs {
|
|
2953
2692
|
testCases: TestCaseResult[];
|
|
2954
2693
|
/** Baseline scenario statuses keyed by scenario id, for regressed/fixed deltas. */
|
|
2955
|
-
baseline?: Map<string, TestStatus
|
|
2694
|
+
baseline?: Map<string, TestStatus>;
|
|
2956
2695
|
format: "text" | "json";
|
|
2957
2696
|
}
|
|
2958
2697
|
type CheckDeps = Record<string, never>;
|
|
2959
2698
|
/** A single rendered step inside a failing scenario. */
|
|
2960
2699
|
interface CheckStep {
|
|
2961
|
-
keyword: StepKeyword
|
|
2700
|
+
keyword: StepKeyword;
|
|
2962
2701
|
text: string;
|
|
2963
2702
|
/** True when this step is the one that failed. */
|
|
2964
2703
|
failed: boolean;
|
|
@@ -3076,7 +2815,7 @@ interface TriageItem {
|
|
|
3076
2815
|
rank: number;
|
|
3077
2816
|
id: string;
|
|
3078
2817
|
scenario: string;
|
|
3079
|
-
status: TestStatus
|
|
2818
|
+
status: TestStatus;
|
|
3080
2819
|
/** `sourceFile:sourceLine` */
|
|
3081
2820
|
location: string;
|
|
3082
2821
|
/** Product-code paths to fix. Empty when the scenario declared no `covers`. */
|
|
@@ -3098,7 +2837,7 @@ interface TriageReport {
|
|
|
3098
2837
|
interface TriageArgs {
|
|
3099
2838
|
testCases: TestCaseResult[];
|
|
3100
2839
|
/** Baseline statuses by scenario id, to flag regressions and rank them first. */
|
|
3101
|
-
baseline?: Map<string, TestStatus
|
|
2840
|
+
baseline?: Map<string, TestStatus>;
|
|
3102
2841
|
format: "text" | "json";
|
|
3103
2842
|
}
|
|
3104
2843
|
type TriageDeps = Record<string, never>;
|
|
@@ -3439,7 +3178,7 @@ interface TraceabilityRequirement {
|
|
|
3439
3178
|
scenarios: Array<{
|
|
3440
3179
|
id: string;
|
|
3441
3180
|
title: string;
|
|
3442
|
-
status: TestStatus
|
|
3181
|
+
status: TestStatus;
|
|
3443
3182
|
sourceFile: string;
|
|
3444
3183
|
sourceLine: number;
|
|
3445
3184
|
covers: string[];
|
|
@@ -3468,7 +3207,7 @@ interface TraceabilityMatrix {
|
|
|
3468
3207
|
untraced: Array<{
|
|
3469
3208
|
id: string;
|
|
3470
3209
|
title: string;
|
|
3471
|
-
status: TestStatus
|
|
3210
|
+
status: TestStatus;
|
|
3472
3211
|
sourceFile: string;
|
|
3473
3212
|
sourceLine: number;
|
|
3474
3213
|
}>;
|
|
@@ -3616,4 +3355,4 @@ declare function normalizeVitestResults(testModules: Parameters<typeof adaptVite
|
|
|
3616
3355
|
*/
|
|
3617
3356
|
declare function normalizePlaywrightResults(testResults: Parameters<typeof adaptPlaywrightRun>[0], adapterOptions?: Parameters<typeof adaptPlaywrightRun>[1], canonicalizeOptions?: CanonicalizeOptions): TestRunResult;
|
|
3618
3357
|
|
|
3619
|
-
export { AgentTextFormatter, type AnchorResolution, type AnchorState, type AstroAssetResult, AstroFormatter, type AstroFormatterOptions as AstroFormatterOpts,
|
|
3358
|
+
export { type AdapterDeps, AgentTextFormatter, type AnchorResolution, type AnchorState, type AstroAssetResult, AstroFormatter, type AstroFormatterOptions as AstroFormatterOpts, type AttachPolicy, type BehaviorDebuggerIssue, type BehaviorDiff, type BehaviorDiffEntry, type BehaviorManifest, BehaviorManifestJsonFormatter, type BehaviorManifestJsonOptions, type BehaviorSourceFile, type BehaviorTag, type BundleOptions, type BundleResult, type CaseBody, type CaseResult, type ChangeType, type ChangedFile, type ChangedFileReview, type CheckArgs, type CheckDeps, type CheckFailure, type CheckReport, type CheckStep, type CodeDiffAnnotation, type CodeDiffAnnotationInput, type CodeDiffEvidence, type CodeDiffInput, type CodeDiffScenarioRef, type CodeDiffSidecar, type CodeDiffSidecarAnnotation, type ColocatedStyle, type CompareFormat, type CompareFormatterOptions, type ConfluenceAuth, ConfluenceFormatter, type ConfluenceFormatterOptions as ConfluenceFormatterOpts, type CopyMarkdownAssetsOptions, type CoverageClass, type CoverageJson, CucumberHtmlFormatter, type CucumberHtmlOptions, CucumberJsonFormatter, type CucumberJsonOptions, CucumberMessagesFormatter, type CucumberMessagesOptions, DEFAULT_LOCKFILE_PATH, type DeploymentEntry, type DeploymentLedger, type DeploymentStatus, type DiffAnchor, type DiffHunk, type DiffLine, type DiffRunsOptions, type EnvironmentDrift, type EvidenceStrength, type ExecutableStoriesConfig, type FetchFn, type FileChangeKind, type FileDiff, type FlakinessLevel, type Formatter, type FormatterOptions, type GenerateArgs, type GenerateCompareResult, type GenerateDeps, type GenerateResult, type GenericWebhookNotifierOptions, type GoalArgs, type GoalDeps, type GoalReport, type GoalRequirementResult, type HistoryEntry, type HistoryStore, type IJsonDataTable, type IJsonDocString, type IJsonEmbedding, type IJsonFeature, type IJsonScenario, type IJsonStep, type IJsonStepArgument, type IJsonStepResult, type IJsonTableRow, type IJsonTag, JUnitFormatter, type JUnitOptions, type JiraAuth, type JiraPublishMode, type ListScenariosArgs, type ListScenariosDeps, type LockEntry, type Lockfile, type Logger, MIN_FLAKINESS_SAMPLES, MIN_METRIC_SAMPLES, MIN_PERF_SAMPLES, MarkdownFormatter, type MarkdownFormatterOptions, type MarkdownOptions, type MarkdownRenderers, type NotificationSummary, type NotifyCondition, type OutputConfig, type OutputFormat, type OutputMode, type OutputRule, PROVIDER_NAMES, type PerformanceTrend, type ProviderName, type PublishConfluenceArgs, type PublishConfluenceDeps, type PublishConfluenceResult, type PublishJiraArgs, type PublishJiraDeps, type PublishJiraResult, type RatchetViolation, type RecordDeploymentArgs, type RecordDeploymentResult, type RecordResultsSummary, type ReleaseManifest, ReleaseManifestFormatter, type RemoteCase, ReportGenerator, type ResolvedFormatterOptions, type ResultAttachment, type ReviewAudience, type ReviewBand, type ReviewClaim, type ReviewContext, ReviewHtmlFormatter, type ReviewHtmlOptions, ReviewMarkdownFormatter, type ReviewMarkdownOptions, type ReviewResult, type ReviewSummary, RunDiffChangelogFormatter, type RunDiffChangelogOptions, RunDiffHtmlFormatter, type RunDiffHtmlOptions, RunDiffMarkdownFormatter, type RunDiffMarkdownOptions, type RunDiffResult, type RunDiffSummary, type ScenarioChangeFlags, type ScenarioChangeKind, type ScenarioDiff, type ScenarioIndex, type ScenarioIndexFilters, type ScenarioIndexItem, ScenarioIndexJsonFormatter, type ScenarioIndexJsonOptions, type ScenarioIndexStep, type ScenarioSnapshot, type SortTestCasesMode, type StabilityGrade, type StarlightBadge, StoryReportJsonFormatter, type StoryReportJsonOptions, type SyncAnalysis, type SyncApplyResult, type SyncEngineConfig, type SyncProvider, type SyncTargets, type TestHistory, type TestMetrics, type TestRailConfig, TraceabilityCsvFormatter, type TraceabilityMatrix, TraceabilityMatrixFormatter, type TraceabilityRequirement, type TriageArgs, type TriageDeps, type TriageItem, type TriageReport, type WatchDeps, type WatchHandle, type WatchOptions, type WebhookPayload, type WebhookSignerHmac, type WriteFile, type XrayConfig, adaptJestRun, adaptPlaywrightRun, adaptVitestRun, analyzeSync, applySync, assembleCodeDiff, buildCheck, buildCoverageJson, buildGoal, buildProvider, buildReview, buildTriage, bundleAssets, calculateFlakiness, calculateStability, classifyStatusChange, clearVersionCache, codeDiffDiagnostics, collectAttachments, computeTestMetrics, copyMarkdownAssets, createAnchor, createPrCommentSummary, createReportGenerator, createTestRailProvider, createXrayProvider, deriveAudience, deriveChangeType, detectCI, detectPerformanceTrend, diffRuns, diffStoryReports, emptyLockfile, findGitDir, generateRunComparison, getDeploymentStatus, getEnvironmentDrift, gradeEvidence, hasSufficientHistory, hashCaseBody, isProviderName, isReviewableSource, isTestFile, joinNameAndExt, listScenarios, loadHistory, normalizeFormats, normalizeJestResults, normalizePlaywrightResults, normalizeVitestResults, parseLockfile, parseUnifiedDiff, projectBehaviours, publishConfluencePage, publishJiraIssue, readBranchName, readGitSha, readLockfile, readPackageVersion, recordDeployment, regenerateArtifacts, regenerateRun, relocateAnchor, renderApplyResult, renderCheck, renderCoverageMarkdown, renderCoverageText, renderGoal, renderPlan, renderTriage, rewriteAssetPaths, saveHistory, scenariosCoveringPaths, sendNotifications, sendSlackNotification, sendTeamsNotification, sendWebhookNotification, serializeLockfile, signBody, startWatch, stripAnsi, toAgentText, toBehaviorManifest, toCaseBody, toReleaseManifest, toScenarioIndex, toTraceabilityMatrix, updateHistory, writeLockfile };
|