Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
385b804
feat: accessibility_tests_with_axe
Utkarsh-0304 Jan 3, 2026
41f3a38
fix: coderabbit_suggestions
Utkarsh-0304 Jan 3, 2026
decbe07
Merge branch 'main' into feat/accessibility_tests
Utkarsh-0304 Jan 3, 2026
bfc36aa
Merge branch 'main' of https://github.com/OWASP/Nest into feat/access…
Utkarsh-0304 Jan 5, 2026
1fce7ce
Merge branch 'feat/accessibility_tests' of https://github.com/Utkarsh…
Utkarsh-0304 Jan 5, 2026
b9c632b
fix: sonarqube_and_coderabbit_suggestions
Utkarsh-0304 Jan 5, 2026
75d220c
fix: code_suggestions
Utkarsh-0304 Jan 5, 2026
ee96230
fix: more dynamic tests cases for handling conditional rendering and …
Utkarsh-0304 Jan 6, 2026
00fc121
Merge branch 'main' into feat/accessibility_tests
Utkarsh-0304 Jan 6, 2026
e8ade76
fix: minor_coderabbit_fixes
Utkarsh-0304 Jan 6, 2026
c3a5b92
Merge branch 'feat/accessibility_tests' of https://github.com/Utkarsh…
Utkarsh-0304 Jan 6, 2026
3edde1a
Merge branch 'main' into feat/accessibility_tests
Utkarsh-0304 Jan 7, 2026
f2a8d1c
feat: add automated ci accessibility tests workflow script
Utkarsh-0304 Jan 7, 2026
d95b1b7
fix: run make check
Utkarsh-0304 Jan 7, 2026
50ecdd7
fix: standardise mock for next/link module
Utkarsh-0304 Jan 8, 2026
51c8d4d
Merge branch 'main' of https://github.com/OWASP/Nest into feat/access…
Utkarsh-0304 Jan 8, 2026
9388e3f
fix: distinct testid for multiple links in itemCardList component
Utkarsh-0304 Jan 8, 2026
6786f6e
fix: handle conditional rendering problems and remove redundant data-…
Utkarsh-0304 Jan 9, 2026
99c04f6
Merge branch 'main' of https://github.com/OWASP/Nest into feat/access…
Utkarsh-0304 Jan 9, 2026
fc5e848
fix: remove redundant mocks and typos
Utkarsh-0304 Jan 9, 2026
4c992c9
fix: remove multiple react imports
Utkarsh-0304 Jan 9, 2026
686703c
fix: return mock map object from useMap() instead of null
Utkarsh-0304 Jan 9, 2026
c237ce4
fix: active chapter count in mock chapter data
Utkarsh-0304 Jan 9, 2026
b55541d
Merge branch 'main' of https://github.com/OWASP/Nest into feat/access…
Utkarsh-0304 Jan 11, 2026
a691e5e
Merge branch 'main' into pr/Utkarsh-0304/3162
arkid15r Jan 11, 2026
f2c5357
Update code
arkid15r Jan 11, 2026
40e8088
Merge branch 'feat/accessibility_tests' of https://github.com/Utkarsh…
Utkarsh-0304 Jan 12, 2026
6779c17
Merge branch 'main' of https://github.com/OWASP/Nest into feat/access…
Utkarsh-0304 Jan 12, 2026
4f6878e
fix: move mock data to __tests__, refactor imports and update needs i…
Utkarsh-0304 Jan 12, 2026
765deff
Merge branch 'main' into feat/accessibility_tests
Utkarsh-0304 Jan 12, 2026
b51cd05
fix: minor spacing issue in workflow file
Utkarsh-0304 Jan 12, 2026
962c62c
Merge branch 'main' of https://github.com/OWASP/Nest into feat/access…
Utkarsh-0304 Jan 12, 2026
5fed933
Merge branch 'feat/accessibility_tests' of https://github.com/Utkarsh…
Utkarsh-0304 Jan 12, 2026
840477f
Merge branch 'main' into feat/accessibility_tests
Utkarsh-0304 Jan 13, 2026
16ac56f
Merge branch 'main' of github.com:OWASP/Nest into pr/Utkarsh-0304/3162
kasya Jan 13, 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
36 changes: 36 additions & 0 deletions .github/workflows/run-ci-cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,40 @@ jobs:
docker run --env-file frontend/.env.example owasp/nest:test-frontend-e2e-latest pnpm run test:e2e
timeout-minutes: 10

run-frontend-a11y-tests:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add it to needs for build-staging-images in this file (L302) and probably to build-production-images as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I do think that we should add run-frontend-a11y-tests under the needs section, to make sure that accessibility tests are verified before building staging or production images. Am I correct in thinking this way?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's add it.

name: Run frontend accessibility tests
needs:
- scan-code
- scan-ci-dependencies
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8

- name: Set up Docker buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f

- name: Build frontend a11y-testing image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
cache-from: |
type=gha
type=registry,ref=owasp/nest:test-frontend-a11y-cache
cache-to: |
type=gha,compression=zstd
context: frontend
file: docker/frontend/Dockerfile.a11y.test
load: true
platforms: linux/amd64
tags: owasp/nest:test-frontend-a11y-latest

