@ralphralphai/playwright 2.4.0 → 2.6.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/README.md +44 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +9 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/reporter.cjs +1 -1
- package/dist/reporter.mjs +1 -1
- package/dist/{upload-CUtC_rnN.mjs → upload-CGIMWRQM.mjs} +338 -23
- package/dist/upload-CGIMWRQM.mjs.map +1 -0
- package/dist/{upload-FIxKqKb3.cjs → upload-H-EycbCA.cjs} +338 -23
- package/dist/upload-H-EycbCA.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/upload-CUtC_rnN.mjs.map +0 -1
- package/dist/upload-FIxKqKb3.cjs.map +0 -1
|
@@ -70,7 +70,7 @@ function snapshot(value) {
|
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
72
72
|
//#region package.json
|
|
73
|
-
var version = "2.
|
|
73
|
+
var version = "2.6.0";
|
|
74
74
|
//#endregion
|
|
75
75
|
//#region src/actions.ts
|
|
76
76
|
const BINDING = "__ralphAction";
|
|
@@ -654,8 +654,10 @@ async function captureAriaSnapshot(page, { viewport, scroll }) {
|
|
|
654
654
|
boxes: true,
|
|
655
655
|
depth: MAX_ARIA_DEPTH
|
|
656
656
|
});
|
|
657
|
-
const
|
|
658
|
-
|
|
657
|
+
const placed = await Promise.all(snapshot.map((node) => toDocument(page, node, scroll)));
|
|
658
|
+
const clips = await readClips(page, placed);
|
|
659
|
+
const visible = placed.flatMap((node) => {
|
|
660
|
+
const kept = keepShown(node, viewport.width, clips, void 0);
|
|
659
661
|
return kept === void 0 ? [] : [kept];
|
|
660
662
|
});
|
|
661
663
|
const described = await Promise.all(visible.map((node) => describe(page, node, {}, false)));
|
|
@@ -719,15 +721,134 @@ function isReachable(box, viewportWidth) {
|
|
|
719
721
|
function isShown(node, viewportWidth) {
|
|
720
722
|
return node.ref !== void 0 && isReachable(node.box, viewportWidth);
|
|
721
723
|
}
|
|
722
|
-
function
|
|
724
|
+
function edgesOf(box) {
|
|
725
|
+
return {
|
|
726
|
+
left: box.x,
|
|
727
|
+
top: box.y,
|
|
728
|
+
right: box.x + box.width,
|
|
729
|
+
bottom: box.y + box.height
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
function intersect(a, b) {
|
|
733
|
+
if (a === void 0) return b;
|
|
734
|
+
return {
|
|
735
|
+
left: Math.max(a.left, b.left),
|
|
736
|
+
top: Math.max(a.top, b.top),
|
|
737
|
+
right: Math.min(a.right, b.right),
|
|
738
|
+
bottom: Math.min(a.bottom, b.bottom)
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
const ROUNDING_SLACK = 1;
|
|
742
|
+
function sticksOut(inner, outer) {
|
|
743
|
+
return inner.x < outer.x - ROUNDING_SLACK || inner.y < outer.y - ROUNDING_SLACK || inner.x + inner.width > outer.x + outer.width + ROUNDING_SLACK || inner.y + inner.height > outer.y + outer.height + ROUNDING_SLACK;
|
|
744
|
+
}
|
|
745
|
+
function overlaps(a, b) {
|
|
746
|
+
return Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x) > ROUNDING_SLACK && Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y) > ROUNDING_SLACK;
|
|
747
|
+
}
|
|
748
|
+
function isOutside(box, clip) {
|
|
749
|
+
return box.x >= clip.right || box.x + box.width <= clip.left || box.y >= clip.bottom || box.y + box.height <= clip.top;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* The area each element is clipped to by its ancestors' `overflow`, in
|
|
753
|
+
* document space, by ref.
|
|
754
|
+
*
|
|
755
|
+
* The boxes are not clipped (the rows of a 448px scroll box run thousands of
|
|
756
|
+
* pixels down the page), and reading an element's ancestors is a page round
|
|
757
|
+
* trip. Only an element that may overflow one is read: a root, one sticking
|
|
758
|
+
* out of its parent, or one running into its next sibling. The clipping
|
|
759
|
+
* ancestor itself is often missing from the tree, since Playwright unwraps a
|
|
760
|
+
* nameless wrapper with one child. Every other element takes its parent's
|
|
761
|
+
* clip.
|
|
762
|
+
*/
|
|
763
|
+
async function readClips(page, nodes) {
|
|
764
|
+
const candidates = [];
|
|
765
|
+
const visit = (node, parent, next, frame) => {
|
|
766
|
+
if (node.box !== void 0 && (parent === void 0 || sticksOut(node.box, parent) || next?.box !== void 0 && overlaps(node.box, next.box))) candidates.push({
|
|
767
|
+
node,
|
|
768
|
+
frame
|
|
769
|
+
});
|
|
770
|
+
const childFrame = node.role === "iframe" && node.box !== void 0 ? intersect(frame, edgesOf(node.box)) : frame;
|
|
771
|
+
const elements = (node.children ?? []).filter((child) => {
|
|
772
|
+
return typeof child !== "string";
|
|
773
|
+
});
|
|
774
|
+
elements.forEach((child, index) => {
|
|
775
|
+
visit(child, node.box, elements[index + 1], childFrame);
|
|
776
|
+
});
|
|
777
|
+
};
|
|
778
|
+
nodes.forEach((node, index) => {
|
|
779
|
+
visit(node, void 0, nodes[index + 1], void 0);
|
|
780
|
+
});
|
|
781
|
+
const clips = await Promise.all(candidates.map(async ({ node, frame }) => {
|
|
782
|
+
const clip = await readClip(page, node);
|
|
783
|
+
return clip === void 0 || node.ref === void 0 ? [] : [[node.ref, intersect(frame, clip)]];
|
|
784
|
+
}));
|
|
785
|
+
return new Map(clips.flat());
|
|
786
|
+
}
|
|
787
|
+
async function readClip(page, node) {
|
|
788
|
+
if (node.box === void 0 || node.ref === void 0) return;
|
|
789
|
+
let read;
|
|
790
|
+
try {
|
|
791
|
+
read = await page.locator(`aria-ref=${node.ref}`).evaluate((element) => {
|
|
792
|
+
const clip = {
|
|
793
|
+
left: -Infinity,
|
|
794
|
+
top: -Infinity,
|
|
795
|
+
right: Infinity,
|
|
796
|
+
bottom: Infinity
|
|
797
|
+
};
|
|
798
|
+
let position = getComputedStyle(element).position;
|
|
799
|
+
for (let ancestor = element.parentElement; ancestor !== null && ancestor !== document.body && ancestor !== document.documentElement; ancestor = ancestor.parentElement) {
|
|
800
|
+
if (position === "fixed") break;
|
|
801
|
+
const style = getComputedStyle(ancestor);
|
|
802
|
+
if (position === "absolute" && style.position === "static" && style.transform === "none") continue;
|
|
803
|
+
position = style.position;
|
|
804
|
+
const clipsX = style.overflowX !== "visible";
|
|
805
|
+
const clipsY = style.overflowY !== "visible";
|
|
806
|
+
if (!clipsX && !clipsY || style.display === "inline") continue;
|
|
807
|
+
const rect = ancestor.getBoundingClientRect();
|
|
808
|
+
const left = rect.left + ancestor.clientLeft;
|
|
809
|
+
const top = rect.top + ancestor.clientTop;
|
|
810
|
+
if (clipsX) {
|
|
811
|
+
clip.left = Math.max(clip.left, left);
|
|
812
|
+
clip.right = Math.min(clip.right, left + ancestor.clientWidth);
|
|
813
|
+
}
|
|
814
|
+
if (clipsY) {
|
|
815
|
+
clip.top = Math.max(clip.top, top);
|
|
816
|
+
clip.bottom = Math.min(clip.bottom, top + ancestor.clientHeight);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
const own = element.getBoundingClientRect();
|
|
820
|
+
return {
|
|
821
|
+
x: own.x,
|
|
822
|
+
y: own.y,
|
|
823
|
+
clip
|
|
824
|
+
};
|
|
825
|
+
}, void 0, { timeout: ELEMENT_LOOKUP_TIMEOUT_MS });
|
|
826
|
+
} catch {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const dx = node.box.x - read.x;
|
|
830
|
+
const dy = node.box.y - read.y;
|
|
831
|
+
return {
|
|
832
|
+
left: read.clip.left + dx,
|
|
833
|
+
top: read.clip.top + dy,
|
|
834
|
+
right: read.clip.right + dx,
|
|
835
|
+
bottom: read.clip.bottom + dy
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
function keepShown(node, viewportWidth, clips, inherited) {
|
|
723
839
|
if (node.role === "iframe" && node.box !== void 0 && (node.box.width < MIN_IFRAME_SIZE || node.box.height < MIN_IFRAME_SIZE)) return;
|
|
840
|
+
const clip = (node.ref === void 0 ? void 0 : clips.get(node.ref)) ?? inherited;
|
|
841
|
+
if (clip !== void 0 && node.box !== void 0 && isOutside(node.box, clip)) return;
|
|
724
842
|
const shown = isShown(node, viewportWidth);
|
|
843
|
+
const childClip = node.role === "iframe" && node.box !== void 0 ? intersect(clip, edgesOf(node.box)) : clip;
|
|
725
844
|
const children = (node.children ?? []).flatMap((child) => {
|
|
726
845
|
if (typeof child === "string") return shown ? [child] : [];
|
|
727
|
-
const kept = keepShown(child, viewportWidth);
|
|
846
|
+
const kept = keepShown(child, viewportWidth, clips, childClip);
|
|
728
847
|
return kept === void 0 ? [] : [kept];
|
|
729
848
|
});
|
|
730
849
|
if (!shown && children.length === 0) return;
|
|
850
|
+
const [only] = children;
|
|
851
|
+
if (node.role === "generic" && !node.name && (node.children?.length ?? 0) > 1 && children.length === 1 && typeof only !== "string" && only?.ref !== void 0) return only;
|
|
731
852
|
return node.children === void 0 ? node : {
|
|
732
853
|
...node,
|
|
733
854
|
children
|
|
@@ -825,6 +946,179 @@ async function describe(page, child, inherited, insideDynamic) {
|
|
|
825
946
|
};
|
|
826
947
|
}
|
|
827
948
|
//#endregion
|
|
949
|
+
//#region src/animation_observer.ts
|
|
950
|
+
/** Runs in the page. Keeps native animations and DOM changes observable without app hooks. */
|
|
951
|
+
function observeAnimations() {
|
|
952
|
+
const paused = /* @__PURE__ */ new Set();
|
|
953
|
+
const roots = /* @__PURE__ */ new Set();
|
|
954
|
+
let dirty = true;
|
|
955
|
+
const observer = new MutationObserver(() => {
|
|
956
|
+
dirty = true;
|
|
957
|
+
});
|
|
958
|
+
const collect = (root, all) => {
|
|
959
|
+
if (!roots.has(root)) {
|
|
960
|
+
roots.add(root);
|
|
961
|
+
observer.observe(root, {
|
|
962
|
+
subtree: true,
|
|
963
|
+
childList: true,
|
|
964
|
+
attributes: true,
|
|
965
|
+
characterData: true
|
|
966
|
+
});
|
|
967
|
+
dirty = true;
|
|
968
|
+
}
|
|
969
|
+
root.getAnimations().forEach((animation) => all.add(animation));
|
|
970
|
+
for (const element of root.querySelectorAll("*")) if (element.shadowRoot) collect(element.shadowRoot, all);
|
|
971
|
+
};
|
|
972
|
+
return {
|
|
973
|
+
sample(finishFinite) {
|
|
974
|
+
const all = /* @__PURE__ */ new Set();
|
|
975
|
+
collect(document, all);
|
|
976
|
+
let changed = dirty;
|
|
977
|
+
dirty = false;
|
|
978
|
+
for (const animation of all) {
|
|
979
|
+
if (animation.playState !== "running") continue;
|
|
980
|
+
if (finishFinite && animation.playbackRate !== 0 && Number.isFinite(animation.effect?.getComputedTiming().endTime)) animation.finish();
|
|
981
|
+
else {
|
|
982
|
+
animation.pause();
|
|
983
|
+
paused.add(animation);
|
|
984
|
+
}
|
|
985
|
+
changed = true;
|
|
986
|
+
}
|
|
987
|
+
return changed;
|
|
988
|
+
},
|
|
989
|
+
async ready() {
|
|
990
|
+
await Promise.all([...paused].map((animation) => animation.ready));
|
|
991
|
+
},
|
|
992
|
+
resume() {
|
|
993
|
+
observer.disconnect();
|
|
994
|
+
for (const animation of paused) if (animation.playState === "paused") animation.play();
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
//#endregion
|
|
999
|
+
//#region src/capture_freezer.ts
|
|
1000
|
+
const PAUSE_LEAD_MS = 100;
|
|
1001
|
+
const ANIMATION_QUIET_MS = 150;
|
|
1002
|
+
const MAX_ANIMATION_SETTLE_MS = 1500;
|
|
1003
|
+
/** One owner of the context-wide clock; captures in different tabs queue here. */
|
|
1004
|
+
var CaptureFreezer = class {
|
|
1005
|
+
context;
|
|
1006
|
+
tail = Promise.resolve();
|
|
1007
|
+
closed = false;
|
|
1008
|
+
constructor(context) {
|
|
1009
|
+
this.context = context;
|
|
1010
|
+
context.once("close", () => {
|
|
1011
|
+
this.closed = true;
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
install() {
|
|
1015
|
+
if (this.context.pages().some((page) => page.url() !== "about:blank")) throw new Error("Ralph freezeDuringCapture requires the clock before page scripts run. Await ralph.observe(context) before creating or navigating pages in a custom context.");
|
|
1016
|
+
return this.context.clock.install();
|
|
1017
|
+
}
|
|
1018
|
+
async capture(page, signal, capture, deadline = Date.now() + 5e3) {
|
|
1019
|
+
const task = this.tail.then(async () => {
|
|
1020
|
+
signal.throwIfAborted();
|
|
1021
|
+
const animations = /* @__PURE__ */ new Map();
|
|
1022
|
+
try {
|
|
1023
|
+
await this.settleAnimations(page, animations, signal, deadline);
|
|
1024
|
+
await this.pauseClock(page, signal);
|
|
1025
|
+
signal.throwIfAborted();
|
|
1026
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
1027
|
+
await this.sampleAnimations(page, animations, signal, false);
|
|
1028
|
+
await this.waitForAnimationsReady(animations, signal);
|
|
1029
|
+
}
|
|
1030
|
+
return await capture();
|
|
1031
|
+
} finally {
|
|
1032
|
+
try {
|
|
1033
|
+
await this.resumeAnimations(animations);
|
|
1034
|
+
} finally {
|
|
1035
|
+
if (!this.closed) await this.context.clock.resume();
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
this.tail = task.catch(() => void 0);
|
|
1040
|
+
return task;
|
|
1041
|
+
}
|
|
1042
|
+
async settleAnimations(page, animations, signal, deadline) {
|
|
1043
|
+
const now = Date.now();
|
|
1044
|
+
const endsAt = now + Math.min(MAX_ANIMATION_SETTLE_MS, Math.max(0, (deadline - now) / 2));
|
|
1045
|
+
let quietSince = now;
|
|
1046
|
+
while (Date.now() < endsAt) {
|
|
1047
|
+
if (await this.sampleAnimations(page, animations, signal, true)) quietSince = Date.now();
|
|
1048
|
+
if (Date.now() - quietSince >= ANIMATION_QUIET_MS) return;
|
|
1049
|
+
await (0, node_timers_promises.setTimeout)(Math.max(0, Math.min(50, endsAt - Date.now())), void 0, { signal }).catch((error) => {
|
|
1050
|
+
signal.throwIfAborted();
|
|
1051
|
+
throw error;
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
async sampleAnimations(page, animations, signal, finishFinite) {
|
|
1056
|
+
let changed = false;
|
|
1057
|
+
for (const frame of page.frames()) {
|
|
1058
|
+
signal.throwIfAborted();
|
|
1059
|
+
try {
|
|
1060
|
+
let handle = animations.get(frame);
|
|
1061
|
+
if (!handle) {
|
|
1062
|
+
handle = await frame.evaluateHandle(observeAnimations);
|
|
1063
|
+
animations.set(frame, handle);
|
|
1064
|
+
}
|
|
1065
|
+
changed = await handle.evaluate((state, finish) => state.sample(finish), finishFinite) || changed;
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
if (!frame.isDetached()) throw error;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
signal.throwIfAborted();
|
|
1071
|
+
return changed;
|
|
1072
|
+
}
|
|
1073
|
+
async waitForAnimationsReady(animations, signal) {
|
|
1074
|
+
signal.throwIfAborted();
|
|
1075
|
+
let onAbort;
|
|
1076
|
+
const aborted = new Promise((_, reject) => {
|
|
1077
|
+
onAbort = () => reject(signal.reason);
|
|
1078
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1079
|
+
});
|
|
1080
|
+
try {
|
|
1081
|
+
await Promise.race([Promise.all([...animations].map(async ([frame, handle]) => {
|
|
1082
|
+
if (frame.isDetached()) return;
|
|
1083
|
+
try {
|
|
1084
|
+
await handle.evaluate((state) => state.ready());
|
|
1085
|
+
} catch (error) {
|
|
1086
|
+
if (!frame.isDetached()) throw error;
|
|
1087
|
+
}
|
|
1088
|
+
})), aborted]);
|
|
1089
|
+
} finally {
|
|
1090
|
+
signal.removeEventListener("abort", onAbort);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
async resumeAnimations(animations) {
|
|
1094
|
+
const restored = await Promise.allSettled([...animations.values()].map(async (handle) => {
|
|
1095
|
+
try {
|
|
1096
|
+
await handle.evaluate((state) => state.resume());
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
if (!destroyedContext(error)) throw error;
|
|
1099
|
+
} finally {
|
|
1100
|
+
await handle.dispose();
|
|
1101
|
+
}
|
|
1102
|
+
}));
|
|
1103
|
+
for (const result of restored) if (result.status === "rejected") throw result.reason;
|
|
1104
|
+
}
|
|
1105
|
+
async pauseClock(page, signal) {
|
|
1106
|
+
for (let attempt = 0;; attempt++) {
|
|
1107
|
+
const time = await page.evaluate(() => Date.now());
|
|
1108
|
+
signal.throwIfAborted();
|
|
1109
|
+
try {
|
|
1110
|
+
await this.context.clock.pauseAt(time + PAUSE_LEAD_MS);
|
|
1111
|
+
return;
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
if (attempt > 0 || !(error instanceof Error) || !error.message.includes("Cannot fast-forward to the past")) throw error;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
function destroyedContext(error) {
|
|
1119
|
+
return error instanceof Error && /Execution context was destroyed|Cannot find context|Target page, context or browser has been closed|Frame was detached/.test(error.message);
|
|
1120
|
+
}
|
|
1121
|
+
//#endregion
|
|
828
1122
|
//#region src/conditions.ts
|
|
829
1123
|
const declared = (declaration = {}) => {
|
|
830
1124
|
const conditions = {};
|
|
@@ -886,11 +1180,11 @@ function nodeKey(conditions) {
|
|
|
886
1180
|
*/
|
|
887
1181
|
const WEBP_QUALITY = 80;
|
|
888
1182
|
const WEBP_MAX_DIMENSION = 16383;
|
|
889
|
-
async function takeScreenshot(page, deadline) {
|
|
1183
|
+
async function takeScreenshot(page, deadline, frozen = false) {
|
|
890
1184
|
const options = {
|
|
891
1185
|
fullPage: true,
|
|
892
1186
|
scale: "css",
|
|
893
|
-
animations: "disabled"
|
|
1187
|
+
animations: frozen ? "allow" : "disabled"
|
|
894
1188
|
};
|
|
895
1189
|
const webp = await page.screenshot({
|
|
896
1190
|
...options,
|
|
@@ -1119,22 +1413,30 @@ var Recorder = class {
|
|
|
1119
1413
|
/** Starts recording URL changes in every current and future tab of `context`. */
|
|
1120
1414
|
observe(context) {
|
|
1121
1415
|
if (this.closed) throw new Error("The Ralph recorder has finished.");
|
|
1122
|
-
|
|
1416
|
+
const existing = this.contexts.get(context);
|
|
1417
|
+
if (existing) return existing.ready;
|
|
1418
|
+
const freezer = this.options.freezeDuringCapture ? new CaptureFreezer(context) : void 0;
|
|
1419
|
+
const ready = freezer?.install() ?? Promise.resolve();
|
|
1123
1420
|
const onPage = (page) => this.watchPage(page);
|
|
1124
|
-
this.contexts.set(context,
|
|
1421
|
+
this.contexts.set(context, {
|
|
1422
|
+
onPage,
|
|
1423
|
+
ready,
|
|
1424
|
+
freezer
|
|
1425
|
+
});
|
|
1125
1426
|
this.actions.observe(context);
|
|
1126
1427
|
context.on("page", onPage);
|
|
1127
1428
|
for (const page of context.pages()) onPage(page);
|
|
1429
|
+
return ready;
|
|
1128
1430
|
}
|
|
1129
1431
|
async recordNode(page, options) {
|
|
1130
|
-
this.observe(page.context());
|
|
1432
|
+
await this.observe(page.context());
|
|
1131
1433
|
const state = this.pages.get(page);
|
|
1132
1434
|
if (!state) throw new Error("Cannot record a closed browser page.");
|
|
1133
1435
|
if (this.paused) return;
|
|
1134
1436
|
await this.enqueueCreateNodeRequest(state, "explicit", options);
|
|
1135
1437
|
}
|
|
1136
1438
|
async setNodeConditions(page, declaration) {
|
|
1137
|
-
this.observe(page.context());
|
|
1439
|
+
await this.observe(page.context());
|
|
1138
1440
|
const state = this.pages.get(page);
|
|
1139
1441
|
if (!state) throw new Error("Cannot tag a closed browser page.");
|
|
1140
1442
|
const key = Symbol();
|
|
@@ -1165,8 +1467,11 @@ var Recorder = class {
|
|
|
1165
1467
|
}
|
|
1166
1468
|
/** Stops watching `context` and waits for its queued recordings. */
|
|
1167
1469
|
async stopContext(context) {
|
|
1168
|
-
const
|
|
1169
|
-
if (
|
|
1470
|
+
const observed = this.contexts.get(context);
|
|
1471
|
+
if (observed) {
|
|
1472
|
+
context.off("page", observed.onPage);
|
|
1473
|
+
await observed.ready;
|
|
1474
|
+
}
|
|
1170
1475
|
const states = [...this.pages.values()].filter((state) => state.page.context() === context);
|
|
1171
1476
|
for (const state of states) state.page.off("framenavigated", state.onNavigation);
|
|
1172
1477
|
await Promise.all(states.map((state) => state.tail));
|
|
@@ -1282,6 +1587,7 @@ var Recorder = class {
|
|
|
1282
1587
|
};
|
|
1283
1588
|
try {
|
|
1284
1589
|
check();
|
|
1590
|
+
await wait(this.contexts.get(page.context()).ready);
|
|
1285
1591
|
if (request.trigger !== "explicit") await this.waitForPageToSettle(page, deadline, check);
|
|
1286
1592
|
check();
|
|
1287
1593
|
const conditions = this.declaredConditions(state);
|
|
@@ -1294,18 +1600,27 @@ var Recorder = class {
|
|
|
1294
1600
|
warnedNoTracker = true;
|
|
1295
1601
|
console.warn("Ralph: this page runs no tracker, so the node conditions the test declares cannot be checked against the tags the app reports. Production events must carry the same tags, or these nodes will match no visitors.");
|
|
1296
1602
|
}
|
|
1297
|
-
|
|
1603
|
+
const freezer = this.contexts.get(page.context()).freezer;
|
|
1604
|
+
if (this.options.reduceMotion && !freezer) {
|
|
1298
1605
|
check();
|
|
1299
1606
|
await wait(waitForAnimations(page, (deadline.endsAt - Date.now()) / 2));
|
|
1300
1607
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1608
|
+
const capture = async () => {
|
|
1609
|
+
check();
|
|
1610
|
+
const before = await wait(readLayout(page));
|
|
1611
|
+
check();
|
|
1612
|
+
const image = await wait(takeScreenshot(page, deadline.endsAt, !!freezer));
|
|
1613
|
+
check();
|
|
1614
|
+
const after = await wait(readLayout(page));
|
|
1615
|
+
check();
|
|
1616
|
+
return {
|
|
1617
|
+
before,
|
|
1618
|
+
image,
|
|
1619
|
+
after,
|
|
1620
|
+
snapshot: await Promise.race([captureAriaSnapshot(page, after).catch(() => void 0), (0, node_timers_promises.setTimeout)(Math.max(0, deadline.endsAt - Date.now()), void 0, { ref: false })])
|
|
1621
|
+
};
|
|
1622
|
+
};
|
|
1623
|
+
const { before, image, after, snapshot } = freezer ? await freezer.capture(page, deadline.signal, capture, deadline.endsAt) : await capture();
|
|
1309
1624
|
checkPage();
|
|
1310
1625
|
const recorded = {
|
|
1311
1626
|
...request,
|
|
@@ -1843,4 +2158,4 @@ Object.defineProperty(exports, "visitAllLinks", {
|
|
|
1843
2158
|
}
|
|
1844
2159
|
});
|
|
1845
2160
|
|
|
1846
|
-
//# sourceMappingURL=upload-
|
|
2161
|
+
//# sourceMappingURL=upload-H-EycbCA.cjs.map
|