ex-pw 0.0.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.js ADDED
@@ -0,0 +1,1735 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ apiMatchers: () => apiMatchers,
24
+ asymmetricMatchers: () => asymmetricMatchers,
25
+ default: () => index_default,
26
+ expect: () => expect18,
27
+ generalMatchers: () => generalMatchers,
28
+ locatorMatchers: () => locatorMatchers,
29
+ pageMatchers: () => pageMatchers,
30
+ toBeCamelCase: () => toBeCamelCase,
31
+ toBeCheckable: () => toBeCheckable,
32
+ toBeClickable: () => toBeClickable,
33
+ toBeDateString: () => toBeDateString,
34
+ toBeEmail: () => toBeEmail,
35
+ toBeISODate: () => toBeISODate,
36
+ toBeInvalid: () => toBeInvalid,
37
+ toBeJSON: () => toBeJSON,
38
+ toBeKebabCase: () => toBeKebabCase,
39
+ toBeLowerCase: () => toBeLowerCase,
40
+ toBePascalCase: () => toBePascalCase,
41
+ toBeRequired: () => toBeRequired,
42
+ toBeSnakeCase: () => toBeSnakeCase,
43
+ toBeSorted: () => toBeSorted,
44
+ toBeURL: () => toBeURL,
45
+ toBeUUID: () => toBeUUID,
46
+ toBeUpperCase: () => toBeUpperCase,
47
+ toBeValid: () => toBeValid,
48
+ toBeWithinRange: () => toBeWithinRange,
49
+ toEndWith: () => toEndWith,
50
+ toHaveClipboardText: () => toHaveClipboardText,
51
+ toHaveConsoleMessage: () => toHaveConsoleMessage,
52
+ toHaveCookie: () => toHaveCookie,
53
+ toHaveCountGreaterThan: () => toHaveCountGreaterThan,
54
+ toHaveCountGreaterThanOrEqual: () => toHaveCountGreaterThanOrEqual,
55
+ toHaveCountLessThan: () => toHaveCountLessThan,
56
+ toHaveCountLessThanOrEqual: () => toHaveCountLessThanOrEqual,
57
+ toHaveHeader: () => toHaveHeader,
58
+ toHaveHeight: () => toHaveHeight,
59
+ toHaveLoadedImage: () => toHaveLoadedImage,
60
+ toHaveLocalStorage: () => toHaveLocalStorage,
61
+ toHaveNoErrors: () => toHaveNoErrors,
62
+ toHavePageError: () => toHavePageError,
63
+ toHaveRequest: () => toHaveRequest,
64
+ toHaveSessionStorage: () => toHaveSessionStorage,
65
+ toHaveSize: () => toHaveSize,
66
+ toHaveStatus: () => toHaveStatus,
67
+ toHaveWidth: () => toHaveWidth,
68
+ toMatchJSON: () => toMatchJSON,
69
+ toMatchSchema: () => toMatchSchema,
70
+ toRespondWithin: () => toRespondWithin,
71
+ toStartWith: () => toStartWith
72
+ });
73
+ module.exports = __toCommonJS(index_exports);
74
+ var import_test18 = require("@playwright/test");
75
+
76
+ // src/matchers/locator/toBeClickable.ts
77
+ async function toBeClickable(locator, options = {}) {
78
+ const assertionName = "toBeClickable";
79
+ const timeout = options.timeout ?? this.timeout;
80
+ let pass = false;
81
+ let errorMessage = "";
82
+ try {
83
+ await locator.click({ trial: true, timeout });
84
+ pass = true;
85
+ } catch (error) {
86
+ pass = false;
87
+ errorMessage = error instanceof Error ? error.message : String(error);
88
+ }
89
+ const message = () => {
90
+ if (this.isNot) {
91
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
92
+ isNot: this.isNot
93
+ }) + `
94
+
95
+ Expected: element to NOT be clickable
96
+ Received: element is clickable`;
97
+ }
98
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
99
+ isNot: this.isNot
100
+ }) + `
101
+
102
+ Expected: element '${locator}' to be clickable
103
+ Received: element is not clickable
104
+ ` + (errorMessage ? `
105
+ Error: ${errorMessage}` : "");
106
+ };
107
+ return {
108
+ pass,
109
+ message,
110
+ name: assertionName
111
+ };
112
+ }
113
+
114
+ // src/matchers/locator/toBeCheckable.ts
115
+ async function toBeCheckable(locator, options = {}) {
116
+ const assertionName = "toBeCheckable";
117
+ const timeout = options.timeout ?? this.timeout;
118
+ let pass = false;
119
+ let errorMessage = "";
120
+ try {
121
+ await locator.check({ trial: true, timeout });
122
+ pass = true;
123
+ } catch (error) {
124
+ pass = false;
125
+ errorMessage = error instanceof Error ? error.message : String(error);
126
+ }
127
+ const message = () => {
128
+ if (this.isNot) {
129
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
130
+ isNot: this.isNot
131
+ }) + `
132
+
133
+ Expected: element '${locator}' to NOT be checkable
134
+ Received: element is checkable`;
135
+ }
136
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
137
+ isNot: this.isNot
138
+ }) + `
139
+
140
+ Expected: element '${locator}' to be checkable
141
+ Received: element is not checkable
142
+ ` + (errorMessage ? `
143
+ Error: ${errorMessage}` : "");
144
+ };
145
+ return {
146
+ pass,
147
+ message,
148
+ name: assertionName
149
+ };
150
+ }
151
+
152
+ // src/matchers/locator/toBeRequired.ts
153
+ var import_test = require("@playwright/test");
154
+ async function toBeRequired(locator, options = {}) {
155
+ const assertionName = "toBeRequired";
156
+ const timeout = options.timeout ?? this.timeout;
157
+ const intervals = options.intervals;
158
+ let pass = false;
159
+ let errorMessage = "";
160
+ try {
161
+ await import_test.expect.poll(
162
+ async () => {
163
+ const hasRequiredAttr = await locator.getAttribute("required");
164
+ if (hasRequiredAttr !== null) return true;
165
+ const ariaRequired = await locator.getAttribute("aria-required");
166
+ if (ariaRequired === "true") return true;
167
+ const isRequired = await locator.evaluate((el) => {
168
+ if ("required" in el) {
169
+ return el.required;
170
+ }
171
+ return false;
172
+ });
173
+ return isRequired;
174
+ },
175
+ { timeout, intervals }
176
+ ).toBe(true);
177
+ pass = true;
178
+ } catch (error) {
179
+ pass = false;
180
+ errorMessage = error instanceof Error ? error.message : String(error);
181
+ }
182
+ const message = () => {
183
+ if (this.isNot) {
184
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
185
+ isNot: this.isNot
186
+ }) + `
187
+
188
+ Expected: element '${locator}' to NOT be required
189
+ Received: element is required`;
190
+ }
191
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
192
+ isNot: this.isNot
193
+ }) + `
194
+
195
+ Expected: element '${locator}' to be required
196
+ Received: element is not required
197
+ ` + (errorMessage ? `
198
+ Details: ${errorMessage}` : "");
199
+ };
200
+ return {
201
+ pass,
202
+ message,
203
+ name: assertionName
204
+ };
205
+ }
206
+
207
+ // src/matchers/locator/toBeInvalid.ts
208
+ var import_test2 = require("@playwright/test");
209
+ var INVALID_CLASSES = [
210
+ "ng-invalid",
211
+ // Angular
212
+ "is-invalid",
213
+ // Bootstrap
214
+ "error",
215
+ // Common pattern
216
+ "has-error",
217
+ // Another common pattern
218
+ "invalid"
219
+ // Generic
220
+ ];
221
+ async function toBeInvalid(locator, options = {}) {
222
+ const assertionName = "toBeInvalid";
223
+ const timeout = options.timeout ?? this.timeout;
224
+ const intervals = options.intervals;
225
+ let pass = false;
226
+ let errorMessage = "";
227
+ try {
228
+ await import_test2.expect.poll(
229
+ async () => {
230
+ const ariaInvalid = await locator.getAttribute("aria-invalid");
231
+ if (ariaInvalid === "true") return true;
232
+ const isNativeInvalid = await locator.evaluate((el) => {
233
+ if ("validity" in el) {
234
+ return !el.validity.valid;
235
+ }
236
+ return false;
237
+ });
238
+ if (isNativeInvalid) return true;
239
+ const classAttr = await locator.getAttribute("class");
240
+ if (classAttr) {
241
+ const classes = classAttr.split(/\s+/);
242
+ for (const invalidClass of INVALID_CLASSES) {
243
+ if (classes.includes(invalidClass)) return true;
244
+ }
245
+ }
246
+ return false;
247
+ },
248
+ { timeout, intervals }
249
+ ).toBe(true);
250
+ pass = true;
251
+ } catch (error) {
252
+ pass = false;
253
+ errorMessage = error instanceof Error ? error.message : String(error);
254
+ }
255
+ const message = () => {
256
+ if (this.isNot) {
257
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
258
+ isNot: this.isNot
259
+ }) + `
260
+
261
+ Expected: element '${locator}' to NOT be invalid
262
+ Received: element is invalid`;
263
+ }
264
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
265
+ isNot: this.isNot
266
+ }) + `
267
+
268
+ Expected: element '${locator}' to be invalid
269
+ Received: element is valid
270
+ ` + (errorMessage ? `
271
+ Details: ${errorMessage}` : "");
272
+ };
273
+ return {
274
+ pass,
275
+ message,
276
+ name: assertionName
277
+ };
278
+ }
279
+
280
+ // src/matchers/locator/toBeValid.ts
281
+ var import_test3 = require("@playwright/test");
282
+ var INVALID_CLASSES2 = [
283
+ "ng-invalid",
284
+ // Angular
285
+ "is-invalid",
286
+ // Bootstrap
287
+ "error",
288
+ // Common pattern
289
+ "has-error",
290
+ // Another common pattern
291
+ "invalid"
292
+ // Generic
293
+ ];
294
+ async function toBeValid(locator, options = {}) {
295
+ const assertionName = "toBeValid";
296
+ const timeout = options.timeout ?? this.timeout;
297
+ const intervals = options.intervals;
298
+ let pass = false;
299
+ let errorMessage = "";
300
+ try {
301
+ await import_test3.expect.poll(
302
+ async () => {
303
+ const ariaInvalid = await locator.getAttribute("aria-invalid");
304
+ if (ariaInvalid === "true") return false;
305
+ const hasValidity = await locator.evaluate((el) => "validity" in el);
306
+ if (hasValidity) {
307
+ const isNativeValid = await locator.evaluate((el) => {
308
+ return el.validity.valid;
309
+ });
310
+ if (!isNativeValid) return false;
311
+ }
312
+ const classAttr = await locator.getAttribute("class");
313
+ if (classAttr) {
314
+ const classes = classAttr.split(/\s+/);
315
+ for (const invalidClass of INVALID_CLASSES2) {
316
+ if (classes.includes(invalidClass)) return false;
317
+ }
318
+ }
319
+ return true;
320
+ },
321
+ { timeout, intervals }
322
+ ).toBe(true);
323
+ pass = true;
324
+ } catch (error) {
325
+ pass = false;
326
+ errorMessage = error instanceof Error ? error.message : String(error);
327
+ }
328
+ const message = () => {
329
+ if (this.isNot) {
330
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
331
+ isNot: this.isNot
332
+ }) + `
333
+
334
+ Expected: element '${locator}' to NOT be valid
335
+ Received: element is valid`;
336
+ }
337
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
338
+ isNot: this.isNot
339
+ }) + `
340
+
341
+ Expected: element '${locator}' to be valid
342
+ Received: element is invalid
343
+ ` + (errorMessage ? `
344
+ Details: ${errorMessage}` : "");
345
+ };
346
+ return {
347
+ pass,
348
+ message,
349
+ name: assertionName
350
+ };
351
+ }
352
+
353
+ // src/matchers/locator/toHaveCount.ts
354
+ var import_test4 = require("@playwright/test");
355
+ async function toHaveCountGreaterThan(locator, count, options = {}) {
356
+ const assertionName = "toHaveCountGreaterThan";
357
+ const timeout = options.timeout ?? this.timeout;
358
+ const intervals = options.intervals;
359
+ let pass = false;
360
+ let actualCount = 0;
361
+ try {
362
+ await import_test4.expect.poll(
363
+ async () => {
364
+ actualCount = await locator.count();
365
+ return actualCount;
366
+ },
367
+ { timeout, intervals }
368
+ ).toBeGreaterThan(count);
369
+ pass = true;
370
+ } catch {
371
+ pass = false;
372
+ }
373
+ const message = () => {
374
+ if (this.isNot) {
375
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
376
+ isNot: this.isNot
377
+ }) + `
378
+
379
+ Expected: element '${locator}' count to NOT be greater than ${count}
380
+ Received: ${actualCount}`;
381
+ }
382
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
383
+ isNot: this.isNot
384
+ }) + `
385
+
386
+ Expected: element '${locator}' count to be greater than ${count}
387
+ Received: ${actualCount}`;
388
+ };
389
+ return {
390
+ pass,
391
+ message,
392
+ name: assertionName,
393
+ expected: `> ${count}`,
394
+ actual: actualCount
395
+ };
396
+ }
397
+ async function toHaveCountGreaterThanOrEqual(locator, count, options = {}) {
398
+ const assertionName = "toHaveCountGreaterThanOrEqual";
399
+ const timeout = options.timeout ?? this.timeout;
400
+ const intervals = options.intervals;
401
+ let pass = false;
402
+ let actualCount = 0;
403
+ try {
404
+ await import_test4.expect.poll(
405
+ async () => {
406
+ actualCount = await locator.count();
407
+ return actualCount;
408
+ },
409
+ { timeout, intervals }
410
+ ).toBeGreaterThanOrEqual(count);
411
+ pass = true;
412
+ } catch {
413
+ pass = false;
414
+ }
415
+ const message = () => {
416
+ if (this.isNot) {
417
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
418
+ isNot: this.isNot
419
+ }) + `
420
+
421
+ Expected: element '${locator}' count to NOT be greater than or equal to ${count}
422
+ Received: ${actualCount}`;
423
+ }
424
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
425
+ isNot: this.isNot
426
+ }) + `
427
+
428
+ Expected: element '${locator}' count to be greater than or equal to ${count}
429
+ Received: ${actualCount}`;
430
+ };
431
+ return {
432
+ pass,
433
+ message,
434
+ name: assertionName,
435
+ expected: `>= ${count}`,
436
+ actual: actualCount
437
+ };
438
+ }
439
+ async function toHaveCountLessThan(locator, count, options = {}) {
440
+ const assertionName = "toHaveCountLessThan";
441
+ const timeout = options.timeout ?? this.timeout;
442
+ const intervals = options.intervals;
443
+ let pass = false;
444
+ let actualCount = 0;
445
+ try {
446
+ await import_test4.expect.poll(
447
+ async () => {
448
+ actualCount = await locator.count();
449
+ return actualCount;
450
+ },
451
+ { timeout, intervals }
452
+ ).toBeLessThan(count);
453
+ pass = true;
454
+ } catch {
455
+ pass = false;
456
+ }
457
+ const message = () => {
458
+ if (this.isNot) {
459
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
460
+ isNot: this.isNot
461
+ }) + `
462
+
463
+ Expected: element '${locator}' count to NOT be less than ${count}
464
+ Received: ${actualCount}`;
465
+ }
466
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
467
+ isNot: this.isNot
468
+ }) + `
469
+
470
+ Expected: element '${locator}' count to be less than ${count}
471
+ Received: ${actualCount}`;
472
+ };
473
+ return {
474
+ pass,
475
+ message,
476
+ name: assertionName,
477
+ expected: `< ${count}`,
478
+ actual: actualCount
479
+ };
480
+ }
481
+ async function toHaveCountLessThanOrEqual(locator, count, options = {}) {
482
+ const assertionName = "toHaveCountLessThanOrEqual";
483
+ const timeout = options.timeout ?? this.timeout;
484
+ const intervals = options.intervals;
485
+ let pass = false;
486
+ let actualCount = 0;
487
+ try {
488
+ await import_test4.expect.poll(
489
+ async () => {
490
+ actualCount = await locator.count();
491
+ return actualCount;
492
+ },
493
+ { timeout, intervals }
494
+ ).toBeLessThanOrEqual(count);
495
+ pass = true;
496
+ } catch {
497
+ pass = false;
498
+ }
499
+ const message = () => {
500
+ if (this.isNot) {
501
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
502
+ isNot: this.isNot
503
+ }) + `
504
+
505
+ Expected: element '${locator}' count to NOT be less than or equal to ${count}
506
+ Received: ${actualCount}`;
507
+ }
508
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
509
+ isNot: this.isNot
510
+ }) + `
511
+
512
+ Expected: element '${locator}' count to be less than or equal to ${count}
513
+ Received: ${actualCount}`;
514
+ };
515
+ return {
516
+ pass,
517
+ message,
518
+ name: assertionName,
519
+ expected: `<= ${count}`,
520
+ actual: actualCount
521
+ };
522
+ }
523
+
524
+ // src/matchers/locator/toHaveWidth.ts
525
+ var import_test5 = require("@playwright/test");
526
+ async function toHaveWidth(locator, expected, options) {
527
+ const timeout = options?.timeout ?? this.timeout;
528
+ const intervals = options?.intervals;
529
+ try {
530
+ await import_test5.expect.poll(async () => {
531
+ const box = await locator.boundingBox();
532
+ return box ? box.width : null;
533
+ }, { timeout, intervals }).toBe(expected);
534
+ return {
535
+ message: () => `expected element '${locator}' to have width ${expected}`,
536
+ pass: true
537
+ };
538
+ } catch (e) {
539
+ return {
540
+ message: () => `expected element '${locator}' to have width ${expected}`,
541
+ pass: false
542
+ };
543
+ }
544
+ }
545
+
546
+ // src/matchers/locator/toHaveHeight.ts
547
+ var import_test6 = require("@playwright/test");
548
+ async function toHaveHeight(locator, expected, options) {
549
+ const timeout = options?.timeout ?? this.timeout;
550
+ const intervals = options?.intervals;
551
+ try {
552
+ await import_test6.expect.poll(async () => {
553
+ const box = await locator.boundingBox();
554
+ return box ? box.height : null;
555
+ }, { timeout, intervals }).toBe(expected);
556
+ return {
557
+ message: () => `expected element '${locator}' to have height ${expected}`,
558
+ pass: true
559
+ };
560
+ } catch (e) {
561
+ return {
562
+ message: () => `expected element '${locator}' to have height ${expected}`,
563
+ pass: false
564
+ };
565
+ }
566
+ }
567
+
568
+ // src/matchers/locator/toHaveSize.ts
569
+ var import_test7 = require("@playwright/test");
570
+ async function toHaveSize(locator, width, height, options) {
571
+ const timeout = options?.timeout ?? this.timeout;
572
+ const intervals = options?.intervals;
573
+ try {
574
+ await import_test7.expect.poll(async () => {
575
+ const box = await locator.boundingBox();
576
+ return box ? { width: box.width, height: box.height } : null;
577
+ }, { timeout, intervals }).toEqual({ width, height });
578
+ return {
579
+ message: () => `expected element '${locator}' to have size { width: ${width}, height: ${height} }`,
580
+ pass: true
581
+ };
582
+ } catch (e) {
583
+ return {
584
+ message: () => `expected element '${locator}' to have size { width: ${width}, height: ${height} }`,
585
+ pass: false
586
+ };
587
+ }
588
+ }
589
+
590
+ // src/matchers/locator/toHaveLoadedImage.ts
591
+ var import_test8 = require("@playwright/test");
592
+ async function toHaveLoadedImage(locator, options) {
593
+ const timeout = options?.timeout ?? this.timeout;
594
+ const intervals = options?.intervals;
595
+ try {
596
+ await import_test8.expect.poll(async () => {
597
+ return await locator.evaluate((el) => {
598
+ if (!(el instanceof HTMLImageElement)) {
599
+ throw new Error("Element is not an HTMLImageElement");
600
+ }
601
+ return el.complete && el.naturalWidth > 0;
602
+ });
603
+ }, { timeout, intervals }).toBe(true);
604
+ return {
605
+ message: () => `expected element '${locator}' to have loaded image`,
606
+ pass: true
607
+ };
608
+ } catch (e) {
609
+ if (e.message && e.message.includes("Element is not an HTMLImageElement")) {
610
+ return {
611
+ message: () => `expected element '${locator}' to have loaded image, but it is not an HTMLImageElement`,
612
+ pass: false
613
+ };
614
+ }
615
+ return {
616
+ message: () => `expected element '${locator}' to have loaded image`,
617
+ pass: false
618
+ };
619
+ }
620
+ }
621
+
622
+ // src/matchers/locator/index.ts
623
+ var locatorMatchers = {
624
+ toBeClickable,
625
+ toBeCheckable,
626
+ toBeRequired,
627
+ toBeInvalid,
628
+ toBeValid,
629
+ toHaveCountGreaterThan,
630
+ toHaveCountGreaterThanOrEqual,
631
+ toHaveCountLessThan,
632
+ toHaveCountLessThanOrEqual,
633
+ toHaveWidth,
634
+ toHaveHeight,
635
+ toHaveSize,
636
+ toHaveLoadedImage
637
+ };
638
+
639
+ // src/matchers/page/toHaveNoErrors.ts
640
+ function toHaveNoErrors(testObject, options = {}) {
641
+ const assertionName = "toHaveNoErrors";
642
+ const { ignore } = options;
643
+ const testInfo = testObject.info();
644
+ let errors = testInfo.errors || [];
645
+ if (ignore) {
646
+ errors = errors.filter((error) => {
647
+ const message2 = error.message || "";
648
+ return !ignore.test(message2);
649
+ });
650
+ }
651
+ const pass = errors.length === 0;
652
+ const errorMessages = errors.map((e, i) => ` ${i + 1}. ${e.message || "Unknown error"}`).join("\n");
653
+ const message = () => {
654
+ if (this.isNot) {
655
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
656
+ isNot: this.isNot
657
+ }) + `
658
+
659
+ Expected: to have errors
660
+ Received: no errors`;
661
+ }
662
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
663
+ isNot: this.isNot
664
+ }) + `
665
+
666
+ Expected: no errors
667
+ Received: ${errors.length} error(s)
668
+
669
+ ` + errorMessages;
670
+ };
671
+ return {
672
+ pass,
673
+ message,
674
+ name: assertionName,
675
+ expected: 0,
676
+ actual: errors.length
677
+ };
678
+ }
679
+
680
+ // src/matchers/page/toHaveCookie.ts
681
+ var import_test9 = require("@playwright/test");
682
+ async function toHaveCookie(page, name, options = {}) {
683
+ const assertionName = "toHaveCookie";
684
+ const { value, domain, timeout = this.timeout, intervals } = options;
685
+ let pass = false;
686
+ let actualValue;
687
+ let foundCookie = false;
688
+ try {
689
+ await import_test9.expect.poll(
690
+ async () => {
691
+ const cookies = await page.context().cookies();
692
+ const cookie = cookies.find((c) => {
693
+ if (c.name !== name) return false;
694
+ if (domain && c.domain !== domain) return false;
695
+ return true;
696
+ });
697
+ if (!cookie) {
698
+ foundCookie = false;
699
+ actualValue = void 0;
700
+ return false;
701
+ }
702
+ foundCookie = true;
703
+ actualValue = cookie.value;
704
+ if (value !== void 0) {
705
+ if (typeof value === "string") {
706
+ return cookie.value === value;
707
+ } else {
708
+ return value.test(cookie.value);
709
+ }
710
+ }
711
+ return true;
712
+ },
713
+ { timeout, intervals }
714
+ ).toBe(true);
715
+ pass = true;
716
+ } catch {
717
+ pass = false;
718
+ }
719
+ const expectedDesc = value ? `cookie "${name}" with value ${value instanceof RegExp ? value : `"${value}"`}` : `cookie "${name}"`;
720
+ const message = () => {
721
+ if (this.isNot) {
722
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
723
+ isNot: this.isNot
724
+ }) + `
725
+
726
+ Expected: NOT to have ${expectedDesc}
727
+ Received: cookie found with value "${actualValue}"`;
728
+ }
729
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
730
+ isNot: this.isNot
731
+ }) + `
732
+
733
+ Expected: ${expectedDesc}
734
+ ` + (foundCookie ? `Received: cookie found with value "${actualValue}"` : `Received: cookie not found`);
735
+ };
736
+ return {
737
+ pass,
738
+ message,
739
+ name: assertionName,
740
+ expected: value ?? name,
741
+ actual: actualValue
742
+ };
743
+ }
744
+
745
+ // src/matchers/page/toHaveLocalStorage.ts
746
+ var import_test10 = require("@playwright/test");
747
+
748
+ // src/utils/matcherUtils.ts
749
+ function formatValue(value) {
750
+ if (value === null) return "null";
751
+ if (value === void 0) return "undefined";
752
+ if (typeof value === "string") return `"${value}"`;
753
+ if (typeof value === "object") {
754
+ try {
755
+ return JSON.stringify(value, null, 2);
756
+ } catch {
757
+ return String(value);
758
+ }
759
+ }
760
+ return String(value);
761
+ }
762
+
763
+ // src/matchers/page/toHaveLocalStorage.ts
764
+ async function toHaveLocalStorage(page, key, options = {}) {
765
+ const assertionName = "toHaveLocalStorage";
766
+ const { value, timeout = this.timeout, intervals } = options;
767
+ let pass = false;
768
+ let actualValue;
769
+ let foundKey = false;
770
+ try {
771
+ await import_test10.expect.poll(
772
+ async () => {
773
+ const storageState = await page.context().storageState();
774
+ const pageUrl = page.url();
775
+ let origin;
776
+ try {
777
+ origin = new URL(pageUrl).origin;
778
+ } catch {
779
+ origin = pageUrl;
780
+ }
781
+ const originStorage = storageState.origins.find(
782
+ (o) => o.origin === origin
783
+ );
784
+ if (!originStorage) {
785
+ foundKey = false;
786
+ actualValue = void 0;
787
+ return false;
788
+ }
789
+ const item = originStorage.localStorage.find((ls) => ls.name === key);
790
+ if (!item) {
791
+ foundKey = false;
792
+ actualValue = void 0;
793
+ return false;
794
+ }
795
+ foundKey = true;
796
+ try {
797
+ actualValue = JSON.parse(item.value);
798
+ } catch {
799
+ actualValue = item.value;
800
+ }
801
+ if (value !== void 0) {
802
+ try {
803
+ (0, import_test10.expect)(actualValue).toEqual(value);
804
+ return true;
805
+ } catch {
806
+ return false;
807
+ }
808
+ }
809
+ return true;
810
+ },
811
+ { timeout, intervals }
812
+ ).toBe(true);
813
+ pass = true;
814
+ } catch {
815
+ pass = false;
816
+ }
817
+ const expectedDesc = value !== void 0 ? `localStorage key "${key}" with value ${formatValue(value)}` : `localStorage key "${key}"`;
818
+ const message = () => {
819
+ if (this.isNot) {
820
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
821
+ isNot: this.isNot
822
+ }) + `
823
+
824
+ Expected: NOT to have ${expectedDesc}
825
+ Received: key found with value ${formatValue(actualValue)}`;
826
+ }
827
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
828
+ isNot: this.isNot
829
+ }) + `
830
+
831
+ Expected: ${expectedDesc}
832
+ ` + (foundKey ? `Received: key found with value ${formatValue(actualValue)}` : `Received: key not found`);
833
+ };
834
+ return {
835
+ pass,
836
+ message,
837
+ name: assertionName,
838
+ expected: value ?? key,
839
+ actual: actualValue
840
+ };
841
+ }
842
+
843
+ // src/matchers/page/toHaveSessionStorage.ts
844
+ var import_test11 = require("@playwright/test");
845
+ async function toHaveSessionStorage(page, key, options = {}) {
846
+ const assertionName = "toHaveSessionStorage";
847
+ const { value, timeout = this.timeout, intervals } = options;
848
+ let pass = false;
849
+ let actualValue;
850
+ let foundKey = false;
851
+ try {
852
+ await import_test11.expect.poll(
853
+ async () => {
854
+ const rawValue = await page.evaluate((k) => {
855
+ return window.sessionStorage.getItem(k);
856
+ }, key);
857
+ if (rawValue === null) {
858
+ foundKey = false;
859
+ actualValue = void 0;
860
+ return false;
861
+ }
862
+ foundKey = true;
863
+ try {
864
+ actualValue = JSON.parse(rawValue);
865
+ } catch {
866
+ actualValue = rawValue;
867
+ }
868
+ if (value !== void 0) {
869
+ try {
870
+ (0, import_test11.expect)(actualValue).toEqual(value);
871
+ return true;
872
+ } catch {
873
+ return false;
874
+ }
875
+ }
876
+ return true;
877
+ },
878
+ { timeout, intervals }
879
+ ).toBe(true);
880
+ pass = true;
881
+ } catch {
882
+ pass = false;
883
+ }
884
+ const expectedDesc = value !== void 0 ? `sessionStorage key "${key}" with value ${formatValue(value)}` : `sessionStorage key "${key}"`;
885
+ const message = () => {
886
+ if (this.isNot) {
887
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
888
+ isNot: this.isNot
889
+ }) + `
890
+
891
+ Expected: NOT to have ${expectedDesc}
892
+ Received: key found with value ${formatValue(actualValue)}`;
893
+ }
894
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
895
+ isNot: this.isNot
896
+ }) + `
897
+
898
+ Expected: ${expectedDesc}
899
+ ` + (foundKey ? `Received: key found with value ${formatValue(actualValue)}` : `Received: key not found`);
900
+ };
901
+ return {
902
+ pass,
903
+ message,
904
+ name: assertionName,
905
+ expected: value ?? key,
906
+ actual: actualValue
907
+ };
908
+ }
909
+
910
+ // src/matchers/page/toHaveClipboardText.ts
911
+ var import_test12 = require("@playwright/test");
912
+ async function toHaveClipboardText(page, expected, options) {
913
+ const timeout = options?.timeout ?? this.timeout;
914
+ const intervals = options?.intervals;
915
+ try {
916
+ const assertion = import_test12.expect.poll(async () => {
917
+ return await page.evaluate(() => navigator.clipboard.readText());
918
+ }, { timeout, intervals });
919
+ if (expected instanceof RegExp) {
920
+ await assertion.toMatch(expected);
921
+ } else {
922
+ await assertion.toBe(expected);
923
+ }
924
+ return {
925
+ message: () => `expected clipboard to have text ${expected}`,
926
+ pass: true
927
+ };
928
+ } catch (e) {
929
+ return {
930
+ message: () => `expected clipboard to have text ${expected} but got error or different text: ${e.message}`,
931
+ pass: false
932
+ };
933
+ }
934
+ }
935
+
936
+ // src/matchers/page/toHaveRequest.ts
937
+ var import_test13 = require("@playwright/test");
938
+ async function toHaveRequest(page, options = {}) {
939
+ const assertionName = "toHaveRequest";
940
+ const { method, status, url, timeout = this.timeout, intervals } = options;
941
+ let matchedRequest;
942
+ let requests = [];
943
+ let pass = false;
944
+ try {
945
+ await import_test13.expect.poll(
946
+ async () => {
947
+ requests = await page.requests();
948
+ for (const request of requests) {
949
+ let matches = true;
950
+ if (url !== void 0) {
951
+ const requestUrl = request.url();
952
+ if (typeof url === "string") {
953
+ if (!requestUrl.includes(url)) matches = false;
954
+ } else {
955
+ if (!url.test(requestUrl)) matches = false;
956
+ }
957
+ }
958
+ if (matches && method !== void 0) {
959
+ if (request.method().toUpperCase() !== method.toUpperCase()) matches = false;
960
+ }
961
+ if (matches && status !== void 0) {
962
+ const response = await request.response();
963
+ if (!response || response.status() !== status) matches = false;
964
+ }
965
+ if (matches) {
966
+ matchedRequest = request;
967
+ return true;
968
+ }
969
+ }
970
+ return false;
971
+ },
972
+ { timeout, intervals }
973
+ ).toBe(true);
974
+ pass = true;
975
+ } catch {
976
+ pass = false;
977
+ }
978
+ const criteriaDesc = [
979
+ url ? `URL matching ${url instanceof RegExp ? url : `"${url}"`}` : null,
980
+ method ? `method "${method}"` : null,
981
+ status ? `status ${status}` : null
982
+ ].filter(Boolean).join(", ");
983
+ const message = () => {
984
+ if (this.isNot) {
985
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
986
+ isNot: this.isNot
987
+ }) + `
988
+
989
+ Expected: NOT to have request with ${criteriaDesc || "any criteria"}
990
+ Received: found matching request: ${matchedRequest?.method()} ${matchedRequest?.url()}`;
991
+ }
992
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
993
+ isNot: this.isNot
994
+ }) + `
995
+
996
+ Expected: request with ${criteriaDesc || "any criteria"}
997
+ Received: no matching request found among ${requests.length} captured requests
998
+
999
+ Note: page.requests() only returns up to 100 most recent requests`;
1000
+ };
1001
+ return {
1002
+ pass,
1003
+ message,
1004
+ name: assertionName
1005
+ };
1006
+ }
1007
+
1008
+ // src/matchers/page/toHaveConsoleMessage.ts
1009
+ var import_test14 = require("@playwright/test");
1010
+ async function toHaveConsoleMessage(page, options = {}) {
1011
+ const assertionName = "toHaveConsoleMessage";
1012
+ const { type, text, timeout = this.timeout, intervals } = options;
1013
+ let matchedMessage;
1014
+ let messages = [];
1015
+ let pass = false;
1016
+ try {
1017
+ await import_test14.expect.poll(
1018
+ async () => {
1019
+ messages = await page.consoleMessages();
1020
+ matchedMessage = messages.find((msg) => {
1021
+ if (type !== void 0) {
1022
+ if (msg.type() !== type) return false;
1023
+ }
1024
+ if (text !== void 0) {
1025
+ const msgText = msg.text();
1026
+ if (typeof text === "string") {
1027
+ if (!msgText.includes(text)) return false;
1028
+ } else {
1029
+ if (!text.test(msgText)) return false;
1030
+ }
1031
+ }
1032
+ return true;
1033
+ });
1034
+ return matchedMessage !== void 0;
1035
+ },
1036
+ { timeout, intervals }
1037
+ ).toBe(true);
1038
+ pass = true;
1039
+ } catch {
1040
+ pass = false;
1041
+ }
1042
+ const criteriaDesc = [
1043
+ type ? `type "${type}"` : null,
1044
+ text ? `text matching ${text instanceof RegExp ? text : `"${text}"`}` : null
1045
+ ].filter(Boolean).join(", ");
1046
+ const message = () => {
1047
+ if (this.isNot) {
1048
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1049
+ isNot: this.isNot
1050
+ }) + `
1051
+
1052
+ Expected: NOT to have console message with ${criteriaDesc || "any criteria"}
1053
+ Received: found matching message: "${matchedMessage?.text()}"`;
1054
+ }
1055
+ const capturedMessages = messages.slice(0, 5).map((m) => ` [${m.type()}] ${m.text().substring(0, 50)}${m.text().length > 50 ? "..." : ""}`).join("\n");
1056
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1057
+ isNot: this.isNot
1058
+ }) + `
1059
+
1060
+ Expected: console message with ${criteriaDesc || "any criteria"}
1061
+ Received: no matching message found among ${messages.length} captured messages
1062
+ ` + (capturedMessages ? `
1063
+ Recent messages:
1064
+ ${capturedMessages}` : "") + `
1065
+
1066
+ Note: page.consoleMessages() only returns up to 200 most recent messages`;
1067
+ };
1068
+ return {
1069
+ pass,
1070
+ message,
1071
+ name: assertionName
1072
+ };
1073
+ }
1074
+
1075
+ // src/matchers/page/toHavePageError.ts
1076
+ var import_test15 = require("@playwright/test");
1077
+ async function toHavePageError(page, options = {}) {
1078
+ const assertionName = "toHavePageError";
1079
+ const { message: errorMessage, name: errorName, timeout = this.timeout, intervals } = options;
1080
+ let matchedError;
1081
+ let errors = [];
1082
+ let pass = false;
1083
+ try {
1084
+ await import_test15.expect.poll(
1085
+ async () => {
1086
+ errors = await page.pageErrors();
1087
+ matchedError = errors.find((error) => {
1088
+ if (errorMessage !== void 0) {
1089
+ const msg = error.message;
1090
+ if (typeof errorMessage === "string") {
1091
+ if (!msg.includes(errorMessage)) return false;
1092
+ } else {
1093
+ if (!errorMessage.test(msg)) return false;
1094
+ }
1095
+ }
1096
+ if (errorName !== void 0) {
1097
+ if (error.name !== errorName) return false;
1098
+ }
1099
+ return true;
1100
+ });
1101
+ return matchedError !== void 0;
1102
+ },
1103
+ { timeout, intervals }
1104
+ ).toBe(true);
1105
+ pass = true;
1106
+ } catch {
1107
+ pass = false;
1108
+ }
1109
+ const criteriaDesc = [
1110
+ errorMessage ? `message matching ${errorMessage instanceof RegExp ? errorMessage : `"${errorMessage}"`}` : null,
1111
+ errorName ? `name "${errorName}"` : null
1112
+ ].filter(Boolean).join(", ");
1113
+ const message = () => {
1114
+ if (this.isNot) {
1115
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1116
+ isNot: this.isNot
1117
+ }) + `
1118
+
1119
+ Expected: NOT to have page error with ${criteriaDesc || "any criteria"}
1120
+ Received: found matching error: ${matchedError?.name}: ${matchedError?.message}`;
1121
+ }
1122
+ const capturedErrors = errors.slice(0, 5).map((e) => ` ${e.name}: ${e.message.substring(0, 60)}${e.message.length > 60 ? "..." : ""}`).join("\n");
1123
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1124
+ isNot: this.isNot
1125
+ }) + `
1126
+
1127
+ Expected: page error with ${criteriaDesc || "any criteria"}
1128
+ Received: no matching error found among ${errors.length} captured errors
1129
+ ` + (capturedErrors ? `
1130
+ Recent errors:
1131
+ ${capturedErrors}` : "") + `
1132
+
1133
+ Note: page.pageErrors() only returns up to 200 most recent errors`;
1134
+ };
1135
+ return {
1136
+ pass,
1137
+ message,
1138
+ name: assertionName
1139
+ };
1140
+ }
1141
+
1142
+ // src/matchers/page/index.ts
1143
+ var pageMatchers = {
1144
+ toHaveNoErrors,
1145
+ toHaveCookie,
1146
+ toHaveLocalStorage,
1147
+ toHaveSessionStorage,
1148
+ toHaveClipboardText,
1149
+ toHaveRequest,
1150
+ toHaveConsoleMessage,
1151
+ toHavePageError
1152
+ };
1153
+
1154
+ // src/matchers/api/toMatchJSON.ts
1155
+ var import_test16 = require("@playwright/test");
1156
+ async function toMatchJSON(response, expected) {
1157
+ const assertionName = "toMatchJSON";
1158
+ let pass = false;
1159
+ let actualBody;
1160
+ let parseError = null;
1161
+ try {
1162
+ actualBody = await response.json();
1163
+ } catch (error) {
1164
+ parseError = error instanceof Error ? error.message : String(error);
1165
+ }
1166
+ if (parseError) {
1167
+ pass = false;
1168
+ } else {
1169
+ try {
1170
+ (0, import_test16.expect)(actualBody).toEqual(expected);
1171
+ pass = true;
1172
+ } catch {
1173
+ pass = false;
1174
+ }
1175
+ }
1176
+ const message = () => {
1177
+ if (parseError) {
1178
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1179
+ isNot: this.isNot
1180
+ }) + `
1181
+
1182
+ Failed to parse response body as JSON:
1183
+ ${parseError}`;
1184
+ }
1185
+ const diff = this.utils.diff(expected, actualBody);
1186
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1187
+ isNot: this.isNot
1188
+ }) + "\n\n" + (this.isNot ? `Expected: not ${formatValue(expected)}
1189
+ ` : `Expected: ${formatValue(expected)}
1190
+ `) + `Received: ${formatValue(actualBody)}` + (diff ? `
1191
+
1192
+ Difference:
1193
+ ${diff}` : "");
1194
+ };
1195
+ return {
1196
+ pass,
1197
+ message,
1198
+ name: assertionName,
1199
+ expected,
1200
+ actual: actualBody
1201
+ };
1202
+ }
1203
+
1204
+ // src/matchers/api/toMatchSchema.ts
1205
+ async function toMatchSchema(response, schema) {
1206
+ const assertionName = "toMatchSchema";
1207
+ let pass = false;
1208
+ let actualBody;
1209
+ let parseError = null;
1210
+ let validationErrors = [];
1211
+ try {
1212
+ actualBody = await response.json();
1213
+ } catch (error) {
1214
+ parseError = error instanceof Error ? error.message : String(error);
1215
+ }
1216
+ if (parseError) {
1217
+ pass = false;
1218
+ } else {
1219
+ const result = schema.safeParse(actualBody);
1220
+ pass = result.success;
1221
+ if (!result.success) {
1222
+ validationErrors = formatZodErrors(result.error);
1223
+ }
1224
+ }
1225
+ const message = () => {
1226
+ if (parseError) {
1227
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1228
+ isNot: this.isNot
1229
+ }) + `
1230
+
1231
+ Failed to parse response body as JSON:
1232
+ ${parseError}`;
1233
+ }
1234
+ if (this.isNot) {
1235
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1236
+ isNot: this.isNot
1237
+ }) + `
1238
+
1239
+ Expected: response to NOT match schema
1240
+ Received: response matches schema
1241
+
1242
+ Body: ${formatValue(actualBody)}`;
1243
+ }
1244
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1245
+ isNot: this.isNot
1246
+ }) + `
1247
+
1248
+ Expected: response to match schema
1249
+ Received: validation failed
1250
+
1251
+ Validation errors:
1252
+ ${validationErrors.map((e) => ` \u2022 ${e}`).join("\n")}
1253
+
1254
+ Body: ${formatValue(actualBody)}`;
1255
+ };
1256
+ return {
1257
+ pass,
1258
+ message,
1259
+ name: assertionName,
1260
+ expected: "valid schema",
1261
+ actual: actualBody
1262
+ };
1263
+ }
1264
+ function formatZodErrors(error) {
1265
+ return error.errors.map((e) => {
1266
+ const path = e.path.length > 0 ? `${e.path.join(".")}: ` : "";
1267
+ return `${path}${e.message}`;
1268
+ });
1269
+ }
1270
+
1271
+ // src/matchers/api/toHaveStatus.ts
1272
+ async function toHaveStatus(response, expected) {
1273
+ const assertionName = "toHaveStatus";
1274
+ const actualStatus = response.status();
1275
+ let pass = false;
1276
+ if (typeof expected === "number") {
1277
+ pass = actualStatus === expected;
1278
+ } else {
1279
+ pass = actualStatus >= expected.min && actualStatus <= expected.max;
1280
+ }
1281
+ const expectedDesc = typeof expected === "number" ? `${expected}` : `${expected.min}-${expected.max}`;
1282
+ const message = () => {
1283
+ if (this.isNot) {
1284
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1285
+ isNot: this.isNot
1286
+ }) + `
1287
+
1288
+ Expected: status NOT to be ${expectedDesc}
1289
+ Received: ${actualStatus}`;
1290
+ }
1291
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1292
+ isNot: this.isNot
1293
+ }) + `
1294
+
1295
+ Expected: status ${expectedDesc}
1296
+ Received: ${actualStatus}`;
1297
+ };
1298
+ return {
1299
+ pass,
1300
+ message,
1301
+ name: assertionName,
1302
+ expected: expectedDesc,
1303
+ actual: actualStatus
1304
+ };
1305
+ }
1306
+
1307
+ // src/matchers/api/toHaveHeader.ts
1308
+ async function toHaveHeader(response, name, options = {}) {
1309
+ const assertionName = "toHaveHeader";
1310
+ const { value } = options;
1311
+ const headers = response.headers();
1312
+ const lowerName = name.toLowerCase();
1313
+ const actualValue = Object.entries(headers).find(
1314
+ ([key]) => key.toLowerCase() === lowerName
1315
+ )?.[1];
1316
+ let pass = actualValue !== void 0;
1317
+ if (pass && value !== void 0) {
1318
+ if (typeof value === "string") {
1319
+ pass = actualValue === value;
1320
+ } else {
1321
+ pass = value.test(actualValue);
1322
+ }
1323
+ }
1324
+ const expectedDesc = value ? `header "${name}" with value ${value instanceof RegExp ? value : `"${value}"`}` : `header "${name}"`;
1325
+ const message = () => {
1326
+ if (this.isNot) {
1327
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1328
+ isNot: this.isNot
1329
+ }) + `
1330
+
1331
+ Expected: NOT to have ${expectedDesc}
1332
+ Received: header found with value "${actualValue}"`;
1333
+ }
1334
+ return this.utils.matcherHint(assertionName, void 0, void 0, {
1335
+ isNot: this.isNot
1336
+ }) + `
1337
+
1338
+ Expected: ${expectedDesc}
1339
+ ` + (actualValue !== void 0 ? `Received: header found with value "${actualValue}"` : `Received: header not found`);
1340
+ };
1341
+ return {
1342
+ pass,
1343
+ message,
1344
+ name: assertionName,
1345
+ expected: value ?? name,
1346
+ actual: actualValue
1347
+ };
1348
+ }
1349
+
1350
+ // src/matchers/api/toRespondWithin.ts
1351
+ async function toRespondWithin(response, timeout) {
1352
+ if (!(response instanceof Promise) && typeof response !== "function") {
1353
+ return {
1354
+ message: () => `toRespondWithin: expected received value to be a Promise or async function, but got ${typeof response}. Did you await the request? Remove 'wait' to allow measurement.`,
1355
+ pass: false
1356
+ };
1357
+ }
1358
+ const start = Date.now();
1359
+ try {
1360
+ if (typeof response === "function") {
1361
+ await response();
1362
+ } else {
1363
+ await response;
1364
+ }
1365
+ } catch (e) {
1366
+ }
1367
+ const duration = Date.now() - start;
1368
+ const pass = duration <= timeout;
1369
+ if (pass) {
1370
+ return {
1371
+ message: () => `expected request not to answer within ${timeout}ms, took ${duration}ms`,
1372
+ pass: true
1373
+ };
1374
+ } else {
1375
+ return {
1376
+ message: () => `expected request to answer within ${timeout}ms, but took ${duration}ms`,
1377
+ pass: false
1378
+ };
1379
+ }
1380
+ }
1381
+
1382
+ // src/matchers/api/index.ts
1383
+ var apiMatchers = {
1384
+ toMatchJSON,
1385
+ toMatchSchema,
1386
+ toHaveStatus,
1387
+ toHaveHeader,
1388
+ toRespondWithin
1389
+ };
1390
+
1391
+ // src/matchers/asymmetric/toBeWithinRange.ts
1392
+ function toBeWithinRange(received, min, max) {
1393
+ const pass = typeof received === "number" && received >= min && received <= max;
1394
+ return {
1395
+ message: () => pass ? `expected ${received} not to be within range ${min} - ${max}` : `expected ${received} to be within range ${min} - ${max}`,
1396
+ pass
1397
+ };
1398
+ }
1399
+
1400
+ // src/matchers/asymmetric/toBeUUID.ts
1401
+ var UUID_PATTERNS = {
1402
+ v1: /^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
1403
+ v4: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
1404
+ v5: /^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
1405
+ any: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
1406
+ };
1407
+ function toBeUUID(received, version) {
1408
+ const pattern = version ? UUID_PATTERNS[version] : UUID_PATTERNS.any;
1409
+ const versionLabel = version || "any";
1410
+ const pass = typeof received === "string" && pattern.test(received);
1411
+ return {
1412
+ message: () => pass ? `expected ${received} not to be a valid UUID (${versionLabel})` : `expected ${received} to be a valid UUID (${versionLabel})`,
1413
+ pass
1414
+ };
1415
+ }
1416
+
1417
+ // src/matchers/asymmetric/toBeISODate.ts
1418
+ var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?(Z|[+-]\d{2}:?\d{2})?$/;
1419
+ function toBeISODate(received) {
1420
+ let pass = false;
1421
+ if (typeof received === "string" && ISO_DATE_PATTERN.test(received)) {
1422
+ const date = new Date(received);
1423
+ if (!isNaN(date.getTime())) {
1424
+ pass = true;
1425
+ }
1426
+ }
1427
+ return {
1428
+ message: () => pass ? `expected ${received} not to be a valid ISO date` : `expected ${received} to be a valid ISO date`,
1429
+ pass
1430
+ };
1431
+ }
1432
+
1433
+ // src/matchers/asymmetric/toBeDateString.ts
1434
+ var FORMAT_PATTERNS = {
1435
+ "YYYY-MM-DD": /^\d{4}-\d{2}-\d{2}$/,
1436
+ "MM/DD/YYYY": /^\d{2}\/\d{2}\/\d{4}$/,
1437
+ "DD/MM/YYYY": /^\d{2}\/\d{2}\/\d{4}$/,
1438
+ "YYYY/MM/DD": /^\d{4}\/\d{2}\/\d{2}$/,
1439
+ "MM-DD-YYYY": /^\d{2}-\d{2}-\d{4}$/,
1440
+ "DD-MM-YYYY": /^\d{2}-\d{2}-\d{4}$/,
1441
+ "YYYYMMDD": /^\d{8}$/
1442
+ };
1443
+ function toBeDateString(received, format) {
1444
+ const pattern = FORMAT_PATTERNS[format];
1445
+ if (!pattern) {
1446
+ throw new Error(
1447
+ `Unsupported date format: ${format}. Supported formats: ${Object.keys(FORMAT_PATTERNS).join(", ")}`
1448
+ );
1449
+ }
1450
+ const pass = typeof received === "string" && pattern.test(received);
1451
+ return {
1452
+ message: () => pass ? `expected ${received} not to be a date string (${format})` : `expected ${received} to be a date string (${format})`,
1453
+ pass
1454
+ };
1455
+ }
1456
+
1457
+ // src/matchers/asymmetric/toBeEmail.ts
1458
+ var EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
1459
+ function toBeEmail(received) {
1460
+ const pass = typeof received === "string" && EMAIL_PATTERN.test(received);
1461
+ return {
1462
+ message: () => pass ? `expected ${received} not to be a valid email` : `expected ${received} to be a valid email`,
1463
+ pass
1464
+ };
1465
+ }
1466
+
1467
+ // src/matchers/asymmetric/toBeURL.ts
1468
+ function toBeURL(received, options = {}) {
1469
+ const { protocol } = options;
1470
+ let pass = false;
1471
+ if (typeof received === "string") {
1472
+ try {
1473
+ const url = new URL(received);
1474
+ pass = true;
1475
+ if (protocol) {
1476
+ const urlProtocol = url.protocol.replace(":", "");
1477
+ const allowedProtocols = Array.isArray(protocol) ? protocol : [protocol];
1478
+ if (!allowedProtocols.includes(urlProtocol)) {
1479
+ pass = false;
1480
+ }
1481
+ }
1482
+ } catch {
1483
+ pass = false;
1484
+ }
1485
+ }
1486
+ const protocolMsg = protocol ? ` (protocol: ${Array.isArray(protocol) ? protocol.join("|") : protocol})` : "";
1487
+ return {
1488
+ message: () => pass ? `expected ${received} not to be a valid URL${protocolMsg}` : `expected ${received} to be a valid URL${protocolMsg}`,
1489
+ pass
1490
+ };
1491
+ }
1492
+
1493
+ // src/matchers/asymmetric/toBeJSON.ts
1494
+ function toBeJSON(received) {
1495
+ let pass = false;
1496
+ if (typeof received === "string") {
1497
+ try {
1498
+ JSON.parse(received);
1499
+ pass = true;
1500
+ } catch {
1501
+ pass = false;
1502
+ }
1503
+ }
1504
+ return {
1505
+ message: () => pass ? `expected ${received} not to be valid JSON` : `expected ${received} to be valid JSON`,
1506
+ pass
1507
+ };
1508
+ }
1509
+
1510
+ // src/matchers/asymmetric/toStartWith.ts
1511
+ function toStartWith(received, expected) {
1512
+ const pass = typeof received === "string" && received.startsWith(expected);
1513
+ return {
1514
+ message: () => pass ? `expected ${received} not to start with ${expected}` : `expected ${received} to start with ${expected}`,
1515
+ pass
1516
+ };
1517
+ }
1518
+
1519
+ // src/matchers/asymmetric/toEndWith.ts
1520
+ function toEndWith(received, expected) {
1521
+ const pass = typeof received === "string" && received.endsWith(expected);
1522
+ return {
1523
+ message: () => pass ? `expected ${received} not to end with ${expected}` : `expected ${received} to end with ${expected}`,
1524
+ pass
1525
+ };
1526
+ }
1527
+
1528
+ // src/matchers/asymmetric/toBeUpperCase.ts
1529
+ function toBeUpperCase(received) {
1530
+ const pass = typeof received === "string" && received === received.toUpperCase() && received !== received.toLowerCase();
1531
+ return {
1532
+ message: () => pass ? `expected ${received} not to be upper case` : `expected ${received} to be upper case`,
1533
+ pass
1534
+ };
1535
+ }
1536
+
1537
+ // src/matchers/asymmetric/toBeLowerCase.ts
1538
+ function toBeLowerCase(received) {
1539
+ const pass = typeof received === "string" && received === received.toLowerCase() && received !== received.toUpperCase();
1540
+ return {
1541
+ message: () => pass ? `expected ${received} not to be lower case` : `expected ${received} to be lower case`,
1542
+ pass
1543
+ };
1544
+ }
1545
+
1546
+ // src/matchers/asymmetric/toBeKebabCase.ts
1547
+ function toBeKebabCase(received) {
1548
+ const pass = typeof received === "string" && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(received);
1549
+ return {
1550
+ message: () => pass ? `expected ${received} not to be kebab-case` : `expected ${received} to be kebab-case`,
1551
+ pass
1552
+ };
1553
+ }
1554
+
1555
+ // src/matchers/asymmetric/toBeCamelCase.ts
1556
+ function toBeCamelCase(received) {
1557
+ const pass = typeof received === "string" && /^[a-z][a-zA-Z0-9]*$/.test(received) && !/[_\-]/.test(received);
1558
+ return {
1559
+ message: () => pass ? `expected ${received} not to be camelCase` : `expected ${received} to be camelCase`,
1560
+ pass
1561
+ };
1562
+ }
1563
+
1564
+ // src/matchers/asymmetric/toBeSnakeCase.ts
1565
+ function toBeSnakeCase(received) {
1566
+ const pass = typeof received === "string" && /^[a-z0-9]+(_[a-z0-9]+)*$/.test(received);
1567
+ return {
1568
+ message: () => pass ? `expected ${received} not to be snake_case` : `expected ${received} to be snake_case`,
1569
+ pass
1570
+ };
1571
+ }
1572
+
1573
+ // src/matchers/asymmetric/toBePascalCase.ts
1574
+ function toBePascalCase(received) {
1575
+ const pass = typeof received === "string" && /^[A-Z][a-zA-Z0-9]*$/.test(received) && !/[_\-]/.test(received);
1576
+ return {
1577
+ message: () => pass ? `expected ${received} not to be PascalCase` : `expected ${received} to be PascalCase`,
1578
+ pass
1579
+ };
1580
+ }
1581
+
1582
+ // src/matchers/asymmetric/index.ts
1583
+ var asymmetricMatchers = {
1584
+ toBeWithinRange,
1585
+ toBeUUID,
1586
+ toBeISODate,
1587
+ toBeDateString,
1588
+ toBeEmail,
1589
+ toBeURL,
1590
+ toBeJSON,
1591
+ toStartWith,
1592
+ toEndWith,
1593
+ toBeUpperCase,
1594
+ toBeLowerCase,
1595
+ toBeKebabCase,
1596
+ toBeCamelCase,
1597
+ toBeSnakeCase,
1598
+ toBePascalCase
1599
+ };
1600
+
1601
+ // src/matchers/general/toBeSorted.ts
1602
+ var import_test17 = require("@playwright/test");
1603
+ function isLocator(value) {
1604
+ return value !== null && typeof value === "object" && "allInnerTexts" in value;
1605
+ }
1606
+ function checkSorted(values, descending, key) {
1607
+ return values.every((item, index) => {
1608
+ if (index === 0) return true;
1609
+ const prev = values[index - 1];
1610
+ let a = key ? typeof key === "function" ? key(prev) : prev[key] : prev;
1611
+ let b = key ? typeof key === "function" ? key(item) : item[key] : item;
1612
+ if (a instanceof Date) a = a.getTime();
1613
+ if (b instanceof Date) b = b.getTime();
1614
+ if (descending) {
1615
+ return a >= b;
1616
+ }
1617
+ return a <= b;
1618
+ });
1619
+ }
1620
+ async function toBeSorted(received, options) {
1621
+ const {
1622
+ descending = false,
1623
+ key,
1624
+ useTextContent = false,
1625
+ compareAsNumbers = false,
1626
+ timeout = this.timeout,
1627
+ intervals
1628
+ } = options || {};
1629
+ if (Array.isArray(received)) {
1630
+ const pass = checkSorted(received, descending, key);
1631
+ return {
1632
+ message: () => pass ? `expected array not to be sorted ${descending ? "descending" : "ascending"}` : `expected array to be sorted ${descending ? "descending" : "ascending"}, but received: [${received.join(", ")}]`,
1633
+ pass
1634
+ };
1635
+ }
1636
+ if (isLocator(received)) {
1637
+ const locator = received;
1638
+ let values = [];
1639
+ let pass = false;
1640
+ try {
1641
+ await import_test17.expect.poll(
1642
+ async () => {
1643
+ values = useTextContent ? await locator.allTextContents() : await locator.allInnerTexts();
1644
+ const compareValues = compareAsNumbers ? values.map((v) => parseFloat(v.replace(/[^0-9.-]/g, ""))) : values;
1645
+ return checkSorted(compareValues, descending);
1646
+ },
1647
+ { timeout, intervals }
1648
+ ).toBe(true);
1649
+ pass = true;
1650
+ } catch {
1651
+ pass = false;
1652
+ }
1653
+ return {
1654
+ message: () => pass ? `expected locator elements not to be sorted ${descending ? "descending" : "ascending"}` : `expected locator elements to be sorted ${descending ? "descending" : "ascending"}, but received: [${values.join(", ")}]`,
1655
+ pass
1656
+ };
1657
+ }
1658
+ return {
1659
+ message: () => `expected an array or Locator, but received: ${typeof received}`,
1660
+ pass: false
1661
+ };
1662
+ }
1663
+
1664
+ // src/matchers/general/index.ts
1665
+ var generalMatchers = {
1666
+ toBeSorted
1667
+ };
1668
+
1669
+ // src/matchers/index.ts
1670
+ var allMatchers = {
1671
+ ...locatorMatchers,
1672
+ ...pageMatchers,
1673
+ ...apiMatchers,
1674
+ ...generalMatchers,
1675
+ ...asymmetricMatchers
1676
+ };
1677
+
1678
+ // src/index.ts
1679
+ var exPwExpect = import_test18.expect.extend(allMatchers);
1680
+ var expect18 = exPwExpect;
1681
+ var exPw = {
1682
+ ...allMatchers
1683
+ };
1684
+ var index_default = exPw;
1685
+ // Annotate the CommonJS export names for ESM import in node:
1686
+ 0 && (module.exports = {
1687
+ apiMatchers,
1688
+ asymmetricMatchers,
1689
+ expect,
1690
+ generalMatchers,
1691
+ locatorMatchers,
1692
+ pageMatchers,
1693
+ toBeCamelCase,
1694
+ toBeCheckable,
1695
+ toBeClickable,
1696
+ toBeDateString,
1697
+ toBeEmail,
1698
+ toBeISODate,
1699
+ toBeInvalid,
1700
+ toBeJSON,
1701
+ toBeKebabCase,
1702
+ toBeLowerCase,
1703
+ toBePascalCase,
1704
+ toBeRequired,
1705
+ toBeSnakeCase,
1706
+ toBeSorted,
1707
+ toBeURL,
1708
+ toBeUUID,
1709
+ toBeUpperCase,
1710
+ toBeValid,
1711
+ toBeWithinRange,
1712
+ toEndWith,
1713
+ toHaveClipboardText,
1714
+ toHaveConsoleMessage,
1715
+ toHaveCookie,
1716
+ toHaveCountGreaterThan,
1717
+ toHaveCountGreaterThanOrEqual,
1718
+ toHaveCountLessThan,
1719
+ toHaveCountLessThanOrEqual,
1720
+ toHaveHeader,
1721
+ toHaveHeight,
1722
+ toHaveLoadedImage,
1723
+ toHaveLocalStorage,
1724
+ toHaveNoErrors,
1725
+ toHavePageError,
1726
+ toHaveRequest,
1727
+ toHaveSessionStorage,
1728
+ toHaveSize,
1729
+ toHaveStatus,
1730
+ toHaveWidth,
1731
+ toMatchJSON,
1732
+ toMatchSchema,
1733
+ toRespondWithin,
1734
+ toStartWith
1735
+ });