chore: unflake auth e2e tests

This commit is contained in:
Alessio Gravili
2024-03-20 23:28:56 -04:00
parent d511e80b01
commit 5f572dbd04
5 changed files with 46 additions and 23 deletions

View File

@@ -51,7 +51,8 @@ module.exports = {
) { ) {
context.report({ context.report({
node: node.callee.property, node: node.callee.property,
message: 'Non-retryable assertion used in Playwright test: "{{ assertion }}"', message:
'Non-retryable, flaky assertion used in Playwright test: "{{ assertion }}". Those need to be wrapped in expect.poll or expect.toPass.',
data: { data: {
assertion: node.callee.property.name, assertion: node.callee.property.name,
}, },

View File

@@ -63,7 +63,8 @@ module.exports = {
'jest/require-top-level-describe': 'off', 'jest/require-top-level-describe': 'off',
'jest-dom/prefer-to-have-attribute': 'off', 'jest-dom/prefer-to-have-attribute': 'off',
'playwright/prefer-web-first-assertions': 'error', 'playwright/prefer-web-first-assertions': 'error',
'payload/no-non-retryable-assertions': 'error', // Enable the no-non-retryable-assertions rule ONLY for hunting for flakes
// 'payload/no-non-retryable-assertions': 'error',
}, },
}, },
{ {

View File

@@ -103,12 +103,19 @@ describe('auth', () => {
await page.locator('#field-enableAPIKey').click() await page.locator('#field-enableAPIKey').click()
// assert that the value is set // assert that the value is set
const apiKey = await page.locator('#apiKey').inputValue() const apiKeyLocator = page.locator('#apiKey')
expect(apiKey).toBeDefined() await expect
.poll(async () => await apiKeyLocator.inputValue(), { timeout: 45000 })
.toBeDefined()
await saveDocAndAssert(page) await saveDocAndAssert(page)
expect(await page.locator('#apiKey').inputValue()).toStrictEqual(apiKey) await expect(async () => {
const apiKey = await apiKeyLocator.inputValue()
expect(await page.locator('#apiKey').inputValue()).toStrictEqual(apiKey)
}).toPass({
timeout: 45000,
})
}) })
test('should disable api key', async () => { test('should disable api key', async () => {
@@ -123,14 +130,18 @@ describe('auth', () => {
await saveDocAndAssert(page) await saveDocAndAssert(page)
// use the api key in a fetch to assert that it is disabled // use the api key in a fetch to assert that it is disabled
const response = await fetch(`${apiURL}/${apiKeysSlug}/me`, { await expect(async () => {
headers: { const response = await fetch(`${apiURL}/${apiKeysSlug}/me`, {
...headers, headers: {
Authorization: `${slug} API-Key ${user.apiKey}`, ...headers,
}, Authorization: `${slug} API-Key ${user.apiKey}`,
}).then((res) => res.json()) },
}).then((res) => res.json())
expect(response.user).toBeNull() expect(response.user).toBeNull()
}).toPass({
timeout: 45000,
})
}) })
}) })
}) })

View File

@@ -42,7 +42,7 @@ export async function delayNetwork({
context: BrowserContext context: BrowserContext
delay: 'Fast 3G' | 'Slow 3G' | 'Slow 4G' delay: 'Fast 3G' | 'Slow 3G' | 'Slow 4G'
page: Page page: Page
}): Promise<void> { }) {
const cdpSession = await context.newCDPSession(page) const cdpSession = await context.newCDPSession(page)
await cdpSession.send('Network.emulateNetworkConditions', { await cdpSession.send('Network.emulateNetworkConditions', {
@@ -91,8 +91,7 @@ export async function saveDocHotkeyAndAssert(page: Page): Promise<void> {
export async function saveDocAndAssert(page: Page, selector = '#action-save'): Promise<void> { export async function saveDocAndAssert(page: Page, selector = '#action-save'): Promise<void> {
await page.click(selector, { delay: 100 }) await page.click(selector, { delay: 100 })
await expect(page.locator('.Toastify')).toContainText('successfully') await expect(page.locator('.Toastify')).toContainText('successfully')
await wait(500) await expect.poll(() => page.url(), { timeout: 45000 }).not.toContain('create')
expect(page.url()).not.toContain('create')
} }
export async function openNav(page: Page): Promise<void> { export async function openNav(page: Page): Promise<void> {
@@ -135,13 +134,24 @@ export function exactText(text: string) {
return new RegExp(`^${text}$`) return new RegExp(`^${text}$`)
} }
export const checkPageTitle = async (page: Page, title: string) => export const checkPageTitle = async (page: Page, title: string) => {
expect(await page.locator('.doc-header__title.render-title')?.first()?.innerText()).toBe(title) await expect
.poll(async () => await page.locator('.doc-header__title.render-title')?.first()?.innerText(), {
timeout: 45000,
})
.toBe(title)
}
export const checkBreadcrumb = async (page: Page, text: string) => export const checkBreadcrumb = async (page: Page, text: string) => {
expect(await page.locator('.step-nav.app-header__step-nav .step-nav__last')?.innerText()).toBe( await expect
text, .poll(
) async () => await page.locator('.step-nav.app-header__step-nav .step-nav__last')?.innerText(),
{
timeout: 45000,
},
)
.toBe(text)
}
export const selectTableRow = async (page: Page, title: string): Promise<void> => { export const selectTableRow = async (page: Page, title: string): Promise<void> => {
const selector = `tbody tr:has-text("${title}") .select-row__checkbox input[type=checkbox]` const selector = `tbody tr:has-text("${title}") .select-row__checkbox input[type=checkbox]`

View File

@@ -4,14 +4,14 @@ export default defineConfig({
// Look for test files in the "test" directory, relative to this configuration file // Look for test files in the "test" directory, relative to this configuration file
testDir: '', testDir: '',
testMatch: '*e2e.spec.ts', testMatch: '*e2e.spec.ts',
timeout: 180000, // 3 minutes timeout: 240000, // 4 minutes
use: { use: {
screenshot: 'only-on-failure', screenshot: 'only-on-failure',
trace: 'retain-on-failure', trace: 'retain-on-failure',
video: 'retain-on-failure', video: 'retain-on-failure',
}, },
expect: { expect: {
timeout: 45000, timeout: 60000,
}, },
workers: 16, workers: 16,
}) })