mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-03 08:02:04 +00:00
117 lines
4.0 KiB
Go
117 lines
4.0 KiB
Go
package models
|
|
|
|
import "testing"
|
|
|
|
// StepSubject answers "what subject does this step actually send", which is
|
|
// not the column once a step replies in the contact's thread. Preflight, the
|
|
// content score and the test send all read it, and getting it wrong reports
|
|
// every follow-up as having no subject line (issue #472).
|
|
func TestStepSubject(t *testing.T) {
|
|
steps := []Sequence{
|
|
{Subject: "Quick question", Kind: "email", ThreadReply: true},
|
|
{Subject: "", Kind: "email", ThreadReply: true},
|
|
{Subject: "", Kind: "action", ThreadReply: true},
|
|
{Subject: "", Kind: "email", ThreadReply: true},
|
|
{Subject: "New angle", Kind: "email", ThreadReply: false},
|
|
{Subject: "", Kind: "email", ThreadReply: true},
|
|
{Subject: "Own subject", Kind: "email", ThreadReply: false},
|
|
}
|
|
for _, tc := range []struct {
|
|
name string
|
|
i int
|
|
want string
|
|
}{
|
|
{"the first step writes its own", 0, "Quick question"},
|
|
{"a follow-up inherits the conversation's", 1, "Quick question"},
|
|
{"an action node between steps is skipped", 3, "Quick question"},
|
|
{"a step that starts a new thread keeps its own", 4, "New angle"},
|
|
{"the steps after it inherit that one", 5, "New angle"},
|
|
{"a step opting out writes its own", 6, "Own subject"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := StepSubject(steps, tc.i); got != tc.want {
|
|
t.Errorf("StepSubject(%d) = %q, want %q", tc.i, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// A threading step with no earlier email to inherit from falls back to its
|
|
// own subject rather than sending a blank one. That is the branch-reached and
|
|
// the deleted-predecessor case, and it is also what the send path does when it
|
|
// finds no parent.
|
|
func TestStepSubjectFallsBackWhenThereIsNothingToInherit(t *testing.T) {
|
|
steps := []Sequence{
|
|
{Subject: "", Kind: "action", ThreadReply: true},
|
|
{Subject: "Only subject", Kind: "email", ThreadReply: true},
|
|
}
|
|
if got := StepSubject(steps, 1); got != "Only subject" {
|
|
t.Errorf("StepSubject = %q, want the step's own subject", got)
|
|
}
|
|
}
|
|
|
|
// An index nobody has is not a panic.
|
|
func TestStepSubjectOutOfRange(t *testing.T) {
|
|
if got := StepSubject(nil, 0); got != "" {
|
|
t.Errorf("StepSubject(nil, 0) = %q, want empty", got)
|
|
}
|
|
if got := StepSubject([]Sequence{{Subject: "x"}}, 3); got != "" {
|
|
t.Errorf("StepSubject(_, 3) = %q, want empty", got)
|
|
}
|
|
}
|
|
|
|
// ThreadReplyDefaults is what keeps `POST /campaigns` with `steps` behaving the
|
|
// way it always has for a caller that does not know the field exists: a step
|
|
// carrying a subject that is not the conversation's opens a new one, a blank or
|
|
// repeated subject continues it (issue #472).
|
|
func TestThreadReplyDefaults(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
subjects []string
|
|
want []bool
|
|
}{
|
|
{
|
|
"a blank follow-up continues the conversation, and so does the step after it",
|
|
[]string{"Quick question", "", "Quick question"},
|
|
[]bool{true, true, true},
|
|
},
|
|
{
|
|
"a subject of its own opens a new conversation, which the next step then continues",
|
|
[]string{"Quick question", "New angle", ""},
|
|
[]bool{true, false, true},
|
|
},
|
|
{
|
|
"a step repeating an older subject, not the current conversation's, opens its own",
|
|
[]string{"Quick question", "", "New angle", "", "Quick question"},
|
|
[]bool{true, true, false, true, false},
|
|
},
|
|
{
|
|
"whitespace is not a different subject",
|
|
[]string{"Quick question", " Quick question "},
|
|
[]bool{true, true},
|
|
},
|
|
{
|
|
"nothing to differ from yet",
|
|
[]string{"", "Quick question"},
|
|
[]bool{true, true},
|
|
},
|
|
{"no steps", nil, []bool{}},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
steps := make([]CreateSequenceInput, 0, len(tc.subjects))
|
|
for _, sub := range tc.subjects {
|
|
steps = append(steps, CreateSequenceInput{Subject: sub})
|
|
}
|
|
got := ThreadReplyDefaults(steps)
|
|
if len(got) != len(tc.want) {
|
|
t.Fatalf("got %d answers, want %d", len(got), len(tc.want))
|
|
}
|
|
for i := range got {
|
|
if got[i] != tc.want[i] {
|
|
t.Errorf("step %d = %v, want %v (subjects %q)", i, got[i], tc.want[i], tc.subjects)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|