Artifact e946a1be95579c4f358d6307b9a0e8125230892707a096ee3e1d3e169b5c93f6:
- File
internal/web/syncurl_test.go
— part of check-in
[058a2216c9]
at
2026-08-27 10:52:44
on branch url-sync-helper
— One definition of swap-the-body-and-fix-the-URL
The diff toggle carried the replaceState handler as literal text in two attributes, with the reasoning in a comment above them. Both move onto a syncurl helper, so the next surface that needs it gets the try/catch and the replaceState-not-pushState choice for free instead of by copy-paste. Emitted markup is unchanged.
The helper neutralizes quotes in the fragment URL: it lands inside a JS string inside an attribute built as HTMLAttr, where escaping is off. (user: dmestas, size: 1826) [annotate] [blame] [check-ins using] [more...]
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) } } }