This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
"use strict";
var extensions = _interopRequireWildcard(require("./matchers"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
expect.extend(extensions);

View File

@@ -0,0 +1,3 @@
"use strict";
require("./extend-expect");

View File

@@ -0,0 +1,192 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "toBeChecked", {
enumerable: true,
get: function () {
return _toBeChecked.toBeChecked;
}
});
Object.defineProperty(exports, "toBeDisabled", {
enumerable: true,
get: function () {
return _toBeDisabled.toBeDisabled;
}
});
Object.defineProperty(exports, "toBeEmpty", {
enumerable: true,
get: function () {
return _toBeEmpty.toBeEmpty;
}
});
Object.defineProperty(exports, "toBeEmptyDOMElement", {
enumerable: true,
get: function () {
return _toBeEmptyDomElement.toBeEmptyDOMElement;
}
});
Object.defineProperty(exports, "toBeEnabled", {
enumerable: true,
get: function () {
return _toBeDisabled.toBeEnabled;
}
});
Object.defineProperty(exports, "toBeInTheDOM", {
enumerable: true,
get: function () {
return _toBeInTheDom.toBeInTheDOM;
}
});
Object.defineProperty(exports, "toBeInTheDocument", {
enumerable: true,
get: function () {
return _toBeInTheDocument.toBeInTheDocument;
}
});
Object.defineProperty(exports, "toBeInvalid", {
enumerable: true,
get: function () {
return _toBeInvalid.toBeInvalid;
}
});
Object.defineProperty(exports, "toBePartiallyChecked", {
enumerable: true,
get: function () {
return _toBePartiallyChecked.toBePartiallyChecked;
}
});
Object.defineProperty(exports, "toBeRequired", {
enumerable: true,
get: function () {
return _toBeRequired.toBeRequired;
}
});
Object.defineProperty(exports, "toBeValid", {
enumerable: true,
get: function () {
return _toBeInvalid.toBeValid;
}
});
Object.defineProperty(exports, "toBeVisible", {
enumerable: true,
get: function () {
return _toBeVisible.toBeVisible;
}
});
Object.defineProperty(exports, "toContainElement", {
enumerable: true,
get: function () {
return _toContainElement.toContainElement;
}
});
Object.defineProperty(exports, "toContainHTML", {
enumerable: true,
get: function () {
return _toContainHtml.toContainHTML;
}
});
Object.defineProperty(exports, "toHaveAccessibleDescription", {
enumerable: true,
get: function () {
return _toHaveAccessibleDescription.toHaveAccessibleDescription;
}
});
Object.defineProperty(exports, "toHaveAccessibleErrorMessage", {
enumerable: true,
get: function () {
return _toHaveAccessibleErrormessage.toHaveAccessibleErrorMessage;
}
});
Object.defineProperty(exports, "toHaveAccessibleName", {
enumerable: true,
get: function () {
return _toHaveAccessibleName.toHaveAccessibleName;
}
});
Object.defineProperty(exports, "toHaveAttribute", {
enumerable: true,
get: function () {
return _toHaveAttribute.toHaveAttribute;
}
});
Object.defineProperty(exports, "toHaveClass", {
enumerable: true,
get: function () {
return _toHaveClass.toHaveClass;
}
});
Object.defineProperty(exports, "toHaveDescription", {
enumerable: true,
get: function () {
return _toHaveDescription.toHaveDescription;
}
});
Object.defineProperty(exports, "toHaveDisplayValue", {
enumerable: true,
get: function () {
return _toHaveDisplayValue.toHaveDisplayValue;
}
});
Object.defineProperty(exports, "toHaveErrorMessage", {
enumerable: true,
get: function () {
return _toHaveErrormessage.toHaveErrorMessage;
}
});
Object.defineProperty(exports, "toHaveFocus", {
enumerable: true,
get: function () {
return _toHaveFocus.toHaveFocus;
}
});
Object.defineProperty(exports, "toHaveFormValues", {
enumerable: true,
get: function () {
return _toHaveFormValues.toHaveFormValues;
}
});
Object.defineProperty(exports, "toHaveStyle", {
enumerable: true,
get: function () {
return _toHaveStyle.toHaveStyle;
}
});
Object.defineProperty(exports, "toHaveTextContent", {
enumerable: true,
get: function () {
return _toHaveTextContent.toHaveTextContent;
}
});
Object.defineProperty(exports, "toHaveValue", {
enumerable: true,
get: function () {
return _toHaveValue.toHaveValue;
}
});
var _toBeInTheDom = require("./to-be-in-the-dom");
var _toBeInTheDocument = require("./to-be-in-the-document");
var _toBeEmpty = require("./to-be-empty");
var _toBeEmptyDomElement = require("./to-be-empty-dom-element");
var _toContainElement = require("./to-contain-element");
var _toContainHtml = require("./to-contain-html");
var _toHaveTextContent = require("./to-have-text-content");
var _toHaveAccessibleDescription = require("./to-have-accessible-description");
var _toHaveAccessibleErrormessage = require("./to-have-accessible-errormessage");
var _toHaveAccessibleName = require("./to-have-accessible-name");
var _toHaveAttribute = require("./to-have-attribute");
var _toHaveClass = require("./to-have-class");
var _toHaveStyle = require("./to-have-style");
var _toHaveFocus = require("./to-have-focus");
var _toHaveFormValues = require("./to-have-form-values");
var _toBeVisible = require("./to-be-visible");
var _toBeDisabled = require("./to-be-disabled");
var _toBeRequired = require("./to-be-required");
var _toBeInvalid = require("./to-be-invalid");
var _toHaveValue = require("./to-have-value");
var _toHaveDisplayValue = require("./to-have-display-value");
var _toBeChecked = require("./to-be-checked");
var _toBePartiallyChecked = require("./to-be-partially-checked");
var _toHaveDescription = require("./to-have-description");
var _toHaveErrormessage = require("./to-have-errormessage");

View File

@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeChecked = toBeChecked;
var _ariaQuery = require("aria-query");
var _utils = require("./utils");
function toBeChecked(element) {
(0, _utils.checkHtmlElement)(element, toBeChecked, this);
const isValidInput = () => {
return element.tagName.toLowerCase() === 'input' && ['checkbox', 'radio'].includes(element.type);
};
const isValidAriaElement = () => {
return roleSupportsChecked(element.getAttribute('role')) && ['true', 'false'].includes(element.getAttribute('aria-checked'));
};
if (!isValidInput() && !isValidAriaElement()) {
return {
pass: false,
message: () => `only inputs with type="checkbox" or type="radio" or elements with ${supportedRolesSentence()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`
};
}
const isChecked = () => {
if (isValidInput()) return element.checked;
return element.getAttribute('aria-checked') === 'true';
};
return {
pass: isChecked(),
message: () => {
const is = isChecked() ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeChecked`, 'element', ''), '', `Received element ${is} checked:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}
function supportedRolesSentence() {
return (0, _utils.toSentence)(supportedRoles().map(role => `role="${role}"`), {
lastWordConnector: ' or '
});
}
function supportedRoles() {
return _ariaQuery.roles.keys().filter(roleSupportsChecked);
}
function roleSupportsChecked(role) {
var _roles$get;
return ((_roles$get = _ariaQuery.roles.get(role)) == null ? void 0 : _roles$get.props['aria-checked']) !== undefined;
}

View File

@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeDisabled = toBeDisabled;
exports.toBeEnabled = toBeEnabled;
var _utils = require("./utils");
// form elements that support 'disabled'
const FORM_TAGS = ['fieldset', 'input', 'select', 'optgroup', 'option', 'button', 'textarea'];
/*
* According to specification:
* If <fieldset> is disabled, the form controls that are its descendants,
* except descendants of its first optional <legend> element, are disabled
*
* https://html.spec.whatwg.org/multipage/form-elements.html#concept-fieldset-disabled
*
* This method tests whether element is first legend child of fieldset parent
*/
function isFirstLegendChildOfFieldset(element, parent) {
return (0, _utils.getTag)(element) === 'legend' && (0, _utils.getTag)(parent) === 'fieldset' && element.isSameNode(Array.from(parent.children).find(child => (0, _utils.getTag)(child) === 'legend'));
}
function isElementDisabledByParent(element, parent) {
return isElementDisabled(parent) && !isFirstLegendChildOfFieldset(element, parent);
}
function isCustomElement(tag) {
return tag.includes('-');
}
/*
* Only certain form elements and custom elements can actually be disabled:
* https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements
*/
function canElementBeDisabled(element) {
const tag = (0, _utils.getTag)(element);
return FORM_TAGS.includes(tag) || isCustomElement(tag);
}
function isElementDisabled(element) {
return canElementBeDisabled(element) && element.hasAttribute('disabled');
}
function isAncestorDisabled(element) {
const parent = element.parentElement;
return Boolean(parent) && (isElementDisabledByParent(element, parent) || isAncestorDisabled(parent));
}
function isElementOrAncestorDisabled(element) {
return canElementBeDisabled(element) && (isElementDisabled(element) || isAncestorDisabled(element));
}
function toBeDisabled(element) {
(0, _utils.checkHtmlElement)(element, toBeDisabled, this);
const isDisabled = isElementOrAncestorDisabled(element);
return {
pass: isDisabled,
message: () => {
const is = isDisabled ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeDisabled`, 'element', ''), '', `Received element ${is} disabled:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}
function toBeEnabled(element) {
(0, _utils.checkHtmlElement)(element, toBeEnabled, this);
const isEnabled = !isElementOrAncestorDisabled(element);
return {
pass: isEnabled,
message: () => {
const is = isEnabled ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeEnabled`, 'element', ''), '', `Received element ${is} enabled:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeEmptyDOMElement = toBeEmptyDOMElement;
var _utils = require("./utils");
function toBeEmptyDOMElement(element) {
(0, _utils.checkHtmlElement)(element, toBeEmptyDOMElement, this);
return {
pass: isEmptyElement(element),
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeEmptyDOMElement`, 'element', ''), '', 'Received:', ` ${this.utils.printReceived(element.innerHTML)}`].join('\n');
}
};
}
/**
* Identifies if an element doesn't contain child nodes (excluding comments)
* Node.COMMENT_NODE can't be used because of the following issue
* https://github.com/jsdom/jsdom/issues/2220
*
* @param {*} element an HtmlElement or SVGElement
* @return {*} true if the element only contains comments or none
*/
function isEmptyElement(element) {
const nonCommentChildNodes = [...element.childNodes].filter(node => node.nodeType !== 8);
return nonCommentChildNodes.length === 0;
}

View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeEmpty = toBeEmpty;
var _utils = require("./utils");
function toBeEmpty(element) {
(0, _utils.deprecate)('toBeEmpty', 'Please use instead toBeEmptyDOMElement for finding empty nodes in the DOM.');
(0, _utils.checkHtmlElement)(element, toBeEmpty, this);
return {
pass: element.innerHTML === '',
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeEmpty`, 'element', ''), '', 'Received:', ` ${this.utils.printReceived(element.innerHTML)}`].join('\n');
}
};
}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeInTheDocument = toBeInTheDocument;
var _utils = require("./utils");
function toBeInTheDocument(element) {
if (element !== null || !this.isNot) {
(0, _utils.checkHtmlElement)(element, toBeInTheDocument, this);
}
const pass = element === null ? false : element.ownerDocument === element.getRootNode({
composed: true
});
const errorFound = () => {
return `expected document not to contain element, found ${this.utils.stringify(element.cloneNode(true))} instead`;
};
const errorNotFound = () => {
return `element could not be found in the document`;
};
return {
pass,
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeInTheDocument`, 'element', ''), '',
// eslint-disable-next-line @babel/new-cap
this.utils.RECEIVED_COLOR(this.isNot ? errorFound() : errorNotFound())].join('\n');
}
};
}

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeInTheDOM = toBeInTheDOM;
var _utils = require("./utils");
function toBeInTheDOM(element, container) {
(0, _utils.deprecate)('toBeInTheDOM', 'Please use toBeInTheDocument for searching the entire document and toContainElement for searching a specific container.');
if (element) {
(0, _utils.checkHtmlElement)(element, toBeInTheDOM, this);
}
if (container) {
(0, _utils.checkHtmlElement)(container, toBeInTheDOM, this);
}
return {
pass: container ? container.contains(element) : !!element,
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeInTheDOM`, 'element', ''), '', 'Received:', ` ${this.utils.printReceived(element ? element.cloneNode(false) : element)}`].join('\n');
}
};
}

View File

@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeInvalid = toBeInvalid;
exports.toBeValid = toBeValid;
var _utils = require("./utils");
const FORM_TAGS = ['form', 'input', 'select', 'textarea'];
function isElementHavingAriaInvalid(element) {
return element.hasAttribute('aria-invalid') && element.getAttribute('aria-invalid') !== 'false';
}
function isSupportsValidityMethod(element) {
return FORM_TAGS.includes((0, _utils.getTag)(element));
}
function isElementInvalid(element) {
const isHaveAriaInvalid = isElementHavingAriaInvalid(element);
if (isSupportsValidityMethod(element)) {
return isHaveAriaInvalid || !element.checkValidity();
} else {
return isHaveAriaInvalid;
}
}
function toBeInvalid(element) {
(0, _utils.checkHtmlElement)(element, toBeInvalid, this);
const isInvalid = isElementInvalid(element);
return {
pass: isInvalid,
message: () => {
const is = isInvalid ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeInvalid`, 'element', ''), '', `Received element ${is} currently invalid:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}
function toBeValid(element) {
(0, _utils.checkHtmlElement)(element, toBeValid, this);
const isValid = !isElementInvalid(element);
return {
pass: isValid,
message: () => {
const is = isValid ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeValid`, 'element', ''), '', `Received element ${is} currently valid:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}

View File

@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBePartiallyChecked = toBePartiallyChecked;
var _utils = require("./utils");
function toBePartiallyChecked(element) {
(0, _utils.checkHtmlElement)(element, toBePartiallyChecked, this);
const isValidInput = () => {
return element.tagName.toLowerCase() === 'input' && element.type === 'checkbox';
};
const isValidAriaElement = () => {
return element.getAttribute('role') === 'checkbox';
};
if (!isValidInput() && !isValidAriaElement()) {
return {
pass: false,
message: () => 'only inputs with type="checkbox" or elements with role="checkbox" and a valid aria-checked attribute can be used with .toBePartiallyChecked(). Use .toHaveValue() instead'
};
}
const isPartiallyChecked = () => {
const isAriaMixed = element.getAttribute('aria-checked') === 'mixed';
if (isValidInput()) {
return element.indeterminate || isAriaMixed;
}
return isAriaMixed;
};
return {
pass: isPartiallyChecked(),
message: () => {
const is = isPartiallyChecked() ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBePartiallyChecked`, 'element', ''), '', `Received element ${is} partially checked:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeRequired = toBeRequired;
var _utils = require("./utils");
// form elements that support 'required'
const FORM_TAGS = ['select', 'textarea'];
const ARIA_FORM_TAGS = ['input', 'select', 'textarea'];
const UNSUPPORTED_INPUT_TYPES = ['color', 'hidden', 'range', 'submit', 'image', 'reset'];
const SUPPORTED_ARIA_ROLES = ['combobox', 'gridcell', 'radiogroup', 'spinbutton', 'tree'];
function isRequiredOnFormTagsExceptInput(element) {
return FORM_TAGS.includes((0, _utils.getTag)(element)) && element.hasAttribute('required');
}
function isRequiredOnSupportedInput(element) {
return (0, _utils.getTag)(element) === 'input' && element.hasAttribute('required') && (element.hasAttribute('type') && !UNSUPPORTED_INPUT_TYPES.includes(element.getAttribute('type')) || !element.hasAttribute('type'));
}
function isElementRequiredByARIA(element) {
return element.hasAttribute('aria-required') && element.getAttribute('aria-required') === 'true' && (ARIA_FORM_TAGS.includes((0, _utils.getTag)(element)) || element.hasAttribute('role') && SUPPORTED_ARIA_ROLES.includes(element.getAttribute('role')));
}
function toBeRequired(element) {
(0, _utils.checkHtmlElement)(element, toBeRequired, this);
const isRequired = isRequiredOnFormTagsExceptInput(element) || isRequiredOnSupportedInput(element) || isElementRequiredByARIA(element);
return {
pass: isRequired,
message: () => {
const is = isRequired ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeRequired`, 'element', ''), '', `Received element ${is} required:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}

View File

@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeVisible = toBeVisible;
var _utils = require("./utils");
function isStyleVisible(element) {
const {
getComputedStyle
} = element.ownerDocument.defaultView;
const {
display,
visibility,
opacity
} = getComputedStyle(element);
return display !== 'none' && visibility !== 'hidden' && visibility !== 'collapse' && opacity !== '0' && opacity !== 0;
}
function isAttributeVisible(element, previousElement) {
let detailsVisibility;
if (previousElement) {
detailsVisibility = element.nodeName === 'DETAILS' && previousElement.nodeName !== 'SUMMARY' ? element.hasAttribute('open') : true;
} else {
detailsVisibility = element.nodeName === 'DETAILS' ? element.hasAttribute('open') : true;
}
return !element.hasAttribute('hidden') && detailsVisibility;
}
function isElementVisible(element, previousElement) {
return isStyleVisible(element) && isAttributeVisible(element, previousElement) && (!element.parentElement || isElementVisible(element.parentElement, element));
}
function toBeVisible(element) {
(0, _utils.checkHtmlElement)(element, toBeVisible, this);
const isInDocument = element.ownerDocument === element.getRootNode({
composed: true
});
const isVisible = isInDocument && isElementVisible(element);
return {
pass: isVisible,
message: () => {
const is = isVisible ? 'is' : 'is not';
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toBeVisible`, 'element', ''), '', `Received element ${is} visible${isInDocument ? '' : ' (element is not in the document)'}:`, ` ${this.utils.printReceived(element.cloneNode(false))}`].join('\n');
}
};
}

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toContainElement = toContainElement;
var _utils = require("./utils");
function toContainElement(container, element) {
(0, _utils.checkHtmlElement)(container, toContainElement, this);
if (element !== null) {
(0, _utils.checkHtmlElement)(element, toContainElement, this);
}
return {
pass: container.contains(element),
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toContainElement`, 'element', 'element'), '',
// eslint-disable-next-line @babel/new-cap
this.utils.RECEIVED_COLOR(`${this.utils.stringify(container.cloneNode(false))} ${this.isNot ? 'contains:' : 'does not contain:'} ${this.utils.stringify(element ? element.cloneNode(false) : element)}
`)].join('\n');
}
};
}

View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toContainHTML = toContainHTML;
var _utils = require("./utils");
function getNormalizedHtml(container, htmlText) {
const div = container.ownerDocument.createElement('div');
div.innerHTML = htmlText;
return div.innerHTML;
}
function toContainHTML(container, htmlText) {
(0, _utils.checkHtmlElement)(container, toContainHTML, this);
if (typeof htmlText !== 'string') {
throw new Error(`.toContainHTML() expects a string value, got ${htmlText}`);
}
return {
pass: container.outerHTML.includes(getNormalizedHtml(container, htmlText)),
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toContainHTML`, 'element', ''), 'Expected:',
// eslint-disable-next-line @babel/new-cap
` ${this.utils.EXPECTED_COLOR(htmlText)}`, 'Received:', ` ${this.utils.printReceived(container.cloneNode(true))}`].join('\n');
}
};
}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveAccessibleDescription = toHaveAccessibleDescription;
var _domAccessibilityApi = require("dom-accessibility-api");
var _utils = require("./utils");
function toHaveAccessibleDescription(htmlElement, expectedAccessibleDescription) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveAccessibleDescription, this);
const actualAccessibleDescription = (0, _domAccessibilityApi.computeAccessibleDescription)(htmlElement);
const missingExpectedValue = arguments.length === 1;
let pass = false;
if (missingExpectedValue) {
// When called without an expected value we only want to validate that the element has an
// accessible description, whatever it may be.
pass = actualAccessibleDescription !== '';
} else {
pass = expectedAccessibleDescription instanceof RegExp ? expectedAccessibleDescription.test(actualAccessibleDescription) : this.equals(actualAccessibleDescription, expectedAccessibleDescription);
}
return {
pass,
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.${toHaveAccessibleDescription.name}`, 'element', ''), `Expected element ${to} have accessible description`, expectedAccessibleDescription, 'Received', actualAccessibleDescription);
}
};
}

View File

@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveAccessibleErrorMessage = toHaveAccessibleErrorMessage;
var _utils = require("./utils");
const ariaInvalidName = 'aria-invalid';
const validStates = ['false'];
// See `aria-errormessage` spec at https://www.w3.org/TR/wai-aria-1.2/#aria-errormessage
function toHaveAccessibleErrorMessage(htmlElement, expectedAccessibleErrorMessage) {
var _htmlElement$ownerDoc, _htmlElement$ownerDoc2;
(0, _utils.checkHtmlElement)(htmlElement, toHaveAccessibleErrorMessage, this);
const to = this.isNot ? 'not to' : 'to';
const method = this.isNot ? '.not.toHaveAccessibleErrorMessage' : '.toHaveAccessibleErrorMessage';
// Enforce Valid Id
const errormessageId = htmlElement.getAttribute('aria-errormessage');
const errormessageIdInvalid = !!errormessageId && /\s+/.test(errormessageId);
if (errormessageIdInvalid) {
return {
pass: false,
message: () => {
return (0, _utils.getMessage)(this, this.utils.matcherHint(method, 'element'), "Expected element's `aria-errormessage` attribute to be empty or a single, valid ID", '', 'Received', `aria-errormessage="${errormessageId}"`);
}
};
}
// See `aria-invalid` spec at https://www.w3.org/TR/wai-aria-1.2/#aria-invalid
const ariaInvalidVal = htmlElement.getAttribute(ariaInvalidName);
const fieldValid = !htmlElement.hasAttribute(ariaInvalidName) || validStates.includes(ariaInvalidVal);
// Enforce Valid `aria-invalid` Attribute
if (fieldValid) {
return {
pass: false,
message: () => {
return (0, _utils.getMessage)(this, this.utils.matcherHint(method, 'element'), 'Expected element to be marked as invalid with attribute', `${ariaInvalidName}="${String(true)}"`, 'Received', htmlElement.hasAttribute('aria-invalid') ? `${ariaInvalidName}="${htmlElement.getAttribute(ariaInvalidName)}` : null);
}
};
}
const error = (0, _utils.normalize)((_htmlElement$ownerDoc = (_htmlElement$ownerDoc2 = htmlElement.ownerDocument.getElementById(errormessageId)) == null ? void 0 : _htmlElement$ownerDoc2.textContent) != null ? _htmlElement$ownerDoc : '');
return {
pass: expectedAccessibleErrorMessage === undefined ? Boolean(error) : expectedAccessibleErrorMessage instanceof RegExp ? expectedAccessibleErrorMessage.test(error) : this.equals(error, expectedAccessibleErrorMessage),
message: () => {
return (0, _utils.getMessage)(this, this.utils.matcherHint(method, 'element'), `Expected element ${to} have accessible error message`, expectedAccessibleErrorMessage != null ? expectedAccessibleErrorMessage : '', 'Received', error);
}
};
}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveAccessibleName = toHaveAccessibleName;
var _domAccessibilityApi = require("dom-accessibility-api");
var _utils = require("./utils");
function toHaveAccessibleName(htmlElement, expectedAccessibleName) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveAccessibleName, this);
const actualAccessibleName = (0, _domAccessibilityApi.computeAccessibleName)(htmlElement);
const missingExpectedValue = arguments.length === 1;
let pass = false;
if (missingExpectedValue) {
// When called without an expected value we only want to validate that the element has an
// accessible name, whatever it may be.
pass = actualAccessibleName !== '';
} else {
pass = expectedAccessibleName instanceof RegExp ? expectedAccessibleName.test(actualAccessibleName) : this.equals(actualAccessibleName, expectedAccessibleName);
}
return {
pass,
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.${toHaveAccessibleName.name}`, 'element', ''), `Expected element ${to} have accessible name`, expectedAccessibleName, 'Received', actualAccessibleName);
}
};
}

View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveAttribute = toHaveAttribute;
var _utils = require("./utils");
function printAttribute(stringify, name, value) {
return value === undefined ? name : `${name}=${stringify(value)}`;
}
function getAttributeComment(stringify, name, value) {
return value === undefined ? `element.hasAttribute(${stringify(name)})` : `element.getAttribute(${stringify(name)}) === ${stringify(value)}`;
}
function toHaveAttribute(htmlElement, name, expectedValue) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveAttribute, this);
const isExpectedValuePresent = expectedValue !== undefined;
const hasAttribute = htmlElement.hasAttribute(name);
const receivedValue = htmlElement.getAttribute(name);
return {
pass: isExpectedValuePresent ? hasAttribute && this.equals(receivedValue, expectedValue) : hasAttribute,
message: () => {
const to = this.isNot ? 'not to' : 'to';
const receivedAttribute = hasAttribute ? printAttribute(this.utils.stringify, name, receivedValue) : null;
const matcher = this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveAttribute`, 'element', this.utils.printExpected(name), {
secondArgument: isExpectedValuePresent ? this.utils.printExpected(expectedValue) : undefined,
comment: getAttributeComment(this.utils.stringify, name, expectedValue)
});
return (0, _utils.getMessage)(this, matcher, `Expected the element ${to} have attribute`, printAttribute(this.utils.stringify, name, expectedValue), 'Received', receivedAttribute);
}
};
}

View File

@@ -0,0 +1,61 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveClass = toHaveClass;
var _utils = require("./utils");
function getExpectedClassNamesAndOptions(params) {
const lastParam = params.pop();
let expectedClassNames, options;
if (typeof lastParam === 'object') {
expectedClassNames = params;
options = lastParam;
} else {
expectedClassNames = params.concat(lastParam);
options = {
exact: false
};
}
return {
expectedClassNames,
options
};
}
function splitClassNames(str) {
if (!str) {
return [];
}
return str.split(/\s+/).filter(s => s.length > 0);
}
function isSubset(subset, superset) {
return subset.every(item => superset.includes(item));
}
function toHaveClass(htmlElement, ...params) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveClass, this);
const {
expectedClassNames,
options
} = getExpectedClassNamesAndOptions(params);
const received = splitClassNames(htmlElement.getAttribute('class'));
const expected = expectedClassNames.reduce((acc, className) => acc.concat(splitClassNames(className)), []);
if (options.exact) {
return {
pass: isSubset(expected, received) && expected.length === received.length,
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveClass`, 'element', this.utils.printExpected(expected.join(' '))), `Expected the element ${to} have EXACTLY defined classes`, expected.join(' '), 'Received', received.join(' '));
}
};
}
return expected.length > 0 ? {
pass: isSubset(expected, received),
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveClass`, 'element', this.utils.printExpected(expected.join(' '))), `Expected the element ${to} have class`, expected.join(' '), 'Received', received.join(' '));
}
} : {
pass: this.isNot ? received.length > 0 : false,
message: () => this.isNot ? (0, _utils.getMessage)(this, this.utils.matcherHint('.not.toHaveClass', 'element', ''), 'Expected the element to have classes', '(none)', 'Received', received.join(' ')) : [this.utils.matcherHint(`.toHaveClass`, 'element'), 'At least one expected class must be provided.'].join('\n')
};
}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveDescription = toHaveDescription;
var _utils = require("./utils");
// See algoritm: https://www.w3.org/TR/accname-1.1/#mapping_additional_nd_description
function toHaveDescription(htmlElement, checkWith) {
(0, _utils.deprecate)('toHaveDescription', 'Please use toHaveAccessibleDescription.');
(0, _utils.checkHtmlElement)(htmlElement, toHaveDescription, this);
const expectsDescription = checkWith !== undefined;
const descriptionIDRaw = htmlElement.getAttribute('aria-describedby') || '';
const descriptionIDs = descriptionIDRaw.split(/\s+/).filter(Boolean);
let description = '';
if (descriptionIDs.length > 0) {
const document = htmlElement.ownerDocument;
const descriptionEls = descriptionIDs.map(descriptionID => document.getElementById(descriptionID)).filter(Boolean);
description = (0, _utils.normalize)(descriptionEls.map(el => el.textContent).join(' '));
}
return {
pass: expectsDescription ? checkWith instanceof RegExp ? checkWith.test(description) : this.equals(description, checkWith) : Boolean(description),
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveDescription`, 'element', ''), `Expected the element ${to} have description`, this.utils.printExpected(checkWith), 'Received', this.utils.printReceived(description));
}
};
}

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveDisplayValue = toHaveDisplayValue;
var _utils = require("./utils");
function toHaveDisplayValue(htmlElement, expectedValue) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveDisplayValue, this);
const tagName = htmlElement.tagName.toLowerCase();
if (!['select', 'input', 'textarea'].includes(tagName)) {
throw new Error('.toHaveDisplayValue() currently supports only input, textarea or select elements, try with another matcher instead.');
}
if (tagName === 'input' && ['radio', 'checkbox'].includes(htmlElement.type)) {
throw new Error(`.toHaveDisplayValue() currently does not support input[type="${htmlElement.type}"], try with another matcher instead.`);
}
const values = getValues(tagName, htmlElement);
const expectedValues = getExpectedValues(expectedValue);
const numberOfMatchesWithValues = expectedValues.filter(expected => values.some(value => expected instanceof RegExp ? expected.test(value) : this.equals(value, String(expected)))).length;
const matchedWithAllValues = numberOfMatchesWithValues === values.length;
const matchedWithAllExpectedValues = numberOfMatchesWithValues === expectedValues.length;
return {
pass: matchedWithAllValues && matchedWithAllExpectedValues,
message: () => (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveDisplayValue`, 'element', ''), `Expected element ${this.isNot ? 'not ' : ''}to have display value`, expectedValue, 'Received', values)
};
}
function getValues(tagName, htmlElement) {
return tagName === 'select' ? Array.from(htmlElement).filter(option => option.selected).map(option => option.textContent) : [htmlElement.value];
}
function getExpectedValues(expectedValue) {
return expectedValue instanceof Array ? expectedValue : [expectedValue];
}

