@reticlehq/browser 3.2.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/actions-dom.d.ts +6 -5
- package/dist/actions/actions-dom.js +5 -4
- package/dist/actions/actions-press.d.ts +3 -3
- package/dist/actions/actions-press.js +0 -3
- package/dist/actions/actions.d.ts +0 -1
- package/dist/actions/actions.js +17 -13
- package/dist/actions/check-state.d.ts +5 -0
- package/dist/actions/check-state.js +24 -0
- package/dist/actions/danger-context.d.ts +3 -2
- package/dist/actions/danger-context.js +2 -1
- package/dist/actions/value-input.d.ts +2 -1
- package/dist/actions/value-input.js +15 -6
- package/dist/connect-options.d.ts +1 -0
- package/dist/dom/a11y.js +43 -3
- package/dist/dom/addressing/source.d.ts +2 -1
- package/dist/dom/dom-ignore.d.ts +1 -0
- package/dist/dom/dom-ignore.js +13 -0
- package/dist/dom/query.js +6 -4
- package/dist/dom/realm.d.ts +6 -0
- package/dist/dom/realm.js +5 -0
- package/dist/dom/snapshot.d.ts +1 -1
- package/dist/dom/snapshot.js +8 -2
- package/dist/observers/console.js +38 -13
- package/dist/observers/dom.js +3 -1
- package/dist/observers/download.js +3 -2
- package/dist/observers/error-repeats.d.ts +18 -0
- package/dist/observers/error-repeats.js +41 -0
- package/dist/observers/field.d.ts +2 -0
- package/dist/observers/field.js +86 -0
- package/dist/observers/frames.js +3 -4
- package/dist/observers/install-all.js +2 -0
- package/dist/observers/net-detail/network-body.d.ts +2 -0
- package/dist/observers/net-detail/network-body.js +24 -7
- package/dist/observers/network.js +14 -1
- package/dist/observers/route.js +4 -4
- package/dist/observers/state.js +21 -8
- package/dist/presenter/carousel/carousel.d.ts +13 -0
- package/dist/presenter/carousel/carousel.js +126 -0
- package/dist/presenter/carousel/offer-card.d.ts +21 -0
- package/dist/presenter/carousel/offer-card.js +55 -0
- package/dist/presenter/carousel/panel-slides.d.ts +7 -0
- package/dist/presenter/carousel/panel-slides.js +10 -0
- package/dist/presenter/carousel/talk-card.d.ts +8 -0
- package/dist/presenter/carousel/talk-card.js +20 -0
- package/dist/presenter/chrome/presenter-log.d.ts +2 -1
- package/dist/presenter/chrome/presenter-log.js +14 -3
- package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -1
- package/dist/presenter/chrome/presenter-report-copy.js +1 -1
- package/dist/presenter/hud-telemetry.d.ts +3 -0
- package/dist/presenter/hud-telemetry.js +87 -0
- package/dist/presenter/presenter-account.js +1 -1
- package/dist/presenter/presenter-config.d.ts +5 -1
- package/dist/presenter/presenter-config.js +4 -1
- package/dist/presenter/presenter-controls.d.ts +1 -0
- package/dist/presenter/presenter-controls.js +12 -1
- package/dist/presenter/presenter-report.js +6 -6
- package/dist/presenter/presenter-settings-styles.js +2 -1
- package/dist/presenter/presenter-settings.d.ts +2 -4
- package/dist/presenter/presenter-settings.js +13 -4
- package/dist/presenter/presenter-shell-styles.js +4 -0
- package/dist/presenter/presenter-shell.d.ts +4 -1
- package/dist/presenter/presenter-shell.js +49 -11
- package/dist/presenter/presenter-styles.js +5 -1
- package/dist/presenter/presenter-workspace.d.ts +0 -7
- package/dist/presenter/presenter-workspace.js +7 -7
- package/dist/presenter/presenter.js +43 -10
- package/dist/presenter/tour/tour.d.ts +3 -0
- package/dist/presenter/tour/tour.js +5 -0
- package/dist/recorder/recorder.js +25 -22
- package/dist/registry/store-adapters.js +32 -2
- package/dist/registry/stores/adapters.js +8 -2
- package/dist/reticle-inject.d.ts +2 -0
- package/dist/reticle-inject.js +1337 -0
- package/dist/reticle.js +6 -0
- package/dist/review/annotator.d.ts +3 -1
- package/dist/review/annotator.js +37 -40
- package/dist/review/marks-for-agent.d.ts +9 -0
- package/dist/review/marks-for-agent.js +12 -0
- package/dist/util/captured-method.d.ts +0 -1
- package/dist/util/captured-method.js +1 -1
- package/package.json +15 -11
- package/dist/presenter/presenter-offer.d.ts +0 -25
- package/dist/presenter/presenter-offer.js +0 -87
|
@@ -14,7 +14,7 @@ const PROJECT_LABEL = 'Project';
|
|
|
14
14
|
const COPY_PATH_LABEL = 'Copy path';
|
|
15
15
|
const COPIED_PATH_LABEL = 'Copied';
|
|
16
16
|
const WORKSPACE_FALLBACK = 'This page';
|
|
17
|
-
|
|
17
|
+
function readWorkspaceRoot() {
|
|
18
18
|
const value = globalThis[RETICLE_ROOT_GLOBAL];
|
|
19
19
|
return 'string' === typeof value && value.length > 0 ? value : undefined;
|
|
20
20
|
}
|
|
@@ -24,13 +24,13 @@ export function workspaceFolderLabel(root) {
|
|
|
24
24
|
const last = parts[parts.length - 1];
|
|
25
25
|
return last !== undefined && last.length > 0 ? last : WORKSPACE_FALLBACK;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
function readProjectIdFromUrl() {
|
|
28
28
|
if ('undefined' === typeof window)
|
|
29
29
|
return undefined;
|
|
30
30
|
const id = new URLSearchParams(window.location.search).get(RETICLE_URL_PARAM.PROJECT);
|
|
31
31
|
return id !== null && id.length > 0 ? id : undefined;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
function workspaceSummary() {
|
|
34
34
|
const root = readWorkspaceRoot();
|
|
35
35
|
const projectId = readProjectIdFromUrl();
|
|
36
36
|
const folder = root !== undefined ? workspaceFolderLabel(root) : WORKSPACE_FALLBACK;
|
|
@@ -106,6 +106,7 @@ export function paintWorkspace(root) {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
export function mountWorkspaceSelector(root) {
|
|
109
|
+
const ac = new AbortController();
|
|
109
110
|
paintWorkspace(root);
|
|
110
111
|
const btn = root.querySelector(`[${WORKSPACE_BTN_ATTR}]`);
|
|
111
112
|
const menu = root.querySelector(`[${WORKSPACE_MENU_ATTR}]`);
|
|
@@ -183,13 +184,12 @@ export function mountWorkspaceSelector(root) {
|
|
|
183
184
|
btn.addEventListener('click', onBtnClick);
|
|
184
185
|
menu.addEventListener('pointerdown', (e) => e.stopPropagation());
|
|
185
186
|
copyBtn?.addEventListener('click', onCopy);
|
|
186
|
-
document.addEventListener('pointerdown', onDocPointer);
|
|
187
|
-
document.addEventListener('keydown', onKeyDown);
|
|
187
|
+
document.addEventListener('pointerdown', onDocPointer, { signal: ac.signal });
|
|
188
|
+
document.addEventListener('keydown', onKeyDown, { signal: ac.signal });
|
|
188
189
|
return () => {
|
|
189
190
|
btn.removeEventListener('click', onBtnClick);
|
|
190
191
|
copyBtn?.removeEventListener('click', onCopy);
|
|
191
|
-
|
|
192
|
-
document.removeEventListener('keydown', onKeyDown);
|
|
192
|
+
ac.abort();
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
export function paintToolbarAccount(root, account, dashboardUrl, details = {}) {
|
|
@@ -3,19 +3,22 @@ import { refs } from '../dom/addressing/refs.js';
|
|
|
3
3
|
import { unreachableStripText } from '../transport/unreachable-message.js';
|
|
4
4
|
import { actionVerb } from './chrome/presenter-verbs.js';
|
|
5
5
|
import { nativeSetTimeout, nativeClearTimeout, nativeNow } from '../timers/native/native-timers.js';
|
|
6
|
-
import { LOG_KIND, CHIP_LABEL, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, } from './chrome/presenter-log.js';
|
|
6
|
+
import { LOG_KIND, CHIP_LABEL, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, clearLogRows, trimLogRows, } from './chrome/presenter-log.js';
|
|
7
7
|
import { PRESENTER_CSS } from './presenter-styles.js';
|
|
8
8
|
import { HudShell } from './presenter-shell.js';
|
|
9
9
|
import { parseImpactSnapshot } from './chrome/presenter-report-copy.js';
|
|
10
|
-
import { BorderMode, DEFAULT_BORDER_MODE, DATA_BUSY, BUSY_OFF, effectivePaceMs, IDLE_AFTER_MS, HEARTBEAT_MS, IDLE_NOTICE_MS, IDLE_END_MS, IDLE_END_MIN_MS, ACT_STRIP, STATE_ATTR, UNREACHABLE_STATE, GLOW_FADE_MS, GLOW_ON, GLOW_OFF, DATA_ON, THROTTLED_ATTR, LIVENESS_ATTR, MARKERS_BTN_ATTR, CLEAR_MARKS_ATTR, MARK_COUNT_ATTR, } from './presenter-config.js';
|
|
10
|
+
import { BorderMode, DEFAULT_BORDER_MODE, DATA_BUSY, BUSY_OFF, effectivePaceMs, IDLE_AFTER_MS, HEARTBEAT_MS, IDLE_NOTICE_MS, IDLE_END_MS, IDLE_END_MIN_MS, ACT_STRIP, STATE_ATTR, UNREACHABLE_STATE, GLOW_FADE_MS, GLOW_ON, GLOW_OFF, DATA_ON, THROTTLED_ATTR, LIVENESS_ATTR, MARKERS_BTN_ATTR, CLEAR_MARKS_ATTR, COPY_MARKS_ATTR, MARKS_ROW_ATTR, MARK_COUNT_ATTR, } from './presenter-config.js';
|
|
11
11
|
import { buildRunState } from './presenter-run-state.js';
|
|
12
12
|
import { moveCursor, ringAround, spawnRipple, pace } from './chrome/presenter-effects.js';
|
|
13
13
|
import { GlowController } from './presenter-glow.js';
|
|
14
14
|
import { PresenterIcon, PRESENTER_ICON_SIZE, hiIcon } from './icons/presenter-icons.js';
|
|
15
15
|
import { renderTally } from './chrome/presenter-tally.js';
|
|
16
|
-
import { CONTROLS_BANNER_HTML, CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
|
|
16
|
+
import { CONTROLS_BANNER_HTML, CONTROLS_FLOWS_HTML, CONTROLS_MARKS_HTML, CONTROLS_FOOT_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
|
|
17
17
|
import { statusTheme, blockerHtml, getPresenterSettings, OutputDetail, syncPageBlocker, } from './presenter-settings.js';
|
|
18
18
|
import { Annotator } from '../review/annotator.js';
|
|
19
|
+
import { shouldAutoOpenChat } from './presenter-shell.js';
|
|
20
|
+
import { installHudTelemetry } from './hud-telemetry.js';
|
|
21
|
+
const COPIED_FLASH_MS = 1600;
|
|
19
22
|
export { GlowPhase } from './presenter-config.js';
|
|
20
23
|
export { LOG_KIND, LOG_RESULT } from './chrome/presenter-log.js';
|
|
21
24
|
export class Presenter {
|
|
@@ -50,6 +53,8 @@ export class Presenter {
|
|
|
50
53
|
#log;
|
|
51
54
|
#logBaseMs;
|
|
52
55
|
#onControl;
|
|
56
|
+
#onHudUse;
|
|
57
|
+
#hudTelemetryTeardown;
|
|
53
58
|
#panel;
|
|
54
59
|
#shell;
|
|
55
60
|
#annotator;
|
|
@@ -70,6 +75,7 @@ export class Presenter {
|
|
|
70
75
|
});
|
|
71
76
|
this.#logMax = clampLogMax(options.logMax);
|
|
72
77
|
this.#onControl = options.onControl;
|
|
78
|
+
this.#onHudUse = options.onHudUse;
|
|
73
79
|
this.#panel = new ControlPanel({
|
|
74
80
|
emit: (kind, text) => this.#onControl?.(text !== undefined ? { kind, text } : { kind }),
|
|
75
81
|
logHuman: (text) => {
|
|
@@ -159,7 +165,7 @@ export class Presenter {
|
|
|
159
165
|
<div data-reticle-glow></div>
|
|
160
166
|
<div data-reticle-cursor></div>
|
|
161
167
|
<div data-reticle-ring></div>
|
|
162
|
-
${HudShell.dockHtml(actStrip, CONTROLS_BANNER_HTML, DATA_RETICLE_LOG, CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML)}`;
|
|
168
|
+
${HudShell.dockHtml(actStrip, CONTROLS_BANNER_HTML, DATA_RETICLE_LOG, CONTROLS_MARKS_HTML + CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML)}`;
|
|
163
169
|
document.body.appendChild(root);
|
|
164
170
|
this.#root = root;
|
|
165
171
|
this.#glow = root.querySelector('[data-reticle-glow]') ?? undefined;
|
|
@@ -179,6 +185,9 @@ export class Presenter {
|
|
|
179
185
|
syncPageBlocker(root, getPresenterSettings(), false);
|
|
180
186
|
this.#glowCtl.setElements(this.#glow, this.#cursor);
|
|
181
187
|
this.#panel.mount(root, this.#glow);
|
|
188
|
+
if (this.#onHudUse !== undefined) {
|
|
189
|
+
this.#hudTelemetryTeardown = installHudTelemetry(document, root, this.#onHudUse);
|
|
190
|
+
}
|
|
182
191
|
this.setMode(this.#mode);
|
|
183
192
|
this.#renderTally();
|
|
184
193
|
}
|
|
@@ -190,7 +199,23 @@ export class Presenter {
|
|
|
190
199
|
const markers = root.querySelector(`[${MARKERS_BTN_ATTR}]`);
|
|
191
200
|
const clear = root.querySelector(`[${CLEAR_MARKS_ATTR}]`);
|
|
192
201
|
const count = root.querySelector(`[${MARK_COUNT_ATTR}]`);
|
|
202
|
+
const copy = root.querySelector(`[${COPY_MARKS_ATTR}]`);
|
|
203
|
+
const row = root.querySelector(`[${MARKS_ROW_ATTR}]`);
|
|
193
204
|
const chrome = {};
|
|
205
|
+
if (row instanceof HTMLElement)
|
|
206
|
+
chrome.copyRow = row;
|
|
207
|
+
let marks = annotator.markCount;
|
|
208
|
+
chrome.onCount = (n) => {
|
|
209
|
+
if (0 === marks && n > 0)
|
|
210
|
+
this.#shell.openChat();
|
|
211
|
+
marks = n;
|
|
212
|
+
};
|
|
213
|
+
if (copy instanceof HTMLElement) {
|
|
214
|
+
copy.addEventListener('click', (e) => {
|
|
215
|
+
e.stopPropagation();
|
|
216
|
+
this.#copyMarks(annotator, copy);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
194
219
|
if (markers instanceof HTMLElement)
|
|
195
220
|
chrome.markersBtn = markers;
|
|
196
221
|
if (clear instanceof HTMLElement)
|
|
@@ -201,6 +226,14 @@ export class Presenter {
|
|
|
201
226
|
annotator.setAccent(statusTheme(getPresenterSettings().statusThemeId).active);
|
|
202
227
|
this.#syncAnnotator();
|
|
203
228
|
}
|
|
229
|
+
#copyMarks(annotator, btn) {
|
|
230
|
+
const text = annotator.agentPrompt(window.location.href);
|
|
231
|
+
void navigator.clipboard?.writeText(text).catch(() => undefined);
|
|
232
|
+
btn.setAttribute('data-copied', '1');
|
|
233
|
+
nativeSetTimeout(() => btn.removeAttribute('data-copied'), COPIED_FLASH_MS);
|
|
234
|
+
if (getPresenterSettings().clearOnCopy)
|
|
235
|
+
annotator.clearAll();
|
|
236
|
+
}
|
|
204
237
|
#syncAnnotator() {
|
|
205
238
|
const live = !this.#shell.isCollapsed() && this.#shell.isAnnotateOn();
|
|
206
239
|
this.#annotator?.toggle(live);
|
|
@@ -213,6 +246,8 @@ export class Presenter {
|
|
|
213
246
|
if (this.#heartbeatTimer !== undefined)
|
|
214
247
|
nativeClearTimeout(this.#heartbeatTimer);
|
|
215
248
|
this.#heartbeatTimer = undefined;
|
|
249
|
+
this.#hudTelemetryTeardown?.();
|
|
250
|
+
this.#hudTelemetryTeardown = undefined;
|
|
216
251
|
this.#shell.teardown();
|
|
217
252
|
this.#panel.teardown();
|
|
218
253
|
this.#sessionActive = false;
|
|
@@ -237,7 +272,7 @@ export class Presenter {
|
|
|
237
272
|
this.#showSession();
|
|
238
273
|
this.#glowCtl.resetActivity(this.#now());
|
|
239
274
|
this.#startHeartbeat();
|
|
240
|
-
if (getPresenterSettings().autoOpenChat) {
|
|
275
|
+
if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat)) {
|
|
241
276
|
this.#shell.openChat();
|
|
242
277
|
}
|
|
243
278
|
}
|
|
@@ -250,7 +285,7 @@ export class Presenter {
|
|
|
250
285
|
this.#hud?.setAttribute(DATA_ON, GLOW_ON);
|
|
251
286
|
this.#lastActionText = unreachableStripText(url, attempts);
|
|
252
287
|
this.#paintActStrip(this.#lastActionText, true);
|
|
253
|
-
if (getPresenterSettings().autoOpenChat)
|
|
288
|
+
if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat))
|
|
254
289
|
this.#shell.openChat();
|
|
255
290
|
}
|
|
256
291
|
#showSession() {
|
|
@@ -413,7 +448,7 @@ export class Presenter {
|
|
|
413
448
|
this.#runLog = [];
|
|
414
449
|
this.#tallied = { passes: 0, fails: 0 };
|
|
415
450
|
if (this.#log !== undefined)
|
|
416
|
-
this.#log
|
|
451
|
+
clearLogRows(this.#log);
|
|
417
452
|
this.#renderTally();
|
|
418
453
|
}
|
|
419
454
|
#applyHideUntilRestart() {
|
|
@@ -477,9 +512,7 @@ export class Presenter {
|
|
|
477
512
|
#pruneLog() {
|
|
478
513
|
if (this.#log === undefined)
|
|
479
514
|
return;
|
|
480
|
-
|
|
481
|
-
this.#log.firstElementChild?.remove();
|
|
482
|
-
}
|
|
515
|
+
trimLogRows(this.#log, this.#logMax);
|
|
483
516
|
}
|
|
484
517
|
setThrottled(throttled) {
|
|
485
518
|
this.#root?.setAttribute(THROTTLED_ATTR, throttled ? '1' : '0');
|
|
@@ -11,6 +11,9 @@ export interface TourDeps {
|
|
|
11
11
|
readonly projectId: string;
|
|
12
12
|
readonly isDriving: () => boolean;
|
|
13
13
|
readonly search?: string;
|
|
14
|
+
readonly navigator?: {
|
|
15
|
+
readonly webdriver?: boolean;
|
|
16
|
+
};
|
|
14
17
|
readonly copy?: (text: string) => Promise<boolean> | boolean;
|
|
15
18
|
readonly select?: (element: Element) => void;
|
|
16
19
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { COPIED_LABEL, COPY_FLASH_MS, COPY_LABEL, COPY_MANUAL_LABEL, TOUR_ATTR, TOUR_CSS, TOUR_PROMPT_ATTR, TOUR_TARGET_ATTR, holeRects, isInteractive, isLastSlide, nextIndex, slideHtml, tourSlides, } from './tour-view.js';
|
|
2
2
|
import { TourAnchor } from '@reticlehq/core/tour';
|
|
3
3
|
import { RETICLE_URL_PARAM } from '@reticlehq/core';
|
|
4
|
+
import { appModalOpen } from '../../dom/dom-ignore.js';
|
|
4
5
|
export const TOUR_SEEN_KEY_PREFIX = 'reticle.tour.seen.';
|
|
5
6
|
const APP_SELECTORS = ['main', '#root', '#app'];
|
|
6
7
|
const HUD_PARTS = ['[data-reticle-hud]', '[data-reticle-chat-panel]'];
|
|
@@ -79,6 +80,8 @@ export function mountTour(deps) {
|
|
|
79
80
|
return undefined;
|
|
80
81
|
if (openedByReticle(deps.search))
|
|
81
82
|
return undefined;
|
|
83
|
+
if (true === deps.navigator?.webdriver)
|
|
84
|
+
return undefined;
|
|
82
85
|
if (tourAlreadySeen(deps.storage, deps.projectId))
|
|
83
86
|
return undefined;
|
|
84
87
|
const doc = deps.document;
|
|
@@ -220,6 +223,8 @@ export function mountTour(deps) {
|
|
|
220
223
|
const onKey = (event) => {
|
|
221
224
|
if (!open)
|
|
222
225
|
return;
|
|
226
|
+
if (appModalOpen(doc))
|
|
227
|
+
return;
|
|
223
228
|
const step = 'ArrowRight' === event.key ? 1 : 'ArrowLeft' === event.key ? -1 : 0;
|
|
224
229
|
if ('Escape' === event.key) {
|
|
225
230
|
event.preventDefault();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionType, AnchorKind, AnnotationKind, DEGRADED_ANCHOR_ROLE, EventType, FLOW_FILE_VERSION, FlowStepTool, RecorderPhase, } from '@reticlehq/core';
|
|
1
|
+
import { ActionType, AnchorKind, AnnotationKind, DEGRADED_ANCHOR_ROLE, EventType, FLOW_FILE_VERSION, FlowStepTool, RecorderPhase, PredicateKind, } from '@reticlehq/core';
|
|
2
2
|
import { REDACTED_VALUE } from '@reticlehq/core';
|
|
3
3
|
import { sourceFromDom } from '../dom/addressing/source.js';
|
|
4
4
|
import { getAccessibleName, getRole, isSensitiveField } from '../dom/a11y.js';
|
|
@@ -83,17 +83,20 @@ export function compileRecording(name, steps, annotations, createdAt, startPath)
|
|
|
83
83
|
}
|
|
84
84
|
if (ann.kind === AnnotationKind.SUCCESS_STATE) {
|
|
85
85
|
if (ann.signal !== undefined)
|
|
86
|
-
success = {
|
|
86
|
+
success = { kind: PredicateKind.SIGNAL, name: ann.signal };
|
|
87
87
|
continue;
|
|
88
88
|
}
|
|
89
89
|
const target = out.at(-1);
|
|
90
90
|
if (target === undefined)
|
|
91
91
|
continue;
|
|
92
92
|
if (ann.kind === AnnotationKind.ASSERT_SIGNAL && ann.signal !== undefined) {
|
|
93
|
-
target.expect =
|
|
93
|
+
target.expect = alsoAssert(target.expect, { kind: PredicateKind.SIGNAL, name: ann.signal });
|
|
94
94
|
}
|
|
95
95
|
else if (ann.kind === AnnotationKind.ASSERT_VISIBLE) {
|
|
96
|
-
target.expect =
|
|
96
|
+
target.expect = alsoAssert(target.expect, {
|
|
97
|
+
kind: PredicateKind.ELEMENT,
|
|
98
|
+
query: anchorToElement(ann.anchor),
|
|
99
|
+
});
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
const flow = { version: FLOW_FILE_VERSION, name, createdAt, steps: out };
|
|
@@ -105,6 +108,14 @@ export function compileRecording(name, steps, annotations, createdAt, startPath)
|
|
|
105
108
|
flow.success = success;
|
|
106
109
|
return flow;
|
|
107
110
|
}
|
|
111
|
+
function alsoAssert(existing, clause) {
|
|
112
|
+
if (existing === undefined)
|
|
113
|
+
return clause;
|
|
114
|
+
if (existing.kind === PredicateKind.ALL_OF) {
|
|
115
|
+
return { kind: PredicateKind.ALL_OF, predicates: [...existing.predicates, clause] };
|
|
116
|
+
}
|
|
117
|
+
return { kind: PredicateKind.ALL_OF, predicates: [existing, clause] };
|
|
118
|
+
}
|
|
108
119
|
function anchorToElement(anchor) {
|
|
109
120
|
if (anchor.kind === AnchorKind.TESTID)
|
|
110
121
|
return { testid: anchor.value };
|
|
@@ -122,7 +133,7 @@ class Recorder {
|
|
|
122
133
|
#startPath;
|
|
123
134
|
#annotations = [];
|
|
124
135
|
#pendingFill;
|
|
125
|
-
#
|
|
136
|
+
#captureAbort;
|
|
126
137
|
#root;
|
|
127
138
|
#statusEl;
|
|
128
139
|
#menuEl;
|
|
@@ -145,9 +156,8 @@ class Recorder {
|
|
|
145
156
|
this.#installCapture();
|
|
146
157
|
}
|
|
147
158
|
destroy() {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.#teardowns = [];
|
|
159
|
+
this.#captureAbort?.abort();
|
|
160
|
+
this.#captureAbort = undefined;
|
|
151
161
|
this.#root?.remove();
|
|
152
162
|
this.#root = undefined;
|
|
153
163
|
this.#statusEl = undefined;
|
|
@@ -159,20 +169,13 @@ class Recorder {
|
|
|
159
169
|
this.#pendingFill = undefined;
|
|
160
170
|
}
|
|
161
171
|
#installCapture() {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
document.addEventListener('
|
|
167
|
-
document.addEventListener('
|
|
168
|
-
document.addEventListener('
|
|
169
|
-
document.addEventListener('submit', onSubmit, true);
|
|
170
|
-
this.#teardowns.push(() => {
|
|
171
|
-
document.removeEventListener('click', onClick, true);
|
|
172
|
-
document.removeEventListener('input', onInput, true);
|
|
173
|
-
document.removeEventListener('change', onChange, true);
|
|
174
|
-
document.removeEventListener('submit', onSubmit, true);
|
|
175
|
-
});
|
|
172
|
+
const ac = new AbortController();
|
|
173
|
+
this.#captureAbort = ac;
|
|
174
|
+
const opts = { capture: true, signal: ac.signal };
|
|
175
|
+
document.addEventListener('click', (ev) => this.#onClick(ev), opts);
|
|
176
|
+
document.addEventListener('input', (ev) => this.#onInput(ev), opts);
|
|
177
|
+
document.addEventListener('change', (ev) => this.#onChange(ev), opts);
|
|
178
|
+
document.addEventListener('submit', (ev) => this.#onSubmit(ev), opts);
|
|
176
179
|
}
|
|
177
180
|
#ignore(ev) {
|
|
178
181
|
const target = ev.target;
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { nativeWarn } from '../timers/console/native-console.js';
|
|
2
2
|
import { markAdapterSource } from './stores.js';
|
|
3
|
+
function snapshotLive(value) {
|
|
4
|
+
try {
|
|
5
|
+
return copyPlain(value, new WeakMap());
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function copyPlain(value, seen) {
|
|
12
|
+
if ('object' !== typeof value || null === value)
|
|
13
|
+
return value;
|
|
14
|
+
const done = seen.get(value);
|
|
15
|
+
if (done !== undefined)
|
|
16
|
+
return done;
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
const out = [];
|
|
19
|
+
seen.set(value, out);
|
|
20
|
+
for (const item of value)
|
|
21
|
+
out.push(copyPlain(item, seen));
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
const proto = Object.getPrototypeOf(value);
|
|
25
|
+
if (proto !== Object.prototype && proto !== null)
|
|
26
|
+
return value;
|
|
27
|
+
const out = {};
|
|
28
|
+
seen.set(value, out);
|
|
29
|
+
for (const [key, item] of Object.entries(value))
|
|
30
|
+
out[key] = copyPlain(item, seen);
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
3
33
|
export function tanstackQueryStore(client) {
|
|
4
34
|
const store = {
|
|
5
35
|
getState: () => {
|
|
@@ -106,7 +136,7 @@ export function svelteStore(readable, warn = nativeWarn) {
|
|
|
106
136
|
let value;
|
|
107
137
|
let called = false;
|
|
108
138
|
stopSubscription(readable.subscribe((next) => {
|
|
109
|
-
value = next;
|
|
139
|
+
value = snapshotLive(next);
|
|
110
140
|
called = true;
|
|
111
141
|
}));
|
|
112
142
|
if (!called && !warnedAboutLazyStore) {
|
|
@@ -132,7 +162,7 @@ export function svelteStore(readable, warn = nativeWarn) {
|
|
|
132
162
|
const PINIA_SUBSCRIBE_OPTIONS = { detached: true, flush: 'sync' };
|
|
133
163
|
export function piniaStore(store) {
|
|
134
164
|
return {
|
|
135
|
-
getState: () => store.$state,
|
|
165
|
+
getState: () => snapshotLive(store.$state),
|
|
136
166
|
subscribe: (listener) => store.$subscribe(() => listener(), { ...PINIA_SUBSCRIBE_OPTIONS }),
|
|
137
167
|
};
|
|
138
168
|
}
|
|
@@ -6,8 +6,14 @@ export function registerAdapter(adapter) {
|
|
|
6
6
|
}
|
|
7
7
|
export function identifyComponent(el) {
|
|
8
8
|
for (const adapter of adapters) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
let info;
|
|
10
|
+
try {
|
|
11
|
+
info = adapter.identify(el);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (info !== null && info !== undefined)
|
|
11
17
|
return info;
|
|
12
18
|
}
|
|
13
19
|
return null;
|