@toolstackhq/cdpwright 1.2.0 → 1.3.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/assert/expect.d.ts +1 -1
- package/dist/assert/expect.js +1 -1
- package/dist/{chunk-PDUS6BDZ.js → chunk-EIAXMGD5.js} +586 -50
- package/dist/chunk-EIAXMGD5.js.map +1 -0
- package/dist/cli.js +601 -73
- package/dist/cli.js.map +1 -1
- package/dist/{expect-CLal_AQd.d.ts → expect-Cd5SNFuF.d.ts} +111 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-PDUS6BDZ.js.map +0 -1
|
@@ -165,27 +165,77 @@ function serializeShadowDomHelpers() {
|
|
|
165
165
|
// src/core/Locator.ts
|
|
166
166
|
var Locator = class {
|
|
167
167
|
frame;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
constructor(frame, selector, options = {}) {
|
|
168
|
+
query;
|
|
169
|
+
constructor(frame, query) {
|
|
171
170
|
this.frame = frame;
|
|
172
|
-
this.
|
|
173
|
-
|
|
171
|
+
this.query = query;
|
|
172
|
+
}
|
|
173
|
+
getEvents() {
|
|
174
|
+
return this.frame.getEvents();
|
|
175
|
+
}
|
|
176
|
+
getFrameId() {
|
|
177
|
+
return this.frame.id;
|
|
178
|
+
}
|
|
179
|
+
describe() {
|
|
180
|
+
switch (this.query.kind) {
|
|
181
|
+
case "selector":
|
|
182
|
+
return this.query.selector;
|
|
183
|
+
case "text":
|
|
184
|
+
return typeof this.query.text === "string" ? `text=${JSON.stringify(this.query.text)}` : `text=${this.query.text.toString()}`;
|
|
185
|
+
case "role":
|
|
186
|
+
return `role=${this.query.role}${this.query.options?.name ? ` name=${typeof this.query.options.name === "string" ? JSON.stringify(this.query.options.name) : this.query.options.name.toString()}` : ""}`;
|
|
187
|
+
}
|
|
174
188
|
}
|
|
175
189
|
async click(options = {}) {
|
|
176
|
-
return this.frame.
|
|
190
|
+
return this.frame.clickLocator(this.query, { ...this.queryTimeoutOptions(), ...options });
|
|
177
191
|
}
|
|
178
192
|
async dblclick(options = {}) {
|
|
179
|
-
return this.frame.
|
|
193
|
+
return this.frame.dblclickLocator(this.query, { ...this.queryTimeoutOptions(), ...options });
|
|
180
194
|
}
|
|
181
195
|
async type(text, options = {}) {
|
|
182
|
-
return this.frame.
|
|
196
|
+
return this.frame.typeLocator(this.query, text, { ...this.queryTimeoutOptions(), ...options });
|
|
183
197
|
}
|
|
184
198
|
async exists() {
|
|
185
|
-
return this.frame.
|
|
199
|
+
return this.frame.existsLocator(this.query);
|
|
200
|
+
}
|
|
201
|
+
async isVisible() {
|
|
202
|
+
return this.frame.isVisibleLocator(this.query);
|
|
203
|
+
}
|
|
204
|
+
async isEnabled() {
|
|
205
|
+
return this.frame.isEnabledLocator(this.query);
|
|
206
|
+
}
|
|
207
|
+
async isChecked() {
|
|
208
|
+
return this.frame.isCheckedLocator(this.query);
|
|
186
209
|
}
|
|
187
210
|
async text() {
|
|
188
|
-
return this.frame.
|
|
211
|
+
return this.frame.textLocator(this.query);
|
|
212
|
+
}
|
|
213
|
+
async value() {
|
|
214
|
+
return this.frame.valueLocator(this.query);
|
|
215
|
+
}
|
|
216
|
+
async attribute(name) {
|
|
217
|
+
return this.frame.attributeLocator(this.query, name);
|
|
218
|
+
}
|
|
219
|
+
async classes() {
|
|
220
|
+
return this.frame.classesLocator(this.query);
|
|
221
|
+
}
|
|
222
|
+
async css(property) {
|
|
223
|
+
return this.frame.cssLocator(this.query, property);
|
|
224
|
+
}
|
|
225
|
+
async hasFocus() {
|
|
226
|
+
return this.frame.hasFocusLocator(this.query);
|
|
227
|
+
}
|
|
228
|
+
async isInViewport(fully = false) {
|
|
229
|
+
return this.frame.isInViewportLocator(this.query, fully);
|
|
230
|
+
}
|
|
231
|
+
async isEditable() {
|
|
232
|
+
return this.frame.isEditableLocator(this.query);
|
|
233
|
+
}
|
|
234
|
+
async count() {
|
|
235
|
+
return this.frame.countLocator(this.query);
|
|
236
|
+
}
|
|
237
|
+
queryTimeoutOptions() {
|
|
238
|
+
return "options" in this.query && this.query.options?.timeoutMs ? { timeoutMs: this.query.options.timeoutMs } : {};
|
|
189
239
|
}
|
|
190
240
|
};
|
|
191
241
|
|
|
@@ -217,6 +267,9 @@ var Frame = class {
|
|
|
217
267
|
this.url = meta.url;
|
|
218
268
|
this.parentId = meta.parentId;
|
|
219
269
|
}
|
|
270
|
+
getEvents() {
|
|
271
|
+
return this.events;
|
|
272
|
+
}
|
|
220
273
|
async evaluate(fnOrString, ...args) {
|
|
221
274
|
return this.evaluateInContext(fnOrString, args);
|
|
222
275
|
}
|
|
@@ -233,7 +286,13 @@ var Frame = class {
|
|
|
233
286
|
return this.querySelectorAllInternal(selector, options, true);
|
|
234
287
|
}
|
|
235
288
|
locator(selector, options = {}) {
|
|
236
|
-
return new Locator(this, selector, options);
|
|
289
|
+
return new Locator(this, { kind: "selector", selector, options });
|
|
290
|
+
}
|
|
291
|
+
getByText(text, options = {}) {
|
|
292
|
+
return new Locator(this, { kind: "text", text, options });
|
|
293
|
+
}
|
|
294
|
+
getByRole(role, options = {}) {
|
|
295
|
+
return new Locator(this, { kind: "role", role, options });
|
|
237
296
|
}
|
|
238
297
|
async click(selector, options = {}) {
|
|
239
298
|
await this.performClick(selector, options, false);
|
|
@@ -668,6 +727,176 @@ var Frame = class {
|
|
|
668
727
|
const box = await this.resolveElementBox(selector, options);
|
|
669
728
|
return Boolean(box && box.visible);
|
|
670
729
|
}
|
|
730
|
+
async clickLocator(query, options = {}) {
|
|
731
|
+
await this.performClickLocator(query, options, false);
|
|
732
|
+
}
|
|
733
|
+
async dblclickLocator(query, options = {}) {
|
|
734
|
+
await this.performClickLocator(query, options, true);
|
|
735
|
+
}
|
|
736
|
+
async typeLocator(query, text, options = {}) {
|
|
737
|
+
const start = Date.now();
|
|
738
|
+
const description = this.locatorDescription(query);
|
|
739
|
+
this.events.emit("action:start", { name: "type", selector: description, frameId: this.id, sensitive: options.sensitive });
|
|
740
|
+
await waitFor(async () => {
|
|
741
|
+
const box = await this.resolveLocatorElementBox(query, options);
|
|
742
|
+
if (!box || !box.visible) {
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
return true;
|
|
746
|
+
}, { timeoutMs: options.timeoutMs ?? this.defaultTimeout, description: `type ${description}` });
|
|
747
|
+
const focusExpression = this.buildLocatorExpression(query, `
|
|
748
|
+
if (!el) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
el.focus();
|
|
752
|
+
`);
|
|
753
|
+
const focusParams = {
|
|
754
|
+
expression: focusExpression,
|
|
755
|
+
returnByValue: true
|
|
756
|
+
};
|
|
757
|
+
if (this.contextId) {
|
|
758
|
+
focusParams.contextId = this.contextId;
|
|
759
|
+
}
|
|
760
|
+
await this.session.send("Runtime.evaluate", focusParams);
|
|
761
|
+
await this.session.send("Input.insertText", { text });
|
|
762
|
+
const duration = Date.now() - start;
|
|
763
|
+
this.events.emit("action:end", { name: "type", selector: description, frameId: this.id, durationMs: duration, sensitive: options.sensitive });
|
|
764
|
+
this.logger.debug("Type", description, `${duration}ms`);
|
|
765
|
+
}
|
|
766
|
+
async existsLocator(query) {
|
|
767
|
+
return Boolean(await this.evalOnLocator(query, false, `
|
|
768
|
+
return Boolean(el);
|
|
769
|
+
`));
|
|
770
|
+
}
|
|
771
|
+
async isVisibleLocator(query) {
|
|
772
|
+
return this.evalOnLocator(query, false, `
|
|
773
|
+
if (!el) {
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
const rect = el.getBoundingClientRect();
|
|
777
|
+
const style = window.getComputedStyle(el);
|
|
778
|
+
return rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none" && Number(style.opacity || "1") > 0;
|
|
779
|
+
`);
|
|
780
|
+
}
|
|
781
|
+
async isEnabledLocator(query) {
|
|
782
|
+
return this.evalOnLocator(query, false, `
|
|
783
|
+
if (!el) {
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
const disabled = Boolean(el.disabled) || el.hasAttribute("disabled");
|
|
787
|
+
const ariaDisabled = el.getAttribute && el.getAttribute("aria-disabled") === "true";
|
|
788
|
+
return !(disabled || ariaDisabled);
|
|
789
|
+
`);
|
|
790
|
+
}
|
|
791
|
+
async isCheckedLocator(query) {
|
|
792
|
+
return this.evalOnLocator(query, false, `
|
|
793
|
+
if (!el) {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
796
|
+
const aria = el.getAttribute && el.getAttribute("aria-checked");
|
|
797
|
+
if (aria === "true") {
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
if (aria === "false") {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
if ("checked" in el) {
|
|
804
|
+
return Boolean(el.checked);
|
|
805
|
+
}
|
|
806
|
+
return null;
|
|
807
|
+
`);
|
|
808
|
+
}
|
|
809
|
+
async textLocator(query) {
|
|
810
|
+
return this.evalOnLocator(query, false, `
|
|
811
|
+
if (!el) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
if (el instanceof HTMLInputElement) {
|
|
815
|
+
const type = (el.getAttribute("type") || "text").toLowerCase();
|
|
816
|
+
if (type === "button" || type === "submit" || type === "reset") {
|
|
817
|
+
return el.value || "";
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return el.textContent || "";
|
|
821
|
+
`);
|
|
822
|
+
}
|
|
823
|
+
async valueLocator(query) {
|
|
824
|
+
return this.evalOnLocator(query, false, `
|
|
825
|
+
if (!el) {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
if ("value" in el) {
|
|
829
|
+
return el.value ?? "";
|
|
830
|
+
}
|
|
831
|
+
return el.getAttribute("value");
|
|
832
|
+
`);
|
|
833
|
+
}
|
|
834
|
+
async attributeLocator(query, name) {
|
|
835
|
+
return this.evalOnLocator(query, false, `
|
|
836
|
+
if (!el || !(el instanceof Element)) {
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
return el.getAttribute(${JSON.stringify(name)});
|
|
840
|
+
`);
|
|
841
|
+
}
|
|
842
|
+
async classesLocator(query) {
|
|
843
|
+
return this.evalOnLocator(query, false, `
|
|
844
|
+
if (!el) {
|
|
845
|
+
return null;
|
|
846
|
+
}
|
|
847
|
+
if (!el.classList) {
|
|
848
|
+
return [];
|
|
849
|
+
}
|
|
850
|
+
return Array.from(el.classList);
|
|
851
|
+
`);
|
|
852
|
+
}
|
|
853
|
+
async cssLocator(query, property) {
|
|
854
|
+
return this.evalOnLocator(query, false, `
|
|
855
|
+
if (!el) {
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
const style = window.getComputedStyle(el);
|
|
859
|
+
return style.getPropertyValue(${JSON.stringify(property)}) || "";
|
|
860
|
+
`);
|
|
861
|
+
}
|
|
862
|
+
async hasFocusLocator(query) {
|
|
863
|
+
return this.evalOnLocator(query, false, `
|
|
864
|
+
if (!el) {
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
return document.activeElement === el;
|
|
868
|
+
`);
|
|
869
|
+
}
|
|
870
|
+
async isInViewportLocator(query, fully = false) {
|
|
871
|
+
return this.evalOnLocator(query, false, `
|
|
872
|
+
if (!el) {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
const rect = el.getBoundingClientRect();
|
|
876
|
+
const viewWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
877
|
+
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
878
|
+
if (${fully ? "true" : "false"}) {
|
|
879
|
+
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= viewHeight && rect.right <= viewWidth;
|
|
880
|
+
}
|
|
881
|
+
return rect.bottom > 0 && rect.right > 0 && rect.top < viewHeight && rect.left < viewWidth;
|
|
882
|
+
`);
|
|
883
|
+
}
|
|
884
|
+
async isEditableLocator(query) {
|
|
885
|
+
return this.evalOnLocator(query, false, `
|
|
886
|
+
if (!el) {
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
const disabled = Boolean(el.disabled) || el.hasAttribute("disabled");
|
|
890
|
+
const readOnly = Boolean(el.readOnly) || el.hasAttribute("readonly");
|
|
891
|
+
const ariaDisabled = el.getAttribute && el.getAttribute("aria-disabled") === "true";
|
|
892
|
+
return !(disabled || readOnly || ariaDisabled);
|
|
893
|
+
`);
|
|
894
|
+
}
|
|
895
|
+
async countLocator(query) {
|
|
896
|
+
return this.evalOnLocator(query, true, `
|
|
897
|
+
return elements.length;
|
|
898
|
+
`);
|
|
899
|
+
}
|
|
671
900
|
async text(selector, options = {}) {
|
|
672
901
|
return this.evalOnSelector(selector, options, false, `
|
|
673
902
|
if (!el) {
|
|
@@ -849,6 +1078,263 @@ var Frame = class {
|
|
|
849
1078
|
return !(disabled || readOnly || ariaDisabled);
|
|
850
1079
|
`);
|
|
851
1080
|
}
|
|
1081
|
+
async performClickLocator(query, options, isDouble) {
|
|
1082
|
+
const start = Date.now();
|
|
1083
|
+
const actionName = isDouble ? "dblclick" : "click";
|
|
1084
|
+
const description = this.locatorDescription(query);
|
|
1085
|
+
this.events.emit("action:start", { name: actionName, selector: description, frameId: this.id });
|
|
1086
|
+
const box = await waitFor(async () => {
|
|
1087
|
+
const result = await this.resolveLocatorElementBox(query, options);
|
|
1088
|
+
if (!result || !result.visible) {
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1091
|
+
return result;
|
|
1092
|
+
}, { timeoutMs: options.timeoutMs ?? this.defaultTimeout, description: `${actionName} ${description}` });
|
|
1093
|
+
const centerX = box.x + box.width / 2;
|
|
1094
|
+
const centerY = box.y + box.height / 2;
|
|
1095
|
+
await this.session.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: centerX, y: centerY });
|
|
1096
|
+
await this.session.send("Input.dispatchMouseEvent", { type: "mousePressed", x: centerX, y: centerY, button: "left", clickCount: 1, buttons: 1 });
|
|
1097
|
+
await this.session.send("Input.dispatchMouseEvent", { type: "mouseReleased", x: centerX, y: centerY, button: "left", clickCount: 1, buttons: 0 });
|
|
1098
|
+
if (isDouble) {
|
|
1099
|
+
await this.session.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: centerX, y: centerY });
|
|
1100
|
+
await this.session.send("Input.dispatchMouseEvent", { type: "mousePressed", x: centerX, y: centerY, button: "left", clickCount: 2, buttons: 1 });
|
|
1101
|
+
await this.session.send("Input.dispatchMouseEvent", { type: "mouseReleased", x: centerX, y: centerY, button: "left", clickCount: 2, buttons: 0 });
|
|
1102
|
+
}
|
|
1103
|
+
const duration = Date.now() - start;
|
|
1104
|
+
this.events.emit("action:end", { name: actionName, selector: description, frameId: this.id, durationMs: duration });
|
|
1105
|
+
this.logger.debug("Click", description, `${duration}ms`);
|
|
1106
|
+
}
|
|
1107
|
+
locatorDescription(query) {
|
|
1108
|
+
switch (query.kind) {
|
|
1109
|
+
case "selector":
|
|
1110
|
+
return query.selector;
|
|
1111
|
+
case "text":
|
|
1112
|
+
return typeof query.text === "string" ? `text=${JSON.stringify(query.text)}` : `text=${query.text.toString()}`;
|
|
1113
|
+
case "role":
|
|
1114
|
+
return `role=${query.role}${query.options?.name ? ` name=${typeof query.options.name === "string" ? JSON.stringify(query.options.name) : query.options.name.toString()}` : ""}`;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
async resolveLocatorElementBox(query, options) {
|
|
1118
|
+
return this.evalOnLocator(query, false, `
|
|
1119
|
+
if (!el) {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
el.scrollIntoView({ block: "center", inline: "center" });
|
|
1123
|
+
const rect = el.getBoundingClientRect();
|
|
1124
|
+
const style = window.getComputedStyle(el);
|
|
1125
|
+
return {
|
|
1126
|
+
x: rect.x,
|
|
1127
|
+
y: rect.y,
|
|
1128
|
+
width: rect.width,
|
|
1129
|
+
height: rect.height,
|
|
1130
|
+
visible: rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none" && Number(style.opacity || "1") > 0
|
|
1131
|
+
};
|
|
1132
|
+
`);
|
|
1133
|
+
}
|
|
1134
|
+
async evalOnLocator(query, all, body) {
|
|
1135
|
+
const expression = this.buildLocatorExpression(query, body, all);
|
|
1136
|
+
const params = {
|
|
1137
|
+
expression,
|
|
1138
|
+
returnByValue: true
|
|
1139
|
+
};
|
|
1140
|
+
if (this.contextId) {
|
|
1141
|
+
params.contextId = this.contextId;
|
|
1142
|
+
}
|
|
1143
|
+
const result = await this.session.send("Runtime.evaluate", params);
|
|
1144
|
+
return result.result.value;
|
|
1145
|
+
}
|
|
1146
|
+
buildLocatorExpression(query, body, all = false) {
|
|
1147
|
+
const helpers = serializeShadowDomHelpers();
|
|
1148
|
+
const serializedQuery = this.serializeLocatorQuery(query);
|
|
1149
|
+
return `(function() {
|
|
1150
|
+
const querySelectorAllDeep = ${helpers.querySelectorAllDeep};
|
|
1151
|
+
const normalizeWhitespace = (value) => String(value ?? "").replace(/\\s+/g, " ").trim();
|
|
1152
|
+
const cssEscape = (value) => {
|
|
1153
|
+
if (typeof CSS !== "undefined" && CSS.escape) return CSS.escape(value);
|
|
1154
|
+
return String(value).replace(/[^a-zA-Z0-9_-]/g, (c) => "\\\\" + c.charCodeAt(0).toString(16) + " ");
|
|
1155
|
+
};
|
|
1156
|
+
const textFromElement = (el) => {
|
|
1157
|
+
if (!el) return "";
|
|
1158
|
+
if (el instanceof HTMLInputElement) {
|
|
1159
|
+
const type = (el.getAttribute("type") || "").toLowerCase();
|
|
1160
|
+
if (type === "button" || type === "submit" || type === "reset" || type === "image") {
|
|
1161
|
+
return el.value || el.getAttribute("alt") || "";
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return el.textContent || "";
|
|
1165
|
+
};
|
|
1166
|
+
const isHidden = (el) => {
|
|
1167
|
+
if (!el || !(el instanceof Element)) return true;
|
|
1168
|
+
const style = window.getComputedStyle(el);
|
|
1169
|
+
if (el.hidden || el.getAttribute("aria-hidden") === "true") return true;
|
|
1170
|
+
return style.display === "none" || style.visibility === "hidden" || Number(style.opacity || "1") <= 0;
|
|
1171
|
+
};
|
|
1172
|
+
const getLabelText = (el) => {
|
|
1173
|
+
if (!el || !(el instanceof Element)) return "";
|
|
1174
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
1175
|
+
if (ariaLabel) return normalizeWhitespace(ariaLabel);
|
|
1176
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
1177
|
+
if (labelledBy) {
|
|
1178
|
+
const parts = labelledBy.split(/\\s+/).filter(Boolean).map((id) => document.getElementById(id)?.textContent || "");
|
|
1179
|
+
const text = normalizeWhitespace(parts.join(" "));
|
|
1180
|
+
if (text) return text;
|
|
1181
|
+
}
|
|
1182
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
1183
|
+
if (el.id) {
|
|
1184
|
+
const label = document.querySelector("label[for="" + cssEscape(el.id) + ""]");
|
|
1185
|
+
if (label) {
|
|
1186
|
+
const text = normalizeWhitespace(label.textContent || "");
|
|
1187
|
+
if (text) return text;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
const wrap = el.closest("label");
|
|
1191
|
+
if (wrap) {
|
|
1192
|
+
const text = normalizeWhitespace(wrap.textContent || "");
|
|
1193
|
+
if (text) return text;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
if (el instanceof HTMLImageElement) {
|
|
1197
|
+
return normalizeWhitespace(el.getAttribute("alt") || el.getAttribute("title") || "");
|
|
1198
|
+
}
|
|
1199
|
+
return normalizeWhitespace(el.getAttribute("title") || "");
|
|
1200
|
+
};
|
|
1201
|
+
const getImplicitRole = (el) => {
|
|
1202
|
+
if (!el || !(el instanceof Element)) return "";
|
|
1203
|
+
const explicitRole = (el.getAttribute("role") || "").trim().split(/\\s+/)[0];
|
|
1204
|
+
if (explicitRole) return explicitRole;
|
|
1205
|
+
const tag = el.tagName.toLowerCase();
|
|
1206
|
+
if (tag === "button") return "button";
|
|
1207
|
+
if (tag === "summary") return "button";
|
|
1208
|
+
if (tag === "a" && el.hasAttribute("href")) return "link";
|
|
1209
|
+
if (tag === "input") {
|
|
1210
|
+
const type = (el.getAttribute("type") || "text").toLowerCase();
|
|
1211
|
+
if (type === "checkbox") return "checkbox";
|
|
1212
|
+
if (type === "radio") return "radio";
|
|
1213
|
+
if (type === "range") return "slider";
|
|
1214
|
+
if (type === "submit" || type === "button" || type === "reset") return "button";
|
|
1215
|
+
if (type === "file") return "button";
|
|
1216
|
+
return "textbox";
|
|
1217
|
+
}
|
|
1218
|
+
if (tag === "textarea") return "textbox";
|
|
1219
|
+
if (tag === "select") return "combobox";
|
|
1220
|
+
if (tag === "img") return "img";
|
|
1221
|
+
if (tag === "ul" || tag === "ol") return "list";
|
|
1222
|
+
if (tag === "li") return "listitem";
|
|
1223
|
+
if (tag === "table") return "table";
|
|
1224
|
+
if (tag === "tr") return "row";
|
|
1225
|
+
if (tag === "td") return "cell";
|
|
1226
|
+
if (tag === "th") return "columnheader";
|
|
1227
|
+
if (/^h[1-6]$/.test(tag)) return "heading";
|
|
1228
|
+
if (tag === "option") return "option";
|
|
1229
|
+
if (tag === "fieldset") return "group";
|
|
1230
|
+
if (tag === "form") return "form";
|
|
1231
|
+
if (el.hasAttribute("contenteditable")) return "textbox";
|
|
1232
|
+
return explicitRole;
|
|
1233
|
+
};
|
|
1234
|
+
const matchText = (actual, expected, exact) => {
|
|
1235
|
+
const normalizedActual = normalizeWhitespace(actual);
|
|
1236
|
+
if (expected && expected.kind === "regex") {
|
|
1237
|
+
const regex = new RegExp(expected.source, expected.flags);
|
|
1238
|
+
return regex.test(normalizedActual);
|
|
1239
|
+
}
|
|
1240
|
+
const normalizedExpected = normalizeWhitespace(expected.value);
|
|
1241
|
+
if (exact) {
|
|
1242
|
+
return normalizedActual === normalizedExpected;
|
|
1243
|
+
}
|
|
1244
|
+
return normalizedActual.toLowerCase().includes(normalizedExpected.toLowerCase());
|
|
1245
|
+
};
|
|
1246
|
+
const matchName = (actual, expected, exact) => {
|
|
1247
|
+
const normalizedActual = normalizeWhitespace(actual);
|
|
1248
|
+
if (expected && expected.kind === "regex") {
|
|
1249
|
+
const regex = new RegExp(expected.source, expected.flags);
|
|
1250
|
+
return regex.test(normalizedActual);
|
|
1251
|
+
}
|
|
1252
|
+
const normalizedExpected = normalizeWhitespace(expected.value);
|
|
1253
|
+
if (exact) {
|
|
1254
|
+
return normalizedActual === normalizedExpected;
|
|
1255
|
+
}
|
|
1256
|
+
return normalizedActual.toLowerCase().includes(normalizedExpected.toLowerCase());
|
|
1257
|
+
};
|
|
1258
|
+
const query = ${serializedQuery};
|
|
1259
|
+
const nodes = Array.from(querySelectorAllDeep(document, "*"));
|
|
1260
|
+
const selectorMatches = () => {
|
|
1261
|
+
if (query.kind !== "selector") {
|
|
1262
|
+
return [];
|
|
1263
|
+
}
|
|
1264
|
+
if (query.selector.includes(">>>")) {
|
|
1265
|
+
return querySelectorAllDeep(document, query.selector);
|
|
1266
|
+
}
|
|
1267
|
+
if (query.parsed?.type === "xpath") {
|
|
1268
|
+
const result = document.evaluate(query.parsed.value, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
1269
|
+
const list = [];
|
|
1270
|
+
for (let i = 0; i < result.snapshotLength; i += 1) {
|
|
1271
|
+
const item = result.snapshotItem(i);
|
|
1272
|
+
if (item instanceof Element) {
|
|
1273
|
+
list.push(item);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return list;
|
|
1277
|
+
}
|
|
1278
|
+
return Array.from(document.querySelectorAll(query.selector));
|
|
1279
|
+
};
|
|
1280
|
+
const selectorMatchSet = selectorMatches();
|
|
1281
|
+
const matches = nodes.filter((el) => {
|
|
1282
|
+
if (!(el instanceof Element)) return false;
|
|
1283
|
+
if (query.kind === "selector") {
|
|
1284
|
+
return selectorMatchSet.includes(el);
|
|
1285
|
+
}
|
|
1286
|
+
if (query.kind === "text") {
|
|
1287
|
+
const text = textFromElement(el);
|
|
1288
|
+
return matchText(text, query.text, Boolean(query.options?.exact));
|
|
1289
|
+
}
|
|
1290
|
+
const role = getImplicitRole(el);
|
|
1291
|
+
if (!role || role !== query.role) {
|
|
1292
|
+
return false;
|
|
1293
|
+
}
|
|
1294
|
+
if (!query.options?.includeHidden && isHidden(el)) {
|
|
1295
|
+
return false;
|
|
1296
|
+
}
|
|
1297
|
+
if (query.options?.name == null) {
|
|
1298
|
+
return true;
|
|
1299
|
+
}
|
|
1300
|
+
const name = getLabelText(el) || textFromElement(el);
|
|
1301
|
+
return matchName(name, query.options.name, Boolean(query.options?.exact));
|
|
1302
|
+
});
|
|
1303
|
+
const textMatches = query.kind === "text"
|
|
1304
|
+
? matches.filter((el) => !matches.some((other) => other !== el && el.contains(other)))
|
|
1305
|
+
: matches;
|
|
1306
|
+
const elements = ${all ? "textMatches" : "textMatches.slice(0, 1)"};
|
|
1307
|
+
const el = elements[0] || null;
|
|
1308
|
+
${body}
|
|
1309
|
+
})()`;
|
|
1310
|
+
}
|
|
1311
|
+
serializeLocatorQuery(query) {
|
|
1312
|
+
switch (query.kind) {
|
|
1313
|
+
case "selector":
|
|
1314
|
+
return JSON.stringify({ kind: "selector", selector: query.selector, options: query.options, parsed: parseSelector(query.selector) });
|
|
1315
|
+
case "text":
|
|
1316
|
+
return JSON.stringify({
|
|
1317
|
+
kind: "text",
|
|
1318
|
+
text: this.serializeTextQuery(query.text),
|
|
1319
|
+
options: query.options
|
|
1320
|
+
});
|
|
1321
|
+
case "role":
|
|
1322
|
+
return JSON.stringify({
|
|
1323
|
+
kind: "role",
|
|
1324
|
+
role: query.role,
|
|
1325
|
+
options: query.options ? {
|
|
1326
|
+
...query.options,
|
|
1327
|
+
name: query.options.name != null ? this.serializeTextQuery(query.options.name) : void 0
|
|
1328
|
+
} : void 0
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
serializeTextQuery(text) {
|
|
1333
|
+
if (text instanceof RegExp) {
|
|
1334
|
+
return { kind: "regex", source: text.source, flags: text.flags.replace("g", "") };
|
|
1335
|
+
}
|
|
1336
|
+
return { kind: "string", value: text };
|
|
1337
|
+
}
|
|
852
1338
|
async performClick(selector, options, isDouble) {
|
|
853
1339
|
const start = Date.now();
|
|
854
1340
|
const actionName = isDouble ? "dblclick" : "click";
|
|
@@ -1126,7 +1612,13 @@ var Page = class {
|
|
|
1126
1612
|
return null;
|
|
1127
1613
|
}
|
|
1128
1614
|
locator(selector) {
|
|
1129
|
-
return
|
|
1615
|
+
return this.mainFrame().locator(selector);
|
|
1616
|
+
}
|
|
1617
|
+
getByText(text, options = {}) {
|
|
1618
|
+
return this.mainFrame().getByText(text, options);
|
|
1619
|
+
}
|
|
1620
|
+
getByRole(role, options = {}) {
|
|
1621
|
+
return this.mainFrame().getByRole(role, options);
|
|
1130
1622
|
}
|
|
1131
1623
|
async goto(url, options = {}) {
|
|
1132
1624
|
ensureAllowedUrl(url, { allowFileUrl: options.allowFileUrl });
|
|
@@ -1362,42 +1854,42 @@ ${document.documentElement.outerHTML}`;
|
|
|
1362
1854
|
|
|
1363
1855
|
// src/assert/expect.ts
|
|
1364
1856
|
var ElementExpectation = class _ElementExpectation {
|
|
1365
|
-
|
|
1366
|
-
selector;
|
|
1857
|
+
target;
|
|
1367
1858
|
options;
|
|
1368
1859
|
negate;
|
|
1369
1860
|
events;
|
|
1370
|
-
constructor(
|
|
1371
|
-
this.
|
|
1372
|
-
this.selector = selector;
|
|
1861
|
+
constructor(target, options, negate, events) {
|
|
1862
|
+
this.target = target;
|
|
1373
1863
|
this.options = options;
|
|
1374
1864
|
this.negate = negate;
|
|
1375
1865
|
this.events = events;
|
|
1376
1866
|
}
|
|
1377
1867
|
get not() {
|
|
1378
|
-
return new _ElementExpectation(this.
|
|
1868
|
+
return new _ElementExpectation(this.target, this.options, !this.negate, this.events);
|
|
1379
1869
|
}
|
|
1380
1870
|
async toExist() {
|
|
1381
1871
|
return this.assert(async () => {
|
|
1382
|
-
const exists = await this.
|
|
1872
|
+
const exists = await this.target.exists();
|
|
1383
1873
|
return this.negate ? !exists : exists;
|
|
1384
1874
|
}, this.negate ? "Expected element not to exist" : "Expected element to exist");
|
|
1385
1875
|
}
|
|
1386
1876
|
async toBeVisible() {
|
|
1387
1877
|
return this.assert(async () => {
|
|
1388
|
-
const visible = await this.
|
|
1878
|
+
const visible = await this.target.isVisible();
|
|
1879
|
+
if (visible == null) return this.negate ? true : false;
|
|
1389
1880
|
return this.negate ? !visible : visible;
|
|
1390
1881
|
}, this.negate ? "Expected element not to be visible" : "Expected element to be visible");
|
|
1391
1882
|
}
|
|
1392
1883
|
async toBeHidden() {
|
|
1393
1884
|
return this.assert(async () => {
|
|
1394
|
-
const visible = await this.
|
|
1885
|
+
const visible = await this.target.isVisible();
|
|
1886
|
+
if (visible == null) return this.negate ? true : false;
|
|
1395
1887
|
return this.negate ? visible : !visible;
|
|
1396
1888
|
}, this.negate ? "Expected element not to be hidden" : "Expected element to be hidden");
|
|
1397
1889
|
}
|
|
1398
1890
|
async toBeEnabled() {
|
|
1399
1891
|
return this.assert(async () => {
|
|
1400
|
-
const enabled = await this.
|
|
1892
|
+
const enabled = await this.target.isEnabled();
|
|
1401
1893
|
if (enabled == null) {
|
|
1402
1894
|
return this.negate ? true : false;
|
|
1403
1895
|
}
|
|
@@ -1406,7 +1898,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1406
1898
|
}
|
|
1407
1899
|
async toBeDisabled() {
|
|
1408
1900
|
return this.assert(async () => {
|
|
1409
|
-
const enabled = await this.
|
|
1901
|
+
const enabled = await this.target.isEnabled();
|
|
1410
1902
|
if (enabled == null) {
|
|
1411
1903
|
return this.negate ? true : false;
|
|
1412
1904
|
}
|
|
@@ -1416,7 +1908,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1416
1908
|
}
|
|
1417
1909
|
async toBeChecked() {
|
|
1418
1910
|
return this.assert(async () => {
|
|
1419
|
-
const checked = await this.
|
|
1911
|
+
const checked = await this.target.isChecked();
|
|
1420
1912
|
if (checked == null) {
|
|
1421
1913
|
return this.negate ? true : false;
|
|
1422
1914
|
}
|
|
@@ -1425,7 +1917,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1425
1917
|
}
|
|
1426
1918
|
async toBeUnchecked() {
|
|
1427
1919
|
return this.assert(async () => {
|
|
1428
|
-
const checked = await this.
|
|
1920
|
+
const checked = await this.target.isChecked();
|
|
1429
1921
|
if (checked == null) {
|
|
1430
1922
|
return this.negate ? true : false;
|
|
1431
1923
|
}
|
|
@@ -1436,7 +1928,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1436
1928
|
async toHaveText(textOrRegex) {
|
|
1437
1929
|
const expected = textOrRegex;
|
|
1438
1930
|
return this.assert(async () => {
|
|
1439
|
-
const text = await this.
|
|
1931
|
+
const text = await this.target.text();
|
|
1440
1932
|
if (text == null) {
|
|
1441
1933
|
return this.negate ? true : false;
|
|
1442
1934
|
}
|
|
@@ -1447,7 +1939,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1447
1939
|
async toHaveExactText(textOrRegex) {
|
|
1448
1940
|
const expected = textOrRegex;
|
|
1449
1941
|
return this.assert(async () => {
|
|
1450
|
-
const text = await this.
|
|
1942
|
+
const text = await this.target.text();
|
|
1451
1943
|
if (text == null) {
|
|
1452
1944
|
return this.negate ? true : false;
|
|
1453
1945
|
}
|
|
@@ -1458,7 +1950,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1458
1950
|
async toContainText(textOrRegex) {
|
|
1459
1951
|
const expected = textOrRegex;
|
|
1460
1952
|
return this.assert(async () => {
|
|
1461
|
-
const text = await this.
|
|
1953
|
+
const text = await this.target.text();
|
|
1462
1954
|
if (text == null) {
|
|
1463
1955
|
return this.negate ? true : false;
|
|
1464
1956
|
}
|
|
@@ -1469,7 +1961,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1469
1961
|
async toHaveValue(valueOrRegex) {
|
|
1470
1962
|
const expected = valueOrRegex;
|
|
1471
1963
|
return this.assert(async () => {
|
|
1472
|
-
const value = await this.
|
|
1964
|
+
const value = await this.target.value();
|
|
1473
1965
|
if (value == null) {
|
|
1474
1966
|
return this.negate ? true : false;
|
|
1475
1967
|
}
|
|
@@ -1480,7 +1972,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1480
1972
|
async toHaveAttribute(name, valueOrRegex) {
|
|
1481
1973
|
const expected = valueOrRegex;
|
|
1482
1974
|
return this.assert(async () => {
|
|
1483
|
-
const value = await this.
|
|
1975
|
+
const value = await this.target.attribute(name);
|
|
1484
1976
|
if (expected === void 0) {
|
|
1485
1977
|
const exists = value != null;
|
|
1486
1978
|
return this.negate ? !exists : exists;
|
|
@@ -1500,7 +1992,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1500
1992
|
}
|
|
1501
1993
|
async toHaveCount(expected) {
|
|
1502
1994
|
return this.assert(async () => {
|
|
1503
|
-
const count = await this.
|
|
1995
|
+
const count = await this.target.count();
|
|
1504
1996
|
const matches = count === expected;
|
|
1505
1997
|
return this.negate ? !matches : matches;
|
|
1506
1998
|
}, this.negate ? "Expected element count not to match" : "Expected element count to match", { expected });
|
|
@@ -1508,7 +2000,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1508
2000
|
async toHaveClass(nameOrRegex) {
|
|
1509
2001
|
const expected = nameOrRegex;
|
|
1510
2002
|
return this.assert(async () => {
|
|
1511
|
-
const classes = await this.
|
|
2003
|
+
const classes = await this.target.classes();
|
|
1512
2004
|
if (classes == null) {
|
|
1513
2005
|
return this.negate ? true : false;
|
|
1514
2006
|
}
|
|
@@ -1518,7 +2010,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1518
2010
|
}
|
|
1519
2011
|
async toHaveClasses(expected) {
|
|
1520
2012
|
return this.assert(async () => {
|
|
1521
|
-
const classes = await this.
|
|
2013
|
+
const classes = await this.target.classes();
|
|
1522
2014
|
if (classes == null) {
|
|
1523
2015
|
return this.negate ? true : false;
|
|
1524
2016
|
}
|
|
@@ -1529,7 +2021,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1529
2021
|
async toHaveCss(property, valueOrRegex) {
|
|
1530
2022
|
const expected = valueOrRegex;
|
|
1531
2023
|
return this.assert(async () => {
|
|
1532
|
-
const value = await this.
|
|
2024
|
+
const value = await this.target.css(property);
|
|
1533
2025
|
if (value == null) {
|
|
1534
2026
|
return this.negate ? true : false;
|
|
1535
2027
|
}
|
|
@@ -1540,7 +2032,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1540
2032
|
}
|
|
1541
2033
|
async toHaveFocus() {
|
|
1542
2034
|
return this.assert(async () => {
|
|
1543
|
-
const focused = await this.
|
|
2035
|
+
const focused = await this.target.hasFocus();
|
|
1544
2036
|
if (focused == null) {
|
|
1545
2037
|
return this.negate ? true : false;
|
|
1546
2038
|
}
|
|
@@ -1549,7 +2041,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1549
2041
|
}
|
|
1550
2042
|
async toBeInViewport(options = {}) {
|
|
1551
2043
|
return this.assert(async () => {
|
|
1552
|
-
const inViewport = await this.
|
|
2044
|
+
const inViewport = await this.target.isInViewport(Boolean(options.fully));
|
|
1553
2045
|
if (inViewport == null) {
|
|
1554
2046
|
return this.negate ? true : false;
|
|
1555
2047
|
}
|
|
@@ -1558,7 +2050,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1558
2050
|
}
|
|
1559
2051
|
async toBeEditable() {
|
|
1560
2052
|
return this.assert(async () => {
|
|
1561
|
-
const editable = await this.
|
|
2053
|
+
const editable = await this.target.isEditable();
|
|
1562
2054
|
if (editable == null) {
|
|
1563
2055
|
return this.negate ? true : false;
|
|
1564
2056
|
}
|
|
@@ -1568,7 +2060,7 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1568
2060
|
async assert(predicate, message, details = {}) {
|
|
1569
2061
|
const timeoutMs = this.options.timeoutMs ?? 3e4;
|
|
1570
2062
|
const start = Date.now();
|
|
1571
|
-
this.events.emit("assertion:start", { name: message, selector: this.
|
|
2063
|
+
this.events.emit("assertion:start", { name: message, selector: this.target.label, frameId: this.target.frameId });
|
|
1572
2064
|
let lastState;
|
|
1573
2065
|
try {
|
|
1574
2066
|
await waitFor(async () => {
|
|
@@ -1578,13 +2070,51 @@ var ElementExpectation = class _ElementExpectation {
|
|
|
1578
2070
|
}, { timeoutMs, description: message });
|
|
1579
2071
|
} catch {
|
|
1580
2072
|
const duration2 = Date.now() - start;
|
|
1581
|
-
this.events.emit("assertion:end", { name: message, selector: this.
|
|
1582
|
-
throw new AssertionError(message, { selector: this.
|
|
2073
|
+
this.events.emit("assertion:end", { name: message, selector: this.target.label, frameId: this.target.frameId, durationMs: duration2, status: "failed" });
|
|
2074
|
+
throw new AssertionError(message, { selector: this.target.label, timeoutMs, lastState: { lastState, ...details } });
|
|
1583
2075
|
}
|
|
1584
2076
|
const duration = Date.now() - start;
|
|
1585
|
-
this.events.emit("assertion:end", { name: message, selector: this.
|
|
2077
|
+
this.events.emit("assertion:end", { name: message, selector: this.target.label, frameId: this.target.frameId, durationMs: duration, status: "passed" });
|
|
1586
2078
|
}
|
|
1587
2079
|
};
|
|
2080
|
+
function frameTarget(frame, selector, options) {
|
|
2081
|
+
return {
|
|
2082
|
+
label: selector,
|
|
2083
|
+
frameId: frame.id,
|
|
2084
|
+
exists: () => frame.exists(selector, options),
|
|
2085
|
+
isVisible: () => frame.isVisible(selector, options),
|
|
2086
|
+
isEnabled: () => frame.isEnabled(selector, options),
|
|
2087
|
+
isChecked: () => frame.isChecked(selector, options),
|
|
2088
|
+
text: () => frame.text(selector, options),
|
|
2089
|
+
value: () => frame.value(selector, options),
|
|
2090
|
+
attribute: (name) => frame.attribute(selector, name, options),
|
|
2091
|
+
count: () => frame.count(selector, options),
|
|
2092
|
+
classes: () => frame.classes(selector, options),
|
|
2093
|
+
css: (property) => frame.css(selector, property, options),
|
|
2094
|
+
hasFocus: () => frame.hasFocus(selector, options),
|
|
2095
|
+
isInViewport: (fully = false) => frame.isInViewport(selector, options, fully),
|
|
2096
|
+
isEditable: () => frame.isEditable(selector, options)
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function locatorTarget(locator) {
|
|
2100
|
+
return {
|
|
2101
|
+
label: locator.describe(),
|
|
2102
|
+
frameId: locator.getFrameId(),
|
|
2103
|
+
exists: () => locator.exists(),
|
|
2104
|
+
isVisible: () => locator.isVisible(),
|
|
2105
|
+
isEnabled: () => locator.isEnabled(),
|
|
2106
|
+
isChecked: () => locator.isChecked(),
|
|
2107
|
+
text: () => locator.text(),
|
|
2108
|
+
value: () => locator.value(),
|
|
2109
|
+
attribute: (name) => locator.attribute(name),
|
|
2110
|
+
count: () => locator.count(),
|
|
2111
|
+
classes: () => locator.classes(),
|
|
2112
|
+
css: (property) => locator.css(property),
|
|
2113
|
+
hasFocus: () => locator.hasFocus(),
|
|
2114
|
+
isInViewport: (fully = false) => locator.isInViewport(fully),
|
|
2115
|
+
isEditable: () => locator.isEditable()
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
1588
2118
|
var ExpectFrame = class {
|
|
1589
2119
|
frame;
|
|
1590
2120
|
events;
|
|
@@ -1593,25 +2123,31 @@ var ExpectFrame = class {
|
|
|
1593
2123
|
this.events = events;
|
|
1594
2124
|
}
|
|
1595
2125
|
element(selector, options = {}) {
|
|
1596
|
-
return new ElementExpectation(this.frame, selector, options, false, this.events);
|
|
2126
|
+
return new ElementExpectation(frameTarget(this.frame, selector, options), options, false, this.events);
|
|
1597
2127
|
}
|
|
1598
2128
|
};
|
|
1599
|
-
function expect(
|
|
2129
|
+
function expect(target) {
|
|
2130
|
+
if (target instanceof Locator) {
|
|
2131
|
+
return new ElementExpectation(locatorTarget(target), {}, false, target.getEvents());
|
|
2132
|
+
}
|
|
1600
2133
|
return {
|
|
1601
|
-
element: (selector, options = {}) => new ElementExpectation(
|
|
2134
|
+
element: (selector, options = {}) => new ElementExpectation(frameTarget(target.mainFrame(), selector, options), options, false, target.getEvents()),
|
|
1602
2135
|
frame: (options) => {
|
|
1603
|
-
const frame =
|
|
2136
|
+
const frame = target.frame(options);
|
|
1604
2137
|
if (!frame) {
|
|
1605
2138
|
throw new AssertionError("Frame not found", { selector: JSON.stringify(options) });
|
|
1606
2139
|
}
|
|
1607
|
-
return new ExpectFrame(frame,
|
|
2140
|
+
return new ExpectFrame(frame, target.getEvents());
|
|
1608
2141
|
}
|
|
1609
2142
|
};
|
|
1610
2143
|
}
|
|
1611
|
-
Page.prototype.expect = function(
|
|
2144
|
+
Page.prototype.expect = function(target, options) {
|
|
1612
2145
|
const builder = expect(this);
|
|
1613
|
-
if (
|
|
1614
|
-
return
|
|
2146
|
+
if (target instanceof Locator) {
|
|
2147
|
+
return expect(target);
|
|
2148
|
+
}
|
|
2149
|
+
if (target) {
|
|
2150
|
+
return builder.element(target, options);
|
|
1615
2151
|
}
|
|
1616
2152
|
return builder;
|
|
1617
2153
|
};
|
|
@@ -1630,4 +2166,4 @@ export {
|
|
|
1630
2166
|
AssertionError,
|
|
1631
2167
|
expect
|
|
1632
2168
|
};
|
|
1633
|
-
//# sourceMappingURL=chunk-
|
|
2169
|
+
//# sourceMappingURL=chunk-EIAXMGD5.js.map
|