✨(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.
This commit is contained in:
committed by
Anthony LC
parent
510d6c3ff1
commit
17ece3b715
@@ -213,7 +213,26 @@ export const goToGridDoc = async (
|
|||||||
return docTitle as string;
|
return docTitle as string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockedDocument = async (page: Page, json: object) => {
|
export const updateDocTitle = async (page: Page, title: string) => {
|
||||||
|
const input = page.getByLabel('doc title input');
|
||||||
|
await expect(input).toBeVisible();
|
||||||
|
await expect(input).toHaveText('');
|
||||||
|
await input.click();
|
||||||
|
await input.fill(title);
|
||||||
|
await input.click();
|
||||||
|
await verifyDocName(page, title);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const waitForResponseCreateDoc = (page: Page) => {
|
||||||
|
return page.waitForResponse(
|
||||||
|
(response) =>
|
||||||
|
response.url().includes('/documents/') &&
|
||||||
|
response.url().includes('/children/') &&
|
||||||
|
response.request().method() === 'POST',
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockedDocument = async (page: Page, data: object) => {
|
||||||
await page.route('**/documents/**/', async (route) => {
|
await page.route('**/documents/**/', async (route) => {
|
||||||
const request = route.request();
|
const request = route.request();
|
||||||
if (
|
if (
|
||||||
@@ -228,7 +247,7 @@ export const mockedDocument = async (page: Page, json: object) => {
|
|||||||
id: 'mocked-document-id',
|
id: 'mocked-document-id',
|
||||||
content: '',
|
content: '',
|
||||||
title: 'Mocked document',
|
title: 'Mocked document',
|
||||||
accesses: [],
|
path: '000000',
|
||||||
abilities: {
|
abilities: {
|
||||||
destroy: false, // Means not owner
|
destroy: false, // Means not owner
|
||||||
link_configuration: false,
|
link_configuration: false,
|
||||||
@@ -239,11 +258,21 @@ export const mockedDocument = async (page: Page, json: object) => {
|
|||||||
update: false,
|
update: false,
|
||||||
partial_update: false, // Means not editor
|
partial_update: false, // Means not editor
|
||||||
retrieve: true,
|
retrieve: true,
|
||||||
|
link_select_options: {
|
||||||
|
public: ['reader', 'editor'],
|
||||||
|
authenticated: ['reader', 'editor'],
|
||||||
|
restricted: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
link_reach: 'restricted',
|
link_reach: 'restricted',
|
||||||
|
computed_link_reach: 'restricted',
|
||||||
|
computed_link_role: 'reader',
|
||||||
|
ancestors_link_reach: null,
|
||||||
|
ancestors_link_role: null,
|
||||||
created_at: '2021-09-01T09:00:00Z',
|
created_at: '2021-09-01T09:00:00Z',
|
||||||
|
user_role: 'owner',
|
||||||
user_roles: ['owner'],
|
user_roles: ['owner'],
|
||||||
...json,
|
...data,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -316,30 +345,32 @@ export const mockedAccesses = async (page: Page, json?: object) => {
|
|||||||
request.url().includes('page=')
|
request.url().includes('page=')
|
||||||
) {
|
) {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
json: {
|
json: [
|
||||||
count: 1,
|
{
|
||||||
next: null,
|
id: 'bc8bbbc5-a635-4f65-9817-fd1e9ec8ef87',
|
||||||
previous: null,
|
user: {
|
||||||
results: [
|
id: 'b4a21bb3-722e-426c-9f78-9d190eda641c',
|
||||||
{
|
email: 'test@accesses.test',
|
||||||
id: 'bc8bbbc5-a635-4f65-9817-fd1e9ec8ef87',
|
|
||||||
user: {
|
|
||||||
id: 'b4a21bb3-722e-426c-9f78-9d190eda641c',
|
|
||||||
email: 'test@accesses.test',
|
|
||||||
},
|
|
||||||
team: '',
|
|
||||||
role: 'reader',
|
|
||||||
abilities: {
|
|
||||||
destroy: true,
|
|
||||||
update: true,
|
|
||||||
partial_update: true,
|
|
||||||
retrieve: true,
|
|
||||||
set_role_to: ['administrator', 'editor'],
|
|
||||||
},
|
|
||||||
...json,
|
|
||||||
},
|
},
|
||||||
],
|
team: '',
|
||||||
},
|
max_ancestors_role: null,
|
||||||
|
max_role: 'reader',
|
||||||
|
role: 'reader',
|
||||||
|
document: {
|
||||||
|
id: 'mocked-document-id',
|
||||||
|
path: '000000',
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
abilities: {
|
||||||
|
destroy: true,
|
||||||
|
update: true,
|
||||||
|
partial_update: true,
|
||||||
|
retrieve: true,
|
||||||
|
set_role_to: ['administrator', 'editor'],
|
||||||
|
},
|
||||||
|
...json,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await route.continue();
|
await route.continue();
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ const data = [
|
|||||||
title: 'Can drop and drag',
|
title: 'Can drop and drag',
|
||||||
updated_at: '2025-03-14T14:45:27.699542Z',
|
updated_at: '2025-03-14T14:45:27.699542Z',
|
||||||
user_roles: ['owner'],
|
user_roles: ['owner'],
|
||||||
|
user_role: 'owner',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'can-only-drop',
|
id: 'can-only-drop',
|
||||||
@@ -260,6 +261,7 @@ const data = [
|
|||||||
|
|
||||||
updated_at: '2025-03-14T14:45:27.699542Z',
|
updated_at: '2025-03-14T14:45:27.699542Z',
|
||||||
user_roles: ['editor'],
|
user_roles: ['editor'],
|
||||||
|
user_role: 'editor',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'no-drop-and-no-drag',
|
id: 'no-drop-and-no-drag',
|
||||||
@@ -307,5 +309,6 @@ const data = [
|
|||||||
title: 'No drop and no drag',
|
title: 'No drop and no drag',
|
||||||
updated_at: '2025-03-14T14:44:16.032774Z',
|
updated_at: '2025-03-14T14:44:16.032774Z',
|
||||||
user_roles: ['reader'],
|
user_roles: ['reader'],
|
||||||
|
user_role: 'reader',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ test.describe('Document grid item options', () => {
|
|||||||
link_reach: 'restricted',
|
link_reach: 'restricted',
|
||||||
created_at: '2021-09-01T09:00:00Z',
|
created_at: '2021-09-01T09:00:00Z',
|
||||||
user_roles: ['editor'],
|
user_roles: ['editor'],
|
||||||
|
user_role: 'editor',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -109,6 +109,11 @@ test.describe('Doc Header', () => {
|
|||||||
versions_list: true,
|
versions_list: true,
|
||||||
versions_retrieve: true,
|
versions_retrieve: true,
|
||||||
update: true,
|
update: true,
|
||||||
|
link_select_options: {
|
||||||
|
public: ['reader', 'editor'],
|
||||||
|
authenticated: ['reader', 'editor'],
|
||||||
|
restricted: null,
|
||||||
|
},
|
||||||
partial_update: true,
|
partial_update: true,
|
||||||
retrieve: true,
|
retrieve: true,
|
||||||
},
|
},
|
||||||
@@ -134,7 +139,7 @@ test.describe('Doc Header', () => {
|
|||||||
await expect(shareModal).toBeVisible();
|
await expect(shareModal).toBeVisible();
|
||||||
await expect(page.getByText('Share the document')).toBeVisible();
|
await expect(page.getByText('Share the document')).toBeVisible();
|
||||||
|
|
||||||
await expect(page.getByPlaceholder('Type a name or email')).toBeVisible();
|
// await expect(page.getByPlaceholder('Type a name or email')).toBeVisible();
|
||||||
|
|
||||||
const invitationCard = shareModal.getByLabel('List invitation card');
|
const invitationCard = shareModal.getByLabel('List invitation card');
|
||||||
await expect(invitationCard).toBeVisible();
|
await expect(invitationCard).toBeVisible();
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
import { createDoc } from './common';
|
||||||
|
import {
|
||||||
|
addMemberToDoc,
|
||||||
|
searchUserToInviteToDoc,
|
||||||
|
updateShareLink,
|
||||||
|
verifyLinkReachIsDisabled,
|
||||||
|
verifyLinkReachIsEnabled,
|
||||||
|
verifyLinkRoleIsDisabled,
|
||||||
|
verifyLinkRoleIsEnabled,
|
||||||
|
verifyMemberAddedToDoc,
|
||||||
|
} from './share-utils';
|
||||||
|
import { createRootSubPage, createSubPageFromParent } from './sub-pages-utils';
|
||||||
|
|
||||||
|
test.describe('Inherited share accesses', () => {
|
||||||
|
test('Vérifie l’héritage des accès', async ({ page, browserName }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
const [titleParent] = await createDoc(page, 'root-doc', browserName, 1);
|
||||||
|
const docTree = page.getByTestId('doc-tree');
|
||||||
|
|
||||||
|
const addButton = page.getByRole('button', { name: 'New page' });
|
||||||
|
// Wait for and intercept the POST request to create a new page
|
||||||
|
const responsePromise = page.waitForResponse(
|
||||||
|
(response) =>
|
||||||
|
response.url().includes('/documents/') &&
|
||||||
|
response.url().includes('/children/') &&
|
||||||
|
response.request().method() === 'POST',
|
||||||
|
);
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const response = await responsePromise;
|
||||||
|
expect(response.ok()).toBeTruthy();
|
||||||
|
const subPageJson = await response.json();
|
||||||
|
|
||||||
|
await expect(docTree).toBeVisible();
|
||||||
|
const subPageItem = docTree
|
||||||
|
.getByTestId(`doc-sub-page-item-${subPageJson.id}`)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
await expect(subPageItem).toBeVisible();
|
||||||
|
await subPageItem.click();
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await expect(page.getByText('Inherited share')).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: titleParent })).toBeVisible();
|
||||||
|
await page.getByRole('button', { name: 'See access' }).click();
|
||||||
|
await expect(page.getByText('Access inherited from the')).toBeVisible();
|
||||||
|
const user = page.getByTestId(
|
||||||
|
`doc-share-member-row-user@${browserName}.e2e`,
|
||||||
|
);
|
||||||
|
await expect(user).toBeVisible();
|
||||||
|
await expect(user.getByText('E2E Chromium')).toBeVisible();
|
||||||
|
await expect(user.getByText('Owner')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Vérifie le message si il y a un accès hérité', async ({
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await createDoc(page, 'root-doc', browserName, 1);
|
||||||
|
|
||||||
|
// Search user to add
|
||||||
|
let users = await searchUserToInviteToDoc(page);
|
||||||
|
let userToAdd = users[0];
|
||||||
|
|
||||||
|
// Add user as Administrator in root doc
|
||||||
|
await addMemberToDoc(page, 'Administrator', [userToAdd]);
|
||||||
|
await verifyMemberAddedToDoc(page, userToAdd, 'Administrator');
|
||||||
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
|
|
||||||
|
// Create sub page
|
||||||
|
const { name: subPageName, item: subPageJson } = await createRootSubPage(
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
'sub-page',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add user as Editor in sub page
|
||||||
|
users = await searchUserToInviteToDoc(page);
|
||||||
|
userToAdd = users[0];
|
||||||
|
await addMemberToDoc(page, 'Editor', [userToAdd]);
|
||||||
|
const userRow = await verifyMemberAddedToDoc(page, userToAdd, 'Editor');
|
||||||
|
await userRow.getByRole('button', { name: 'doc-role-dropdown' }).click();
|
||||||
|
await page.getByText('This user has access').click();
|
||||||
|
await userRow.click();
|
||||||
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
|
|
||||||
|
// Add new sub page to sub page
|
||||||
|
await createSubPageFromParent(
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
subPageJson.id,
|
||||||
|
'sub-page-2',
|
||||||
|
);
|
||||||
|
|
||||||
|
// // Check sub page inherited share
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await expect(page.getByText('Inherited share')).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: subPageName })).toBeVisible();
|
||||||
|
await page.getByRole('button', { name: 'See access' }).click();
|
||||||
|
await expect(page.getByText('Access inherited from the')).toBeVisible();
|
||||||
|
const user = page.getByTestId(`doc-share-member-row-${userToAdd.email}`);
|
||||||
|
await expect(user).toBeVisible();
|
||||||
|
await expect(user.getByText('Administrator')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Inherited share link', () => {
|
||||||
|
test('Vérifie si le lien est bien hérité', async ({ page, browserName }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
// Create root doc
|
||||||
|
await createDoc(page, 'root-doc', browserName, 1);
|
||||||
|
|
||||||
|
// Update share link
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await updateShareLink(page, 'Connected', 'Reading');
|
||||||
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
|
|
||||||
|
// Create sub page
|
||||||
|
await createRootSubPage(page, browserName, 'sub-page');
|
||||||
|
|
||||||
|
// // verify share link is restricted and reader
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await expect(page.getByText('Inherited share')).toBeVisible();
|
||||||
|
// await verifyShareLink(page, 'Connected', 'Reading');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Vérification du message de warning lorsque les règles de partage diffèrent', async ({
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/');
|
||||||
|
// Create root doc
|
||||||
|
await createDoc(page, 'root-doc', browserName, 1);
|
||||||
|
|
||||||
|
// Update share link
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await updateShareLink(page, 'Connected', 'Reading');
|
||||||
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
|
|
||||||
|
// Create sub page
|
||||||
|
await createRootSubPage(page, browserName, 'sub-page');
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
|
||||||
|
// Update share link to public and edition
|
||||||
|
await updateShareLink(page, 'Public', 'Edition');
|
||||||
|
await expect(page.getByText('Sharing rules differ from the')).toBeVisible();
|
||||||
|
const restoreButton = page.getByRole('button', { name: 'Restore' });
|
||||||
|
await expect(restoreButton).toBeVisible();
|
||||||
|
await restoreButton.click();
|
||||||
|
await expect(
|
||||||
|
page.getByText('The document visibility has been updated').first(),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.getByText('Sharing rules differ from the')).toBeHidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Vérification des possibilités de liens hérités', async ({
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/');
|
||||||
|
// Create root doc
|
||||||
|
await createDoc(page, 'root-doc', browserName, 1);
|
||||||
|
|
||||||
|
// Update share link
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await updateShareLink(page, 'Connected', 'Reading');
|
||||||
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
|
await expect(
|
||||||
|
page.getByText('Document accessible to any connected person'),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// Create sub page
|
||||||
|
const { item: subPageItem } = await createRootSubPage(
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
'sub-page',
|
||||||
|
);
|
||||||
|
await expect(
|
||||||
|
page.getByText('Document accessible to any connected person'),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// Update share link to public and edition
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await verifyLinkReachIsDisabled(page, 'Private');
|
||||||
|
await updateShareLink(page, 'Public', 'Edition');
|
||||||
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
|
await expect(page.getByText('Public document')).toBeVisible();
|
||||||
|
|
||||||
|
// Create sub page
|
||||||
|
await createSubPageFromParent(
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
subPageItem.id,
|
||||||
|
'sub-page-2',
|
||||||
|
);
|
||||||
|
await expect(page.getByText('Public document')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify share link and role
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
await verifyLinkReachIsDisabled(page, 'Private');
|
||||||
|
await verifyLinkReachIsDisabled(page, 'Connected');
|
||||||
|
await verifyLinkReachIsEnabled(page, 'Public');
|
||||||
|
await verifyLinkRoleIsDisabled(page, 'Reading');
|
||||||
|
await verifyLinkRoleIsEnabled(page, 'Edition');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -8,47 +8,59 @@ test.beforeEach(async ({ page }) => {
|
|||||||
|
|
||||||
test.describe('Document list members', () => {
|
test.describe('Document list members', () => {
|
||||||
test('it checks a big list of members', async ({ page }) => {
|
test('it checks a big list of members', async ({ page }) => {
|
||||||
await page.route(
|
|
||||||
/.*\/documents\/.*\/accesses\/\?page=.*/,
|
|
||||||
async (route) => {
|
|
||||||
const request = route.request();
|
|
||||||
const url = new URL(request.url());
|
|
||||||
const pageId = url.searchParams.get('page') ?? '1';
|
|
||||||
|
|
||||||
const accesses = {
|
|
||||||
count: 40,
|
|
||||||
next: +pageId < 2 ? 'http://anything/?page=2' : undefined,
|
|
||||||
previous: null,
|
|
||||||
results: Array.from({ length: 20 }, (_, i) => ({
|
|
||||||
id: `2ff1ec07-86c1-4534-a643-f41824a6c53a-${pageId}-${i}`,
|
|
||||||
user: {
|
|
||||||
id: `fc092149-cafa-4ffa-a29d-e4b18af751-${pageId}-${i}`,
|
|
||||||
email: `impress@impress.world-page-${pageId}-${i}`,
|
|
||||||
full_name: `Impress World Page ${pageId}-${i}`,
|
|
||||||
},
|
|
||||||
team: '',
|
|
||||||
role: 'editor',
|
|
||||||
abilities: {
|
|
||||||
destroy: false,
|
|
||||||
partial_update: true,
|
|
||||||
set_role_to: [],
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (request.method().includes('GET')) {
|
|
||||||
await route.fulfill({
|
|
||||||
json: accesses,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await route.continue();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const docTitle = await goToGridDoc(page);
|
const docTitle = await goToGridDoc(page);
|
||||||
await verifyDocName(page, docTitle);
|
await verifyDocName(page, docTitle);
|
||||||
|
|
||||||
|
// Get the current URL and extract the last part
|
||||||
|
const currentUrl = page.url();
|
||||||
|
console.log('Current URL:', currentUrl);
|
||||||
|
const currentDocId = (() => {
|
||||||
|
// Remove trailing slash if present
|
||||||
|
const cleanUrl = currentUrl.endsWith('/')
|
||||||
|
? currentUrl.slice(0, -1)
|
||||||
|
: currentUrl;
|
||||||
|
|
||||||
|
// Split by '/' and get the last part
|
||||||
|
return cleanUrl.split('/').pop() || '';
|
||||||
|
})();
|
||||||
|
|
||||||
|
await page.route('**/documents/**/accesses/', async (route) => {
|
||||||
|
const request = route.request();
|
||||||
|
const url = new URL(request.url());
|
||||||
|
const pageId = url.searchParams.get('page') ?? '1';
|
||||||
|
|
||||||
|
const accesses = Array.from({ length: 20 }, (_, i) => ({
|
||||||
|
id: `2ff1ec07-86c1-4534-a643-f41824a6c53a-${pageId}-${i}`,
|
||||||
|
document: {
|
||||||
|
id: currentDocId,
|
||||||
|
name: `Doc ${pageId}-${i}`,
|
||||||
|
path: `0000.${pageId}-${i}`,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: `fc092149-cafa-4ffa-a29d-e4b18af751-${pageId}-${i}`,
|
||||||
|
email: `impress@impress.world-page-${pageId}-${i}`,
|
||||||
|
full_name: `Impress World Page ${pageId}-${i}`,
|
||||||
|
},
|
||||||
|
team: '',
|
||||||
|
role: 'editor',
|
||||||
|
max_ancestors_role: null,
|
||||||
|
max_role: 'editor',
|
||||||
|
abilities: {
|
||||||
|
destroy: false,
|
||||||
|
partial_update: true,
|
||||||
|
set_role_to: ['administrator', 'editor'],
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (request.method().includes('GET')) {
|
||||||
|
await route.fulfill({
|
||||||
|
json: accesses,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await route.continue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Share' }).click();
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
|
||||||
const prefix = 'doc-share-member-row';
|
const prefix = 'doc-share-member-row';
|
||||||
@@ -56,11 +68,6 @@ test.describe('Document list members', () => {
|
|||||||
const loadMore = page.getByTestId('load-more-members');
|
const loadMore = page.getByTestId('load-more-members');
|
||||||
|
|
||||||
await expect(elements).toHaveCount(20);
|
await expect(elements).toHaveCount(20);
|
||||||
await expect(page.getByText(`Impress World Page 1-16`)).toBeVisible();
|
|
||||||
|
|
||||||
await loadMore.click();
|
|
||||||
await expect(elements).toHaveCount(40);
|
|
||||||
await expect(page.getByText(`Impress World Page 2-15`)).toBeVisible();
|
|
||||||
|
|
||||||
await expect(loadMore).toBeHidden();
|
await expect(loadMore).toBeHidden();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ test.describe('Document search', () => {
|
|||||||
);
|
);
|
||||||
await verifyDocName(page, doc2Title);
|
await verifyDocName(page, doc2Title);
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.getByRole('button', { name: 'search' }).click();
|
await page
|
||||||
|
.getByTestId('left-panel-desktop')
|
||||||
|
.getByRole('button', { name: 'search' })
|
||||||
|
.click();
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('img', { name: 'No active search' }),
|
page.getByRole('img', { name: 'No active search' }),
|
||||||
|
|||||||
158
src/frontend/apps/e2e/__tests__/app-impress/share-utils.ts
Normal file
158
src/frontend/apps/e2e/__tests__/app-impress/share-utils.ts
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import { Locator, Page, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
export type UserSearchResult = {
|
||||||
|
email: string;
|
||||||
|
full_name?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Role = 'Administrator' | 'Owner' | 'Member' | 'Editor' | 'Reader';
|
||||||
|
export type LinkReach = 'Private' | 'Connected' | 'Public';
|
||||||
|
export type LinkRole = 'Reading' | 'Edition';
|
||||||
|
|
||||||
|
export const searchUserToInviteToDoc = async (
|
||||||
|
page: Page,
|
||||||
|
inputFill?: string,
|
||||||
|
): Promise<UserSearchResult[]> => {
|
||||||
|
const inputFillValue = inputFill ?? 'user ';
|
||||||
|
|
||||||
|
const responsePromise = page.waitForResponse(
|
||||||
|
(response) =>
|
||||||
|
response
|
||||||
|
.url()
|
||||||
|
.includes(`/users/?q=${encodeURIComponent(inputFillValue)}`) &&
|
||||||
|
response.status() === 200,
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
const inputSearch = page.getByRole('combobox', {
|
||||||
|
name: 'Quick search input',
|
||||||
|
});
|
||||||
|
await expect(inputSearch).toBeVisible();
|
||||||
|
await inputSearch.fill(inputFillValue);
|
||||||
|
const response = await responsePromise;
|
||||||
|
const users = (await response.json()) as UserSearchResult[];
|
||||||
|
return users;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addMemberToDoc = async (
|
||||||
|
page: Page,
|
||||||
|
role: Role,
|
||||||
|
users: UserSearchResult[],
|
||||||
|
) => {
|
||||||
|
const list = page.getByTestId('doc-share-add-member-list');
|
||||||
|
await expect(list).toBeHidden();
|
||||||
|
const quickSearchContent = page.getByTestId('doc-share-quick-search');
|
||||||
|
for (const user of users) {
|
||||||
|
await quickSearchContent
|
||||||
|
.getByTestId(`search-user-row-${user.email}`)
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
await list.getByLabel('doc-role-dropdown').click();
|
||||||
|
await expect(page.getByLabel(role)).toBeVisible();
|
||||||
|
await page.getByLabel(role).click();
|
||||||
|
await page.getByRole('button', { name: 'Invite' }).click();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyMemberAddedToDoc = async (
|
||||||
|
page: Page,
|
||||||
|
user: UserSearchResult,
|
||||||
|
role: Role,
|
||||||
|
): Promise<Locator> => {
|
||||||
|
const container = page.getByLabel('List members card');
|
||||||
|
await expect(container).toBeVisible();
|
||||||
|
const userRow = container.getByTestId(`doc-share-member-row-${user.email}`);
|
||||||
|
await expect(userRow).toBeVisible();
|
||||||
|
await expect(userRow.getByText(role)).toBeVisible();
|
||||||
|
await expect(userRow.getByText(user.full_name || user.email)).toBeVisible();
|
||||||
|
return userRow;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateShareLink = async (
|
||||||
|
page: Page,
|
||||||
|
linkReach: LinkReach,
|
||||||
|
linkRole?: LinkRole | null,
|
||||||
|
) => {
|
||||||
|
await page.getByRole('button', { name: 'Visibility', exact: true }).click();
|
||||||
|
await page.getByRole('menuitem', { name: linkReach }).click();
|
||||||
|
|
||||||
|
const visibilityUpdatedText = page
|
||||||
|
.getByText('The document visibility has been updated')
|
||||||
|
.first();
|
||||||
|
|
||||||
|
await expect(visibilityUpdatedText).toBeVisible();
|
||||||
|
|
||||||
|
if (linkRole) {
|
||||||
|
await page
|
||||||
|
.getByRole('button', { name: 'Visibility mode', exact: true })
|
||||||
|
.click();
|
||||||
|
await page.getByRole('menuitem', { name: linkRole }).click();
|
||||||
|
await expect(visibilityUpdatedText).toBeVisible();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyLinkReachIsDisabled = async (
|
||||||
|
page: Page,
|
||||||
|
linkReach: LinkReach,
|
||||||
|
) => {
|
||||||
|
await page.getByRole('button', { name: 'Visibility', exact: true }).click();
|
||||||
|
const item = page.getByRole('menuitem', { name: linkReach });
|
||||||
|
await expect(item).toBeDisabled();
|
||||||
|
await page.click('body');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyLinkReachIsEnabled = async (
|
||||||
|
page: Page,
|
||||||
|
linkReach: LinkReach,
|
||||||
|
) => {
|
||||||
|
await page.getByRole('button', { name: 'Visibility', exact: true }).click();
|
||||||
|
const item = page.getByRole('menuitem', { name: linkReach });
|
||||||
|
await expect(item).toBeEnabled();
|
||||||
|
await page.click('body');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyLinkRoleIsDisabled = async (
|
||||||
|
page: Page,
|
||||||
|
linkRole: LinkRole,
|
||||||
|
) => {
|
||||||
|
await page
|
||||||
|
.getByRole('button', { name: 'Visibility mode', exact: true })
|
||||||
|
.click();
|
||||||
|
const item = page.getByRole('menuitem', { name: linkRole });
|
||||||
|
await expect(item).toBeDisabled();
|
||||||
|
await page.click('body');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyLinkRoleIsEnabled = async (
|
||||||
|
page: Page,
|
||||||
|
linkRole: LinkRole,
|
||||||
|
) => {
|
||||||
|
await page
|
||||||
|
.getByRole('button', { name: 'Visibility mode', exact: true })
|
||||||
|
.click();
|
||||||
|
const item = page.getByRole('menuitem', { name: linkRole });
|
||||||
|
await expect(item).toBeEnabled();
|
||||||
|
await page.click('body');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyShareLink = async (
|
||||||
|
page: Page,
|
||||||
|
linkReach: LinkReach,
|
||||||
|
linkRole?: LinkRole | null,
|
||||||
|
) => {
|
||||||
|
const visibilityDropdownButton = page.getByRole('button', {
|
||||||
|
name: 'Visibility',
|
||||||
|
exact: true,
|
||||||
|
});
|
||||||
|
await expect(visibilityDropdownButton).toBeVisible();
|
||||||
|
await expect(visibilityDropdownButton.getByText(linkReach)).toBeVisible();
|
||||||
|
|
||||||
|
if (linkRole) {
|
||||||
|
const visibilityModeButton = page.getByRole('button', {
|
||||||
|
name: 'Visibility mode',
|
||||||
|
exact: true,
|
||||||
|
});
|
||||||
|
await expect(visibilityModeButton).toBeVisible();
|
||||||
|
await expect(page.getByText(linkRole)).toBeVisible();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { Page, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
import { randomName, updateDocTitle, waitForResponseCreateDoc } from './common';
|
||||||
|
|
||||||
|
export const createRootSubPage = async (
|
||||||
|
page: Page,
|
||||||
|
browserName: string,
|
||||||
|
docName: string,
|
||||||
|
) => {
|
||||||
|
// Get add button
|
||||||
|
const addButton = page.getByRole('button', { name: 'New page' });
|
||||||
|
|
||||||
|
// Get response
|
||||||
|
const responsePromise = waitForResponseCreateDoc(page);
|
||||||
|
await addButton.click();
|
||||||
|
const response = await responsePromise;
|
||||||
|
expect(response.ok()).toBeTruthy();
|
||||||
|
const subPageJson = (await response.json()) as { id: string };
|
||||||
|
|
||||||
|
// Get doc tree
|
||||||
|
const docTree = page.getByTestId('doc-tree');
|
||||||
|
await expect(docTree).toBeVisible();
|
||||||
|
|
||||||
|
// Get sub page item
|
||||||
|
const subPageItem = docTree
|
||||||
|
.getByTestId(`doc-sub-page-item-${subPageJson.id}`)
|
||||||
|
.first();
|
||||||
|
await expect(subPageItem).toBeVisible();
|
||||||
|
await subPageItem.click();
|
||||||
|
|
||||||
|
// Update sub page name
|
||||||
|
const randomDocs = randomName(docName, browserName, 1);
|
||||||
|
await updateDocTitle(page, randomDocs[0]);
|
||||||
|
|
||||||
|
// Return sub page data
|
||||||
|
return { name: randomDocs[0], docTreeItem: subPageItem, item: subPageJson };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createSubPageFromParent = async (
|
||||||
|
page: Page,
|
||||||
|
browserName: string,
|
||||||
|
parentId: string,
|
||||||
|
subPageName: string,
|
||||||
|
) => {
|
||||||
|
// Get parent doc tree item
|
||||||
|
const parentDocTreeItem = page.getByTestId(`doc-sub-page-item-${parentId}`);
|
||||||
|
await expect(parentDocTreeItem).toBeVisible();
|
||||||
|
await parentDocTreeItem.hover();
|
||||||
|
|
||||||
|
// Create sub page
|
||||||
|
const responsePromise = waitForResponseCreateDoc(page);
|
||||||
|
await parentDocTreeItem.getByRole('button', { name: 'add_box' }).click();
|
||||||
|
|
||||||
|
// Get response
|
||||||
|
const response = await responsePromise;
|
||||||
|
expect(response.ok()).toBeTruthy();
|
||||||
|
const subPageJson = (await response.json()) as { id: string };
|
||||||
|
|
||||||
|
// Get doc tree
|
||||||
|
const docTree = page.getByTestId('doc-tree');
|
||||||
|
await expect(docTree).toBeVisible();
|
||||||
|
|
||||||
|
// Get sub page item
|
||||||
|
const subPageItem = docTree
|
||||||
|
.getByTestId(`doc-sub-page-item-${subPageJson.id}`)
|
||||||
|
.first();
|
||||||
|
await expect(subPageItem).toBeVisible();
|
||||||
|
await subPageItem.click();
|
||||||
|
|
||||||
|
// Update sub page name
|
||||||
|
const subPageTitle = randomName(subPageName, browserName, 1)[0];
|
||||||
|
await updateDocTitle(page, subPageTitle);
|
||||||
|
|
||||||
|
// Return sub page data
|
||||||
|
return { name: subPageTitle, docTreeItem: subPageItem, item: subPageJson };
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user