Skip to content

Commit d8c9283

Browse files
committed
🐛(frontend) fix 404 page when reload 403 page
When users were reloading a 403 page, they were redirected to the 404 page because of Nextjs routing mechanism. This commit fixes this issue by removing the 403 page from the pages directory and creating a component that is used directly in the layout when a 403 error is detected.
1 parent 1e39d17 commit d8c9283

File tree

8 files changed

+120
-149
lines changed

8 files changed

+120
-149
lines changed

CHANGELOG.md

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,13 @@ and this project adheres to
1313
- ♿(frontend) improve accessibility:
1414
- #1354
1515
- ♿ improve accessibility by adding landmark roles to layout #1394
16+
- ✨ add document visible in list and openable via enter key #1365
17+
- ♿ add pdf outline property to enable bookmarks display #1368
1618

1719
### Fixed
1820

1921
- 🐛(backend) duplicate sub docs as root for reader users
20-
21-
### Changed
22-
23-
- ♿(frontend) improve accessibility:
24-
- ✨ add document visible in list and openable via enter key #1365
25-
26-
### Changed
27-
28-
- ♿(frontend) improve accessibility:
29-
- ♿ add pdf outline property to enable bookmarks display #1368
22+
- 🐛(frontend) fix 404 page when reload 403 page #1402
3023

3124
## [3.7.0] - 2025-09-12
3225

src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
randomName,
88
verifyDocName,
99
} from './utils-common';
10+
import { connectOtherUserToDoc } from './utils-share';
1011
import { createRootSubPage } from './utils-sub-pages';
1112

