diff --git a/CHANGELOG.md b/CHANGELOG.md index 886ff225..d5e11983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ and this project adheres to - 🔒️(backend) configure throttle on every viewsets #1343 - ⬆️ Bump eslint to V9 #1071 +- ♿(frontend) improve accessibility: + - ♿(frontend) fix major accessibility issues reported by wave and axe #1344 + - #1341 ## [3.6.0] - 2025-09-04 diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index ca4053c6..ec4cd2bc 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -226,9 +226,13 @@ test.describe('Doc Editor', () => { await editor.fill('Hello World Doc persisted 2'); await expect(editor.getByText('Hello World Doc persisted 2')).toBeVisible(); + await page.waitForTimeout(1000); + const urlDoc = page.url(); await page.goto(urlDoc); + // Wait for editor to load + await expect(editor).toBeVisible(); await expect(editor.getByText('Hello World Doc persisted 2')).toBeVisible(); }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts index 59a1b998..88429f00 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts @@ -80,9 +80,7 @@ test.describe('Documents Grid mobile', () => { hasText: 'My mocked document', }); - await expect( - row.locator('[aria-describedby="doc-title"]').nth(0), - ).toHaveText('My mocked document'); + await expect(row.getByTestId('doc-title')).toHaveText('My mocked document'); }); }); @@ -295,7 +293,7 @@ test.describe('Documents Grid', () => { docs = result.results as SmallDoc[]; await expect(page.getByTestId('grid-loader')).toBeHidden(); - await expect(page.locator('h4').getByText('All docs')).toBeVisible(); + await expect(page.locator('h2').getByText('All docs')).toBeVisible(); const thead = page.getByTestId('docs-grid-header'); await expect(thead.getByText(/Name/i)).toBeVisible(); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts index 60cff9a3..97d36cc8 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts @@ -173,12 +173,13 @@ test.describe('Document search', () => { .getByRole('combobox', { name: 'Quick search input' }) .fill('sub page search'); - // Expect to find the first doc + // Expect to find the first and second docs in the results list + const resultsList = page.getByRole('listbox'); await expect( - page.getByRole('presentation').getByLabel(firstDocTitle), + resultsList.getByRole('option', { name: firstDocTitle }), ).toBeVisible(); await expect( - page.getByRole('presentation').getByLabel(secondDocTitle), + resultsList.getByRole('option', { name: secondDocTitle }), ).toBeVisible(); await page.getByRole('button', { name: 'close' }).click(); @@ -195,14 +196,15 @@ test.describe('Document search', () => { .fill('second'); // Now there is a sub page - expect to have the focus on the current doc + const updatedResultsList = page.getByRole('listbox'); await expect( - page.getByRole('presentation').getByLabel(secondDocTitle), + updatedResultsList.getByRole('option', { name: secondDocTitle }), ).toBeVisible(); await expect( - page.getByRole('presentation').getByLabel(secondChildDocTitle), + updatedResultsList.getByRole('option', { name: secondChildDocTitle }), ).toBeVisible(); await expect( - page.getByRole('presentation').getByLabel(firstDocTitle), + updatedResultsList.getByRole('option', { name: firstDocTitle }), ).toBeHidden(); }); }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts b/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts index 504f0b4e..4d5a214b 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts @@ -172,7 +172,7 @@ export const goToGridDoc = async ( await expect(row).toBeVisible(); - const docTitleContent = row.locator('[aria-describedby="doc-title"]').first(); + const docTitleContent = row.getByTestId('doc-title').first(); const docTitle = await docTitleContent.textContent(); expect(docTitle).toBeDefined(); diff --git a/src/frontend/apps/impress/src/components/dropdown-menu/DropdownMenu.tsx b/src/frontend/apps/impress/src/components/dropdown-menu/DropdownMenu.tsx index e3617288..df3049f7 100644 --- a/src/frontend/apps/impress/src/components/dropdown-menu/DropdownMenu.tsx +++ b/src/frontend/apps/impress/src/components/dropdown-menu/DropdownMenu.tsx @@ -110,7 +110,6 @@ export const DropdownMenu = ({ $direction="row" $align="center" $position="relative" - aria-controls="menu" > {children} ) : ( - - {children} - + {children} ) } > diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx index ab11f0a2..cdccc047 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx @@ -82,12 +82,11 @@ export const SimpleDocItem = ({ {displayTitle} diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx index 7867e904..9447d0a1 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx @@ -70,7 +70,6 @@ export const DocsGrid = ({ > - - - - {t('Name')} - - - {isDesktop && ( - - - {t('Updated at')} - + + + + + + {t('Name')} + + + {isDesktop && ( + + + {t('Updated at')} + + + )} + + + {isDesktop ? ( + + ) : ( + + )} + + {hasNextPage && !loading && ( + + {!isFetching && hasNextPage && ( + + )} + )} - - {isDesktop ? ( - - ) : ( - - )} - - {hasNextPage && !loading && ( - - {!isFetching && hasNextPage && ( - - )} - - )} )} diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx index e84c4a2b..06edf5ed 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx @@ -53,67 +53,76 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => { `} className="--docs--doc-grid-item" > - - - - {isShared && ( - - {dragMode && ( - - )} - {!dragMode && ( - - {isPublic - ? t('Accessible to anyone') - : t('Accessible to authenticated users')} - - } - placement="top" - > -
- -
-
- )} -
- )} -
-
+ + + {isShared && ( + + {dragMode && ( + + )} + {!dragMode && ( + + {isPublic + ? t('Accessible to anyone') + : t('Accessible to authenticated users')} + + } + placement="top" + > +
+ +
+
+ )} +
+ )} +
+ +
{ $align="center" $justify={isDesktop ? 'space-between' : 'flex-end'} $gap="32px" + role="gridcell" > {isDesktop && ( diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridLoader.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridLoader.tsx index 71fa1828..cd3358ab 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridLoader.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridLoader.tsx @@ -1,5 +1,5 @@ import { Loader } from '@openfun/cunningham-react'; -import { createGlobalStyle } from 'styled-components'; +import { createGlobalStyle, css } from 'styled-components'; import { Box } from '@/components'; @@ -32,6 +32,9 @@ export const DocsGridLoader = ({ isLoading }: DocsGridLoaderProps) => { $zIndex={998} $position="absolute" className="--docs--doc-grid-loader" + $css={css` + pointer-events: none; + `} > diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx index bafacf0b..cc554d73 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx @@ -19,6 +19,7 @@ export const Draggable = (props: DraggableProps) => { {...attributes} data-testid={`draggable-doc-${props.id}`} className="--docs--grid-draggable" + role="presentation" > {props.children} diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx index 851bf6f6..b5301393 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx @@ -35,6 +35,7 @@ export const Droppable = ({ { > {t('Pinned documents')} - void docs.fetchNextPage()} - $padding="none" - > - {favoriteDocs.map((doc) => ( - - ))} - + + + {favoriteDocs.map((doc) => ( + + ))} + + {docs.hasNextPage && ( + void docs.fetchNextPage()} + $padding="none" + /> + )} + );