jojo/tests/e2e/e2e_test.go
oliverpool 88ba174119 tests: better factory with forgery package (#11356)
### Context

Following the feedback in forgejo/discussions#170 (and my ambitious attempt in forgejo/forgejo#10985), it appears that having an easy-to-use factory package would greatly help get rid of the global fixtures.

I think that the global fixtures are quite harmful (recent example: https://codeberg.org/forgejo/forgejo/pulls/9906#issuecomment-10826066):
- hard to write (contributor must know where to add them)
- hard to change (may break some unrelated tests)
- hard to review (not located near the test code)
- they require the tests to execute sequentially

### Proposed way forward

The `forgery` package (the name represents faking/crafting and sounds good with Forgejo) is meant to replace global yaml fixtures with local go factories. The forgery can currently:
- create users
- create repos
- create organisations

This allowed me to drop `CreateDeclarativeRepoWithOptions` (and deprecate `CreateDeclarativeRepo`).

I think that further changes should be delayed to other PRs (I have a local branch to create `Project`)

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [ ] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [x] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

*The decision if the pull request will be shown in the release notes is up to the mergers / release team.*

The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11356
Reviewed-by: limiting-factor <limiting-factor@noreply.codeberg.org>
2026-05-12 20:57:02 +02:00

144 lines
4.1 KiB
Go

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// This is primarily coped from /tests/integration/integration_test.go
// TODO: Move common functions to shared file
//nolint:forbidigo
package e2e
import (
"context"
"fmt"
"net/url"
"os"
"os/exec"
"path/filepath"
"testing"
"forgejo.org/models/unittest"
"forgejo.org/modules/graceful"
"forgejo.org/modules/log"
"forgejo.org/modules/setting"
"forgejo.org/modules/test"
"forgejo.org/modules/testlogger"
"forgejo.org/modules/util"
"forgejo.org/modules/web"
"forgejo.org/routers"
"forgejo.org/tests"
)
var testE2eWebRoutes *web.Route
func TestMain(m *testing.M) {
defer log.GetManager().Close()
managerCtx, cancel := context.WithCancel(context.Background())
graceful.InitManager(managerCtx)
defer cancel()
tests.InitTest(true)
initChangedFiles()
testE2eWebRoutes = routers.NormalRoutes()
err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(setting.AppWorkPath, "models/fixtures/"),
Base: setting.AppWorkPath,
Dirs: []string{"tests/e2e/fixtures/"},
},
)
if err != nil {
fmt.Printf("Error initializing test database: %v\n", err)
os.Exit(1)
}
exitVal := m.Run()
if err := testlogger.WriterCloser.Reset(); err != nil {
fmt.Printf("testlogger.WriterCloser.Reset: error ignored: %v\n", err)
}
if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil {
fmt.Printf("util.RemoveAll: %v\n", err)
os.Exit(1)
}
if err = util.RemoveAll(setting.Indexer.RepoPath); err != nil {
fmt.Printf("Unable to remove repo indexer: %v\n", err)
os.Exit(1)
}
os.Exit(exitVal)
}
// TestE2e should be the only test e2e necessary. It will collect all "*.test.e2e.ts" 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.ts")
paths, err := filepath.Glob(searchGlob)
if err != nil {
t.Fatal(err)
} else if len(paths) == 0 {
t.Fatal(fmt.Errorf("No e2e tests found in %s", searchGlob))
}
runArgs := []string{"npx", "playwright", "test"}
_, testVisual := os.LookupEnv("VISUAL_TEST")
// To update snapshot outputs
if _, set := os.LookupEnv("ACCEPT_VISUAL"); set {
runArgs = append(runArgs, "--update-snapshots")
}
if project := os.Getenv("PLAYWRIGHT_PROJECT"); project != "" {
runArgs = append(runArgs, "--project="+project)
}
// Create new test for each input file
for _, path := range paths {
_, filename := filepath.Split(path)
testname := filename[:len(filename)-len(filepath.Ext(path))]
if canSkipTest(path) {
fmt.Printf("No related changes for test, skipping: %s\n", filename)
continue
}
t.Run(testname, func(t *testing.T) {
if testname == "buttons.test.e2e" || testname == "dropdown.test.e2e" || testname == "modal.test.e2e" {
defer test.MockVariableValue(&setting.IsProd, false)()
defer test.MockVariableValue(&testE2eWebRoutes, routers.NormalRoutes())()
}
if testname == "codemirror.test.e2e" {
defer test.MockVariableValue(&setting.DisableGitHooks, false)()
}
if testname == "user-settings.test.e2e" {
defer test.MockVariableValue(&setting.Quota.Enabled, true)()
defer test.MockVariableValue(&testE2eWebRoutes, routers.NormalRoutes())()
}
if testname == "runner-management.test.e2e" {
defer unittest.OverrideFixtures("tests/e2e/fixtures/runner-management")()
}
// Default 2 minute timeout
onForgejoRun(t, func(*testing.T, *url.URL) {
DeclareGitRepos(t)
thisTest := runArgs
// when all tests are run, use unique artifacts directories per test to preserve artifacts from other tests
if testVisual {
thisTest = append(thisTest, "--output=tests/e2e/test-artifacts/"+testname)
}
thisTest = append(thisTest, path)
cmd := exec.Command(runArgs[0], thisTest...)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("GITEA_URL=%s", setting.AppURL))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil && !testVisual {
log.Fatal("Playwright Failed: %s", err)
}
})
})
}
}