View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveErrorMessage = toHaveErrorMessage;
var _utils = require("./utils");
// See aria-errormessage spec https://www.w3.org/TR/wai-aria-1.2/#aria-errormessage
function toHaveErrorMessage(htmlElement, checkWith) {
(0, _utils.deprecate)('toHaveErrorMessage', 'Please use toHaveAccessibleErrorMessage.');
(0, _utils.checkHtmlElement)(htmlElement, toHaveErrorMessage, this);
if (!htmlElement.hasAttribute('aria-invalid') || htmlElement.getAttribute('aria-invalid') === 'false') {
const not = this.isNot ? '.not' : '';
return {
pass: false,
message: () => {
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${not}.toHaveErrorMessage`, 'element', ''), `Expected the element to have invalid state indicated by`, 'aria-invalid="true"', 'Received', htmlElement.hasAttribute('aria-invalid') ? `aria-invalid="${htmlElement.getAttribute('aria-invalid')}"` : this.utils.printReceived(''));
}
};
}
const expectsErrorMessage = checkWith !== undefined;
const errormessageIDRaw = htmlElement.getAttribute('aria-errormessage') || '';
const errormessageIDs = errormessageIDRaw.split(/\s+/).filter(Boolean);
let errormessage = '';
if (errormessageIDs.length > 0) {
const document = htmlElement.ownerDocument;
const errormessageEls = errormessageIDs.map(errormessageID => document.getElementById(errormessageID)).filter(Boolean);
errormessage = (0, _utils.normalize)(errormessageEls.map(el => el.textContent).join(' '));
}
return {
pass: expectsErrorMessage ? checkWith instanceof RegExp ? checkWith.test(errormessage) : this.equals(errormessage, checkWith) : Boolean(errormessage),
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveErrorMessage`, 'element', ''), `Expected the element ${to} have error message`, this.utils.printExpected(checkWith), 'Received', this.utils.printReceived(errormessage));
}
};
}

