Skip to content

Commit c904619

Browse files
✨(frontend) enhance document sharing and access management
- Introduced new utility functions for managing document sharing, including `searchUserToInviteToDoc`, `addMemberToDoc`, and `updateShareLink`. - Updated existing tests to verify inherited share access and link visibility features. - Refactored document access handling in tests to improve clarity and maintainability. - Added comprehensive tests for inherited share functionalities, ensuring proper role and access management for subpages.
1 parent a668728 commit c904619

9 files changed

+564
-71
lines changed

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

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,26 @@ export const goToGridDoc = async (
188188
return docTitle as string;
189189
};
190190

191-
export const mockedDocument = async (page: Page, json: object) => {
191+
export const updateDocTitle = async (page: Page, title: string) => {
192+
const input = page.getByLabel('doc title input');
193+
await expect(input).toBeVisible();
194+
await expect(input).toHaveText('');
195+
await input.click();
196+
await input.fill(title);
197+
await input.click();
198+
await verifyDocName(page, title);
199+
};
200+
201+
export const getWaitForCreateDoc = (page: Page) => {
202+
return page.waitForResponse(
203+
(response) =>
204+
response.url().includes('/documents/') &&
205+
response.url().includes('/children/') &&
206+
response.request().method() === 'POST',
207+
);
208+
};
209+
210+
export const mockedDocument = async (page: Page, data: object) => {
192211
await page.route('**/documents/**/', async (route) => {
193212
const request = route.request();
194213
if (
@@ -203,7 +222,7 @@ export const mockedDocument = async (page: Page, json: object) => {
203222
id: 'mocked-document-id',
204223
content: '',
205224
title: 'Mocked document',
206-
accesses: [],
225+
path: '000000',
207226
abilities: {
208227
destroy: false, // Means not owner
209228
link_configuration: false,
@@ -214,11 +233,21 @@ export const mockedDocument = async (page: Page, json: object) => {
214233
update: false,
215234
partial_update: false, // Means not editor
216235
retrieve: true,
236+
link_select_options: {
237+
public: ['reader', 'editor'],
238+
authenticated: ['reader', 'editor'],
239+
restricted: null,
240+
},
217241
},
218242
link_reach: 'restricted',
243+
computed_link_reach: 'restricted',
244+
computed_link_role: 'reader',
245+
ancestors_link_reach: null,
246+
ancestors_link_role: null,
219247
created_at: '2021-09-01T09:00:00Z',
248+
user_role: 'owner',
220249
user_roles: ['owner'],
221-
...json,
250+
...data,
222251
},
223252
});
224253
} else {
@@ -291,30 +320,32 @@ export const mockedAccesses = async (page: Page, json?: object) => {
291320
request.url().includes('page=')
292321
) {
293322
await route.fulfill({
294-
json: {
295-
count: 1,
296-
next: null,
297-
previous: null,
298-
results: [
299-
{
300-
id: 'bc8bbbc5-a635-4f65-9817-fd1e9ec8ef87',
301-
user: {
302-
id: 'b4a21bb3-722e-426c-9f78-9d190eda641c',
303-
email: 'test@accesses.test',
304-
},
305-
team: '',
306-
role: 'reader',
307-
abilities: {
308-
destroy: true,
309-
update: true,
310-
partial_update: true,
311-
retrieve: true,
312-
set_role_to: ['administrator', 'editor'],
313-
},
314-
...json,
323+
json: [
324+
{
325+
id: 'bc8bbbc5-a635-4f65-9817-fd1e9ec8ef87',
326+
user: {
327+
id: 'b4a21bb3-722e-426c-9f78-9d190eda641c',
328+
email: 'test@accesses.test',
315329
},
316-
],
317-
},
330+
team: '',
331+
max_ancestors_role: null,
332+
max_role: 'reader',
333+
role: 'reader',
334+
document: {
335+
id: 'mocked-document-id',
336+
path: '000000',
337+
depth: 1,
338+
},
339+
abilities: {
340+
destroy: true,
341+
update: true,
342+
partial_update: true,
343+
retrieve: true,
344+
set_role_to: ['administrator', 'editor'],
345+
},
346+
...json,
347+
},
348+
],
318349
});
319350
} else {
320351
await route.continue();

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ const data = [
212212
title: 'Can drop and drag',
213213
updated_at: '2025-03-14T14:45:27.699542Z',
214214
user_roles: ['owner'],
215+
user_role: 'owner',
215216
},
216217
{
217218
id: 'can-only-drop',
@@ -260,6 +261,7 @@ const data = [
260261

261262
updated_at: '2025-03-14T14:45:27.699542Z',
262263
user_roles: ['editor'],
264+
user_role: 'editor',
263265
},
264266
{
265267
id: 'no-drop-and-no-drag',
@@ -307,5 +309,6 @@ const data = [
307309
title: 'No drop and no drag',
308310
updated_at: '2025-03-14T14:44:16.032774Z',
309311
user_roles: ['reader'],
312+
user_role: 'reader',
310313
},
311314
];

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ test.describe('Document grid item options', () => {
170170
link_reach: 'restricted',
171171
created_at: '2021-09-01T09:00:00Z',
172172
user_roles: ['editor'],
173+
user_role: 'editor',
173174
},
174175
],
175176
},

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ test.describe('Doc Header', () => {
5454
retrieve: true,
5555
},
5656
link_reach: 'public',
57+
computed_link_reach: 'public',
5758
created_at: '2021-09-01T09:00:00Z',
5859
});
5960

@@ -135,6 +136,11 @@ test.describe('Doc Header', () => {
135136
versions_list: true,
136137
versions_retrieve: true,
137138
update: true,
139+
link_select_options: {
140+
public: ['reader', 'editor'],
141+
authenticated: ['reader', 'editor'],
142+
restricted: null,
143+
},
138144
partial_update: true,
139145
retrieve: true,
140146
},
@@ -160,7 +166,7 @@ test.describe('Doc Header', () => {
160166
await expect(shareModal).toBeVisible();
161167
await expect(page.getByText('Share the document')).toBeVisible();
162168

163-
await expect(page.getByPlaceholder('Type a name or email')).toBeVisible();
169+
// await expect(page.getByPlaceholder('Type a name or email')).toBeVisible();
164170

165171
const invitationCard = shareModal.getByLabel('List invitation card');
166172
await expect(invitationCard).toBeVisible();
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
import { createDoc } from './common';
4+
import {
5+
addMemberToDoc,
6+
searchUserToInviteToDoc,
7+
updateShareLink,
8+
verifyLinkReachIsDisabled,
9+
verifyLinkReachIsEnabled,
10+
verifyLinkRoleIsDisabled,
11+
verifyLinkRoleIsEnabled,
12+
verifyMemberAddedToDoc,
13+
} from './share-utils';
14+
import { createRootSubPage, createSubPageFromParent } from './sub-pages-utils';
15+
16+
test.describe('Inherited share accesses', () => {
17+
test('Vérifie l’héritage des accès', async ({ page, browserName }) => {
18+
await page.goto('/');
19+
const [titleParent] = await createDoc(page, 'root-doc', browserName, 1);
20+
const docTree = page.getByTestId('doc-tree');
21+
22+
const addButton = page.getByRole('button', { name: 'New page' });
23+
// Wait for and intercept the POST request to create a new page
24+
const responsePromise = page.waitForResponse(
25+
(response) =>
26+
response.url().includes('/documents/') &&
27+
response.url().includes('/children/') &&
28+
response.request().method() === 'POST',
29+
);
30+
await addButton.click();
31+
32+
const response = await responsePromise;
33+
expect(response.ok()).toBeTruthy();
34+
const subPageJson = await response.json();
35+
36+
await expect(docTree).toBeVisible();
37+
const subPageItem = docTree
38+
.getByTestId(`doc-sub-page-item-${subPageJson.id}`)
39+
.first();
40+
41+
await expect(subPageItem).toBeVisible();
42+
await subPageItem.click();
43+
await page.getByRole('button', { name: 'Share' }).click();
44+
await expect(page.getByText('Inherited share')).toBeVisible();
45+
await expect(page.getByRole('link', { name: titleParent })).toBeVisible();
46+
await page.getByRole('button', { name: 'See access' }).click();
47+
await expect(page.getByText('Access inherited from the')).toBeVisible();
48+
const user = page.getByTestId(
49+
`doc-share-member-row-user@${browserName}.e2e`,
50+
);
51+
await expect(user).toBeVisible();
52+
await expect(user.getByText('E2E Chromium')).toBeVisible();
53+
await expect(user.getByText('Owner')).toBeVisible();
54+
});
55+
56+
test('Vérifie le message si il y a un accès hérité', async ({
57+
page,
58+
browserName,
59+
}) => {
60+
await page.goto('/');
61+
await createDoc(page, 'root-doc', browserName, 1);
62+
63+
// Search user to add
64+
let users = await searchUserToInviteToDoc(page);
65+
let userToAdd = users[0];
66+
67+
// Add user as Administrator in root doc
68+
await addMemberToDoc(page, 'Administrator', [userToAdd]);
69+
await verifyMemberAddedToDoc(page, userToAdd, 'Administrator');
70+
await page.getByRole('button', { name: 'OK' }).click();
71+
72+
// Create sub page
73+
const { name: subPageName, item: subPageJson } = await createRootSubPage(
74+
page,
75+
browserName,
76+
'sub-page',
77+
);
78+
79+
// Add user as Editor in sub page
80+
users = await searchUserToInviteToDoc(page);
81+
userToAdd = users[0];
82+
await addMemberToDoc(page, 'Editor', [userToAdd]);
83+
const userRow = await verifyMemberAddedToDoc(page, userToAdd, 'Editor');
84+
await userRow.getByRole('button', { name: 'doc-role-dropdown' }).click();
85+
await page.getByText('This user has access').click();
86+
await userRow.click();
87+
await page.getByRole('button', { name: 'OK' }).click();
88+
89+
// Add new sub page to sub page
90+
await createSubPageFromParent(
91+
page,
92+
browserName,
93+
subPageJson.id,
94+
'sub-page-2',
95+
);
96+
97+
// // Check sub page inherited share
98+
await page.getByRole('button', { name: 'Share' }).click();
99+
await expect(page.getByText('Inherited share')).toBeVisible();
100+
await expect(page.getByRole('link', { name: subPageName })).toBeVisible();
101+
await page.getByRole('button', { name: 'See access' }).click();
102+
await expect(page.getByText('Access inherited from the')).toBeVisible();
103+
const user = page.getByTestId(`doc-share-member-row-${userToAdd.email}`);
104+
await expect(user).toBeVisible();
105+
await expect(user.getByText('Administrator')).toBeVisible();
106+
});
107+
});
108+
109+
test.describe('Inherited share link', () => {
110+
test('Vérifie si le lien est bien hérité', async ({ page, browserName }) => {
111+
await page.goto('/');
112+
// Create root doc
113+
await createDoc(page, 'root-doc', browserName, 1);
114+
115+
// Update share link
116+
await page.getByRole('button', { name: 'Share' }).click();
117+
await updateShareLink(page, 'Connected', 'Reading');
118+
await page.getByRole('button', { name: 'OK' }).click();
119+
120+
// Create sub page
121+
await createRootSubPage(page, browserName, 'sub-page');
122+
123+
// // verify share link is restricted and reader
124+
await page.getByRole('button', { name: 'Share' }).click();
125+
await expect(page.getByText('Inherited share')).toBeVisible();
126+
// await verifyShareLink(page, 'Connected', 'Reading');
127+
});
128+
129+
test('Vérification du message de warning lorsque les règles de partage diffèrent', async ({
130+
page,
131+
browserName,
132+
}) => {
133+
await page.goto('/');
134+
// Create root doc
135+
await createDoc(page, 'root-doc', browserName, 1);
136+
137+
// Update share link
138+
await page.getByRole('button', { name: 'Share' }).click();
139+
await updateShareLink(page, 'Connected', 'Reading');
140+
await page.getByRole('button', { name: 'OK' }).click();
141+
142+
// Create sub page
143+
await createRootSubPage(page, browserName, 'sub-page');
144+
await page.getByRole('button', { name: 'Share' }).click();
145+
146+
// Update share link to public and edition
147+
await updateShareLink(page, 'Public', 'Edition');
148+
await expect(page.getByText('Sharing rules differ from the')).toBeVisible();
149+
const restoreButton = page.getByRole('button', { name: 'Restore' });
150+
await expect(restoreButton).toBeVisible();
151+
await restoreButton.click();
152+
await expect(
153+
page.getByText('The document visibility has been updated').first(),
154+
).toBeVisible();
155+
await expect(page.getByText('Sharing rules differ from the')).toBeHidden();
156+
});
157+
158+
test('Vérification des possibilités de liens hérités', async ({
159+
page,
160+
browserName,
161+
}) => {
162+
await page.goto('/');
163+
// Create root doc
164+
await createDoc(page, 'root-doc', browserName, 1);
165+
166+
// Update share link
167+
await page.getByRole('button', { name: 'Share' }).click();
168+
await updateShareLink(page, 'Connected', 'Reading');
169+
await page.getByRole('button', { name: 'OK' }).click();
170+
await expect(
171+
page.getByText('Document accessible to any connected person'),
172+
).toBeVisible();
173+
174+
// Create sub page
175+
const { item: subPageItem } = await createRootSubPage(
176+
page,
177+
browserName,
178+
'sub-page',
179+
);
180+
await expect(
181+
page.getByText('Document accessible to any connected person'),
182+
).toBeVisible();
183+
184+
// Update share link to public and edition
185+
await page.getByRole('button', { name: 'Share' }).click();
186+
await verifyLinkReachIsDisabled(page, 'Private');
187+
await updateShareLink(page, 'Public', 'Edition');
188+
await page.getByRole('button', { name: 'OK' }).click();
189+
await expect(page.getByText('Public document')).toBeVisible();
190+
191+
// Create sub page
192+
await createSubPageFromParent(
193+
page,
194+
browserName,
195+
subPageItem.id,
196+
'sub-page-2',
197+
);
198+
await expect(page.getByText('Public document')).toBeVisible();
199+
200+
// Verify share link and role
201+
await page.getByRole('button', { name: 'Share' }).click();
202+
await verifyLinkReachIsDisabled(page, 'Private');
203+
await verifyLinkReachIsDisabled(page, 'Connected');
204+
await verifyLinkReachIsEnabled(page, 'Public');
205+
await verifyLinkRoleIsDisabled(page, 'Reading');
206+
await verifyLinkRoleIsEnabled(page, 'Edition');
207+
});
208+
});

0 commit comments

Comments
 (0)