Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to

- ✨(y-provider) preserve callouts, PDFs, page breaks, interlinking
links and commented text on HTML/markdown export #2296
- ✨(frontend) add a user menu #2463

### Changed

Expand Down
7 changes: 4 additions & 3 deletions src/frontend/apps/e2e/__tests__/app-impress/auth.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ const saveStorageState = async (

await SignIn(page, browserName);

/**
* If the grid is displayed, it means the user is logged in and the storage state can be saved.
*/
await expect(
page.locator('header').first().getByRole('button', {
name: 'Logout',
}),
page.getByRole('heading', { name: 'All docs', level: 2 }),
).toBeVisible({ timeout: 10000 });

await page.context().storageState({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
updateRoleUser,
updateShareLink,
} from './utils-share';
import { logOut } from './utils-signin';

test.beforeEach(async ({ page }) => {
await page.goto('/');
Expand Down Expand Up @@ -312,7 +313,7 @@ test.describe('Doc Comments', () => {
await updateShareLink(page, 'Public', 'Editing');

// Anonymous user can see and add comments
await otherPage.getByRole('button', { name: 'Logout' }).click();
await logOut(otherPage);

await expect(
otherPage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from './utils-common';
import { writeInEditor } from './utils-editor';
import { connectOtherUserToDoc, updateRoleUser } from './utils-share';
import { SignIn } from './utils-signin';
import { SignIn, logOut } from './utils-signin';
import { createRootSubPage } from './utils-sub-pages';

test.describe('Document create member', () => {
Expand Down Expand Up @@ -371,11 +371,7 @@ test.describe('Document create member: Multiple login', () => {

const urlDoc = page.url();

await page
.getByRole('button', {
name: 'Logout',
})
.click();
await logOut(page);

const otherBrowser = BROWSERS.find((b) => b !== browserName);

Expand Down
16 changes: 3 additions & 13 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
import { BROWSERS, createDoc, verifyDocName } from './utils-common';
import { getEditor, writeInEditor } from './utils-editor';
import { addNewMember, connectOtherUserToDoc } from './utils-share';
import { SignIn, expectLoginPage } from './utils-signin';
import { SignIn, expectLoginPage, logOut } from './utils-signin';
import { createRootSubPage } from './utils-sub-pages';

test.describe('Doc Visibility', () => {
Expand Down Expand Up @@ -81,13 +81,7 @@ test.describe('Doc Visibility: Restricted', () => {
await verifyDocName(page, docTitle);

const urlDoc = page.url();

await page
.getByRole('button', {
name: 'Logout',
})
.click();

await logOut(page);
await expectLoginPage(page);

await page.goto(urlDoc);
Expand All @@ -112,11 +106,7 @@ test.describe('Doc Visibility: Restricted', () => {

const urlDoc = page.url();

await page
.getByRole('button', {
name: 'Logout',
})
.click();
await logOut(page);

const otherBrowser = BROWSERS.find((b) => b !== browserName);
if (!otherBrowser) {
Expand Down
27 changes: 0 additions & 27 deletions src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, test } from '@playwright/test';

import { overrideConfig } from './utils-common';
import { SignIn, expectLoginPage } from './utils-signin';

test.describe('Header', () => {
test('checks all the elements are visible', async ({ page }) => {
Expand All @@ -14,14 +13,6 @@ test.describe('Header', () => {
'font-family',
/Roboto/i,
);

await expect(
header.getByRole('button', {
name: 'Logout',
}),
).toBeVisible();

await expect(header.getByText('English')).toBeVisible();
});

test('checks all the elements are visible with DSFR theme', async ({
Expand Down Expand Up @@ -106,21 +97,3 @@ test.describe('Header', () => {
await expect(logoImage).toHaveAttribute('alt', '');
});
});

test.describe('Header: Log out', () => {
test.use({ storageState: { cookies: [], origins: [] } });

// eslint-disable-next-line playwright/expect-expect
test('checks logout button', async ({ page, browserName }) => {
await page.goto('/');
await SignIn(page, browserName);

await page
.getByRole('button', {
name: 'Logout',
})
.click();

await expectLoginPage(page);
});
});
49 changes: 27 additions & 22 deletions src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ test.describe('Language', () => {
});

test('checks language switching', async ({ page }) => {
const header = page.locator('header').first();
const languagePicker = header.locator('.--docs--language-picker-text');

await expect(page.locator('html')).toHaveAttribute('lang', 'en-us');

// initial language should be english
Expand All @@ -58,34 +55,38 @@ test.describe('Language', () => {

await expect(page.locator('html')).toHaveAttribute('lang', 'fr');

await page.getByLabel('Ouvrir le menu utilisateur').click();
await expect(
header.getByRole('button').getByText('Français'),
page.getByRole('button', { name: 'Language: Français' }),
).toBeVisible();

await expect(page.getByLabel('Se déconnecter')).toBeVisible();

// Switch to German using the utility function for consistency
await waitForLanguageSwitch(page, TestLanguage.German);
await expect(header.getByRole('button').getByText('Deutsch')).toBeVisible();

await expect(page.getByLabel('Abmelden')).toBeVisible();

await expect(page.locator('html')).toHaveAttribute('lang', 'de');
await expect(page.getByText('Déconnexion')).toBeVisible();

await languagePicker.click();
await page.keyboard.press('Escape');

await expect(page.locator('[role="menu"]')).toBeVisible();
// Switch to German using the utility function for consistency
await waitForLanguageSwitch(
page,
TestLanguage.German,
'Ouvrir le menu utilisateur',
);

const menuItems = page.locator('[role="menuitemradio"]');
await expect(menuItems.first()).toBeVisible();
await page.getByLabel('Open user menu').click();
await expect(
page.getByRole('button', { name: 'Language: Deutsch' }),
).toBeVisible();

await menuItems.first().click();
await expect(page.getByText('Logout', { exact: true })).toBeVisible();

await expect(page.locator('html')).toHaveAttribute('lang', 'en');
await expect(languagePicker).toContainText('English');
await expect(page.locator('html')).toHaveAttribute('lang', 'de');
});

test('can switch language using only keyboard', async ({ page }) => {
/**
* This test is currently failing due to a known issue with the language picker component.
* A pull request has been created to address this issue: https://github.com/suitenumerique/ui-kit/pull/265
* TODO: Adapt this test once the PR is merged and the uikit version bumped.
*/
Comment on lines +84 to +88

@AntoLC AntoLC Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

There is a accessibility issue with the user menu component.
A pull request has been created to fix this issue: suitenumerique/ui-kit#265

test.skip('can switch language using only keyboard', async ({ page }) => {
await page.goto('/');
await waitForLanguageSwitch(page, TestLanguage.English);

Expand Down Expand Up @@ -171,7 +172,11 @@ test.describe('Language', () => {
/**
* Swedish is not yet supported in the BlockNote locales, so it should fallback to English
*/
await waitForLanguageSwitch(page, TestLanguage.Swedish);
await waitForLanguageSwitch(
page,
TestLanguage.Swedish,
'Ouvrir le menu utilisateur',
);
await openSuggestionMenu({ page });
await expect(
suggestionMenu.getByText('Headings', { exact: true }),
Expand Down
16 changes: 16 additions & 0 deletions src/frontend/apps/e2e/__tests__/app-impress/left-panel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
verifyDocName,
} from './utils-common';
import { tryFocusEditorContent } from './utils-editor';
import { SignIn, expectLoginPage, logOut } from './utils-signin';
import { createRootSubPage } from './utils-sub-pages';

test.describe('Left panel desktop', () => {
Expand All @@ -19,6 +20,8 @@ test.describe('Left panel desktop', () => {
await expect(page.getByTestId('left-panel-mobile')).toBeHidden();
await expect(page.getByTestId('home-button')).toBeHidden();
await expect(page.getByTestId('new-doc-button')).toBeVisible();
await expect(page.getByLabel('Open user menu')).toBeVisible();
await expect(page.getByLabel('Open help menu')).toBeVisible();

await goToGridDoc(page);

Expand Down Expand Up @@ -309,3 +312,16 @@ test.describe('Left panel responsive', () => {
await expect(leftPanel).toBeHidden();
});
});

test.describe('Left Panel: Log out', () => {
test.use({ storageState: { cookies: [], origins: [] } });

// eslint-disable-next-line playwright/expect-expect
test('checks logout button', async ({ page, browserName }) => {
await page.goto('/');
await SignIn(page, browserName);
await logOut(page);

await expectLoginPage(page);
});
});
8 changes: 5 additions & 3 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ type TestLanguageValue = (typeof TestLanguage)[TestLanguageKey];
export async function waitForLanguageSwitch(
page: Page,
lang: TestLanguageValue,
labelUserMenu = 'Open user menu',
) {
await page.route(/\**\/api\/v1.0\/users\/\**/, async (route, request) => {
if (request.method().includes('PATCH')) {
Expand All @@ -412,8 +413,8 @@ export async function waitForLanguageSwitch(
}
});

const header = page.locator('header').first();
const languagePicker = header.locator('.--docs--language-picker-text');
await page.getByLabel(labelUserMenu).click();
const languagePicker = page.getByRole('button', { name: /Language/ });
const isAlreadyTargetLanguage = await languagePicker
.innerText()
.then((text) => text.toLowerCase().includes(lang.label.toLowerCase()));
Expand All @@ -424,7 +425,8 @@ export async function waitForLanguageSwitch(

await languagePicker.click();

await page.getByRole('menuitemradio', { name: lang.label }).click();
await page.getByRole('menuitem', { name: lang.label }).click();
await page.keyboard.press('Escape');
}

export const clickInEditorShareButton = async (page: Page) => {
Expand Down
5 changes: 5 additions & 0 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-signin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export const SignIn = async (
await keycloakSignIn(page, browserName, fromHome);
};

export const logOut = async (page: Page) => {
await page.getByLabel('Open user menu').click();
await page.getByText('Logout', { exact: true }).click();
};

export const customSignIn = async (
page: Page,
browserName: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,30 @@ import { Button } from '@gouvfr-lasuite/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';

import { Box, BoxButton } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { BoxButton } from '@/components';

import ProConnectImg from '../assets/button-proconnect.svg';
import { useAuth } from '../hooks';
import { gotoLogin, gotoLogout } from '../utils';
import { gotoLogin } from '../utils';

export const ButtonLogin = () => {
const { t } = useTranslation();
const { authenticated } = useAuth();
const { colorsTokens } = useCunninghamTheme();

if (!authenticated) {
return (
<Button
onClick={() => gotoLogin()}
color="brand"
variant="tertiary"
aria-label={t('Login')}
className="--docs--button-login"
>
{t('Login')}
</Button>
);
if (authenticated) {
return null;
}

return (
<Box
$css={css`
.--docs--button-logout:focus-visible {
box-shadow: 0 0 0 2px ${colorsTokens['brand-400']} !important;
border-radius: var(--c--globals--spacings--st);
}
`}
<Button
onClick={() => gotoLogin()}
color="brand"
size="small"
aria-label={t('Sign in')}
className="--docs--button-login"
>
<Button
onClick={gotoLogout}
color="brand"
variant="tertiary"
aria-label={t('Logout')}
className="--docs--button-logout"
>
{t('Logout')}
</Button>
</Box>
{t('Sign in')}
</Button>
);
};

Expand Down
Loading
Loading