View File

@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveFocus = toHaveFocus;
var _utils = require("./utils");
function toHaveFocus(element) {
(0, _utils.checkHtmlElement)(element, toHaveFocus, this);
return {
pass: element.ownerDocument.activeElement === element,
message: () => {
return [this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveFocus`, 'element', ''), '', ...(this.isNot ? ['Received element is focused:', ` ${this.utils.printReceived(element)}`] : ['Expected element with focus:', ` ${this.utils.printExpected(element)}`, 'Received element with focus:', ` ${this.utils.printReceived(element.ownerDocument.activeElement)}`])].join('\n');
}
};
}

View File

@@ -0,0 +1,76 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveFormValues = toHaveFormValues;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _isEqualWith = _interopRequireDefault(require("lodash/isEqualWith"));
var _uniq = _interopRequireDefault(require("lodash/uniq"));
var _css = _interopRequireDefault(require("css.escape"));
var _utils = require("./utils");
// Returns the combined value of several elements that have the same name
// e.g. radio buttons or groups of checkboxes
function getMultiElementValue(elements) {
const types = (0, _uniq.default)(elements.map(element => element.type));
if (types.length !== 1) {
throw new Error('Multiple form elements with the same name must be of the same type');
}
switch (types[0]) {
case 'radio':
{
const theChosenOne = elements.find(radio => radio.checked);
return theChosenOne ? theChosenOne.value : undefined;
}
case 'checkbox':
return elements.filter(checkbox => checkbox.checked).map(checkbox => checkbox.value);
default:
// NOTE: Not even sure this is a valid use case, but just in case...
return elements.map(element => element.value);
}
}
function getFormValue(container, name) {
const elements = [...container.querySelectorAll(`[name="${(0, _css.default)(name)}"]`)];
/* istanbul ignore if */
if (elements.length === 0) {
return undefined; // shouldn't happen, but just in case
}
switch (elements.length) {
case 1:
return (0, _utils.getSingleElementValue)(elements[0]);
default:
return getMultiElementValue(elements);
}
}
// Strips the `[]` suffix off a form value name
function getPureName(name) {
return /\[\]$/.test(name) ? name.slice(0, -2) : name;
}
function getAllFormValues(container) {
const names = Array.from(container.elements).map(element => element.name);
return names.reduce((obj, name) => (0, _extends2.default)({}, obj, {
[getPureName(name)]: getFormValue(container, name)
}), {});
}
function toHaveFormValues(formElement, expectedValues) {
(0, _utils.checkHtmlElement)(formElement, toHaveFormValues, this);
if (!formElement.elements) {
// TODO: Change condition to use instanceof against the appropriate element classes instead
throw new Error('toHaveFormValues must be called on a form or a fieldset');
}
const formValues = getAllFormValues(formElement);
return {
pass: Object.entries(expectedValues).every(([name, expectedValue]) => (0, _isEqualWith.default)(formValues[name], expectedValue, _utils.compareArraysAsSet)),
message: () => {
const to = this.isNot ? 'not to' : 'to';
const matcher = `${this.isNot ? '.not' : ''}.toHaveFormValues`;
const commonKeyValues = Object.keys(formValues).filter(key => expectedValues.hasOwnProperty(key)).reduce((obj, key) => (0, _extends2.default)({}, obj, {
[key]: formValues[key]
}), {});
return [this.utils.matcherHint(matcher, 'element', ''), `Expected the element ${to} have form values`, this.utils.diff(expectedValues, commonKeyValues)].join('\n\n');
}
};
}

View File

@@ -0,0 +1,53 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveStyle = toHaveStyle;
var _chalk = _interopRequireDefault(require("chalk"));
var _utils = require("./utils");
function getStyleDeclaration(document, css) {
const styles = {};
// The next block is necessary to normalize colors
const copy = document.createElement('div');
Object.keys(css).forEach(property => {
copy.style[property] = css[property];
styles[property] = copy.style[property];
});
return styles;
}
function isSubset(styles, computedStyle) {
return !!Object.keys(styles).length && Object.entries(styles).every(([prop, value]) => computedStyle[prop] === value || computedStyle.getPropertyValue(prop.toLowerCase()) === value);
}
function printoutStyles(styles) {
return Object.keys(styles).sort().map(prop => `${prop}: ${styles[prop]};`).join('\n');
}
// Highlights only style rules that were expected but were not found in the
// received computed styles
function expectedDiff(diffFn, expected, computedStyles) {
const received = Array.from(computedStyles).filter(prop => expected[prop] !== undefined).reduce((obj, prop) => Object.assign(obj, {
[prop]: computedStyles.getPropertyValue(prop)
}), {});
const diffOutput = diffFn(printoutStyles(expected), printoutStyles(received));
// Remove the "+ Received" annotation because this is a one-way diff
return diffOutput.replace(`${_chalk.default.red('+ Received')}\n`, '');
}
function toHaveStyle(htmlElement, css) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveStyle, this);
const parsedCSS = typeof css === 'object' ? css : (0, _utils.parseCSS)(css, toHaveStyle, this);
const {
getComputedStyle
} = htmlElement.ownerDocument.defaultView;
const expected = getStyleDeclaration(htmlElement.ownerDocument, parsedCSS);
const received = getComputedStyle(htmlElement);
return {
pass: isSubset(expected, received),
message: () => {
const matcher = `${this.isNot ? '.not' : ''}.toHaveStyle`;
return [this.utils.matcherHint(matcher, 'element', ''), expectedDiff(this.utils.diff, expected, received)].join('\n\n');
}
};
}

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveTextContent = toHaveTextContent;
var _utils = require("./utils");
function toHaveTextContent(node, checkWith, options = {
normalizeWhitespace: true
}) {
(0, _utils.checkNode)(node, toHaveTextContent, this);
const textContent = options.normalizeWhitespace ? (0, _utils.normalize)(node.textContent) : node.textContent.replace(/\u00a0/g, ' '); // Replace &nbsp; with normal spaces
const checkingWithEmptyString = textContent !== '' && checkWith === '';
return {
pass: !checkingWithEmptyString && (0, _utils.matches)(textContent, checkWith),
message: () => {
const to = this.isNot ? 'not to' : 'to';
return (0, _utils.getMessage)(this, this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveTextContent`, 'element', ''), checkingWithEmptyString ? `Checking with empty string will always match, use .toBeEmptyDOMElement() instead` : `Expected element ${to} have text content`, checkWith, 'Received', textContent);
}
};
}