- name: Run frontend a11y tests
run: |
docker run --env-file frontend/.env.example owasp/nest:test-frontend-a11y-latest pnpm run test:a11y
timeout-minutes: 10

set-release-version:
name: Set release version
outputs:
Expand All @@ -297,6 +331,7 @@ jobs:
github.ref == 'refs/heads/main'
needs:
- run-backend-tests
- run-frontend-a11y-tests
- run-frontend-e2e-tests
- run-frontend-unit-tests
- set-release-version
Expand Down Expand Up @@ -662,6 +697,7 @@ jobs:
github.event.action == 'published'
needs:
- run-backend-tests
- run-frontend-a11y-tests
- run-frontend-e2e-tests
- run-frontend-unit-tests
- set-release-version
Expand Down
27 changes: 27 additions & 0 deletions docker/frontend/Dockerfile.a11y.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM node:24-alpine

ENV FORCE_COLOR=1 \
NPM_CACHE="/app/.npm" \
PNPM_HOME="/pnpm"

ENV NPM_CONFIG_RETRY=5 \
NPM_CONFIG_TIMEOUT=30000 \
PATH="$PNPM_HOME:$PATH"

RUN --mount=type=cache,target=${NPM_CACHE} \
npm install --ignore-scripts -g pnpm --cache ${NPM_CACHE}

WORKDIR /app

COPY --chmod=444 --chown=root:root package.json pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile --ignore-scripts && \
chown node:node /app

COPY __tests__/a11y __tests__/a11y
COPY __tests__/mockData __tests__/mockData
COPY .pnpmrc jest.config.ts jest.setup.ts tsconfig.json ./
COPY public public
COPY src src

USER node
2 changes: 1 addition & 1 deletion docker/frontend/Dockerfile.e2e.test
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile --ignore-scripts

COPY __tests__/e2e __tests__/e2e
COPY __tests__/unit/data __tests__/unit/data
COPY __tests__/mockData __tests__/mockData
COPY .pnpmrc next.config.ts postcss.config.js playwright.config.ts tailwind.config.mjs tsconfig.json ./
COPY public public
COPY src src
1 change: 1 addition & 0 deletions docker/frontend/Dockerfile.unit.test
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
chown node:node /app

COPY __tests__/unit __tests__/unit
COPY __tests__/mockData __tests__/mockData
COPY .pnpmrc jest.config.ts jest.setup.ts tsconfig.json ./
COPY public public
COPY src src
Expand Down
8 changes: 8 additions & 0 deletions frontend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,16 @@ shell-frontend:

test-frontend: \
test-frontend-unit \
test-frontend-a11y \
test-frontend-e2e

test-frontend-a11y:
@DOCKER_BUILDKIT=1 NEXT_PUBLIC_ENVIRONMENT=local docker build \
--cache-from nest-test-frontend-a11y \
-f docker/frontend/Dockerfile.a11y.test frontend \
-t nest-test-frontend-a11y
@docker run --env-file frontend/.env.example --rm nest-test-frontend-a11y pnpm run test:a11y

test-frontend-e2e:
@DOCKER_BUILDKIT=1 NEXT_PUBLIC_ENVIRONMENT=local docker build \
--cache-from nest-test-frontend-e2e \
Expand Down
32 changes: 32 additions & 0 deletions frontend/__tests__/a11y/components/ActionButton.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import ActionButton from 'components/ActionButton'

expect.extend(toHaveNoViolations)

describe('ActionButton Accessibility', () => {
it('should not have any accessibility violations when no url is provided', async () => {
const { container } = render(<ActionButton>Sample Text</ActionButton>)

const results = await axe(container)

expect(results).toHaveNoViolations()
})

it('should not have any accessibility violations when url is provided', async () => {
const { container } = render(<ActionButton url="https://example.com">Visit Site</ActionButton>)

const results = await axe(container)

expect(results).toHaveNoViolations()
})

it('should not have any accessibility violations when tooltipLabel is provided', async () => {
const { baseElement } = render(
<ActionButton tooltipLabel="Test Label">Test Button</ActionButton>
)
const results = await axe(baseElement)

expect(results).toHaveNoViolations()
})
})
15 changes: 15 additions & 0 deletions frontend/__tests__/a11y/components/AnchorTitle.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import AnchorTitle from 'components/AnchorTitle'

expect.extend(toHaveNoViolations)

