package markup
import (
"strings"
"testing"
)
// hostResolver is a resolver that knows which repository its pages are
// served from — the upgrade that turns a reference link into a
// previewable one (RFC 0011 §14).
type hostResolver struct{ fakeResolver }
func (hostResolver) RefRepo() string { return "de mo" }
func (hostResolver) ResolveToken(t RefToken) (string, bool) {
if t.Kind == RefTicket {
return "/r/demo/ticket/" + t.ID, true
}
return "", false
}
// Every reference on every surface carries the same hooks — the
// unqualified [[wiki]] and bare-hash spellings included. A reader
// hovering a hash in a ticket and a repo-qualified token in chat is
// doing the same thing and must get the same card.
func TestEveryReferenceCarriesThePreviewHook(t *testing.T) {
src := "See [[Design]], abc123def456 and /r/demo/ticket/xy9deadbeef too\n"
out, err := Render([]byte(src), hostResolver{})
if err != nil {
t.Fatal(err)
}
s := string(out)
for _, want := range []string{
`data-ref="wiki/Design"`,
`data-ref-kind="wiki"`,
`data-ref="[abc123def456]"`,
`data-ref-kind="hash"`,
`data-ref="demo:ticket/xy9deadbeef"`,
} {
if !strings.Contains(s, want) {
t.Fatalf("missing hook %s in:\n%s", want, s)
}
}
// One armed anchor per reference: hover, focus and tap.
for _, ev := range []string{"data-on:mouseenter", "data-on:focus", "data-on:click"} {
if n := strings.Count(s, ev); n != 3 {
t.Fatalf("%s appears %d times, want 3 in:\n%s", ev, n, s)
}
}
// The repo rides the fragment URL escaped, never raw.
if !strings.Contains(s, "/r/de+mo/ref.frag?ref=") {
t.Fatalf("fragment URL not escaped:\n%s", s)
}
// The hash link keeps the styling it has had since 0002: the hook
// is added, the look is not changed.
if strings.Contains(s, `class="ref"`) && !strings.Contains(s, `class="ref" data-ref="demo:ticket/xy9deadbeef"`) {
t.Fatalf("hash link restyled:\n%s", s)
}
}
// The card is positioned AT the link that opened it, not centred by
// the UA. CSS anchor positioning where it exists, a measured fallback
// where it does not.
func TestPreviewAttrsPositionTheCardAtTheLink(t *testing.T) {
var joined string
for _, kv := range RefPreviewAttrs("demo", "#5") {
joined += kv[0] + "=" + kv[1] + "\n"
}
for _, want := range []string{
"position-anchor", "anchorName", "getBoundingClientRect",
"showPopover", "refpop",
} {
if !strings.Contains(joined, want) {
t.Fatalf("preview attrs miss %q:\n%s", want, joined)
}
}
}
// A resolver that does not know its repository mints the link and no
// hooks: there is no fragment URL to fetch, and a hook nothing arms is
// a hook that lies.
func TestNoRepoMeansNoHooks(t *testing.T) {
out, err := Render([]byte("See [[Design]].\n"), fakeResolver{})
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(out), "data-on:") {
t.Fatalf("hooks minted without a repository:\n%s", out)
}
}