Skip to content

Testing Web Apps ​

Introduction ​

An app is an http.Handler, so the standard library's httptest tests it. web.New(pages.Routes(), …) receives the generated page table, and each app has its own container and singletons, so every test can build a fresh one.

This page covers request tests, testing services directly, mail and crons, and live pages in a browser.

Testing Requests ​

This test serves the app with httptest and checks that an unknown pet answers 404:

go
func TestPets(t *testing.T) {
	app := web.New()
	app.Service(OpenDB)
	srv := httptest.NewServer(app.Handler())
	defer srv.Close()

	res, err := http.Get(srv.URL + "/pets/9")
	if err != nil {
		t.Fatal(err)
	}
	defer res.Body.Close()
	if res.StatusCode != 404 {
		t.Errorf("GET /pets/9: %d", res.StatusCode)
	}
}

Test files are _test.go; go test ./... runs them (go tool vuka test ./... when the package has .vuka.html templates).

Building the App in a Test ​

These methods and options set up the app a test checks:

app.Build()every problem of the app — a test that the wiring is right, with no request
app.Handler()the handler; panics when Build fails
web.Resolve[T](app)the app's T, built with its dependencies: a service to call directly, or to seed
app.Service(fakeConstructor)a ready value replaces a constructor: provide the fake instead of the real one
web.Only(pkgs…)take only the declarations of these packages (import paths; "main" for the main package)
web.NoDotEnv(), web.DotEnv(files…)which env files a test reads; under go test, .env.test and .env

See Dependency Injection and Configuration.

Testing a Service Directly ​

web.Resolve hands the test a service built with its dependencies, to call without a request:

go
func TestStore(t *testing.T) {
	app := web.New()
	app.Service(OpenDB)
	store, err := web.Resolve[*PetStore](app)
	if err != nil {
		t.Fatal(err)
	}
	p, err := store.Add(NewPet{Name: "Rex"})
	if err != nil {
		t.Fatal(err)
	}
	t.Log("added", p.ID)
}

Limiting a Test to Some Packages ​

web.Only matters when a test binary links packages that declare routes of their own: a library's tests, or an app whose packages each register a few.

Testing Mail and Crons ​

mailtest.New() is a Mailer that keeps what the app sends instead of sending it, and mailtest.Last(t, m) reads it back; see Mail. crontest.Run(app, name) runs a cron with its dependencies, and crontest.NewClock drives the schedule with a virtual clock; see Crons.

Testing Live Pages in a Browser ​

Live components are tested over HTTP for their first render (the page carries data-vk-token=), and in a browser for their events.

web's own tests drive a headless Chrome over the DevTools protocol and skip when none is found; VUKA_CHROME names the binary. See examples/live/main_test.vuka (its Go is what vuka eject writes).

Released under the MIT License. Vuka builds on Go and its tools, which are made by the Go Authors. Vuka is not affiliated with Google or the Go project. Go is a trademark of Google LLC.