@instructure/ui-test-utils
Version:
A UI testing library made by Instructure Inc.
273 lines (269 loc) • 10.7 kB
JavaScript
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);
}
};
}
;