This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
docs/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts
Anthony LC fbdeb90113 🛂(frontend) invalidate doc query when lost connection
When the provider reports a lost connection,
we invalidate the doc query to refetch the document
data.
This ensures that if a user has lost is rights
to access a document, he will be redirected
to a 403 page without needing to refresh the page.
2025-09-17 17:45:26 +02:00

346 lines
10 KiB
TypeScript

import { expect, test } from '@playwright/test';
import {
BROWSERS,
createDoc,
keyCloakSignIn,
randomName,
verifyDocName,
} from './utils-common';
import { connectOtherUserToDoc, updateRoleUser } from './utils-share';
import { createRootSubPage } from './utils-sub-pages';
test.describe('Document create member', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('it selects 2 users and 1 invitation', async ({ page, browserName }) => {
const inputFill = 'user.test';
const responsePromise = page.waitForResponse(
(response) =>
response.url().includes(`/users/?q=${encodeURIComponent(inputFill)}`) &&
response.status() === 200,
);
await createDoc(page, 'select-multi-users', browserName, 1);
await page.getByRole('button', { name: 'Share' }).click();
const inputSearch = page.getByRole('combobox', {
name: 'Quick search input',
});
await expect(inputSearch).toBeVisible();
// Select user 1 and verify tag
await inputSearch.fill(inputFill);
const response = await responsePromise;
const users = (await response.json()) as {
email: string;
full_name?: string | null;
}[];
const list = page.getByTestId('doc-share-add-member-list');
await expect(list).toBeHidden();
const quickSearchContent = page.getByTestId('doc-share-quick-search');
await quickSearchContent
.getByTestId(`search-user-row-${users[0].email}`)
.click();
await expect(list).toBeVisible();
await expect(
list.getByTestId(`doc-share-add-member-${users[0].email}`),
).toBeVisible();
await expect(
list.getByText(`${users[0].full_name || users[0].email}`),
).toBeVisible();
// Select user 2 and verify tag
await inputSearch.fill(inputFill);
await quickSearchContent
.getByTestId(`search-user-row-${users[1].email}`)
.click();
await expect(
list.getByTestId(`doc-share-add-member-${users[1].email}`),
).toBeVisible();
await expect(
list.getByText(`${users[1].full_name || users[1].email}`),
).toBeVisible();
// Select email and verify tag
const email = randomName('test@test.fr', browserName, 1)[0];
await inputSearch.fill(email);
await quickSearchContent.getByText(email).click();
await expect(list.getByText(email)).toBeVisible();
// Check roles are displayed
await list.getByLabel('doc-role-dropdown').click();
await expect(page.getByLabel('Reader')).toBeVisible();
await expect(page.getByLabel('Editor')).toBeVisible();
await expect(page.getByLabel('Owner')).toBeVisible();
await expect(page.getByLabel('Administrator')).toBeVisible();
// Validate
await page.getByLabel('Administrator').click();
await page.getByRole('button', { name: 'Invite' }).click();
// Check invitation added
await expect(
quickSearchContent.getByText('Pending invitations'),
).toBeVisible();
await expect(quickSearchContent.getByText(email).first()).toBeVisible();
// Check user added
await expect(page.getByText('Share with 3 users')).toBeVisible();
await expect(
quickSearchContent
.getByText(users[0].full_name || users[0].email)
.first(),
).toBeVisible();
await expect(
quickSearchContent.getByText(users[0].email).first(),
).toBeVisible();
await expect(
quickSearchContent.getByText(users[1].email).first(),
).toBeVisible();
await expect(
quickSearchContent
.getByText(users[1].full_name || users[1].email)
.first(),
).toBeVisible();
});
test('it try to add twice the same invitation', async ({
page,
browserName,
}) => {
await createDoc(page, 'invitation-twice', browserName, 1);
await page.getByRole('button', { name: 'Share' }).click();
const inputSearch = page.getByRole('combobox', {
name: 'Quick search input',
});
const [email] = randomName('test@test.fr', browserName, 1);
await inputSearch.fill(email);
await page.getByTestId(`search-user-row-${email}`).click();
// Choose a role
const container = page.getByTestId('doc-share-add-member-list');
await container.getByLabel('doc-role-dropdown').click();
await page.getByLabel('Owner').click();
const responsePromiseCreateInvitation = page.waitForResponse(
(response) =>
response.url().includes('/invitations/') && response.status() === 201,
);
await page.getByRole('button', { name: 'Invite' }).click();
// Check invitation sent
const responseCreateInvitation = await responsePromiseCreateInvitation;
expect(responseCreateInvitation.ok()).toBeTruthy();
await inputSearch.fill(email);
await page.getByTestId(`search-user-row-${email}`).click();
// Choose a role
await container.getByLabel('doc-role-dropdown').click();
await page.getByLabel('Owner').click();
const responsePromiseCreateInvitationFail = page.waitForResponse(
(response) =>
response.url().includes('/invitations/') && response.status() === 400,
);
await page.getByRole('button', { name: 'Invite' }).click();
await expect(
page.getByText(`"${email}" is already invited to the document.`),
).toBeVisible();
const responseCreateInvitationFail =
await responsePromiseCreateInvitationFail;
expect(responseCreateInvitationFail.ok()).toBeFalsy();
});
test('it manages invitation', async ({ page, browserName }) => {
await createDoc(page, 'user-invitation', browserName, 1);
await page.getByRole('button', { name: 'Share' }).click();
const inputSearch = page.getByRole('combobox', {
name: 'Quick search input',
});
const email = randomName('test@test.fr', browserName, 1)[0];
await inputSearch.fill(email);
await page.getByTestId(`search-user-row-${email}`).click();
// Choose a role
const container = page.getByTestId('doc-share-add-member-list');
await container.getByLabel('doc-role-dropdown').click();
await page.getByLabel('Administrator').click();
const responsePromiseCreateInvitation = page.waitForResponse(
(response) =>
response.url().includes('/invitations/') && response.status() === 201,
);
await page.getByRole('button', { name: 'Invite' }).click();
// Check invitation sent
const responseCreateInvitation = await responsePromiseCreateInvitation;
expect(responseCreateInvitation.ok()).toBeTruthy();
const listInvitation = page.getByTestId('doc-share-quick-search');
const userInvitation = listInvitation.getByTestId(
`doc-share-invitation-row-${email}`,
);
await expect(userInvitation).toBeVisible();
await userInvitation.getByLabel('doc-role-dropdown').click();
await page.getByLabel('Reader').click();
const moreActions = userInvitation.getByRole('button', {
name: 'Open invitation actions menu',
});
await moreActions.click();
await page.getByLabel('Delete').click();
await expect(userInvitation).toBeHidden();
});
test('It creates a member from a request coming from a 403 page', async ({
page,
browserName,
}) => {
test.slow();
const [docTitle] = await createDoc(
page,
'Member access request',
browserName,
1,
);
await verifyDocName(page, docTitle);
await page
.locator('.ProseMirror')
.locator('.bn-block-outer')
.last()
.fill('Hello World');
const urlDoc = page.url();
// Other user will request access
const { otherPage, otherBrowserName, cleanup } =
await connectOtherUserToDoc(browserName, urlDoc);
await expect(
otherPage.getByText('Insufficient access rights to view the document.'),
).toBeVisible({
timeout: 10000,
});
await otherPage.getByRole('button', { name: 'Request access' }).click();
await expect(
otherPage.getByText('Your access request for this document is pending.'),
).toBeVisible();
// First user approves the request
await page.getByRole('button', { name: 'Share' }).click();
await expect(page.getByText('Access Requests')).toBeVisible();
await expect(page.getByText(`E2E ${otherBrowserName}`)).toBeVisible();
const emailRequest = `user.test@${otherBrowserName}.test`;
await expect(page.getByText(emailRequest)).toBeVisible();
const container = page.getByTestId(
`doc-share-access-request-row-${emailRequest}`,
);
await container.getByLabel('doc-role-dropdown').click();
await page.getByLabel('Administrator').click();
await container.getByRole('button', { name: 'Approve' }).click();
await expect(page.getByText('Access Requests')).toBeHidden();
await expect(page.getByText('Share with 2 users')).toBeVisible();
await expect(page.getByText(`E2E ${otherBrowserName}`)).toBeVisible();
// Other user verifies he has access
await otherPage.reload();
await verifyDocName(otherPage, docTitle);
await expect(otherPage.getByText('Hello World')).toBeVisible();
// Revoke access
await updateRoleUser(page, 'Remove access', emailRequest);
await expect(
otherPage.getByText('Insufficient access rights to view the document.'),
).toBeVisible();
// Cleanup: other user logout
await cleanup();
});
});
test.describe('Document create member: Multiple login', () => {
test.use({ storageState: { cookies: [], origins: [] } });
test('It cannot request member access on child doc on a 403 page', async ({
page,
browserName,
}) => {
test.slow();
await page.goto('/');
await keyCloakSignIn(page, browserName);
const [docParent] = await createDoc(
page,
'Block Member access request on child doc - parent',
browserName,
1,
);
await verifyDocName(page, docParent);
await createRootSubPage(
page,
browserName,
'Block Member access request on child doc - child',
);
const urlDoc = page.url();
await page
.getByRole('button', {
name: 'Logout',
})
.click();
const otherBrowser = BROWSERS.find((b) => b !== browserName);
await keyCloakSignIn(page, otherBrowser!);
await expect(page.getByTestId('header-logo-link')).toBeVisible({
timeout: 10000,
});
await page.goto(urlDoc);
await expect(
page.getByText(
"You're currently viewing a sub-document. To gain access, please request permission from the main document.",
),
).toBeVisible({
timeout: 10000,
});
await expect(
page.getByRole('button', { name: 'Request access' }),
).toBeHidden();
});
});