-
Notifications
You must be signed in to change notification settings - Fork 9.7k
feat: Add a11y regression scan suite #13663
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
viktoravelino
merged 17 commits into
feat/a11y
from
feat/a11y-playwright-regression-suite
Jun 16, 2026
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
8c2f79a
test: add component a11y unit tests (jest-axe)
viktoravelino a9f03a3
ci: split a11y unit tests into separate workflow
viktoravelino 8aa5c36
fix(a11y): resolve component gaps flagged by a11y unit tests
viktoravelino c5cf324
Merge branch 'feat/a11y' into feat/a11y-unit-tests
viktoravelino 03423f8
Merge branch 'feat/a11y' into feat/a11y-unit-tests
viktoravelino 388da0c
fix: skip Puppeteer Chrome download in remaining Dockerfiles
viktoravelino 9b688c7
test: extend a11y unit test coverage (jest-axe)
viktoravelino 30bde9d
fix: make webhook copy field a real button (a11y)
viktoravelino 857ed55
Merge branch 'feat/a11y' into feat/a11y-unit-tests
viktoravelino 9138e25
feat: update a11y unit tests and improve accessibility semantics in c…
viktoravelino ada48b2
feat: enable pull request trigger for a11y scan workflow
viktoravelino 160ec8b
Merge branch 'feat/a11y' into feat/a11y-unit-tests
viktoravelino 55e67e5
test: add a11y regression scan suite
viktoravelino f3e41cf
test: make a11y scans non-blocking
viktoravelino 3618b16
Merge branch 'feat/a11y' into feat/a11y-playwright-regression-suite
viktoravelino 958ebf0
test: discover a11y scan specs
viktoravelino 34313d7
ci: group a11y workflow checks
viktoravelino File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| import { expect, type LangflowPage, test } from "../fixtures"; | ||
| import { adjustScreenView } from "../utils/adjust-screen-view"; | ||
| import { TID } from "../utils/constants/testIds"; | ||
| import { TEXTS } from "../utils/constants/texts"; | ||
| import { TIMEOUTS } from "../utils/constants/timeouts"; | ||
| import { addComponentFromSidebar } from "../utils/flow/add-component-from-sidebar"; | ||
|
|
||
| async function disableAnimations(page: LangflowPage) { | ||
| await page.addStyleTag({ | ||
| content: ` | ||
| *, | ||
| *::before, | ||
| *::after { | ||
| animation-duration: 0s !important; | ||
| animation-delay: 0s !important; | ||
| transition-duration: 0s !important; | ||
| transition-delay: 0s !important; | ||
| scroll-behavior: auto !important; | ||
| } | ||
| `, | ||
| }); | ||
| } | ||
|
|
||
| async function hideComponentSidebar(page: LangflowPage) { | ||
| const style = await page.addStyleTag({ | ||
| content: '[data-testid="shad-sidebar"] { display: none !important; }', | ||
| }); | ||
| await expect(page.getByTestId("shad-sidebar")).toBeHidden(); | ||
| return style; | ||
| } | ||
|
|
||
| async function openBlankFlowForA11y(page: LangflowPage) { | ||
| await page.goto("/"); | ||
| await expect(page.getByTestId(TID.mainpageTitle)).toBeVisible({ | ||
| timeout: TIMEOUTS.standard, | ||
| }); | ||
|
|
||
| const emptyPageButton = page.getByTestId(TID.newProjectBtnEmptyPage); | ||
| if (await emptyPageButton.isVisible()) { | ||
| await emptyPageButton.click(); | ||
| } else { | ||
| await page.getByTestId(TID.newProjectBtn).click(); | ||
| } | ||
|
|
||
| const welcomePanel = page.getByTestId("flow-builder-welcome-panel"); | ||
| const modalTitle = page.getByTestId(TID.modalTitle); | ||
| await expect(welcomePanel.or(modalTitle)).toBeVisible({ | ||
| timeout: TIMEOUTS.standard, | ||
| }); | ||
|
|
||
| if (await welcomePanel.isVisible()) { | ||
| await page.getByTestId("flow-builder-welcome-browse-more").click(); | ||
| } | ||
|
|
||
| await expect(page.getByTestId(TID.blankFlow)).toBeVisible({ | ||
| timeout: TIMEOUTS.standard, | ||
| }); | ||
| await page.getByTestId(TID.blankFlow).click(); | ||
| } | ||
|
|
||
| test.describe("core application accessibility", () => { | ||
| test.describe.configure({ mode: "serial" }); | ||
|
|
||
| test( | ||
| "scans flow creation and playground states", | ||
| { tag: ["@a11y", "@workspace"] }, | ||
| async ({ page }) => { | ||
| await openBlankFlowForA11y(page); | ||
| await disableAnimations(page); | ||
| await expect(page.getByTestId(TID.sidebarSearchInput)).toBeVisible(); | ||
| const emptyCanvasSidebarStyle = await hideComponentSidebar(page); | ||
|
|
||
| await page.runA11yScan("flow-canvas-empty"); | ||
|
|
||
| await emptyCanvasSidebarStyle.evaluate((style) => style.remove()); | ||
| await expect(page.getByTestId(TID.sidebarSearchInput)).toBeVisible(); | ||
| await addComponentFromSidebar(page, { | ||
| search: TEXTS.searchChatOutput, | ||
| testId: "input_outputChat Output", | ||
| hoverAdd: true, | ||
| }); | ||
| await addComponentFromSidebar(page, { | ||
| search: TEXTS.searchChatInput, | ||
| testId: "input_outputChat Input", | ||
| position: { x: 100, y: 100 }, | ||
| }); | ||
| await adjustScreenView(page); | ||
| await hideComponentSidebar(page); | ||
|
|
||
| await page | ||
| .getByTestId("handle-chatinput-noshownode-chat message-source") | ||
| .click(); | ||
| await page | ||
| .getByTestId("handle-chatoutput-noshownode-inputs-target") | ||
| .click(); | ||
|
|
||
| await page.runA11yScan("flow-canvas-populated"); | ||
|
|
||
| await page.getByTestId("title-Chat Input").click(); | ||
| await expect(page.getByTestId(TID.editFieldsButton)).toBeVisible(); | ||
| await page.getByTestId(TID.editFieldsButton).click(); | ||
| await expect(page.getByTestId("showinput_value")).toBeVisible(); | ||
|
|
||
| await page.runA11yScan("component-configuration"); | ||
|
|
||
| await page.getByTestId(TID.editFieldsButton).click(); | ||
| await page | ||
| .getByRole("button", { name: TEXTS.playground, exact: true }) | ||
| .click(); | ||
| await expect(page.getByTestId(TID.inputChatPlayground)).toBeVisible({ | ||
| timeout: TIMEOUTS.componentMount, | ||
| }); | ||
|
|
||
| await page.runA11yScan("playground-empty"); | ||
|
|
||
| await page | ||
| .getByTestId(TID.inputChatPlayground) | ||
| .fill("Accessibility test"); | ||
| await page.getByTestId(TID.buttonSend).first().click(); | ||
| await expect(page.getByTestId(TID.chatMessage)).toHaveText( | ||
| "Accessibility test", | ||
| { timeout: TIMEOUTS.componentMount }, | ||
| ); | ||
|
|
||
| await page.runA11yScan("playground-with-message"); | ||
| }, | ||
| ); | ||
|
|
||
| test( | ||
| "scans flows landing page", | ||
| { tag: ["@a11y", "@workspace"] }, | ||
| async ({ page }) => { | ||
| await page.goto("/flows"); | ||
| await disableAnimations(page); | ||
| await expect(page.getByTestId(TID.mainpageTitle)).toBeVisible({ | ||
| timeout: TIMEOUTS.standard, | ||
| }); | ||
|
|
||
| await page.runA11yScan("flows-landing"); | ||
| }, | ||
| ); | ||
|
|
||
| test( | ||
| "scans general settings", | ||
| { tag: ["@a11y", "@workspace"] }, | ||
| async ({ page }) => { | ||
| await page.goto("/settings/general"); | ||
| await disableAnimations(page); | ||
| await expect(page.getByTestId(TID.settingsMenuHeader)).toBeVisible({ | ||
| timeout: TIMEOUTS.standard, | ||
| }); | ||
|
|
||
| await page.runA11yScan("settings-general"); | ||
| }, | ||
| ); | ||
|
|
||
| test( | ||
| "scans files page", | ||
| { tag: ["@a11y", "@workspace"] }, | ||
| async ({ page }) => { | ||
| await page.goto("/assets/files"); | ||
| await disableAnimations(page); | ||
| await expect(page.getByTestId(TID.mainpageTitle)).toContainText("Files", { | ||
| timeout: TIMEOUTS.standard, | ||
| }); | ||
| await expect(page.getByTestId("upload-file-btn")).toBeVisible(); | ||
|
|
||
| await page.runA11yScan("files-page"); | ||
| }, | ||
| ); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.