Five explicit footer states, status-primary:
1. Summarized — chip + actions, no button (unchanged)
2. No captions (TranscriptStatus=="none") — NEW: 'No transcript available' muted
text, no button, no POST URL. Removes the dead-end 'Summarize' button that
tried and failed when there were no captions to fetch.
3. Queued (SummarizeRequested) — chip + muted text, no button (unchanged)
4. Rate-limited — 'Fetching soon…' + quiet 'Summarize now' → /retry-now
5. Pending — 'Not summarized' + quiet 'Summarize now' → /summarize
One verb ('Summarize now'), one quiet style (.btn-quiet, renamed from .btn-retry
which was state-specific). User doesn't see the internal pipeline distinction;
both buttons post to their existing handlers unchanged. Form class renamed
card-nudge-form. Dropped engineer-facing tooltip; user-facing hint added.
'Try now' wording removed entirely.
154 lines
5.0 KiB
Go
154 lines
5.0 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.d-ma.be/mathias/tapir/internal/adapters/store"
|
|
)
|
|
|
|
func renderVideoCard(t *testing.T, r store.SummaryRow) string {
|
|
t.Helper()
|
|
var sb strings.Builder
|
|
if err := VideoCard(r).Render(context.Background(), &sb); err != nil {
|
|
t.Fatalf("render VideoCard: %v", err)
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// noActionButton asserts the rendered HTML contains no form POST (no action URL
|
|
// of the form /v/.../summarize or /v/.../retry-now) and no btn-quiet button.
|
|
func noActionButton(t *testing.T, html, state string) {
|
|
t.Helper()
|
|
if strings.Contains(html, "/summarize") {
|
|
t.Errorf("state %q: expected no summarize URL, got:\n%s", state, html)
|
|
}
|
|
if strings.Contains(html, "/retry-now") {
|
|
t.Errorf("state %q: expected no retry-now URL, got:\n%s", state, html)
|
|
}
|
|
if strings.Contains(html, "btn-quiet") {
|
|
t.Errorf("state %q: expected no action button, got:\n%s", state, html)
|
|
}
|
|
}
|
|
|
|
// TestVideoCard_State1_Summarized — chip + no nudge button.
|
|
func TestVideoCard_State1_Summarized(t *testing.T) {
|
|
html := renderVideoCard(t, store.SummaryRow{
|
|
VideoID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
Title: "Done Video",
|
|
Summarized: true,
|
|
Summary: "A great talk about Go.",
|
|
AIProvider: "local",
|
|
})
|
|
|
|
if !strings.Contains(html, "local") {
|
|
t.Errorf("state 1: expected AI provider chip, got:\n%s", html)
|
|
}
|
|
noActionButton(t, html, "summarized")
|
|
if strings.Contains(html, "Summarize now") {
|
|
t.Errorf("state 1: no nudge button on a summarized card, got:\n%s", html)
|
|
}
|
|
}
|
|
|
|
// TestVideoCard_State2_NoTranscript — terminal; muted status, NO button, NO POST URL.
|
|
func TestVideoCard_State2_NoTranscript(t *testing.T) {
|
|
html := renderVideoCard(t, store.SummaryRow{
|
|
VideoID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
Title: "Silent Video",
|
|
Summarized: false,
|
|
TranscriptStatus: "none",
|
|
})
|
|
|
|
if !strings.Contains(html, "No transcript available") {
|
|
t.Errorf("state 2: expected 'No transcript available' text, got:\n%s", html)
|
|
}
|
|
noActionButton(t, html, "none-transcript")
|
|
if strings.Contains(html, "Summarize now") {
|
|
t.Errorf("state 2: no nudge button when there are no captions, got:\n%s", html)
|
|
}
|
|
}
|
|
|
|
// TestVideoCard_State3_Queued — "Queued" chip, no button.
|
|
func TestVideoCard_State3_Queued(t *testing.T) {
|
|
html := renderVideoCard(t, store.SummaryRow{
|
|
VideoID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
Title: "Queued Video",
|
|
Summarized: false,
|
|
SummarizeRequested: true,
|
|
})
|
|
|
|
if !strings.Contains(html, "Queued") {
|
|
t.Errorf("state 3: expected 'Queued' chip, got:\n%s", html)
|
|
}
|
|
noActionButton(t, html, "queued")
|
|
}
|
|
|
|
// TestVideoCard_State4_RateLimited — quiet status + "Summarize now" → retry-now URL.
|
|
func TestVideoCard_State4_RateLimited(t *testing.T) {
|
|
html := renderVideoCard(t, store.SummaryRow{
|
|
VideoID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
Title: "Throttled Video",
|
|
Summarized: false,
|
|
TranscriptStatus: "rate_limited",
|
|
})
|
|
|
|
if !strings.Contains(html, "Fetching soon") {
|
|
t.Errorf("state 4: expected 'Fetching soon' status text, got:\n%s", html)
|
|
}
|
|
if !strings.Contains(html, "Summarize now") {
|
|
t.Errorf("state 4: expected 'Summarize now' button, got:\n%s", html)
|
|
}
|
|
if !strings.Contains(html, "retry-now") {
|
|
t.Errorf("state 4: expected retry-now URL in form action, got:\n%s", html)
|
|
}
|
|
if strings.Contains(html, "/summarize\"") {
|
|
t.Errorf("state 4: rate-limited card must not POST to /summarize, got:\n%s", html)
|
|
}
|
|
if strings.Contains(html, "Try now") {
|
|
t.Errorf("state 4: 'Try now' verb must not appear, got:\n%s", html)
|
|
}
|
|
}
|
|
|
|
// TestVideoCard_State5_Pending — quiet status + "Summarize now" → summarize URL.
|
|
func TestVideoCard_State5_Pending(t *testing.T) {
|
|
html := renderVideoCard(t, store.SummaryRow{
|
|
VideoID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
Title: "Fresh Video",
|
|
Summarized: false,
|
|
})
|
|
|
|
if !strings.Contains(html, "Not summarized") {
|
|
t.Errorf("state 5: expected 'Not summarized' status text, got:\n%s", html)
|
|
}
|
|
if !strings.Contains(html, "Summarize now") {
|
|
t.Errorf("state 5: expected 'Summarize now' button, got:\n%s", html)
|
|
}
|
|
if !strings.Contains(html, "/summarize") {
|
|
t.Errorf("state 5: expected summarize URL in form action, got:\n%s", html)
|
|
}
|
|
if strings.Contains(html, "retry-now") {
|
|
t.Errorf("state 5: pending card must not POST to /retry-now, got:\n%s", html)
|
|
}
|
|
if strings.Contains(html, "Try now") {
|
|
t.Errorf("state 5: 'Try now' verb must not appear, got:\n%s", html)
|
|
}
|
|
}
|
|
|
|
// TestVideoCard_TryNowAbsent — "Try now" must not appear in any rendered card.
|
|
func TestVideoCard_TryNowAbsent(t *testing.T) {
|
|
cases := []store.SummaryRow{
|
|
{VideoID: "a", Summarized: true, Summary: "s", AIProvider: "local"},
|
|
{VideoID: "b", TranscriptStatus: "none"},
|
|
{VideoID: "c", SummarizeRequested: true},
|
|
{VideoID: "d", TranscriptStatus: "rate_limited"},
|
|
{VideoID: "e"},
|
|
}
|
|
for _, r := range cases {
|
|
html := renderVideoCard(t, r)
|
|
if strings.Contains(html, "Try now") {
|
|
t.Errorf("'Try now' must not appear in any card state; video %q got:\n%s", r.VideoID, html)
|
|
}
|
|
}
|
|
}
|