Skip to content
quarry Artifact [e946a1be95]
Login

Artifact [e946a1be95]

Artifact e946a1be95579c4f358d6307b9a0e8125230892707a096ee3e1d3e169b5c93f6:


package web

import (
	"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)
		}
	}
}