UNPKG

@instructure/ui-test-utils

Version:

A UI testing library made by Instructure Inc.

273 lines (269 loc) • 10.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = assertions; var _react = _interopRequireDefault(require("react")); var _reactDom = require("react-dom"); var _uiTestQueries = require("@instructure/ui-test-queries"); /* * The MIT License (MIT) * * Copyright (c) 2015 - present Instructure, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ function assertions(chai, utils) { const flag = utils.flag, inspect = utils.inspect; const Assertion = chai.Assertion; function wrapObj(obj) { if (obj && typeof obj.getDOMNode === 'function') { return obj; } let node; if ((0, _uiTestQueries.isElement)(obj)) { node = obj; } else if ( /*#__PURE__*/_react.default.isValidElement(obj)) { node = (0, _reactDom.findDOMNode)(obj); } if (node) { return (0, _uiTestQueries.wrapQueryResult)(node); } return void 0; } function addAssertion(name, assertion) { // @ts-expect-error don't know how to type this.. if (Assertion.prototype[name]) { overwriteMethod(name, assertion); } else { addMethod(name, assertion); } } function overwriteProperty(name, assertion) { Assertion.overwriteProperty(name, function (_super) { return wrapOverwriteAssertion(assertion, _super); }); } function overwriteMethod(name, assertion) { Assertion.overwriteMethod(name, function (_super) { return wrapOverwriteAssertion(assertion, _super); }); } function addMethod(name, assertion) { Assertion.addMethod(name, wrapAssertion(assertion)); } function addChainableMethod(name, assertion) { Assertion.addChainableMethod(name, wrapAssertion(assertion)); } function overwriteChainableMethod(name, assertion) { Assertion.overwriteChainableMethod(name, function (_super) { return wrapOverwriteAssertion(assertion, _super); }, function (_super) { return function () { _super.call(this); }; }); } function wrapOverwriteAssertion(assertion, _super) { return function (arg1, arg2) { const wrapper = wrapObj(flag(this, 'object')); if (!wrapper) { // @ts-expect-error TODO: this needs new syntax // eslint-disable-next-line prefer-rest-params return _super.apply(this, arguments); } assertion.call(this, { markup: () => wrapper.toString(), sig: inspect(wrapper.getDOMNode()), wrapper, arg1, arg2, flag, inspect }); }; } function wrapAssertion(assertion) { return function (arg1, arg2) { const wrapper = wrapObj(flag(this, 'object')); const config = { wrapper, arg1, flag, inspect }; if (wrapper) { config.markup = () => wrapper.toString(); config.sig = inspect(wrapper.getDOMNode()); } if (arguments.length > 1) { config.arg2 = arg2; } assertion.call(this, config); }; } overwriteProperty('not', function () { flag(this, 'negate', true); }); addChainableMethod('exactly', function exactly({ flag, arg1 }) { flag(this, 'exactlyCount', arg1); }); addAssertion('text', function text({ wrapper, markup, flag, arg1, arg2, sig }) { const actual = wrapper.text(); // TODO check if this is this never null if (typeof arg1 !== 'undefined') { if (flag(this, 'contains')) { 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); } else { this.assert(actual && (0, _uiTestQueries.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); } } flag(this, 'object', actual); }); overwriteChainableMethod('contain', function contain({ wrapper, markup, arg1, sig }) { if (arg1) { this.assert(wrapper && wrapper.contains(arg1), () => `expected ${sig} to contain ${(0, _uiTestQueries.elementToString)(arg1)} ${markup()}`, () => `expected ${sig} to not contain ${(0, _uiTestQueries.elementToString)(arg1)} ${markup()}`, arg1); } }); addAssertion('className', function className({ wrapper, markup, arg1, sig }) { const actual = wrapper.classNames(); // TODO check if this is this never null 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); }); addAssertion('match', function match({ wrapper, markup, arg1, sig }) { this.assert(wrapper && wrapper.matches(arg1), () => `expected ${sig} to match #{exp} ${markup()}`, () => `expected ${sig} to not match #{exp} ${markup()}`, arg1); }); addAssertion('descendants', listAndCountAssertion('descendants', 'descendants')); addAssertion('children', listAndCountAssertion('children', 'children')); addAssertion('ancestors', listAndCountAssertion('ancestors', 'ancestors')); addAssertion('parents', listAndCountAssertion('parents', 'parents')); addAssertion('attribute', propAndValueAssertion('attribute', 'attribute')); addAssertion('style', propAndValueAssertion('style', 'computed CSS style')); addAssertion('bounds', propAndValueAssertion('bounds', 'bounding client rect')); addAssertion('tagName', valueAssertion('tagName', 'tag name')); addAssertion('id', valueAssertion('id', 'id')); addAssertion('visible', booleanAssertion('visible', 'visible')); addAssertion('clickable', booleanAssertion('clickable', 'clickable')); addAssertion('focus', booleanAssertion('containsFocus', 'focused or contain the focused element')); addAssertion('focused', booleanAssertion('focused', 'focused')); addAssertion('focusable', booleanAssertion('focusable', 'focusable')); addAssertion('tabbable', booleanAssertion('tabbable', 'tabbable')); addAssertion('checked', booleanAssertion('checked', 'checked')); addAssertion('selected', booleanAssertion('selected', 'selected')); addAssertion('disabled', booleanAssertion('disabled', 'disabled')); addAssertion('enabled', booleanAssertion('enabled', 'enabled')); addAssertion('readonly', booleanAssertion('readonly', 'readonly')); addAssertion('accessible', booleanAssertion('accessible', 'accessible')); addAssertion('role', valueAssertion('role', 'role')); addAssertion('title', valueAssertion('title', 'title')); addAssertion('value', valueAssertion('value', 'value')); addAssertion('label', valueAssertion('label', 'label')); } function getActual(wrapper, assertion, ...args) { const methodOrProperty = wrapper ? wrapper[assertion] : void 0; if (typeof methodOrProperty === 'function') { return methodOrProperty(...args); } else { return methodOrProperty; } } function propAndValueAssertion(assertion, desc) { return function (args) { const wrapper = args.wrapper, markup = args.markup, flag = args.flag, inspect = args.inspect, arg1 = args.arg1, arg2 = args.arg2, arg3 = args.arg3, sig = args.sig; const actual = getActual(wrapper, assertion, arg1); if (arg2) { this.assert(actual && (0, _uiTestQueries.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); } else { 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); } flag(this, 'object', actual); }; } function booleanAssertion(assertion, desc) { return function ({ wrapper, markup, sig }) { const actual = getActual(wrapper, assertion); this.assert(actual, () => `expected ${sig} to be ${desc} ${markup()}`, () => `expected ${sig} to not be ${desc} ${markup()}`, void 0); }; } function valueAssertion(assertion, desc) { return function ({ wrapper, markup, arg1, arg2, sig }) { const actual = getActual(wrapper, assertion); this.assert((0, _uiTestQueries.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); }; } function listAndCountAssertion(assertion, desc) { return function ({ wrapper, markup, arg1, sig, flag }) { const exactlyCount = flag(this, 'exactlyCount'); const actual = getActual(wrapper, assertion, arg1); const count = actual.length; if (exactlyCount || exactlyCount === 0) { 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); } else { this.assert(count > 0, () => `expected ${sig} to have ${desc} #{exp} ${markup()}`, () => `expected ${sig} to not have ${desc} #{exp} ${markup()}`, arg1); } }; }