From 16a63a16b39c6251e4e3748008dea21b2f55b8d1 Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Tue, 12 Mar 2024 01:56:09 +0100 Subject: [PATCH 1/2] Playwright e2e test for taborder This should be a failing test for Firefox (but working in Chrome?) for the taborder in the explore page. Tabbing through the page should ensure that certain elements are focused at least once. --- tests/e2e/explore.test.e2e.js | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/e2e/explore.test.e2e.js diff --git a/tests/e2e/explore.test.e2e.js b/tests/e2e/explore.test.e2e.js new file mode 100644 index 000000000..f486a3cb5 --- /dev/null +++ b/tests/e2e/explore.test.e2e.js @@ -0,0 +1,39 @@ +// @ts-check +// document is a global in evaluate, so it's safe to ignore here +/* eslint no-undef: 0 */ +import {test, expect} from '@playwright/test'; + +test('Explore view taborder', async ({page}) => { + await page.goto('/explore/repos'); + + const l1 = page.locator('[href="https://forgejo.org"]'); + const l2 = page.locator('[href="/assets/licenses.txt"]'); + const l3 = page.locator('[href*="/stars"]').first(); + const l4 = page.locator('[href*="/forks"]').first(); + let res = 0; + const exp = 15; // 0b1111 = four passing tests + + for (let i = 0; i < 150; i++) { + await page.keyboard.press('Tab'); + if (await l1.evaluate((node) => document.activeElement === node)) { + res |= 1; + continue; + } + if (await l2.evaluate((node) => document.activeElement === node)) { + res |= 1 << 1; + continue; + } + if (await l3.evaluate((node) => document.activeElement === node)) { + res |= 1 << 2; + continue; + } + if (await l4.evaluate((node) => document.activeElement === node)) { + res |= 1 << 3; + continue; + } + if (res === exp) { + break; + } + } + await expect(res).toBe(exp); +}); From 7dc453bb398a63597bfa5f65b7a4c2ea45fc9e09 Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Tue, 12 Mar 2024 02:03:30 +0100 Subject: [PATCH 2/2] Remove inputs in dropdowns from taborder Inputs are normally present in the taborder of a website. When they are inside a dropdown, this means a user could theoretically also tab through them. With the current dropdown approach, however, this can result in the focus being trapped, because the dropdown is closed after the focus switches to the next element. In this case, the focus moves to the end of the page, breaking keyword navigation and making parts of the page inaccessible with a keyboard. I was only able to reproduce this in Firefox. This patch removes inputs inside dropdowns from taborder. It should be generally safe even with potential side-effects, because *nothing* inside dropdowns should be in the tab order. This is a hotfix for https://codeberg.org/forgejo/forgejo/issues/2635, but I acknowledge it is not an ideal solution. --- web_src/js/modules/fomantic/dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/js/modules/fomantic/dropdown.js b/web_src/js/modules/fomantic/dropdown.js index c053256dd..36b2b4ca0 100644 --- a/web_src/js/modules/fomantic/dropdown.js +++ b/web_src/js/modules/fomantic/dropdown.js @@ -39,6 +39,7 @@ function updateMenuItem(dropdown, item) { item.setAttribute('role', dropdown[ariaPatchKey].listItemRole); item.setAttribute('tabindex', '-1'); for (const a of item.querySelectorAll('a')) a.setAttribute('tabindex', '-1'); + for (const input of item.querySelectorAll('input')) input.setAttribute('tabindex', '-1'); } // make the label item and its "delete icon" has correct aria attributes