7de788ceed
* feat: add cross-integration entity references * fix(web): anchor entity reference menu to composer * fix: keep Kandev tasks under @ mentions * fix: address entity reference review findings * test(e2e): use option role for prompt menu * test(e2e): update passthrough mention roles * fix: preserve queued references and paginate Azure PRs
117 lines
3.7 KiB
Go
117 lines
3.7 KiB
Go
package entityrefs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"testing"
|
|
|
|
apiv1 "github.com/kandev/kandev/pkg/api/v1"
|
|
)
|
|
|
|
func TestNormalizeForSubmissionCanonicalizesAndDeduplicates(t *testing.T) {
|
|
ref := apiv1.EntityReference{
|
|
Version: apiv1.EntityReferenceVersion,
|
|
Ref: CanonicalRef("jira", "issue", " site-a ", " 10001 "),
|
|
Provider: " jira ",
|
|
Kind: " issue ",
|
|
ID: " 10001 ",
|
|
Key: " ENG-7\n",
|
|
Title: " Fix\n authentication ",
|
|
URL: " https://jira.example.test/browse/ENG-7 ",
|
|
Scope: " site-a ",
|
|
}
|
|
|
|
got, err := NormalizeForSubmission([]apiv1.EntityReference{ref, ref})
|
|
if err != nil {
|
|
t.Fatalf("normalize: %v", err)
|
|
}
|
|
if len(got) != 1 {
|
|
t.Fatalf("references = %#v, want one deduplicated reference", got)
|
|
}
|
|
want := apiv1.EntityReference{
|
|
Version: apiv1.EntityReferenceVersion,
|
|
Ref: CanonicalRef("jira", "issue", "site-a", "10001"),
|
|
Provider: "jira",
|
|
Kind: "issue",
|
|
ID: "10001",
|
|
Key: "ENG-7",
|
|
Title: "Fix authentication",
|
|
URL: "https://jira.example.test/browse/ENG-7",
|
|
Scope: "site-a",
|
|
}
|
|
if got[0] != want {
|
|
t.Fatalf("reference = %#v, want %#v", got[0], want)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeForSubmissionRejectsMalformedKnownVersion(t *testing.T) {
|
|
valid := apiv1.EntityReference{
|
|
Version: apiv1.EntityReferenceVersion,
|
|
Ref: CanonicalRef("kandev", "task", "workspace-1", "task-1"),
|
|
Provider: "kandev", Kind: "task", ID: "task-1",
|
|
Title: "Task", URL: "/t/task-1", Scope: "workspace-1",
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
edit func(*apiv1.EntityReference)
|
|
}{
|
|
{name: "spoofed ref", edit: func(ref *apiv1.EntityReference) { ref.Ref = "mention:v1:kandev:task:workspace-1:other" }},
|
|
{name: "unsafe scheme", edit: func(ref *apiv1.EntityReference) { ref.URL = "javascript:alert(1)" }},
|
|
{name: "external internal route", edit: func(ref *apiv1.EntityReference) {
|
|
ref.Provider = "jira"
|
|
ref.Ref = CanonicalRef("jira", "task", ref.Scope, ref.ID)
|
|
}},
|
|
{name: "wrong task route", edit: func(ref *apiv1.EntityReference) { ref.URL = "/t/other" }},
|
|
{name: "empty title", edit: func(ref *apiv1.EntityReference) { ref.Title = " \n " }},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
ref := valid
|
|
test.edit(&ref)
|
|
_, err := NormalizeForSubmission([]apiv1.EntityReference{ref})
|
|
if !errors.Is(err, ErrInvalidReference) {
|
|
t.Fatalf("error = %v, want invalid reference", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeForSubmissionOmitsUnknownVersion(t *testing.T) {
|
|
got, err := NormalizeForSubmission([]apiv1.EntityReference{{
|
|
Version: 99, Ref: "future", Provider: "future", Kind: "thing", ID: "1",
|
|
Title: "Future", URL: "https://future.test/1", Scope: "tenant",
|
|
}})
|
|
if err != nil {
|
|
t.Fatalf("normalize: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("references = %#v, want unknown version omitted", got)
|
|
}
|
|
}
|
|
|
|
func TestNormalizePersistedDecodesJSONRoundTripAndOmitsMalformed(t *testing.T) {
|
|
valid := apiv1.EntityReference{
|
|
Version: apiv1.EntityReferenceVersion,
|
|
Ref: CanonicalRef("linear", "issue", "acme", "issue-1"),
|
|
Provider: "linear", Kind: "issue", ID: "issue-1", Key: "ENG-1",
|
|
Title: "Fix auth", URL: "https://linear.app/acme/issue/ENG-1", Scope: "acme",
|
|
}
|
|
rawJSON, err := json.Marshal([]apiv1.EntityReference{valid, {
|
|
Version: apiv1.EntityReferenceVersion,
|
|
Ref: "bad", Provider: "linear", Kind: "issue", ID: "bad",
|
|
Title: "Bad", URL: "https://linear.app/bad", Scope: "acme",
|
|
}})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
var roundTripped any
|
|
if err := json.Unmarshal(rawJSON, &roundTripped); err != nil {
|
|
t.Fatalf("unmarshal: %v", err)
|
|
}
|
|
|
|
got := NormalizePersisted(roundTripped)
|
|
if len(got) != 1 || got[0] != valid {
|
|
t.Fatalf("references = %#v, want only valid typed reference", got)
|
|
}
|
|
}
|