diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ea7d6..5dd70d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ and this project adheres to ### Fixed +- 🐛(frontend) improve e2e tests avoiding race condition from mocks #641 - 🐛(backend) fix flaky test with search contact #605 - 🐛(backend) fix flaky test with team access #646 - 🧑‍💻(dimail) remove 'NoneType: None' log in debug mode diff --git a/src/frontend/apps/desk/next-env.d.ts b/src/frontend/apps/desk/next-env.d.ts index 95ddcae..a58a43b 100644 --- a/src/frontend/apps/desk/next-env.d.ts +++ b/src/frontend/apps/desk/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts index a1ed78f..5653ee4 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts @@ -60,12 +60,6 @@ test.describe('Config', () => { page, browserName, }) => { - await page.goto('/'); - // Login with a user who has the visibility on the groups should see groups - // It's now the backend that decides if the user can see the group menu and they - // should be redirected to the groups page in such case - await keyCloakSignIn(page, browserName, 'team-administrator'); - await page.route('**/api/v1.0/config/', async (route) => { const request = route.request(); if (request.method().includes('GET')) { @@ -83,6 +77,12 @@ test.describe('Config', () => { } }); + await page.goto('/'); + // Login with a user who has the visibility on the groups should see groups + // It's now the backend that decides if the user can see the group menu and they + // should be redirected to the groups page in such case + await keyCloakSignIn(page, browserName, 'team-administrator'); + await expect(page.locator('menu')).toBeHidden(); await expect(page.getByText('Groups')).toBeVisible(); diff --git a/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts index f38b115..6addc22 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts @@ -25,9 +25,9 @@ const payloadGetTeams = { ], }; -const mockApiRequests = (page: Page) => { - void page.route('**/teams/?ordering=-created_at', (route) => { - void route.fulfill({ +const mockApiRequests = async (page: Page) => { + await page.route('**/teams/?ordering=-created_at', async (route) => { + await route.fulfill({ json: payloadGetTeams.results, }); }); @@ -40,11 +40,11 @@ test.describe('Keyboard navigation', () => { }) => { const page = await browser.newPage(); + await mockApiRequests(page); + await page.goto('/'); await keyCloakSignIn(page, browserName, 'team-owner-mail-member'); - void mockApiRequests(page); - const header = page.locator('header'); // La Gauffre button is loaded asynchronously, so we wait for it to be visible diff --git a/src/frontend/apps/e2e/__tests__/app-desk/mail-domain-create-mailbox.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/mail-domain-create-mailbox.spec.ts index 09bca20..7a0a52e 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/mail-domain-create-mailbox.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/mail-domain-create-mailbox.spec.ts @@ -85,10 +85,13 @@ const mailboxesFixtures = { }, }; -const interceptCommonApiRequests = (page: Page, mailDomains?: MailDomain[]) => { +const interceptCommonApiRequests = async ( + page: Page, + mailDomains?: MailDomain[], +) => { const mailDomainsToUse = mailDomains ?? mailDomainsFixtures; - void page.route('**/api/v1.0/mail-domains/?page=*', (route) => { - void route.fulfill({ + await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => { + await route.fulfill({ json: { count: mailDomainsToUse.length, next: null, @@ -98,28 +101,37 @@ const interceptCommonApiRequests = (page: Page, mailDomains?: MailDomain[]) => { }); }); - mailDomainsToUse.forEach((mailDomain) => { - void page.route(`**/api/v1.0/mail-domains/${mailDomain.slug}/`, (route) => { - void route.fulfill({ - json: mailDomain, - }); - }); + await Promise.all( + mailDomainsToUse.map(async (mailDomain) => { + await page.route( + `**/api/v1.0/mail-domains/${mailDomain.slug}/`, + async (route) => { + await route.fulfill({ + json: mailDomain, + }); + }, + ); + }), + ); - void page.route( - `**/api/v1.0/mail-domains/${mailDomain.slug}/mailboxes/?page=1**`, - (route) => { - void route.fulfill({ - json: { - count: mailboxesFixtures.domainFr.page1.length, - next: null, - previous: null, - results: mailboxesFixtures.domainFr.page1, - }, - }); - }, - { times: 1 }, - ); - }); + await Promise.all( + mailDomainsToUse.map(async (mailDomain) => { + await page.route( + `**/api/v1.0/mail-domains/${mailDomain.slug}/mailboxes/?page=1**`, + async (route) => { + await route.fulfill({ + json: { + count: mailboxesFixtures.domainFr.page1.length, + next: null, + previous: null, + results: mailboxesFixtures.domainFr.page1, + }, + }); + }, + { times: 1 }, + ); + }), + ); }; const navigateToMailboxCreationFormForMailDomainFr = async ( @@ -131,19 +143,20 @@ const navigateToMailboxCreationFormForMailDomainFr = async ( }; test.describe('Mail domain create mailbox', () => { - test.beforeEach(async ({ page, browserName }) => { - await page.goto('/'); - // Login with a user who has the visibility on the mail domains - await keyCloakSignIn(page, browserName, 'mail-member'); - }); - - test('checks create mailbox button is visible or not', async ({ page }) => { + test('checks create mailbox button is visible or not', async ({ + page, + browserName, + }) => { const domains = [...mailDomainsFixtures]; domains[0].status = 'enabled'; domains[1].status = 'pending'; domains[2].status = 'disabled'; domains[3].status = 'failed'; - void interceptCommonApiRequests(page, domains); + await interceptCommonApiRequests(page, domains); + + await page.goto('/'); + // Login with a user who has the visibility on the mail domains + await keyCloakSignIn(page, browserName, 'mail-member'); await page .locator('menu') @@ -190,6 +203,7 @@ test.describe('Mail domain create mailbox', () => { test('checks user can create a mailbox when he has post ability', async ({ page, + browserName, }) => { const newMailbox = { id: '04433733-c9b7-453a-8122-755ac115bb00', @@ -197,13 +211,13 @@ test.describe('Mail domain create mailbox', () => { secondary_email: 'john.doe-complex2024@mail.com', }; - const interceptRequests = (page: Page) => { - void interceptCommonApiRequests(page); + const interceptRequests = async (page: Page) => { + await interceptCommonApiRequests(page); - void page.route( + await page.route( '**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**', - (route) => { - void route.fulfill({ + async (route) => { + await route.fulfill({ json: { count: [...mailboxesFixtures.domainFr.page1, newMailbox].length, next: null, @@ -214,15 +228,15 @@ test.describe('Mail domain create mailbox', () => { }, ); - void page.route( + await page.route( '**/api/v1.0/mail-domains/domainfr/mailboxes/', - (route) => { + async (route) => { if (route.request().method() === 'POST') { - void route.fulfill({ + await route.fulfill({ json: newMailbox, }); } else { - void route.continue(); + await route.continue(); } }, ); @@ -249,8 +263,12 @@ test.describe('Mail domain create mailbox', () => { } }); - void interceptRequests(page); - expect(true).toBeTruthy(); + await interceptRequests(page); + + await page.goto('/'); + // Login with a user who has the visibility on the mail domains + await keyCloakSignIn(page, browserName, 'mail-member'); + await navigateToMailboxCreationFormForMailDomainFr(page); await page.getByRole('button', { name: 'Cancel' }).click(); @@ -315,15 +333,16 @@ test.describe('Mail domain create mailbox', () => { test('checks user is not allowed to create a mailbox when he is missing post ability', async ({ page, + browserName, }) => { const localMailDomainsFixtures = [...mailDomainsFixtures]; localMailDomainsFixtures[0].abilities.post = false; const localMailDomainDomainFr = localMailDomainsFixtures[0]; const localMailboxFixtures = { ...mailboxesFixtures }; - const interceptRequests = (page: Page) => { - void page.route('**/api/v1.0/mail-domains/?page=*', (route) => { - void route.fulfill({ + const interceptRequests = async (page: Page) => { + await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => { + await route.fulfill({ json: { count: localMailDomainsFixtures.length, next: null, @@ -333,16 +352,16 @@ test.describe('Mail domain create mailbox', () => { }); }); - void page.route('**/api/v1.0/mail-domains/domainfr/', (route) => { - void route.fulfill({ + await page.route('**/api/v1.0/mail-domains/domainfr/', async (route) => { + await route.fulfill({ json: localMailDomainDomainFr, }); }); - void page.route( + await page.route( '**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**', - (route) => { - void route.fulfill({ + async (route) => { + await route.fulfill({ json: { count: localMailboxFixtures.domainFr.page1.length, next: null, @@ -355,7 +374,11 @@ test.describe('Mail domain create mailbox', () => { ); }; - void interceptRequests(page); + await interceptRequests(page); + + await page.goto('/'); + // Login with a user who has the visibility on the mail domains + await keyCloakSignIn(page, browserName, 'mail-member'); await page .locator('menu') diff --git a/src/frontend/apps/e2e/__tests__/app-desk/mail-domain.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/mail-domain.spec.ts index ab2fec5..ca71b41 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/mail-domain.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/mail-domain.spec.ts @@ -142,11 +142,6 @@ test.describe('Mail domain', () => { }); test.describe('user is administrator or owner', () => { - test.beforeEach(async ({ page, browserName }) => { - await page.goto('/'); - await keyCloakSignIn(page, browserName, 'mail-owner'); - }); - test.describe('mail domain is enabled', () => { const mailDomainsFixtures: MailDomain[] = [ { @@ -215,9 +210,12 @@ test.describe('Mail domain', () => { }, ]; - test('checks if all tabs are visible', async ({ page }) => { + test('checks if all tabs are visible', async ({ page, browserName }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-owner'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -230,9 +228,13 @@ test.describe('Mail domain', () => { test('checks all the elements are visible when domain exist but contains no mailboxes', async ({ page, + browserName, }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-owner'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -248,6 +250,7 @@ test.describe('Mail domain', () => { test('checks all the elements are visible when domain exists and contains 2 pages of mailboxes', async ({ page, + browserName, }) => { const mailboxesFixtures = { domainFr: { @@ -324,6 +327,9 @@ test.describe('Mail domain', () => { await interceptApiCalls(); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-owner'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -360,9 +366,15 @@ test.describe('Mail domain', () => { }, ]; - test('checks expected elements are visible', async ({ page }) => { + test('checks expected elements are visible', async ({ + page, + browserName, + }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-owner'); + await clickOnMailDomainsNavButton(page); await expect(page).toHaveURL(/mail-domains\//); @@ -404,9 +416,15 @@ test.describe('Mail domain', () => { }, ]; - test('checks expected elements are visible', async ({ page }) => { + test('checks expected elements are visible', async ({ + page, + browserName, + }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-owner'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -447,9 +465,15 @@ test.describe('Mail domain', () => { }, ]; - test('checks expected elements are visible', async ({ page }) => { + test('checks expected elements are visible', async ({ + page, + browserName, + }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-owner'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -476,11 +500,6 @@ test.describe('Mail domain', () => { }); test.describe('user is member', () => { - test.beforeEach(async ({ page, browserName }) => { - await page.goto('/'); - await keyCloakSignIn(page, browserName, 'mail-member'); - }); - test.describe('mail domain is enabled', () => { const mailDomainsFixtures: MailDomain[] = [ { @@ -551,9 +570,13 @@ test.describe('Mail domain', () => { test('checks all the elements are visible when domain exist but contains no mailboxes', async ({ page, + browserName, }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-member'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -569,6 +592,7 @@ test.describe('Mail domain', () => { test('checks all the elements are visible when domain exists and contains 2 pages of mailboxes', async ({ page, + browserName, }) => { const mailboxesFixtures = { domainFr: { @@ -645,6 +669,9 @@ test.describe('Mail domain', () => { await interceptApiCalls(); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-member'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -681,9 +708,15 @@ test.describe('Mail domain', () => { }, ]; - test('checks expected elements are visible', async ({ page }) => { + test('checks expected elements are visible', async ({ + page, + browserName, + }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-member'); + await clickOnMailDomainsNavButton(page); await expect(page).toHaveURL(/mail-domains\//); @@ -725,9 +758,15 @@ test.describe('Mail domain', () => { }, ]; - test('checks expected elements are visible', async ({ page }) => { + test('checks expected elements are visible', async ({ + page, + browserName, + }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-member'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); @@ -768,9 +807,15 @@ test.describe('Mail domain', () => { }, ]; - test('checks expected elements are visible', async ({ page }) => { + test('checks expected elements are visible', async ({ + page, + browserName, + }) => { await interceptCommonApiCalls(page, mailDomainsFixtures); + await page.goto('/'); + await keyCloakSignIn(page, browserName, 'mail-member'); + await clickOnMailDomainsNavButton(page); await assertMailDomainUpperElementsAreVisible(page); diff --git a/src/frontend/apps/e2e/__tests__/app-desk/mail-domains.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/mail-domains.spec.ts index e9079aa..5bd09a0 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/mail-domains.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/mail-domains.spec.ts @@ -73,16 +73,14 @@ const mailDomainsFixtures: MailDomain[] = [ test.describe('Mail domains', () => { test.describe('checks all the elements are visible', () => { - test.beforeEach(async ({ page, browserName }) => { + test('checks the sort button', async ({ page, browserName }) => { await page.goto('/'); // The user is a team administrator, so they land on the team page // This allows to prevent the redirection to the mail domains page // to make the '/api/v1.0/mail-domains/?page=1&ordering=created_at' // query at login, which will be cached and not called afterward in tests. await keyCloakSignIn(page, browserName, 'team-administrator-mail-member'); - }); - test('checks the sort button', async ({ page }) => { await page .locator('menu') .first() @@ -128,7 +126,7 @@ test.describe('Mail domains', () => { expect(responseSortDesc.ok()).toBeTruthy(); }); - test('when no mail domain exists', async ({ page }) => { + test('when no mail domain exists', async ({ page, browserName }) => { await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => { await route.fulfill({ json: { @@ -140,6 +138,13 @@ test.describe('Mail domains', () => { }); }); + await page.goto('/'); + // The user is a team administrator, so they land on the team page + // This allows to prevent the redirection to the mail domains page + // to make the '/api/v1.0/mail-domains/?page=1&ordering=created_at' + // query at login, which will be cached and not called afterward in tests. + await keyCloakSignIn(page, browserName, 'team-administrator-mail-member'); + await page .locator('menu') .first() @@ -152,7 +157,7 @@ test.describe('Mail domains', () => { await expect(page.getByText('No domains exist.')).toBeVisible(); }); - test('when 4 mail domains exist', async ({ page }) => { + test('when 4 mail domains exist', async ({ page, browserName }) => { await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => { await route.fulfill({ json: { @@ -164,6 +169,13 @@ test.describe('Mail domains', () => { }); }); + await page.goto('/'); + // The user is a team administrator, so they land on the team page + // This allows to prevent the redirection to the mail domains page + // to make the '/api/v1.0/mail-domains/?page=1&ordering=created_at' + // query at login, which will be cached and not called afterward in tests. + await keyCloakSignIn(page, browserName, 'team-administrator-mail-member'); + await page .locator('menu') .first() diff --git a/src/frontend/apps/e2e/playwright.config.ts b/src/frontend/apps/e2e/playwright.config.ts index e7b19af..8d99414 100644 --- a/src/frontend/apps/e2e/playwright.config.ts +++ b/src/frontend/apps/e2e/playwright.config.ts @@ -9,7 +9,7 @@ const baseURL = `http://localhost:${PORT}`; */ export default defineConfig({ // Timeout per test - timeout: 30 * 1000, + timeout: 10 * 1000, testDir: './__tests__', outputDir: './test-results',