mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-01-10 15:42:16 +01:00
chore(e2e): simplify authentication setup (#6400)
Some checks are pending
/ release (push) Waiting to run
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Some checks are pending
/ release (push) Waiting to run
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Replaced manual login and context loading across tests with Playwright's `test.use` configuration for user authentication. This simplifies test setup, improves readability, and reduces repetition. For #6362 Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6400 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: Julian Schlarb <julian.schlarb@denktmit.de> Co-committed-by: Julian Schlarb <julian.schlarb@denktmit.de>
This commit is contained in:
parent
a2eb249766
commit
68d690b6b9
19 changed files with 327 additions and 254 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -73,6 +73,7 @@ cpu.out
|
|||
/tests/e2e/reports
|
||||
/tests/e2e/test-artifacts
|
||||
/tests/e2e/test-snapshots
|
||||
/tests/e2e/.auth
|
||||
/tests/*.ini
|
||||
/tests/**/*.git/**/*.sample
|
||||
/node_modules
|
||||
|
|
|
@ -250,16 +250,18 @@ test('For anyone', async ({page}) => {
|
|||
If you need a user account, you can use something like:
|
||||
|
||||
~~~js
|
||||
import {test, login_user, login} from './utils_e2e.ts';
|
||||
import {test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2'); // or another user
|
||||
});
|
||||
// reuse user2 token from scope `shared`
|
||||
test.use({user: 'user2', authScope: 'shared'})
|
||||
|
||||
test('For signed users only', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('For signed users only', async ({page}) => {
|
||||
|
||||
})
|
||||
~~~
|
||||
|
||||
users are created in [utils_e2e_test.go](utils_e2e_test.go)
|
||||
|
||||
### Run tests very selectively
|
||||
|
||||
Browser testing can take some time.
|
||||
|
|
|
@ -10,72 +10,61 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, save_visual, load_logged_in_context} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
const workflow_trigger_notification_text = 'This workflow has a workflow_dispatch event trigger.';
|
||||
test.describe('Workflow Authenticated user2', () => {
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('workflow dispatch present', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
test('workflow dispatch present', async ({page}) => {
|
||||
await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0');
|
||||
|
||||
await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0');
|
||||
await expect(page.getByText(workflow_trigger_notification_text)).toBeVisible();
|
||||
|
||||
await expect(page.getByText(workflow_trigger_notification_text)).toBeVisible();
|
||||
const run_workflow_btn = page.locator('#workflow_dispatch_dropdown>button');
|
||||
await expect(run_workflow_btn).toBeVisible();
|
||||
|
||||
const run_workflow_btn = page.locator('#workflow_dispatch_dropdown>button');
|
||||
await expect(run_workflow_btn).toBeVisible();
|
||||
|
||||
const menu = page.locator('#workflow_dispatch_dropdown>.menu');
|
||||
await expect(menu).toBeHidden();
|
||||
await run_workflow_btn.click();
|
||||
await expect(menu).toBeVisible();
|
||||
await save_visual(page);
|
||||
});
|
||||
|
||||
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');
|
||||
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();
|
||||
|
||||
// Remove the required attribute so we can trigger the error message!
|
||||
await page.evaluate(() => {
|
||||
const elem = document.querySelector('input[name="inputs[string2]"]');
|
||||
elem?.removeAttribute('required');
|
||||
const menu = page.locator('#workflow_dispatch_dropdown>.menu');
|
||||
await expect(menu).toBeHidden();
|
||||
await run_workflow_btn.click();
|
||||
await expect(menu).toBeVisible();
|
||||
await save_visual(page);
|
||||
});
|
||||
|
||||
await page.locator('#workflow-dispatch-submit').click();
|
||||
test('dispatch error: missing inputs', async ({page}, testInfo) => {
|
||||
test.skip(testInfo.project.name === 'Mobile Safari', 'Flaky behaviour on mobile safari; see https://codeberg.org/forgejo/forgejo/pulls/3334#issuecomment-2033383');
|
||||
|
||||
await expect(page.getByText('Require value for input "String w/o. default".')).toBeVisible();
|
||||
await save_visual(page);
|
||||
});
|
||||
await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0');
|
||||
|
||||
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');
|
||||
await page.locator('#workflow_dispatch_dropdown>button').click();
|
||||
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
// Remove the required attribute so we can trigger the error message!
|
||||
await page.evaluate(() => {
|
||||
const elem = document.querySelector('input[name="inputs[string2]"]');
|
||||
elem?.removeAttribute('required');
|
||||
});
|
||||
|
||||
await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0');
|
||||
await page.locator('#workflow-dispatch-submit').click();
|
||||
|
||||
await page.locator('#workflow_dispatch_dropdown>button').click();
|
||||
await expect(page.getByText('Require value for input "String w/o. default".')).toBeVisible();
|
||||
await save_visual(page);
|
||||
});
|
||||
|
||||
await page.fill('input[name="inputs[string2]"]', 'abc');
|
||||
await save_visual(page);
|
||||
await page.locator('#workflow-dispatch-submit').click();
|
||||
test('dispatch success', async ({page}, testInfo) => {
|
||||
test.skip(testInfo.project.name === 'Mobile Safari', 'Flaky behaviour on mobile safari; see https://codeberg.org/forgejo/forgejo/pulls/3334#issuecomment-2033383');
|
||||
await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0');
|
||||
|
||||
await expect(page.getByText('Workflow run was successfully requested.')).toBeVisible();
|
||||
await page.locator('#workflow_dispatch_dropdown>button').click();
|
||||
|
||||
await expect(page.locator('.run-list>:first-child .run-list-meta', {hasText: 'now'})).toBeVisible();
|
||||
await save_visual(page);
|
||||
await page.fill('input[name="inputs[string2]"]', 'abc');
|
||||
await save_visual(page);
|
||||
await page.locator('#workflow-dispatch-submit').click();
|
||||
|
||||
await expect(page.getByText('Workflow run was successfully requested.')).toBeVisible();
|
||||
|
||||
await expect(page.locator('.run-list>:first-child .run-list-meta', {hasText: 'now'})).toBeVisible();
|
||||
await save_visual(page);
|
||||
});
|
||||
});
|
||||
|
||||
test('workflow dispatch box not available for unauthenticated users', async ({page}) => {
|
||||
|
|
|
@ -3,21 +3,24 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, save_visual, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Correct link and tooltip', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
test.describe.configure({retries: 2});
|
||||
|
||||
test('Correct link and tooltip', async ({page}, testInfo) => {
|
||||
if (testInfo.retry) {
|
||||
await page.goto('/user2/test_workflows/actions');
|
||||
}
|
||||
|
||||
const searchResponse = page.waitForResponse((resp) => resp.url().includes('/repo/search?') && resp.status() === 200);
|
||||
const response = await page.goto('/?repo-search-query=test_workflows');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
await searchResponse;
|
||||
|
||||
const repoStatus = page.locator('.dashboard-repos .repo-owner-name-list > li:nth-child(1) > a:nth-child(2)');
|
||||
// wait for network activity to cease (so status was loaded in frontend)
|
||||
await page.waitForLoadState('networkidle'); // eslint-disable-line playwright/no-networkidle
|
||||
await expect(repoStatus).toHaveAttribute('href', '/user2/test_workflows/actions', {timeout: 10000});
|
||||
await expect(repoStatus).toHaveAttribute('data-tooltip-content', /^(Error|Failure)$/);
|
||||
await save_visual(page);
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
// @ts-check
|
||||
import {test, expect} from '@playwright/test';
|
||||
import {login_user, save_visual, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {expect} from '@playwright/test';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Change git note', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
test('Change git note', async ({page}) => {
|
||||
let response = await page.goto('/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
|
|
@ -5,14 +5,11 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, save_visual, login_user, login} from './utils_e2e.ts';
|
||||
import {test, save_visual} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Menu accessibility', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('Menu accessibility', async ({page}) => {
|
||||
await page.goto('/user2/repo1/issues/1');
|
||||
await expect(page.getByLabel('user2 reacted eyes. Remove eyes')).toBeVisible();
|
||||
await expect(page.getByLabel('reacted laugh. Remove laugh')).toBeVisible();
|
||||
|
@ -24,9 +21,8 @@ test('Menu accessibility', async ({browser}, workerInfo) => {
|
|||
await expect(page.getByLabel('user1, user2 reacted laugh. Remove laugh')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Hyperlink paste behaviour', async ({browser}, workerInfo) => {
|
||||
test('Hyperlink paste behaviour', async ({page}, workerInfo) => {
|
||||
test.skip(['Mobile Safari', 'Mobile Chrome', 'webkit'].includes(workerInfo.project.name), 'Mobile clients seem to have very weird behaviour with this test, which I cannot confirm with real usage');
|
||||
const page = await login({browser}, workerInfo);
|
||||
await page.goto('/user2/repo1/issues/new');
|
||||
await page.locator('textarea').click();
|
||||
// same URL
|
||||
|
@ -58,8 +54,7 @@ test('Hyperlink paste behaviour', async ({browser}, workerInfo) => {
|
|||
await page.locator('textarea').fill('');
|
||||
});
|
||||
|
||||
test('Always focus edit tab first on edit', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('Always focus edit tab first on edit', async ({page}) => {
|
||||
const response = await page.goto('/user2/repo1/issues/1');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -82,9 +77,8 @@ test('Always focus edit tab first on edit', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('Quote reply', async ({browser}, workerInfo) => {
|
||||
test('Quote reply', async ({page}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name !== 'firefox', 'Uses Firefox specific selection quirks');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/user2/repo1/issues/1');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -157,9 +151,8 @@ test('Quote reply', async ({browser}, workerInfo) => {
|
|||
await editorTextarea.fill('');
|
||||
});
|
||||
|
||||
test('Pull quote reply', async ({browser}, workerInfo) => {
|
||||
test('Pull quote reply', async ({page}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name !== 'firefox', 'Uses Firefox specific selection quirks');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/user2/commitsonpr/pulls/1/files');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
/* eslint playwright/expect-expect: ["error", { "assertFunctionNames": ["check_wip"] }] */
|
||||
|
||||
import {expect, type Page} from '@playwright/test';
|
||||
import {test, save_visual, login_user, login} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test.describe('Pull: Toggle WIP', () => {
|
||||
const prTitle = 'pull5';
|
||||
|
||||
async function toggle_wip_to({page}, should: boolean) {
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
if (should) {
|
||||
|
@ -39,8 +38,7 @@ test.describe('Pull: Toggle WIP', () => {
|
|||
}
|
||||
}
|
||||
|
||||
test.beforeEach(async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test.beforeEach(async ({page}) => {
|
||||
const response = await page.goto('/user2/repo1/pulls/5');
|
||||
expect(response?.status()).toBe(200); // Status OK
|
||||
// ensure original title
|
||||
|
@ -50,9 +48,8 @@ test.describe('Pull: Toggle WIP', () => {
|
|||
await check_wip({page}, false);
|
||||
});
|
||||
|
||||
test('simple toggle', async ({browser}, workerInfo) => {
|
||||
test('simple toggle', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
await page.goto('/user2/repo1/pulls/5');
|
||||
// toggle to WIP
|
||||
await toggle_wip_to({page}, true);
|
||||
|
@ -62,9 +59,8 @@ test.describe('Pull: Toggle WIP', () => {
|
|||
await check_wip({page}, false);
|
||||
});
|
||||
|
||||
test('manual edit', async ({browser}, workerInfo) => {
|
||||
test('manual edit', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
await page.goto('/user2/repo1/pulls/5');
|
||||
// manually edit title to another prefix
|
||||
await page.locator('#issue-title-edit-show').click();
|
||||
|
@ -76,9 +72,8 @@ test.describe('Pull: Toggle WIP', () => {
|
|||
await check_wip({page}, false);
|
||||
});
|
||||
|
||||
test('maximum title length', async ({browser}, workerInfo) => {
|
||||
test('maximum title length', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
await page.goto('/user2/repo1/pulls/5');
|
||||
// check maximum title length is handled gracefully
|
||||
const maxLenStr = prTitle + 'a'.repeat(240);
|
||||
|
@ -96,17 +91,16 @@ test.describe('Pull: Toggle WIP', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('Issue: Labels', async ({browser}, workerInfo) => {
|
||||
test('Issue: Labels', async ({page}, 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}: {page: 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;
|
||||
await page.waitForLoadState();
|
||||
}
|
||||
|
||||
const page = await login({browser}, workerInfo);
|
||||
// select label list in sidebar only
|
||||
const labelList = page.locator('.issue-content-right .labels-list a');
|
||||
const response = await page.goto('/user2/repo1/issues/1');
|
||||
|
@ -144,9 +138,8 @@ test('Issue: Labels', async ({browser}, workerInfo) => {
|
|||
await expect(labelList.filter({hasText: 'label1'})).toBeVisible();
|
||||
});
|
||||
|
||||
test('Issue: Assignees', async ({browser}, workerInfo) => {
|
||||
test('Issue: Assignees', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
// select label list in sidebar only
|
||||
const assigneesList = page.locator('.issue-content-right .assignees.list .selected .item a');
|
||||
|
||||
|
@ -182,9 +175,8 @@ test('Issue: Assignees', async ({browser}, workerInfo) => {
|
|||
await expect(page.locator('.ui.assignees.list .item.no-select')).toBeHidden();
|
||||
});
|
||||
|
||||
test('New Issue: Assignees', async ({browser}, workerInfo) => {
|
||||
test('New Issue: Assignees', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
// select label list in sidebar only
|
||||
const assigneesList = page.locator('.issue-content-right .assignees.list .selected .item');
|
||||
|
||||
|
@ -224,9 +216,8 @@ test('New Issue: Assignees', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('Issue: Milestone', async ({browser}, workerInfo) => {
|
||||
test('Issue: Milestone', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
|
||||
const response = await page.goto('/user2/repo1/issues/1');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
@ -248,9 +239,8 @@ test('Issue: Milestone', async ({browser}, workerInfo) => {
|
|||
await expect(page.locator('.timeline-item.event').last()).toContainText('user2 removed this from the milestone1 milestone');
|
||||
});
|
||||
|
||||
test('New Issue: Milestone', async ({browser}, workerInfo) => {
|
||||
test('New Issue: Milestone', async ({page}, 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');
|
||||
const page = await login({browser}, workerInfo);
|
||||
|
||||
const response = await page.goto('/user2/repo1/issues/new');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
|
|
@ -5,21 +5,16 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, save_visual, load_logged_in_context, login_user} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Markdown image preview behaviour', async ({browser}, workerInfo) => {
|
||||
test('Markdown image preview behaviour', async ({page}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Flaky behaviour on mobile safari;');
|
||||
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
|
||||
// Editing the root README.md file for image preview
|
||||
const editPath = '/user2/repo1/src/branch/master/README.md';
|
||||
|
||||
const page = await context.newPage();
|
||||
const response = await page.goto(editPath, {waitUntil: 'domcontentloaded'});
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -43,12 +38,9 @@ test('Markdown image preview behaviour', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('markdown indentation', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
|
||||
test('markdown indentation', async ({page}) => {
|
||||
const initText = `* first\n* second\n* third\n* last`;
|
||||
|
||||
const page = await context.newPage();
|
||||
const response = await page.goto('/user2/repo1/issues/new');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -116,12 +108,9 @@ test('markdown indentation', async ({browser}, workerInfo) => {
|
|||
await expect(textarea).toHaveValue(initText);
|
||||
});
|
||||
|
||||
test('markdown list continuation', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
|
||||
test('markdown list continuation', async ({page}) => {
|
||||
const initText = `* first\n* second\n* third\n* last`;
|
||||
|
||||
const page = await context.newPage();
|
||||
const response = await page.goto('/user2/repo1/issues/new');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -213,10 +202,7 @@ test('markdown list continuation', async ({browser}, workerInfo) => {
|
|||
}
|
||||
});
|
||||
|
||||
test('markdown insert table', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
|
||||
const page = await context.newPage();
|
||||
test('markdown insert table', async ({page}) => {
|
||||
const response = await page.goto('/user2/repo1/issues/new');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
|
|
@ -5,16 +5,13 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, save_visual, login_user, login} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
import {validate_form} from './shared/forms.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('org team settings', async ({browser}, workerInfo) => {
|
||||
test('org team settings', async ({page}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/org/org3/teams/team1/edit');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, save_visual, login_user, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
test('Follow actions', async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Follow actions', async ({page}) => {
|
||||
await page.goto('/user1');
|
||||
|
||||
// Check if following and then unfollowing works.
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
// @watch end
|
||||
|
||||
import {expect, type Locator} from '@playwright/test';
|
||||
import {test, save_visual, login_user, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
const assertReactionCounts = (comment: Locator, counts: unknown) =>
|
||||
expect(async () => {
|
||||
|
@ -26,6 +24,7 @@ const assertReactionCounts = (comment: Locator, counts: unknown) =>
|
|||
]),
|
||||
),
|
||||
);
|
||||
// eslint-disable-next-line playwright/no-standalone-expect
|
||||
return expect(reactions).toStrictEqual(counts);
|
||||
}).toPass();
|
||||
|
||||
|
@ -35,10 +34,7 @@ async function toggleReaction(menu: Locator, reaction: string) {
|
|||
await menu.locator(`[role=menuitem][data-reaction-content="${reaction}"]`).click();
|
||||
}
|
||||
|
||||
test('Reaction Selectors', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
|
||||
test('Reaction Selectors', async ({page}) => {
|
||||
const response = await page.goto('/user2/repo1/issues/1');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
|
|
@ -9,24 +9,18 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, save_visual, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
import {validate_form} from './shared/forms.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test.describe.configure({
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
test('External Release Attachments', async ({browser, isMobile}, workerInfo) => {
|
||||
test('External Release Attachments', async ({page, isMobile}) => {
|
||||
test.skip(isMobile);
|
||||
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
/** @type {import('@playwright/test').Page} */
|
||||
const page = await context.newPage();
|
||||
|
||||
// Click "New Release"
|
||||
await page.goto('/user2/repo2/releases');
|
||||
await page.click('.button.small.primary');
|
||||
|
|
|
@ -5,13 +5,9 @@
|
|||
// @watch end
|
||||
|
||||
import {expect, type Page} from '@playwright/test';
|
||||
import {test, save_visual, login_user, login} from './utils_e2e.ts';
|
||||
import {save_visual, test} from './utils_e2e.ts';
|
||||
import {accessibilityCheck} from './shared/accessibility.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
|
||||
async function assertSelectedLines(page: Page, nums: string[]) {
|
||||
const pageAssertions = async () => {
|
||||
expect(
|
||||
|
@ -81,20 +77,23 @@ test('Readable diff', async ({page}, workerInfo) => {
|
|||
}
|
||||
});
|
||||
|
||||
test('Username highlighted in commits', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
await page.goto('/user2/mentions-highlighted/commits/branch/main');
|
||||
// check first commit
|
||||
await page.getByRole('link', {name: 'A commit message which'}).click();
|
||||
await expect(page.getByRole('link', {name: '@user2'})).toHaveCSS('background-color', /(.*)/);
|
||||
await expect(page.getByRole('link', {name: '@user1'})).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
await accessibilityCheck({page}, ['.commit-header'], [], []);
|
||||
await save_visual(page);
|
||||
// check second commit
|
||||
await page.goto('/user2/mentions-highlighted/commits/branch/main');
|
||||
await page.locator('tbody').getByRole('link', {name: 'Another commit which mentions'}).click();
|
||||
await expect(page.getByRole('link', {name: '@user2'})).toHaveCSS('background-color', /(.*)/);
|
||||
await expect(page.getByRole('link', {name: '@user1'})).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
await accessibilityCheck({page}, ['.commit-header'], [], []);
|
||||
await save_visual(page);
|
||||
test.describe('As authenticated user', () => {
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Username highlighted in commits', async ({page}) => {
|
||||
await page.goto('/user2/mentions-highlighted/commits/branch/main');
|
||||
// check first commit
|
||||
await page.getByRole('link', {name: 'A commit message which'}).click();
|
||||
await expect(page.getByRole('link', {name: '@user2'})).toHaveCSS('background-color', /(.*)/);
|
||||
await expect(page.getByRole('link', {name: '@user1'})).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
await accessibilityCheck({page}, ['.commit-header'], [], []);
|
||||
await save_visual(page);
|
||||
// check second commit
|
||||
await page.goto('/user2/mentions-highlighted/commits/branch/main');
|
||||
await page.locator('tbody').getByRole('link', {name: 'Another commit which mentions'}).click();
|
||||
await expect(page.getByRole('link', {name: '@user2'})).toHaveCSS('background-color', /(.*)/);
|
||||
await expect(page.getByRole('link', {name: '@user1'})).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
await accessibilityCheck({page}, ['.commit-header'], [], []);
|
||||
await save_visual(page);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, save_visual, login_user, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {test, save_visual, test_context} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(({browser}, workerInfo) => login_user(browser, workerInfo, 'user2'));
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('Migration Progress Page', async ({page: unauthedPage, browser}, workerInfo) => {
|
||||
test('Migration Progress Page', async ({page, browser}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Flaky actionability checks on Mobile Safari');
|
||||
|
||||
const page = await (await load_logged_in_context(browser, workerInfo, 'user2')).newPage();
|
||||
|
||||
expect((await page.goto('/user2/invalidrepo'))?.status(), 'repo should not exist yet').toBe(404);
|
||||
|
||||
await page.goto('/repo/migrate?service_type=1');
|
||||
|
@ -23,10 +21,12 @@ test('Migration Progress Page', async ({page: unauthedPage, browser}, workerInfo
|
|||
await form.locator('button.primary').click({timeout: 5000});
|
||||
await expect(page).toHaveURL('user2/invalidrepo');
|
||||
await save_visual(page);
|
||||
// page screenshot of unauthedPage is checked automatically after the test
|
||||
// page screenshot of unauthenticatedPage is checked automatically after the test
|
||||
|
||||
expect((await unauthedPage.goto('/user2/invalidrepo'))?.status(), 'public migration page should be accessible').toBe(200);
|
||||
await expect(unauthedPage.locator('#repo_migrating_progress')).toBeVisible();
|
||||
const ctx = await test_context(browser);
|
||||
const unauthenticatedPage = await ctx.newPage();
|
||||
expect((await unauthenticatedPage.goto('/user2/invalidrepo'))?.status(), 'public migration page should be accessible').toBe(200);
|
||||
await expect(unauthenticatedPage.locator('#repo_migrating_progress')).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
await expect(page.locator('#repo_migrating_failed')).toBeVisible();
|
||||
|
|
|
@ -4,15 +4,12 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, dynamic_id, save_visual, login_user, login} from './utils_e2e.ts';
|
||||
import {test, dynamic_id, save_visual} from './utils_e2e.ts';
|
||||
import {validate_form} from './shared/forms.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('New repo: invalid', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('New repo: invalid', async ({page}) => {
|
||||
const response = await page.goto('/repo/create');
|
||||
expect(response?.status()).toBe(200);
|
||||
// check that relevant form content is hidden or available
|
||||
|
@ -28,8 +25,7 @@ test('New repo: invalid', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('New repo: initialize', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('New repo: initialize', async ({page}, workerInfo) => {
|
||||
const response = await page.goto('/repo/create');
|
||||
expect(response?.status()).toBe(200);
|
||||
// check that relevant form content is hidden or available
|
||||
|
@ -62,8 +58,7 @@ test('New repo: initialize', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('New repo: initialize later', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('New repo: initialize later', async ({page}) => {
|
||||
const response = await page.goto('/repo/create');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -97,9 +92,8 @@ test('New repo: initialize later', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('New repo: from template', async ({browser}, workerInfo) => {
|
||||
test('New repo: from template', async ({page}, workerInfo) => {
|
||||
test.skip(['Mobile Safari', 'webkit'].includes(workerInfo.project.name), 'WebKit browsers seem to have CORS issues with localhost here.');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/repo/create');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -114,8 +108,7 @@ test('New repo: from template', async ({browser}, workerInfo) => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test('New repo: label set', async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('New repo: label set', async ({page}) => {
|
||||
await page.goto('/repo/create');
|
||||
|
||||
const reponame = dynamic_id();
|
||||
|
|
|
@ -7,16 +7,13 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, save_visual, login_user, login} from './utils_e2e.ts';
|
||||
import {test, save_visual} from './utils_e2e.ts';
|
||||
import {validate_form} from './shared/forms.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
test.use({user: 'user2'});
|
||||
|
||||
test('repo webhook settings', async ({browser}, workerInfo) => {
|
||||
test('repo webhook settings', async ({page}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/user2/repo1/settings/hooks/forgejo/new');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -35,9 +32,8 @@ test('repo webhook settings', async ({browser}, workerInfo) => {
|
|||
});
|
||||
|
||||
test.describe('repo branch protection settings', () => {
|
||||
test('form', async ({browser}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const page = await login({browser}, workerInfo);
|
||||
test('form', async ({page}, {project}) => {
|
||||
test.skip(project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const response = await page.goto('/user2/repo1/settings/branches/edit');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
|
@ -56,8 +52,7 @@ test.describe('repo branch protection settings', () => {
|
|||
await save_visual(page);
|
||||
});
|
||||
|
||||
test.afterEach(async ({browser}, workerInfo) => {
|
||||
const page = await login({browser}, workerInfo);
|
||||
test.afterEach(async ({page}) => {
|
||||
// delete the rule for the next test
|
||||
await page.goto('/user2/repo1/settings/branches/');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
|
|
@ -5,19 +5,12 @@
|
|||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, load_logged_in_context} from './utils_e2e.ts';
|
||||
import {test} from './utils_e2e.ts';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
|
||||
test.describe('desktop viewport', () => {
|
||||
test.use({viewport: {width: 1920, height: 300}});
|
||||
|
||||
test('Settings button on right of repo header', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
test.describe('desktop viewport as user 2', () => {
|
||||
test.use({user: 'user2', viewport: {width: 1920, height: 300}});
|
||||
|
||||
test('Settings button on right of repo header', async ({page}) => {
|
||||
await page.goto('/user2/repo1');
|
||||
|
||||
const settingsBtn = page.locator('.overflow-menu-items>#settings-btn');
|
||||
|
@ -27,24 +20,7 @@ test.describe('desktop viewport', () => {
|
|||
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('Settings button on right of repo header also when add more button is shown', async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user12');
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user12');
|
||||
const page = await context.newPage();
|
||||
|
||||
await page.goto('/user12/repo10');
|
||||
|
||||
const settingsBtn = page.locator('.overflow-menu-items>#settings-btn');
|
||||
await expect(settingsBtn).toBeVisible();
|
||||
await expect(settingsBtn).toHaveClass(/right/);
|
||||
|
||||
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('Settings button on right of org header', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
|
||||
test('Settings button on right of org header', async ({page}) => {
|
||||
await page.goto('/org3');
|
||||
|
||||
const settingsBtn = page.locator('.overflow-menu-items>#settings-btn');
|
||||
|
@ -53,6 +29,24 @@ test.describe('desktop viewport', () => {
|
|||
|
||||
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('desktop viewport as user12', () => {
|
||||
test.use({user: 'user12', viewport: {width: 1920, height: 300}});
|
||||
|
||||
test('Settings button on right of repo header also when add more button is shown', async ({page}) => {
|
||||
await page.goto('/user12/repo10');
|
||||
|
||||
const settingsBtn = page.locator('.overflow-menu-items>#settings-btn');
|
||||
await expect(settingsBtn).toBeVisible();
|
||||
await expect(settingsBtn).toHaveClass(/right/);
|
||||
|
||||
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('desktop viewport, unauthenticated', () => {
|
||||
test.use({viewport: {width: 1920, height: 300}});
|
||||
|
||||
test('User overview overflow menu should not be influenced', async ({page}) => {
|
||||
await page.goto('/user2');
|
||||
|
@ -64,12 +58,9 @@ test.describe('desktop viewport', () => {
|
|||
});
|
||||
|
||||
test.describe('small viewport', () => {
|
||||
test.use({viewport: {width: 800, height: 300}});
|
||||
|
||||
test('Settings button in overflow menu of repo header', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
test.use({user: 'user2', viewport: {width: 800, height: 300}});
|
||||
|
||||
test('Settings button in overflow menu of repo header', async ({page}) => {
|
||||
await page.goto('/user2/repo1');
|
||||
|
||||
await expect(page.locator('.overflow-menu-items>#settings-btn')).toHaveCount(0);
|
||||
|
@ -89,10 +80,7 @@ test.describe('small viewport', () => {
|
|||
expect(Array.from(new Set(items))).toHaveLength(items.length);
|
||||
});
|
||||
|
||||
test('Settings button in overflow menu of org header', async ({browser}, workerInfo) => {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
const page = await context.newPage();
|
||||
|
||||
test('Settings button in overflow menu of org header', async ({page}) => {
|
||||
await page.goto('/org3');
|
||||
|
||||
await expect(page.locator('.overflow-menu-items>#settings-btn')).toHaveCount(0);
|
||||
|
@ -111,6 +99,10 @@ test.describe('small viewport', () => {
|
|||
const items = shownItems.concat(overflowItems);
|
||||
expect(Array.from(new Set(items))).toHaveLength(items.length);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('small viewport, unauthenticated', () => {
|
||||
test.use({viewport: {width: 800, height: 300}});
|
||||
|
||||
test('User overview overflow menu should not be influenced', async ({page}) => {
|
||||
await page.goto('/user2');
|
||||
|
|
|
@ -1,9 +1,31 @@
|
|||
import {expect, test as baseTest, type Browser, type BrowserContextOptions, type APIRequestContext, type TestInfo, type Page} from '@playwright/test';
|
||||
|
||||
export const test = baseTest.extend({
|
||||
context: async ({browser}, use) => {
|
||||
return use(await test_context(browser));
|
||||
import * as path from 'node:path';
|
||||
|
||||
const AUTH_PATH = 'tests/e2e/.auth';
|
||||
|
||||
type AuthScope = 'logout' | 'shared' | 'webauthn';
|
||||
|
||||
export type TestOptions = {
|
||||
forEachTest: void
|
||||
user: string | null;
|
||||
authScope: AuthScope;
|
||||
};
|
||||
|
||||
export const test = baseTest.extend<TestOptions>({
|
||||
context: async ({browser, user, authScope, contextOptions}, use, {project}) => {
|
||||
if (user && authScope) {
|
||||
const browserName = project.name.toLowerCase().replace(' ', '-');
|
||||
contextOptions.storageState = path.join(AUTH_PATH, `state-${browserName}-${user}-${authScope}.json`);
|
||||
} else {
|
||||
// if no user is given, ensure to have clean state
|
||||
contextOptions.storageState = {cookies: [], origins: []};
|
||||
}
|
||||
|
||||
return use(await test_context(browser, contextOptions));
|
||||
},
|
||||
user: null,
|
||||
authScope: 'shared',
|
||||
// see https://playwright.dev/docs/test-fixtures#adding-global-beforeeachaftereach-hooks
|
||||
forEachTest: [async ({page}, use) => {
|
||||
await use();
|
||||
|
@ -15,7 +37,7 @@ export const test = baseTest.extend({
|
|||
}, {auto: true}],
|
||||
});
|
||||
|
||||
async function test_context(browser: Browser, options?: BrowserContextOptions) {
|
||||
export async function test_context(browser: Browser, options?: BrowserContextOptions) {
|
||||
const context = await browser.newContext(options);
|
||||
|
||||
context.on('page', (page) => {
|
||||
|
|
|
@ -5,17 +5,27 @@ package e2e
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
modules_session "code.gitea.io/gitea/modules/session"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -25,6 +35,8 @@ func onForgejoRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare .
|
|||
if len(prepare) == 0 || prepare[0] {
|
||||
defer tests.PrepareTestEnv(t, 1)()
|
||||
}
|
||||
createSessions(t)
|
||||
|
||||
s := http.Server{
|
||||
Handler: testE2eWebRoutes,
|
||||
}
|
||||
|
@ -64,3 +76,118 @@ func onForgejoRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...
|
|||
callback(t.(*testing.T), u)
|
||||
}, prepare...)
|
||||
}
|
||||
|
||||
func createSessions(t testing.TB) {
|
||||
t.Helper()
|
||||
// copied from playwright.config.ts
|
||||
browsers := []string{
|
||||
"chromium",
|
||||
"firefox",
|
||||
"webkit",
|
||||
"Mobile Chrome",
|
||||
"Mobile Safari",
|
||||
}
|
||||
scopes := []string{
|
||||
"shared",
|
||||
}
|
||||
users := []string{
|
||||
"user1",
|
||||
"user2",
|
||||
"user12",
|
||||
"user40",
|
||||
}
|
||||
|
||||
authState := filepath.Join(filepath.Dir(setting.AppPath), "tests", "e2e", ".auth")
|
||||
err := os.RemoveAll(authState)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = os.MkdirAll(authState, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
createSessionCookie := stateHelper(t)
|
||||
|
||||
for _, user := range users {
|
||||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: strings.ToLower(user)})
|
||||
for _, browser := range browsers {
|
||||
for _, scope := range scopes {
|
||||
stateFile := strings.ReplaceAll(strings.ToLower(fmt.Sprintf("state-%s-%s-%s.json", browser, user, scope)), " ", "-")
|
||||
createSessionCookie(filepath.Join(authState, stateFile), u)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stateHelper(t testing.TB) func(stateFile string, user *user_model.User) {
|
||||
type Cookie struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Domain string `json:"domain"`
|
||||
Path string `json:"path"`
|
||||
Expires int `json:"expires"`
|
||||
HTTPOnly bool `json:"httpOnly"`
|
||||
Secure bool `json:"secure"`
|
||||
SameSite string `json:"sameSite"`
|
||||
}
|
||||
|
||||
type BrowserState struct {
|
||||
Cookies []Cookie `json:"cookies"`
|
||||
Origins []string `json:"origins"`
|
||||
}
|
||||
|
||||
options := session.Options{
|
||||
Provider: setting.SessionConfig.Provider,
|
||||
ProviderConfig: setting.SessionConfig.ProviderConfig,
|
||||
CookieName: setting.SessionConfig.CookieName,
|
||||
CookiePath: setting.SessionConfig.CookiePath,
|
||||
Gclifetime: setting.SessionConfig.Gclifetime,
|
||||
Maxlifetime: setting.SessionConfig.Maxlifetime,
|
||||
Secure: setting.SessionConfig.Secure,
|
||||
SameSite: setting.SessionConfig.SameSite,
|
||||
Domain: setting.SessionConfig.Domain,
|
||||
}
|
||||
|
||||
opt := session.PrepareOptions([]session.Options{options})
|
||||
|
||||
vsp := modules_session.VirtualSessionProvider{}
|
||||
err := vsp.Init(opt.Maxlifetime, opt.ProviderConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
return func(stateFile string, user *user_model.User) {
|
||||
buf := make([]byte, opt.IDLength/2)
|
||||
_, err = rand.Read(buf)
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionID := hex.EncodeToString(buf)
|
||||
|
||||
s, err := vsp.Read(sessionID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Set("uid", user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Release()
|
||||
require.NoError(t, err)
|
||||
|
||||
state := BrowserState{
|
||||
Cookies: []Cookie{
|
||||
{
|
||||
Name: opt.CookieName,
|
||||
Value: sessionID,
|
||||
Domain: setting.Domain,
|
||||
Path: "/",
|
||||
Expires: -1,
|
||||
HTTPOnly: true,
|
||||
Secure: false,
|
||||
SameSite: "Lax",
|
||||
},
|
||||
},
|
||||
Origins: []string{},
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = os.WriteFile(stateFile, jsonData, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue