@najemi-software/vitest-dom 0.1.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.
@@ -0,0 +1,1688 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/matchers.ts
8
+ var matchers_exports = {};
9
+ __export(matchers_exports, {
10
+ toBeChecked: () => toBeChecked,
11
+ toBeDisabled: () => toBeDisabled,
12
+ toBeEmpty: () => toBeEmpty,
13
+ toBeEmptyDOMElement: () => toBeEmptyDOMElement,
14
+ toBeEnabled: () => toBeEnabled,
15
+ toBeInTheDOM: () => toBeInTheDOM,
16
+ toBeInTheDocument: () => toBeInTheDocument,
17
+ toBeInvalid: () => toBeInvalid,
18
+ toBePartiallyChecked: () => toBePartiallyChecked,
19
+ toBeRequired: () => toBeRequired,
20
+ toBeValid: () => toBeValid,
21
+ toBeVisible: () => toBeVisible,
22
+ toContainElement: () => toContainElement,
23
+ toContainHTML: () => toContainHTML,
24
+ toHaveAccessibleDescription: () => toHaveAccessibleDescription,
25
+ toHaveAccessibleName: () => toHaveAccessibleName,
26
+ toHaveAttribute: () => toHaveAttribute,
27
+ toHaveClass: () => toHaveClass,
28
+ toHaveDescription: () => toHaveDescription,
29
+ toHaveDisplayValue: () => toHaveDisplayValue,
30
+ toHaveErrorMessage: () => toHaveErrorMessage,
31
+ toHaveFocus: () => toHaveFocus,
32
+ toHaveFormValues: () => toHaveFormValues,
33
+ toHaveStyle: () => toHaveStyle,
34
+ toHaveTextContent: () => toHaveTextContent,
35
+ toHaveValue: () => toHaveValue
36
+ });
37
+
38
+ // src/utils.ts
39
+ import redent from "redent";
40
+
41
+ // src/css-parse.js
42
+ var commentre = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g;
43
+ function cssParse(css, options) {
44
+ options = options || {};
45
+ let lineno = 1;
46
+ let column = 1;
47
+ function updatePosition(str) {
48
+ let lines = str.match(/\n/g);
49
+ if (lines)
50
+ lineno += lines.length;
51
+ let i = str.lastIndexOf("\n");
52
+ column = ~i ? str.length - i : column + str.length;
53
+ }
54
+ function position() {
55
+ let start = { line: lineno, column };
56
+ return function(node) {
57
+ node.position = new Position(start);
58
+ whitespace();
59
+ return node;
60
+ };
61
+ }
62
+ function Position(start) {
63
+ this.start = start;
64
+ this.end = { line: lineno, column };
65
+ this.source = options.source;
66
+ }
67
+ Position.prototype.content = css;
68
+ let errorsList = [];
69
+ function error(msg) {
70
+ let err = new Error(
71
+ options.source + ":" + lineno + ":" + column + ": " + msg
72
+ );
73
+ err.reason = msg;
74
+ err.filename = options.source;
75
+ err.line = lineno;
76
+ err.column = column;
77
+ err.source = css;
78
+ if (options.silent) {
79
+ errorsList.push(err);
80
+ } else {
81
+ throw err;
82
+ }
83
+ }
84
+ function stylesheet() {
85
+ let rulesList = rules();
86
+ return {
87
+ type: "stylesheet",
88
+ stylesheet: {
89
+ source: options.source,
90
+ rules: rulesList,
91
+ parsingErrors: errorsList
92
+ }
93
+ };
94
+ }
95
+ function open() {
96
+ return match(/^{\s*/);
97
+ }
98
+ function close() {
99
+ return match(/^}/);
100
+ }
101
+ function rules() {
102
+ let node;
103
+ let rules2 = [];
104
+ whitespace();
105
+ comments(rules2);
106
+ while (css.length && css.charAt(0) != "}" && (node = atrule() || rule())) {
107
+ if (node !== false) {
108
+ rules2.push(node);
109
+ comments(rules2);
110
+ }
111
+ }
112
+ return rules2;
113
+ }
114
+ function match(re) {
115
+ let m = re.exec(css);
116
+ if (!m)
117
+ return;
118
+ let str = m[0];
119
+ updatePosition(str);
120
+ css = css.slice(str.length);
121
+ return m;
122
+ }
123
+ function whitespace() {
124
+ match(/^\s*/);
125
+ }
126
+ function comments(rules2) {
127
+ let c;
128
+ rules2 = rules2 || [];
129
+ while (c = comment()) {
130
+ if (c !== false) {
131
+ rules2.push(c);
132
+ }
133
+ }
134
+ return rules2;
135
+ }
136
+ function comment() {
137
+ let pos = position();
138
+ if ("/" != css.charAt(0) || "*" != css.charAt(1))
139
+ return;
140
+ let i = 2;
141
+ while ("" != css.charAt(i) && ("*" != css.charAt(i) || "/" != css.charAt(i + 1)))
142
+ ++i;
143
+ i += 2;
144
+ if ("" === css.charAt(i - 1)) {
145
+ return error("End of comment missing");
146
+ }
147
+ let str = css.slice(2, i - 2);
148
+ column += 2;
149
+ updatePosition(str);
150
+ css = css.slice(i);
151
+ column += 2;
152
+ return pos({
153
+ type: "comment",
154
+ comment: str
155
+ });
156
+ }
157
+ function selector() {
158
+ let m = match(/^([^{]+)/);
159
+ if (!m)
160
+ return;
161
+ return trim(m[0]).replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, "").replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, function(m2) {
162
+ return m2.replace(/,/g, "\u200C");
163
+ }).split(/\s*(?![^(]*\)),\s*/).map(function(s) {
164
+ return s.replace(/\u200C/g, ",");
165
+ });
166
+ }
167
+ function declaration() {
168
+ let pos = position();
169
+ let prop = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
170
+ if (!prop)
171
+ return;
172
+ prop = trim(prop[0]);
173
+ if (!match(/^:\s*/))
174
+ return error("property missing ':'");
175
+ let val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
176
+ let ret = pos({
177
+ type: "declaration",
178
+ property: prop.replace(commentre, ""),
179
+ value: val ? trim(val[0]).replace(commentre, "") : ""
180
+ });
181
+ match(/^[;\s]*/);
182
+ return ret;
183
+ }
184
+ function declarations() {
185
+ let decls = [];
186
+ if (!open())
187
+ return error("missing '{'");
188
+ comments(decls);
189
+ let decl;
190
+ while (decl = declaration()) {
191
+ if (decl !== false) {
192
+ decls.push(decl);
193
+ comments(decls);
194
+ }
195
+ }
196
+ if (!close())
197
+ return error("missing '}'");
198
+ return decls;
199
+ }
200
+ function keyframe() {
201
+ let m;
202
+ let vals = [];
203
+ let pos = position();
204
+ while (m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)) {
205
+ vals.push(m[1]);
206
+ match(/^,\s*/);
207
+ }
208
+ if (!vals.length)
209
+ return;
210
+ return pos({
211
+ type: "keyframe",
212
+ values: vals,
213
+ declarations: declarations()
214
+ });
215
+ }
216
+ function atkeyframes() {
217
+ let pos = position();
218
+ let m = match(/^@([-\w]+)?keyframes\s*/);
219
+ if (!m)
220
+ return;
221
+ let vendor = m[1];
222
+ m = match(/^([-\w]+)\s*/);
223
+ if (!m)
224
+ return error("@keyframes missing name");
225
+ let name = m[1];
226
+ if (!open())
227
+ return error("@keyframes missing '{'");
228
+ let frame;
229
+ let frames = comments();
230
+ while (frame = keyframe()) {
231
+ frames.push(frame);
232
+ frames = frames.concat(comments());
233
+ }
234
+ if (!close())
235
+ return error("@keyframes missing '}'");
236
+ return pos({
237
+ type: "keyframes",
238
+ name,
239
+ vendor,
240
+ keyframes: frames
241
+ });
242
+ }
243
+ function atsupports() {
244
+ let pos = position();
245
+ let m = match(/^@supports *([^{]+)/);
246
+ if (!m)
247
+ return;
248
+ let supports = trim(m[1]);
249
+ if (!open())
250
+ return error("@supports missing '{'");
251
+ let style = comments().concat(rules());
252
+ if (!close())
253
+ return error("@supports missing '}'");
254
+ return pos({
255
+ type: "supports",
256
+ supports,
257
+ rules: style
258
+ });
259
+ }
260
+ function athost() {
261
+ let pos = position();
262
+ let m = match(/^@host\s*/);
263
+ if (!m)
264
+ return;
265
+ if (!open())
266
+ return error("@host missing '{'");
267
+ let style = comments().concat(rules());
268
+ if (!close())
269
+ return error("@host missing '}'");
270
+ return pos({
271
+ type: "host",
272
+ rules: style
273
+ });
274
+ }
275
+ function atmedia() {
276
+ let pos = position();
277
+ let m = match(/^@media *([^{]+)/);
278
+ if (!m)
279
+ return;
280
+ let media = trim(m[1]);
281
+ if (!open())
282
+ return error("@media missing '{'");
283
+ let style = comments().concat(rules());
284
+ if (!close())
285
+ return error("@media missing '}'");
286
+ return pos({
287
+ type: "media",
288
+ media,
289
+ rules: style
290
+ });
291
+ }
292
+ function atcustommedia() {
293
+ let pos = position();
294
+ let m = match(/^@custom-media\s+(--[^\s]+)\s*([^{;]+);/);
295
+ if (!m)
296
+ return;
297
+ return pos({
298
+ type: "custom-media",
299
+ name: trim(m[1]),
300
+ media: trim(m[2])
301
+ });
302
+ }
303
+ function atpage() {
304
+ let pos = position();
305
+ let m = match(/^@page */);
306
+ if (!m)
307
+ return;
308
+ let sel = selector() || [];
309
+ if (!open())
310
+ return error("@page missing '{'");
311
+ let decls = comments();
312
+ let decl;
313
+ while (decl = declaration()) {
314
+ decls.push(decl);
315
+ decls = decls.concat(comments());
316
+ }
317
+ if (!close())
318
+ return error("@page missing '}'");
319
+ return pos({
320
+ type: "page",
321
+ selectors: sel,
322
+ declarations: decls
323
+ });
324
+ }
325
+ function atdocument() {
326
+ let pos = position();
327
+ let m = match(/^@([-\w]+)?document *([^{]+)/);
328
+ if (!m)
329
+ return;
330
+ let vendor = trim(m[1]);
331
+ let doc = trim(m[2]);
332
+ if (!open())
333
+ return error("@document missing '{'");
334
+ let style = comments().concat(rules());
335
+ if (!close())
336
+ return error("@document missing '}'");
337
+ return pos({
338
+ type: "document",
339
+ document: doc,
340
+ vendor,
341
+ rules: style
342
+ });
343
+ }
344
+ function atfontface() {
345
+ let pos = position();
346
+ let m = match(/^@font-face\s*/);
347
+ if (!m)
348
+ return;
349
+ if (!open())
350
+ return error("@font-face missing '{'");
351
+ let decls = comments();
352
+ let decl;
353
+ while (decl = declaration()) {
354
+ decls.push(decl);
355
+ decls = decls.concat(comments());
356
+ }
357
+ if (!close())
358
+ return error("@font-face missing '}'");
359
+ return pos({
360
+ type: "font-face",
361
+ declarations: decls
362
+ });
363
+ }
364
+ let atimport = _compileAtrule("import");
365
+ let atcharset = _compileAtrule("charset");
366
+ let atnamespace = _compileAtrule("namespace");
367
+ function _compileAtrule(name) {
368
+ let re = new RegExp("^@" + name + "\\s*([^;]+);");
369
+ return function() {
370
+ let pos = position();
371
+ let m = match(re);
372
+ if (!m)
373
+ return;
374
+ let ret = { type: name };
375
+ ret[name] = m[1].trim();
376
+ return pos(ret);
377
+ };
378
+ }
379
+ function atrule() {
380
+ if (css[0] != "@")
381
+ return;
382
+ return atkeyframes() || atmedia() || atcustommedia() || atsupports() || atimport() || atcharset() || atnamespace() || atdocument() || atpage() || athost() || atfontface();
383
+ }
384
+ function rule() {
385
+ let pos = position();
386
+ let sel = selector();
387
+ if (!sel)
388
+ return error("selector missing");
389
+ comments();
390
+ return pos({
391
+ type: "rule",
392
+ selectors: sel,
393
+ declarations: declarations()
394
+ });
395
+ }
396
+ return addParent(stylesheet());
397
+ }
398
+ function trim(str) {
399
+ return str ? str.replace(/^\s+|\s+$/g, "") : "";
400
+ }
401
+ function addParent(obj, parent) {
402
+ let isNode = obj && typeof obj.type === "string";
403
+ let childParent = isNode ? obj : parent;
404
+ for (var k in obj) {
405
+ let value = obj[k];
406
+ if (Array.isArray(value)) {
407
+ value.forEach(function(v) {
408
+ addParent(v, childParent);
409
+ });
410
+ } else if (value && typeof value === "object") {
411
+ addParent(value, childParent);
412
+ }
413
+ }
414
+ if (isNode) {
415
+ Object.defineProperty(obj, "parent", {
416
+ configurable: true,
417
+ writable: true,
418
+ enumerable: false,
419
+ value: parent || null
420
+ });
421
+ }
422
+ return obj;
423
+ }
424
+ var css_parse_default = cssParse;
425
+
426
+ // src/utils.ts
427
+ import isEqual from "lodash-es/isEqual";
428
+ import isFunction from "lodash-es/isFunction";
429
+ var GenericTypeError = class extends Error {
430
+ constructor(expectedString, received, matcherFn, context) {
431
+ super();
432
+ const printWithType = "printWithType" in context.utils && isFunction(context.utils.printWithType) ? context.utils.printWithType : _printWithType;
433
+ if (Error.captureStackTrace) {
434
+ Error.captureStackTrace(this, matcherFn);
435
+ }
436
+ let withType = "";
437
+ try {
438
+ withType = printWithType(
439
+ "Received",
440
+ received,
441
+ context.utils.printReceived
442
+ );
443
+ } catch (e) {
444
+ }
445
+ this.message = [
446
+ context.utils.matcherHint(
447
+ `${context.isNot ? ".not" : ""}.${matcherFn.name}`,
448
+ "received",
449
+ ""
450
+ ),
451
+ "",
452
+ `${context.utils.RECEIVED_COLOR(
453
+ "received"
454
+ )} value must ${expectedString}.`,
455
+ withType
456
+ ].join("\n");
457
+ }
458
+ };
459
+ var HtmlElementTypeError = class extends GenericTypeError {
460
+ constructor(element, matcherFn, context) {
461
+ super("be an HTMLElement or an SVGElement", element, matcherFn, context);
462
+ }
463
+ };
464
+ var NodeTypeError = class extends GenericTypeError {
465
+ constructor(element, matcherFn, context) {
466
+ super("be a Node", element, matcherFn, context);
467
+ }
468
+ };
469
+ function checkHasWindow(htmlElement, ErrorClass, matcherFn, context) {
470
+ if (!htmlElement || !htmlElement.ownerDocument || !htmlElement.ownerDocument.defaultView) {
471
+ throw new ErrorClass(htmlElement, matcherFn, context);
472
+ }
473
+ }
474
+ function checkNode(node, matcherFn, context) {
475
+ checkHasWindow(node, NodeTypeError, matcherFn, context);
476
+ const window = node.ownerDocument.defaultView;
477
+ if (!(node instanceof window.Node)) {
478
+ throw new NodeTypeError(node, matcherFn, context);
479
+ }
480
+ }
481
+ function checkHtmlElement(htmlElement, matcher, context) {
482
+ checkHasWindow(htmlElement, HtmlElementTypeError, matcher, context);
483
+ const window = htmlElement.ownerDocument.defaultView;
484
+ if (!(htmlElement instanceof window.HTMLElement) && // @ts-expect-error
485
+ !(htmlElement instanceof window.SVGElement)) {
486
+ throw new HtmlElementTypeError(htmlElement, matcher, context);
487
+ }
488
+ }
489
+ var InvalidCSSError = class extends Error {
490
+ constructor(received, matcherFn, context) {
491
+ super();
492
+ if (Error.captureStackTrace) {
493
+ Error.captureStackTrace(this, matcherFn);
494
+ }
495
+ this.message = [
496
+ received.message,
497
+ "",
498
+ context.utils.RECEIVED_COLOR(`Failing css:`),
499
+ context.utils.RECEIVED_COLOR(`${received.css}`)
500
+ ].join("\n");
501
+ }
502
+ };
503
+ function parseCSS(css, matcherFn, context) {
504
+ const ast = css_parse_default(`selector { ${css} }`, { silent: true }).stylesheet;
505
+ if (ast.parsingErrors && ast.parsingErrors.length > 0) {
506
+ const { reason, line } = ast.parsingErrors[0];
507
+ throw new InvalidCSSError(
508
+ {
509
+ css,
510
+ message: `Syntax error parsing expected css: ${reason} on line: ${line}`
511
+ },
512
+ matcherFn,
513
+ context
514
+ );
515
+ }
516
+ const parsedRules = ast.rules[0].declarations.filter((d) => d.type === "declaration").reduce(
517
+ (obj, { property, value }) => Object.assign(obj, { [property]: value }),
518
+ {}
519
+ );
520
+ return parsedRules;
521
+ }
522
+ function display(context, value) {
523
+ return typeof value === "string" ? value : context.utils.stringify(value);
524
+ }
525
+ function getMessage(context, matcher, expectedLabel, expectedValue, receivedLabel, receivedValue) {
526
+ return [
527
+ `${matcher}
528
+ `,
529
+ `${expectedLabel}:
530
+ ${context.utils.EXPECTED_COLOR(
531
+ redent(display(context, expectedValue), 2)
532
+ )}`,
533
+ `${receivedLabel}:
534
+ ${context.utils.RECEIVED_COLOR(
535
+ redent(display(context, receivedValue), 2)
536
+ )}`
537
+ ].join("\n");
538
+ }
539
+ function matches(textToMatch, matcher) {
540
+ if (matcher instanceof RegExp) {
541
+ return matcher.test(textToMatch);
542
+ } else {
543
+ return textToMatch.includes(String(matcher));
544
+ }
545
+ }
546
+ function deprecate(name, replacementText) {
547
+ console.warn(
548
+ `Warning: ${name} has been deprecated and will be removed in future updates.`,
549
+ replacementText
550
+ );
551
+ }
552
+ function normalize(text) {
553
+ return text.replace(/\s+/g, " ").trim();
554
+ }
555
+ function getTag(element) {
556
+ return element.tagName && element.tagName.toLowerCase();
557
+ }
558
+ function getSelectValue({ multiple, options }) {
559
+ const selectedOptions = [...options].filter((option) => option.selected);
560
+ if (multiple) {
561
+ return [...selectedOptions].map((opt) => opt.value);
562
+ }
563
+ if (selectedOptions.length === 0) {
564
+ return void 0;
565
+ }
566
+ return selectedOptions[0].value;
567
+ }
568
+ function getInputValue(inputElement) {
569
+ switch (inputElement.type) {
570
+ case "number":
571
+ return inputElement.value === "" ? null : Number(inputElement.value);
572
+ case "checkbox":
573
+ return inputElement.checked;
574
+ default:
575
+ return inputElement.value;
576
+ }
577
+ }
578
+ function getSingleElementValue(element) {
579
+ if (!element) {
580
+ return void 0;
581
+ }
582
+ switch (element.tagName.toLowerCase()) {
583
+ case "input":
584
+ return getInputValue(element);
585
+ case "select":
586
+ return getSelectValue(element);
587
+ default:
588
+ return element.value;
589
+ }
590
+ }
591
+ function compareArraysAsSet(a, b) {
592
+ if (Array.isArray(a) && Array.isArray(b)) {
593
+ return isEqual(new Set(a), new Set(b));
594
+ }
595
+ return void 0;
596
+ }
597
+ function toSentence(array, { wordConnector = ", ", lastWordConnector = " and " } = {}) {
598
+ return [array.slice(0, -1).join(wordConnector), array[array.length - 1]].join(
599
+ array.length > 1 ? lastWordConnector : ""
600
+ );
601
+ }
602
+ function _printWithType(name, value, print) {
603
+ const type = getType(value);
604
+ const hasType = type !== "null" && type !== "undefined" ? `${name} has type: ${type}
605
+ ` : "";
606
+ const hasValue = `${name} has value: ${print(value)}`;
607
+ return hasType + hasValue;
608
+ }
609
+ function getType(value) {
610
+ if (value === void 0) {
611
+ return "undefined";
612
+ } else if (value === null) {
613
+ return "null";
614
+ } else if (Array.isArray(value)) {
615
+ return "array";
616
+ } else if (typeof value === "boolean") {
617
+ return "boolean";
618
+ } else if (typeof value === "function") {
619
+ return "function";
620
+ } else if (typeof value === "number") {
621
+ return "number";
622
+ } else if (typeof value === "string") {
623
+ return "string";
624
+ } else if (typeof value === "bigint") {
625
+ return "bigint";
626
+ } else if (typeof value === "object") {
627
+ if (value != null) {
628
+ if (value.constructor === RegExp) {
629
+ return "regexp";
630
+ } else if (value.constructor === Map) {
631
+ return "map";
632
+ } else if (value.constructor === Set) {
633
+ return "set";
634
+ } else if (value.constructor === Date) {
635
+ return "date";
636
+ }
637
+ }
638
+ return "object";
639
+ } else if (typeof value === "symbol") {
640
+ return "symbol";
641
+ }
642
+ throw new Error(`value of unknown type: ${value}`);
643
+ }
644
+
645
+ // src/to-be-in-the-dom.js
646
+ function toBeInTheDOM(element, container) {
647
+ deprecate(
648
+ "toBeInTheDOM",
649
+ "Please use toBeInTheDocument for searching the entire document and toContainElement for searching a specific container."
650
+ );
651
+ if (element) {
652
+ checkHtmlElement(element, toBeInTheDOM, this);
653
+ }
654
+ if (container) {
655
+ checkHtmlElement(container, toBeInTheDOM, this);
656
+ }
657
+ return {
658
+ pass: container ? container.contains(element) : !!element,
659
+ message: () => {
660
+ return [
661
+ this.utils.matcherHint(
662
+ `${this.isNot ? ".not" : ""}.toBeInTheDOM`,
663
+ "element",
664
+ ""
665
+ ),
666
+ "",
667
+ "Received:",
668
+ ` ${this.utils.printReceived(
669
+ element ? element.cloneNode(false) : element
670
+ )}`
671
+ ].join("\n");
672
+ }
673
+ };
674
+ }
675
+
676
+ // src/to-be-in-the-document.js
677
+ function toBeInTheDocument(element) {
678
+ if (element !== null || !this.isNot) {
679
+ checkHtmlElement(element, toBeInTheDocument, this);
680
+ }
681
+ const pass = element === null ? false : element.ownerDocument === element.getRootNode({ composed: true });
682
+ const errorFound = () => {
683
+ return `expected document not to contain element, found ${this.utils.stringify(
684
+ element.cloneNode(true)
685
+ )} instead`;
686
+ };
687
+ const errorNotFound = () => {
688
+ return `element could not be found in the document`;
689
+ };
690
+ return {
691
+ pass,
692
+ message: () => {
693
+ return [
694
+ this.utils.matcherHint(
695
+ `${this.isNot ? ".not" : ""}.toBeInTheDocument`,
696
+ "element",
697
+ ""
698
+ ),
699
+ "",
700
+ this.utils.RECEIVED_COLOR(this.isNot ? errorFound() : errorNotFound())
701
+ ].join("\n");
702
+ }
703
+ };
704
+ }
705
+
706
+ // src/to-be-empty.js
707
+ function toBeEmpty(element) {
708
+ deprecate(
709
+ "toBeEmpty",
710
+ "Please use instead toBeEmptyDOMElement for finding empty nodes in the DOM."
711
+ );
712
+ checkHtmlElement(element, toBeEmpty, this);
713
+ return {
714
+ pass: element.innerHTML === "",
715
+ message: () => {
716
+ return [
717
+ this.utils.matcherHint(
718
+ `${this.isNot ? ".not" : ""}.toBeEmpty`,
719
+ "element",
720
+ ""
721
+ ),
722
+ "",
723
+ "Received:",
724
+ ` ${this.utils.printReceived(element.innerHTML)}`
725
+ ].join("\n");
726
+ }
727
+ };
728
+ }
729
+
730
+ // src/to-be-empty-dom-element.js
731
+ function toBeEmptyDOMElement(element) {
732
+ checkHtmlElement(element, toBeEmptyDOMElement, this);
733
+ return {
734
+ pass: isEmptyElement(element),
735
+ message: () => {
736
+ return [
737
+ this.utils.matcherHint(
738
+ `${this.isNot ? ".not" : ""}.toBeEmptyDOMElement`,
739
+ "element",
740
+ ""
741
+ ),
742
+ "",
743
+ "Received:",
744
+ ` ${this.utils.printReceived(element.innerHTML)}`
745
+ ].join("\n");
746
+ }
747
+ };
748
+ }
749
+ function isEmptyElement(element) {
750
+ const nonCommentChildNodes = [...element.childNodes].filter(
751
+ (node) => node.nodeType !== 8
752
+ );
753
+ return nonCommentChildNodes.length === 0;
754
+ }
755
+
756
+ // src/to-contain-element.js
757
+ function toContainElement(container, element) {
758
+ checkHtmlElement(container, toContainElement, this);
759
+ if (element !== null) {
760
+ checkHtmlElement(element, toContainElement, this);
761
+ }
762
+ return {
763
+ pass: container.contains(element),
764
+ message: () => {
765
+ return [
766
+ this.utils.matcherHint(
767
+ `${this.isNot ? ".not" : ""}.toContainElement`,
768
+ "element",
769
+ "element"
770
+ ),
771
+ "",
772
+ this.utils.RECEIVED_COLOR(`${this.utils.stringify(
773
+ container.cloneNode(false)
774
+ )} ${this.isNot ? "contains:" : "does not contain:"} ${this.utils.stringify(element ? element.cloneNode(false) : element)}
775
+ `)
776
+ ].join("\n");
777
+ }
778
+ };
779
+ }
780
+
781
+ // src/to-contain-html.js
782
+ function getNormalizedHtml(container, htmlText) {
783
+ const div = container.ownerDocument.createElement("div");
784
+ div.innerHTML = htmlText;
785
+ return div.innerHTML;
786
+ }
787
+ function toContainHTML(container, htmlText) {
788
+ checkHtmlElement(container, toContainHTML, this);
789
+ if (typeof htmlText !== "string") {
790
+ throw new Error(`.toContainHTML() expects a string value, got ${htmlText}`);
791
+ }
792
+ return {
793
+ pass: container.outerHTML.includes(getNormalizedHtml(container, htmlText)),
794
+ message: () => {
795
+ return [
796
+ this.utils.matcherHint(
797
+ `${this.isNot ? ".not" : ""}.toContainHTML`,
798
+ "element",
799
+ ""
800
+ ),
801
+ "Expected:",
802
+ ` ${this.utils.EXPECTED_COLOR(htmlText)}`,
803
+ "Received:",
804
+ ` ${this.utils.printReceived(container.cloneNode(true))}`
805
+ ].join("\n");
806
+ }
807
+ };
808
+ }
809
+
810
+ // src/to-have-text-content.js
811
+ function toHaveTextContent(node, checkWith, options = { normalizeWhitespace: true }) {
812
+ checkNode(node, toHaveTextContent, this);
813
+ const textContent = options.normalizeWhitespace ? normalize(node.textContent) : node.textContent.replace(/\u00a0/g, " ");
814
+ const checkingWithEmptyString = textContent !== "" && checkWith === "";
815
+ return {
816
+ pass: !checkingWithEmptyString && matches(textContent, checkWith),
817
+ message: () => {
818
+ const to = this.isNot ? "not to" : "to";
819
+ return getMessage(
820
+ this,
821
+ this.utils.matcherHint(
822
+ `${this.isNot ? ".not" : ""}.toHaveTextContent`,
823
+ "element",
824
+ ""
825
+ ),
826
+ checkingWithEmptyString ? `Checking with empty string will always match, use .toBeEmptyDOMElement() instead` : `Expected element ${to} have text content`,
827
+ checkWith,
828
+ "Received",
829
+ textContent
830
+ );
831
+ }
832
+ };
833
+ }
834
+
835
+ // src/to-have-accessible-description.js
836
+ import { computeAccessibleDescription } from "dom-accessibility-api";
837
+ function toHaveAccessibleDescription(htmlElement, expectedAccessibleDescription) {
838
+ checkHtmlElement(htmlElement, toHaveAccessibleDescription, this);
839
+ const actualAccessibleDescription = computeAccessibleDescription(htmlElement);
840
+ const missingExpectedValue = arguments.length === 1;
841
+ let pass = false;
842
+ if (missingExpectedValue) {
843
+ pass = actualAccessibleDescription !== "";
844
+ } else {
845
+ pass = expectedAccessibleDescription instanceof RegExp ? expectedAccessibleDescription.test(actualAccessibleDescription) : this.equals(
846
+ actualAccessibleDescription,
847
+ expectedAccessibleDescription
848
+ );
849
+ }
850
+ return {
851
+ pass,
852
+ message: () => {
853
+ const to = this.isNot ? "not to" : "to";
854
+ return getMessage(
855
+ this,
856
+ this.utils.matcherHint(
857
+ `${this.isNot ? ".not" : ""}.${toHaveAccessibleDescription.name}`,
858
+ "element",
859
+ ""
860
+ ),
861
+ `Expected element ${to} have accessible description`,
862
+ expectedAccessibleDescription,
863
+ "Received",
864
+ actualAccessibleDescription
865
+ );
866
+ }
867
+ };
868
+ }
869
+
870
+ // src/to-have-accessible-name.js
871
+ import { computeAccessibleName } from "dom-accessibility-api";
872
+ function toHaveAccessibleName(htmlElement, expectedAccessibleName) {
873
+ checkHtmlElement(htmlElement, toHaveAccessibleName, this);
874
+ const actualAccessibleName = computeAccessibleName(htmlElement);
875
+ const missingExpectedValue = arguments.length === 1;
876
+ let pass = false;
877
+ if (missingExpectedValue) {
878
+ pass = actualAccessibleName !== "";
879
+ } else {
880
+ pass = expectedAccessibleName instanceof RegExp ? expectedAccessibleName.test(actualAccessibleName) : this.equals(actualAccessibleName, expectedAccessibleName);
881
+ }
882
+ return {
883
+ pass,
884
+ message: () => {
885
+ const to = this.isNot ? "not to" : "to";
886
+ return getMessage(
887
+ this,
888
+ this.utils.matcherHint(
889
+ `${this.isNot ? ".not" : ""}.${toHaveAccessibleName.name}`,
890
+ "element",
891
+ ""
892
+ ),
893
+ `Expected element ${to} have accessible name`,
894
+ expectedAccessibleName,
895
+ "Received",
896
+ actualAccessibleName
897
+ );
898
+ }
899
+ };
900
+ }
901
+
902
+ // src/to-have-attribute.js
903
+ function printAttribute(stringify, name, value) {
904
+ return value === void 0 ? name : `${name}=${stringify(value)}`;
905
+ }
906
+ function getAttributeComment(stringify, name, value) {
907
+ return value === void 0 ? `element.hasAttribute(${stringify(name)})` : `element.getAttribute(${stringify(name)}) === ${stringify(value)}`;
908
+ }
909
+ function toHaveAttribute(htmlElement, name, expectedValue) {
910
+ checkHtmlElement(htmlElement, toHaveAttribute, this);
911
+ const isExpectedValuePresent = expectedValue !== void 0;
912
+ const hasAttribute = htmlElement.hasAttribute(name);
913
+ const receivedValue = htmlElement.getAttribute(name);
914
+ return {
915
+ pass: isExpectedValuePresent ? hasAttribute && this.equals(receivedValue, expectedValue) : hasAttribute,
916
+ message: () => {
917
+ const to = this.isNot ? "not to" : "to";
918
+ const receivedAttribute = hasAttribute ? printAttribute(this.utils.stringify, name, receivedValue) : null;
919
+ const matcher = this.utils.matcherHint(
920
+ `${this.isNot ? ".not" : ""}.toHaveAttribute`,
921
+ "element",
922
+ this.utils.printExpected(name),
923
+ {
924
+ secondArgument: isExpectedValuePresent ? this.utils.printExpected(expectedValue) : void 0,
925
+ comment: getAttributeComment(
926
+ this.utils.stringify,
927
+ name,
928
+ expectedValue
929
+ )
930
+ }
931
+ );
932
+ return getMessage(
933
+ this,
934
+ matcher,
935
+ `Expected the element ${to} have attribute`,
936
+ printAttribute(this.utils.stringify, name, expectedValue),
937
+ "Received",
938
+ receivedAttribute
939
+ );
940
+ }
941
+ };
942
+ }
943
+
944
+ // src/to-have-class.js
945
+ function getExpectedClassNamesAndOptions(params) {
946
+ const lastParam = params.pop();
947
+ let expectedClassNames, options;
948
+ if (typeof lastParam === "object") {
949
+ expectedClassNames = params;
950
+ options = lastParam;
951
+ } else {
952
+ expectedClassNames = params.concat(lastParam);
953
+ options = { exact: false };
954
+ }
955
+ return { expectedClassNames, options };
956
+ }
957
+ function splitClassNames(str) {
958
+ if (!str) {
959
+ return [];
960
+ }
961
+ return str.split(/\s+/).filter((s) => s.length > 0);
962
+ }
963
+ function isSubset(subset, superset) {
964
+ return subset.every((item) => superset.includes(item));
965
+ }
966
+ function toHaveClass(htmlElement, ...params) {
967
+ checkHtmlElement(htmlElement, toHaveClass, this);
968
+ const { expectedClassNames, options } = getExpectedClassNamesAndOptions(params);
969
+ const received = splitClassNames(htmlElement.getAttribute("class"));
970
+ const expected = expectedClassNames.reduce(
971
+ (acc, className) => acc.concat(splitClassNames(className)),
972
+ []
973
+ );
974
+ if (options.exact) {
975
+ return {
976
+ pass: isSubset(expected, received) && expected.length === received.length,
977
+ message: () => {
978
+ const to = this.isNot ? "not to" : "to";
979
+ return getMessage(
980
+ this,
981
+ this.utils.matcherHint(
982
+ `${this.isNot ? ".not" : ""}.toHaveClass`,
983
+ "element",
984
+ this.utils.printExpected(expected.join(" "))
985
+ ),
986
+ `Expected the element ${to} have EXACTLY defined classes`,
987
+ expected.join(" "),
988
+ "Received",
989
+ received.join(" ")
990
+ );
991
+ }
992
+ };
993
+ }
994
+ return expected.length > 0 ? {
995
+ pass: isSubset(expected, received),
996
+ message: () => {
997
+ const to = this.isNot ? "not to" : "to";
998
+ return getMessage(
999
+ this,
1000
+ this.utils.matcherHint(
1001
+ `${this.isNot ? ".not" : ""}.toHaveClass`,
1002
+ "element",
1003
+ this.utils.printExpected(expected.join(" "))
1004
+ ),
1005
+ `Expected the element ${to} have class`,
1006
+ expected.join(" "),
1007
+ "Received",
1008
+ received.join(" ")
1009
+ );
1010
+ }
1011
+ } : {
1012
+ pass: this.isNot ? received.length > 0 : false,
1013
+ message: () => this.isNot ? getMessage(
1014
+ this,
1015
+ this.utils.matcherHint(".not.toHaveClass", "element", ""),
1016
+ "Expected the element to have classes",
1017
+ "(none)",
1018
+ "Received",
1019
+ received.join(" ")
1020
+ ) : [
1021
+ this.utils.matcherHint(`.toHaveClass`, "element"),
1022
+ "At least one expected class must be provided."
1023
+ ].join("\n")
1024
+ };
1025
+ }
1026
+
1027
+ // src/to-have-style.js
1028
+ import chalk from "chalk";
1029
+ function getStyleDeclaration(document, css) {
1030
+ const styles = {};
1031
+ const copy = document.createElement("div");
1032
+ Object.keys(css).forEach((property) => {
1033
+ copy.style[property] = css[property];
1034
+ styles[property] = copy.style[property];
1035
+ });
1036
+ return styles;
1037
+ }
1038
+ function isSubset2(styles, computedStyle) {
1039
+ return !!Object.keys(styles).length && Object.entries(styles).every(
1040
+ ([prop, value]) => computedStyle[prop] === value || computedStyle.getPropertyValue(prop.toLowerCase()) === value
1041
+ );
1042
+ }
1043
+ function printoutStyles(styles) {
1044
+ return Object.keys(styles).sort().map((prop) => `${prop}: ${styles[prop]};`).join("\n");
1045
+ }
1046
+ function expectedDiff(diffFn, expected, computedStyles) {
1047
+ const received = Array.from(computedStyles).filter((prop) => expected[prop] !== void 0).reduce(
1048
+ (obj, prop) => Object.assign(obj, { [prop]: computedStyles.getPropertyValue(prop) }),
1049
+ {}
1050
+ );
1051
+ const diffOutput = diffFn(printoutStyles(expected), printoutStyles(received));
1052
+ return diffOutput.replace(`${chalk.red("+ Received")}
1053
+ `, "");
1054
+ }
1055
+ function toHaveStyle(htmlElement, css) {
1056
+ checkHtmlElement(htmlElement, toHaveStyle, this);
1057
+ const parsedCSS = typeof css === "object" ? css : parseCSS(css, toHaveStyle, this);
1058
+ const { getComputedStyle } = htmlElement.ownerDocument.defaultView;
1059
+ const expected = getStyleDeclaration(htmlElement.ownerDocument, parsedCSS);
1060
+ const received = getComputedStyle(htmlElement);
1061
+ return {
1062
+ pass: isSubset2(expected, received),
1063
+ message: () => {
1064
+ const matcher = `${this.isNot ? ".not" : ""}.toHaveStyle`;
1065
+ return [
1066
+ this.utils.matcherHint(matcher, "element", ""),
1067
+ expectedDiff(this.utils.diff, expected, received)
1068
+ ].join("\n\n");
1069
+ }
1070
+ };
1071
+ }
1072
+
1073
+ // src/to-have-focus.js
1074
+ function toHaveFocus(element) {
1075
+ checkHtmlElement(element, toHaveFocus, this);
1076
+ return {
1077
+ pass: element.ownerDocument.activeElement === element,
1078
+ message: () => {
1079
+ return [
1080
+ this.utils.matcherHint(
1081
+ `${this.isNot ? ".not" : ""}.toHaveFocus`,
1082
+ "element",
1083
+ ""
1084
+ ),
1085
+ "",
1086
+ ...this.isNot ? [
1087
+ "Received element is focused:",
1088
+ ` ${this.utils.printReceived(element)}`
1089
+ ] : [
1090
+ "Expected element with focus:",
1091
+ ` ${this.utils.printExpected(element)}`,
1092
+ "Received element with focus:",
1093
+ ` ${this.utils.printReceived(
1094
+ element.ownerDocument.activeElement
1095
+ )}`
1096
+ ]
1097
+ ].join("\n");
1098
+ }
1099
+ };
1100
+ }
1101
+
1102
+ // src/to-have-form-values.ts
1103
+ import escape from "css.escape";
1104
+ import { isEqualWith, uniq } from "lodash-es";
1105
+ function getMultiElementValue(elements) {
1106
+ const types = uniq(elements.map((element) => element.type));
1107
+ if (types.length !== 1) {
1108
+ throw new Error(
1109
+ "Multiple form elements with the same name must be of the same type"
1110
+ );
1111
+ }
1112
+ switch (types[0]) {
1113
+ case "radio": {
1114
+ const theChosenOne = elements.find((radio) => radio.checked);
1115
+ return theChosenOne ? theChosenOne.value : void 0;
1116
+ }
1117
+ case "checkbox":
1118
+ return elements.filter((checkbox) => checkbox.checked).map((checkbox) => checkbox.value);
1119
+ default:
1120
+ return elements.map((element) => element.value);
1121
+ }
1122
+ }
1123
+ function getFormValue(container, name) {
1124
+ container.elements;
1125
+ const elements = [
1126
+ ...container.querySelectorAll(`[name="${escape(name)}"]`)
1127
+ ];
1128
+ if (elements.length === 0) {
1129
+ return void 0;
1130
+ }
1131
+ switch (elements.length) {
1132
+ case 1:
1133
+ return getSingleElementValue(elements[0]);
1134
+ default:
1135
+ return getMultiElementValue(elements);
1136
+ }
1137
+ }
1138
+ function getPureName(name) {
1139
+ return /\[\]$/.test(name) ? name.slice(0, -2) : name;
1140
+ }
1141
+ function getAllFormValues(container) {
1142
+ const names = Array.from(container.elements).map(
1143
+ (element) => element.name
1144
+ );
1145
+ return names.reduce(
1146
+ (obj, name) => ({
1147
+ ...obj,
1148
+ [getPureName(name)]: getFormValue(container, name)
1149
+ }),
1150
+ {}
1151
+ );
1152
+ }
1153
+ function toHaveFormValues(formElement, expectedValues) {
1154
+ checkHtmlElement(formElement, toHaveFormValues, this);
1155
+ if (!formElement.elements) {
1156
+ throw new Error("toHaveFormValues must be called on a form or a fieldset");
1157
+ }
1158
+ const formValues = getAllFormValues(formElement);
1159
+ return {
1160
+ pass: Object.entries(expectedValues).every(
1161
+ ([name, expectedValue]) => isEqualWith(formValues[name], expectedValue, compareArraysAsSet)
1162
+ ),
1163
+ message: () => {
1164
+ const to = this.isNot ? "not to" : "to";
1165
+ const matcher = `${this.isNot ? ".not" : ""}.toHaveFormValues`;
1166
+ const commonKeyValues = Object.keys(formValues).filter((key) => expectedValues.hasOwnProperty(key)).reduce((obj, key) => ({ ...obj, [key]: formValues[key] }), {});
1167
+ return [
1168
+ this.utils.matcherHint(matcher, "element", ""),
1169
+ `Expected the element ${to} have form values`,
1170
+ this.utils.diff(expectedValues, commonKeyValues)
1171
+ ].join("\n\n");
1172
+ }
1173
+ };
1174
+ }
1175
+
1176
+ // src/to-be-visible.js
1177
+ function isStyleVisible(element) {
1178
+ const { getComputedStyle } = element.ownerDocument.defaultView;
1179
+ const { display: display2, visibility, opacity } = getComputedStyle(element);
1180
+ return display2 !== "none" && visibility !== "hidden" && visibility !== "collapse" && opacity !== "0" && opacity !== 0;
1181
+ }
1182
+ function isAttributeVisible(element, previousElement) {
1183
+ let detailsVisibility;
1184
+ if (previousElement) {
1185
+ detailsVisibility = element.nodeName === "DETAILS" && previousElement.nodeName !== "SUMMARY" ? element.hasAttribute("open") : true;
1186
+ } else {
1187
+ detailsVisibility = element.nodeName === "DETAILS" ? element.hasAttribute("open") : true;
1188
+ }
1189
+ return !element.hasAttribute("hidden") && detailsVisibility;
1190
+ }
1191
+ function isElementVisible(element, previousElement) {
1192
+ return isStyleVisible(element) && isAttributeVisible(element, previousElement) && (!element.parentElement || isElementVisible(element.parentElement, element));
1193
+ }
1194
+ function toBeVisible(element) {
1195
+ checkHtmlElement(element, toBeVisible, this);
1196
+ const isInDocument = element.ownerDocument === element.getRootNode({ composed: true });
1197
+ const isVisible = isInDocument && isElementVisible(element);
1198
+ return {
1199
+ pass: isVisible,
1200
+ message: () => {
1201
+ const is = isVisible ? "is" : "is not";
1202
+ return [
1203
+ this.utils.matcherHint(
1204
+ `${this.isNot ? ".not" : ""}.toBeVisible`,
1205
+ "element",
1206
+ ""
1207
+ ),
1208
+ "",
1209
+ `Received element ${is} visible${isInDocument ? "" : " (element is not in the document)"}:`,
1210
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1211
+ ].join("\n");
1212
+ }
1213
+ };
1214
+ }
1215
+
1216
+ // src/to-be-disabled.js
1217
+ var FORM_TAGS = [
1218
+ "fieldset",
1219
+ "input",
1220
+ "select",
1221
+ "optgroup",
1222
+ "option",
1223
+ "button",
1224
+ "textarea"
1225
+ ];
1226
+ function isFirstLegendChildOfFieldset(element, parent) {
1227
+ return getTag(element) === "legend" && getTag(parent) === "fieldset" && element.isSameNode(
1228
+ Array.from(parent.children).find((child) => getTag(child) === "legend")
1229
+ );
1230
+ }
1231
+ function isElementDisabledByParent(element, parent) {
1232
+ return isElementDisabled(parent) && !isFirstLegendChildOfFieldset(element, parent);
1233
+ }
1234
+ function isCustomElement(tag) {
1235
+ return tag.includes("-");
1236
+ }
1237
+ function canElementBeDisabled(element) {
1238
+ const tag = getTag(element);
1239
+ return FORM_TAGS.includes(tag) || isCustomElement(tag);
1240
+ }
1241
+ function isElementDisabled(element) {
1242
+ return canElementBeDisabled(element) && element.hasAttribute("disabled");
1243
+ }
1244
+ function isAncestorDisabled(element) {
1245
+ const parent = element.parentElement;
1246
+ return Boolean(parent) && (isElementDisabledByParent(element, parent) || isAncestorDisabled(parent));
1247
+ }
1248
+ function isElementOrAncestorDisabled(element) {
1249
+ return canElementBeDisabled(element) && (isElementDisabled(element) || isAncestorDisabled(element));
1250
+ }
1251
+ function toBeDisabled(element) {
1252
+ checkHtmlElement(element, toBeDisabled, this);
1253
+ const isDisabled = isElementOrAncestorDisabled(element);
1254
+ return {
1255
+ pass: isDisabled,
1256
+ message: () => {
1257
+ const is = isDisabled ? "is" : "is not";
1258
+ return [
1259
+ this.utils.matcherHint(
1260
+ `${this.isNot ? ".not" : ""}.toBeDisabled`,
1261
+ "element",
1262
+ ""
1263
+ ),
1264
+ "",
1265
+ `Received element ${is} disabled:`,
1266
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1267
+ ].join("\n");
1268
+ }
1269
+ };
1270
+ }
1271
+ function toBeEnabled(element) {
1272
+ checkHtmlElement(element, toBeEnabled, this);
1273
+ const isEnabled = !isElementOrAncestorDisabled(element);
1274
+ return {
1275
+ pass: isEnabled,
1276
+ message: () => {
1277
+ const is = isEnabled ? "is" : "is not";
1278
+ return [
1279
+ this.utils.matcherHint(
1280
+ `${this.isNot ? ".not" : ""}.toBeEnabled`,
1281
+ "element",
1282
+ ""
1283
+ ),
1284
+ "",
1285
+ `Received element ${is} enabled:`,
1286
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1287
+ ].join("\n");
1288
+ }
1289
+ };
1290
+ }
1291
+
1292
+ // src/to-be-required.js
1293
+ var FORM_TAGS2 = ["select", "textarea"];
1294
+ var ARIA_FORM_TAGS = ["input", "select", "textarea"];
1295
+ var UNSUPPORTED_INPUT_TYPES = [
1296
+ "color",
1297
+ "hidden",
1298
+ "range",
1299
+ "submit",
1300
+ "image",
1301
+ "reset"
1302
+ ];
1303
+ var SUPPORTED_ARIA_ROLES = [
1304
+ "combobox",
1305
+ "gridcell",
1306
+ "radiogroup",
1307
+ "spinbutton",
1308
+ "tree"
1309
+ ];
1310
+ function isRequiredOnFormTagsExceptInput(element) {
1311
+ return FORM_TAGS2.includes(getTag(element)) && element.hasAttribute("required");
1312
+ }
1313
+ function isRequiredOnSupportedInput(element) {
1314
+ return getTag(element) === "input" && element.hasAttribute("required") && (element.hasAttribute("type") && !UNSUPPORTED_INPUT_TYPES.includes(element.getAttribute("type")) || !element.hasAttribute("type"));
1315
+ }
1316
+ function isElementRequiredByARIA(element) {
1317
+ return element.hasAttribute("aria-required") && element.getAttribute("aria-required") === "true" && (ARIA_FORM_TAGS.includes(getTag(element)) || element.hasAttribute("role") && SUPPORTED_ARIA_ROLES.includes(element.getAttribute("role")));
1318
+ }
1319
+ function toBeRequired(element) {
1320
+ checkHtmlElement(element, toBeRequired, this);
1321
+ const isRequired = isRequiredOnFormTagsExceptInput(element) || isRequiredOnSupportedInput(element) || isElementRequiredByARIA(element);
1322
+ return {
1323
+ pass: isRequired,
1324
+ message: () => {
1325
+ const is = isRequired ? "is" : "is not";
1326
+ return [
1327
+ this.utils.matcherHint(
1328
+ `${this.isNot ? ".not" : ""}.toBeRequired`,
1329
+ "element",
1330
+ ""
1331
+ ),
1332
+ "",
1333
+ `Received element ${is} required:`,
1334
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1335
+ ].join("\n");
1336
+ }
1337
+ };
1338
+ }
1339
+
1340
+ // src/to-be-invalid.js
1341
+ var FORM_TAGS3 = ["form", "input", "select", "textarea"];
1342
+ function isElementHavingAriaInvalid(element) {
1343
+ return element.hasAttribute("aria-invalid") && element.getAttribute("aria-invalid") !== "false";
1344
+ }
1345
+ function isSupportsValidityMethod(element) {
1346
+ return FORM_TAGS3.includes(getTag(element));
1347
+ }
1348
+ function isElementInvalid(element) {
1349
+ const isHaveAriaInvalid = isElementHavingAriaInvalid(element);
1350
+ if (isSupportsValidityMethod(element)) {
1351
+ return isHaveAriaInvalid || !element.checkValidity();
1352
+ } else {
1353
+ return isHaveAriaInvalid;
1354
+ }
1355
+ }
1356
+ function toBeInvalid(element) {
1357
+ checkHtmlElement(element, toBeInvalid, this);
1358
+ const isInvalid = isElementInvalid(element);
1359
+ return {
1360
+ pass: isInvalid,
1361
+ message: () => {
1362
+ const is = isInvalid ? "is" : "is not";
1363
+ return [
1364
+ this.utils.matcherHint(
1365
+ `${this.isNot ? ".not" : ""}.toBeInvalid`,
1366
+ "element",
1367
+ ""
1368
+ ),
1369
+ "",
1370
+ `Received element ${is} currently invalid:`,
1371
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1372
+ ].join("\n");
1373
+ }
1374
+ };
1375
+ }
1376
+ function toBeValid(element) {
1377
+ checkHtmlElement(element, toBeValid, this);
1378
+ const isValid = !isElementInvalid(element);
1379
+ return {
1380
+ pass: isValid,
1381
+ message: () => {
1382
+ const is = isValid ? "is" : "is not";
1383
+ return [
1384
+ this.utils.matcherHint(
1385
+ `${this.isNot ? ".not" : ""}.toBeValid`,
1386
+ "element",
1387
+ ""
1388
+ ),
1389
+ "",
1390
+ `Received element ${is} currently valid:`,
1391
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1392
+ ].join("\n");
1393
+ }
1394
+ };
1395
+ }
1396
+
1397
+ // src/to-have-value.js
1398
+ import { isEqualWith as isEqualWith2 } from "lodash-es";
1399
+ function toHaveValue(htmlElement, expectedValue) {
1400
+ checkHtmlElement(htmlElement, toHaveValue, this);
1401
+ if (htmlElement.tagName.toLowerCase() === "input" && ["checkbox", "radio"].includes(htmlElement.type)) {
1402
+ throw new Error(
1403
+ "input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead"
1404
+ );
1405
+ }
1406
+ const receivedValue = getSingleElementValue(htmlElement);
1407
+ const expectsValue = expectedValue !== void 0;
1408
+ let expectedTypedValue = expectedValue;
1409
+ let receivedTypedValue = receivedValue;
1410
+ if (expectedValue == receivedValue && expectedValue !== receivedValue) {
1411
+ expectedTypedValue = `${expectedValue} (${typeof expectedValue})`;
1412
+ receivedTypedValue = `${receivedValue} (${typeof receivedValue})`;
1413
+ }
1414
+ return {
1415
+ pass: expectsValue ? isEqualWith2(receivedValue, expectedValue, compareArraysAsSet) : Boolean(receivedValue),
1416
+ message: () => {
1417
+ const to = this.isNot ? "not to" : "to";
1418
+ const matcher = this.utils.matcherHint(
1419
+ `${this.isNot ? ".not" : ""}.toHaveValue`,
1420
+ "element",
1421
+ expectedValue
1422
+ );
1423
+ return getMessage(
1424
+ this,
1425
+ matcher,
1426
+ `Expected the element ${to} have value`,
1427
+ expectsValue ? expectedTypedValue : "(any)",
1428
+ "Received",
1429
+ receivedTypedValue
1430
+ );
1431
+ }
1432
+ };
1433
+ }
1434
+
1435
+ // src/to-have-display-value.js
1436
+ function toHaveDisplayValue(htmlElement, expectedValue) {
1437
+ checkHtmlElement(htmlElement, toHaveDisplayValue, this);
1438
+ const tagName = htmlElement.tagName.toLowerCase();
1439
+ if (!["select", "input", "textarea"].includes(tagName)) {
1440
+ throw new Error(
1441
+ ".toHaveDisplayValue() currently supports only input, textarea or select elements, try with another matcher instead."
1442
+ );
1443
+ }
1444
+ if (tagName === "input" && ["radio", "checkbox"].includes(htmlElement.type)) {
1445
+ throw new Error(
1446
+ `.toHaveDisplayValue() currently does not support input[type="${htmlElement.type}"], try with another matcher instead.`
1447
+ );
1448
+ }
1449
+ const values = getValues(tagName, htmlElement);
1450
+ const expectedValues = getExpectedValues(expectedValue);
1451
+ const numberOfMatchesWithValues = expectedValues.filter(
1452
+ (expected) => values.some(
1453
+ (value) => expected instanceof RegExp ? expected.test(value) : this.equals(value, String(expected))
1454
+ )
1455
+ ).length;
1456
+ const matchedWithAllValues = numberOfMatchesWithValues === values.length;
1457
+ const matchedWithAllExpectedValues = numberOfMatchesWithValues === expectedValues.length;
1458
+ return {
1459
+ pass: matchedWithAllValues && matchedWithAllExpectedValues,
1460
+ message: () => getMessage(
1461
+ this,
1462
+ this.utils.matcherHint(
1463
+ `${this.isNot ? ".not" : ""}.toHaveDisplayValue`,
1464
+ "element",
1465
+ ""
1466
+ ),
1467
+ `Expected element ${this.isNot ? "not " : ""}to have display value`,
1468
+ expectedValue,
1469
+ "Received",
1470
+ values
1471
+ )
1472
+ };
1473
+ }
1474
+ function getValues(tagName, htmlElement) {
1475
+ return tagName === "select" ? Array.from(htmlElement).filter((option) => option.selected).map((option) => option.textContent) : [htmlElement.value];
1476
+ }
1477
+ function getExpectedValues(expectedValue) {
1478
+ return expectedValue instanceof Array ? expectedValue : [expectedValue];
1479
+ }
1480
+
1481
+ // src/to-be-checked.js
1482
+ import { createRequire } from "module";
1483
+ var require2 = createRequire(import.meta.url);
1484
+ var { roles } = require2("aria-query");
1485
+ function toBeChecked(element) {
1486
+ checkHtmlElement(element, toBeChecked, this);
1487
+ const isValidInput = () => {
1488
+ return element.tagName.toLowerCase() === "input" && ["checkbox", "radio"].includes(element.type);
1489
+ };
1490
+ const isValidAriaElement = () => {
1491
+ return roleSupportsChecked(element.getAttribute("role")) && ["true", "false"].includes(element.getAttribute("aria-checked"));
1492
+ };
1493
+ if (!isValidInput() && !isValidAriaElement()) {
1494
+ return {
1495
+ pass: false,
1496
+ message: () => `only inputs with type="checkbox" or type="radio" or elements with ${supportedRolesSentence()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`
1497
+ };
1498
+ }
1499
+ const isChecked = () => {
1500
+ if (isValidInput())
1501
+ return element.checked;
1502
+ return element.getAttribute("aria-checked") === "true";
1503
+ };
1504
+ return {
1505
+ pass: isChecked(),
1506
+ message: () => {
1507
+ const is = isChecked() ? "is" : "is not";
1508
+ return [
1509
+ this.utils.matcherHint(
1510
+ `${this.isNot ? ".not" : ""}.toBeChecked`,
1511
+ "element",
1512
+ ""
1513
+ ),
1514
+ "",
1515
+ `Received element ${is} checked:`,
1516
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1517
+ ].join("\n");
1518
+ }
1519
+ };
1520
+ }
1521
+ function supportedRolesSentence() {
1522
+ return toSentence(
1523
+ supportedRoles().map((role) => `role="${role}"`),
1524
+ { lastWordConnector: " or " }
1525
+ );
1526
+ }
1527
+ function supportedRoles() {
1528
+ return roles.keys().filter(roleSupportsChecked);
1529
+ }
1530
+ function roleSupportsChecked(role) {
1531
+ return roles.get(role)?.props["aria-checked"] !== void 0;
1532
+ }
1533
+
1534
+ // src/to-be-partially-checked.js
1535
+ function toBePartiallyChecked(element) {
1536
+ checkHtmlElement(element, toBePartiallyChecked, this);
1537
+ const isValidInput = () => {
1538
+ return element.tagName.toLowerCase() === "input" && element.type === "checkbox";
1539
+ };
1540
+ const isValidAriaElement = () => {
1541
+ return element.getAttribute("role") === "checkbox";
1542
+ };
1543
+ if (!isValidInput() && !isValidAriaElement()) {
1544
+ return {
1545
+ pass: false,
1546
+ message: () => 'only inputs with type="checkbox" or elements with role="checkbox" and a valid aria-checked attribute can be used with .toBePartiallyChecked(). Use .toHaveValue() instead'
1547
+ };
1548
+ }
1549
+ const isPartiallyChecked = () => {
1550
+ const isAriaMixed = element.getAttribute("aria-checked") === "mixed";
1551
+ if (isValidInput()) {
1552
+ return element.indeterminate || isAriaMixed;
1553
+ }
1554
+ return isAriaMixed;
1555
+ };
1556
+ return {
1557
+ pass: isPartiallyChecked(),
1558
+ message: () => {
1559
+ const is = isPartiallyChecked() ? "is" : "is not";
1560
+ return [
1561
+ this.utils.matcherHint(
1562
+ `${this.isNot ? ".not" : ""}.toBePartiallyChecked`,
1563
+ "element",
1564
+ ""
1565
+ ),
1566
+ "",
1567
+ `Received element ${is} partially checked:`,
1568
+ ` ${this.utils.printReceived(element.cloneNode(false))}`
1569
+ ].join("\n");
1570
+ }
1571
+ };
1572
+ }
1573
+
1574
+ // src/to-have-description.js
1575
+ function toHaveDescription(htmlElement, checkWith) {
1576
+ deprecate("toHaveDescription", "Please use toHaveAccessibleDescription.");
1577
+ checkHtmlElement(htmlElement, toHaveDescription, this);
1578
+ const expectsDescription = checkWith !== void 0;
1579
+ const descriptionIDRaw = htmlElement.getAttribute("aria-describedby") || "";
1580
+ const descriptionIDs = descriptionIDRaw.split(/\s+/).filter(Boolean);
1581
+ let description = "";
1582
+ if (descriptionIDs.length > 0) {
1583
+ const document = htmlElement.ownerDocument;
1584
+ const descriptionEls = descriptionIDs.map((descriptionID) => document.getElementById(descriptionID)).filter(Boolean);
1585
+ description = normalize(
1586
+ descriptionEls.map((el) => el.textContent).join(" ")
1587
+ );
1588
+ }
1589
+ return {
1590
+ pass: expectsDescription ? checkWith instanceof RegExp ? checkWith.test(description) : this.equals(description, checkWith) : Boolean(description),
1591
+ message: () => {
1592
+ const to = this.isNot ? "not to" : "to";
1593
+ return getMessage(
1594
+ this,
1595
+ this.utils.matcherHint(
1596
+ `${this.isNot ? ".not" : ""}.toHaveDescription`,
1597
+ "element",
1598
+ ""
1599
+ ),
1600
+ `Expected the element ${to} have description`,
1601
+ this.utils.printExpected(checkWith),
1602
+ "Received",
1603
+ this.utils.printReceived(description)
1604
+ );
1605
+ }
1606
+ };
1607
+ }
1608
+
1609
+ // src/to-have-errormessage.js
1610
+ function toHaveErrorMessage(htmlElement, checkWith) {
1611
+ checkHtmlElement(htmlElement, toHaveErrorMessage, this);
1612
+ if (!htmlElement.hasAttribute("aria-invalid") || htmlElement.getAttribute("aria-invalid") === "false") {
1613
+ const not = this.isNot ? ".not" : "";
1614
+ return {
1615
+ pass: false,
1616
+ message: () => {
1617
+ return getMessage(
1618
+ this,
1619
+ this.utils.matcherHint(`${not}.toHaveErrorMessage`, "element", ""),
1620
+ `Expected the element to have invalid state indicated by`,
1621
+ 'aria-invalid="true"',
1622
+ "Received",
1623
+ htmlElement.hasAttribute("aria-invalid") ? `aria-invalid="${htmlElement.getAttribute("aria-invalid")}"` : this.utils.printReceived("")
1624
+ );
1625
+ }
1626
+ };
1627
+ }
1628
+ const expectsErrorMessage = checkWith !== void 0;
1629
+ const errormessageIDRaw = htmlElement.getAttribute("aria-errormessage") || "";
1630
+ const errormessageIDs = errormessageIDRaw.split(/\s+/).filter(Boolean);
1631
+ let errormessage = "";
1632
+ if (errormessageIDs.length > 0) {
1633
+ const document = htmlElement.ownerDocument;
1634
+ const errormessageEls = errormessageIDs.map((errormessageID) => document.getElementById(errormessageID)).filter(Boolean);
1635
+ errormessage = normalize(
1636
+ errormessageEls.map((el) => el.textContent).join(" ")
1637
+ );
1638
+ }
1639
+ return {
1640
+ pass: expectsErrorMessage ? checkWith instanceof RegExp ? checkWith.test(errormessage) : this.equals(errormessage, checkWith) : Boolean(errormessage),
1641
+ message: () => {
1642
+ const to = this.isNot ? "not to" : "to";
1643
+ return getMessage(
1644
+ this,
1645
+ this.utils.matcherHint(
1646
+ `${this.isNot ? ".not" : ""}.toHaveErrorMessage`,
1647
+ "element",
1648
+ ""
1649
+ ),
1650
+ `Expected the element ${to} have error message`,
1651
+ this.utils.printExpected(checkWith),
1652
+ "Received",
1653
+ this.utils.printReceived(errormessage)
1654
+ );
1655
+ }
1656
+ };
1657
+ }
1658
+
1659
+ export {
1660
+ toBeInTheDOM,
1661
+ toBeInTheDocument,
1662
+ toBeEmpty,
1663
+ toBeEmptyDOMElement,
1664
+ toContainElement,
1665
+ toContainHTML,
1666
+ toHaveTextContent,
1667
+ toHaveAccessibleDescription,
1668
+ toHaveAccessibleName,
1669
+ toHaveAttribute,
1670
+ toHaveClass,
1671
+ toHaveStyle,
1672
+ toHaveFocus,
1673
+ toHaveFormValues,
1674
+ toBeVisible,
1675
+ toBeDisabled,
1676
+ toBeEnabled,
1677
+ toBeRequired,
1678
+ toBeInvalid,
1679
+ toBeValid,
1680
+ toHaveValue,
1681
+ toHaveDisplayValue,
1682
+ toBeChecked,
1683
+ toBePartiallyChecked,
1684
+ toHaveDescription,
1685
+ toHaveErrorMessage,
1686
+ matchers_exports
1687
+ };
1688
+ //# sourceMappingURL=chunk-V52HJAAH.js.map