UNPKG

11 kBJavaScriptView Raw
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2015 - present Instructure, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24import React from 'react';
25import { findDOMNode } from 'react-dom';
26import { elementToString, wrapQueryResult, isElement, matches } from '@instructure/ui-test-queries';
27export default function assertions(chai, utils) {
28 const flag = utils.flag,
29 inspect = utils.inspect;
30 const Assertion = chai.Assertion;
31
32 function wrapObj(obj) {
33 if (obj && typeof obj.getDOMNode === 'function') {
34 return obj;
35 }
36
37 let node;
38
39 if (isElement(obj)) {
40 node = obj;
41 } else if ( /*#__PURE__*/React.isValidElement(obj)) {
42 node = findDOMNode(obj);
43 }
44
45 if (node) {
46 return wrapQueryResult(node);
47 }
48
49 return void 0;
50 }
51
52 function addAssertion(name, assertion) {
53 if (Assertion.prototype[name]) {
54 overwriteMethod(name, assertion);
55 } else {
56 addMethod(name, assertion);
57 }
58 }
59
60 function overwriteProperty(name, assertion) {
61 Assertion.overwriteProperty(name, function (_super) {
62 return wrapOverwriteAssertion(assertion, _super);
63 });
64 }
65
66 function overwriteMethod(name, assertion) {
67 Assertion.overwriteMethod(name, function (_super) {
68 return wrapOverwriteAssertion(assertion, _super);
69 });
70 }
71
72 function addMethod(name, assertion) {
73 Assertion.addMethod(name, wrapAssertion(assertion));
74 }
75
76 function addChainableMethod(name, assertion) {
77 Assertion.addChainableMethod(name, wrapAssertion(assertion));
78 }
79
80 function overwriteChainableMethod(name, assertion) {
81 Assertion.overwriteChainableMethod(name, function (_super) {
82 return wrapOverwriteAssertion(assertion, _super);
83 }, function (_super) {
84 return function () {
85 _super.call(this);
86 };
87 });
88 }
89
90 function wrapOverwriteAssertion(assertion, _super) {
91 return function (arg1, arg2) {
92 const wrapper = wrapObj(flag(this, 'object'));
93
94 if (!wrapper) {
95 // eslint-disable-next-line prefer-rest-params
96 return _super.apply(this, arguments);
97 }
98
99 assertion.call(this, {
100 markup: () => wrapper.toString(),
101 sig: inspect(wrapper.getDOMNode()),
102 wrapper,
103 arg1,
104 arg2,
105 flag,
106 inspect
107 });
108 };
109 }
110
111 function wrapAssertion(assertion) {
112 return function (arg1, arg2) {
113 const wrapper = wrapObj(flag(this, 'object'));
114 const config = {
115 wrapper,
116 arg1,
117 flag,
118 inspect
119 };
120
121 if (wrapper) {
122 config.markup = () => wrapper.toString();
123
124 config.sig = inspect(wrapper.getDOMNode());
125 }
126
127 if (arguments.length > 1) {
128 config.arg2 = arg2;
129 }
130
131 assertion.call(this, config);
132 };
133 }
134
135 overwriteProperty('not', function () {
136 flag(this, 'negate', true);
137 });
138 addChainableMethod('exactly', function exactly(_ref) {
139 let flag = _ref.flag,
140 arg1 = _ref.arg1;
141 flag(this, 'exactlyCount', arg1);
142 });
143 addAssertion('text', function text(_ref2) {
144 let wrapper = _ref2.wrapper,
145 markup = _ref2.markup,
146 flag = _ref2.flag,
147 arg1 = _ref2.arg1,
148 arg2 = _ref2.arg2,
149 sig = _ref2.sig;
150 const actual = wrapper.text(); // TODO check if this is this never null
151
152 if (typeof arg1 !== 'undefined') {
153 if (flag(this, 'contains')) {
154 this.assert(actual && actual.indexOf(String(arg1)) > -1, () => `expected ${sig} to contain text #{exp}, but it has #{act} ${markup()}`, () => `expected ${sig} not to contain text #{exp}, but it has #{act} ${markup()}`, arg1, actual);
155 } else {
156 this.assert(actual && matches(actual, arg1, arg2), () => `expected ${sig} to have text #{exp}, but it has #{act} ${markup()}`, () => `expected ${sig} to not have text #{exp}, but it has #{act} ${markup()}`, arg1, actual);
157 }
158 }
159
160 flag(this, 'object', actual);
161 });
162 overwriteChainableMethod('contain', function contain(_ref3) {
163 let wrapper = _ref3.wrapper,
164 markup = _ref3.markup,
165 arg1 = _ref3.arg1,
166 sig = _ref3.sig;
167
168 if (arg1) {
169 this.assert(wrapper && wrapper.contains(arg1), () => `expected ${sig} to contain ${elementToString(arg1)} ${markup()}`, () => `expected ${sig} to not contain ${elementToString(arg1)} ${markup()}`, arg1);
170 }
171 });
172 addAssertion('className', function className(_ref4) {
173 let wrapper = _ref4.wrapper,
174 markup = _ref4.markup,
175 arg1 = _ref4.arg1,
176 sig = _ref4.sig;
177 const actual = wrapper.classNames(); // TODO check if this is this never null
178
179 this.assert(wrapper && wrapper.hasClass(arg1), () => `expected ${sig} to have a #{exp} class, but it has #{act} ${markup()}`, () => `expected ${sig} to not have a #{exp} class, but it has #{act} ${markup()}`, arg1, actual);
180 });
181 addAssertion('match', function match(_ref5) {
182 let wrapper = _ref5.wrapper,
183 markup = _ref5.markup,
184 arg1 = _ref5.arg1,
185 sig = _ref5.sig;
186 this.assert(wrapper && wrapper.matches(arg1), () => `expected ${sig} to match #{exp} ${markup()}`, () => `expected ${sig} to not match #{exp} ${markup()}`, arg1);
187 });
188 addAssertion('descendants', listAndCountAssertion('descendants', 'descendants'));
189 addAssertion('children', listAndCountAssertion('children', 'children'));
190 addAssertion('ancestors', listAndCountAssertion('ancestors', 'ancestors'));
191 addAssertion('parents', listAndCountAssertion('parents', 'parents'));
192 addAssertion('attribute', propAndValueAssertion('attribute', 'attribute'));
193 addAssertion('style', propAndValueAssertion('style', 'computed CSS style'));
194 addAssertion('bounds', propAndValueAssertion('bounds', 'bounding client rect'));
195 addAssertion('tagName', valueAssertion('tagName', 'tag name'));
196 addAssertion('id', valueAssertion('id', 'id'));
197 addAssertion('visible', booleanAssertion('visible', 'visible'));
198 addAssertion('clickable', booleanAssertion('clickable', 'clickable'));
199 addAssertion('focus', booleanAssertion('containsFocus', 'focused or contain the focused element'));
200 addAssertion('focused', booleanAssertion('focused', 'focused'));
201 addAssertion('focusable', booleanAssertion('focusable', 'focusable'));
202 addAssertion('tabbable', booleanAssertion('tabbable', 'tabbable'));
203 addAssertion('checked', booleanAssertion('checked', 'checked'));
204 addAssertion('selected', booleanAssertion('selected', 'selected'));
205 addAssertion('disabled', booleanAssertion('disabled', 'disabled'));
206 addAssertion('enabled', booleanAssertion('enabled', 'enabled'));
207 addAssertion('readonly', booleanAssertion('readonly', 'readonly'));
208 addAssertion('accessible', booleanAssertion('accessible', 'accessible'));
209 addAssertion('role', valueAssertion('role', 'role'));
210 addAssertion('title', valueAssertion('title', 'title'));
211 addAssertion('value', valueAssertion('value', 'value'));
212 addAssertion('label', valueAssertion('label', 'label'));
213}
214
215function getActual(wrapper, assertion) {
216 const methodOrProperty = wrapper ? wrapper[assertion] : void 0;
217
218 if (typeof methodOrProperty === 'function') {
219 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
220 args[_key - 2] = arguments[_key];
221 }
222
223 return methodOrProperty(...args);
224 } else {
225 return methodOrProperty;
226 }
227}
228
229function propAndValueAssertion(assertion, desc) {
230 return function (args) {
231 const wrapper = args.wrapper,
232 markup = args.markup,
233 flag = args.flag,
234 inspect = args.inspect,
235 arg1 = args.arg1,
236 arg2 = args.arg2,
237 arg3 = args.arg3,
238 sig = args.sig;
239 const actual = getActual(wrapper, assertion, arg1);
240
241 if (arg2) {
242 this.assert(actual && matches(actual, arg2, arg3), () => `expected ${sig} to have a ${inspect(arg1)} ${desc} with the value #{exp}, but the value was #{act} ${markup()}`, () => `expected ${sig} to not have a ${inspect(arg1)} ${desc} with the value #{act} ${markup()}`, arg2, actual);
243 } else {
244 this.assert(typeof actual !== 'undefined' && actual !== null, () => `expected ${sig} to have a #{exp} ${desc} ${markup()}`, () => `expected ${sig} to not have a #{exp} ${desc} ${markup()}`, arg1, actual);
245 }
246
247 flag(this, 'object', actual);
248 };
249}
250
251function booleanAssertion(assertion, desc) {
252 return function (_ref6) {
253 let wrapper = _ref6.wrapper,
254 markup = _ref6.markup,
255 sig = _ref6.sig;
256 const actual = getActual(wrapper, assertion);
257 this.assert(actual, () => `expected ${sig} to be ${desc} ${markup()}`, () => `expected ${sig} to not be ${desc} ${markup()}`, void 0);
258 };
259}
260
261function valueAssertion(assertion, desc) {
262 return function (_ref7) {
263 let wrapper = _ref7.wrapper,
264 markup = _ref7.markup,
265 arg1 = _ref7.arg1,
266 arg2 = _ref7.arg2,
267 sig = _ref7.sig;
268 const actual = getActual(wrapper, assertion);
269 this.assert(matches(actual, arg1, arg2), () => `expected ${sig} to have a #{exp} ${desc}, but it has #{act} ${markup()}`, () => `expected ${sig} to not have a #{exp} ${desc}, but it has #{act} ${markup()}`, arg1, actual);
270 };
271}
272
273function listAndCountAssertion(assertion, desc) {
274 return function (_ref8) {
275 let wrapper = _ref8.wrapper,
276 markup = _ref8.markup,
277 arg1 = _ref8.arg1,
278 sig = _ref8.sig,
279 flag = _ref8.flag;
280 const exactlyCount = flag(this, 'exactlyCount');
281 const actual = getActual(wrapper, assertion, arg1);
282 const count = actual.length;
283
284 if (exactlyCount || exactlyCount === 0) {
285 this.assert(count === exactlyCount, () => `expected ${sig} to have ${exactlyCount} ${desc} #{exp} but actually found ${count} ${markup()}`, () => `expected ${sig} to not have ${exactlyCount} ${desc} #{exp} but actually found ${count} ${markup()}`, arg1);
286 } else {
287 this.assert(count > 0, () => `expected ${sig} to have ${desc} #{exp} ${markup()}`, () => `expected ${sig} to not have ${desc} #{exp} ${markup()}`, arg1);
288 }
289 };
290}
\No newline at end of file