diff --git a/tests/e2e/actions.test.e2e.ts b/tests/e2e/actions.test.e2e.ts index 0aa1c747dc..e9f7db52f2 100644 --- a/tests/e2e/actions.test.e2e.ts +++ b/tests/e2e/actions.test.e2e.ts @@ -20,7 +20,6 @@ const workflow_trigger_notification_text = 'This workflow has a workflow_dispatc test('workflow dispatch present', async ({browser}, workerInfo) => { const context = await load_logged_in_context(browser, workerInfo, 'user2'); - /** @type {import('@playwright/test').Page} */ const page = await context.newPage(); await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0'); @@ -40,7 +39,6 @@ test('workflow dispatch error: missing inputs', async ({browser}, workerInfo) => test.skip(workerInfo.project.name === 'Mobile Safari', 'Flaky behaviour on mobile safari; see https://codeberg.org/forgejo/forgejo/pulls/3334#issuecomment-2033383'); const context = await load_logged_in_context(browser, workerInfo, 'user2'); - /** @type {import('@playwright/test').Page} */ const page = await context.newPage(); await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0'); @@ -62,14 +60,13 @@ test('workflow dispatch success', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Flaky behaviour on mobile safari; see https://codeberg.org/forgejo/forgejo/pulls/3334#issuecomment-2033383'); const context = await load_logged_in_context(browser, workerInfo, 'user2'); - /** @type {import('@playwright/test').Page} */ const page = await context.newPage(); await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0'); await page.locator('#workflow_dispatch_dropdown>button').click(); - await page.type('input[name="inputs[string2]"]', 'abc'); + await page.fill('input[name="inputs[string2]"]', 'abc'); await page.locator('#workflow-dispatch-submit').click(); await expect(page.getByText('Workflow run was successfully requested.')).toBeVisible(); diff --git a/tests/e2e/example.test.e2e.ts b/tests/e2e/example.test.e2e.ts index 90fd9169a4..64818c4557 100644 --- a/tests/e2e/example.test.e2e.ts +++ b/tests/e2e/example.test.e2e.ts @@ -21,10 +21,10 @@ test('Load Homepage', async ({page}) => { test('Register Form', async ({page}, workerInfo) => { const response = await page.goto('/user/sign_up'); expect(response?.status()).toBe(200); // Status OK - await page.type('input[name=user_name]', `e2e-test-${workerInfo.workerIndex}`); - await page.type('input[name=email]', `e2e-test-${workerInfo.workerIndex}@test.com`); - await page.type('input[name=password]', 'test123test123'); - await page.type('input[name=retype]', 'test123test123'); + await page.fill('input[name=user_name]', `e2e-test-${workerInfo.workerIndex}`); + await page.fill('input[name=email]', `e2e-test-${workerInfo.workerIndex}@test.com`); + await page.fill('input[name=password]', 'test123test123'); + await page.fill('input[name=retype]', 'test123test123'); await page.click('form button.ui.primary.button:visible'); // Make sure we routed to the home page. Else login failed. expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); diff --git a/tests/e2e/issue-sidebar.test.e2e.ts b/tests/e2e/issue-sidebar.test.e2e.ts index 422f3ef94e..1e05069e7f 100644 --- a/tests/e2e/issue-sidebar.test.e2e.ts +++ b/tests/e2e/issue-sidebar.test.e2e.ts @@ -4,19 +4,18 @@ // web_src/js/features/repo-issue** // @watch end -import {expect} from '@playwright/test'; +/* eslint playwright/expect-expect: ["error", { "assertFunctionNames": ["check_wip"] }] */ + +import {expect, type Page} from '@playwright/test'; import {test, login_user, login} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); }); -/* eslint-disable playwright/expect-expect */ -// some tests are reported to have no assertions, -// which is not correct, because they use the global helper function test.describe('Pull: Toggle WIP', () => { const prTitle = 'pull5'; - async function toggle_wip_to({page}, should) { + async function toggle_wip_to({page}, should: boolean) { await page.waitForLoadState('domcontentloaded'); if (should) { await page.getByText('Still in progress?').click(); @@ -25,7 +24,7 @@ test.describe('Pull: Toggle WIP', () => { } } - async function check_wip({page}, is) { + async function check_wip({page}, is: boolean) { const elemTitle = 'h1'; const stateLabel = '.issue-state-label'; await page.waitForLoadState('domcontentloaded'); @@ -96,12 +95,11 @@ test.describe('Pull: Toggle WIP', () => { await expect(page.locator('h1')).toContainText(maxLenStr); }); }); -/* eslint-enable playwright/expect-expect */ test('Issue: Labels', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); - async function submitLabels({page}) { + async function submitLabels({page}: {page: Page}) { const submitted = page.waitForResponse('/user2/repo1/issues/labels'); await page.locator('textarea').first().click(); // close via unrelated element await submitted; @@ -199,7 +197,7 @@ test('New Issue: Assignees', async ({browser}, workerInfo) => { // Assign other user (with searchbox) await page.locator('.select-assignees.dropdown').click(); - await page.type('.select-assignees .menu .search input', 'user4'); + await page.fill('.select-assignees .menu .search input', 'user4'); await expect(page.locator('.select-assignees .menu .item').filter({hasText: 'user2'})).toBeHidden(); await expect(page.locator('.select-assignees .menu .item').filter({hasText: 'user4'})).toBeVisible(); await page.locator('.select-assignees .menu .item').filter({hasText: 'user4'}).click(); diff --git a/tests/e2e/markdown-editor.test.e2e.ts b/tests/e2e/markdown-editor.test.e2e.ts index 5db242bb36..4cdf4644f7 100644 --- a/tests/e2e/markdown-editor.test.e2e.ts +++ b/tests/e2e/markdown-editor.test.e2e.ts @@ -29,7 +29,7 @@ test('markdown indentation', async ({browser}, workerInfo) => { // Indent, then unindent first line await textarea.focus(); - await textarea.evaluate((it) => it.setSelectionRange(0, 0)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(0, 0)); await indent.click(); await expect(textarea).toHaveValue(`${tab}* first\n* second\n* third\n* last`); await unindent.click(); @@ -45,7 +45,7 @@ test('markdown indentation', async ({browser}, workerInfo) => { // Subsequently, select a chunk of 2nd and 3rd line and indent both, preserving the cursor position in relation to text await textarea.focus(); - await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('hird'))); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('hird'))); await indent.click(); const lines23 = `* first\n${tab}${tab}* second\n${tab}* third\n* last`; await expect(textarea).toHaveValue(lines23); @@ -60,7 +60,7 @@ test('markdown indentation', async ({browser}, workerInfo) => { // Indent and unindent with cursor at the end of the line await textarea.focus(); - await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond'))); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond'))); await textarea.press('End'); await indent.click(); await expect(textarea).toHaveValue(`* first\n${tab}* second\n* third\n* last`); @@ -69,7 +69,7 @@ test('markdown indentation', async ({browser}, workerInfo) => { // Check that Tab does work after input await textarea.focus(); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Shift+Enter'); // Avoid triggering the prefix continuation feature await textarea.pressSequentially('* least'); await indent.click(); @@ -78,7 +78,7 @@ test('markdown indentation', async ({browser}, workerInfo) => { // Check that partial indents are cleared await textarea.focus(); await textarea.fill(initText); - await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('* second'), it.value.indexOf('* second'))); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.indexOf('* second'), it.value.indexOf('* second'))); await textarea.pressSequentially(' '); await unindent.click(); await expect(textarea).toHaveValue(initText); @@ -99,7 +99,7 @@ test('markdown list continuation', async ({browser}, workerInfo) => { await textarea.fill(initText); // Test continuation of '* ' prefix - await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond'))); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond'))); await textarea.press('End'); await textarea.press('Enter'); await textarea.pressSequentially('middle'); @@ -112,7 +112,7 @@ test('markdown list continuation', async ({browser}, workerInfo) => { await expect(textarea).toHaveValue(`* first\n* second\n${tab}* middle\n${tab}* muddle\n* third\n* last`); // Test breaking in the middle of a line - await textarea.evaluate((it) => it.setSelectionRange(it.value.lastIndexOf('ddle'), it.value.lastIndexOf('ddle'))); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.lastIndexOf('ddle'), it.value.lastIndexOf('ddle'))); await textarea.pressSequentially('tate'); await textarea.press('Enter'); await textarea.pressSequentially('me'); @@ -120,7 +120,7 @@ test('markdown list continuation', async ({browser}, workerInfo) => { // Test not triggering when Shift held await textarea.fill(initText); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Shift+Enter'); await textarea.press('Enter'); await textarea.pressSequentially('...but not least'); @@ -128,28 +128,28 @@ test('markdown list continuation', async ({browser}, workerInfo) => { // Test continuation of ordered list await textarea.fill(`1. one\n2. two`); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Enter'); await textarea.pressSequentially('three'); await expect(textarea).toHaveValue(`1. one\n2. two\n3. three`); // Test continuation of alternative ordered list syntax await textarea.fill(`1) one\n2) two`); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Enter'); await textarea.pressSequentially('three'); await expect(textarea).toHaveValue(`1) one\n2) two\n3) three`); // Test continuation of blockquote await textarea.fill(`> knowledge is power`); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Enter'); await textarea.pressSequentially('france is bacon'); await expect(textarea).toHaveValue(`> knowledge is power\n> france is bacon`); // Test continuation of checklists await textarea.fill(`- [ ] have a problem\n- [x] create a solution`); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Enter'); await textarea.pressSequentially('write a test'); await expect(textarea).toHaveValue(`- [ ] have a problem\n- [x] create a solution\n- [ ] write a test`); @@ -174,7 +174,7 @@ test('markdown list continuation', async ({browser}, workerInfo) => { ]; for (const prefix of prefixes) { await textarea.fill(`${prefix}one`); - await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length)); await textarea.press('Enter'); await textarea.pressSequentially('two'); await expect(textarea).toHaveValue(`${prefix}one\n${prefix}two`); diff --git a/tests/e2e/reaction-selectors.test.e2e.ts b/tests/e2e/reaction-selectors.test.e2e.ts index a52b47e036..3bd54c7881 100644 --- a/tests/e2e/reaction-selectors.test.e2e.ts +++ b/tests/e2e/reaction-selectors.test.e2e.ts @@ -3,14 +3,14 @@ // routers/web/repo/issue.go // @watch end -import {expect} from '@playwright/test'; +import {expect, type Locator} from '@playwright/test'; import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); }); -const assertReactionCounts = (comment, counts) => +const assertReactionCounts = (comment: Locator, counts: unknown) => expect(async () => { await expect(comment.locator('.reactions')).toBeVisible(); @@ -29,7 +29,7 @@ const assertReactionCounts = (comment, counts) => return expect(reactions).toStrictEqual(counts); }).toPass(); -async function toggleReaction(menu, reaction) { +async function toggleReaction(menu: Locator, reaction: string) { await menu.evaluateAll((menus) => menus[0].focus()); await menu.locator('.add-reaction').click(); await menu.locator(`[role=menuitem][data-reaction-content="${reaction}"]`).click(); diff --git a/tests/e2e/repo-code.test.e2e.ts b/tests/e2e/repo-code.test.e2e.ts index d114a9b9c0..d78fa33fe5 100644 --- a/tests/e2e/repo-code.test.e2e.ts +++ b/tests/e2e/repo-code.test.e2e.ts @@ -4,7 +4,7 @@ // services/gitdiff/** // @watch end -import {expect} from '@playwright/test'; +import {expect, type Page} from '@playwright/test'; import {test, login_user, login} from './utils_e2e.ts'; import {accessibilityCheck} from './shared/accessibility.ts'; @@ -12,7 +12,7 @@ test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); }); -async function assertSelectedLines(page, nums) { +async function assertSelectedLines(page: Page, nums: string[]) { const pageAssertions = async () => { expect( await Promise.all((await page.locator('tr.active [data-line-number]').all()).map((line) => line.getAttribute('data-line-number'))), diff --git a/tests/e2e/shared/accessibility.ts b/tests/e2e/shared/accessibility.ts index 6675e0d9eb..1b59d89485 100644 --- a/tests/e2e/shared/accessibility.ts +++ b/tests/e2e/shared/accessibility.ts @@ -3,9 +3,9 @@ import {AxeBuilder} from '@axe-core/playwright'; export async function accessibilityCheck({page}: {page: Page}, includes: string[], excludes: string[], disabledRules: string[]) { // contrast of inline links is still a global issue in Forgejo - disabledRules += 'link-in-text-block'; + disabledRules.push('link-in-text-block'); - let accessibilityScanner = await new AxeBuilder({page}) + let accessibilityScanner = new AxeBuilder({page}) .disableRules(disabledRules); // passing the whole array seems to be not supported, // iterating has the nice side-effectof skipping this if the array is empty diff --git a/tests/e2e/utils_e2e.ts b/tests/e2e/utils_e2e.ts index 89dacce8a4..a52495bcc6 100644 --- a/tests/e2e/utils_e2e.ts +++ b/tests/e2e/utils_e2e.ts @@ -33,8 +33,8 @@ export async function login_user(browser: Browser, workerInfo: TestInfo, user: s expect(response?.status()).toBe(200); // Status OK // Fill out form - await page.type('input[name=user_name]', user); - await page.type('input[name=password]', LOGIN_PASSWORD); + await page.fill('input[name=user_name]', user); + await page.fill('input[name=password]', LOGIN_PASSWORD); await page.click('form button.ui.primary.button:visible'); await page.waitForLoadState(); @@ -48,15 +48,13 @@ export async function login_user(browser: Browser, workerInfo: TestInfo, user: s } export async function load_logged_in_context(browser: Browser, workerInfo: TestInfo, user: string) { - let context; try { - context = await test_context(browser, {storageState: `${ARTIFACTS_PATH}/state-${user}-${workerInfo.workerIndex}.json`}); + return await test_context(browser, {storageState: `${ARTIFACTS_PATH}/state-${user}-${workerInfo.workerIndex}.json`}); } catch (err) { if (err.code === 'ENOENT') { throw new Error(`Could not find state for '${user}'. Did you call login_user(browser, workerInfo, '${user}') in test.beforeAll()?`); } } - return context; } export async function login({browser}: {browser: Browser}, workerInfo: TestInfo) { diff --git a/tests/e2e/webauthn.test.e2e.ts b/tests/e2e/webauthn.test.e2e.ts index c351b6a468..98a2d1c152 100644 --- a/tests/e2e/webauthn.test.e2e.ts +++ b/tests/e2e/webauthn.test.e2e.ts @@ -30,7 +30,6 @@ test('WebAuthn register & login flow', async ({browser, request}, workerInfo) => transport: 'usb', automaticPresenceSimulation: true, isUserVerified: true, - backupEligibility: true, // TODO: this doesn't seem to be available?! }, });