fix: make web-test-runner using documentOrShadowRoot.activeElement debuggable
This commit is contained in:
parent
3d1c723d39
commit
3e13adedc2
17 changed files with 160 additions and 122 deletions
6
.changeset/wise-mirrors-grabberz.md
Normal file
6
.changeset/wise-mirrors-grabberz.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@lion/ui': patch
|
||||
---
|
||||
|
||||
make web-test-runner statements checking `documentOrShadowRoot.activeElement` debuggable by exposing
|
||||
a test-helper method `isActiveElement`.
|
||||
|
|
@ -1,20 +1,22 @@
|
|||
import {
|
||||
getComboboxMembers,
|
||||
getFilteredOptionValues,
|
||||
mimicKeyPress,
|
||||
mimicUserTyping,
|
||||
mimicUserTypingAdvanced,
|
||||
} from '@lion/ui/combobox-test-helpers.js';
|
||||
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
|
||||
import { Required, Unparseable } from '@lion/ui/form-core.js';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { LionCombobox } from '@lion/ui/combobox.js';
|
||||
import { browserDetection } from '@lion/ui/core.js';
|
||||
import '@lion/ui/define/lion-combobox.js';
|
||||
import '@lion/ui/define/lion-listbox.js';
|
||||
import '@lion/ui/define/lion-option.js';
|
||||
import { Required, Unparseable } from '@lion/ui/form-core.js';
|
||||
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { LitElement } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
getFilteredOptionValues,
|
||||
mimicUserTypingAdvanced,
|
||||
getComboboxMembers,
|
||||
mimicUserTyping,
|
||||
mimicKeyPress,
|
||||
} from '@lion/ui/combobox-test-helpers.js';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../types/SelectionDisplay.js').SelectionDisplay} SelectionDisplay
|
||||
|
|
@ -986,7 +988,7 @@ describe('lion-combobox', () => {
|
|||
options[0].click();
|
||||
await el.updateComplete;
|
||||
expect(el.opened).to.equal(false);
|
||||
expect(document.activeElement).to.equal(_inputNode);
|
||||
expect(isActiveElement(_inputNode)).to.be.true;
|
||||
|
||||
// step [4]
|
||||
await el.updateComplete;
|
||||
|
|
|
|||
14
packages/ui/components/core/test-helpers/isActiveElement.js
Normal file
14
packages/ui/components/core/test-helpers/isActiveElement.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { getDeepActiveElement } from '../src/getDeepActiveElement.js';
|
||||
/**
|
||||
* Readable alternative for `expect(el).to.equal(document.activeElement);`.
|
||||
* While this is readable by itself, it makes Web Test Runner hang completely in many occasions.
|
||||
* Therefore it's better to write:
|
||||
* `expect(isActiveElement(el)).to.be.true;`
|
||||
* @param {Element} el
|
||||
* @param {{deep?: boolean}} opts
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isActiveElement(el, { deep = false } = {}) {
|
||||
const activeEl = deep ? getDeepActiveElement() : document.activeElement;
|
||||
return el === activeEl;
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { LitElement } from 'lit';
|
|||
import sinon from 'sinon';
|
||||
|
||||
import { ScopedElementsMixin, supportsScopedRegistry } from '../src/ScopedElementsMixin.js';
|
||||
import { isActiveElement } from '../test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../types/SlotMixinTypes.js').SlotHost} SlotHost
|
||||
|
|
@ -210,12 +211,12 @@ describe('SlotMixin', () => {
|
|||
);
|
||||
const el = /** @type {* & SlotHost} */ (await fixture(`<${tag}></${tag}>`));
|
||||
el._focusableNode.focus();
|
||||
expect(document.activeElement).to.equal(el._focusableNode);
|
||||
expect(isActiveElement(el._focusableNode)).to.be.true;
|
||||
|
||||
el.currentValue = 1;
|
||||
await el.updateComplete;
|
||||
|
||||
expect(document.activeElement).to.equal(el._focusableNode);
|
||||
expect(isActiveElement(el._focusableNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('keeps focus after rerendering complex shadow root into slot', async () => {
|
||||
|
|
@ -277,7 +278,7 @@ describe('SlotMixin', () => {
|
|||
el.currentValue = 1;
|
||||
await el.updateComplete;
|
||||
|
||||
expect(document.activeElement).to.equal(el._focusableNode);
|
||||
expect(isActiveElement(el._focusableNode)).to.be.true;
|
||||
expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
|
||||
});
|
||||
|
||||
|
|
@ -335,12 +336,12 @@ describe('SlotMixin', () => {
|
|||
|
||||
el._focusableNode._buttonNode.focus();
|
||||
|
||||
expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
|
||||
expect(isActiveElement(el._focusableNode._buttonNode, { deep: true })).to.be.true;
|
||||
|
||||
el.currentValue = 1;
|
||||
await el.updateComplete;
|
||||
|
||||
expect(document.activeElement).to.equal(el._focusableNode);
|
||||
expect(isActiveElement(el._focusableNode)).to.be.true;
|
||||
expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable lit-a11y/no-autofocus */
|
||||
import { expect, fixture as _fixture, html, unsafeStatic, aTimeout } from '@open-wc/testing';
|
||||
import { runOverlayMixinSuite } from '../../overlays/test-suites/OverlayMixin.suite.js';
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
import '@lion/ui/define/lion-dialog.js';
|
||||
|
||||
/**
|
||||
|
|
@ -89,8 +90,8 @@ describe('lion-dialog', () => {
|
|||
const invokerNode = el._overlayInvokerNode;
|
||||
invokerNode.focus();
|
||||
invokerNode.click();
|
||||
const contentNode = el.querySelector('[slot="content"]');
|
||||
expect(document.activeElement).to.equal(contentNode);
|
||||
const contentNode = /** @type {Element} */ (el.querySelector('[slot="content"]'));
|
||||
expect(isActiveElement(contentNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on autofocused element', async () => {
|
||||
|
|
@ -107,8 +108,8 @@ describe('lion-dialog', () => {
|
|||
const invokerNode = el._overlayInvokerNode;
|
||||
invokerNode.focus();
|
||||
invokerNode.click();
|
||||
const input = el.querySelector('input');
|
||||
expect(document.activeElement).to.equal(input);
|
||||
const input = /** @type {Element} */ (el.querySelector('input'));
|
||||
expect(isActiveElement(input)).to.be.true;
|
||||
});
|
||||
|
||||
it('with trapsKeyboardFocus set to false the focus stays on the invoker', async () => {
|
||||
|
|
@ -125,7 +126,7 @@ describe('lion-dialog', () => {
|
|||
const invokerNode = el._overlayInvokerNode;
|
||||
invokerNode.focus();
|
||||
invokerNode.click();
|
||||
expect(document.activeElement).to.equal(invokerNode);
|
||||
expect(isActiveElement(invokerNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('opened-changed event should send detail object with opened state', async () => {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { LitElement } from 'lit';
|
||||
import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
|
||||
import { defineCE, expect, fixture, html, triggerFocusFor, unsafeStatic } from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { spy } from 'sinon';
|
||||
import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
|
||||
import { NativeTextFieldMixin } from '@lion/ui/form-core.js';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { browserDetection } from '@lion/ui/core.js';
|
||||
import { LitElement } from 'lit';
|
||||
import { spy } from 'sinon';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
|
||||
* @typedef {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
|
||||
* @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -56,7 +58,7 @@ export function runNativeTextFieldMixinSuite(customConfig) {
|
|||
const { _inputNode } = getFormControlMembers(el);
|
||||
await triggerFocusFor(el);
|
||||
await el.updateComplete;
|
||||
expect(document.activeElement).to.equal(_inputNode);
|
||||
expect(isActiveElement(_inputNode)).to.be.true;
|
||||
await sendKeys({
|
||||
press: 'h',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,27 +1,28 @@
|
|||
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||
import { Required, Validator } from '@lion/ui/form-core.js';
|
||||
import '@lion/ui/define/lion-field.js';
|
||||
import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
|
||||
import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
|
||||
import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
|
||||
import {
|
||||
expect,
|
||||
fixture,
|
||||
html,
|
||||
triggerBlurFor,
|
||||
triggerFocusFor,
|
||||
unsafeStatic,
|
||||
} from '@open-wc/testing';
|
||||
import { Required, Validator } from '@lion/ui/form-core.js';
|
||||
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||
import '@lion/ui/define/lion-field.js';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
triggerFocusFor,
|
||||
triggerBlurFor,
|
||||
unsafeStatic,
|
||||
fixture,
|
||||
expect,
|
||||
html,
|
||||
} from '@open-wc/testing';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../src/LionField.js').LionField} LionField
|
||||
* @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
|
||||
* @typedef {FormControlHost & HTMLElement & {_parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
|
||||
* @typedef {HTMLElement & {shadowRoot: HTMLElement, assignedNodes: Function}} ShadowHTMLElement
|
||||
* @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
|
||||
* @typedef {import('../src/LionField.js').LionField} LionField
|
||||
*/
|
||||
|
||||
/** @typedef {HTMLElement & {shadowRoot: HTMLElement, assignedNodes: Function}} ShadowHTMLElement */
|
||||
|
||||
const tagString = 'lion-field';
|
||||
const tag = unsafeStatic(tagString);
|
||||
const inputSlotString = '<input slot="input" />';
|
||||
|
|
@ -106,7 +107,7 @@ describe('<lion-field>', () => {
|
|||
|
||||
await triggerFocusFor(el);
|
||||
|
||||
expect(document.activeElement).to.equal(_inputNode);
|
||||
expect(isActiveElement(_inputNode)).to.be.true;
|
||||
expect(cbFocusHost.callCount).to.equal(1);
|
||||
expect(cbFocusNativeInput.callCount).to.equal(1);
|
||||
expect(cbBlurHost.callCount).to.equal(0);
|
||||
|
|
@ -117,7 +118,7 @@ describe('<lion-field>', () => {
|
|||
expect(cbBlurNativeInput.callCount).to.equal(1);
|
||||
|
||||
await triggerFocusFor(el);
|
||||
expect(document.activeElement).to.equal(_inputNode);
|
||||
expect(isActiveElement(_inputNode)).to.be.true;
|
||||
expect(cbFocusHost.callCount).to.equal(2);
|
||||
expect(cbFocusNativeInput.callCount).to.equal(2);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
/* eslint-disable lit-a11y/no-autofocus */
|
||||
import { expect, fixture } from '@open-wc/testing';
|
||||
import { html } from 'lit';
|
||||
import { getAllTagNames } from './helpers/helpers.js';
|
||||
import './helpers/umbrella-form.js';
|
||||
import '@lion/ui/define/lion-dialog.js';
|
||||
import '@lion/ui/define/lion-checkbox.js';
|
||||
import '@lion/ui/define/lion-dialog.js';
|
||||
import '@lion/ui/define/lion-option.js';
|
||||
import '@lion/ui/define/lion-radio.js';
|
||||
import { html } from 'lit';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
import { getAllTagNames } from './helpers/helpers.js';
|
||||
import './helpers/umbrella-form.js';
|
||||
/**
|
||||
* @typedef {import('./helpers/umbrella-form.js').UmbrellaForm} UmbrellaForm
|
||||
* @typedef {import('../../dialog/src/LionDialog.js').LionDialog} LionDialog
|
||||
|
|
@ -89,6 +90,6 @@ describe('Form inside dialog Integrations', () => {
|
|||
el._overlayInvokerNode.click();
|
||||
const lionInput = el.querySelector('[name="input"]');
|
||||
// @ts-expect-error [allow-protected-in-tests]
|
||||
expect(document.activeElement).to.equal(lionInput._focusableNode);
|
||||
expect(isActiveElement(lionInput._focusableNode)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,25 +1,27 @@
|
|||
import { LionFieldset } from '@lion/ui/fieldset.js';
|
||||
import '@lion/ui/define/lion-fieldset.js';
|
||||
import { LionField, Required } from '@lion/ui/form-core.js';
|
||||
import '@lion/ui/define/lion-field.js';
|
||||
import '@lion/ui/define/lion-validation-feedback.js';
|
||||
import { LionFieldset } from '@lion/ui/fieldset.js';
|
||||
import '@lion/ui/define/lion-checkbox-group.js';
|
||||
import '@lion/ui/define/lion-radio-group.js';
|
||||
import '@lion/ui/define/lion-fieldset.js';
|
||||
import '@lion/ui/define/lion-checkbox.js';
|
||||
import '@lion/ui/define/lion-listbox.js';
|
||||
import '@lion/ui/define/lion-option.js';
|
||||
import '@lion/ui/define/lion-checkbox-group.js';
|
||||
import '@lion/ui/define/lion-checkbox.js';
|
||||
import '@lion/ui/define/lion-radio-group.js';
|
||||
import '@lion/ui/define/lion-field.js';
|
||||
import '@lion/ui/define/lion-radio.js';
|
||||
import '@lion/ui/define/lion-form.js';
|
||||
import { spy } from 'sinon';
|
||||
import {
|
||||
fixture as _fixture,
|
||||
unsafeStatic,
|
||||
aTimeout,
|
||||
defineCE,
|
||||
expect,
|
||||
fixture as _fixture,
|
||||
html,
|
||||
oneEvent,
|
||||
unsafeStatic,
|
||||
expect,
|
||||
html,
|
||||
} from '@open-wc/testing';
|
||||
import { spy } from 'sinon';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../src/LionForm.js').LionForm} LionForm
|
||||
|
|
@ -225,7 +227,7 @@ describe('<lion-form>', () => {
|
|||
button.click();
|
||||
expect(dispatchSpy.args[0][0].type).to.equal('submit');
|
||||
// @ts-ignore [allow-protected] in test
|
||||
expect(document.activeElement).to.equal(el.formElements[1]._inputNode);
|
||||
expect(isActiveElement(el.formElements[1]._inputNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first erroneous form element within a fieldset', async () => {
|
||||
|
|
@ -248,7 +250,7 @@ describe('<lion-form>', () => {
|
|||
expect(dispatchSpy.args[0][0].type).to.equal('submit');
|
||||
const fieldset = el.formElements[0];
|
||||
// @ts-ignore [allow-protected] in test
|
||||
expect(document.activeElement).to.equal(fieldset.formElements[1]._inputNode);
|
||||
expect(isActiveElement(fieldset.formElements[1]._inputNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous fieldset', async () => {
|
||||
|
|
@ -268,7 +270,7 @@ describe('<lion-form>', () => {
|
|||
button.click();
|
||||
expect(dispatchSpy.args[0][0].type).to.equal('submit');
|
||||
const fieldset = el.formElements[0];
|
||||
expect(document.activeElement).to.equal(fieldset.formElements[0]._inputNode);
|
||||
expect(isActiveElement(fieldset.formElements[0]._inputNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous fieldset within another fieldset', async () => {
|
||||
|
|
@ -290,7 +292,7 @@ describe('<lion-form>', () => {
|
|||
const childFieldsetEl = parentFieldSetEl.formElements[0];
|
||||
const inputEl = childFieldsetEl.formElements[0];
|
||||
button.click();
|
||||
expect(document.activeElement).to.equal(inputEl._focusableNode);
|
||||
expect(isActiveElement(inputEl._focusableNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous listbox', async () => {
|
||||
|
|
@ -308,7 +310,7 @@ describe('<lion-form>', () => {
|
|||
const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
|
||||
button.click();
|
||||
const listboxEl = el.formElements[0];
|
||||
expect(document.activeElement).to.equal(listboxEl._inputNode);
|
||||
expect(isActiveElement(listboxEl._inputNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous listbox within a fieldset', async () => {
|
||||
|
|
@ -329,7 +331,7 @@ describe('<lion-form>', () => {
|
|||
button.click();
|
||||
const fieldsetEl = el.formElements[0];
|
||||
const listboxEl = fieldsetEl.formElements[0];
|
||||
expect(document.activeElement).to.equal(listboxEl._inputNode);
|
||||
expect(isActiveElement(listboxEl._inputNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous checkbox-group', async () => {
|
||||
|
|
@ -348,7 +350,7 @@ describe('<lion-form>', () => {
|
|||
const checkboxGroupEl = el.formElements[0];
|
||||
const checkboxEl = checkboxGroupEl.formElements[0];
|
||||
button.click();
|
||||
expect(document.activeElement).to.equal(checkboxEl._focusableNode);
|
||||
expect(isActiveElement(checkboxEl._focusableNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous radio-group', async () => {
|
||||
|
|
@ -370,6 +372,6 @@ describe('<lion-form>', () => {
|
|||
const radioGroupEl = el.formElements[0];
|
||||
const radioEl = radioGroupEl.formElements[0];
|
||||
button.click();
|
||||
expect(document.activeElement).to.equal(radioEl._focusableNode);
|
||||
expect(isActiveElement(radioEl._focusableNode)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* and contains several bugs on IE11.
|
||||
*/
|
||||
|
||||
import { getDeepActiveElement } from './get-deep-active-element.js';
|
||||
import { getDeepActiveElement } from '../../../core/src/getDeepActiveElement.js';
|
||||
import { getFocusableElements } from './get-focusable-elements.js';
|
||||
import { deepContains } from './deep-contains.js';
|
||||
import { keyCodes } from './key-codes.js';
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
html,
|
||||
} from '@open-wc/testing';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
import { createShadowHost } from '../test-helpers/createShadowHost.js';
|
||||
import { _adoptStyleUtils } from '../src/utils/adopt-styles.js';
|
||||
import { simulateTab } from '../src/utils/simulate-tab.js';
|
||||
|
|
@ -574,7 +575,8 @@ describe('OverlayController', () => {
|
|||
trapsKeyboardFocus: true,
|
||||
});
|
||||
await ctrl.show();
|
||||
expect(ctrl.contentNode).to.equal(document.activeElement);
|
||||
|
||||
expect(isActiveElement(ctrl.contentNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('keeps focus within the overlay e.g. you can not tab out by accident', async () => {
|
||||
|
|
@ -1139,10 +1141,10 @@ describe('OverlayController', () => {
|
|||
await ctrl.show();
|
||||
const input = /** @type {HTMLInputElement} */ (contentNode.querySelector('input'));
|
||||
input.focus();
|
||||
expect(document.activeElement).to.equal(input);
|
||||
expect(isActiveElement(input)).to.be.true;
|
||||
|
||||
await ctrl.hide();
|
||||
expect(document.activeElement).to.equal(document.body);
|
||||
expect(isActiveElement(document.body)).to.be.true;
|
||||
});
|
||||
|
||||
it('supports elementToFocusAfterHide option to focus it when hiding', async () => {
|
||||
|
|
@ -1159,10 +1161,10 @@ describe('OverlayController', () => {
|
|||
await ctrl.show();
|
||||
const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
|
||||
textarea.focus();
|
||||
expect(document.activeElement).to.equal(textarea);
|
||||
expect(isActiveElement(textarea)).to.be.true;
|
||||
|
||||
await ctrl.hide();
|
||||
expect(document.activeElement).to.equal(input);
|
||||
expect(isActiveElement(input)).to.be.true;
|
||||
expect(isInViewport(input)).to.be.true;
|
||||
});
|
||||
|
||||
|
|
@ -1187,10 +1189,10 @@ describe('OverlayController', () => {
|
|||
await ctrl.show();
|
||||
const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
|
||||
textarea.focus();
|
||||
expect(document.activeElement).to.equal(textarea);
|
||||
expect(isActiveElement(textarea)).to.be.true;
|
||||
|
||||
await ctrl.hide();
|
||||
expect(document.activeElement).to.equal(input);
|
||||
expect(isActiveElement(input)).to.be.true;
|
||||
|
||||
document.body.removeChild(shadowHost);
|
||||
});
|
||||
|
|
@ -1208,10 +1210,10 @@ describe('OverlayController', () => {
|
|||
await ctrl.show();
|
||||
// an outside element has taken over focus
|
||||
outsideButton.focus();
|
||||
expect(document.activeElement).to.equal(outsideButton);
|
||||
expect(isActiveElement(outsideButton)).to.be.true;
|
||||
|
||||
await ctrl.hide();
|
||||
expect(document.activeElement).to.equal(outsideButton);
|
||||
expect(isActiveElement(outsideButton)).to.be.true;
|
||||
});
|
||||
|
||||
it('allows to set elementToFocusAfterHide on show', async () => {
|
||||
|
|
@ -1230,10 +1232,10 @@ describe('OverlayController', () => {
|
|||
await ctrl.show(input);
|
||||
const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
|
||||
textarea.focus();
|
||||
expect(document.activeElement).to.equal(textarea);
|
||||
expect(isActiveElement(textarea)).to.be.true;
|
||||
|
||||
await ctrl.hide();
|
||||
expect(document.activeElement).to.equal(input);
|
||||
expect(isActiveElement(input)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
/* eslint-disable lit-a11y/no-autofocus */
|
||||
import { expect, fixture, nextFrame } from '@open-wc/testing';
|
||||
import { html } from 'lit/static-html.js';
|
||||
import { getFocusableElements } from '@lion/ui/overlays.js';
|
||||
import { renderLitAsNode } from '@lion/ui/helpers.js';
|
||||
import { getDeepActiveElement, getFocusableElements } from '@lion/ui/overlays.js';
|
||||
import { html } from 'lit/static-html.js';
|
||||
|
||||
import { keyCodes } from '../../src/utils/key-codes.js';
|
||||
import { isActiveElement } from '../../../core/test-helpers/isActiveElement.js';
|
||||
import { containFocus } from '../../src/utils/contain-focus.js';
|
||||
import { keyCodes } from '../../src/utils/key-codes.js';
|
||||
|
||||
function simulateTabWithinContainFocus() {
|
||||
const event = new CustomEvent('keydown', { detail: 0, bubbles: true });
|
||||
|
|
@ -87,7 +88,7 @@ describe('containFocus()', () => {
|
|||
const root = /** @type {HTMLElement} */ (document.getElementById('rootElement'));
|
||||
const { disconnect } = containFocus(root);
|
||||
|
||||
expect(getDeepActiveElement()).to.equal(root);
|
||||
expect(isActiveElement(root, { deep: true })).to.be.true;
|
||||
expect(root.getAttribute('tabindex')).to.equal('-1');
|
||||
expect(root.style.getPropertyValue('outline-style')).to.equal('none');
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ describe('containFocus()', () => {
|
|||
const el = /** @type {HTMLElement} */ (document.querySelector('input[autofocus]'));
|
||||
const { disconnect } = containFocus(el);
|
||||
|
||||
expect(getDeepActiveElement()).to.equal(el);
|
||||
expect(isActiveElement(el, { deep: true })).to.be.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -113,7 +114,7 @@ describe('containFocus()', () => {
|
|||
/** @type {HTMLElement} */ (document.getElementById('outside-1')).focus();
|
||||
|
||||
simulateTabWithinContainFocus();
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[0]);
|
||||
expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -127,7 +128,7 @@ describe('containFocus()', () => {
|
|||
focusableElements[focusableElements.length - 1].focus();
|
||||
|
||||
simulateTabWithinContainFocus();
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[0]);
|
||||
expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -146,7 +147,7 @@ describe('containFocus()', () => {
|
|||
* actual tab key press. So the best we can do is if we didn't redirect focus
|
||||
* to the first element.
|
||||
*/
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[2]);
|
||||
expect(isActiveElement(focusableElements[2], { deep: true })).to.be.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -158,9 +159,10 @@ describe('containFocus()', () => {
|
|||
const { disconnect } = containFocus(root);
|
||||
|
||||
focusableElements[2].focus();
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[2]);
|
||||
expect(isActiveElement(focusableElements[2], { deep: true })).to.be.true;
|
||||
|
||||
document.body.click(); // this does not cause focusout event :( doesn't seem possible to mock
|
||||
expect(getDeepActiveElement()).to.equal(root);
|
||||
expect(isActiveElement(root, { deep: true })).to.be.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -185,11 +187,12 @@ describe('containFocus()', () => {
|
|||
|
||||
// Simulate tab in window
|
||||
simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-1')));
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[0]);
|
||||
expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
|
||||
|
||||
// Simulate shift+tab in window
|
||||
simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-2')));
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[focusableElements.length - 1]);
|
||||
expect(isActiveElement(focusableElements[focusableElements.length - 1], { deep: true })).to.be
|
||||
.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -202,11 +205,12 @@ describe('containFocus()', () => {
|
|||
|
||||
// Simulate tab in window
|
||||
simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-1')));
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[0]);
|
||||
expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
|
||||
|
||||
// Simulate shift+tab in window
|
||||
simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-2')));
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[focusableElements.length - 1]);
|
||||
expect(isActiveElement(focusableElements[focusableElements.length - 1], { deep: true })).to.be
|
||||
.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
@ -219,11 +223,12 @@ describe('containFocus()', () => {
|
|||
|
||||
// Simulate tab in window
|
||||
simulateTabInWindow(focusableElements[0]);
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[0]);
|
||||
expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
|
||||
|
||||
// Simulate shift+tab in window
|
||||
simulateTabInWindow(focusableElements[focusableElements.length - 1]);
|
||||
expect(getDeepActiveElement()).to.equal(focusableElements[focusableElements.length - 1]);
|
||||
expect(isActiveElement(focusableElements[focusableElements.length - 1], { deep: true })).to.be
|
||||
.true;
|
||||
|
||||
disconnect();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,30 +1,28 @@
|
|||
import { LitElement } from 'lit';
|
||||
import { LionOption } from '@lion/ui/listbox.js';
|
||||
import { OverlayController } from '@lion/ui/overlays.js';
|
||||
import { mimicClick } from '@lion/ui/overlays-test-helpers.js';
|
||||
import { LionSelectInvoker, LionSelectRich } from '@lion/ui/select-rich.js';
|
||||
|
||||
import '@lion/ui/define/lion-option.js';
|
||||
import '@lion/ui/define/lion-listbox.js';
|
||||
import { getSelectRichMembers } from '@lion/ui/select-rich-test-helpers.js';
|
||||
import { mimicClick } from '@lion/ui/overlays-test-helpers.js';
|
||||
import { OverlayController } from '@lion/ui/overlays.js';
|
||||
import { LionOption } from '@lion/ui/listbox.js';
|
||||
import '@lion/ui/define/lion-select-rich.js';
|
||||
import '@lion/ui/define/lion-listbox.js';
|
||||
import '@lion/ui/define/lion-option.js';
|
||||
import { LitElement } from 'lit';
|
||||
import {
|
||||
fixture as _fixture,
|
||||
unsafeStatic,
|
||||
nextFrame,
|
||||
aTimeout,
|
||||
defineCE,
|
||||
expect,
|
||||
fixture as _fixture,
|
||||
html,
|
||||
nextFrame,
|
||||
unsafeStatic,
|
||||
} from '@open-wc/testing';
|
||||
import { getSelectRichMembers } from '@lion/ui/select-rich-test-helpers.js';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../../listbox/src/LionOptions.js').LionOptions} LionOptions
|
||||
* @typedef {import('../../listbox/types/ListboxMixinTypes.js').ListboxHost} ListboxHost
|
||||
* @typedef {import('../../form-core/types/FormControlMixinTypes.js').FormControlHost} FormControlHost
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import('../../listbox/types/ListboxMixinTypes.js').ListboxHost} ListboxHost
|
||||
* @typedef {import('../../listbox/src/LionOptions.js').LionOptions} LionOptions
|
||||
* @typedef {import('lit').TemplateResult} TemplateResult
|
||||
*/
|
||||
|
||||
|
|
@ -478,7 +476,7 @@ describe('lion-select-rich', () => {
|
|||
|
||||
el.opened = true;
|
||||
await el.updateComplete;
|
||||
expect(document.activeElement).to.equal(_listboxNode);
|
||||
expect(isActiveElement(_listboxNode)).to.be.true;
|
||||
|
||||
el.opened = false;
|
||||
await el.updateComplete;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
|
||||
import { expect, fixture as _fixture } from '@open-wc/testing';
|
||||
import { html } from 'lit/static-html.js';
|
||||
import sinon from 'sinon';
|
||||
import { Validator } from '@lion/ui/form-core.js';
|
||||
import { LionSwitch } from '@lion/ui/switch.js';
|
||||
import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
|
||||
|
||||
import { html } from 'lit/static-html.js';
|
||||
import '@lion/ui/define/lion-switch.js';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../src/LionSwitchButton.js').LionSwitchButton} LionSwitchButton
|
||||
* @typedef {import('lit').TemplateResult} TemplateResult
|
||||
* @typedef {import('@lion/ui/types/form-core.js').FormControlHost} FormControlHost
|
||||
* @typedef {import('lit').TemplateResult} TemplateResult
|
||||
*/
|
||||
|
||||
const IsTrue = class extends Validator {
|
||||
|
|
@ -60,7 +61,7 @@ describe('lion-switch', () => {
|
|||
const { _inputNode, _labelNode } = getSwitchMembers(el);
|
||||
|
||||
_labelNode.click();
|
||||
expect(document.activeElement).to.equal(_inputNode);
|
||||
expect(isActiveElement(_inputNode)).to.be.true;
|
||||
});
|
||||
|
||||
it('clicking the label should not focus the toggle button when disabled', async () => {
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@ export { withTooltipConfig } from '../components/overlays/src/configurations/wit
|
|||
|
||||
export { containFocus, rotateFocus } from '../components/overlays/src/utils/contain-focus.js';
|
||||
export { deepContains } from '../components/overlays/src/utils/deep-contains.js';
|
||||
export { getDeepActiveElement } from '../components/overlays/src/utils/get-deep-active-element.js';
|
||||
// re-export via this entrypoint for backwards compatibility
|
||||
export { getDeepActiveElement } from '../components/core/src/getDeepActiveElement.js';
|
||||
export { getFocusableElements } from '../components/overlays/src/utils/get-focusable-elements.js';
|
||||
export {
|
||||
setSiblingsInert,
|
||||
unsetSiblingsInert,
|
||||
setSiblingsInert,
|
||||
} from '../components/overlays/src/utils/inert-siblings.js';
|
||||
|
||||
export { overlays } from '../components/overlays/src/singleton.js';
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ const groups = (
|
|||
await optimisedGlob(['packages/*/test', 'packages/ui/components/**/test'], {
|
||||
onlyDirectories: true,
|
||||
})
|
||||
).map(dir => ({ name: dir.split('/').at(-2), files: `${dir}/**/*.test.js` }));
|
||||
) // @ts-expect-error [update-es-version-later]
|
||||
.map(dir => ({ name: dir.split('/').at(-2), files: `${dir}/**/*.test.js` })); // .filter(({name}) => name === 'overlays');
|
||||
|
||||
/**
|
||||
* @type {import('@web/test-runner').TestRunnerConfig['testRunnerHtml']}
|
||||
|
|
|
|||
Loading…
Reference in a new issue