diff --git a/packages/picker/src/Picker.ts b/packages/picker/src/Picker.ts
index e324f5ae88..8dc018b98e 100644
--- a/packages/picker/src/Picker.ts
+++ b/packages/picker/src/Picker.ts
@@ -271,10 +271,15 @@ export class PickerBase extends SizedMixin(Focusable) {
return;
}
- this.restoreChildren = reparentChildren(
- reparentableChildren,
- this.optionsMenu
- );
+ this.restoreChildren = reparentChildren<
+ Element & { focused?: boolean }
+ >(reparentableChildren, this.optionsMenu, () => {
+ return (el) => {
+ if (typeof el.focused !== 'undefined') {
+ el.focused = false;
+ }
+ };
+ });
this.optionsMenu.selectable = true;
diff --git a/packages/picker/test/picker.test.ts b/packages/picker/test/picker.test.ts
index 48b8a821e0..17216f282d 100644
--- a/packages/picker/test/picker.test.ts
+++ b/packages/picker/test/picker.test.ts
@@ -27,6 +27,7 @@ import {
expect,
waitUntil,
nextFrame,
+ oneEvent,
} from '@open-wc/testing';
import '@spectrum-web-components/shared/src/focus-visible.js';
import { spy } from 'sinon';
@@ -38,7 +39,12 @@ import {
tabEvent,
tEvent,
} from '../../../test/testing-helpers.js';
-import { a11ySnapshot, findAccessibilityNode } from '@web/test-runner-commands';
+import {
+ a11ySnapshot,
+ executeServerCommand,
+ findAccessibilityNode,
+ sendKeys,
+} from '@web/test-runner-commands';
const isMenuActiveElement = function (): boolean {
return document.activeElement instanceof Menu;
@@ -52,7 +58,10 @@ describe('Picker', () => {
Where do you live?
-
+
Deselect
Select Inverse
@@ -177,7 +186,6 @@ describe('Picker', () => {
await elementUpdated(el);
expect(el.value).to.equal('option-new');
});
-
it('manages its "name" value in the accessibility tree', async () => {
const el = await pickerFixture();
@@ -240,11 +248,119 @@ describe('Picker', () => {
await expect(el).to.be.accessible();
});
- it('closes when becoming disabled', async () => {
+ it('opens with visible focus on a menu item on `DownArrow`', async () => {
const el = await pickerFixture();
+ const firstItem = el.querySelector('sp-menu-item') as MenuItem;
+
await elementUpdated(el);
+ expect(firstItem.focused, 'not visually focused').to.be.false;
+
+ el.focus();
+ await elementUpdated(el);
+ const opened = oneEvent(el, 'sp-opened');
+ await sendKeys({
+ press: 'ArrowDown',
+ });
+ await opened;
+
+ expect(el.open).to.be.true;
+ expect(firstItem.focused, 'not visually focused').to.be.true;
+
+ const closed = oneEvent(el, 'sp-closed');
+ await sendKeys({
+ press: 'Escape',
+ });
+ await closed;
+
+ expect(el.open).to.be.false;
+ await waitUntil(() => !firstItem.focused, 'not visually focused');
+ });
+ it('opens without visible focus on a menu item on click', async () => {
+ const el = await pickerFixture();
+
+ /**
+ * Firefox will not accept a single "click" from Playwright as deactivating the
+ * :focus-visible heuristic. So, to trick it, we "click" three times! Once to
+ * open, once to close, and once to open again before taking the operative test
+ * that the first item in the menu is to given the `focused` attribute immediately.
+ */
+
+ const firstItem = el.querySelector('sp-menu-item') as MenuItem;
+
+ await elementUpdated(el);
+ const boundingRect = el.getBoundingClientRect();
+
+ expect(firstItem.focused, 'not visually focused').to.be.false;
+ let opened = oneEvent(el, 'sp-opened');
+ await executeServerCommand('send-mouse', {
+ steps: [
+ {
+ type: 'move',
+ position: [
+ boundingRect.x + boundingRect.width / 2,
+ boundingRect.y + boundingRect.height / 2,
+ ],
+ },
+ {
+ type: 'down',
+ },
+ {
+ type: 'up',
+ },
+ ],
+ });
+ await opened;
+ expect(el.open).to.be.true;
+ const closed = oneEvent(el, 'sp-closed');
+ await executeServerCommand('send-mouse', {
+ steps: [
+ {
+ type: 'move',
+ position: [
+ boundingRect.x + boundingRect.width / 2,
+ boundingRect.y + boundingRect.height / 2,
+ ],
+ },
+ {
+ type: 'down',
+ },
+ {
+ type: 'up',
+ },
+ ],
+ });
+ await closed;
+
+ expect(el.open).to.be.false;
+ opened = oneEvent(el, 'sp-opened');
+ await executeServerCommand('send-mouse', {
+ steps: [
+ {
+ type: 'move',
+ position: [
+ boundingRect.x + boundingRect.width / 2,
+ boundingRect.y + boundingRect.height / 2,
+ ],
+ },
+ {
+ type: 'down',
+ },
+ {
+ type: 'up',
+ },
+ ],
+ });
+ await opened;
+
+ expect(el.open).to.be.true;
+ expect(firstItem.focused, 'still not visually focused').to.be.false;
+ });
+ it('closes when becoming disabled', async () => {
+ const el = await pickerFixture();
+
+ await elementUpdated(el);
expect(el.open).to.be.false;
el.click();
await elementUpdated(el);
diff --git a/web-test-runner.config.js b/web-test-runner.config.js
index 2fd9d6fe8a..142329dd94 100644
--- a/web-test-runner.config.js
+++ b/web-test-runner.config.js
@@ -87,8 +87,6 @@ export default {
playwrightLauncher({
product: 'firefox',
launchOptions: {
- headless: false,
- args: ['-headless'],
firefoxUserPrefs: {
'toolkit.telemetry.reportingpolicy.firstRun': false,
'browser.shell.checkDefaultBrowser': false,