describe('AnchorTitle Accessibility', () => {
it('should not have any accessibility violations', async () => {
const { container } = render(<AnchorTitle title="Test Title" />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import AutoScrollToTop from 'components/AutoScrollToTop'

expect.extend(toHaveNoViolations)

jest.mock('next/navigation', () => ({
usePathname: () => '/test-path',
}))

beforeAll(() => {
window.scrollTo = jest.fn()
})

afterAll(() => {
jest.clearAllMocks()
})

describe('AutoScrollToTop Accessibility', () => {
it('should not have any accessibility violations', async () => {
const { container } = render(<AutoScrollToTop />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})
})
28 changes: 28 additions & 0 deletions frontend/__tests__/a11y/components/Badges.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import Badges from 'components/Badges'

const defaultProps = {
name: 'Test Badge',
cssClass: 'medal',
}

expect.extend(toHaveNoViolations)

describe('Badges Accessibility', () => {
it('should not have any accessibility violations when tooltip is enabled', async () => {
const { baseElement } = render(<Badges {...defaultProps} />)

const results = await axe(baseElement)

expect(results).toHaveNoViolations()
})

it('should not have any accessibility violations when tooltip is disabled', async () => {
const { baseElement } = render(<Badges {...defaultProps} showTooltip={false} />)

const results = await axe(baseElement)

expect(results).toHaveNoViolations()
})
})
83 changes: 83 additions & 0 deletions frontend/__tests__/a11y/components/BarChart.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import { ReactNode } from 'react'
import BarChart from 'components/BarChart'

const mockProps = {
title: 'Calories Burned',
labels: ['Mon', 'Tue', 'Wed'],
days: [200, 150, 100],
requirements: [180, 170, 90],
}

jest.mock('react-apexcharts', () => {
return function MockChart(props: {
options: unknown
series: unknown
height: number
type: string
}) {
const mockOptions = props.options as Record<string, unknown>

return (
<div
data-testid="mock-chart"
data-options={JSON.stringify(mockOptions)}
data-series={JSON.stringify(props.series)}
data-height={props.height}
data-type={props.type}
/>
)
}
})

jest.mock('next/dynamic', () => {
return function mockDynamic() {
return jest.requireMock('react-apexcharts')
}
})

jest.mock('next-themes', () => ({
ThemeProvider: ({ children, ...props }: { children: ReactNode; [key: string]: unknown }) => (
<div {...props}>{children}</div>
),
useTheme: () => ({ theme: 'light', setTheme: jest.fn() }),
}))

jest.mock('components/AnchorTitle', () => {
return function MockAnchorTitle({ title }: { title: string }) {
return <div data-testid="anchor-title">{title}</div>
}
})

jest.mock('components/SecondaryCard', () => {
return function MockSecondaryCard({
title,
icon,
children,
}: {
title: ReactNode
icon?: unknown
children: ReactNode
}) {
return (
<div data-testid="secondary-card">
<div data-testid="card-title">{title}</div>
{icon && <div data-testid="card-icon">icon</div>}
<div data-testid="card-content">{children}</div>
</div>
)
}
})

expect.extend(toHaveNoViolations)

describe('BarChart Accessibility', () => {
it('should not have any accessibility violations', async () => {
const { container } = render(<BarChart {...mockProps} />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})
})
15 changes: 15 additions & 0 deletions frontend/__tests__/a11y/components/BreadCrumbs.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Breadcrumbs } from '@heroui/react'
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'

expect.extend(toHaveNoViolations)

describe('Breadcrumbs a11y', () => {
it('should not have any accessibility violations', async () => {
const { container } = render(<Breadcrumbs />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render } from '@testing-library/react'
import { useBreadcrumbs } from 'hooks/useBreadcrumbs'
import { axe, toHaveNoViolations } from 'jest-axe'
import { usePathname } from 'next/navigation'
import BreadCrumbsWrapper from 'components/BreadCrumbsWrapper'

expect.extend(toHaveNoViolations)

jest.mock('next/navigation', () => ({
usePathname: jest.fn(),
}))

jest.mock('hooks/useBreadcrumbs', () => ({
useBreadcrumbs: jest.fn(),
}))

describe('BreadcrumbsWrapper a11y', () => {
beforeAll(() => {
;(usePathname as jest.Mock).mockReturnValue('/projects/test-project')
;(useBreadcrumbs as jest.Mock).mockReturnValue([
{ title: 'Home', path: '/' },
{ title: 'Projects', path: '/projects' },
{ title: 'Test Project', path: '/projects/test-project' },
])
})

it('should not have any accessibility violations', async () => {
const { container } = render(<BreadCrumbsWrapper />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})
})
38 changes: 38 additions & 0 deletions frontend/__tests__/a11y/components/CalendarButton.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { render } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import { FaCalendarAlt } from 'react-icons/fa'
import CalendarButton from 'components/CalendarButton'

expect.extend(toHaveNoViolations)

const mockEvent = {
title: 'Test Event',
description: 'Test description',
location: 'Test Location',
startDate: '2025-12-01',
endDate: '2025-12-02',
}

describe('CalendarButton Accessibility', () => {
it('should not have any accessibility violations as an icon-only button', async () => {
const { container } = render(<CalendarButton event={mockEvent} />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})

it('should not have any accessibility violations when showLabel is enabled', async () => {
const { container } = render(<CalendarButton event={mockEvent} showLabel />)

const results = await axe(container)

expect(results).toHaveNoViolations()
})

it('should not have any accessibility violations when custom icon is provided', async () => {
const { container } = render(<CalendarButton event={mockEvent} icon={<FaCalendarAlt />} />)
const results = await axe(container)
expect(results).toHaveNoViolations()
})
})
Loading