View File

@@ -0,0 +1,31 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveValue = toHaveValue;
var _isEqualWith = _interopRequireDefault(require("lodash/isEqualWith"));
var _utils = require("./utils");
function toHaveValue(htmlElement, expectedValue) {
(0, _utils.checkHtmlElement)(htmlElement, toHaveValue, this);
if (htmlElement.tagName.toLowerCase() === 'input' && ['checkbox', 'radio'].includes(htmlElement.type)) {
throw new Error('input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead');
}
const receivedValue = (0, _utils.getSingleElementValue)(htmlElement);
const expectsValue = expectedValue !== undefined;
let expectedTypedValue = expectedValue;
let receivedTypedValue = receivedValue;
if (expectedValue == receivedValue && expectedValue !== receivedValue) {
expectedTypedValue = `${expectedValue} (${typeof expectedValue})`;
receivedTypedValue = `${receivedValue} (${typeof receivedValue})`;
}
return {
pass: expectsValue ? (0, _isEqualWith.default)(receivedValue, expectedValue, _utils.compareArraysAsSet) : Boolean(receivedValue),
message: () => {
const to = this.isNot ? 'not to' : 'to';
const matcher = this.utils.matcherHint(`${this.isNot ? '.not' : ''}.toHaveValue`, 'element', expectedValue);
return (0, _utils.getMessage)(this, matcher, `Expected the element ${to} have value`, expectsValue ? expectedTypedValue : '(any)', 'Received', receivedTypedValue);
}
};
}

