Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e688e94
chore: add accessibility action plan and gap report for IBM Level 1 c…
viktoravelino Jun 9, 2026
2ffd2d1
Merge branch 'release-1.10.0' into feat/a11y
viktoravelino Jun 9, 2026
fa7d541
feat: integrate accessibility checker for automated a11y scans
viktoravelino Jun 9, 2026
c9d45fa
feat: add accessibility test usage documentation for IBM scans
viktoravelino Jun 9, 2026
f188b5b
feat: enhance accessibility testing with JSON report aggregation and …
viktoravelino Jun 10, 2026
170acde
feat: add GitHub Actions workflow for IBM accessibility scans
viktoravelino Jun 10, 2026
6d5ef55
feat: update a11y scan workflow to allow testing from feat/a11y branch
viktoravelino Jun 10, 2026
db8da2a
Merge branch 'release-1.10.0' into feat/a11y
viktoravelino Jun 10, 2026
cd9ab69
feat: skip Puppeteer download during npm install in Dockerfiles for a…
viktoravelino Jun 10, 2026
66318cf
Merge branch 'feat/a11y' of github.com:langflow-ai/langflow into feat…
viktoravelino Jun 10, 2026
583afd0
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 12, 2026
d76e217
feat: enhance a11y scan workflow to resolve and scan latest release b…
viktoravelino Jun 12, 2026
9dbde72
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 15, 2026
3c1b2cd
test: add component a11y unit tests (jest-axe) (#13613)
viktoravelino Jun 15, 2026
287ca4c
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 15, 2026
0007f20
feat: Add a11y regression scan suite (#13663)
viktoravelino Jun 16, 2026
caad567
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 16, 2026
5992048
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 17, 2026
d82723e
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 18, 2026
c49a8db
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 19, 2026
c368ade
fix(a11y): restore focus-visible indicators (#13664)
olayinkaadelakun Jun 22, 2026
d36083e
a11y: improve auth accessibility coverage (#13724)
viktoravelino Jun 22, 2026
6fae209
fix(a11y): add accessible names and hide decorative icons in Langflow…
olayinkaadelakun Jun 22, 2026
5ea9fe6
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 23, 2026
6f7c1f8
fix(a11y): add accessible names to icon-only buttons, fix placeholder…
olayinkaadelakun Jun 24, 2026
f54bbbd
Merge remote-tracking branch 'origin/release-1.11.0' into feat/a11y
viktoravelino Jun 24, 2026
df4857f
fix: update package dependencies and versions in package-lock.json
viktoravelino Jun 24, 2026
168054d
chore: Remove accessibility documentation and reports
viktoravelino Jun 24, 2026
5eaf6f9
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 24, 2026
ab5b9d9
chore: Add accessibility scan reports (#13812)
viktoravelino Jun 25, 2026
04c861f
fix: update Playwright version to 1.60.0 and enhance a11y scan options
viktoravelino Jun 25, 2026
b2432ab
fix(test): keep fixture args destructured
viktoravelino Jun 25, 2026
adb1446
Merge branch 'release-1.11.0' into feat/a11y
viktoravelino Jun 25, 2026
28bb7a8
test(a11y): bootstrap asset route scans
viktoravelino Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions .github/workflows/a11y-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
name: A11y / IBM Equal Access Scans

on:
pull_request:
schedule:
# Run nightly at 02:00 UTC, after the nightly build window
- cron: "0 2 * * *"
Comment thread
viktoravelino marked this conversation as resolved.
workflow_dispatch:
inputs:
ref:
description: "(Optional) ref to checkout"
required: false
type: string
assert:
description: "Fail the run when scans differ from committed baselines"
required: false
type: boolean
default: false

env:
NODE_VERSION: "22"
PYTHON_VERSION: "3.13"
Comment thread
viktoravelino marked this conversation as resolved.
# Define the directory where Playwright browsers will be installed.
# This path is used for caching across workflows
PLAYWRIGHT_BROWSERS_PATH: "ms-playwright"
PLAYWRIGHT_VERSION: "1.59.1"
Comment thread
viktoravelino marked this conversation as resolved.
Outdated

jobs:
a11y-scan:
name: Playwright scan runner
runs-on: ubuntu-latest
permissions:
contents: read
steps:
# Cron only fires from the default branch, so scheduled runs resolve the
# latest release-* branch and scan that (same pattern as nightly_build).
- name: Resolve Ref To Scan
id: resolve_ref
shell: bash
run: |
if [ -n "${{ inputs.ref }}" ]; then
REF="${{ inputs.ref }}"
elif [ "${{ github.event_name }}" = "schedule" ]; then
REF=$(git ls-remote --heads https://github.com/${{ github.repository }} 'refs/heads/release-*' \
| awk '{print $2}' \
| sed 's|refs/heads/||' \
| grep -E '^release-[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -V \
| tail -n 1)
if [ -z "$REF" ]; then
echo "No release-* branch found in ${{ github.repository }}"
exit 1
fi
else
REF="${{ github.ref }}"
fi
echo "ref=$REF" >> "$GITHUB_OUTPUT"
echo "Scanning ref: $REF"

- name: Checkout Repository
uses: actions/checkout@v6
with:
ref: ${{ steps.resolve_ref.outputs.ref }}

- name: Setup Node.js Environment
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}

- name: Get npm cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> "$GITHUB_OUTPUT"

- name: Cache npm dependencies
uses: actions/cache@v5
continue-on-error: true
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-npm-${{ env.NODE_VERSION }}-${{ hashFiles('src/frontend/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-${{ env.NODE_VERSION }}-

- name: Install Frontend Dependencies
run: npm ci
working-directory: ./src/frontend

- name: Cache Playwright Browsers
id: cache-playwright
uses: actions/cache@v5
continue-on-error: true
with:
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
key: playwright-${{ env.PLAYWRIGHT_VERSION }}-chromium-${{ runner.os }}
restore-keys: |
playwright-${{ env.PLAYWRIGHT_VERSION }}-chromium-${{ runner.os }}

- name: Install Playwright Browser Dependencies
if: steps.cache-playwright.outputs.cache-hit != 'true'
shell: bash
run: |
cd ./src/frontend
npx playwright install --with-deps chromium

- name: "Setup Environment"
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
python-version: ${{ env.PYTHON_VERSION }}
prune-cache: false

- name: Install Python Dependencies
run: uv sync

- name: Run IBM Equal Access Scans
shell: bash
env:
RUN_A11Y: "true"
RUN_A11Y_ASSERT: ${{ github.event_name == 'workflow_dispatch' && inputs.assert && 'true' || 'false' }}
LANGFLOW_DEACTIVATE_TRACING: "true"
run: |
cd src/frontend
# Only specs that call runA11yScan produce reports; discover them
# so new scan hosts are picked up without editing this workflow.
SCAN_SPECS=$(grep -rl "runA11yScan(" tests --include="*.spec.ts" | sort)
echo "Specs with a11y scans:"
echo "$SCAN_SPECS"
test -n "$SCAN_SPECS"
npx playwright test $SCAN_SPECS --project=chromium --workers=1 --retries=2

- name: Build IBM Scan Summary
if: always()
shell: bash
run: |
cd src/frontend
if ls coverage/accessibility-reports/*.json > /dev/null 2>&1; then
npm run a11y:report --silent
{
echo '```text'
npm run a11y:report --silent
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
else
echo "No accessibility reports were generated." | tee -a "$GITHUB_STEP_SUMMARY"
fi

- name: Upload Accessibility Reports
if: always()
uses: actions/upload-artifact@v6
with:
name: ibm-a11y-reports-${{ github.run_attempt }}
path: src/frontend/coverage/accessibility-reports
retention-days: 30
overwrite: true
48 changes: 48 additions & 0 deletions .github/workflows/a11y-unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: A11y / Component Unit Tests

on:
pull_request:
paths:
- "src/frontend/**"
- ".github/workflows/a11y-unit-tests.yml"
- "Makefile.frontend"
workflow_call:
inputs:
ref:
description: "(Optional) ref to checkout"
required: false
type: string
workflow_dispatch:
inputs:
ref:
description: "(Optional) ref to checkout"
required: false
type: string

env:
NODE_VERSION: "22"

jobs:
a11y-unit-tests:
name: jest-axe
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}

- name: Setup Node.js Environment
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
cache-dependency-path: ./src/frontend/package-lock.json

# These are regression locks: every a11y unit test passes as of the
# component fixes in feat/a11y-unit-tests, so a failure here means a
# real a11y regression and blocks the PR.
- name: Run jest-axe unit tests
run: make test_frontend_a11y_unit_ci
24 changes: 21 additions & 3 deletions Makefile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
FRONTEND_DIR = src/frontend
NPM = npm

.PHONY: install_frontend install_frontendci install_frontendc frontend_deps_check build_frontend run_frontend frontend frontendc format_frontend tests_frontend test_frontend test_frontend_watch test_frontend_coverage test_frontend_verbose test_frontend_ci test_frontend_clean test_frontend_file test_frontend_pattern test_frontend_snapshots test_frontend_config test_frontend_bail test_frontend_silent test_frontend_coverage_open help_frontend storybook storybook_build storybook_network
.PHONY: install_frontend install_frontendci install_frontendc frontend_deps_check build_frontend run_frontend frontend frontendc format_frontend tests_frontend test_frontend_a11y_scan test_frontend_a11y_scan_blocking test_frontend_a11y_scan_update test_frontend test_frontend_watch test_frontend_coverage test_frontend_verbose test_frontend_ci test_frontend_a11y_unit_ci test_frontend_clean test_frontend_file test_frontend_pattern test_frontend_snapshots test_frontend_config test_frontend_bail test_frontend_silent test_frontend_coverage_open help_frontend storybook storybook_build storybook_network

######################
# FRONTEND DEPENDENCIES
Expand Down Expand Up @@ -77,6 +77,17 @@ else
@cd $(FRONTEND_DIR) && npx playwright test --project=chromium
endif

test_frontend_a11y_scan: frontend_deps_check ## run non-blocking IBM a11y scans with Playwright
@cd $(FRONTEND_DIR) && SCAN_SPECS="$$(grep -rl "runA11yScan(" tests --include="*.spec.ts" | sort)" && echo "Specs with a11y scans:" && echo "$$SCAN_SPECS" && test -n "$$SCAN_SPECS" && RUN_A11Y=true RUN_A11Y_ASSERT=false npx playwright test $$SCAN_SPECS --project=chromium --workers=1

test_frontend_a11y_scan_blocking: frontend_deps_check ## run blocking IBM a11y scans against baselines
@cd $(FRONTEND_DIR) && SCAN_SPECS="$$(grep -rl "runA11yScan(" tests --include="*.spec.ts" | sort)" && echo "Specs with a11y scans:" && echo "$$SCAN_SPECS" && test -n "$$SCAN_SPECS" && RUN_A11Y=true RUN_A11Y_ASSERT=true npx playwright test $$SCAN_SPECS --project=chromium --workers=1

test_frontend_a11y_scan_update: frontend_deps_check ## refresh IBM a11y scan baselines
@cd $(FRONTEND_DIR) && rm -rf coverage/accessibility-reports && SCAN_SPECS="$$(grep -rl "runA11yScan(" tests --include="*.spec.ts" | sort)" && echo "Specs with a11y scans:" && echo "$$SCAN_SPECS" && test -n "$$SCAN_SPECS" && RUN_A11Y=true RUN_A11Y_ASSERT=false npx playwright test $$SCAN_SPECS --project=chromium --workers=1
@mkdir -p $(FRONTEND_DIR)/tests/baselines
@cp $(FRONTEND_DIR)/coverage/accessibility-reports/chromium__*.json $(FRONTEND_DIR)/tests/baselines/

######################
# FRONTEND UNIT TESTS (JEST)
######################
Expand All @@ -102,9 +113,16 @@ test_frontend_verbose: frontend_deps_check ## run frontend tests with verbose ou
@cd $(FRONTEND_DIR) && npx jest --verbose

# Run frontend tests in CI mode (no watch, with coverage)
# Excludes *.a11y.test.* files - those run in their own blocking
# workflow (a11y-unit-tests.yml).
test_frontend_ci: frontend_deps_check ## run frontend tests in CI mode
@echo "Running frontend tests in CI mode..."
@cd $(FRONTEND_DIR) && CI=true npx jest --ci --coverage --watchAll=false
@cd $(FRONTEND_DIR) && CI=true npx jest --ci --coverage --watchAll=false --testPathIgnorePatterns="/node_modules/" "test-utils.tsx" "\.a11y\.test\."

# Run only the a11y component tests (jest-axe)
test_frontend_a11y_unit_ci: frontend_deps_check ## run Jest axe unit tests in CI mode
@echo "Running Jest axe unit tests in CI mode..."
@cd $(FRONTEND_DIR) && CI=true npx jest --ci --watchAll=false --testPathPatterns="\.a11y\.test\."

# Clean test cache and run tests
test_frontend_clean: frontend_deps_check ## clean test cache and run tests
Expand Down Expand Up @@ -268,4 +286,4 @@ help_frontend: ## show frontend help
@echo " $(GREEN)make storybook_network$(NC) - Run Storybook accessible on network"
@echo ''
@echo "$(GREEN)═══════════════════════════════════════════════════════════════════$(NC)"
@echo ''
@echo ''
5 changes: 4 additions & 1 deletion docker/build_and_push.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ COPY ./src /app/src

COPY src/frontend /tmp/src/frontend
WORKDIR /tmp/src/frontend
# PUPPETEER_SKIP_DOWNLOAD: puppeteer (via accessibility-checker, test-only)
# must not download Chrome here - the builder image lacks unzip and the
# production image never runs it.
RUN --mount=type=cache,target=/root/.npm \
npm ci \
PUPPETEER_SKIP_DOWNLOAD=true npm ci \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/langflow/frontend \
&& rm -rf /tmp/src/frontend
Expand Down
5 changes: 4 additions & 1 deletion docker/build_and_push_base.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ COPY src/frontend /tmp/src/frontend
WORKDIR /tmp/src/frontend
# Increase memory and disable concurrent builds to avoid esbuild crashes on emulated architectures
# Force esbuild to use JS implementation on emulated architectures to avoid native binary crashes
RUN npm install \
# PUPPETEER_SKIP_DOWNLOAD: puppeteer (via accessibility-checker, test-only)
# must not download Chrome here - the build env can't fetch it and the
# production image never runs it.
RUN PUPPETEER_SKIP_DOWNLOAD=true npm install \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/base/langflow/frontend \
&& rm -rf /tmp/src/frontend
Expand Down
5 changes: 4 additions & 1 deletion docker/build_and_push_ep.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ COPY ./src /app/src

COPY src/frontend /tmp/src/frontend
WORKDIR /tmp/src/frontend
# PUPPETEER_SKIP_DOWNLOAD: puppeteer (via accessibility-checker, test-only)
# must not download Chrome here - the builder image lacks unzip and the
# production image never runs it.
RUN --mount=type=cache,target=/root/.npm \
npm ci \
PUPPETEER_SKIP_DOWNLOAD=true npm ci \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/langflow/frontend \
&& rm -rf /tmp/src/frontend
Expand Down
5 changes: 4 additions & 1 deletion docker/build_and_push_with_extras.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ COPY ./src /app/src

COPY src/frontend /tmp/src/frontend
WORKDIR /tmp/src/frontend
# PUPPETEER_SKIP_DOWNLOAD: puppeteer (via accessibility-checker, test-only)
# must not download Chrome here - the builder image lacks unzip and the
# production image never runs it.
RUN --mount=type=cache,target=/root/.npm \
npm ci \
PUPPETEER_SKIP_DOWNLOAD=true npm ci \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/langflow/frontend \
&& rm -rf /tmp/src/frontend
Expand Down
5 changes: 4 additions & 1 deletion docker/frontend/build_and_push_frontend.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
FROM --platform=$BUILDPLATFORM node:lts-bookworm-slim AS builder-base
COPY src/frontend /frontend

RUN cd /frontend && npm install && npm run build
# PUPPETEER_SKIP_DOWNLOAD: puppeteer (via accessibility-checker, test-only)
# must not download Chrome here - the build env can't fetch it and the
# production image never runs it.
RUN cd /frontend && PUPPETEER_SKIP_DOWNLOAD=true npm install && npm run build

################################
# RUNTIME
Expand Down
15 changes: 15 additions & 0 deletions src/frontend/.achecker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ruleArchive: 19May2026
policies:
- IBM_Accessibility
reportLevels:
- violation
# - potentialviolation
# - recommendation
# - potentialrecommendation
# - manual
outputFormat:
- html
- json
outputFilenameTimestamp: false
baselineFolder: tests/baselines
outputFolder: coverage/accessibility-reports
Loading
Loading