Skip to content
quarry Artifact [04c334875f]
Login

Artifact [04c334875f]

Artifact 04c334875ff298a9322b093c74be5d0bdb7e59925b409d04ebae5c3ff3284b8f:


package web

import (
	"strings"
	"testing"
)

func renderSettings(t *testing.T, d pageData) string {
	t.Helper()
	var sb strings.Builder
	if err := settingsPage.Execute(&sb, d); err != nil {
		t.Fatalf("render: %v", err)
	}
	return sb.String()
}

// The section is gated on the PLANE, not on the list. A repository with
// no subscriptions must still show the form that creates the first one —
// gating on the list is how a settings screen becomes impossible to use.
func TestWebhookFormRendersWithNoSubscriptions(t *testing.T) {
	got := renderSettings(t, pageData{Repo: "alpha", HasHooks: true})
	if !strings.Contains(got, `action="/r/alpha/settings/hooks"`) {
		t.Error("no webhook form on a repository with zero subscriptions")
	}
	if !strings.Contains(got, `value="add"`) {
		t.Error("no add action")
	}
}

// No store attached is not the same fact as no subscriptions, and only
// one of them invites a click.
func TestWebhookSectionAbsentWithoutAStore(t *testing.T) {
	got := renderSettings(t, pageData{Repo: "alpha"})
	if strings.Contains(got, "/settings/hooks") {
		t.Error("drew a webhook form with no store behind it")
	}
}

func TestWebhookRowsCarryTheirActions(t *testing.T) {
	got := renderSettings(t, pageData{Repo: "alpha", HasHooks: true, Hooks: []HookSub{
		{ID: 7, URL: "https://example.test/h", Events: "ticket", Active: true},
		{ID: 8, URL: "https://example.test/j", Events: "*", Active: false},
	}})
	for _, want := range []string{
		`value="7"`, `value="8"`,
		`value="ticket"`, // the selection is editable in place
		`value="pause"`,  // an active subscription offers pause
		`value="resume"`, // a paused one offers resume
		`value="delete"`,
		`value="events"`,
	} {
		if !strings.Contains(got, want) {
			t.Errorf("missing %s", want)
		}
	}
}

// The secret exists in exactly one render and is never stored readable,
// so the one render has to actually show it.
func TestNewSecretShownOnce(t *testing.T) {
	got := renderSettings(t, pageData{Repo: "alpha", HasHooks: true, NewHookSecret: "deadbeef"})
	if !strings.Contains(got, "deadbeef") {
		t.Error("a freshly minted secret was not shown")
	}
	if strings.Contains(renderSettings(t, pageData{Repo: "alpha", HasHooks: true}), "deadbeef") {
		t.Error("the secret survived into a later render")
	}
}

func TestCheckPatternsRefusesWhatCannotMatch(t *testing.T) {
	for _, ok := range []string{"", "*", "ticket", "ticket.closed", "ticket landing.accepted"} {
		if err := checkPatterns(ok); err != nil {
			t.Errorf("checkPatterns(%q) = %v, want nil", ok, err)
		}
	}
	// "tickets" is the typo that would otherwise deliver nothing and
	// read as a broken forge.
	for _, bad := range []string{"tickets", "ticket.exploded", "landing.merged"} {
		if err := checkPatterns(bad); err == nil {
			t.Errorf("checkPatterns(%q) accepted a pattern no event matches", bad)
		}
	}
}