/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { reducers, } = require("resource://devtools/client/accessibility/reducers/index.js"); const CheckClass = require("resource://devtools/client/accessibility/components/Check.js"); const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); const { createStore, combineReducers, } = require("resource://devtools/client/shared/vendor/redux.js"); /** * Prepare the store for use in testing. */ function setupStore({ preloadedState } = {}) { const store = createStore(combineReducers(reducers), preloadedState); return store; } /** * Build a mock accessible object. * @param {Object} form * Data similar to what accessible actor passes to accessible front. */ function mockAccessible(form) { return { on: jest.fn(), off: jest.fn(), isDestroyed: () => !form?.actorID, audit: jest.fn().mockReturnValue(Promise.resolve()), ...form, }; } /** * * @param {DOMNode} * DOMNode that corresponds to a menu item in a menu list * @param {Object} * Expected properties: * - role: optional ARIA role for the menu item * - checked: optional checked state for the menu item * - disabled: optional disabled state for the menu item * - label: optional text label for the menu item */ function checkMenuItem(menuItem, expected) { expect(menuItem.tagName).toBe("BUTTON"); if (expected.role) { expect(menuItem.getAttribute("role")).toBe(expected.role); } else if (typeof expected.checked !== "undefined") { expect(menuItem.getAttribute("role")).toBe("menuitemcheckbox"); } else { expect(menuItem.getAttribute("role")).toBe("menuitem"); } if (typeof expected.checked !== "undefined") { expect(menuItem.hasAttribute("aria-checked")).toBe(expected.checked); } if (expected.checked) { expect(menuItem.getAttribute("aria-checked")).toBe("true"); } if (expected.disabled) { expect(menuItem.hasAttribute("disabled")).toBe(true); } if (expected.label) { expect(menuItem.textContent).toBe(expected.label); } } /** * * @param {ReactWrapper} * React wrapper for the top level check component. * @param {Object} * Expected audit properties: * - score: audit score * - issue: audit issue type */ function testCustomCheck(wrapper, props) { expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.children().length).toBe(1); const check = wrapper.childAt(0); expect(wrapper.find(CheckClass)).toStrictEqual(check); testCheck(check, props); } /** * * @param {ReactWrapper} * React wrapper for the check component. * @param {Object} * Expected audit properties: * - score: audit score * - issue: audit issue type */ function testCheck(wrapper, props) { expect(wrapper.html()).toMatchSnapshot(); const container = wrapper.childAt(0); expect(container.hasClass("accessibility-check")).toBe(true); expect(container.prop("role")).toBe("presentation"); expect(container.prop("tabIndex")).toBe("-1"); expect(wrapper.props()).toMatchObject(props); const localized = wrapper.find(FluentReact.Localized); expect(localized.length).toBe(3); const heading = localized.at(0).childAt(0); expect(heading.type()).toBe("h3"); expect(heading.hasClass("accessibility-check-header")).toBe(true); const icon = localized.at(1).childAt(0); expect(icon.type()).toBe("img"); expect(icon.prop("data-score")).toEqual(props.score); const annotation = localized.at(2).childAt(0); expect(annotation.type()).toBe("p"); expect(annotation.hasClass("accessibility-check-annotation")).toBe(true); } module.exports = { checkMenuItem, mockAccessible, setupStore, testCheck, testCustomCheck, };