Initial implementation of the eec-campaigns tool
Drives listmonk's real Campaign API from git-authored Markdown+frontmatter, so broadcast/segment emails get listmonk's mature unsubscribe/bulk-send/ attachment handling instead of reimplementing it. sync only ever creates or updates a draft (idempotent, diff-based, refuses to touch a non-draft campaign); a pushed send/<slug> tag or manual workflow run is the only way to actually trigger a send. Includes list-name resolution, segment_query materialization into managed lists, content-hash-deduped attachment uploads, and an automatic post-sync preview email.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package campaign
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSend_TransitionsDraftToRunning(t *testing.T) {
|
||||
f := newFakeListmonk(t)
|
||||
f.campaigns = []fakeCampaign{{ID: 1, Name: "launch", Status: "draft"}}
|
||||
lm := f.client()
|
||||
|
||||
camp, err := Send(lm, "launch")
|
||||
if err != nil {
|
||||
t.Fatalf("Send: %v", err)
|
||||
}
|
||||
if camp.ID != 1 {
|
||||
t.Errorf("expected campaign id 1, got %d", camp.ID)
|
||||
}
|
||||
if f.campaigns[0].Status != "running" {
|
||||
t.Errorf("expected status running, got %q", f.campaigns[0].Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSend_TransitionsPausedToRunning(t *testing.T) {
|
||||
f := newFakeListmonk(t)
|
||||
f.campaigns = []fakeCampaign{{ID: 1, Name: "launch", Status: "paused"}}
|
||||
lm := f.client()
|
||||
|
||||
if _, err := Send(lm, "launch"); err != nil {
|
||||
t.Fatalf("Send: %v", err)
|
||||
}
|
||||
if f.campaigns[0].Status != "running" {
|
||||
t.Errorf("expected status running, got %q", f.campaigns[0].Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSend_RefusesWhenAlreadyRunning(t *testing.T) {
|
||||
f := newFakeListmonk(t)
|
||||
f.campaigns = []fakeCampaign{{ID: 1, Name: "launch", Status: "running"}}
|
||||
lm := f.client()
|
||||
|
||||
if _, err := Send(lm, "launch"); err == nil || !strings.Contains(err.Error(), "running") {
|
||||
t.Fatalf("expected a refusal mentioning 'running', got %v", err)
|
||||
}
|
||||
if f.campaigns[0].Status != "running" {
|
||||
t.Errorf("expected status to remain running, got %q", f.campaigns[0].Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSend_ErrorsWhenCampaignMissing(t *testing.T) {
|
||||
f := newFakeListmonk(t)
|
||||
lm := f.client()
|
||||
|
||||
if _, err := Send(lm, "nonexistent"); err == nil || !strings.Contains(err.Error(), "run sync first") {
|
||||
t.Fatalf("expected a 'run sync first' error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTest_SendsPreviewToGivenAddresses(t *testing.T) {
|
||||
f := newFakeListmonk(t)
|
||||
f.campaigns = []fakeCampaign{{ID: 1, Name: "launch", Status: "draft"}}
|
||||
lm := f.client()
|
||||
|
||||
if err := Test(lm, "launch", []string{"me@example.com"}); err != nil {
|
||||
t.Fatalf("Test: %v", err)
|
||||
}
|
||||
if len(f.testCalls) != 1 || f.testCalls[0].CampaignID != 1 {
|
||||
t.Fatalf("expected 1 test call against campaign 1, got %+v", f.testCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTest_ErrorsWhenCampaignMissing(t *testing.T) {
|
||||
f := newFakeListmonk(t)
|
||||
lm := f.client()
|
||||
|
||||
if err := Test(lm, "nonexistent", []string{"me@example.com"}); err == nil || !strings.Contains(err.Error(), "run sync first") {
|
||||
t.Fatalf("expected a 'run sync first' error, got %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user