package handlers
import (
"net/http"
"net/url"
"strings"
"testing"
"github.com/mixeme/selfpost/internal/app"
"github.com/mixeme/selfpost/internal/store"
)
// The pages of the Outbound group, rendered from the real stores and the
// handlers, with the refusals each form can come back with. Their markup is
// held to the mockups by the guards in internal/web/view; what is checked here
// is that the handlers fill the typed pages from what is stored and that every
// state a form can end in lands on the page that owns it.
func has(t *testing.T, where, body string, wants ...string) {
t.Helper()
for _, w := range wants {
if !strings.Contains(body, w) {
t.Errorf("%s is missing %q:\n%s", where, w, body)
}
}
}
func lacks(t *testing.T, where, body string, gone ...string) {
t.Helper()
for _, g := range gone {
if strings.Contains(body, g) {
t.Errorf("%s carries %q", where, g)
}
}
}
// pageOf reads a page of domain 1 as the global administrator, binding the
// path's {id} the way the router would.
func pageOf(t *testing.T, h http.HandlerFunc, target string) string {
t.Helper()
rec := send(h, &globalPrincipal, "GET", target, map[string]string{"id": "1"}, nil)
if rec.Code != http.StatusOK {
t.Fatalf("GET %s = %d, want 200:\n%s", target, rec.Code, rec.Body.String())
}
return rec.Body.String()
}
func TestDomainsListShowsTheAddFormToTheGlobalRoleOnly(t *testing.T) {
s := newAppStand(t)
body := getBody(t, s.h.HandleDashboard, "/outbound/domains")
has(t, "list", body, `
Outbound domains
`, `
Add a domain
`, `action="/outbound/domains"`,
`example.org`, `href="/outbound/domains/1/delete"`, `1 domain · DNS cached`, `>DKIM`, `>SPF`, `>DMARC`, `mail`)
ops := domainAdmin(t, s.h.store, "ops", s.d.ID)
body = getBodyAs(t, s.h.HandleDashboard, "/outbound/domains", ops)
has(t, "list for a domain administrator", body, `example.org`, `href="/outbound/domains/1"`)
lacks(t, "list for a domain administrator", body, `Add a domain`, `/delete`)
// What the viewer does not reach is not listed.
other, err := s.h.store.AddDomain("other.example.net", "mail")
if err != nil {
t.Fatal(err)
}
lacks(t, "list for a domain administrator", getBodyAs(t, s.h.HandleDashboard, "/outbound/domains", ops), other.Name)
has(t, "list", getBody(t, s.h.HandleDashboard, "/outbound/domains"), other.Name)
}
// A refused name comes back on the list, with what was typed in the field.
func TestAddDomainRefusalKeepsWhatWasTyped(t *testing.T) {
s := newAppStand(t)
rec := postFormAs(s.h.HandleAddDomain, globalPrincipal, "/outbound/domains", nil, url.Values{"name": {`Not A Domain "`}})
if rec.Code != http.StatusBadRequest {
t.Fatalf("a bad name = %d, want 400:\n%s", rec.Code, rec.Body.String())
}
body := rec.Body.String()
has(t, "refused add", body, `
`, `alerts@example.org`, `200 / h`, `2 IPs`,
`href="/outbound/domains/1/applications/`+idStr(a.ID)+`">Edit`,
`mail.example.org`, `STARTTLS (submission)`, `action="/outbound/domains/1/dns-recheck"`,
`href="/outbound/log?domain=example.org"`, `href="/outbound/domains/1/settings"`, `href="/outbound/domains/1/delete"`)
// The flash the redirects carry.
rec := send(s.h.HandleDomainDetail, &globalPrincipal, "GET", "/outbound/domains/1?appsaved=1", s.paths, nil)
has(t, "domain after a save", rec.Body.String(), `
`, `Application saved.`)
// A domain administrator does not get the global role's delete entry.
ops := domainAdmin(t, s.h.store, "ops", s.d.ID)
rec = send(s.h.HandleDomainDetail, &ops, "GET", "/outbound/domains/1", s.paths, nil)
if rec.Code != http.StatusOK {
t.Fatalf("domain page for its administrator = %d", rec.Code)
}
lacks(t, "domain for a domain administrator", rec.Body.String(), `href="/outbound/domains/1/delete"`)
}
func TestDomainPageWithoutApplicationsSaysSo(t *testing.T) {
s := newAppStand(t)
body := pageOf(t, s.h.HandleDomainDetail, "/outbound/domains/1")
has(t, "domain", body, `No applications yet.`)
lacks(t, "domain", body, `
Login
`)
}
// The rest of the settings page, beside the report address (the three choices
// are in handlers_dmarc_test.go).
func TestDomainSettingsPageHasItsBoxes(t *testing.T) {
s := newAppStand(t)
body := pageOf(t, s.h.HandleDomainSettings, "/outbound/domains/1/settings")
has(t, "settings", body, `