View File

@@ -0,0 +1,188 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NodeTypeError = exports.HtmlElementTypeError = void 0;
exports.checkHtmlElement = checkHtmlElement;
exports.checkNode = checkNode;
exports.compareArraysAsSet = compareArraysAsSet;
exports.deprecate = deprecate;
exports.getMessage = getMessage;
exports.getSingleElementValue = getSingleElementValue;
exports.getTag = getTag;
exports.matches = matches;
exports.normalize = normalize;
exports.parseCSS = parseCSS;
exports.toSentence = toSentence;
var _redent = _interopRequireDefault(require("redent"));
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
var _cssTools = require("@adobe/css-tools");
class GenericTypeError extends Error {
constructor(expectedString, received, matcherFn, context) {
super();
/* istanbul ignore next */
if (Error.captureStackTrace) {
Error.captureStackTrace(this, matcherFn);
}
let withType = '';
try {
withType = context.utils.printWithType('Received', received, context.utils.printReceived);
} catch (e) {
// Can throw for Document:
// https://github.com/jsdom/jsdom/issues/2304
}
this.message = [context.utils.matcherHint(`${context.isNot ? '.not' : ''}.${matcherFn.name}`, 'received', ''), '',
// eslint-disable-next-line @babel/new-cap
`${context.utils.RECEIVED_COLOR('received')} value must ${expectedString}.`, withType].join('\n');
}
}
class HtmlElementTypeError extends GenericTypeError {
constructor(...args) {
super('be an HTMLElement or an SVGElement', ...args);
}
}
exports.HtmlElementTypeError = HtmlElementTypeError;
class NodeTypeError extends GenericTypeError {
constructor(...args) {
super('be a Node', ...args);
}
}
exports.NodeTypeError = NodeTypeError;
function checkHasWindow(htmlElement, ErrorClass, ...args) {
if (!htmlElement || !htmlElement.ownerDocument || !htmlElement.ownerDocument.defaultView) {
throw new ErrorClass(htmlElement, ...args);
}
}
function checkNode(node, ...args) {
checkHasWindow(node, NodeTypeError, ...args);
const window = node.ownerDocument.defaultView;
if (!(node instanceof window.Node)) {
throw new NodeTypeError(node, ...args);
}
}
function checkHtmlElement(htmlElement, ...args) {
checkHasWindow(htmlElement, HtmlElementTypeError, ...args);
const window = htmlElement.ownerDocument.defaultView;
if (!(htmlElement instanceof window.HTMLElement) && !(htmlElement instanceof window.SVGElement)) {
throw new HtmlElementTypeError(htmlElement, ...args);
}
}
class InvalidCSSError extends Error {
constructor(received, matcherFn, context) {
super();
/* istanbul ignore next */
if (Error.captureStackTrace) {
Error.captureStackTrace(this, matcherFn);
}
this.message = [received.message, '',
// eslint-disable-next-line @babel/new-cap
context.utils.RECEIVED_COLOR(`Failing css:`),
// eslint-disable-next-line @babel/new-cap
context.utils.RECEIVED_COLOR(`${received.css}`)].join('\n');
}
}
function parseCSS(css, ...args) {
const ast = (0, _cssTools.parse)(`selector { ${css} }`, {
silent: true
}).stylesheet;
if (ast.parsingErrors && ast.parsingErrors.length > 0) {
const {
reason,
line
} = ast.parsingErrors[0];
throw new InvalidCSSError({
css,
message: `Syntax error parsing expected css: ${reason} on line: ${line}`
}, ...args);
}
const parsedRules = ast.rules[0].declarations.filter(d => d.type === 'declaration').reduce((obj, {
property,
value
}) => Object.assign(obj, {
[property]: value
}), {});
return parsedRules;
}
function display(context, value) {
return typeof value === 'string' ? value : context.utils.stringify(value);
}
function getMessage(context, matcher, expectedLabel, expectedValue, receivedLabel, receivedValue) {
return [`${matcher}\n`,
// eslint-disable-next-line @babel/new-cap
`${expectedLabel}:\n${context.utils.EXPECTED_COLOR((0, _redent.default)(display(context, expectedValue), 2))}`,
// eslint-disable-next-line @babel/new-cap
`${receivedLabel}:\n${context.utils.RECEIVED_COLOR((0, _redent.default)(display(context, receivedValue), 2))}`].join('\n');
}
function matches(textToMatch, matcher) {
if (matcher instanceof RegExp) {
return matcher.test(textToMatch);
} else {
return textToMatch.includes(String(matcher));
}
}
function deprecate(name, replacementText) {
// Notify user that they are using deprecated functionality.
// eslint-disable-next-line no-console
console.warn(`Warning: ${name} has been deprecated and will be removed in future updates.`, replacementText);
}
function normalize(text) {
return text.replace(/\s+/g, ' ').trim();
}
function getTag(element) {
return element.tagName && element.tagName.toLowerCase();
}
function getSelectValue({
multiple,
options
}) {
const selectedOptions = [...options].filter(option => option.selected);
if (multiple) {
return [...selectedOptions].map(opt => opt.value);
}
/* istanbul ignore if */
if (selectedOptions.length === 0) {
return undefined; // Couldn't make this happen, but just in case
}
return selectedOptions[0].value;
}
function getInputValue(inputElement) {
switch (inputElement.type) {
case 'number':
return inputElement.value === '' ? null : Number(inputElement.value);
case 'checkbox':
return inputElement.checked;
default:
return inputElement.value;
}
}
function getSingleElementValue(element) {
/* istanbul ignore if */
if (!element) {
return undefined;
}
switch (element.tagName.toLowerCase()) {
case 'input':
return getInputValue(element);
case 'select':
return getSelectValue(element);
default:
return element.value;
}
}
function compareArraysAsSet(a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
return (0, _isEqual.default)(new Set(a), new Set(b));
}
return undefined;
}
function toSentence(array, {
wordConnector = ', ',
lastWordConnector = ' and '
} = {}) {
return [array.slice(0, -1).join(wordConnector), array[array.length - 1]].join(array.length > 1 ? lastWordConnector : '');
}