Skip to content
quarry Artifact [edc6499913]
Login

Artifact [edc6499913]

Artifact edc649991374c2e72243f4d9956058995d666bb6145db219d6923b26ecd58c23:


package web

import (
	"encoding/json"
	"strings"
	"testing"
)

// The handler has three moving parts that all matter, and none of them
// are visible in a rendered page: the address-bar correction reads the
// link's OWN href, it is wrapped so a throw cannot cancel the fetch, and
// the fetch still happens. Pin the shape, not the prose.
func TestSyncURLAttrShape(t *testing.T) {
	got := string(syncURLAttr("/r/x/doc.frag?doc=README.md"))
	for _, want := range []string{
		`data-on:click__prevent="`,
		`history.replaceState(null,''`,
		`evt.currentTarget.getAttribute('href')`,
		`try{`, `}catch(e){}`,
		`@get('/r/x/doc.frag?doc=README.md')`,
	} {
		if !strings.Contains(got, want) {
			t.Fatalf("attribute missing %q:\n%s", want, got)
		}
	}
	// replaceState, not pushState: a view toggle must not make the back
	// button walk every view the reader tried.
	if strings.Contains(got, "pushState") {
		t.Fatalf("view toggles must replace, not push:\n%s", got)
	}
	// The catch has to sit around replaceState and NOT around @get, or a
	// cosmetic failure takes the fetch down with it.
	if strings.Index(got, "}catch(e){}") > strings.Index(got, "@get(") {
		t.Fatalf("@get must sit outside the catch, after it:\n%s", got)
	}
}

// The fragment lands inside a JS string inside an HTML attribute with
// escaping switched off. Nothing in it may close either quote.
func TestSyncURLAttrNeutralizesQuotes(t *testing.T) {
	got := string(syncURLAttr(`/x?a='+alert(1)+'&b="&c=\`))
	if strings.Contains(got, `'+alert(1)+'`) {
		t.Fatalf("single quote survived into the JS string:\n%s", got)
	}
	if strings.Contains(got, `b="`) {
		t.Fatalf("double quote survived into the attribute:\n%s", got)
	}
	for _, want := range []string{"%27", "%22", "%5C"} {
		if !strings.Contains(got, want) {
			t.Fatalf("expected %s escape in:\n%s", want, got)
		}
	}
}

// The README/LICENSE tabs are the surface this was built for: their
// href is already the real, cold-loadable route, so the address bar must
// follow it. Render the panel and check the anchor carries both halves.
func TestDocTabsSyncTheURL(t *testing.T) {
	// Built the way the handler builds it — from the op's JSON — so the
	// test cannot drift from the shape the page actually renders.
	var about aboutData
	if err := json.Unmarshal([]byte(`{"docPath":"README.md","docs":[
		{"path":"README.md","label":"README"},
		{"path":"LICENSE","label":"License"}]}`), &about); err != nil {
		t.Fatal(err)
	}
	data := pageData{Repo: "demo", About: &about}
	var buf strings.Builder
	if err := treePage.ExecuteTemplate(&buf, "doc-panel", data); err != nil {
		t.Fatal(err)
	}
	got := buf.String()
	// The no-script path: a plain load of the same view.
	if !strings.Contains(got, `href="/r/demo?doc=LICENSE"`) {
		t.Fatalf("license tab lost its real href:\n%s", got)
	}
	// The scripted path: fragment fetch AND address-bar correction.
	if !strings.Contains(got, `@get('/r/demo/doc.frag?doc=LICENSE')`) {
		t.Fatalf("license tab lost its fragment fetch:\n%s", got)
	}
	if !strings.Contains(got, `history.replaceState`) {
		t.Fatalf("doc tabs swap content without correcting the URL:\n%s", got)
	}
}