package notify
import (
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
)
// The client POSTs the Novu-shaped trigger to /v1/events/trigger.
func TestTriggerShape(t *testing.T) {
var got map[string]any
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v1/events/trigger" || r.Method != "POST" {
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
}
b, _ := io.ReadAll(r.Body)
json.Unmarshal(b, &got)
w.WriteHeader(201)
}))
defer srv.Close()
c := New(srv.URL, "")
err := c.Trigger(context.Background(), "quarry-mention",
Recipient{SubscriberID: "dan"},
map[string]any{"repo": "r1", "text": "hi @dan"}, "txn-1")
if err != nil {
t.Fatal(err)
}
if got["name"] != "quarry-mention" || got["transactionId"] != "txn-1" {
t.Fatalf("trigger body = %+v", got)
}
to := got["to"].(map[string]any)
if to["subscriberId"] != "dan" {
t.Fatalf("recipient = %+v", to)
}
if p := got["payload"].(map[string]any); p["repo"] != "r1" {
t.Fatalf("payload = %+v", p)
}
}
// A disabled client (empty base) no-ops without a call.
func TestDisabledClientNoOps(t *testing.T) {
if err := New("", "").Trigger(context.Background(), "x", Recipient{}, nil, ""); err != nil {
t.Fatalf("disabled client should no-op: %v", err)
}
var nilClient *Client
if err := nilClient.Trigger(context.Background(), "x", Recipient{}, nil, ""); err != nil {
t.Fatalf("nil client should no-op: %v", err)
}
}
// A non-2xx response surfaces as an error (best-effort callers log it).
func TestTriggerErrorStatus(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(500)
}))
defer srv.Close()
if err := New(srv.URL, "").Trigger(context.Background(), "x", Recipient{SubscriberID: "u"}, nil, ""); err == nil {
t.Fatal("want error on 500")
}
}
// A step's redirect is snapshotted verbatim by notify — subject and
// body are rendered against the payload, rich fields are not
// (notify#328). An unrendered template is not a destination.
func TestLinkRefusesAnUnrenderedTemplate(t *testing.T) {
raw := Message{Extras: json.RawMessage(`{"redirect":{"url":"{{payload.link}}"}}`)}
if got := raw.Link(); got != "" {
t.Errorf("FAIL: a raw template became a link: %q", got)
}
real := Message{Extras: json.RawMessage(`{"redirect":{"url":"https://forge.example/r/a"}}`)}
if got := real.Link(); got != "https://forge.example/r/a" {
t.Errorf("FAIL: a resolved link was dropped: %q", got)
}
t.Log("ok: only a resolved redirect becomes a link")
}