From 3a3416c0699db0e5ffc14cbdd94f081d2c1e36c0 Mon Sep 17 00:00:00 2001 From: Anbraten Date: Fri, 8 Nov 2024 09:55:54 +0100 Subject: [PATCH 01/16] Migrate playwright to typescript --- playwright.config.ts | 6 +++--- tests/e2e/README.md | 8 ++++---- .../{actions.test.e2e.js => actions.test.e2e.ts} | 4 +--- tests/e2e/changes.go | 2 +- ...st.e2e.js => dashboard-ci-status.test.e2e.ts} | 4 +--- tests/e2e/e2e_test.go | 2 +- .../{example.test.e2e.js => example.test.e2e.ts} | 4 +--- .../{explore.test.e2e.js => explore.test.e2e.ts} | 3 +-- ...ent.test.e2e.js => issue-comment.test.e2e.ts} | 4 +--- ...bar.test.e2e.js => issue-sidebar.test.e2e.ts} | 4 +--- ...r.test.e2e.js => markdown-editor.test.e2e.ts} | 4 +--- .../{markup.test.e2e.js => markup.test.e2e.ts} | 4 +--- ...ings.test.e2e.js => org-settings.test.e2e.ts} | 6 ++---- ...s.test.e2e.js => profile_actions.test.e2e.ts} | 4 +--- ...est.e2e.js => reaction-selectors.test.e2e.ts} | 4 +--- .../{release.test.e2e.js => release.test.e2e.ts} | 6 ++---- ...po-code.test.e2e.js => repo-code.test.e2e.ts} | 4 +--- ....test.e2e.js => repo-commitgraph.test.e2e.ts} | 4 +--- ...rate.test.e2e.js => repo-migrate.test.e2e.ts} | 4 +--- ...ngs.test.e2e.js => repo-settings.test.e2e.ts} | 6 ++---- ...po-wiki.test.e2e.js => repo-wiki.test.e2e.ts} | 4 +--- ....e2e.js => right-settings-button.test.e2e.ts} | 4 +--- tests/e2e/shared/{forms.js => forms.ts} | 5 ++--- tests/e2e/{utils_e2e.js => utils_e2e.ts} | 16 ++++++++-------- ...webauthn.test.e2e.js => webauthn.test.e2e.ts} | 5 ++--- 25 files changed, 42 insertions(+), 79 deletions(-) rename tests/e2e/{actions.test.e2e.js => actions.test.e2e.ts} (99%) rename tests/e2e/{dashboard-ci-status.test.e2e.js => dashboard-ci-status.test.e2e.ts} (97%) rename tests/e2e/{example.test.e2e.js => example.test.e2e.ts} (96%) rename tests/e2e/{explore.test.e2e.js => explore.test.e2e.ts} (96%) rename tests/e2e/{issue-comment.test.e2e.js => issue-comment.test.e2e.ts} (99%) rename tests/e2e/{issue-sidebar.test.e2e.js => issue-sidebar.test.e2e.ts} (99%) rename tests/e2e/{markdown-editor.test.e2e.js => markdown-editor.test.e2e.ts} (99%) rename tests/e2e/{markup.test.e2e.js => markup.test.e2e.ts} (92%) rename tests/e2e/{org-settings.test.e2e.js => org-settings.test.e2e.ts} (89%) rename tests/e2e/{profile_actions.test.e2e.js => profile_actions.test.e2e.ts} (98%) rename tests/e2e/{reaction-selectors.test.e2e.js => reaction-selectors.test.e2e.ts} (99%) rename tests/e2e/{release.test.e2e.js => release.test.e2e.ts} (97%) rename tests/e2e/{repo-code.test.e2e.js => repo-code.test.e2e.ts} (99%) rename tests/e2e/{repo-commitgraph.test.e2e.js => repo-commitgraph.test.e2e.ts} (98%) rename tests/e2e/{repo-migrate.test.e2e.js => repo-migrate.test.e2e.ts} (98%) rename tests/e2e/{repo-settings.test.e2e.js => repo-settings.test.e2e.ts} (95%) rename tests/e2e/{repo-wiki.test.e2e.js => repo-wiki.test.e2e.ts} (94%) rename tests/e2e/{right-settings-button.test.e2e.js => right-settings-button.test.e2e.ts} (99%) rename tests/e2e/shared/{forms.js => forms.ts} (92%) rename tests/e2e/{utils_e2e.js => utils_e2e.ts} (80%) rename tests/e2e/{webauthn.test.e2e.js => webauthn.test.e2e.ts} (94%) diff --git a/playwright.config.ts b/playwright.config.ts index 194f7f7d36..625dc3bc69 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,4 @@ -import {devices} from '@playwright/test'; +import {devices, type PlaywrightTestConfig} from '@playwright/test'; const BASE_URL = process.env.GITEA_URL?.replace?.(/\/$/g, '') || 'http://localhost:3000'; @@ -8,7 +8,7 @@ const BASE_URL = process.env.GITEA_URL?.replace?.(/\/$/g, '') || 'http://localho */ export default { testDir: './tests/e2e/', - testMatch: /.*\.test\.e2e\.js/, // Match any .test.e2e.js files + testMatch: /.*\.test\.e2e\.ts/, // Match any .test.e2e.js files // you can adjust this value locally to match your machine's power, // or pass `--workers x` to playwright @@ -99,4 +99,4 @@ export default { outputDir: 'tests/e2e/test-artifacts/', /* Folder for test artifacts such as screenshots, videos, traces, etc. */ snapshotDir: 'tests/e2e/test-snapshots/', -}; +} satisfies PlaywrightTestConfig; diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 36b9a187c3..d20f2cf633 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -77,7 +77,7 @@ and playwright to perform tests on it. > (e.g. when only creating new content), > or that they restore the initial state for the next browser run. -#### With the playwright UI: +#### With the playwright UI: Playwright ships with an integrated UI mode which allows you to run individual tests and to debug them by seeing detailed traces of what playwright does. @@ -90,7 +90,7 @@ npx playwright test --ui #### Running individual tests ``` -npx playwright test actions.test.e2e.js:9 +npx playwright test actions.test.e2e.ts:9 ``` First, specify the complete test filename, @@ -145,7 +145,7 @@ TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgr ### Running individual tests -Example command to run `example.test.e2e.js` test file: +Example command to run `example.test.e2e.ts` test file: > **Note** > Unlike integration tests, this filtering is at the file level, not function @@ -212,7 +212,7 @@ Feel free to improve the logic used there if you need more advanced functionalit If you can, perform automated accessibility testing using [AxeCore](https://github.com/dequelabs/axe-core-npm/blob/develop/packages/playwright/README.md). -Take a look at `shared/forms.js` and some other places for inspiration. +Take a look at `shared/forms.ts` and some other places for inspiration. ### List related files coverage diff --git a/tests/e2e/actions.test.e2e.js b/tests/e2e/actions.test.e2e.ts similarity index 99% rename from tests/e2e/actions.test.e2e.js rename to tests/e2e/actions.test.e2e.ts index 01ddb7b971..5e3ae7e3ff 100644 --- a/tests/e2e/actions.test.e2e.js +++ b/tests/e2e/actions.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/repo/actions/** // web_src/css/actions.css @@ -12,7 +10,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/changes.go b/tests/e2e/changes.go index acc1a796a4..1a314727d6 100644 --- a/tests/e2e/changes.go +++ b/tests/e2e/changes.go @@ -29,7 +29,7 @@ func initChangedFiles() { globalPatterns := []string{ // meta and config "Makefile", - "playwright.config.js", + "playwright.config.ts", ".forgejo/workflows/testing.yml", "tests/e2e/*.go", "tests/e2e/shared/*", diff --git a/tests/e2e/dashboard-ci-status.test.e2e.js b/tests/e2e/dashboard-ci-status.test.e2e.ts similarity index 97% rename from tests/e2e/dashboard-ci-status.test.e2e.js rename to tests/e2e/dashboard-ci-status.test.e2e.ts index 289430055c..a5bdc7ade9 100644 --- a/tests/e2e/dashboard-ci-status.test.e2e.js +++ b/tests/e2e/dashboard-ci-status.test.e2e.ts @@ -1,11 +1,9 @@ -// @ts-check - // @watch start // web_src/js/components/DashboardRepoList.vue // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 3e1bcefd66..b8c89625c0 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -79,7 +79,7 @@ func TestMain(m *testing.M) { // TestE2e should be the only test e2e necessary. It will collect all "*.test.e2e.js" files in this directory and build a test for each. func TestE2e(t *testing.T) { // Find the paths of all e2e test files in test directory. - searchGlob := filepath.Join(filepath.Dir(setting.AppPath), "tests", "e2e", "*.test.e2e.js") + searchGlob := filepath.Join(filepath.Dir(setting.AppPath), "tests", "e2e", "*.test.e2e.ts") paths, err := filepath.Glob(searchGlob) if err != nil { t.Fatal(err) diff --git a/tests/e2e/example.test.e2e.js b/tests/e2e/example.test.e2e.ts similarity index 96% rename from tests/e2e/example.test.e2e.js rename to tests/e2e/example.test.e2e.ts index a413a218c6..90fd9169a4 100644 --- a/tests/e2e/example.test.e2e.js +++ b/tests/e2e/example.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/user/auth/** // web_src/js/features/user-** @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, save_visual} from './utils_e2e.js'; +import {test, login_user, save_visual} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/explore.test.e2e.js b/tests/e2e/explore.test.e2e.ts similarity index 96% rename from tests/e2e/explore.test.e2e.js rename to tests/e2e/explore.test.e2e.ts index eb0c723f36..44c9b21f58 100644 --- a/tests/e2e/explore.test.e2e.js +++ b/tests/e2e/explore.test.e2e.ts @@ -1,4 +1,3 @@ -// @ts-check // document is a global in evaluate, so it's safe to ignore here // eslint playwright/no-conditional-in-test: 0 @@ -8,7 +7,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test} from './utils_e2e.js'; +import {test} from './utils_e2e.ts'; test('Explore view taborder', async ({page}) => { await page.goto('/explore/repos'); diff --git a/tests/e2e/issue-comment.test.e2e.js b/tests/e2e/issue-comment.test.e2e.ts similarity index 99% rename from tests/e2e/issue-comment.test.e2e.js rename to tests/e2e/issue-comment.test.e2e.ts index 8a1e48d75f..7b8326b832 100644 --- a/tests/e2e/issue-comment.test.e2e.js +++ b/tests/e2e/issue-comment.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // web_src/js/features/comp/** // web_src/js/features/repo-** @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, login} from './utils_e2e.js'; +import {test, login_user, login} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/issue-sidebar.test.e2e.js b/tests/e2e/issue-sidebar.test.e2e.ts similarity index 99% rename from tests/e2e/issue-sidebar.test.e2e.js rename to tests/e2e/issue-sidebar.test.e2e.ts index 8b5fa59331..31962bf3b4 100644 --- a/tests/e2e/issue-sidebar.test.e2e.js +++ b/tests/e2e/issue-sidebar.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/repo/issue/view_content/** // web_src/css/repo/issue-** @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, login} from './utils_e2e.js'; +import {test, login_user, login} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/markdown-editor.test.e2e.js b/tests/e2e/markdown-editor.test.e2e.ts similarity index 99% rename from tests/e2e/markdown-editor.test.e2e.js rename to tests/e2e/markdown-editor.test.e2e.ts index 36b35d7e8e..5db242bb36 100644 --- a/tests/e2e/markdown-editor.test.e2e.js +++ b/tests/e2e/markdown-editor.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // web_src/js/features/comp/ComboMarkdownEditor.js // web_src/css/editor/combomarkdowneditor.css @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, load_logged_in_context, login_user} from './utils_e2e.js'; +import {test, load_logged_in_context, login_user} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/markup.test.e2e.js b/tests/e2e/markup.test.e2e.ts similarity index 92% rename from tests/e2e/markup.test.e2e.js rename to tests/e2e/markup.test.e2e.ts index f7ec31709d..2cf32669e4 100644 --- a/tests/e2e/markup.test.e2e.js +++ b/tests/e2e/markup.test.e2e.ts @@ -1,11 +1,9 @@ -// @ts-check - // @watch start // web_src/css/markup/** // @watch end import {expect} from '@playwright/test'; -import {test} from './utils_e2e.js'; +import {test} from './utils_e2e.ts'; test('markup with #xyz-mode-only', async ({page}) => { const response = await page.goto('/user2/repo1/issues/1'); diff --git a/tests/e2e/org-settings.test.e2e.js b/tests/e2e/org-settings.test.e2e.ts similarity index 89% rename from tests/e2e/org-settings.test.e2e.js rename to tests/e2e/org-settings.test.e2e.ts index 21f34c123d..b645d94161 100644 --- a/tests/e2e/org-settings.test.e2e.js +++ b/tests/e2e/org-settings.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/org/team/new.tmpl // web_src/css/form.css @@ -7,8 +5,8 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, login} from './utils_e2e.js'; -import {validate_form} from './shared/forms.js'; +import {test, login_user, login} from './utils_e2e.ts'; +import {validate_form} from './shared/forms.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/profile_actions.test.e2e.js b/tests/e2e/profile_actions.test.e2e.ts similarity index 98% rename from tests/e2e/profile_actions.test.e2e.js rename to tests/e2e/profile_actions.test.e2e.ts index d168037041..efb4dd2f49 100644 --- a/tests/e2e/profile_actions.test.e2e.js +++ b/tests/e2e/profile_actions.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // routers/web/user/** // templates/shared/user/** @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test('Follow actions', async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/reaction-selectors.test.e2e.js b/tests/e2e/reaction-selectors.test.e2e.ts similarity index 99% rename from tests/e2e/reaction-selectors.test.e2e.js rename to tests/e2e/reaction-selectors.test.e2e.ts index 184f25fe18..a52b47e036 100644 --- a/tests/e2e/reaction-selectors.test.e2e.js +++ b/tests/e2e/reaction-selectors.test.e2e.ts @@ -1,12 +1,10 @@ -// @ts-check - // @watch start // web_src/js/features/comp/ReactionSelector.js // routers/web/repo/issue.go // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/release.test.e2e.js b/tests/e2e/release.test.e2e.ts similarity index 97% rename from tests/e2e/release.test.e2e.js rename to tests/e2e/release.test.e2e.ts index 76c7ac0212..373f23dfa7 100644 --- a/tests/e2e/release.test.e2e.js +++ b/tests/e2e/release.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // models/repo/attachment.go // modules/structs/attachment.go @@ -11,8 +9,8 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, save_visual, load_logged_in_context} from './utils_e2e.js'; -import {validate_form} from './shared/forms.js'; +import {test, login_user, save_visual, load_logged_in_context} from './utils_e2e.ts'; +import {validate_form} from './shared/forms.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/repo-code.test.e2e.js b/tests/e2e/repo-code.test.e2e.ts similarity index 99% rename from tests/e2e/repo-code.test.e2e.js rename to tests/e2e/repo-code.test.e2e.ts index fdb92762ff..5207a6389c 100644 --- a/tests/e2e/repo-code.test.e2e.js +++ b/tests/e2e/repo-code.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // web_src/js/features/repo-code.js // web_src/css/repo.css @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/repo-commitgraph.test.e2e.js b/tests/e2e/repo-commitgraph.test.e2e.ts similarity index 98% rename from tests/e2e/repo-commitgraph.test.e2e.js rename to tests/e2e/repo-commitgraph.test.e2e.ts index f06c68a55d..2a6fb1e6d7 100644 --- a/tests/e2e/repo-commitgraph.test.e2e.js +++ b/tests/e2e/repo-commitgraph.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/repo/graph.tmpl // web_src/css/features/gitgraph.css @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/repo-migrate.test.e2e.js b/tests/e2e/repo-migrate.test.e2e.ts similarity index 98% rename from tests/e2e/repo-migrate.test.e2e.js rename to tests/e2e/repo-migrate.test.e2e.ts index 2ad4400340..c4d1604a6f 100644 --- a/tests/e2e/repo-migrate.test.e2e.js +++ b/tests/e2e/repo-migrate.test.e2e.ts @@ -1,11 +1,9 @@ -// @ts-check - // @watch start // web_src/js/features/repo-migrate.js // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(({browser}, workerInfo) => login_user(browser, workerInfo, 'user2')); diff --git a/tests/e2e/repo-settings.test.e2e.js b/tests/e2e/repo-settings.test.e2e.ts similarity index 95% rename from tests/e2e/repo-settings.test.e2e.js rename to tests/e2e/repo-settings.test.e2e.ts index b4fdc1ae6c..8bd7299182 100644 --- a/tests/e2e/repo-settings.test.e2e.js +++ b/tests/e2e/repo-settings.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/webhook/shared-settings.tmpl // templates/repo/settings/** @@ -9,8 +7,8 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, login} from './utils_e2e.js'; -import {validate_form} from './shared/forms.js'; +import {test, login_user, login} from './utils_e2e.ts'; +import {validate_form} from './shared/forms.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/repo-wiki.test.e2e.js b/tests/e2e/repo-wiki.test.e2e.ts similarity index 94% rename from tests/e2e/repo-wiki.test.e2e.js rename to tests/e2e/repo-wiki.test.e2e.ts index eb6c033748..5b681c583c 100644 --- a/tests/e2e/repo-wiki.test.e2e.js +++ b/tests/e2e/repo-wiki.test.e2e.ts @@ -1,12 +1,10 @@ -// @ts-check - // @watch start // templates/repo/wiki/** // web_src/css/repo** // @watch end import {expect} from '@playwright/test'; -import {test} from './utils_e2e.js'; +import {test} from './utils_e2e.ts'; test(`Search for long titles and test for no overflow`, async ({page}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275'); diff --git a/tests/e2e/right-settings-button.test.e2e.js b/tests/e2e/right-settings-button.test.e2e.ts similarity index 99% rename from tests/e2e/right-settings-button.test.e2e.js rename to tests/e2e/right-settings-button.test.e2e.ts index 87e10c040c..bfb1800a27 100644 --- a/tests/e2e/right-settings-button.test.e2e.js +++ b/tests/e2e/right-settings-button.test.e2e.ts @@ -1,5 +1,3 @@ -// @ts-check - // @watch start // templates/org/** // templates/repo/** @@ -7,7 +5,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, login_user, load_logged_in_context} from './utils_e2e.js'; +import {test, login_user, load_logged_in_context} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); diff --git a/tests/e2e/shared/forms.js b/tests/e2e/shared/forms.ts similarity index 92% rename from tests/e2e/shared/forms.js rename to tests/e2e/shared/forms.ts index 5775c40826..52432ccbe8 100644 --- a/tests/e2e/shared/forms.js +++ b/tests/e2e/shared/forms.ts @@ -1,8 +1,7 @@ -import {expect} from '@playwright/test'; +import {expect, type Page} from '@playwright/test'; import {AxeBuilder} from '@axe-core/playwright'; -export async function validate_form({page}, scope) { - scope ??= 'form'; +export async function validate_form({page}: {page: Page}, scope: 'form' | 'fieldset' = 'form') { const accessibilityScanResults = await new AxeBuilder({page}) // disable checking for link style - should be fixed, but not now .disableRules('link-in-text-block') diff --git a/tests/e2e/utils_e2e.js b/tests/e2e/utils_e2e.ts similarity index 80% rename from tests/e2e/utils_e2e.js rename to tests/e2e/utils_e2e.ts index 7cfd7388ca..050847c5ed 100644 --- a/tests/e2e/utils_e2e.js +++ b/tests/e2e/utils_e2e.ts @@ -1,4 +1,4 @@ -import {expect, test as baseTest} from '@playwright/test'; +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) => { @@ -6,7 +6,7 @@ export const test = baseTest.extend({ }, }); -async function test_context(browser, options) { +async function test_context(browser: Browser, options?: BrowserContextOptions) { const context = await browser.newContext(options); context.on('page', (page) => { @@ -21,7 +21,7 @@ const LOGIN_PASSWORD = 'password'; // log in user and store session info. This should generally be // run in test.beforeAll(), then the session can be loaded in tests. -export async function login_user(browser, workerInfo, user) { +export async function login_user(browser: Browser, workerInfo: TestInfo, user: string) { test.setTimeout(60000); // Set up a new context const context = await test_context(browser); @@ -47,7 +47,7 @@ export async function login_user(browser, workerInfo, user) { return context; } -export async function load_logged_in_context(browser, workerInfo, user) { +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`}); @@ -59,12 +59,12 @@ export async function load_logged_in_context(browser, workerInfo, user) { return context; } -export async function login({browser}, workerInfo) { +export async function login({browser}: {browser: Browser}, workerInfo: TestInfo) { const context = await load_logged_in_context(browser, workerInfo, 'user2'); - return await context.newPage(); + return await context?.newPage(); } -export async function save_visual(page) { +export async function save_visual(page: Page) { // Optionally include visual testing if (process.env.VISUAL_TEST) { await page.waitForLoadState('networkidle'); @@ -83,7 +83,7 @@ export async function save_visual(page) { // Create a temporary user and login to that user and store session info. // This should ideally run on a per test basis. -export async function create_temp_user(browser, workerInfo, request) { +export async function create_temp_user(browser: Browser, workerInfo: TestInfo, request: APIRequestContext) { const username = globalThis.crypto.randomUUID(); const newUser = await request.post(`/api/v1/admin/users`, { headers: { diff --git a/tests/e2e/webauthn.test.e2e.js b/tests/e2e/webauthn.test.e2e.ts similarity index 94% rename from tests/e2e/webauthn.test.e2e.js rename to tests/e2e/webauthn.test.e2e.ts index 7168de223a..38e6b27821 100644 --- a/tests/e2e/webauthn.test.e2e.js +++ b/tests/e2e/webauthn.test.e2e.ts @@ -1,6 +1,5 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -// @ts-check // @watch start // templates/user/auth/** @@ -9,7 +8,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, create_temp_user} from './utils_e2e.js'; +import {test, create_temp_user} from './utils_e2e.ts'; test('WebAuthn register & login flow', async ({browser, request}, workerInfo) => { test.skip(workerInfo.project.name !== 'chromium', 'Uses Chrome protocol'); @@ -31,7 +30,7 @@ test('WebAuthn register & login flow', async ({browser, request}, workerInfo) => transport: 'usb', automaticPresenceSimulation: true, isUserVerified: true, - backupEligibility: true, + backupEligibility: true, // TODO: this doesn't seem to be available?! }, }); From 7db3781abf2547bd2ef165f9f01c36ac92b34c05 Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Sun, 10 Nov 2024 14:35:40 +0100 Subject: [PATCH 02/16] chore(e2e): Update global patterns Guard against regressions in template classes (see https://codeberg.org/forgejo/forgejo/pulls/5892 for example) Fix broken frontend test patterns as per https://codeberg.org/forgejo/forgejo/pulls/5734#issuecomment-2406914 --- tests/e2e/changes.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/e2e/changes.go b/tests/e2e/changes.go index acc1a796a4..d9ea830951 100644 --- a/tests/e2e/changes.go +++ b/tests/e2e/changes.go @@ -34,10 +34,11 @@ func initChangedFiles() { "tests/e2e/*.go", "tests/e2e/shared/*", // frontend files - "frontend/*.js", - "frontend/{base,index}.css", - // templates + "web_src/js/{index,utils}.*", + "web_src/css/{base,index}.css", + // templates and helpers "templates/base/**", + "modules/templates/**", } fullRunPatterns := []glob.Glob{} for _, expr := range globalPatterns { From 9995ca1547d601c6d6d8b8c427707ecdaddf074a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 12 Nov 2024 00:02:42 +0000 Subject: [PATCH 03/16] Update dependency @axe-core/playwright to v4.10.1 --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 267b1de595..79ab9d53b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "wrap-ansi": "9.0.0" }, "devDependencies": { - "@axe-core/playwright": "4.10.0", + "@axe-core/playwright": "4.10.1", "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", "@playwright/test": "1.48.2", "@stoplight/spectral-cli": "6.13.1", @@ -163,13 +163,13 @@ } }, "node_modules/@axe-core/playwright": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.10.0.tgz", - "integrity": "sha512-kEr3JPEVUSnKIYp/egV2jvFj+chIjCjPp3K3zlpJMza/CB3TFw8UZNbI9agEC2uMz4YbgAOyzlbUy0QS+OofFA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.10.1.tgz", + "integrity": "sha512-EV5t39VV68kuAfMKqb/RL+YjYKhfuGim9rgIaQ6Vntb2HgaCaau0h98Y3WEUqW1+PbdzxDtDNjFAipbtZuBmEA==", "dev": true, "license": "MPL-2.0", "dependencies": { - "axe-core": "~4.10.0" + "axe-core": "~4.10.2" }, "peerDependencies": { "playwright-core": ">= 1.0.0" diff --git a/package.json b/package.json index ea2a132df5..c045a4f437 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "wrap-ansi": "9.0.0" }, "devDependencies": { - "@axe-core/playwright": "4.10.0", + "@axe-core/playwright": "4.10.1", "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", "@playwright/test": "1.48.2", "@stoplight/spectral-cli": "6.13.1", From 8f6d20c1a37d7c116a627228c4405cfb324692f4 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 12 Nov 2024 02:03:17 +0000 Subject: [PATCH 04/16] Update dependency postcss to v8.4.49 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 267b1de595..6b4ac9e914 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ "monaco-editor": "0.51.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", - "postcss": "8.4.48", + "postcss": "8.4.49", "postcss-loader": "8.1.1", "postcss-nesting": "13.0.1", "pretty-ms": "9.0.0", @@ -13083,9 +13083,9 @@ } }, "node_modules/postcss": { - "version": "8.4.48", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.48.tgz", - "integrity": "sha512-GCRK8F6+Dl7xYniR5a4FYbpBzU8XnZVeowqsQFYdcXuSbChgiks7qybSkbvnaeqv0G0B+dd9/jJgH8kkLDQeEA==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "funding": [ { "type": "opencollective", diff --git a/package.json b/package.json index ea2a132df5..5f3f012cff 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "monaco-editor": "0.51.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", - "postcss": "8.4.48", + "postcss": "8.4.49", "postcss-loader": "8.1.1", "postcss-nesting": "13.0.1", "pretty-ms": "9.0.0", From 58ee2386d755a503fdc5bb8352e27fd49cbd23fc Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 12 Nov 2024 02:04:00 +0000 Subject: [PATCH 05/16] Update module github.com/buildkite/terminal-to-html/v3 to v3.16.4 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9537d12204..31f1b784c0 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/alecthomas/chroma/v2 v2.14.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.4.2 - github.com/buildkite/terminal-to-html/v3 v3.16.3 + github.com/buildkite/terminal-to-html/v3 v3.16.4 github.com/caddyserver/certmagic v0.21.4 github.com/chi-middleware/proxy v1.1.1 github.com/djherbis/buffer v1.2.0 diff --git a/go.sum b/go.sum index a1c1056623..49b1074748 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/buildkite/terminal-to-html/v3 v3.16.3 h1:IGuJjboHjuMLWOGsKZKNxbbn41emOLiHzXPmQZk31fk= -github.com/buildkite/terminal-to-html/v3 v3.16.3/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0= +github.com/buildkite/terminal-to-html/v3 v3.16.4 h1:QFYO8IGvRnp7tGgiQb8g9uFU8kY9wOzxsFFx17+yy6Q= +github.com/buildkite/terminal-to-html/v3 v3.16.4/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0= github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE= From 520a7bca9343e29000dfa6caf0b0aeaaba5a062e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 12 Nov 2024 05:57:01 +0000 Subject: [PATCH 06/16] Update dependency happy-dom to v15.11.1 (forgejo) (#5920) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 267b1de595..37394cb4a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,7 +86,7 @@ "eslint-plugin-vue-scoped-css": "2.8.1", "eslint-plugin-wc": "2.2.0", "globals": "15.12.0", - "happy-dom": "15.11.0", + "happy-dom": "15.11.2", "license-checker-rseidelsohn": "4.4.2", "markdownlint-cli": "0.42.0", "postcss-html": "1.7.0", @@ -10257,9 +10257,9 @@ } }, "node_modules/happy-dom": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.0.tgz", - "integrity": "sha512-/zyxHbXriYJ8b9Urh43ILk/jd9tC07djURnJuAimJ3tJCOLOzOUp7dEHDwJOZyzROlrrooUhr/0INZIDBj1Bjw==", + "version": "15.11.2", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.2.tgz", + "integrity": "sha512-MZ8kazOz+8i9G+olnJS836mNaF96UhOTzuECmxdE56+1+juiubqaJHTJUf+1WZ6Vs09lKLdmfX2AxGslfj1XFg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ea2a132df5..7dc1140a96 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "eslint-plugin-vue-scoped-css": "2.8.1", "eslint-plugin-wc": "2.2.0", "globals": "15.12.0", - "happy-dom": "15.11.0", + "happy-dom": "15.11.2", "license-checker-rseidelsohn": "4.4.2", "markdownlint-cli": "0.42.0", "postcss-html": "1.7.0", From 983aed4268f6ba6d6bc071d81d9cf61082c71789 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Tue, 12 Nov 2024 08:13:33 +0100 Subject: [PATCH 07/16] fix(ci): synchronize updates the commit status asynchronously When a new commit is pushed to an existing pull request, the update of the commit status will happen asynchronously, via the git hook. --- FAIL: TestPullRequestCommitStatus/synchronize (2.14s) actions_trigger_test.go:331: Error Trace: /workspace/forgejo/forgejo/tests/integration/actions_trigger_test.go:331 Error: Should be true Test: TestPullRequestCommitStatus/synchronize --- tests/integration/actions_trigger_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index 9cf2d4305f..dfd1f75b3c 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -328,7 +328,9 @@ jobs: sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) require.NoError(t, err) // verify the commit status changes to CommitStatusSuccess when the job changes to StatusSuccess - assert.True(t, checkCommitStatus(sha, context, api.CommitStatusPending)) + require.Eventually(t, func() bool { + return checkCommitStatus(sha, context, api.CommitStatusPending) + }, 30*time.Second, 1*time.Second) for _, actionRun := range actionRuns { // verify the expected ActionRunJob was created and is StatusWaiting job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{RunID: actionRun.ID, CommitSHA: sha}) @@ -339,7 +341,9 @@ jobs: actions_service.CreateCommitStatus(db.DefaultContext, job) } // verify the commit status changed to CommitStatusSuccess because the job(s) changed to StatusSuccess - assert.True(t, checkCommitStatus(sha, context, api.CommitStatusSuccess)) + require.Eventually(t, func() bool { + return checkCommitStatus(sha, context, api.CommitStatusSuccess) + }, 30*time.Second, 1*time.Second) testCase.assert(t, sha, testCase.onType, testCase.action, actionRuns) }) From dd6ea5f3c8b25f14f287d12bbb31948503b953ab Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Tue, 12 Nov 2024 07:50:39 +0100 Subject: [PATCH 08/16] chore(renovate): always set the test/not-needed label Under the assumption that all dependencies have at least some test coverage. It may not be always true but it is generally true. Ideally there would be an inventory, a checklist of dependencies that miss test coverage, but that does not exist. --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index cd927797f5..59d533336e 100644 --- a/renovate.json +++ b/renovate.json @@ -16,7 +16,7 @@ "prConcurrentLimit": 10, "osvVulnerabilityAlerts": true, "automergeStrategy": "squash", - "labels": ["dependency-upgrade"], + "labels": ["dependency-upgrade","test/not-needed"], "packageRules": [ { "description": "Require approval for python minor version", From 2e9a8c4fc0a5add9c5e701dc67cb5e5112212d87 Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Tue, 12 Nov 2024 20:36:26 +0100 Subject: [PATCH 09/16] chore(lint): Ignore playwright reports for linting Was part of c9e402afdc573a9706fa45a1052c122f34264b89 but got dropped from Makefile in 8dc72589cafd0881e234af489c4b3d643422f7e9 There are no JavaScript files in e2e left, so apply some rule to TypeScript only --- eslint.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index da1b2b5d49..c52fdd4ddd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -20,7 +20,7 @@ export default tseslint.config( ...tseslint.configs.recommended, eslintPluginImportX.flatConfigs.typescript, { - ignores: ['web_src/js/vendor', 'web_src/fomantic', 'public/assets/js'], + ignores: ['web_src/js/vendor', 'web_src/fomantic', 'public/assets/js', 'tests/e2e/reports/'], }, { plugins: { @@ -1112,7 +1112,7 @@ export default tseslint.config( ], }, }, { - files: ['tests/e2e/**/*.js', 'tests/e2e/**/*.ts'], + files: ['tests/e2e/**/*.ts'], languageOptions: { globals: { ...globals.browser, From 0aaf9e400ffb1d1ccf3e626f7c3ba6db61e11b8a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 13 Nov 2024 05:45:40 +0000 Subject: [PATCH 10/16] Update linters (forgejo) (#5934) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 116 +++++++++++++++++++++++----------------------- package.json | 8 ++-- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index a945da537b..a92cd4cf56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "@stoplight/spectral-cli": "6.13.1", "@stylistic/eslint-plugin-js": "2.10.1", "@stylistic/stylelint-plugin": "3.1.1", - "@typescript-eslint/parser": "8.13.0", + "@typescript-eslint/parser": "8.14.0", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.4", "@vitest/eslint-plugin": "1.1.7", @@ -74,7 +74,7 @@ "eslint": "9.14.0", "eslint-import-resolver-typescript": "3.6.3", "eslint-plugin-array-func": "5.0.2", - "eslint-plugin-import-x": "4.4.0", + "eslint-plugin-import-x": "4.4.2", "eslint-plugin-no-jquery": "3.0.2", "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.0.1", @@ -82,7 +82,7 @@ "eslint-plugin-sonarjs": "2.0.4", "eslint-plugin-unicorn": "56.0.0", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.30.0", + "eslint-plugin-vue": "9.31.0", "eslint-plugin-vue-scoped-css": "2.8.1", "eslint-plugin-wc": "2.2.0", "globals": "15.12.0", @@ -96,7 +96,7 @@ "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", "typescript": "5.6.3", - "typescript-eslint": "8.13.0", + "typescript-eslint": "8.14.0", "vite-string-plugin": "1.3.4", "vitest": "2.1.4" }, @@ -4866,17 +4866,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", - "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", + "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/type-utils": "8.13.0", - "@typescript-eslint/utils": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/type-utils": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4900,16 +4900,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", - "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", + "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "debug": "^4.3.4" }, "engines": { @@ -4929,14 +4929,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", - "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", + "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0" + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4947,14 +4947,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", - "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", + "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/utils": "8.13.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/utils": "8.14.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -4972,9 +4972,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", - "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", + "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", "dev": true, "license": "MIT", "engines": { @@ -4986,14 +4986,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", - "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", + "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -5031,16 +5031,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", - "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", + "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0" + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5054,13 +5054,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", - "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", + "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.13.0", + "@typescript-eslint/types": "8.14.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -8433,9 +8433,9 @@ } }, "node_modules/eslint-plugin-import-x": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.4.0.tgz", - "integrity": "sha512-me58aWTjdkPtgmOzPe+uP0bebpN5etH4bJRnYzy85Rn9g/3QyASg6kTCqdwNzyaJRqMI2ii2o8s01P2LZpREHg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.4.2.tgz", + "integrity": "sha512-mDRXPSLQ0UQZQw91QdG4/qZT6hgeW2MJTczAbgPseUZuPEtIjjdPOolXroRkulnOn3fzj6gNgvk+wchMJiHElg==", "dev": true, "license": "MIT", "dependencies": { @@ -9365,9 +9365,9 @@ "license": "MIT" }, "node_modules/eslint-plugin-vue": { - "version": "9.30.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.30.0.tgz", - "integrity": "sha512-CyqlRgShvljFkOeYK8wN5frh/OGTvkj1S7wlr2Q2pUvwq+X5VYiLd6ZjujpgSgLnys2W8qrBLkXQ41SUYaoPIQ==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.31.0.tgz", + "integrity": "sha512-aYMUCgivhz1o4tLkRHj5oq9YgYPM4/EJc0M7TAKRLCUA5OYxRLAhYEVD2nLtTwLyixEFI+/QXSvKU9ESZFgqjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -15893,15 +15893,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.13.0.tgz", - "integrity": "sha512-vIMpDRJrQd70au2G8w34mPps0ezFSPMEX4pXkTzUkrNbRX+36ais2ksGWN0esZL+ZMaFJEneOBHzCgSqle7DHw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.14.0.tgz", + "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.13.0", - "@typescript-eslint/parser": "8.13.0", - "@typescript-eslint/utils": "8.13.0" + "@typescript-eslint/eslint-plugin": "8.14.0", + "@typescript-eslint/parser": "8.14.0", + "@typescript-eslint/utils": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 9e7d9e5167..cd5d02257f 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@stoplight/spectral-cli": "6.13.1", "@stylistic/eslint-plugin-js": "2.10.1", "@stylistic/stylelint-plugin": "3.1.1", - "@typescript-eslint/parser": "8.13.0", + "@typescript-eslint/parser": "8.14.0", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.4", "@vitest/eslint-plugin": "1.1.7", @@ -73,7 +73,7 @@ "eslint": "9.14.0", "eslint-import-resolver-typescript": "3.6.3", "eslint-plugin-array-func": "5.0.2", - "eslint-plugin-import-x": "4.4.0", + "eslint-plugin-import-x": "4.4.2", "eslint-plugin-no-jquery": "3.0.2", "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.0.1", @@ -81,7 +81,7 @@ "eslint-plugin-sonarjs": "2.0.4", "eslint-plugin-unicorn": "56.0.0", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.30.0", + "eslint-plugin-vue": "9.31.0", "eslint-plugin-vue-scoped-css": "2.8.1", "eslint-plugin-wc": "2.2.0", "globals": "15.12.0", @@ -95,7 +95,7 @@ "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", "typescript": "5.6.3", - "typescript-eslint": "8.13.0", + "typescript-eslint": "8.14.0", "vite-string-plugin": "1.3.4", "vitest": "2.1.4" }, From 10573c6f2bee29280f37515136adeb6e76fcfd71 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 13 Nov 2024 07:18:45 +0000 Subject: [PATCH 11/16] Update dependency @vitest/eslint-plugin to v1.1.9 (forgejo) (#5931) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a92cd4cf56..af570d35e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "@typescript-eslint/parser": "8.14.0", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.4", - "@vitest/eslint-plugin": "1.1.7", + "@vitest/eslint-plugin": "1.1.10", "@vue/test-utils": "2.4.6", "eslint": "9.14.0", "eslint-import-resolver-typescript": "3.6.3", @@ -5142,9 +5142,9 @@ } }, "node_modules/@vitest/eslint-plugin": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.7.tgz", - "integrity": "sha512-pTWGW3y6lH2ukCuuffpan6kFxG6nIuoesbhMiQxskyQMRcCN5t9SXsKrNHvEw3p8wcCsgJoRqFZVkOTn6TjclA==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.10.tgz", + "integrity": "sha512-uScH5Kz5v32vvtQYB2iodpoPg2mGASK+VKpjlc2IUgE0+16uZKqVKi2vQxjxJ6sMCQLBs4xhBFZlmZBszsmfKQ==", "dev": true, "license": "MIT", "peerDependencies": { diff --git a/package.json b/package.json index cd5d02257f..a07492fb3a 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@typescript-eslint/parser": "8.14.0", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.4", - "@vitest/eslint-plugin": "1.1.7", + "@vitest/eslint-plugin": "1.1.10", "@vue/test-utils": "2.4.6", "eslint": "9.14.0", "eslint-import-resolver-typescript": "3.6.3", From 7a764a2996f00060838344fe2eccb34203df0ca5 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 13 Nov 2024 07:20:12 +0000 Subject: [PATCH 12/16] Update dependency happy-dom to v15.11.3 (forgejo) (#5932) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index af570d35e3..9913fd439e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,7 +86,7 @@ "eslint-plugin-vue-scoped-css": "2.8.1", "eslint-plugin-wc": "2.2.0", "globals": "15.12.0", - "happy-dom": "15.11.2", + "happy-dom": "15.11.4", "license-checker-rseidelsohn": "4.4.2", "markdownlint-cli": "0.42.0", "postcss-html": "1.7.0", @@ -10257,9 +10257,9 @@ } }, "node_modules/happy-dom": { - "version": "15.11.2", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.2.tgz", - "integrity": "sha512-MZ8kazOz+8i9G+olnJS836mNaF96UhOTzuECmxdE56+1+juiubqaJHTJUf+1WZ6Vs09lKLdmfX2AxGslfj1XFg==", + "version": "15.11.4", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.4.tgz", + "integrity": "sha512-AU6tzh3ADd28vSmXahgLsGyGGihXPGeKH0owDn9lhHolB6vIwEhag//T+TBzDoAcHhmVEwlxwSgtW1KZep+1MA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a07492fb3a..5b21afbd6d 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "eslint-plugin-vue-scoped-css": "2.8.1", "eslint-plugin-wc": "2.2.0", "globals": "15.12.0", - "happy-dom": "15.11.2", + "happy-dom": "15.11.4", "license-checker-rseidelsohn": "4.4.2", "markdownlint-cli": "0.42.0", "postcss-html": "1.7.0", From 6bfa0ee13b329255f5ae7de986b04685113a966f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 13 Nov 2024 07:23:17 +0000 Subject: [PATCH 13/16] Update dependency @stoplight/spectral-cli to v6.14.0 (forgejo) (#5933) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 119 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9913fd439e..e44c6f073c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "@axe-core/playwright": "4.10.0", "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", "@playwright/test": "1.48.2", - "@stoplight/spectral-cli": "6.13.1", + "@stoplight/spectral-cli": "6.14.0", "@stylistic/eslint-plugin-js": "2.10.1", "@stylistic/stylelint-plugin": "3.1.1", "@typescript-eslint/parser": "8.14.0", @@ -3351,10 +3351,23 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, "node_modules/@jsep-plugin/regex": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.3.tgz", - "integrity": "sha512-XfZgry4DwEZvSFtS/6Y+R48D7qJYJK6R9/yJFyUFHCIUMEEHuJ4X95TDgJp5QkmzfLYvapMPzskV5HpIDrREug==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", "dev": true, "license": "MIT", "engines": { @@ -3365,9 +3378,9 @@ } }, "node_modules/@jsep-plugin/ternary": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@jsep-plugin/ternary/-/ternary-1.1.3.tgz", - "integrity": "sha512-qtLGzCNzPVJ3kdH6/zoLWDPjauHIKiLSBAR71Wa0+PWvGA8wODUQvRgxtpUA5YqAYL3CQ8S4qXhd/9WuWTZirg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/ternary/-/ternary-1.1.4.tgz", + "integrity": "sha512-ck5wiqIbqdMX6WRQztBL7ASDty9YLgJ3sSAK5ZpBzXeySvFGCzIvM6UiAI4hTZ22fEcYQVV/zhUbNscggW+Ukg==", "dev": true, "license": "MIT", "engines": { @@ -3992,20 +4005,20 @@ } }, "node_modules/@stoplight/spectral-cli": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.13.1.tgz", - "integrity": "sha512-v6ipX4w6wRhtbOotwdPL7RrEkP0m1OwHTIyqzVrAPi932F/zkee24jmf1CHNrTynonmfGoU6/XpeqUHtQdKDFw==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.14.0.tgz", + "integrity": "sha512-pq1qWENLtI97afz9Ygx0TtBXj9s97oQnjMOUp4USzXdnxhKhlYwlhJIA9U3VYzktA+QpHdTXVd4GSgyxdHSBSg==", "dev": true, "license": "Apache-2.0", "dependencies": { "@stoplight/json": "~3.21.0", "@stoplight/path": "1.3.2", - "@stoplight/spectral-core": "^1.18.3", - "@stoplight/spectral-formatters": "^1.3.0", - "@stoplight/spectral-parsers": "^1.0.3", + "@stoplight/spectral-core": "^1.19.2", + "@stoplight/spectral-formatters": "^1.4.0", + "@stoplight/spectral-parsers": "^1.0.4", "@stoplight/spectral-ref-resolver": "^1.0.4", - "@stoplight/spectral-ruleset-bundler": "^1.5.4", - "@stoplight/spectral-ruleset-migrator": "^1.9.6", + "@stoplight/spectral-ruleset-bundler": "^1.6.0", + "@stoplight/spectral-ruleset-migrator": "^1.11.0", "@stoplight/spectral-rulesets": ">=1", "@stoplight/spectral-runtime": "^1.1.2", "@stoplight/types": "^13.6.0", @@ -4022,7 +4035,7 @@ "spectral": "dist/index.js" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": "^16.20 || ^18.18 || >= 20.17" } }, "node_modules/@stoplight/spectral-cli/node_modules/fast-glob": { @@ -4056,9 +4069,9 @@ } }, "node_modules/@stoplight/spectral-core": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.19.1.tgz", - "integrity": "sha512-YiWhXdjyjn4vCl3102ywzwCEJzncxapFcj4dxcj1YP/bZ62DFeGJ8cEaMP164vSw2kI3rX7EMMzI/c8XOUnTfQ==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.19.2.tgz", + "integrity": "sha512-Yx1j7d0VGEbsOCimPgl+L8w7ZuuOaxqGvXSUXgm9weoGR5idLQjPaTuHLdfdziR1gjqQdVTCEk/dN0cFfUKhow==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4075,17 +4088,17 @@ "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.0", "es-aggregate-error": "^1.0.7", - "jsonpath-plus": "7.1.0", + "jsonpath-plus": "10.1.0", "lodash": "~4.17.21", "lodash.topath": "^4.5.2", "minimatch": "3.1.2", - "nimma": "0.2.2", + "nimma": "0.2.3", "pony-cause": "^1.0.0", - "simple-eval": "1.0.0", + "simple-eval": "1.0.1", "tslib": "^2.3.0" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": "^16.20 || ^18.18 || >= 20.17" } }, "node_modules/@stoplight/spectral-core/node_modules/@stoplight/types": { @@ -4266,9 +4279,9 @@ } }, "node_modules/@stoplight/spectral-ruleset-migrator": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.10.0.tgz", - "integrity": "sha512-nDfkVfYeWWv0UvILC4TWZSnRqQ4rHgeOJO1/lHQ7XHeG5iONanQ639B1aK6ZS6vuUc8gwuyQsrPF67b4sHIyYw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.11.0.tgz", + "integrity": "sha512-FHxc/C/RhEYXW8zcp9mO50/jt+0Of6p6ZFVoV84l9y7agQchc9RGFjN6src4kO7bg6eUWQK6+5rUIV6yFKhBgg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4282,13 +4295,13 @@ "@types/node": "*", "ajv": "^8.17.1", "ast-types": "0.14.2", - "astring": "^1.7.5", + "astring": "^1.9.0", "reserved": "0.1.2", "tslib": "^2.3.1", "validate-npm-package-name": "3.0.0" }, "engines": { - "node": ">=12" + "node": "^16.20 || ^18.18 || >= 20.17" } }, "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/yaml": { @@ -11417,9 +11430,9 @@ } }, "node_modules/jsep": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.9.tgz", - "integrity": "sha512-i1rBX5N7VPl0eYb6+mHNp52sEuaS2Wi8CDYx1X5sn9naevL78+265XJqy1qENEk7mRKwS06NHpUqiBwR7qeodw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", "dev": true, "license": "MIT", "engines": { @@ -11498,13 +11511,22 @@ } }, "node_modules/jsonpath-plus": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.1.0.tgz", - "integrity": "sha512-gTaNRsPWO/K2KY6MrqaUFClF9kmuM6MFH5Dhg1VYDODgFbByw1yb7xu3hrViE/sz+dGOeMWgCzwUwQtAnCTE9g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.1.0.tgz", + "integrity": "sha512-gHfV1IYqH8uJHYVTs8BJX1XKy2/rR93+f8QQi0xhx95aCiXn1ettYAd5T+7FU6wfqyDoX/wy0pm/fL3jOKJ9Lg==", "dev": true, "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.2.1", + "@jsep-plugin/regex": "^1.0.3", + "jsep": "^1.3.9" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" } }, "node_modules/jsonpointer": { @@ -12388,9 +12410,9 @@ "license": "MIT" }, "node_modules/nimma": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.2.tgz", - "integrity": "sha512-V52MLl7BU+tH2Np9tDrIXK8bql3MVUadnMIl/0/oZSGC9keuro0O9UUv9QKp0aMvtN8HRew4G7byY7H4eWsxaQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.3.tgz", + "integrity": "sha512-1ZOI8J+1PKKGceo/5CT5GfQOG6H8I2BencSK06YarZ2wXwH37BSSUWldqJmMJYA5JfqDqffxDXynt6f11AyKcA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -12403,21 +12425,10 @@ "node": "^12.20 || >=14.13" }, "optionalDependencies": { - "jsonpath-plus": "^6.0.1", + "jsonpath-plus": "^6.0.1 || ^10.1.0", "lodash.topath": "^4.5.2" } }, - "node_modules/nimma/node_modules/jsonpath-plus": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz", - "integrity": "sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/node-fetch": { "version": "2.6.13", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", @@ -14487,13 +14498,13 @@ } }, "node_modules/simple-eval": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-eval/-/simple-eval-1.0.0.tgz", - "integrity": "sha512-kpKJR+bqTscgC0xuAl2xHN6bB12lHjC2DCUfqjAx19bQyO3R2EVLOurm3H9AUltv/uFVcSCVNc6faegR+8NYLw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-eval/-/simple-eval-1.0.1.tgz", + "integrity": "sha512-LH7FpTAkeD+y5xQC4fzS+tFtaNlvt3Ib1zKzvhjv/Y+cioV4zIuw4IZr2yhRLu67CWL7FR9/6KXKnjRoZTvGGQ==", "dev": true, "license": "MIT", "dependencies": { - "jsep": "^1.1.2" + "jsep": "^1.3.6" }, "engines": { "node": ">=12" diff --git a/package.json b/package.json index 5b21afbd6d..3be4a974b7 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@axe-core/playwright": "4.10.0", "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", "@playwright/test": "1.48.2", - "@stoplight/spectral-cli": "6.13.1", + "@stoplight/spectral-cli": "6.14.0", "@stylistic/eslint-plugin-js": "2.10.1", "@stylistic/stylelint-plugin": "3.1.1", "@typescript-eslint/parser": "8.14.0", From 68658400be0e6bc318a65be1da52aa6ab77856b4 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Wed, 13 Nov 2024 08:25:26 +0100 Subject: [PATCH 14/16] chore(renovate): throttle down upgrade of linters & test packages Once a month. * Without throttling multiple test / linter packages are updated every day and this exceeds the review capacity of Forgejo contributors at the moment. Some of them even release more than once a day, apparently on every commit. * Add @axe-core/playwright --- renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 59d533336e..4e869db579 100644 --- a/renovate.json +++ b/renovate.json @@ -144,8 +144,9 @@ }, { "description": "Automerge some packages when CI succeeds", - "extends": ["packages:linters", "packages:test"], + "extends": ["packages:linters", "packages:test", "schedule:monthly"], "matchPackageNames": [ + "@axe-core/playwright", "@eslint-community/**", "@playwright/**", "@stoplight/spectral-cli", From 40551de313c33a10b6ea9d67bf506a7700c48950 Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Tue, 12 Nov 2024 21:07:09 +0100 Subject: [PATCH 15/16] tests(e2e): Refactor various tests Goals: - speedup - less flakiness - best practices and more use - documentation config: - sync ports in Makefile and playwright config (otherwise, some tests fail locally because they assert the full URL including the (wrong) port) - even more generous timeouts - limit workers to one again (because I finally understand how Playwright works) - allow nested functions to group them together with the related test all: - deprecate waitForLoadState('networkidle') - it is discouraged as per https://playwright.dev/docs/api/class-page#page-wait-for-load-state - I could not find a usage that seems to require it actually (see added documentation in README) - adding an exception should be made explicitly - it does not do what you might expect anyway in most cases - only log in when necessary webauthn: - verify that login is possible after disabling key - otherwise, the cleanup was not necessary after the previous refactor to create a fresh user each issue-sidebar / WIP toggle: - split into smaller chunks - restore original state first - add missed assertion to fix race condition (not waiting before state was reached) - explicitly toggle the state to detect mismatch earlier issue-sidebar / labels: - restore original state first - better waiting for background request --- Makefile | 1 - eslint.config.mjs | 3 +- playwright.config.ts | 14 +- tests/e2e/README.md | 88 ++++++++++ tests/e2e/actions.test.e2e.ts | 5 - tests/e2e/dashboard-ci-status.test.e2e.ts | 5 +- tests/e2e/issue-comment.test.e2e.ts | 2 +- tests/e2e/issue-sidebar.test.e2e.ts | 186 +++++++++++++--------- tests/e2e/markup.test.e2e.ts | 1 - tests/e2e/profile_actions.test.e2e.ts | 1 - tests/e2e/repo-code.test.e2e.ts | 11 +- tests/e2e/repo-commitgraph.test.e2e.ts | 12 +- tests/e2e/repo-wiki.test.e2e.ts | 1 - tests/e2e/utils_e2e.ts | 4 +- tests/e2e/webauthn.test.e2e.ts | 13 +- 15 files changed, 230 insertions(+), 117 deletions(-) diff --git a/Makefile b/Makefile index ae7ed16846..670cb9452a 100644 --- a/Makefile +++ b/Makefile @@ -716,7 +716,6 @@ test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql .PHONY: test-e2e-debugserver test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite - sed -i s/3003/3000/g tests/sqlite.ini GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestDebugserver -test.timeout 24h .PHONY: bench-sqlite diff --git a/eslint.config.mjs b/eslint.config.mjs index c52fdd4ddd..73a4e0bcfa 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1125,7 +1125,8 @@ export default tseslint.config( ...playwright.configs['flat/recommended'].rules, 'playwright/no-conditional-in-test': [0], 'playwright/no-conditional-expect': [0], - 'playwright/no-networkidle': [0], + // allow grouping helper functions with tests + 'unicorn/consistent-function-scoping': [0], 'playwright/no-skipped-test': [ 2, diff --git a/playwright.config.ts b/playwright.config.ts index 625dc3bc69..0994c55045 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,6 +1,6 @@ import {devices, type PlaywrightTestConfig} from '@playwright/test'; -const BASE_URL = process.env.GITEA_URL?.replace?.(/\/$/g, '') || 'http://localhost:3000'; +const BASE_URL = process.env.GITEA_URL?.replace?.(/\/$/g, '') || 'http://localhost:3003'; /** * @see https://playwright.dev/docs/test-configuration @@ -12,7 +12,7 @@ export default { // you can adjust this value locally to match your machine's power, // or pass `--workers x` to playwright - workers: process.env.CI ? 1 : 2, + workers: 1, /* Maximum time one test can run for. */ timeout: 30 * 1000, @@ -22,7 +22,7 @@ export default { * Maximum time expect() should wait for the condition to be met. * For example in `await expect(locator).toHaveText();` */ - timeout: 2000, + timeout: 3000, }, /* Fail the build on CI if you accidentally left test.only in the source code. */ @@ -30,6 +30,8 @@ export default { /* Retry on CI only */ retries: process.env.CI ? 1 : 0, + /* fail fast */ + maxFailures: process.env.CI ? 1 : 0, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: process.env.CI ? 'list' : [['list'], ['html', {outputFolder: 'tests/e2e/reports/', open: 'never'}]], @@ -41,7 +43,7 @@ export default { locale: 'en-US', /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ - actionTimeout: 2000, + actionTimeout: 3000, /* Maximum time allowed for navigation, such as `page.goto()`. */ navigationTimeout: 10 * 1000, @@ -95,8 +97,8 @@ export default { }, ], - /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + /* Folder for test artifacts created during test execution such as screenshots, traces, etc. */ outputDir: 'tests/e2e/test-artifacts/', - /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + /* Folder for explicit snapshots for visual testing */ snapshotDir: 'tests/e2e/test-snapshots/', } satisfies PlaywrightTestConfig; diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 8fae664564..81dc0bf832 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -175,6 +175,70 @@ ACCEPT_VISUAL=1 will overwrite the snapshot images with new images. If you know noteworthy tests that can act as an inspiration for new tests, please add some details here. +### Understanding and waiting for page loads + +[Waiting for a load state](https://playwright.dev/docs/api/class-frame#frame-wait-for-load-state) +sound like a convenient way to ensure the page was loaded, +but it only works once and consecutive calls to it +(e.g. after clicking a button which should reload a page) +return immediately without waiting for *another* load event. + +If you match something which is on both the old and the new page, +you might succeed before the page was reloaded, +although the code using a `waitForLoadState` might intuitively suggest +the page was changed before. + +Interacting with the page before the reload +(e.g. by opening a dropdown) +might then race and result in flaky tests, +depending on the speed of the hardware running the test. + +A possible way to test that an interaction worked is by checking for a known change first. +For example: + +- you submit a form and you want to check that the content persisted +- checking for the content directly would succeed even without a page reload +- check for a success message first (will wait until it appears), then verify the content + +Alternatively, if you know the backend request that will be made before the reload, +you can explicitly wait for it: + +~~~js +const submitted = page.waitForResponse('/my/backend/post/request'); +await page.locator('button').first().click(); // perform your interaction +await submitted; +~~~ + +If the page redirects to another URL, +you can alternatively use: + +~~~js +await page.waitForURL('**/target.html'); +~~~ + +### Only sign in if necessary + +Signing in takes time and is actually executed step-by-step. +If your test does not rely on a user account, skip this step. + +~~~js +test('For anyone', async ({page}) => { + await page.goto('/somepage'); +~~~ + +If you need a user account, you can use something like: + +~~~js +import {test, login_user, login} from './utils_e2e.ts'; + +test.beforeAll(async ({browser}, workerInfo) => { + await login_user(browser, workerInfo, 'user2'); // or another user +}); + +test('For signed users only', async ({browser}, workerInfo) => { + const page = await login({browser}, workerInfo); +~~~ + ### Run tests very selectively Browser testing can take some time. @@ -264,3 +328,27 @@ and a set of files with a certain ending: The patterns are evaluated on a "first-match" basis. Under the hood, [gobwas/glob](https://github.com/gobwas/glob) is used. + +## Grouped retry for interactions + +Sometimes, it can be necessary to retry certain interactions together. +Consider the following procedure: + +1. click to open a dropdown +2. interact with content in the dropdown + +When for some reason the dropdown does not open, +for example because of it taking time to initialize after page load, +the click will succeed, +but the depending interaction won't, +although playwright repeatedly tries to find the content. + +You can [group statements using toPass]()https://playwright.dev/docs/test-assertions#expecttopass). +This code retries the dropdown click until the second item is found. + +~~~js +await expect(async () => { + await page.locator('.dropdown').click(); + await page.locator('.dropdown .item').first().click(); +}).toPass(); +~~~ diff --git a/tests/e2e/actions.test.e2e.ts b/tests/e2e/actions.test.e2e.ts index 5e3ae7e3ff..0aa1c747dc 100644 --- a/tests/e2e/actions.test.e2e.ts +++ b/tests/e2e/actions.test.e2e.ts @@ -44,7 +44,6 @@ test('workflow dispatch error: missing inputs', async ({browser}, workerInfo) => const page = await context.newPage(); await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0'); - await page.waitForLoadState('networkidle'); await page.locator('#workflow_dispatch_dropdown>button').click(); @@ -55,7 +54,6 @@ test('workflow dispatch error: missing inputs', async ({browser}, workerInfo) => }); await page.locator('#workflow-dispatch-submit').click(); - await page.waitForLoadState('networkidle'); await expect(page.getByText('Require value for input "String w/o. default".')).toBeVisible(); }); @@ -68,13 +66,11 @@ test('workflow dispatch success', async ({browser}, workerInfo) => { const page = await context.newPage(); await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0'); - await page.waitForLoadState('networkidle'); await page.locator('#workflow_dispatch_dropdown>button').click(); await page.type('input[name="inputs[string2]"]', 'abc'); await page.locator('#workflow-dispatch-submit').click(); - await page.waitForLoadState('networkidle'); await expect(page.getByText('Workflow run was successfully requested.')).toBeVisible(); @@ -83,7 +79,6 @@ test('workflow dispatch success', async ({browser}, workerInfo) => { test('workflow dispatch box not available for unauthenticated users', async ({page}) => { await page.goto('/user2/test_workflows/actions?workflow=test-dispatch.yml&actor=0&status=0'); - await page.waitForLoadState('networkidle'); await expect(page.locator('body')).not.toContainText(workflow_trigger_notification_text); }); diff --git a/tests/e2e/dashboard-ci-status.test.e2e.ts b/tests/e2e/dashboard-ci-status.test.e2e.ts index a5bdc7ade9..531955209a 100644 --- a/tests/e2e/dashboard-ci-status.test.e2e.ts +++ b/tests/e2e/dashboard-ci-status.test.e2e.ts @@ -15,10 +15,9 @@ test('Correct link and tooltip', async ({browser}, workerInfo) => { const response = await page.goto('/?repo-search-query=test_workflows'); expect(response?.status()).toBe(200); - await page.waitForLoadState('networkidle'); - 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', 'Failure'); }); diff --git a/tests/e2e/issue-comment.test.e2e.ts b/tests/e2e/issue-comment.test.e2e.ts index 7b8326b832..9a3a45f522 100644 --- a/tests/e2e/issue-comment.test.e2e.ts +++ b/tests/e2e/issue-comment.test.e2e.ts @@ -56,7 +56,7 @@ test('Always focus edit tab first on edit', async ({browser}, workerInfo) => { await page.locator('#issue-1 .comment-container a[data-tab-for=markdown-previewer]').click(); await page.click('#issue-1 .comment-container .save'); - await page.waitForLoadState('networkidle'); + await page.waitForLoadState(); // Edit again and assert that edit tab should be active (and not preview tab) await page.click('#issue-1 .comment-container .context-menu'); diff --git a/tests/e2e/issue-sidebar.test.e2e.ts b/tests/e2e/issue-sidebar.test.e2e.ts index 31962bf3b4..422f3ef94e 100644 --- a/tests/e2e/issue-sidebar.test.e2e.ts +++ b/tests/e2e/issue-sidebar.test.e2e.ts @@ -11,92 +11,137 @@ test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); }); -// belongs to test: Pull: Toggle WIP -const prTitle = 'pull5'; - -async function click_toggle_wip({page}) { - await page.locator('.toggle-wip>a').click(); - await page.waitForLoadState('networkidle'); -} - -async function check_wip({page}, is) { - const elemTitle = '#issue-title-display'; - const stateLabel = '.issue-state-label'; - await expect(page.locator(elemTitle)).toContainText(prTitle); - await expect(page.locator(elemTitle)).toContainText('#5'); - if (is) { - await expect(page.locator(elemTitle)).toContainText('WIP'); - await expect(page.locator(stateLabel)).toContainText('Draft'); - } else { - await expect(page.locator(elemTitle)).not.toContainText('WIP'); - await expect(page.locator(stateLabel)).toContainText('Open'); +/* 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) { + await page.waitForLoadState('domcontentloaded'); + if (should) { + await page.getByText('Still in progress?').click(); + } else { + await page.getByText('Ready for review?').click(); + } } -} -test('Pull: Toggle WIP', 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'); - const page = await login({browser}, workerInfo); - const response = await page.goto('/user2/repo1/pulls/5'); - expect(response?.status()).toBe(200); // Status OK - // initial state - await check_wip({page}, false); - // toggle to WIP - await click_toggle_wip({page}); - await check_wip({page}, true); - // remove WIP - await click_toggle_wip({page}); - await check_wip({page}, false); + async function check_wip({page}, is) { + const elemTitle = 'h1'; + const stateLabel = '.issue-state-label'; + await page.waitForLoadState('domcontentloaded'); + await expect(page.locator(elemTitle)).toContainText(prTitle); + await expect(page.locator(elemTitle)).toContainText('#5'); + if (is) { + await expect(page.locator(elemTitle)).toContainText('WIP'); + await expect(page.locator(stateLabel)).toContainText('Draft'); + } else { + await expect(page.locator(elemTitle)).not.toContainText('WIP'); + await expect(page.locator(stateLabel)).toContainText('Open'); + } + } - // manually edit title to another prefix - await page.locator('#issue-title-edit-show').click(); - await page.locator('#issue-title-editor input').fill(`[WIP] ${prTitle}`); - await page.getByText('Save').click(); - await page.waitForLoadState('networkidle'); - await check_wip({page}, true); - // remove again - await click_toggle_wip({page}); - await check_wip({page}, false); - // check maximum title length is handled gracefully - const maxLenStr = prTitle + 'a'.repeat(240); - await page.locator('#issue-title-edit-show').click(); - await page.locator('#issue-title-editor input').fill(maxLenStr); - await page.getByText('Save').click(); - await page.waitForLoadState('networkidle'); - await click_toggle_wip({page}); - await check_wip({page}, true); - await click_toggle_wip({page}); - await check_wip({page}, false); - await expect(page.locator('h1')).toContainText(maxLenStr); - // restore original title - await page.locator('#issue-title-edit-show').click(); - await page.locator('#issue-title-editor input').fill(prTitle); - await page.getByText('Save').click(); - await check_wip({page}, false); + test.beforeEach(async ({browser}, workerInfo) => { + const page = await login({browser}, workerInfo); + const response = await page.goto('/user2/repo1/pulls/5'); + expect(response?.status()).toBe(200); // Status OK + // ensure original title + await page.locator('#issue-title-edit-show').click(); + await page.locator('#issue-title-editor input').fill(prTitle); + await page.getByText('Save').click(); + await check_wip({page}, false); + }); + + test('simple toggle', 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'); + const page = await login({browser}, workerInfo); + await page.goto('/user2/repo1/pulls/5'); + // toggle to WIP + await toggle_wip_to({page}, true); + await check_wip({page}, true); + // remove WIP + await toggle_wip_to({page}, false); + await check_wip({page}, false); + }); + + test('manual edit', 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'); + 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(); + await page.locator('#issue-title-editor input').fill(`[WIP] ${prTitle}`); + await page.getByText('Save').click(); + await check_wip({page}, true); + // remove again + await toggle_wip_to({page}, false); + await check_wip({page}, false); + }); + + test('maximum title length', 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'); + 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); + await page.locator('#issue-title-edit-show').click(); + await page.locator('#issue-title-editor input').fill(maxLenStr); + await page.getByText('Save').click(); + await expect(page.locator('h1')).toContainText(maxLenStr); + await check_wip({page}, false); + await toggle_wip_to({page}, true); + await check_wip({page}, true); + await expect(page.locator('h1')).toContainText(maxLenStr); + await toggle_wip_to({page}, false); + await check_wip({page}, false); + 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}) { + 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'); expect(response?.status()).toBe(200); - // preconditions - await expect(labelList.filter({hasText: 'label1'})).toBeVisible(); + + // restore initial state + await page.locator('.select-label').click(); + const responsePromise = page.waitForResponse('/user2/repo1/issues/labels'); + await page.getByText('Clear labels').click(); + await responsePromise; + await expect(labelList.filter({hasText: 'label1'})).toBeHidden(); await expect(labelList.filter({hasText: 'label2'})).toBeHidden(); - // add label2 + + // add both labels await page.locator('.select-label').click(); // label search could be tested this way: // await page.locator('.select-label input').fill('label2'); await page.locator('.select-label .item').filter({hasText: 'label2'}).click(); - await page.locator('.select-label').click(); - await page.waitForLoadState('networkidle'); + await page.locator('.select-label .item').filter({hasText: 'label1'}).click(); + await submitLabels({page}); await expect(labelList.filter({hasText: 'label2'})).toBeVisible(); - // test removing label again - await page.locator('.select-label').click(); - await page.locator('.select-label .item').filter({hasText: 'label2'}).click(); - await page.locator('.select-label').click(); - await page.waitForLoadState('networkidle'); + await expect(labelList.filter({hasText: 'label1'})).toBeVisible(); + + // test removing label2 again + // due to a race condition, the page could still be "reloading", + // closing the dropdown after it was clicked. + // Retry the interaction as a group + // also see https://playwright.dev/docs/test-assertions#expecttopass + await expect(async () => { + await page.locator('.select-label').click(); + await page.locator('.select-label .item').filter({hasText: 'label2'}).click(); + }).toPass(); + await submitLabels({page}); await expect(labelList.filter({hasText: 'label2'})).toBeHidden(); await expect(labelList.filter({hasText: 'label1'})).toBeVisible(); }); @@ -109,11 +154,6 @@ test('Issue: Assignees', async ({browser}, workerInfo) => { const response = await page.goto('/org3/repo3/issues/1'); expect(response?.status()).toBe(200); - // preconditions - await expect(assigneesList.filter({hasText: 'user2'})).toBeVisible(); - await expect(assigneesList.filter({hasText: 'user4'})).toBeHidden(); - await expect(page.locator('.ui.assignees.list .item.no-select')).toBeHidden(); - // Clear all assignees await page.locator('.select-assignees-modify.dropdown').click(); await page.locator('.select-assignees-modify.dropdown .no-select.item').click(); diff --git a/tests/e2e/markup.test.e2e.ts b/tests/e2e/markup.test.e2e.ts index 2cf32669e4..2726942d57 100644 --- a/tests/e2e/markup.test.e2e.ts +++ b/tests/e2e/markup.test.e2e.ts @@ -8,7 +8,6 @@ import {test} from './utils_e2e.ts'; test('markup with #xyz-mode-only', async ({page}) => { const response = await page.goto('/user2/repo1/issues/1'); expect(response?.status()).toBe(200); - await page.waitForLoadState('networkidle'); const comment = page.locator('.comment-body>.markup', {hasText: 'test markup light/dark-mode-only'}); await expect(comment).toBeVisible(); diff --git a/tests/e2e/profile_actions.test.e2e.ts b/tests/e2e/profile_actions.test.e2e.ts index efb4dd2f49..51a690aa60 100644 --- a/tests/e2e/profile_actions.test.e2e.ts +++ b/tests/e2e/profile_actions.test.e2e.ts @@ -13,7 +13,6 @@ test('Follow actions', async ({browser}, workerInfo) => { const page = await context.newPage(); await page.goto('/user1'); - await page.waitForLoadState('networkidle'); // Check if following and then unfollowing works. // This checks that the event listeners of diff --git a/tests/e2e/repo-code.test.e2e.ts b/tests/e2e/repo-code.test.e2e.ts index 5207a6389c..b22670ab76 100644 --- a/tests/e2e/repo-code.test.e2e.ts +++ b/tests/e2e/repo-code.test.e2e.ts @@ -5,11 +5,7 @@ // @watch end import {expect} 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'); -}); +import {test} from './utils_e2e.ts'; async function assertSelectedLines(page, nums) { const pageAssertions = async () => { @@ -33,10 +29,7 @@ async function assertSelectedLines(page, nums) { return pageAssertions(); } -test('Line Range Selection', async ({browser}, workerInfo) => { - const context = await load_logged_in_context(browser, workerInfo, 'user2'); - const page = await context.newPage(); - +test('Line Range Selection', async ({page}) => { const filePath = '/user2/repo1/src/branch/master/README.md?display=source'; const response = await page.goto(filePath); diff --git a/tests/e2e/repo-commitgraph.test.e2e.ts b/tests/e2e/repo-commitgraph.test.e2e.ts index 2a6fb1e6d7..5f0cad117a 100644 --- a/tests/e2e/repo-commitgraph.test.e2e.ts +++ b/tests/e2e/repo-commitgraph.test.e2e.ts @@ -5,11 +5,7 @@ // @watch end import {expect} 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'); -}); +import {test} from './utils_e2e.ts'; test('Commit graph overflow', async ({page}) => { await page.goto('/user2/diff-test/graph'); @@ -18,9 +14,7 @@ test('Commit graph overflow', async ({page}) => { await expect(page.locator('.selection.search.dropdown')).toBeInViewport({ratio: 1}); }); -test('Switch branch', async ({browser}, workerInfo) => { - const context = await load_logged_in_context(browser, workerInfo, 'user2'); - const page = await context.newPage(); +test('Switch branch', async ({page}) => { const response = await page.goto('/user2/repo1/graph'); expect(response?.status()).toBe(200); @@ -29,7 +23,7 @@ test('Switch branch', async ({browser}, workerInfo) => { await input.pressSequentially('develop', {delay: 50}); await input.press('Enter'); - await page.waitForLoadState('networkidle'); + await page.waitForLoadState(); await expect(page.locator('#loading-indicator')).toBeHidden(); await expect(page.locator('#rel-container')).toBeVisible(); diff --git a/tests/e2e/repo-wiki.test.e2e.ts b/tests/e2e/repo-wiki.test.e2e.ts index 5b681c583c..f581ecdab6 100644 --- a/tests/e2e/repo-wiki.test.e2e.ts +++ b/tests/e2e/repo-wiki.test.e2e.ts @@ -9,7 +9,6 @@ import {test} from './utils_e2e.ts'; test(`Search for long titles and test for no overflow`, async ({page}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275'); await page.goto('/user2/repo1/wiki'); - await page.waitForLoadState('networkidle'); await page.getByPlaceholder('Search wiki').fill('spaces'); await page.getByPlaceholder('Search wiki').click(); // workaround: HTMX listens on keyup events, playwright's fill only triggers the input event diff --git a/tests/e2e/utils_e2e.ts b/tests/e2e/utils_e2e.ts index 050847c5ed..89dacce8a4 100644 --- a/tests/e2e/utils_e2e.ts +++ b/tests/e2e/utils_e2e.ts @@ -37,7 +37,7 @@ export async function login_user(browser: Browser, workerInfo: TestInfo, user: s await page.type('input[name=password]', LOGIN_PASSWORD); await page.click('form button.ui.primary.button:visible'); - await page.waitForLoadState('networkidle'); + await page.waitForLoadState(); expect(page.url(), {message: `Failed to login user ${user}`}).toBe(`${workerInfo.project.use.baseURL}/`); @@ -67,7 +67,7 @@ export async function login({browser}: {browser: Browser}, workerInfo: TestInfo) export async function save_visual(page: Page) { // Optionally include visual testing if (process.env.VISUAL_TEST) { - await page.waitForLoadState('networkidle'); + await page.waitForLoadState('domcontentloaded'); // Mock page/version string await page.locator('footer div.ui.left').evaluate((node) => node.innerHTML = 'MOCK'); await expect(page).toHaveScreenshot({ diff --git a/tests/e2e/webauthn.test.e2e.ts b/tests/e2e/webauthn.test.e2e.ts index 38e6b27821..c351b6a468 100644 --- a/tests/e2e/webauthn.test.e2e.ts +++ b/tests/e2e/webauthn.test.e2e.ts @@ -8,7 +8,7 @@ // @watch end import {expect} from '@playwright/test'; -import {test, create_temp_user} from './utils_e2e.ts'; +import {test, create_temp_user, login_user} from './utils_e2e.ts'; test('WebAuthn register & login flow', async ({browser, request}, workerInfo) => { test.skip(workerInfo.project.name !== 'chromium', 'Uses Chrome protocol'); @@ -38,8 +38,10 @@ test('WebAuthn register & login flow', async ({browser, request}, workerInfo) => await page.getByText('Add security key').click(); // Logout. - await page.locator('div[aria-label="Profile and settingsā€¦"]').click(); - await page.getByText('Sign Out').click(); + await expect(async () => { + await page.locator('div[aria-label="Profile and settingsā€¦"]').click(); + await page.getByText('Sign Out').click(); + }).toPass(); await page.waitForURL(`${workerInfo.project.use.baseURL}/`); // Login. @@ -57,5 +59,8 @@ test('WebAuthn register & login flow', async ({browser, request}, workerInfo) => expect(response?.status()).toBe(200); await page.getByRole('button', {name: 'Remove'}).click(); await page.getByRole('button', {name: 'Yes'}).click(); - await page.waitForURL(`${workerInfo.project.use.baseURL}/user/settings/security`); + await page.waitForLoadState(); + + // verify the user can login without a key + await login_user(browser, workerInfo, username); }); From 74923307218903df2d09331e9b104dd109c65cec Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Wed, 13 Nov 2024 12:30:25 +0100 Subject: [PATCH 16/16] chore(ci): trigger a mirror when a release is publish Notify https://code.forgejo.org/forgejo/forgejo that a new release was published by setting the trigger label to https://code.forgejo.org/forgejo/forgejo/issues/5. It is only ever useful when a stable release is published, the experimental releases are not mirrored. But it is triggered in all cases. This will waste a few mirror check daily, when experimental releases are built. This is an improvement compared to the current situation where mirrors are checked hourly: * Instead of being checked 24 times per day it will be down to less than 5 * The mirror happens immediately after the release is published instead of waiting for the next run of the cron job. If a mirror operation is in progress, as evidenced by the presence of the trigger label on the issure, it means two releases are being published. Wait up to 1h for the mirror to complete and remove the trigger label. --- .forgejo/workflows/publish-release.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.forgejo/workflows/publish-release.yml b/.forgejo/workflows/publish-release.yml index 66432f37a0..e4f7028ca7 100644 --- a/.forgejo/workflows/publish-release.yml +++ b/.forgejo/workflows/publish-release.yml @@ -59,6 +59,24 @@ jobs: gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} verbose: ${{ vars.VERBOSE }} + - name: get trigger mirror issue + id: mirror + uses: https://code.forgejo.org/infrastructure/issue-action/get@v1.1.0 + with: + forgejo: https://code.forgejo.org + repository: forgejo/forgejo + labels: mirror-trigger + + - name: trigger the mirror + uses: https://code.forgejo.org/infrastructure/issue-action/set@v1.1.0 + with: + forgejo: https://code.forgejo.org + repository: forgejo/forgejo + token: ${{ secrets.LABEL_ISSUE_FORGEJO_MIRROR_TOKEN }} + numbers: ${{ steps.mirror.outputs.numbers }} + label-wait-if-exists: 3600 + label: trigger + - name: upgrade v*.next.forgejo.org uses: https://code.forgejo.org/infrastructure/next-digest@v1.1.0 with: