@vostride/agent-qa-web 0.1.20 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,37 +1,133 @@
1
1
  import { Page, LaunchOptions, BrowserContextOptions, Locator } from 'playwright-core';
2
- import { PlatformAdapter, PlatformConfig, ObserveOptions, ScreenState, Action, ActionResult, ConsoleLogEntry, NetworkLogEntry, ElementInfo, AccessibilityViolation } from '@vostride/agent-qa-core';
2
+ import { PlatformAdapter, OperationCaptureSupport, PlatformConfig, LiveStreamCapability, RecordingCapability, ObserveOptions, ActionsFor, ExecuteOptions, ActionResult, ConsoleLogEntry, NetworkLogEntry, InterimNode, Action, AccessibilityViolation } from '@vostride/agent-qa-runner';
3
+ import { ScreenState } from '@vostride/agent-qa-schema';
3
4
 
4
- declare class WebPlatformAdapter implements PlatformAdapter {
5
+ interface WebPlatformAdapterOptions {
6
+ readonly hostOwnsSignals?: true;
7
+ }
8
+ declare class WebPlatformAdapter implements PlatformAdapter<'web'> {
9
+ private readonly options;
5
10
  readonly platform: "web";
11
+ constructor(options?: WebPlatformAdapterOptions);
6
12
  private browser;
7
13
  private context;
8
14
  private page;
9
15
  private lastRefs;
16
+ private epoch;
10
17
  private pageLogBuffers;
11
18
  private logCaptureConfig;
12
19
  private disconnected;
13
20
  private intentionalClose;
21
+ private armedRoutes;
22
+ private pendingDialogArm;
23
+ private browserName;
24
+ private screencast;
25
+ private screencastCapability;
26
+ private recordingCapability;
27
+ private recordingPageRevision;
28
+ private recordingConfig;
29
+ private screencastFrameSeq;
30
+ private screencastAckTokens;
31
+ private screencastOnFrame;
32
+ private keepaliveTimer;
33
+ private lastScreencastSize;
34
+ private keepaliveEchoDeadline;
35
+ private screencastChain;
36
+ private withdrawnSnapshot;
37
+ private screencastRecoveryTimer;
38
+ private operationCapture;
39
+ operationCaptureSupport: OperationCaptureSupport | undefined;
14
40
  setup(config: PlatformConfig): Promise<void>;
41
+ /**
42
+ * 403 D-05/LIVE-01: the Chromium screencast producer, or ABSENT when this adapter cannot stream.
43
+ *
44
+ * Absence means "no continuous stream", not "no preview": since 428-05 the composition's
45
+ * `liveStreamFor` wraps this adapter's `screenshot()` in the labelled 1 s snapshot producer, both
46
+ * as the fallback behind a screencast that fails to start and as the whole preview on a
47
+ * non-Chromium target. The two gates here (Chromium only, and a page to stream) stay exactly as
48
+ * they are, so the absence stays honest.
49
+ *
50
+ * SCOPE (428 D-18, closes WIN #273): the screencast shows the page the test is acting on. Both
51
+ * page-switch sites (`tab new`, `tab switch`) go through `setActivePage`, which re-binds the
52
+ * running screencast to the new page INSIDE this same capability object: no stop, no re-register,
53
+ * no stream end, so a subscriber only sees the picture change. Start, stop and re-bind run on one
54
+ * serialised chain. A popup or a closing tab never changes `this.page` in this adapter, so the
55
+ * preview already shows the acting page in those cases.
56
+ */
57
+ get liveStream(): LiveStreamCapability | undefined;
58
+ /** Run `step` after every earlier start, stop and re-bind has settled (428 D-18). */
59
+ private onScreencastChain;
60
+ /** Stop and detach the current CDP session, best-effort, and forget its tokens and keepalive. */
61
+ private detachScreencast;
62
+ /** Wire `cdp`'s screencast frames to `onFrame`; shared by `start` and `rebindScreencast`. */
63
+ private attachScreencast;
64
+ /**
65
+ * The one place the page the test acts on changes (428 D-18). Recording keeps following its
66
+ * starting page through the revision counter (424 reconciliation 25(d)); the live screencast,
67
+ * when running, re-binds to the new page on the serialised chain.
68
+ */
69
+ private setActivePage;
70
+ /**
71
+ * Move the running screencast onto `this.page` without its subscribers noticing: the old session
72
+ * is stopped and detached, a new one is started with the stored `onFrame`, and the id sequence
73
+ * continues. Ids still pending in the hub settle through its ack bound and are dropped here as
74
+ * unknown. Best-effort throughout; it never throws into a step.
75
+ */
76
+ private rebindScreencast;
77
+ /**
78
+ * 428 D-12's second half: the screencast was withdrawn while the browser is still up (its CDP
79
+ * session detached or unusable), which only this capability can see. Detected when a keepalive
80
+ * capture or a re-bind's start rejects on the active session; the capability then serves the
81
+ * labelled 1 s snapshot preview of the current page through the same `onFrame`, until `stop()`,
82
+ * `cleanup()` or a successful re-bind. The declared kind stays `cdp-screencast`; the frames carry
83
+ * `kind: 'snapshot'`, which is what labels the preview. Runs on the serialised chain.
84
+ */
85
+ private handleScreencastWithdrawn;
86
+ /** While the snapshot fallback runs, try the screencast again every SCREENCAST_RECOVERY_MS (428 WR-08). */
87
+ private armScreencastRecovery;
88
+ private clearScreencastRecovery;
89
+ private browserIsLive;
90
+ private stopWithdrawnSnapshot;
91
+ private clearKeepalive;
92
+ /** (Re-)arm the quiet-page keepalive for `cdp`; every screencast frame pushes it back. */
93
+ private armKeepalive;
94
+ /**
95
+ * 428 D-15: a fresh capture on the same CDP session, emitted as a frame with no ack token (the ack
96
+ * path drops ids it never minted a token for). A capture that rejects emits nothing. While the
97
+ * capability is started under a live browser, a session that then fails a trivial probe too is a
98
+ * withdrawn screencast (D-12, see `handleScreencastWithdrawn`); one that still answers only had a
99
+ * bad moment, such as a cross-process navigation, and re-arms (428 WR-08). One that never settles
100
+ * emits nothing and arms nothing, which is the honest amber.
101
+ */
102
+ private fireKeepalive;
103
+ /** Whether `cdp` still answers a command that cannot fail on a usable session. */
104
+ private sessionAnswers;
105
+ get recording(): RecordingCapability | undefined;
15
106
  cleanup(): Promise<void>;
16
107
  get isBrowserDisconnected(): boolean;
17
108
  observe(options?: ObserveOptions): Promise<ScreenState>;
18
- execute(action: Action): Promise<ActionResult>;
109
+ private observeDocument;
110
+ execute(action: ActionsFor<'web'>, options?: ExecuteOptions): Promise<ActionResult>;
111
+ private executeWithErrorResult;
19
112
  screenshot(): Promise<Buffer | undefined>;
20
113
  getPage(): Page | null;
21
- getVideoPath(): Promise<string | null>;
22
114
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
23
115
  drainNetworkLogs(urlPattern?: string): NetworkLogEntry[];
116
+ /** 439 D-04: a completed download's bytes held in memory, by its sha256. */
117
+ readDownloadBytes(sha256: string): Uint8Array | undefined;
118
+ peekNetworkLogs(urlPattern?: string): NetworkLogEntry[];
24
119
  private attachLogListeners;
25
120
  private resolveTabTargetAsync;
26
121
  private executeAction;
27
122
  }
28
123
 
29
- declare class FarmWebAdapter implements PlatformAdapter {
124
+ declare class FarmWebAdapter implements PlatformAdapter<'web'> {
30
125
  readonly platform: "web";
31
126
  private browser;
32
127
  private context;
33
128
  private page;
34
129
  private lastRefs;
130
+ private epoch;
35
131
  private sessionUrl;
36
132
  private sessionId;
37
133
  private testFailed;
@@ -39,27 +135,59 @@ declare class FarmWebAdapter implements PlatformAdapter {
39
135
  private credentials;
40
136
  private pageLogBuffers;
41
137
  private logCaptureConfig;
138
+ private armedRoutes;
139
+ private pendingDialogArm;
140
+ private recordingCapability;
141
+ private recordingConfig;
42
142
  setup(config: PlatformConfig): Promise<void>;
143
+ get recording(): RecordingCapability | undefined;
43
144
  cleanup(): Promise<void>;
44
145
  observe(options?: ObserveOptions): Promise<ScreenState>;
45
- execute(action: Action): Promise<ActionResult>;
146
+ private observeDocument;
147
+ execute(action: ActionsFor<'web'>): Promise<ActionResult>;
46
148
  screenshot(): Promise<Buffer | undefined>;
47
149
  getPage(): Page | null;
48
- getVideoPath(): Promise<string | null>;
49
150
  markFailed(): void;
50
151
  getSessionUrl(): string | undefined;
51
152
  getSessionId(): string | undefined;
52
153
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
53
154
  drainNetworkLogs(urlPattern?: string): NetworkLogEntry[];
155
+ peekNetworkLogs(urlPattern?: string): NetworkLogEntry[];
54
156
  private attachLogListeners;
55
157
  private resolveTabTargetAsync;
56
158
  private executeAction;
57
159
  }
58
160
 
161
+ /**
162
+ * Parse a Playwright ARIA snapshot into platform-neutral runner interim nodes.
163
+ *
164
+ * Emits nodes in document order with role/name/attributes and a `parentIndex`
165
+ * derived from indentation depth: the nearest kept entry among the line's true
166
+ * ancestors; a dropped line still bounds its subtree (438 gap round, CR-02). A line
167
+ * whose role is not kept never becomes a node: its quoted name and inline text fold
168
+ * into the nearest kept entry among the line's true ancestors (438 D-02, the row
169
+ * text), and a kept content line's own inline text becomes its `text`. Playwright
170
+ * ai-mode `[ref=eN]` annotations are captured into an index-aligned `nativeRefs`
171
+ * array (adapter-private native handles) and are never written into the node. Accepts both ai-mode (annotated) and default-mode
172
+ * (unannotated) snapshot text.
173
+ *
174
+ * No ref minting and no tree rendering happen here — the shared runner builder
175
+ * owns both (D-01/D-02/D-03).
176
+ */
177
+ declare function parseAriaSnapshot(ariaTree: string): {
178
+ nodes: InterimNode[];
179
+ nativeRefs: (string | undefined)[];
180
+ };
181
+ declare function observePage(page: Page, options?: {
182
+ filterSelector?: string;
183
+ extractDom?: boolean;
184
+ }): Promise<ScreenState>;
185
+
59
186
  type RefMap = Record<string, {
187
+ nativeRef: string;
60
188
  role: string;
61
- name?: string;
62
- nth?: number;
189
+ name: string;
190
+ rowText?: string;
63
191
  bounds?: {
64
192
  x: number;
65
193
  y: number;
@@ -78,16 +206,7 @@ interface SnapshotResult {
78
206
  elementCount: number;
79
207
  }
80
208
 
81
- declare function parseAriaSnapshot(ariaTree: string): {
82
- tree: string;
83
- elements: ElementInfo[];
84
- refs: RefMap;
85
- };
86
- declare function observePage(page: Page, options?: {
87
- filterSelector?: string;
88
- extractDom?: boolean;
89
- }): Promise<ScreenState>;
90
-
209
+ /** Resolves a ref to the aria-ref locator of the element observed under it; never by position. */
91
210
  declare class ElementResolver {
92
211
  private page;
93
212
  private refs;
@@ -113,7 +232,7 @@ declare class ActionValidationError extends Error {
113
232
  readonly suggestion?: string;
114
233
  constructor(message: string, suggestion?: string);
115
234
  }
116
- declare function validateAction(action: Action, elementRole: string | undefined): ValidationResult;
235
+ declare function validateAction(action: ActionsFor<'web'>, elementRole: string | undefined): ValidationResult;
117
236
 
118
237
  interface SmartWaitOptions {
119
238
  timeout?: number;
package/dist/index.d.ts CHANGED
@@ -1,37 +1,133 @@
1
1
  import { Page, LaunchOptions, BrowserContextOptions, Locator } from 'playwright-core';
2
- import { PlatformAdapter, PlatformConfig, ObserveOptions, ScreenState, Action, ActionResult, ConsoleLogEntry, NetworkLogEntry, ElementInfo, AccessibilityViolation } from '@vostride/agent-qa-core';
2
+ import { PlatformAdapter, OperationCaptureSupport, PlatformConfig, LiveStreamCapability, RecordingCapability, ObserveOptions, ActionsFor, ExecuteOptions, ActionResult, ConsoleLogEntry, NetworkLogEntry, InterimNode, Action, AccessibilityViolation } from '@vostride/agent-qa-runner';
3
+ import { ScreenState } from '@vostride/agent-qa-schema';
3
4
 
4
- declare class WebPlatformAdapter implements PlatformAdapter {
5
+ interface WebPlatformAdapterOptions {
6
+ readonly hostOwnsSignals?: true;
7
+ }
8
+ declare class WebPlatformAdapter implements PlatformAdapter<'web'> {
9
+ private readonly options;
5
10
  readonly platform: "web";
11
+ constructor(options?: WebPlatformAdapterOptions);
6
12
  private browser;
7
13
  private context;
8
14
  private page;
9
15
  private lastRefs;
16
+ private epoch;
10
17
  private pageLogBuffers;
11
18
  private logCaptureConfig;
12
19
  private disconnected;
13
20
  private intentionalClose;
21
+ private armedRoutes;
22
+ private pendingDialogArm;
23
+ private browserName;
24
+ private screencast;
25
+ private screencastCapability;
26
+ private recordingCapability;
27
+ private recordingPageRevision;
28
+ private recordingConfig;
29
+ private screencastFrameSeq;
30
+ private screencastAckTokens;
31
+ private screencastOnFrame;
32
+ private keepaliveTimer;
33
+ private lastScreencastSize;
34
+ private keepaliveEchoDeadline;
35
+ private screencastChain;
36
+ private withdrawnSnapshot;
37
+ private screencastRecoveryTimer;
38
+ private operationCapture;
39
+ operationCaptureSupport: OperationCaptureSupport | undefined;
14
40
  setup(config: PlatformConfig): Promise<void>;
41
+ /**
42
+ * 403 D-05/LIVE-01: the Chromium screencast producer, or ABSENT when this adapter cannot stream.
43
+ *
44
+ * Absence means "no continuous stream", not "no preview": since 428-05 the composition's
45
+ * `liveStreamFor` wraps this adapter's `screenshot()` in the labelled 1 s snapshot producer, both
46
+ * as the fallback behind a screencast that fails to start and as the whole preview on a
47
+ * non-Chromium target. The two gates here (Chromium only, and a page to stream) stay exactly as
48
+ * they are, so the absence stays honest.
49
+ *
50
+ * SCOPE (428 D-18, closes WIN #273): the screencast shows the page the test is acting on. Both
51
+ * page-switch sites (`tab new`, `tab switch`) go through `setActivePage`, which re-binds the
52
+ * running screencast to the new page INSIDE this same capability object: no stop, no re-register,
53
+ * no stream end, so a subscriber only sees the picture change. Start, stop and re-bind run on one
54
+ * serialised chain. A popup or a closing tab never changes `this.page` in this adapter, so the
55
+ * preview already shows the acting page in those cases.
56
+ */
57
+ get liveStream(): LiveStreamCapability | undefined;
58
+ /** Run `step` after every earlier start, stop and re-bind has settled (428 D-18). */
59
+ private onScreencastChain;
60
+ /** Stop and detach the current CDP session, best-effort, and forget its tokens and keepalive. */
61
+ private detachScreencast;
62
+ /** Wire `cdp`'s screencast frames to `onFrame`; shared by `start` and `rebindScreencast`. */
63
+ private attachScreencast;
64
+ /**
65
+ * The one place the page the test acts on changes (428 D-18). Recording keeps following its
66
+ * starting page through the revision counter (424 reconciliation 25(d)); the live screencast,
67
+ * when running, re-binds to the new page on the serialised chain.
68
+ */
69
+ private setActivePage;
70
+ /**
71
+ * Move the running screencast onto `this.page` without its subscribers noticing: the old session
72
+ * is stopped and detached, a new one is started with the stored `onFrame`, and the id sequence
73
+ * continues. Ids still pending in the hub settle through its ack bound and are dropped here as
74
+ * unknown. Best-effort throughout; it never throws into a step.
75
+ */
76
+ private rebindScreencast;
77
+ /**
78
+ * 428 D-12's second half: the screencast was withdrawn while the browser is still up (its CDP
79
+ * session detached or unusable), which only this capability can see. Detected when a keepalive
80
+ * capture or a re-bind's start rejects on the active session; the capability then serves the
81
+ * labelled 1 s snapshot preview of the current page through the same `onFrame`, until `stop()`,
82
+ * `cleanup()` or a successful re-bind. The declared kind stays `cdp-screencast`; the frames carry
83
+ * `kind: 'snapshot'`, which is what labels the preview. Runs on the serialised chain.
84
+ */
85
+ private handleScreencastWithdrawn;
86
+ /** While the snapshot fallback runs, try the screencast again every SCREENCAST_RECOVERY_MS (428 WR-08). */
87
+ private armScreencastRecovery;
88
+ private clearScreencastRecovery;
89
+ private browserIsLive;
90
+ private stopWithdrawnSnapshot;
91
+ private clearKeepalive;
92
+ /** (Re-)arm the quiet-page keepalive for `cdp`; every screencast frame pushes it back. */
93
+ private armKeepalive;
94
+ /**
95
+ * 428 D-15: a fresh capture on the same CDP session, emitted as a frame with no ack token (the ack
96
+ * path drops ids it never minted a token for). A capture that rejects emits nothing. While the
97
+ * capability is started under a live browser, a session that then fails a trivial probe too is a
98
+ * withdrawn screencast (D-12, see `handleScreencastWithdrawn`); one that still answers only had a
99
+ * bad moment, such as a cross-process navigation, and re-arms (428 WR-08). One that never settles
100
+ * emits nothing and arms nothing, which is the honest amber.
101
+ */
102
+ private fireKeepalive;
103
+ /** Whether `cdp` still answers a command that cannot fail on a usable session. */
104
+ private sessionAnswers;
105
+ get recording(): RecordingCapability | undefined;
15
106
  cleanup(): Promise<void>;
16
107
  get isBrowserDisconnected(): boolean;
17
108
  observe(options?: ObserveOptions): Promise<ScreenState>;
18
- execute(action: Action): Promise<ActionResult>;
109
+ private observeDocument;
110
+ execute(action: ActionsFor<'web'>, options?: ExecuteOptions): Promise<ActionResult>;
111
+ private executeWithErrorResult;
19
112
  screenshot(): Promise<Buffer | undefined>;
20
113
  getPage(): Page | null;
21
- getVideoPath(): Promise<string | null>;
22
114
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
23
115
  drainNetworkLogs(urlPattern?: string): NetworkLogEntry[];
116
+ /** 439 D-04: a completed download's bytes held in memory, by its sha256. */
117
+ readDownloadBytes(sha256: string): Uint8Array | undefined;
118
+ peekNetworkLogs(urlPattern?: string): NetworkLogEntry[];
24
119
  private attachLogListeners;
25
120
  private resolveTabTargetAsync;
26
121
  private executeAction;
27
122
  }
28
123
 
29
- declare class FarmWebAdapter implements PlatformAdapter {
124
+ declare class FarmWebAdapter implements PlatformAdapter<'web'> {
30
125
  readonly platform: "web";
31
126
  private browser;
32
127
  private context;
33
128
  private page;
34
129
  private lastRefs;
130
+ private epoch;
35
131
  private sessionUrl;
36
132
  private sessionId;
37
133
  private testFailed;
@@ -39,27 +135,59 @@ declare class FarmWebAdapter implements PlatformAdapter {
39
135
  private credentials;
40
136
  private pageLogBuffers;
41
137
  private logCaptureConfig;
138
+ private armedRoutes;
139
+ private pendingDialogArm;
140
+ private recordingCapability;
141
+ private recordingConfig;
42
142
  setup(config: PlatformConfig): Promise<void>;
143
+ get recording(): RecordingCapability | undefined;
43
144
  cleanup(): Promise<void>;
44
145
  observe(options?: ObserveOptions): Promise<ScreenState>;
45
- execute(action: Action): Promise<ActionResult>;
146
+ private observeDocument;
147
+ execute(action: ActionsFor<'web'>): Promise<ActionResult>;
46
148
  screenshot(): Promise<Buffer | undefined>;
47
149
  getPage(): Page | null;
48
- getVideoPath(): Promise<string | null>;
49
150
  markFailed(): void;
50
151
  getSessionUrl(): string | undefined;
51
152
  getSessionId(): string | undefined;
52
153
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
53
154
  drainNetworkLogs(urlPattern?: string): NetworkLogEntry[];
155
+ peekNetworkLogs(urlPattern?: string): NetworkLogEntry[];
54
156
  private attachLogListeners;
55
157
  private resolveTabTargetAsync;
56
158
  private executeAction;
57
159
  }
58
160
 
161
+ /**
162
+ * Parse a Playwright ARIA snapshot into platform-neutral runner interim nodes.
163
+ *
164
+ * Emits nodes in document order with role/name/attributes and a `parentIndex`
165
+ * derived from indentation depth: the nearest kept entry among the line's true
166
+ * ancestors; a dropped line still bounds its subtree (438 gap round, CR-02). A line
167
+ * whose role is not kept never becomes a node: its quoted name and inline text fold
168
+ * into the nearest kept entry among the line's true ancestors (438 D-02, the row
169
+ * text), and a kept content line's own inline text becomes its `text`. Playwright
170
+ * ai-mode `[ref=eN]` annotations are captured into an index-aligned `nativeRefs`
171
+ * array (adapter-private native handles) and are never written into the node. Accepts both ai-mode (annotated) and default-mode
172
+ * (unannotated) snapshot text.
173
+ *
174
+ * No ref minting and no tree rendering happen here — the shared runner builder
175
+ * owns both (D-01/D-02/D-03).
176
+ */
177
+ declare function parseAriaSnapshot(ariaTree: string): {
178
+ nodes: InterimNode[];
179
+ nativeRefs: (string | undefined)[];
180
+ };
181
+ declare function observePage(page: Page, options?: {
182
+ filterSelector?: string;
183
+ extractDom?: boolean;
184
+ }): Promise<ScreenState>;
185
+
59
186
  type RefMap = Record<string, {
187
+ nativeRef: string;
60
188
  role: string;
61
- name?: string;
62
- nth?: number;
189
+ name: string;
190
+ rowText?: string;
63
191
  bounds?: {
64
192
  x: number;
65
193
  y: number;
@@ -78,16 +206,7 @@ interface SnapshotResult {
78
206
  elementCount: number;
79
207
  }
80
208
 
81
- declare function parseAriaSnapshot(ariaTree: string): {
82
- tree: string;
83
- elements: ElementInfo[];
84
- refs: RefMap;
85
- };
86
- declare function observePage(page: Page, options?: {
87
- filterSelector?: string;
88
- extractDom?: boolean;
89
- }): Promise<ScreenState>;
90
-
209
+ /** Resolves a ref to the aria-ref locator of the element observed under it; never by position. */
91
210
  declare class ElementResolver {
92
211
  private page;
93
212
  private refs;
@@ -113,7 +232,7 @@ declare class ActionValidationError extends Error {
113
232
  readonly suggestion?: string;
114
233
  constructor(message: string, suggestion?: string);
115
234
  }
116
- declare function validateAction(action: Action, elementRole: string | undefined): ValidationResult;
235
+ declare function validateAction(action: ActionsFor<'web'>, elementRole: string | undefined): ValidationResult;
117
236
 
118
237
  interface SmartWaitOptions {
119
238
  timeout?: number;