@kraken-e2e/core 0.1.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.
Files changed (50) hide show
  1. package/LICENSE +674 -0
  2. package/dist/ctk.d.ts +57 -0
  3. package/dist/ctk.d.ts.map +1 -0
  4. package/dist/ctk.js +137 -0
  5. package/dist/ctk.js.map +1 -0
  6. package/dist/event-bus.d.ts +21 -0
  7. package/dist/event-bus.d.ts.map +1 -0
  8. package/dist/event-bus.js +55 -0
  9. package/dist/event-bus.js.map +1 -0
  10. package/dist/event-schemas.d.ts +13 -0
  11. package/dist/event-schemas.d.ts.map +1 -0
  12. package/dist/event-schemas.js +202 -0
  13. package/dist/event-schemas.js.map +1 -0
  14. package/dist/host.d.ts +10 -0
  15. package/dist/host.d.ts.map +1 -0
  16. package/dist/host.js +23 -0
  17. package/dist/host.js.map +1 -0
  18. package/dist/index.d.ts +19 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +19 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/logger.d.ts +16 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +13 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/registry.d.ts +50 -0
  27. package/dist/registry.d.ts.map +1 -0
  28. package/dist/registry.js +244 -0
  29. package/dist/registry.js.map +1 -0
  30. package/dist/runner.d.ts +60 -0
  31. package/dist/runner.d.ts.map +1 -0
  32. package/dist/runner.js +363 -0
  33. package/dist/runner.js.map +1 -0
  34. package/dist/scenario.d.ts +25 -0
  35. package/dist/scenario.d.ts.map +1 -0
  36. package/dist/scenario.js +85 -0
  37. package/dist/scenario.js.map +1 -0
  38. package/dist/scheduler.d.ts +87 -0
  39. package/dist/scheduler.d.ts.map +1 -0
  40. package/dist/scheduler.js +190 -0
  41. package/dist/scheduler.js.map +1 -0
  42. package/dist/testing/fake-driver.d.ts +54 -0
  43. package/dist/testing/fake-driver.d.ts.map +1 -0
  44. package/dist/testing/fake-driver.js +209 -0
  45. package/dist/testing/fake-driver.js.map +1 -0
  46. package/dist/testing/index.d.ts +2 -0
  47. package/dist/testing/index.d.ts.map +1 -0
  48. package/dist/testing/index.js +2 -0
  49. package/dist/testing/index.js.map +1 -0
  50. package/package.json +53 -0
