(e2e) fix flakiness

Some flakiness appeared in the e2e tests. It
started to impact many pull requests. Time to
fix them.
This commit is contained in:
Anthony LC
2025-01-29 14:06:38 +01:00
committed by Anthony LC
parent 7880391648
commit 6569f61fc4
11 changed files with 117 additions and 180 deletions

View File

@@ -26,7 +26,7 @@ export const createDoc = async (
page: Page,
docName: string,
browserName: string,
length: number,
length: number = 1,
) => {
const randomDocs = randomName(docName, browserName, length);
@@ -40,7 +40,8 @@ export const createDoc = async (
})
.click();
const input = page.getByRole('textbox', { name: 'doc title input' });
const input = page.getByLabel('doc title input');
await expect(input).toHaveText('');
await input.click();
await input.fill(randomDocs[i]);
await input.blur();
@@ -91,6 +92,22 @@ export const addNewMember = async (
return users[index].email;
};
export const getGridRow = async (page: Page, title: string) => {
const docsGrid = page.getByRole('grid');
await expect(docsGrid).toBeVisible();
await expect(page.getByTestId('grid-loader')).toBeHidden();
const rows = docsGrid.getByRole('row');
const row = rows.filter({
hasText: title,
});
await expect(row).toBeVisible();
return row;
};
interface GoToGridDocOptions {
nthRow?: number;
title?: string;
@@ -104,7 +121,7 @@ export const goToGridDoc = async (
const docsGrid = page.getByTestId('docs-grid');
await expect(docsGrid).toBeVisible();
await expect(docsGrid.getByTestId('grid-loader')).toBeHidden();
await expect(page.getByTestId('grid-loader')).toBeHidden();
const rows = docsGrid.getByRole('row');

View File

@@ -220,7 +220,7 @@ test.describe('Doc Editor', () => {
browserName,
}) => {
// Check the first doc
const [doc] = await createDoc(page, 'doc-saves-change', browserName, 1);
const [doc] = await createDoc(page, 'doc-saves-change', browserName);
await verifyDocName(page, doc);
const editor = page.locator('.ProseMirror');
@@ -228,9 +228,11 @@ test.describe('Doc Editor', () => {
await editor.fill('Hello World Doc persisted 1');
await expect(editor.getByText('Hello World Doc persisted 1')).toBeVisible();
const secondDoc = await goToGridDoc(page, {
nthRow: 2,
});
const [secondDoc] = await createDoc(
page,
'doc-saves-change-other',
browserName,
);
await verifyDocName(page, secondDoc);
@@ -238,6 +240,7 @@ test.describe('Doc Editor', () => {
title: doc,
});
await verifyDocName(page, doc);
await expect(editor.getByText('Hello World Doc persisted 1')).toBeVisible();
});
@@ -246,8 +249,7 @@ test.describe('Doc Editor', () => {
test.skip(browserName === 'webkit', 'This test is very flaky with webkit');
// Check the first doc
const doc = await goToGridDoc(page);
const [doc] = await createDoc(page, 'doc-quit-1', browserName, 1);
await verifyDocName(page, doc);
const editor = page.locator('.ProseMirror');

View File

@@ -1,75 +0,0 @@
import { expect, test } from '@playwright/test';
import { createDoc, verifyDocName } from './common';
type SmallDoc = {
id: string;
title: string;
};
test.describe('Document favorite', () => {
test('it check the favorite workflow', async ({ page, browserName }) => {
const id = Math.random().toString(7);
await page.goto('/');
// Create document
const createdDoc = await createDoc(page, `Doc ${id}`, browserName, 1);
await verifyDocName(page, createdDoc[0]);
// Reload page
await page.reload();
await page.goto('/');
// Get all documents
let docs: SmallDoc[] = [];
const response = await page.waitForResponse(
(response) =>
response.url().endsWith('documents/?page=1') &&
response.status() === 200,
);
const result = await response.json();
docs = result.results as SmallDoc[];
const docsGrid = page.getByTestId('docs-grid');
await docsGrid.getByRole('heading', { name: 'All docs' }).click();
await expect(docsGrid.getByText(`Doc ${id}`)).toBeVisible();
const doc = docs.find((doc) => doc.title === createdDoc[0]) as SmallDoc;
// Check document
expect(doc).not.toBeUndefined();
expect(doc?.title).toBe(createdDoc[0]);
// Open document actions
const button = docsGrid.getByTestId(`docs-grid-actions-button-${doc.id}`);
await expect(button).toBeVisible();
await button.click();
// Pin document
const pinButton = page.getByTestId(`docs-grid-actions-pin-${docs[0].id}`);
await expect(pinButton).toBeVisible();
await pinButton.click();
// Check response
const responsePin = await page.waitForResponse(
(response) =>
response.url().includes(`documents/${doc.id}/favorite/`) &&
response.status() === 201,
);
expect(responsePin.ok()).toBeTruthy();
// Check left panel favorites
const leftPanelFavorites = page.getByTestId('left-panel-favorites');
await expect(leftPanelFavorites).toBeVisible();
await expect(leftPanelFavorites.getByText(`Doc ${id}`)).toBeVisible();
//
await button.click();
const unpinButton = page.getByTestId(
`docs-grid-actions-unpin-${docs[0].id}`,
);
await expect(unpinButton).toBeVisible();
await unpinButton.click();
// Check left panel favorites
await expect(leftPanelFavorites.getByText(`Doc ${id}`)).toBeHidden();
});
});

View File

@@ -1,5 +1,7 @@
import { expect, test } from '@playwright/test';
import { createDoc, getGridRow } from './common';
type SmallDoc = {
id: string;
title: string;
@@ -92,6 +94,31 @@ test.describe('Documents Grid mobile', () => {
});
test.describe('Document grid item options', () => {
test('it pins a document', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, `Favorite doc`, browserName);
await page.goto('/');
const row = await getGridRow(page, docTitle);
// Pin
await row.getByText(`more_horiz`).click();
await page.getByText('push_pin').click();
// Check is pinned
await expect(row.getByLabel('Pin document icon')).toBeVisible();
const leftPanelFavorites = page.getByTestId('left-panel-favorites');
await expect(leftPanelFavorites.getByText(docTitle)).toBeVisible();
// Unpin
await row.getByText(`more_horiz`).click();
await page.getByText('Unpin').click();
// Check is unpinned
await expect(row.getByLabel('Pin document icon')).toBeHidden();
await expect(leftPanelFavorites.getByText(docTitle)).toBeHidden();
});
test('it deletes the document', async ({ page }) => {
let docs: SmallDoc[] = [];
const response = await page.waitForResponse(

View File

@@ -26,7 +26,7 @@ test.describe('Document create member', () => {
const response = await responsePromise;
const users = (await response.json()).results as {
email: string;
full_name: string;
full_name?: string | null;
}[];
const list = page.getByTestId('doc-share-add-member-list');
@@ -40,7 +40,9 @@ test.describe('Document create member', () => {
await expect(
list.getByTestId(`doc-share-add-member-${users[0].email}`),
).toBeVisible();
await expect(list.getByText(`${users[0].full_name}`)).toBeVisible();
await expect(
list.getByText(`${users[0].full_name || users[0].email}`),
).toBeVisible();
// Select user 2 and verify tag
await inputSearch.fill('user');
@@ -51,7 +53,9 @@ test.describe('Document create member', () => {
await expect(
list.getByTestId(`doc-share-add-member-${users[1].email}`),
).toBeVisible();
await expect(list.getByText(`${users[1].full_name}`)).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];
@@ -81,7 +85,9 @@ test.describe('Document create member', () => {
// Check user added
await expect(page.getByText('Share with 3 users')).toBeVisible();
await expect(
quickSearchContent.getByText(users[0].full_name).first(),
quickSearchContent
.getByText(users[0].full_name || users[0].email)
.first(),
).toBeVisible();
await expect(
quickSearchContent.getByText(users[0].email).first(),
@@ -90,7 +96,9 @@ test.describe('Document create member', () => {
quickSearchContent.getByText(users[1].email).first(),
).toBeVisible();
await expect(
quickSearchContent.getByText(users[1].full_name).first(),
quickSearchContent
.getByText(users[1].full_name || users[1].email)
.first(),
).toBeVisible();
});

View File

@@ -1,21 +1,32 @@
import { expect, test } from '@playwright/test';
import { DateTime } from 'luxon';
import { createDoc, verifyDocName } from './common';
type SmallDoc = {
id: string;
title: string;
updated_at: string;
};
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test.describe('Document search', () => {
test('it checks all elements are visible', async ({ page }) => {
test('it searches documents', async ({ page, browserName }) => {
const [doc1Title] = await createDoc(
page,
'My doc search super',
browserName,
1,
);
await verifyDocName(page, doc1Title);
await page.goto('/');
const [doc2Title] = await createDoc(
page,
'My doc search doc',
browserName,
1,
);
await verifyDocName(page, doc2Title);
await page.goto('/');
await page.getByRole('button', { name: 'search' }).click();
await expect(
page.getByRole('img', { name: 'No active search' }),
).toBeVisible();
@@ -24,91 +35,32 @@ test.describe('Document search', () => {
page.getByLabel('Search modal').getByText('search'),
).toBeVisible();
await expect(
page.getByPlaceholder('Type the name of a document'),
).toBeVisible();
});
const inputSearch = page.getByPlaceholder('Type the name of a document');
test('it checks search for a document', async ({ page, browserName }) => {
const id = Math.random().toString(36).substring(7);
await inputSearch.click();
await inputSearch.fill('My doc search');
await inputSearch.press('ArrowDown');
const doc1 = await createDoc(page, `My super ${id} doc`, browserName, 1);
await verifyDocName(page, doc1[0]);
await page.goto('/');
const doc2 = await createDoc(
page,
`My super ${id} very doc`,
browserName,
1,
);
await verifyDocName(page, doc2[0]);
await page.goto('/');
await page.getByRole('button', { name: 'search' }).click();
await page.getByPlaceholder('Type the name of a document').click();
await page
.getByPlaceholder('Type the name of a document')
.fill(`My super ${id}`);
let responsePromisePage = page.waitForResponse(
(response) =>
response.url().includes(`/documents/?page=1&title=My+super+${id}`) &&
response.status() === 200,
);
let response = await responsePromisePage;
let result = (await response.json()) as { results: SmallDoc[] };
let docs = result.results;
expect(docs.length).toEqual(2);
await Promise.all(
docs.map(async (doc: SmallDoc) => {
await expect(
page.getByTestId(`doc-search-item-${doc.id}`),
).toBeVisible();
const updatedAt = DateTime.fromISO(doc.updated_at ?? DateTime.now())
.setLocale('en')
.toRelative();
await expect(
page.getByTestId(`doc-search-item-${doc.id}`).getByText(updatedAt!),
).toBeVisible();
}),
);
const firstDoc = docs[0];
const listSearch = page.getByRole('listbox').getByRole('group');
const rowdoc = listSearch.getByRole('option').first();
await expect(rowdoc.getByText('keyboard_return')).toBeVisible();
await expect(rowdoc.getByText(/seconds? ago/)).toBeVisible();
await expect(
page
.getByTestId(`doc-search-item-${firstDoc.id}`)
.getByText('keyboard_return'),
listSearch.getByRole('option').getByText(doc1Title),
).toBeVisible();
await page
.getByPlaceholder('Type the name of a document')
.press('ArrowDown');
const secondDoc = docs[1];
await expect(
page
.getByTestId(`doc-search-item-${secondDoc.id}`)
.getByText('keyboard_return'),
listSearch.getByRole('option').getByText(doc2Title),
).toBeVisible();
await page.getByPlaceholder('Type the name of a document').click();
await page
.getByPlaceholder('Type the name of a document')
.fill(`My super ${id} doc`);
await inputSearch.fill('My doc search super');
responsePromisePage = page.waitForResponse(
(response) =>
response
.url()
.includes(`/documents/?page=1&title=My+super+${id}+doc`) &&
response.status() === 200,
);
await expect(
listSearch.getByRole('option').getByText(doc1Title),
).toBeVisible();
response = await responsePromisePage;
result = (await response.json()) as { results: SmallDoc[] };
docs = result.results;
expect(docs.length).toEqual(1);
await expect(
listSearch.getByRole('option').getByText(doc2Title),
).toBeHidden();
});
});

View File

@@ -171,6 +171,9 @@ test.describe('Doc Visibility: Restricted', () => {
await page.goto(urlDoc);
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(1000);
await verifyDocName(page, docTitle);
await expect(page.getByLabel('Share button')).toBeVisible();
});
@@ -209,6 +212,7 @@ test.describe('Doc Visibility: Public', () => {
page.getByText('The document visibility has been updated.'),
).toBeVisible();
await expect(page.getByLabel('Visibility mode')).toBeVisible();
await page.getByLabel('Visibility mode').click();
await page
.getByRole('button', {

View File

@@ -13,11 +13,9 @@
},
"devDependencies": {
"@playwright/test": "1.49.1",
"@types/luxon": "3.4.2",
"@types/node": "*",
"@types/pdf-parse": "1.1.4",
"eslint-config-impress": "*",
"luxon": "3.5.0",
"typescript": "*"
},
"dependencies": {

View File

@@ -30,12 +30,9 @@ import { DocShareModalFooter } from './DocShareModalFooter';
import { DocShareModalInviteUserRow } from './DocShareModalInviteUserByEmail';
const ShareModalStyle = createGlobalStyle`
.c__modal__title {
padding-bottom: 0 !important;
}
}
`;
type Props = {

View File

@@ -70,6 +70,7 @@ export const DocsGrid = ({
>
<DocsGridLoader isLoading={isRefetching || loading} />
<Card
role="grid"
data-testid="docs-grid"
$height="100%"
$width="100%"

View File

@@ -1,4 +1,5 @@
import { DateTime } from 'luxon';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, Text } from '@/components';
@@ -30,6 +31,7 @@ export const SimpleDocItem = ({
isPinned = false,
showAccesses = false,
}: SimpleDocItemProps) => {
const { t } = useTranslation();
const { spacingsTokens } = useCunninghamTheme();
const { isDesktop } = useResponsiveStore();
const spacings = spacingsTokens();
@@ -44,7 +46,11 @@ export const SimpleDocItem = ({
filter: drop-shadow(0px 2px 2px rgba(0, 0, 0, 0.05));
`}
>
{isPinned ? <PinnedDocumentIcon /> : <SimpleFileIcon />}
{isPinned ? (
<PinnedDocumentIcon aria-label={t('Pin document icon')} />
) : (
<SimpleFileIcon aria-label={t('Simple document icon')} />
)}
</Box>
<Box $justify="center">
<Text