1 | import { extendObject, applyCssPrefixes } from '@angular/flex-layout/_private-utils';
|
2 | import { TestBed } from '@angular/core/testing';
|
3 | import { By } from '@angular/platform-browser';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | const _dom = {
|
16 | hasStyle,
|
17 | getDistributedNodes,
|
18 | getShadowRoot,
|
19 | getText,
|
20 | getStyle,
|
21 | childNodes,
|
22 | childNodesAsList,
|
23 | hasClass,
|
24 | hasAttribute,
|
25 | getAttribute,
|
26 | hasShadowRoot,
|
27 | isCommentNode,
|
28 | isElementNode,
|
29 | isPresent,
|
30 | isShadowRoot,
|
31 | tagName,
|
32 | lastElementChild
|
33 | };
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | function getStyle(element, stylename) {
|
40 | return element.style[stylename];
|
41 | }
|
42 | function hasStyle(element, styleName, styleValue = '', inlineOnly = true) {
|
43 | let value = getStyle(element, styleName) || '';
|
44 | if (!value && !inlineOnly) {
|
45 |
|
46 | value = typeof getComputedStyle === 'function' &&
|
47 | getComputedStyle(element).getPropertyValue(styleName) || '';
|
48 | }
|
49 | return styleValue ? value == styleValue : value.length > 0;
|
50 | }
|
51 | function getDistributedNodes(el) {
|
52 | return el.getDistributedNodes();
|
53 | }
|
54 | function getShadowRoot(el) {
|
55 | return el.shadowRoot;
|
56 | }
|
57 | function getText(el) {
|
58 | return el.textContent || '';
|
59 | }
|
60 | function childNodesAsList(el) {
|
61 | const list = el.childNodes;
|
62 | const res = new Array(list.length);
|
63 | for (let i = 0; i < list.length; i++) {
|
64 | res[i] = list[i];
|
65 | }
|
66 | return res;
|
67 | }
|
68 | function hasClass(element, className) {
|
69 | return element.classList.contains(className);
|
70 | }
|
71 | function hasAttribute(element, attributeName) {
|
72 | return element.hasAttribute(attributeName);
|
73 | }
|
74 | function getAttribute(element, attributeName) {
|
75 | return element.getAttribute(attributeName);
|
76 | }
|
77 | function childNodes(el) {
|
78 | return el.childNodes;
|
79 | }
|
80 | function hasShadowRoot(node) {
|
81 | return isPresent(node.shadowRoot) && node instanceof HTMLElement;
|
82 | }
|
83 | function isCommentNode(node) {
|
84 | return node.nodeType === Node.COMMENT_NODE;
|
85 | }
|
86 | function isElementNode(node) {
|
87 | return node.nodeType === Node.ELEMENT_NODE;
|
88 | }
|
89 | function isShadowRoot(node) {
|
90 | return node instanceof DocumentFragment;
|
91 | }
|
92 | function isPresent(obj) {
|
93 | return obj != null;
|
94 | }
|
95 | function tagName(element) {
|
96 | return element.tagName;
|
97 | }
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | function lastElementChild(element) {
|
103 | return element.lastElementChild;
|
104 | }
|
105 |
|
106 | const _global = (typeof window === 'undefined' ? global : window);
|
107 | const expect$1 = _global.expect;
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 | const customMatchers = {
|
114 | toEqual: function (util) {
|
115 | return {
|
116 | compare: function (actual, expected) {
|
117 | return { pass: util.equals(actual, expected) };
|
118 | }
|
119 | };
|
120 | },
|
121 | toHaveText: function () {
|
122 | return {
|
123 | compare: function (actual, expectedText) {
|
124 | const actualText = elementText(actual);
|
125 | return {
|
126 | pass: actualText == expectedText,
|
127 | get message() {
|
128 | return 'Expected ' + actualText + ' to be equal to ' + expectedText;
|
129 | }
|
130 | };
|
131 | }
|
132 | };
|
133 | },
|
134 | toHaveCssClass: function () {
|
135 | return { compare: buildError(false), negativeCompare: buildError(true) };
|
136 | function buildError(isNot) {
|
137 | return function (actual, className) {
|
138 | return {
|
139 | pass: _dom.hasClass(actual, className) == !isNot,
|
140 | get message() {
|
141 | return `
|
142 | Expected ${actual.outerHTML} ${isNot ? 'not ' : ''}
|
143 | to contain the CSS class '${className}'
|
144 | `;
|
145 | }
|
146 | };
|
147 | };
|
148 | }
|
149 | },
|
150 | toHaveMap: function () {
|
151 | return {
|
152 | compare: function (actual, map) {
|
153 | let allPassed;
|
154 | allPassed = Object.keys(map).length !== 0;
|
155 | Object.keys(map).forEach(key => {
|
156 | allPassed = allPassed && (actual[key] === map[key]);
|
157 | });
|
158 | return {
|
159 | pass: allPassed,
|
160 | get message() {
|
161 | return `
|
162 | Expected ${JSON.stringify(actual)} ${!allPassed ? ' ' : 'not '} to contain the
|
163 | '${JSON.stringify(map)}'
|
164 | `;
|
165 | }
|
166 | };
|
167 | }
|
168 | };
|
169 | },
|
170 | toHaveAttributes: function () {
|
171 | return {
|
172 | compare: function (actual, map) {
|
173 | let allPassed;
|
174 | let attributeNames = Object.keys(map);
|
175 | allPassed = attributeNames.length !== 0;
|
176 | attributeNames.forEach(name => {
|
177 | allPassed = allPassed && _dom.hasAttribute(actual, name)
|
178 | && _dom.getAttribute(actual, name) === map[name];
|
179 | });
|
180 | return {
|
181 | pass: allPassed,
|
182 | get message() {
|
183 | return `
|
184 | Expected ${actual.outerHTML} ${allPassed ? 'not ' : ''} attributes to contain
|
185 | '${JSON.stringify(map)}'
|
186 | `;
|
187 | }
|
188 | };
|
189 | }
|
190 | };
|
191 | },
|
192 | |
193 |
|
194 |
|
195 | toHaveStyle: function () {
|
196 | return {
|
197 | compare: buildCompareStyleFunction(true)
|
198 | };
|
199 | },
|
200 | |
201 |
|
202 |
|
203 | toHaveCSS: function () {
|
204 | return {
|
205 | compare: buildCompareStyleFunction(false)
|
206 | };
|
207 | }
|
208 | };
|
209 |
|
210 |
|
211 |
|
212 |
|
213 | function buildCompareStyleFunction(inlineOnly = true) {
|
214 | return function (actual, styles, styler) {
|
215 | const found = {};
|
216 | const styleMap = {};
|
217 | if (typeof styles === 'string') {
|
218 | styleMap[styles] = '';
|
219 | }
|
220 | else {
|
221 | Object.assign(styleMap, styles);
|
222 | }
|
223 | let allPassed = Object.keys(styleMap).length !== 0;
|
224 | Object.keys(styleMap).forEach(prop => {
|
225 | let { elHasStyle, current } = hasPrefixedStyles(actual, prop, styleMap[prop], inlineOnly, styler);
|
226 | allPassed = allPassed && elHasStyle;
|
227 | if (!elHasStyle) {
|
228 | extendObject(found, current);
|
229 | }
|
230 | });
|
231 | return {
|
232 | pass: allPassed,
|
233 | get message() {
|
234 | const expectedValueStr = (typeof styles === 'string') ? styleMap :
|
235 | JSON.stringify(styleMap, null, 2);
|
236 | const foundValueStr = inlineOnly ? actual.outerHTML : JSON.stringify(found);
|
237 | return `
|
238 | Expected ${foundValueStr}${!allPassed ? '' : ' not'} to contain the
|
239 | CSS ${typeof styles === 'string' ? 'property' : 'styles'} '${expectedValueStr}'
|
240 | `;
|
241 | }
|
242 | };
|
243 | };
|
244 | }
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 | function hasPrefixedStyles(actual, key, value, inlineOnly, styler) {
|
251 | const current = {};
|
252 | if (value === '*') {
|
253 | return { elHasStyle: styler.lookupStyle(actual, key, inlineOnly) !== '', current };
|
254 | }
|
255 | value = value.trim();
|
256 | let elHasStyle = styler.lookupStyle(actual, key, inlineOnly) === value;
|
257 | if (!elHasStyle) {
|
258 | let prefixedStyles = applyCssPrefixes({ [key]: value });
|
259 | Object.keys(prefixedStyles).forEach(prop => {
|
260 |
|
261 | elHasStyle = elHasStyle ||
|
262 | styler.lookupStyle(actual, prop, inlineOnly) === prefixedStyles[prop];
|
263 | });
|
264 | }
|
265 |
|
266 | return { elHasStyle, current };
|
267 | }
|
268 | function elementText(n) {
|
269 | const hasNodes = (m) => {
|
270 | const children = _dom.childNodes(m);
|
271 | return children && children['length'];
|
272 | };
|
273 | if (n instanceof Array) {
|
274 | return n.map(elementText).join('');
|
275 | }
|
276 | if (_dom.isCommentNode(n)) {
|
277 | return '';
|
278 | }
|
279 | if (_dom.isElementNode(n) && _dom.tagName(n) == 'CONTENT') {
|
280 | return elementText(Array.prototype.slice.apply(_dom.getDistributedNodes(n)));
|
281 | }
|
282 | if (_dom.hasShadowRoot(n)) {
|
283 | return elementText(_dom.childNodesAsList(_dom.getShadowRoot(n)));
|
284 | }
|
285 | if (hasNodes(n)) {
|
286 | return elementText(_dom.childNodesAsList(n));
|
287 | }
|
288 | return _dom.getText(n);
|
289 | }
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | function makeCreateTestComponent(getClass) {
|
296 | let componentAny;
|
297 |
|
298 | return function createTestComponent(template, styles) {
|
299 | if (!componentAny) {
|
300 |
|
301 | componentAny = getClass();
|
302 | }
|
303 | return TestBed
|
304 | .overrideComponent(componentAny, {
|
305 | set: {
|
306 | template: template,
|
307 | styles: styles || [],
|
308 | }
|
309 | })
|
310 | .createComponent(componentAny);
|
311 | };
|
312 | }
|
313 |
|
314 |
|
315 |
|
316 | function expectNativeEl(fixture, instanceOptions) {
|
317 | extendObject(fixture.componentInstance, instanceOptions || {});
|
318 | fixture.detectChanges();
|
319 | return expect(fixture.debugElement.children[0].nativeElement);
|
320 | }
|
321 |
|
322 |
|
323 |
|
324 | function expectEl(debugEl) {
|
325 | return expect(debugEl.nativeElement);
|
326 | }
|
327 | function queryFor(fixture, selector) {
|
328 | return fixture.debugElement.queryAll(By.css(selector));
|
329 | }
|
330 |
|
331 |
|
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 | export { _dom, customMatchers, expect$1 as expect, expectEl, expectNativeEl, makeCreateTestComponent, queryFor };
|
344 |
|