1 | var QUnitDOM = (function (exports) {
|
2 | 'use strict';
|
3 |
|
4 | function exists(options, message) {
|
5 | var expectedCount = null;
|
6 | if (typeof options === 'string') {
|
7 | message = options;
|
8 | }
|
9 | else if (options) {
|
10 | expectedCount = options.count;
|
11 | }
|
12 | var elements = this.findElements();
|
13 | if (expectedCount === null) {
|
14 | var result = elements.length > 0;
|
15 | var expected = format$1(this.targetDescription);
|
16 | var actual = result ? expected : format$1(this.targetDescription, 0);
|
17 | if (!message) {
|
18 | message = expected;
|
19 | }
|
20 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
21 | }
|
22 | else if (typeof expectedCount === 'number') {
|
23 | var result = elements.length === expectedCount;
|
24 | var actual = format$1(this.targetDescription, elements.length);
|
25 | var expected = format$1(this.targetDescription, expectedCount);
|
26 | if (!message) {
|
27 | message = expected;
|
28 | }
|
29 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
30 | }
|
31 | else {
|
32 | throw new TypeError("Unexpected Parameter: " + expectedCount);
|
33 | }
|
34 | }
|
35 | function format$1(selector, num) {
|
36 | if (num === undefined || num === null) {
|
37 | return "Element " + selector + " exists";
|
38 | }
|
39 | else if (num === 0) {
|
40 | return "Element " + selector + " does not exist";
|
41 | }
|
42 | else if (num === 1) {
|
43 | return "Element " + selector + " exists once";
|
44 | }
|
45 | else if (num === 2) {
|
46 | return "Element " + selector + " exists twice";
|
47 | }
|
48 | else {
|
49 | return "Element " + selector + " exists " + num + " times";
|
50 | }
|
51 | }
|
52 |
|
53 |
|
54 | function elementToString(el) {
|
55 | if (!el)
|
56 | return '<not found>';
|
57 | var desc;
|
58 | if (el instanceof NodeList) {
|
59 | if (el.length === 0) {
|
60 | return 'empty NodeList';
|
61 | }
|
62 | desc = Array.prototype.slice.call(el, 0, 5).map(elementToString).join(', ');
|
63 | return el.length > 5 ? desc + "... (+" + (el.length - 5) + " more)" : desc;
|
64 | }
|
65 | if (!(el instanceof HTMLElement || el instanceof SVGElement)) {
|
66 | return String(el);
|
67 | }
|
68 | desc = el.tagName.toLowerCase();
|
69 | if (el.id) {
|
70 | desc += "#" + el.id;
|
71 | }
|
72 | if (el.className && !(el.className instanceof SVGAnimatedString)) {
|
73 | desc += "." + String(el.className).replace(/\s+/g, '.');
|
74 | }
|
75 | Array.prototype.forEach.call(el.attributes, function (attr) {
|
76 | if (attr.name !== 'class' && attr.name !== 'id') {
|
77 | desc += "[" + attr.name + (attr.value ? "=\"" + attr.value + "\"]" : ']');
|
78 | }
|
79 | });
|
80 | return desc;
|
81 | }
|
82 |
|
83 | function focused(message) {
|
84 | var element = this.findTargetElement();
|
85 | if (!element)
|
86 | return;
|
87 | var result = document.activeElement === element;
|
88 | var actual = elementToString(document.activeElement);
|
89 | var expected = elementToString(this.target);
|
90 | if (!message) {
|
91 | message = "Element " + expected + " is focused";
|
92 | }
|
93 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
94 | }
|
95 |
|
96 | function notFocused(message) {
|
97 | var element = this.findTargetElement();
|
98 | if (!element)
|
99 | return;
|
100 | var result = document.activeElement !== element;
|
101 | var expected = "Element " + this.targetDescription + " is not focused";
|
102 | var actual = result ? expected : "Element " + this.targetDescription + " is focused";
|
103 | if (!message) {
|
104 | message = expected;
|
105 | }
|
106 | this.pushResult({ result: result, message: message, actual: actual, expected: expected });
|
107 | }
|
108 |
|
109 | function checked(message) {
|
110 | var element = this.findTargetElement();
|
111 | if (!element)
|
112 | return;
|
113 | var isChecked = element.checked === true;
|
114 | var isNotChecked = element.checked === false;
|
115 | var result = isChecked;
|
116 | var hasCheckedProp = isChecked || isNotChecked;
|
117 | if (!hasCheckedProp) {
|
118 | var ariaChecked = element.getAttribute('aria-checked');
|
119 | if (ariaChecked !== null) {
|
120 | result = ariaChecked === 'true';
|
121 | }
|
122 | }
|
123 | var actual = result ? 'checked' : 'not checked';
|
124 | var expected = 'checked';
|
125 | if (!message) {
|
126 | message = "Element " + elementToString(this.target) + " is checked";
|
127 | }
|
128 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
129 | }
|
130 |
|
131 | function notChecked(message) {
|
132 | var element = this.findTargetElement();
|
133 | if (!element)
|
134 | return;
|
135 | var isChecked = element.checked === true;
|
136 | var isNotChecked = element.checked === false;
|
137 | var result = !isChecked;
|
138 | var hasCheckedProp = isChecked || isNotChecked;
|
139 | if (!hasCheckedProp) {
|
140 | var ariaChecked = element.getAttribute('aria-checked');
|
141 | if (ariaChecked !== null) {
|
142 | result = ariaChecked !== 'true';
|
143 | }
|
144 | }
|
145 | var actual = result ? 'not checked' : 'checked';
|
146 | var expected = 'not checked';
|
147 | if (!message) {
|
148 | message = "Element " + elementToString(this.target) + " is not checked";
|
149 | }
|
150 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
151 | }
|
152 |
|
153 | function required(message) {
|
154 | var element = this.findTargetElement();
|
155 | if (!element)
|
156 | return;
|
157 | if (!(element instanceof HTMLInputElement ||
|
158 | element instanceof HTMLTextAreaElement ||
|
159 | element instanceof HTMLSelectElement)) {
|
160 | throw new TypeError("Unexpected Element Type: " + element.toString());
|
161 | }
|
162 | var result = element.required === true;
|
163 | var actual = result ? 'required' : 'not required';
|
164 | var expected = 'required';
|
165 | if (!message) {
|
166 | message = "Element " + elementToString(this.target) + " is required";
|
167 | }
|
168 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
169 | }
|
170 |
|
171 | function notRequired(message) {
|
172 | var element = this.findTargetElement();
|
173 | if (!element)
|
174 | return;
|
175 | if (!(element instanceof HTMLInputElement ||
|
176 | element instanceof HTMLTextAreaElement ||
|
177 | element instanceof HTMLSelectElement)) {
|
178 | throw new TypeError("Unexpected Element Type: " + element.toString());
|
179 | }
|
180 | var result = element.required === false;
|
181 | var actual = !result ? 'required' : 'not required';
|
182 | var expected = 'not required';
|
183 | if (!message) {
|
184 | message = "Element " + elementToString(this.target) + " is not required";
|
185 | }
|
186 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
187 | }
|
188 |
|
189 | function isValid(message, options) {
|
190 | if (options === void 0) { options = {}; }
|
191 | var element = this.findTargetElement();
|
192 | if (!element)
|
193 | return;
|
194 | if (!(element instanceof HTMLFormElement ||
|
195 | element instanceof HTMLInputElement ||
|
196 | element instanceof HTMLTextAreaElement ||
|
197 | element instanceof HTMLButtonElement ||
|
198 | element instanceof HTMLOutputElement ||
|
199 | element instanceof HTMLSelectElement)) {
|
200 | throw new TypeError("Unexpected Element Type: " + element.toString());
|
201 | }
|
202 | var validity = element.reportValidity() === true;
|
203 | var result = validity === !options.inverted;
|
204 | var actual = validity ? 'valid' : 'not valid';
|
205 | var expected = options.inverted ? 'not valid' : 'valid';
|
206 | if (!message) {
|
207 | message = "Element " + elementToString(this.target) + " is " + actual;
|
208 | }
|
209 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
210 | }
|
211 |
|
212 |
|
213 |
|
214 | function visible(el) {
|
215 | if (el === null)
|
216 | return false;
|
217 | if (el.offsetWidth === 0 || el.offsetHeight === 0)
|
218 | return false;
|
219 | var clientRects = el.getClientRects();
|
220 | if (clientRects.length === 0)
|
221 | return false;
|
222 | for (var i = 0; i < clientRects.length; i++) {
|
223 | var rect = clientRects[i];
|
224 | if (rect.width !== 0 && rect.height !== 0)
|
225 | return true;
|
226 | }
|
227 | return false;
|
228 | }
|
229 |
|
230 | function isVisible(options, message) {
|
231 | var expectedCount = null;
|
232 | if (typeof options === 'string') {
|
233 | message = options;
|
234 | }
|
235 | else if (options) {
|
236 | expectedCount = options.count;
|
237 | }
|
238 | var elements = this.findElements().filter(visible);
|
239 | if (expectedCount === null) {
|
240 | var result = elements.length > 0;
|
241 | var expected = format(this.targetDescription);
|
242 | var actual = result ? expected : format(this.targetDescription, 0);
|
243 | if (!message) {
|
244 | message = expected;
|
245 | }
|
246 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
247 | }
|
248 | else if (typeof expectedCount === 'number') {
|
249 | var result = elements.length === expectedCount;
|
250 | var actual = format(this.targetDescription, elements.length);
|
251 | var expected = format(this.targetDescription, expectedCount);
|
252 | if (!message) {
|
253 | message = expected;
|
254 | }
|
255 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
256 | }
|
257 | else {
|
258 | throw new TypeError("Unexpected Parameter: " + expectedCount);
|
259 | }
|
260 | }
|
261 | function format(selector, num) {
|
262 | if (num === undefined || num === null) {
|
263 | return "Element " + selector + " is visible";
|
264 | }
|
265 | else if (num === 0) {
|
266 | return "Element " + selector + " is not visible";
|
267 | }
|
268 | else if (num === 1) {
|
269 | return "Element " + selector + " is visible once";
|
270 | }
|
271 | else if (num === 2) {
|
272 | return "Element " + selector + " is visible twice";
|
273 | }
|
274 | else {
|
275 | return "Element " + selector + " is visible " + num + " times";
|
276 | }
|
277 | }
|
278 |
|
279 | function isDisabled(message, options) {
|
280 | if (options === void 0) { options = {}; }
|
281 | var inverted = options.inverted;
|
282 | var element = this.findTargetElement();
|
283 | if (!element)
|
284 | return;
|
285 | if (!(element instanceof HTMLInputElement ||
|
286 | element instanceof HTMLTextAreaElement ||
|
287 | element instanceof HTMLSelectElement ||
|
288 | element instanceof HTMLButtonElement ||
|
289 | element instanceof HTMLOptGroupElement ||
|
290 | element instanceof HTMLOptionElement ||
|
291 | element instanceof HTMLFieldSetElement)) {
|
292 | throw new TypeError("Unexpected Element Type: " + element.toString());
|
293 | }
|
294 | var result = element.disabled === !inverted;
|
295 | var actual = element.disabled === false
|
296 | ? "Element " + this.targetDescription + " is not disabled"
|
297 | : "Element " + this.targetDescription + " is disabled";
|
298 | var expected = inverted
|
299 | ? "Element " + this.targetDescription + " is not disabled"
|
300 | : "Element " + this.targetDescription + " is disabled";
|
301 | if (!message) {
|
302 | message = expected;
|
303 | }
|
304 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
305 | }
|
306 |
|
307 | function matchesSelector(elements, compareSelector) {
|
308 | var failures = elements.filter(function (it) { return !it.matches(compareSelector); });
|
309 | return failures.length;
|
310 | }
|
311 |
|
312 | function collapseWhitespace(string) {
|
313 | return string
|
314 | .replace(/[\t\r\n]/g, ' ')
|
315 | .replace(/ +/g, ' ')
|
316 | .replace(/^ /, '')
|
317 | .replace(/ $/, '');
|
318 | }
|
319 |
|
320 | |
321 |
|
322 |
|
323 |
|
324 |
|
325 |
|
326 | function toArray(list) {
|
327 | return Array.prototype.slice.call(list);
|
328 | }
|
329 |
|
330 | var DOMAssertions = (function () {
|
331 | function DOMAssertions(target, rootElement, testContext) {
|
332 | this.target = target;
|
333 | this.rootElement = rootElement;
|
334 | this.testContext = testContext;
|
335 | }
|
336 | |
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 | DOMAssertions.prototype.exists = function (options, message) {
|
350 | exists.call(this, options, message);
|
351 | return this;
|
352 | };
|
353 | |
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 | DOMAssertions.prototype.doesNotExist = function (message) {
|
364 | exists.call(this, { count: 0 }, message);
|
365 | return this;
|
366 | };
|
367 | |
368 |
|
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 |
|
378 |
|
379 |
|
380 | DOMAssertions.prototype.isChecked = function (message) {
|
381 | checked.call(this, message);
|
382 | return this;
|
383 | };
|
384 | |
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 | DOMAssertions.prototype.isNotChecked = function (message) {
|
398 | notChecked.call(this, message);
|
399 | return this;
|
400 | };
|
401 | |
402 |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 | DOMAssertions.prototype.isFocused = function (message) {
|
413 | focused.call(this, message);
|
414 | return this;
|
415 | };
|
416 | |
417 |
|
418 |
|
419 |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 | DOMAssertions.prototype.isNotFocused = function (message) {
|
428 | notFocused.call(this, message);
|
429 | return this;
|
430 | };
|
431 | |
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 | DOMAssertions.prototype.isRequired = function (message) {
|
443 | required.call(this, message);
|
444 | return this;
|
445 | };
|
446 | |
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 | DOMAssertions.prototype.isNotRequired = function (message) {
|
458 | notRequired.call(this, message);
|
459 | return this;
|
460 | };
|
461 | |
462 |
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 | DOMAssertions.prototype.isValid = function (message) {
|
476 | isValid.call(this, message);
|
477 | return this;
|
478 | };
|
479 | |
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 | DOMAssertions.prototype.isNotValid = function (message) {
|
494 | isValid.call(this, message, { inverted: true });
|
495 | return this;
|
496 | };
|
497 | |
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 | DOMAssertions.prototype.isVisible = function (options, message) {
|
520 | isVisible.call(this, options, message);
|
521 | return this;
|
522 | };
|
523 | |
524 |
|
525 |
|
526 |
|
527 |
|
528 |
|
529 |
|
530 |
|
531 |
|
532 |
|
533 |
|
534 |
|
535 |
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 |
|
542 | DOMAssertions.prototype.isNotVisible = function (message) {
|
543 | isVisible.call(this, { count: 0 }, message);
|
544 | return this;
|
545 | };
|
546 | |
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 |
|
555 |
|
556 |
|
557 |
|
558 |
|
559 |
|
560 | DOMAssertions.prototype.hasAttribute = function (name, value, message) {
|
561 | var element = this.findTargetElement();
|
562 | if (!element)
|
563 | return this;
|
564 | if (arguments.length === 1) {
|
565 | value = { any: true };
|
566 | }
|
567 | var actualValue = element.getAttribute(name);
|
568 | if (value instanceof RegExp) {
|
569 | var result = value.test(actualValue);
|
570 | var expected = "Element " + this.targetDescription + " has attribute \"" + name + "\" with value matching " + value;
|
571 | var actual = actualValue === null
|
572 | ? "Element " + this.targetDescription + " does not have attribute \"" + name + "\""
|
573 | : "Element " + this.targetDescription + " has attribute \"" + name + "\" with value " + JSON.stringify(actualValue);
|
574 | if (!message) {
|
575 | message = expected;
|
576 | }
|
577 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
578 | }
|
579 | else if (value.any === true) {
|
580 | var result = actualValue !== null;
|
581 | var expected = "Element " + this.targetDescription + " has attribute \"" + name + "\"";
|
582 | var actual = result
|
583 | ? expected
|
584 | : "Element " + this.targetDescription + " does not have attribute \"" + name + "\"";
|
585 | if (!message) {
|
586 | message = expected;
|
587 | }
|
588 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
589 | }
|
590 | else {
|
591 | var result = value === actualValue;
|
592 | var expected = "Element " + this.targetDescription + " has attribute \"" + name + "\" with value " + JSON.stringify(value);
|
593 | var actual = actualValue === null
|
594 | ? "Element " + this.targetDescription + " does not have attribute \"" + name + "\""
|
595 | : "Element " + this.targetDescription + " has attribute \"" + name + "\" with value " + JSON.stringify(actualValue);
|
596 | if (!message) {
|
597 | message = expected;
|
598 | }
|
599 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
600 | }
|
601 | return this;
|
602 | };
|
603 | |
604 |
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 | DOMAssertions.prototype.doesNotHaveAttribute = function (name, message) {
|
617 | var element = this.findTargetElement();
|
618 | if (!element)
|
619 | return;
|
620 | var result = !element.hasAttribute(name);
|
621 | var expected = "Element " + this.targetDescription + " does not have attribute \"" + name + "\"";
|
622 | var actual = expected;
|
623 | if (!result) {
|
624 | var value = element.getAttribute(name);
|
625 | actual = "Element " + this.targetDescription + " has attribute \"" + name + "\" with value " + JSON.stringify(value);
|
626 | }
|
627 | if (!message) {
|
628 | message = expected;
|
629 | }
|
630 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
631 | return this;
|
632 | };
|
633 | DOMAssertions.prototype.hasNoAttribute = function (name, message) {
|
634 | return this.doesNotHaveAttribute(name, message);
|
635 | };
|
636 | DOMAssertions.prototype.lacksAttribute = function (name, message) {
|
637 | return this.doesNotHaveAttribute(name, message);
|
638 | };
|
639 | |
640 |
|
641 |
|
642 |
|
643 |
|
644 |
|
645 |
|
646 |
|
647 |
|
648 |
|
649 |
|
650 |
|
651 |
|
652 |
|
653 | DOMAssertions.prototype.hasAria = function (name, value, message) {
|
654 | return this.hasAttribute("aria-" + name, value, message);
|
655 | };
|
656 | |
657 |
|
658 |
|
659 |
|
660 |
|
661 |
|
662 |
|
663 |
|
664 |
|
665 |
|
666 |
|
667 |
|
668 | DOMAssertions.prototype.doesNotHaveAria = function (name, message) {
|
669 | return this.doesNotHaveAttribute("aria-" + name, message);
|
670 | };
|
671 | |
672 |
|
673 |
|
674 |
|
675 |
|
676 |
|
677 |
|
678 |
|
679 |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 | DOMAssertions.prototype.hasProperty = function (name, value, message) {
|
686 | var element = this.findTargetElement();
|
687 | if (!element)
|
688 | return this;
|
689 | var description = this.targetDescription;
|
690 | var actualValue = element[name];
|
691 | if (value instanceof RegExp) {
|
692 | var result = value.test(String(actualValue));
|
693 | var expected = "Element " + description + " has property \"" + name + "\" with value matching " + value;
|
694 | var actual = "Element " + description + " has property \"" + name + "\" with value " + JSON.stringify(actualValue);
|
695 | if (!message) {
|
696 | message = expected;
|
697 | }
|
698 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
699 | }
|
700 | else {
|
701 | var result = value === actualValue;
|
702 | var expected = "Element " + description + " has property \"" + name + "\" with value " + JSON.stringify(value);
|
703 | var actual = "Element " + description + " has property \"" + name + "\" with value " + JSON.stringify(actualValue);
|
704 | if (!message) {
|
705 | message = expected;
|
706 | }
|
707 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
708 | }
|
709 | return this;
|
710 | };
|
711 | |
712 |
|
713 |
|
714 |
|
715 |
|
716 |
|
717 |
|
718 |
|
719 |
|
720 |
|
721 |
|
722 | DOMAssertions.prototype.isDisabled = function (message) {
|
723 | isDisabled.call(this, message);
|
724 | return this;
|
725 | };
|
726 | |
727 |
|
728 |
|
729 |
|
730 |
|
731 |
|
732 |
|
733 |
|
734 |
|
735 |
|
736 |
|
737 |
|
738 |
|
739 | DOMAssertions.prototype.isNotDisabled = function (message) {
|
740 | isDisabled.call(this, message, { inverted: true });
|
741 | return this;
|
742 | };
|
743 | DOMAssertions.prototype.isEnabled = function (message) {
|
744 | return this.isNotDisabled(message);
|
745 | };
|
746 | |
747 |
|
748 |
|
749 |
|
750 |
|
751 |
|
752 |
|
753 |
|
754 |
|
755 |
|
756 |
|
757 |
|
758 |
|
759 |
|
760 |
|
761 |
|
762 |
|
763 |
|
764 | DOMAssertions.prototype.hasClass = function (expected, message) {
|
765 | var element = this.findTargetElement();
|
766 | if (!element)
|
767 | return this;
|
768 | var actual = element.classList.toString();
|
769 | if (expected instanceof RegExp) {
|
770 | var classNames = Array.prototype.slice.call(element.classList);
|
771 | var result = classNames.some(function (className) {
|
772 | return expected.test(className);
|
773 | });
|
774 | if (!message) {
|
775 | message = "Element " + this.targetDescription + " has CSS class matching " + expected;
|
776 | }
|
777 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
778 | }
|
779 | else {
|
780 | var result = element.classList.contains(expected);
|
781 | if (!message) {
|
782 | message = "Element " + this.targetDescription + " has CSS class \"" + expected + "\"";
|
783 | }
|
784 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
785 | }
|
786 | return this;
|
787 | };
|
788 | |
789 |
|
790 |
|
791 |
|
792 |
|
793 |
|
794 |
|
795 |
|
796 |
|
797 |
|
798 |
|
799 |
|
800 |
|
801 |
|
802 |
|
803 |
|
804 |
|
805 |
|
806 |
|
807 |
|
808 | DOMAssertions.prototype.doesNotHaveClass = function (expected, message) {
|
809 | var element = this.findTargetElement();
|
810 | if (!element)
|
811 | return this;
|
812 | var actual = element.classList.toString();
|
813 | if (expected instanceof RegExp) {
|
814 | var classNames = Array.prototype.slice.call(element.classList);
|
815 | var result = classNames.every(function (className) {
|
816 | return !expected.test(className);
|
817 | });
|
818 | if (!message) {
|
819 | message = "Element " + this.targetDescription + " does not have CSS class matching " + expected;
|
820 | }
|
821 | this.pushResult({ result: result, actual: actual, expected: "not: " + expected, message: message });
|
822 | }
|
823 | else {
|
824 | var result = !element.classList.contains(expected);
|
825 | if (!message) {
|
826 | message = "Element " + this.targetDescription + " does not have CSS class \"" + expected + "\"";
|
827 | }
|
828 | this.pushResult({ result: result, actual: actual, expected: "not: " + expected, message: message });
|
829 | }
|
830 | return this;
|
831 | };
|
832 | DOMAssertions.prototype.hasNoClass = function (expected, message) {
|
833 | return this.doesNotHaveClass(expected, message);
|
834 | };
|
835 | DOMAssertions.prototype.lacksClass = function (expected, message) {
|
836 | return this.doesNotHaveClass(expected, message);
|
837 | };
|
838 | |
839 |
|
840 |
|
841 |
|
842 |
|
843 |
|
844 |
|
845 |
|
846 |
|
847 |
|
848 |
|
849 |
|
850 |
|
851 |
|
852 |
|
853 | DOMAssertions.prototype.hasStyle = function (expected, message) {
|
854 | return this.hasPseudoElementStyle(null, expected, message);
|
855 | };
|
856 | |
857 |
|
858 |
|
859 |
|
860 |
|
861 |
|
862 |
|
863 |
|
864 |
|
865 |
|
866 |
|
867 |
|
868 |
|
869 |
|
870 |
|
871 | DOMAssertions.prototype.hasPseudoElementStyle = function (selector, expected, message) {
|
872 | var element = this.findTargetElement();
|
873 | if (!element)
|
874 | return this;
|
875 | var computedStyle = window.getComputedStyle(element, selector);
|
876 | var expectedProperties = Object.keys(expected);
|
877 | if (expectedProperties.length <= 0) {
|
878 | throw new TypeError("Missing style expectations. There must be at least one style property in the passed in expectation object.");
|
879 | }
|
880 | var result = expectedProperties.every(function (property) { return computedStyle[property] === expected[property]; });
|
881 | var actual = {};
|
882 | expectedProperties.forEach(function (property) { return (actual[property] = computedStyle[property]); });
|
883 | if (!message) {
|
884 | var normalizedSelector = selector ? selector.replace(/^:{0,2}/, '::') : '';
|
885 | message = "Element " + this.targetDescription + normalizedSelector + " has style \"" + JSON.stringify(expected) + "\"";
|
886 | }
|
887 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
888 | return this;
|
889 | };
|
890 | |
891 |
|
892 |
|
893 |
|
894 |
|
895 |
|
896 |
|
897 |
|
898 |
|
899 |
|
900 |
|
901 |
|
902 |
|
903 |
|
904 |
|
905 | DOMAssertions.prototype.doesNotHaveStyle = function (expected, message) {
|
906 | return this.doesNotHavePseudoElementStyle(null, expected, message);
|
907 | };
|
908 | |
909 |
|
910 |
|
911 |
|
912 |
|
913 |
|
914 |
|
915 |
|
916 |
|
917 |
|
918 |
|
919 |
|
920 |
|
921 |
|
922 |
|
923 | DOMAssertions.prototype.doesNotHavePseudoElementStyle = function (selector, expected, message) {
|
924 | var element = this.findTargetElement();
|
925 | if (!element)
|
926 | return this;
|
927 | var computedStyle = window.getComputedStyle(element, selector);
|
928 | var expectedProperties = Object.keys(expected);
|
929 | if (expectedProperties.length <= 0) {
|
930 | throw new TypeError("Missing style expectations. There must be at least one style property in the passed in expectation object.");
|
931 | }
|
932 | var result = expectedProperties.some(function (property) { return computedStyle[property] !== expected[property]; });
|
933 | var actual = {};
|
934 | expectedProperties.forEach(function (property) { return (actual[property] = computedStyle[property]); });
|
935 | if (!message) {
|
936 | var normalizedSelector = selector ? selector.replace(/^:{0,2}/, '::') : '';
|
937 | message = "Element " + this.targetDescription + normalizedSelector + " does not have style \"" + JSON.stringify(expected) + "\"";
|
938 | }
|
939 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
940 | return this;
|
941 | };
|
942 | |
943 |
|
944 |
|
945 |
|
946 |
|
947 |
|
948 |
|
949 |
|
950 |
|
951 |
|
952 |
|
953 |
|
954 |
|
955 |
|
956 |
|
957 |
|
958 |
|
959 |
|
960 |
|
961 |
|
962 |
|
963 |
|
964 |
|
965 |
|
966 |
|
967 |
|
968 |
|
969 |
|
970 |
|
971 | DOMAssertions.prototype.hasText = function (expected, message) {
|
972 | var element = this.findTargetElement();
|
973 | if (!element)
|
974 | return this;
|
975 | if (expected instanceof RegExp) {
|
976 | var result = expected.test(element.textContent);
|
977 | var actual = element.textContent;
|
978 | if (!message) {
|
979 | message = "Element " + this.targetDescription + " has text matching " + expected;
|
980 | }
|
981 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
982 | }
|
983 | else if (expected.any === true) {
|
984 | var result = Boolean(element.textContent);
|
985 | var expected_1 = "Element " + this.targetDescription + " has a text";
|
986 | var actual = result ? expected_1 : "Element " + this.targetDescription + " has no text";
|
987 | if (!message) {
|
988 | message = expected_1;
|
989 | }
|
990 | this.pushResult({ result: result, actual: actual, expected: expected_1, message: message });
|
991 | }
|
992 | else if (typeof expected === 'string') {
|
993 | expected = collapseWhitespace(expected);
|
994 | var actual = collapseWhitespace(element.textContent);
|
995 | var result = actual === expected;
|
996 | if (!message) {
|
997 | message = "Element " + this.targetDescription + " has text \"" + expected + "\"";
|
998 | }
|
999 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
1000 | }
|
1001 | else {
|
1002 | throw new TypeError("You must pass a string or Regular Expression to \"hasText\". You passed " + expected + ".");
|
1003 | }
|
1004 | return this;
|
1005 | };
|
1006 | DOMAssertions.prototype.matchesText = function (expected, message) {
|
1007 | return this.hasText(expected, message);
|
1008 | };
|
1009 | |
1010 |
|
1011 |
|
1012 |
|
1013 |
|
1014 |
|
1015 |
|
1016 |
|
1017 |
|
1018 |
|
1019 | DOMAssertions.prototype.hasAnyText = function (message) {
|
1020 | return this.hasText({ any: true }, message);
|
1021 | };
|
1022 | |
1023 |
|
1024 |
|
1025 |
|
1026 |
|
1027 |
|
1028 |
|
1029 |
|
1030 |
|
1031 |
|
1032 | DOMAssertions.prototype.hasNoText = function (message) {
|
1033 | return this.hasText('', message);
|
1034 | };
|
1035 | |
1036 |
|
1037 |
|
1038 |
|
1039 |
|
1040 |
|
1041 |
|
1042 |
|
1043 |
|
1044 |
|
1045 |
|
1046 |
|
1047 |
|
1048 |
|
1049 |
|
1050 |
|
1051 |
|
1052 |
|
1053 |
|
1054 |
|
1055 |
|
1056 | DOMAssertions.prototype.includesText = function (text, message) {
|
1057 | var element = this.findTargetElement();
|
1058 | if (!element)
|
1059 | return this;
|
1060 | var collapsedText = collapseWhitespace(element.textContent);
|
1061 | var result = collapsedText.indexOf(text) !== -1;
|
1062 | var actual = collapsedText;
|
1063 | var expected = text;
|
1064 | if (!message) {
|
1065 | message = "Element " + this.targetDescription + " has text containing \"" + text + "\"";
|
1066 | }
|
1067 | if (!result && text !== collapseWhitespace(text)) {
|
1068 | console.warn('The `.includesText()`, `.containsText()`, and `.hasTextContaining()` assertions collapse whitespace. The text you are checking for contains whitespace that may have made your test fail incorrectly. Try the `.hasText()` assertion passing in your expected text as a RegExp pattern. Your text:\n' +
|
1069 | text);
|
1070 | }
|
1071 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
1072 | return this;
|
1073 | };
|
1074 | DOMAssertions.prototype.containsText = function (expected, message) {
|
1075 | return this.includesText(expected, message);
|
1076 | };
|
1077 | DOMAssertions.prototype.hasTextContaining = function (expected, message) {
|
1078 | return this.includesText(expected, message);
|
1079 | };
|
1080 | |
1081 |
|
1082 |
|
1083 |
|
1084 |
|
1085 |
|
1086 |
|
1087 |
|
1088 |
|
1089 |
|
1090 |
|
1091 |
|
1092 |
|
1093 |
|
1094 | DOMAssertions.prototype.doesNotIncludeText = function (text, message) {
|
1095 | var element = this.findTargetElement();
|
1096 | if (!element)
|
1097 | return this;
|
1098 | var collapsedText = collapseWhitespace(element.textContent);
|
1099 | var result = collapsedText.indexOf(text) === -1;
|
1100 | var expected = "Element " + this.targetDescription + " does not include text \"" + text + "\"";
|
1101 | var actual = expected;
|
1102 | if (!result) {
|
1103 | actual = "Element " + this.targetDescription + " includes text \"" + text + "\"";
|
1104 | }
|
1105 | if (!message) {
|
1106 | message = expected;
|
1107 | }
|
1108 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
1109 | return this;
|
1110 | };
|
1111 | DOMAssertions.prototype.doesNotContainText = function (unexpected, message) {
|
1112 | return this.doesNotIncludeText(unexpected, message);
|
1113 | };
|
1114 | DOMAssertions.prototype.doesNotHaveTextContaining = function (unexpected, message) {
|
1115 | return this.doesNotIncludeText(unexpected, message);
|
1116 | };
|
1117 | |
1118 |
|
1119 |
|
1120 |
|
1121 |
|
1122 |
|
1123 |
|
1124 |
|
1125 |
|
1126 |
|
1127 |
|
1128 |
|
1129 |
|
1130 |
|
1131 |
|
1132 |
|
1133 | DOMAssertions.prototype.hasValue = function (expected, message) {
|
1134 | var element = this.findTargetElement();
|
1135 | if (!element)
|
1136 | return this;
|
1137 | if (arguments.length === 0) {
|
1138 | expected = { any: true };
|
1139 | }
|
1140 | var value = element.value;
|
1141 | if (expected instanceof RegExp) {
|
1142 | var result = expected.test(value);
|
1143 | var actual = value;
|
1144 | if (!message) {
|
1145 | message = "Element " + this.targetDescription + " has value matching " + expected;
|
1146 | }
|
1147 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
1148 | }
|
1149 | else if (expected.any === true) {
|
1150 | var result = Boolean(value);
|
1151 | var expected_2 = "Element " + this.targetDescription + " has a value";
|
1152 | var actual = result ? expected_2 : "Element " + this.targetDescription + " has no value";
|
1153 | if (!message) {
|
1154 | message = expected_2;
|
1155 | }
|
1156 | this.pushResult({ result: result, actual: actual, expected: expected_2, message: message });
|
1157 | }
|
1158 | else {
|
1159 | var actual = value;
|
1160 | var result = actual === expected;
|
1161 | if (!message) {
|
1162 | message = "Element " + this.targetDescription + " has value \"" + expected + "\"";
|
1163 | }
|
1164 | this.pushResult({ result: result, actual: actual, expected: expected, message: message });
|
1165 | }
|
1166 | return this;
|
1167 | };
|
1168 | |
1169 |
|
1170 |
|
1171 |
|
1172 |
|
1173 |
|
1174 |
|
1175 |
|
1176 |
|
1177 |
|
1178 |
|
1179 | DOMAssertions.prototype.hasAnyValue = function (message) {
|
1180 | return this.hasValue({ any: true }, message);
|
1181 | };
|
1182 | |
1183 |
|
1184 |
|
1185 |
|
1186 |
|
1187 |
|
1188 |
|
1189 |
|
1190 |
|
1191 |
|
1192 |
|
1193 |
|
1194 |
|
1195 | DOMAssertions.prototype.hasNoValue = function (message) {
|
1196 | return this.hasValue('', message);
|
1197 | };
|
1198 | DOMAssertions.prototype.lacksValue = function (message) {
|
1199 | return this.hasNoValue(message);
|
1200 | };
|
1201 | |
1202 |
|
1203 |
|
1204 |
|
1205 |
|
1206 |
|
1207 |
|
1208 |
|
1209 |
|
1210 |
|
1211 | DOMAssertions.prototype.matchesSelector = function (compareSelector, message) {
|
1212 | var targetElements = this.target instanceof Element ? [this.target] : this.findElements();
|
1213 | var targets = targetElements.length;
|
1214 | var matchFailures = matchesSelector(targetElements, compareSelector);
|
1215 | var singleElement = targets === 1;
|
1216 | var selectedByPart = this.target instanceof Element ? 'passed' : "selected by " + this.target;
|
1217 | var actual;
|
1218 | var expected;
|
1219 | if (matchFailures === 0) {
|
1220 |
|
1221 | if (!message) {
|
1222 | message = singleElement
|
1223 | ? "The element " + selectedByPart + " also matches the selector " + compareSelector + "."
|
1224 | : targets + " elements, selected by " + this.target + ", also match the selector " + compareSelector + ".";
|
1225 | }
|
1226 | actual = expected = message;
|
1227 | this.pushResult({ result: true, actual: actual, expected: expected, message: message });
|
1228 | }
|
1229 | else {
|
1230 | var difference = targets - matchFailures;
|
1231 |
|
1232 | if (!message) {
|
1233 | message = singleElement
|
1234 | ? "The element " + selectedByPart + " did not also match the selector " + compareSelector + "."
|
1235 | : matchFailures + " out of " + targets + " elements selected by " + this.target + " did not also match the selector " + compareSelector + ".";
|
1236 | }
|
1237 | actual = singleElement ? message : difference + " elements matched " + compareSelector + ".";
|
1238 | expected = singleElement
|
1239 | ? "The element should have matched " + compareSelector + "."
|
1240 | : targets + " elements should have matched " + compareSelector + ".";
|
1241 | this.pushResult({ result: false, actual: actual, expected: expected, message: message });
|
1242 | }
|
1243 | return this;
|
1244 | };
|
1245 | |
1246 |
|
1247 |
|
1248 |
|
1249 |
|
1250 |
|
1251 |
|
1252 |
|
1253 |
|
1254 |
|
1255 | DOMAssertions.prototype.doesNotMatchSelector = function (compareSelector, message) {
|
1256 | var targetElements = this.target instanceof Element ? [this.target] : this.findElements();
|
1257 | var targets = targetElements.length;
|
1258 | var matchFailures = matchesSelector(targetElements, compareSelector);
|
1259 | var singleElement = targets === 1;
|
1260 | var selectedByPart = this.target instanceof Element ? 'passed' : "selected by " + this.target;
|
1261 | var actual;
|
1262 | var expected;
|
1263 | if (matchFailures === targets) {
|
1264 |
|
1265 | if (!message) {
|
1266 | message = singleElement
|
1267 | ? "The element " + selectedByPart + " did not also match the selector " + compareSelector + "."
|
1268 | : targets + " elements, selected by " + this.target + ", did not also match the selector " + compareSelector + ".";
|
1269 | }
|
1270 | actual = expected = message;
|
1271 | this.pushResult({ result: true, actual: actual, expected: expected, message: message });
|
1272 | }
|
1273 | else {
|
1274 | var difference = targets - matchFailures;
|
1275 |
|
1276 | if (!message) {
|
1277 | message = singleElement
|
1278 | ? "The element " + selectedByPart + " must not also match the selector " + compareSelector + "."
|
1279 | : difference + " elements out of " + targets + ", selected by " + this.target + ", must not also match the selector " + compareSelector + ".";
|
1280 | }
|
1281 | actual = singleElement
|
1282 | ? "The element " + selectedByPart + " matched " + compareSelector + "."
|
1283 | : matchFailures + " elements did not match " + compareSelector + ".";
|
1284 | expected = singleElement
|
1285 | ? message
|
1286 | : targets + " elements should not have matched " + compareSelector + ".";
|
1287 | this.pushResult({ result: false, actual: actual, expected: expected, message: message });
|
1288 | }
|
1289 | return this;
|
1290 | };
|
1291 | |
1292 |
|
1293 |
|
1294 |
|
1295 |
|
1296 |
|
1297 |
|
1298 |
|
1299 |
|
1300 |
|
1301 |
|
1302 |
|
1303 |
|
1304 |
|
1305 |
|
1306 |
|
1307 | DOMAssertions.prototype.hasTagName = function (tagName, message) {
|
1308 | var element = this.findTargetElement();
|
1309 | var actual;
|
1310 | var expected;
|
1311 | if (!element)
|
1312 | return this;
|
1313 | if (typeof tagName !== 'string') {
|
1314 | throw new TypeError("You must pass a string to \"hasTagName\". You passed " + tagName + ".");
|
1315 | }
|
1316 | actual = element.tagName.toLowerCase();
|
1317 | expected = tagName.toLowerCase();
|
1318 | if (actual === expected) {
|
1319 | if (!message) {
|
1320 | message = "Element " + this.targetDescription + " has tagName " + expected;
|
1321 | }
|
1322 | this.pushResult({ result: true, actual: actual, expected: expected, message: message });
|
1323 | }
|
1324 | else {
|
1325 | if (!message) {
|
1326 | message = "Element " + this.targetDescription + " does not have tagName " + expected;
|
1327 | }
|
1328 | this.pushResult({ result: false, actual: actual, expected: expected, message: message });
|
1329 | }
|
1330 | return this;
|
1331 | };
|
1332 | |
1333 |
|
1334 |
|
1335 |
|
1336 |
|
1337 |
|
1338 |
|
1339 |
|
1340 |
|
1341 |
|
1342 |
|
1343 |
|
1344 |
|
1345 |
|
1346 |
|
1347 |
|
1348 | DOMAssertions.prototype.doesNotHaveTagName = function (tagName, message) {
|
1349 | var element = this.findTargetElement();
|
1350 | var actual;
|
1351 | var expected;
|
1352 | if (!element)
|
1353 | return this;
|
1354 | if (typeof tagName !== 'string') {
|
1355 | throw new TypeError("You must pass a string to \"doesNotHaveTagName\". You passed " + tagName + ".");
|
1356 | }
|
1357 | actual = element.tagName.toLowerCase();
|
1358 | expected = tagName.toLowerCase();
|
1359 | if (actual !== expected) {
|
1360 | if (!message) {
|
1361 | message = "Element " + this.targetDescription + " does not have tagName " + expected;
|
1362 | }
|
1363 | this.pushResult({ result: true, actual: actual, expected: expected, message: message });
|
1364 | }
|
1365 | else {
|
1366 | if (!message) {
|
1367 | message = "Element " + this.targetDescription + " has tagName " + expected;
|
1368 | }
|
1369 | this.pushResult({ result: false, actual: actual, expected: expected, message: message });
|
1370 | }
|
1371 | return this;
|
1372 | };
|
1373 | |
1374 |
|
1375 |
|
1376 | DOMAssertions.prototype.pushResult = function (result) {
|
1377 | this.testContext.pushResult(result);
|
1378 | };
|
1379 | |
1380 |
|
1381 |
|
1382 |
|
1383 |
|
1384 |
|
1385 | DOMAssertions.prototype.findTargetElement = function () {
|
1386 | var el = this.findElement();
|
1387 | if (el === null) {
|
1388 | var message = "Element " + (this.target || '<unknown>') + " should exist";
|
1389 | this.pushResult({ message: message, result: false, actual: undefined, expected: undefined });
|
1390 | return null;
|
1391 | }
|
1392 | return el;
|
1393 | };
|
1394 | |
1395 |
|
1396 |
|
1397 |
|
1398 |
|
1399 |
|
1400 | DOMAssertions.prototype.findElement = function () {
|
1401 | if (this.target === null) {
|
1402 | return null;
|
1403 | }
|
1404 | else if (typeof this.target === 'string') {
|
1405 | return this.rootElement.querySelector(this.target);
|
1406 | }
|
1407 | else if (this.target instanceof Element) {
|
1408 | return this.target;
|
1409 | }
|
1410 | else {
|
1411 | throw new TypeError("Unexpected Parameter: " + this.target);
|
1412 | }
|
1413 | };
|
1414 | |
1415 |
|
1416 |
|
1417 |
|
1418 |
|
1419 |
|
1420 | DOMAssertions.prototype.findElements = function () {
|
1421 | if (this.target === null) {
|
1422 | return [];
|
1423 | }
|
1424 | else if (typeof this.target === 'string') {
|
1425 | return toArray(this.rootElement.querySelectorAll(this.target));
|
1426 | }
|
1427 | else if (this.target instanceof Element) {
|
1428 | return [this.target];
|
1429 | }
|
1430 | else {
|
1431 | throw new TypeError("Unexpected Parameter: " + this.target);
|
1432 | }
|
1433 | };
|
1434 | Object.defineProperty(DOMAssertions.prototype, "targetDescription", {
|
1435 | |
1436 |
|
1437 |
|
1438 | get: function () {
|
1439 | return elementToString(this.target);
|
1440 | },
|
1441 | enumerable: false,
|
1442 | configurable: true
|
1443 | });
|
1444 | return DOMAssertions;
|
1445 | }());
|
1446 |
|
1447 | var _getRootElement = function () { return null; };
|
1448 | function overrideRootElement(fn) {
|
1449 | _getRootElement = fn;
|
1450 | }
|
1451 | function getRootElement() {
|
1452 | return _getRootElement();
|
1453 | }
|
1454 |
|
1455 | function install (assert) {
|
1456 | assert.dom = function (target, rootElement) {
|
1457 | if (!isValidRootElement(rootElement)) {
|
1458 | throw new Error(rootElement + " is not a valid root element");
|
1459 | }
|
1460 | rootElement = rootElement || this.dom.rootElement || getRootElement();
|
1461 | if (arguments.length === 0) {
|
1462 | target = rootElement instanceof Element ? rootElement : null;
|
1463 | }
|
1464 | return new DOMAssertions(target, rootElement, this);
|
1465 | };
|
1466 | function isValidRootElement(element) {
|
1467 | return (!element ||
|
1468 | (typeof element === 'object' &&
|
1469 | typeof element.querySelector === 'function' &&
|
1470 | typeof element.querySelectorAll === 'function'));
|
1471 | }
|
1472 | }
|
1473 |
|
1474 | function setup(assert, options) {
|
1475 | if (options === void 0) { options = {}; }
|
1476 | install(assert);
|
1477 | var getRootElement = typeof options.getRootElement === 'function'
|
1478 | ? options.getRootElement
|
1479 | : function () { return document.querySelector('#ember-testing'); };
|
1480 | overrideRootElement(getRootElement);
|
1481 | }
|
1482 |
|
1483 |
|
1484 | install(QUnit.assert);
|
1485 |
|
1486 | exports.setup = setup;
|
1487 |
|
1488 | Object.defineProperty(exports, '__esModule', { value: true });
|
1489 |
|
1490 | return exports;
|
1491 |
|
1492 | }({}));
|
1493 |
|