//go:build browser package calendartest import ( "context" "io" "log/slog" "net" "net/http" "os/exec" "path/filepath" "regexp" "testing" "time" calendar "amadan.net/oficina/calendar/internal/calendar" ) // TestBookingInARealBrowser drives the stranger's whole journey in // Chromium with JavaScript OFF — the only proof the scriptless floor // is real — and the host's availability pane with it on. // // The hold and the confirm are two node invocations because the link // between them is in a mail only the Go side can read. func TestBookingInARealBrowser(t *testing.T) { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listen: %v", err) } origin := "http://" + ln.Addr().String() app, err := calendar.New(calendar.Config{ DBPath: filepath.Join(t.TempDir(), "calendar.db"), Env: "development", Origin: origin, Logger: slog.New(slog.NewTextHandler(io.Discard, nil)), }) if err != nil { t.Fatalf("calendar.New: %v", err) } t.Cleanup(func() { app.Close() }) srv := &http.Server{Handler: app.Handler()} go func() { _ = srv.Serve(ln) }() t.Cleanup(func() { _ = srv.Close() }) session := signInOverHTTP(t, app, origin, "host@example.com") // The host, the handle and a published page, through the store — // the browser passes are about the stranger's side. ctx := context.Background() st := app.StoreForTest() host := app.PersonByAddressForTest(t, "host@example.com") if err := st.SaveHandle(ctx, host.ID, "paul"); err != nil { t.Fatal(err) } ws, _ := calendar.ParseAvailability("every day 9-5") page, err := st.CreateBookingPage(ctx, host.ID, calendar.BookingPageInput{ Title: "Quick chat", Description: "Half an hour.", Availability: "every day 9-5", DurationMin: 30, HorizonDays: 30}, ws) if err != nil { t.Fatal(err) } if err := st.PublishBookingPage(ctx, host.ID, page.ID, true); err != nil { t.Fatal(err) } public := "/book/paul/" + page.Code node := func(args ...string) { t.Helper() ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) defer cancel() cmd := exec.CommandContext(ctx, "node", append([]string{"test/browser/booking.mjs"}, args...)...) cmd.Dir = repoRootForBrowser(t) out, err := cmd.CombinedOutput() t.Logf("node %s:\n%s", args[0], out) if err != nil { t.Fatalf("the browser checks failed: %v", err) } } node("hold", origin, public) body, err := app.LastMailForTest() if err != nil { t.Fatal(err) } link := regexp.MustCompile(`/book/m/[0-9a-f]{64}`).FindString(body) if link == "" { t.Fatalf("no manage link in the hold mail:\n%s", body) } node("confirm", origin, link) node("pane", origin, session.Name, session.Value) }