1213
test.describe('Document create member', () => {
@@ -209,20 +210,13 @@ test.describe('Document create member', () => {
209210

210211
await expect(userInvitation).toBeHidden();
211212
});
212-
});
213-
214-
test.describe('Document create member: Multiple login', () => {
215-
test.use({ storageState: { cookies: [], origins: [] } });
216213

217214
test('It creates a member from a request coming from a 403 page', async ({
218215
page,
219216
browserName,
220217
}) => {
221218
test.slow();
222219

223-
await page.goto('/');
224-
await keyCloakSignIn(page, browserName);
225-
226220
const [docTitle] = await createDoc(
227221
page,
228222
'Member access request',
@@ -232,55 +226,37 @@ test.describe('Document create member: Multiple login', () => {
232226

233227
await verifyDocName(page, docTitle);
234228

235-
const urlDoc = page.url();
236-
237229
await page
238-
.getByRole('button', {
239-
name: 'Logout',
240-
})
241-
.click();
242-
243-
const otherBrowser = BROWSERS.find((b) => b !== browserName);
230+
.locator('.ProseMirror')
231+
.locator('.bn-block-outer')
232+
.last()
233+
.fill('Hello World');
244234

245-
await keyCloakSignIn(page, otherBrowser!);
235+
const urlDoc = page.url();
246236

247-
await expect(page.getByTestId('header-logo-link')).toBeVisible();
248-
249-
await page.goto(urlDoc);
237+
// Other user will request access
238+
const { otherPage, otherBrowserName, cleanup } =
239+
await connectOtherUserToDoc(browserName, urlDoc);
250240

251241
await expect(
252-
page.getByText('Insufficient access rights to view the document.'),
242+
otherPage.getByText('Insufficient access rights to view the document.'),
253243
).toBeVisible({
254244
timeout: 10000,
255245
});
256246

257-
await page.getByRole('button', { name: 'Request access' }).click();
247+
await otherPage.getByRole('button', { name: 'Request access' }).click();
258248

259249
await expect(
260-
page.getByText('Your access request for this document is pending.'),
250+
otherPage.getByText('Your access request for this document is pending.'),
261251
).toBeVisible();
262252

263-
await page
264-
.getByRole('button', {
265-
name: 'Logout',
266-
})
267-
.click();
268-
269-
await page.goto('/');
270-
await keyCloakSignIn(page, browserName);
271-
272-
await expect(page.getByTestId('header-logo-link')).toBeVisible({
273-
timeout: 10000,
274-
});
275-
276-
await page.goto(urlDoc);
277-
253+
// First user approves the request
278254
await page.getByRole('button', { name: 'Share' }).click();
279255

280256
await expect(page.getByText('Access Requests')).toBeVisible();
281-
await expect(page.getByText(`E2E ${otherBrowser}`)).toBeVisible();
257+
await expect(page.getByText(`E2E ${otherBrowserName}`)).toBeVisible();
282258

283-
const emailRequest = `user.test@${otherBrowser}.test`;
259+
const emailRequest = `user.test@${otherBrowserName}.test`;
284260
await expect(page.getByText(emailRequest)).toBeVisible();
285261
const container = page.getByTestId(
286262
`doc-share-access-request-row-${emailRequest}`,
@@ -291,8 +267,20 @@ test.describe('Document create member: Multiple login', () => {
291267

292268
await expect(page.getByText('Access Requests')).toBeHidden();
293269
await expect(page.getByText('Share with 2 users')).toBeVisible();
294-
await expect(page.getByText(`E2E ${otherBrowser}`)).toBeVisible();
270+
await expect(page.getByText(`E2E ${otherBrowserName}`)).toBeVisible();
271+
272+
// Other user verifies he has access
273+
await otherPage.reload();
274+
await verifyDocName(otherPage, docTitle);
275+
await expect(otherPage.getByText('Hello World')).toBeVisible();
276+
277+
// Cleanup: other user logout
278+
await cleanup();
295279
});
280+
});
281+
282+
test.describe('Document create member: Multiple login', () => {
283+
test.use({ storageState: { cookies: [], origins: [] } });
296284

297285
test('It cannot request member access on child doc on a 403 page', async ({
298286
page,

src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
keyCloakSignIn,
88
verifyDocName,
99
} from './utils-common';
10+
import { addNewMember, connectOtherUserToDoc } from './utils-share';
1011
import { createRootSubPage } from './utils-sub-pages';
1112

1213
test.describe('Doc Visibility', () => {
@@ -146,47 +147,31 @@ test.describe('Doc Visibility: Restricted', () => {
146147

147148
await verifyDocName(page, docTitle);
148149

149-
await page.getByRole('button', { name: 'Share' }).click();
150-
151-
const inputSearch = page.getByRole('combobox', {
152-
name: 'Quick search input',
153-
});
154-
155-
const otherBrowser = BROWSERS.find((b) => b !== browserName);
156-
if (!otherBrowser) {
157-
throw new Error('No alternative browser found');
158-
}
159-
const username = `user.test@${otherBrowser}.test`;
160-
await inputSearch.fill(username);
161-
await page.getByRole('option', { name: username }).click();
162-
163-
// Choose a role
164-
const container = page.getByTestId('doc-share-add-member-list');
165-
await container.getByLabel('doc-role-dropdown').click();
166-
await page.getByLabel('Reader').click();
167-
168-
await page.getByRole('button', { name: 'Invite' }).click();
169-
170-
await page.locator('.c__modal__backdrop').click({
171-
position: { x: 0, y: 0 },
172-
});
150+
await page
151+
.locator('.ProseMirror')
152+
.locator('.bn-block-outer')
153+
.last()
154+
.fill('Hello World');
173155

174156
const urlDoc = page.url();
175157

176-
await page
177-
.getByRole('button', {
178-
name: 'Logout',
179-
})
180-
.click();
158+
const { otherBrowserName, otherPage } = await connectOtherUserToDoc(
159+
browserName,
160+
urlDoc,
161+
);
181162

182-
await keyCloakSignIn(page, otherBrowser);
163+
await expect(
164+
otherPage.getByText('Insufficient access rights to view the document.'),
165+
).toBeVisible({
166+
timeout: 10000,
167+
});
183168

184-
await expect(page.getByTestId('header-logo-link')).toBeVisible();
169+
await page.getByRole('button', { name: 'Share' }).click();
185170

186-
await page.goto(urlDoc);
171+
await addNewMember(page, 0, 'Reader', otherBrowserName);
187172

188-
await verifyDocName(page, docTitle);
189-
await expect(page.getByLabel('Share button')).toBeVisible();
173+
await otherPage.reload();
174+
await expect(otherPage.getByText('Hello World')).toBeVisible();
190175
});
191176
});
192177

src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Page, expect } from '@playwright/test';
22

3-
export const BROWSERS = ['chromium', 'webkit', 'firefox'];
3+
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
4+
export const BROWSERS: BrowserName[] = ['chromium', 'webkit', 'firefox'];
45

56
export const CONFIG = {
67
AI_FEATURE_ENABLED: true,

src/frontend/apps/e2e/__tests__/app-impress/utils-share.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { Page, expect } from '@playwright/test';
1+
import { Page, chromium, expect } from '@playwright/test';
2+
3+
import {
4+
BROWSERS,
5+
BrowserName,
6+
keyCloakSignIn,
7+
verifyDocName,
8+
} from './utils-common';
29

310
export type Role = 'Administrator' | 'Owner' | 'Member' | 'Editor' | 'Reader';
411
export type LinkReach = 'Private' | 'Connected' | 'Public';
@@ -61,6 +68,56 @@ export const updateShareLink = async (
6168
}
6269
};
6370

71+
/**
72+
* Connects another user to a document.
73+
* Useful to test real-time collaboration features.
74+
* @param browserName The name of the browser to use.
75+
* @param docUrl The URL of the document to connect to.
76+
* @param docTitle The title of the document (optional).
77+
* @returns An object containing the other browser, context, and page.
78+
*/
79+
export const connectOtherUserToDoc = async (
80+
browserName: BrowserName,
81+
docUrl: string,
82+
docTitle?: string,
83+
) => {
84+
const otherBrowserName = BROWSERS.find((b) => b !== browserName);
85+
if (!otherBrowserName) {
86+
throw new Error('No alternative browser found');
87+
}
88+
89+
const otherBrowser = await chromium.launch({ headless: true });
90+
const otherContext = await otherBrowser.newContext({
91+
locale: 'en-US',
92+
timezoneId: 'Europe/Paris',
93+
permissions: [],
94+
storageState: {
95+
cookies: [],
96+
origins: [],
97+
},
98+
});
99+
const otherPage = await otherContext.newPage();
100+
await otherPage.goto(docUrl);
101+
102+
await otherPage.getByRole('button', { name: 'Login' }).click({
103+
timeout: 15000,
104+
});
105+
106+
await keyCloakSignIn(otherPage, otherBrowserName, false);
107+
108+
if (docTitle) {
109+
await verifyDocName(otherPage, docTitle);
110+
}
111+
112+
const cleanup = async () => {
113+
await otherPage.close();
114+
await otherContext.close();
115+
await otherBrowser.close();
116+
};
117+
118+
return { otherBrowser, otherContext, otherPage, otherBrowserName, cleanup };
119+
};
120+
64121
export const mockedInvitations = async (page: Page, json?: object) => {
65122
let result = [
66123
{

0 commit comments

Comments
 (0)