@@ -0,0 +1,190 @@
1
+ import { KrakenError, serializeError } from '@kraken-e2e/contracts';
2
+ /**
3
+ * Named background tasks (the detach/join escape hatch — ADR-0001 §5.9).
4
+ * An unjoined handle at scenario end fails the scenario (leak detection).
5
+ */
6
+ export class TaskRegistry {
7
+ #tasks = new Map();
8
+ /**
9
+ * Check-then-start: the duplicate-handle check runs BEFORE the task body is
10
+ * invoked, so a rejected registration never leaves an untracked task running
11
+ * (and never produces an unhandled rejection).
12
+ */
13
+ register(handle, start, startedBy) {
14
+ if (this.#tasks.has(handle)) {
15
+ throw new KrakenError('KRK-PLAN-DUPLICATE-TASK', `A background task named "${handle}" is already running.`, { fix: 'Use a distinct handle per detached task within a scenario.' });
16
+ }
17
+ // Track the settlement so an early rejection never becomes an unhandled one.
18
+ const outcome = start().then(() => ({ ok: true }), (error) => ({ ok: false, error }));
19
+ this.#tasks.set(handle, { outcome, startedBy, joined: false });
20
+ }
21
+ async join(handle, timeoutMs) {
22
+ const entry = this.#tasks.get(handle);
23
+ if (!entry) {
24
+ throw new KrakenError('KRK-PLAN-UNKNOWN-TASK', `No background task named "${handle}" was started.`, { fix: 'Start it with a detached step before joining it.' });
25
+ }
26
+ entry.joined = true;
27
+ let timer;
28
+ const timeout = new Promise((resolve) => {
29
+ timer = setTimeout(() => resolve('timeout'), timeoutMs);
30
+ });
31
+ const result = await Promise.race([entry.outcome, timeout]);
32
+ clearTimeout(timer);
33
+ if (result === 'timeout') {
34
+ throw new KrakenError('KRK-PLAN-TASK-JOIN-TIMEOUT', `Background task "${handle}" (started by ${entry.startedBy}) did not complete within ${timeoutMs}ms.`);
35
+ }
36
+ if (!result.ok) {
37
+ throw KrakenError.wrap(result.error, 'KRK-STEP-FAILED', `Background task "${handle}" failed`);
38
+ }
39
+ }
40
+ unjoined() {
41
+ return [...this.#tasks.entries()]
42
+ .filter(([, entry]) => !entry.joined)
43
+ .map(([handle, entry]) => ({ handle, startedBy: entry.startedBy }));
44
+ }
45
+ /**
46
+ * Settle everything (ignoring outcomes) so nothing dangles past the
47
+ * scenario — with a budget: a detached task that ignores the AbortSignal
48
+ * must never hang the run forever. Returns the handles still pending after
49
+ * the budget so the caller can fail the scenario explicitly.
50
+ */
51
+ async drain(timeoutMs) {
52
+ const entries = [...this.#tasks.entries()];
53
+ const settled = new Set();
54
+ await Promise.race([
55
+ Promise.all(entries.map(async ([handle, entry]) => {
56
+ await entry.outcome;
57
+ settled.add(handle);
58
+ })),
59
+ new Promise((resolve) => setTimeout(resolve, timeoutMs)),
60
+ ]);
61
+ return entries.map(([handle]) => handle).filter((handle) => !settled.has(handle));
62
+ }
63
+ }
64
+ /**
65
+ * Executes a ScenarioPlan (ADR-0002 D7). The default shape is a chain, so
66
+ * execution is sequential in text order; `detach` nodes spawn tracked tasks;
67
+ * `join` nodes await them. Failure policy is failFast: the first failure
68
+ * aborts in-flight sibling work via the shared AbortSignal.
69
+ */
70
+ export async function executePlan(plan, deps) {
71
+ const world = {};
72
+ const tasks = new TaskRegistry();
73
+ const { events, abortController } = deps;
74
+ const contextFor = (actorId) => {
75
+ const actor = deps.actors.get(actorId);
76
+ if (!actor) {
77
+ throw new KrakenError('KRK-STEP-UNKNOWN-ACTOR', `Plan node references actor "${actorId}" but no session was booted for it.`);
78
+ }
79
+ return { actor, world, tasks, abort: abortController.signal, actors: deps.actors };
80
+ };
81
+ let failure;
82
+ for (const node of plan.nodes) {
83
+ if (failure)
84
+ break;
85
+ const startedAt = Date.now();
86
+ events.emit({
87
+ type: 'stepStarted',
88
+ scenarioId: plan.scenarioId,
89
+ stepId: node.id,
90
+ actorId: node.actorId,
91
+ text: node.title,
92
+ });
93
+ try {
94
+ if (node.kind === 'detach') {
95
+ const handle = node.taskHandle;
96
+ if (!handle) {
97
+ throw new KrakenError('KRK-PLAN-UNKNOWN-TASK', `Detach node "${node.id}" has no task handle.`);
98
+ }
99
+ // Spawn without awaiting; the step itself passes once the task starts.
100
+ tasks.register(handle, () => node.run(contextFor(node.actorId)), node.title);
101
+ }
102
+ else if (node.kind === 'join') {
103
+ const handle = node.taskHandle;
104
+ if (!handle) {
105
+ throw new KrakenError('KRK-PLAN-UNKNOWN-TASK', `Join node "${node.id}" has no task handle.`);
106
+ }
107
+ if (node.joinTimeoutMs === undefined) {
108
+ // Explicit-duration policy (ADR-0003 D4 / ADR-0004 D6): no silent default.
109
+ throw new KrakenError('KRK-PLAN-UNKNOWN-TASK', `Join node "${node.id}" has no joinTimeoutMs.`);
110
+ }
111
+ await tasks.join(handle, node.joinTimeoutMs);
112
+ }
113
+ else {
114
+ await node.run(contextFor(node.actorId));
115
+ }
116
+ events.emit({
117
+ type: 'stepFinished',
118
+ scenarioId: plan.scenarioId,
119
+ stepId: node.id,
120
+ actorId: node.actorId,
121
+ text: node.title,
122
+ status: 'passed',
123
+ durationMs: Date.now() - startedAt,
124
+ });
125
+ }
126
+ catch (error) {
127
+ failure = { error, nodeId: node.id };
128
+ abortController.abort();
129
+ events.emit({
130
+ type: 'stepFinished',
131
+ scenarioId: plan.scenarioId,
132
+ stepId: node.id,
133
+ actorId: node.actorId,
134
+ text: node.title,
135
+ status: 'failed',
136
+ durationMs: Date.now() - startedAt,
137
+ error: serializeError(error),
138
+ });
139
+ }
140
+ }
141
+ // Skipped steps after a failure are reported so the timeline stays complete.
142
+ if (failure) {
143
+ const failedIndex = plan.nodes.findIndex((node) => node.id === failure?.nodeId);
144
+ for (const node of plan.nodes.slice(failedIndex + 1)) {
145
+ events.emit({
146
+ type: 'stepStarted',
147
+ scenarioId: plan.scenarioId,
148
+ stepId: node.id,
149
+ actorId: node.actorId,
150
+ text: node.title,
151
+ });
152
+ events.emit({
153
+ type: 'stepFinished',
154
+ scenarioId: plan.scenarioId,
155
+ stepId: node.id,
156
+ actorId: node.actorId,
157
+ text: node.title,
158
+ status: 'skipped',
159
+ durationMs: 0,
160
+ });
161
+ }
162
+ }
163
+ const unsettled = await tasks.drain(deps.drainTimeoutMs ?? 5_000);
164
+ if (!failure && unsettled.length > 0) {
165
+ failure = {
166
+ error: new KrakenError('KRK-PLAN-UNJOINED-TASK', `Background task(s) did not settle after the scenario ended (abort ignored?): ${unsettled.join(', ')}.`, { fix: 'Detached task bodies must honor ctx.abort (AbortSignal).' }),
167
+ nodeId: 'scenario-end',
168
+ };
169
+ abortController.abort();
170
+ }
171
+ if (!failure) {
172
+ const leaked = tasks.unjoined();
173
+ if (leaked.length > 0) {
174
+ const description = leaked
175
+ .map((leak) => `"${leak.handle}" (started by ${leak.startedBy})`)
176
+ .join(', ');
177
+ failure = {
178
+ error: new KrakenError('KRK-PLAN-UNJOINED-TASK', `Scenario ended with unjoined background task(s): ${description}.`, {
179
+ fix: 'Join every detached task with a "…background task {handle} completes within…" step.',
180
+ }),
181
+ nodeId: 'scenario-end',
182
+ };
183
+ abortController.abort();
184
+ }
185
+ }
186
+ return failure
187
+ ? { status: 'failed', error: failure.error, failedNodeId: failure.nodeId }
188
+ : { status: 'passed' };
189
+ }
190
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type CoreOperation, type KrakenDriver, type SemanticKey, type TargetLocator } from '@kraken-e2e/contracts';
2
+ export interface FakeElement {
3
+ text: string;
4
+ visible: boolean;
5
+ }
6
+ export interface FakeAction {
7
+ readonly actorId: string;
8
+ readonly op: 'tap' | 'typeText' | 'pressKey' | 'navigate' | 'scrollIntoView';
9
+ readonly target?: TargetLocator;
10
+ readonly text?: string;
11
+ readonly key?: SemanticKey;
12
+ readonly destination?: string;
13
+ }
14
+ /**
15
+ * The shared "app backend": per-actor screens plus latency-simulated effects.
16
+ * Wire app behavior with onAction — e.g. when alice taps "send", set bob's
17
+ * message cell after 120ms.
18
+ */
19
+ export declare class FakeAppWorld {
20
+ #private;
21
+ readonly actions: FakeAction[];
22
+ /** App behavior hook — the "backend logic" of the fake app. */
23
+ onAction: ((action: FakeAction, world: FakeAppWorld) => void) | undefined;
24
+ screen(actorId: string): Map<string, FakeElement>;
25
+ setElement(actorId: string, testId: string, element: FakeElement): this;
26
+ getElement(actorId: string, testId: string): FakeElement | undefined;
27
+ /** Simulates app latency: apply an effect after `ms` (e.g. message delivery). */
28
+ after(ms: number, effect: () => void): void;
29
+ get pendingEffects(): number;
30
+ record(action: FakeAction): void;
31
+ }
32
+ export interface FakeDriverOptions {
33
+ readonly world: FakeAppWorld;
34
+ /** Driver id (default 'fake'). */
35
+ readonly id?: string;
36
+ /** Platforms this fake provides (default ['fake']). */
37
+ readonly platforms?: readonly string[];
38
+ /** Simulate a host-gated driver (the C4b test uses a darwin-only fake). */
39
+ readonly hostRequirements?: {
40
+ readonly platforms?: readonly string[];
41
+ };
42
+ /** Ops to declare unsupported (they throw KRK-SESSION-OP-UNSUPPORTED). */
43
+ readonly unsupported?: readonly CoreOperation[];
44
+ /** Make specific ops fail (orchestrator failure-path tests). */
45
+ readonly failOn?: {
46
+ readonly op: CoreOperation;
47
+ readonly actorId?: string;
48
+ };
49
+ /** Per-op artificial latency in ms. */
50
+ readonly opLatencyMs?: number;
51
+ }
52
+ /** Build a fake driver bound to a shared world. Dogfoods defineDriver(). */
53
+ export declare function createFakeDriver(options: FakeDriverOptions): KrakenDriver<FakeDriverOptions>;
54
+ //# sourceMappingURL=fake-driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-driver.d.ts","sourceRoot":"","sources":["../../src/testing/fake-driver.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,aAAa,EAGlB,KAAK,YAAY,EAGjB,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGnB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,qBAAa,YAAY;;IAEvB,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAM;IAEpC,+DAA+D;IAC/D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAE1E,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC;IASjD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKvE,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIpE,iFAAiF;IACjF,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI;IAW3C,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;CAIjC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IACvE,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAChD,gEAAgE;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC;QAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uCAAuC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAsKD,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAmB5F"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * FakeDriver (ADR-0002 D9): a first-class in-memory driver implementing the
3
+ * full contract, NOT test scaffolding. Per-actor screens plus a SHARED
4
+ * FakeAppWorld let one actor's action change another actor's screen after a
5
+ * configurable latency — so the whole engine (orchestrator, scheduler,
6
+ * signaling, reporting) exercises real cross-actor E2E with zero devices.
7
+ */
8
+ import { writeFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ import { CORE_OPERATIONS, defineDriver, KrakenError, } from '@kraken-e2e/contracts';
11
+ /**
12
+ * The shared "app backend": per-actor screens plus latency-simulated effects.
13
+ * Wire app behavior with onAction — e.g. when alice taps "send", set bob's
14
+ * message cell after 120ms.
15
+ */
16
+ export class FakeAppWorld {
17
+ #screens = new Map();
18
+ actions = [];
19
+ #pendingEffects = 0;
20
+ /** App behavior hook — the "backend logic" of the fake app. */
21
+ onAction;
22
+ screen(actorId) {
23
+ let screen = this.#screens.get(actorId);
24
+ if (!screen) {
25
+ screen = new Map();
26
+ this.#screens.set(actorId, screen);
27
+ }
28
+ return screen;
29
+ }
30
+ setElement(actorId, testId, element) {
31
+ this.screen(actorId).set(testId, { ...element });
32
+ return this;
33
+ }
34
+ getElement(actorId, testId) {
35
+ return this.screen(actorId).get(testId);
36
+ }
37
+ /** Simulates app latency: apply an effect after `ms` (e.g. message delivery). */
38
+ after(ms, effect) {
39
+ this.#pendingEffects += 1;
40
+ setTimeout(() => {
41
+ try {
42
+ effect();
43
+ }
44
+ finally {
45
+ this.#pendingEffects -= 1;
46
+ }
47
+ }, ms);
48
+ }
49
+ get pendingEffects() {
50
+ return this.#pendingEffects;
51
+ }
52
+ record(action) {
53
+ this.actions.push(action);
54
+ this.onAction?.(action, this);
55
+ }
56
+ }
57
+ class FakeSession {
58
+ world;
59
+ options;
60
+ services;
61
+ actorId;
62
+ driverId;
63
+ platform;
64
+ capabilities;
65
+ #disposed = false;
66
+ #screenshotCount = 0;
67
+ constructor(world, options, actor, services) {
68
+ this.world = world;
69
+ this.options = options;
70
+ this.services = services;
71
+ this.actorId = actor.id;
72
+ this.driverId = options.id ?? 'fake';
73
+ this.platform = actor.platform;
74
+ const unsupported = new Set(options.unsupported ?? []);
75
+ this.capabilities = Object.fromEntries(CORE_OPERATIONS.map((op) => [op, unsupported.has(op) ? 'unsupported' : 'supported']));
76
+ }
77
+ async #guard(op) {
78
+ if (this.capabilities[op] === 'unsupported') {
79
+ throw new KrakenError('KRK-SESSION-OP-UNSUPPORTED', `Operation "${op}" is not supported by ${this.driverId} (declared in capabilities).`);
80
+ }
81
+ if (this.options.failOn?.op === op) {
82
+ const { actorId } = this.options.failOn;
83
+ if (actorId === undefined || actorId === this.actorId) {
84
+ throw new KrakenError('KRK-STEP-FAILED', `Injected failure on ${op} for ${this.actorId}.`);
85
+ }
86
+ }
87
+ const latency = this.options.opLatencyMs ?? 0;
88
+ if (latency > 0)
89
+ await new Promise((resolve) => setTimeout(resolve, latency));
90
+ }
91
+ #find(target) {
92
+ const element = this.#lookup(target);
93
+ if (!element) {
94
+ throw new KrakenError('KRK-SESSION-ELEMENT-NOT-FOUND', `Actor "${this.actorId}" has no element matching ${target.by}="${target.value}".`, { data: { target: { ...target } } });
95
+ }
96
+ return element;
97
+ }
98
+ #lookup(target) {
99
+ const screen = this.world.screen(this.actorId);
100
+ if (target.by === 'testId' || target.by === 'a11y' || target.by === 'native') {
101
+ return screen.get(target.value);
102
+ }
103
+ // by text: first element whose text matches
104
+ for (const element of screen.values()) {
105
+ const matches = target.exact
106
+ ? element.text === target.value
107
+ : element.text.includes(target.value);
108
+ if (matches)
109
+ return element;
110
+ }
111
+ return undefined;
112
+ }
113
+ async tap(target) {
114
+ await this.#guard('tap');
115
+ this.#find(target);
116
+ this.world.record({ actorId: this.actorId, op: 'tap', target });
117
+ }
118
+ async typeText(target, text) {
119
+ await this.#guard('typeText');
120
+ const element = this.#find(target);
121
+ element.text = text;
122
+ this.world.record({ actorId: this.actorId, op: 'typeText', target, text });
123
+ }
124
+ async readText(target) {
125
+ await this.#guard('readText');
126
+ return this.#find(target).text;
127
+ }
128
+ async waitFor(target, state, opts) {
129
+ await this.#guard('waitFor');
130
+ const timeoutMs = opts?.timeoutMs ?? 1_000;
131
+ const pollMs = opts?.pollMs ?? 15;
132
+ const startedAt = Date.now();
133
+ for (;;) {
134
+ const element = this.#lookup(target);
135
+ const satisfied = state === 'visible'
136
+ ? element?.visible === true
137
+ : state === 'hidden'
138
+ ? element === undefined || element.visible === false
139
+ : element !== undefined; // 'attached'
140
+ if (satisfied)
141
+ return;
142
+ if (Date.now() - startedAt >= timeoutMs) {
143
+ throw new KrakenError('KRK-SESSION-WAIT-TIMEOUT', `Actor "${this.actorId}" waited ${timeoutMs}ms for ${target.by}="${target.value}" to be ${state}.`);
144
+ }
145
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
146
+ }
147
+ }
148
+ async isDisplayed(target) {
149
+ await this.#guard('isDisplayed');
150
+ return this.#lookup(target)?.visible === true;
151
+ }
152
+ async scrollIntoView(target) {
153
+ await this.#guard('scrollIntoView');
154
+ this.#find(target);
155
+ this.world.record({ actorId: this.actorId, op: 'scrollIntoView', target });
156
+ }
157
+ async pressKey(key) {
158
+ await this.#guard('pressKey');
159
+ this.world.record({ actorId: this.actorId, op: 'pressKey', key });
160
+ }
161
+ async navigate(destination) {
162
+ await this.#guard('navigate');
163
+ this.world.record({ actorId: this.actorId, op: 'navigate', destination });
164
+ }
165
+ async screenshot() {
166
+ await this.#guard('screenshot');
167
+ this.#screenshotCount += 1;
168
+ const path = join(this.services.artifactsDir, `${this.actorId}-screen-${this.#screenshotCount}.txt`);
169
+ writeFileSync(path, await this.source());
170
+ return { kind: 'screenshot', path };
171
+ }
172
+ async source() {
173
+ await this.#guard('source');
174
+ const screen = this.world.screen(this.actorId);
175
+ return JSON.stringify(Object.fromEntries(screen.entries()), null, 2);
176
+ }
177
+ async dispose() {
178
+ // Idempotent by contract.
179
+ this.#disposed = true;
180
+ }
181
+ get disposed() {
182
+ return this.#disposed;
183
+ }
184
+ native(kind) {
185
+ throw new KrakenError('KRK-SESSION-OP-UNSUPPORTED', `FakeDriver has no native session (requested "${String(kind)}").`);
186
+ }
187
+ }
188
+ /** Build a fake driver bound to a shared world. Dogfoods defineDriver(). */
189
+ export function createFakeDriver(options) {
190
+ const factory = defineDriver((opts) => ({
191
+ manifest: {
192
+ id: opts.id ?? 'fake',
193
+ platforms: [...(opts.platforms ?? ['fake'])],
194
+ version: '0.0.0',
195
+ platformLabel: `Fake (${opts.id ?? 'fake'}, in-memory)`,
196
+ ...(opts.hostRequirements !== undefined
197
+ ? {
198
+ hostRequirements: { platforms: opts.hostRequirements.platforms ?? [] },
199
+ disabledFix: 'This fake driver is host-gated for testing purposes.',
200
+ }
201
+ : {}),
202
+ },
203
+ start: async () => { },
204
+ createSession: async (actor, services) => new FakeSession(opts.world, opts, actor, services),
205
+ stop: async () => { },
206
+ }));
207
+ return factory(options);
208
+ }
209
+ //# sourceMappingURL=fake-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-driver.js","sourceRoot":"","sources":["../../src/testing/fake-driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { createFakeDriver, type FakeAction, FakeAppWorld, type FakeDriverOptions, type FakeElement, } from './fake-driver.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createFakeDriver, FakeAppWorld, } from './fake-driver.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAEhB,YAAY,GAGb,MAAM,kBAAkB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@kraken-e2e/core",
3
+ "version": "0.1.0",
4
+ "description": "Orchestrator: session manager, DAG step scheduler, plugin registry, host detection, event bus; exports the driver Conformance Test Kit at @kraken-e2e/core/ctk",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ },
11
+ "./ctk": {
12
+ "types": "./dist/ctk.d.ts",
13
+ "default": "./dist/ctk.js"
14
+ },
15
+ "./testing": {
16
+ "types": "./dist/testing/index.d.ts",
17
+ "default": "./dist/testing/index.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "LICENSE"
24
+ ],
25
+ "sideEffects": false,
26
+ "engines": {
27
+ "node": ">=22.13.0"
28
+ },
29
+ "dependencies": {
30
+ "zod": "^4.0.0",
31
+ "@kraken-e2e/contracts": "0.1.0",
32
+ "@kraken-e2e/signaling": "0.1.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.15.0",
36
+ "typescript": "~6.0.3",
37
+ "vitest": "^4.1.9"
38
+ },
39
+ "peerDependencies": {
40
+ "vitest": "^4.0.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "vitest": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "license": "GPL-3.0-only",
48
+ "scripts": {
49
+ "build": "tsc -p tsconfig.build.json",
50
+ "typecheck": "tsc --noEmit",
51
+ "test": "vitest run"
52
+ }
53
+ }