package edge import ( "encoding/json" "os/exec" "regexp" "testing" ) // The pending page's retry script, run for real under node against a fake // browser: storage, window.name, location, the clock and setTimeout. The // substring checks in pending_test.go pin the markup; these pin what the // script DOES. Skipped where node is not installed. type jsTab struct { Storage string `json:"storage"` // "ok", "throws" WindowName string `json:"windowName"` WindowNames bool `json:"windowNameWorks"` Session string `json:"session"` // prior sessionStorage value for the key Now int64 `json:"now"` } type jsOutcome struct { Reload bool `json:"reload"` Replaced string `json:"replaced"` Heading string `json:"heading"` Session string `json:"session"` Window string `json:"windowName"` } var scriptRE = regexp.MustCompile(`(?s)`) func runPendingScript(t *testing.T, fallback string, tab jsTab) jsOutcome { t.Helper() node, err := exec.LookPath("node") if err != nil { t.Skip("node not installed") } m := scriptRE.FindSubmatch(renderPendingPage(fallback)) if m == nil { t.Fatal("no script in the pending page") } in, _ := json.Marshal(tab) prog := ` const tab = ` + string(in) + `; const out = {reload:false, replaced:"", heading:"", session:"", windowName:""}; const store = {}; if (tab.session) store["carlos-pending:x.go.tito.example"] = tab.session; global.sessionStorage = { getItem(k){ if (tab.storage==="throws") throw new Error("SecurityError"); return k in store ? store[k] : null; }, setItem(k,v){ if (tab.storage==="throws") throw new Error("SecurityError"); store[k]=String(v); }, }; let wn = tab.windowName; global.window = {}; Object.defineProperty(global.window, "name", { get(){ return wn; }, set(v){ if (tab.windowNameWorks) wn = String(v); }, }); global.location = { host: "x.go.tito.example", href: "https://x.go.tito.example/p", replace(u){ if (u === this.href) out.reload = true; else out.replaced = u; }, }; Date.now = () => tab.now; global.setTimeout = (fn) => fn(); const els = {h:{textContent:""}, b:{textContent:""}}; global.document = { title:"", getElementById(id){ return els[id]; } }; ` + string(m[1]) + ` out.heading = els.h.textContent; out.session = store["carlos-pending:x.go.tito.example"] || ""; out.windowName = wn; console.log(JSON.stringify(out)); ` cmd := exec.Command(node, "-e", prog) b, err := cmd.CombinedOutput() if err != nil { t.Fatalf("node: %v\n%s", err, b) } var o jsOutcome if err := json.Unmarshal(b, &o); err != nil { t.Fatalf("node output %q: %v", b, err) } return o } func TestPendingScriptFirstLoadRetries(t *testing.T) { o := runPendingScript(t, "", jsTab{Storage: "ok", Now: 1_000_000}) if !o.Reload || o.Heading != "" { t.Fatalf("first load did not schedule a reload: %+v", o) } } func TestPendingScriptGivesUpAfterTheWindow(t *testing.T) { // Seen continuously (last 5s ago) since 95s ago. o := runPendingScript(t, "", jsTab{Storage: "ok", Now: 1_000_000, Session: `{"first":905000,"last":995000}`}) if o.Reload || o.Heading != goneHeading { t.Fatalf("did not give up after the window: %+v", o) } } func TestPendingScriptGivesUpToTheFallback(t *testing.T) { o := runPendingScript(t, "https://www.example.com/", jsTab{Storage: "ok", Now: 1_000_000, Session: `{"first":905000,"last":995000}`}) if o.Replaced != "https://www.example.com/" { t.Fatalf("did not go to the fallback: %+v", o) } } func TestPendingScriptStaleStartIsAFreshEpisode(t *testing.T) { // First seen long ago, but not seen for a minute: a new episode. o := runPendingScript(t, "", jsTab{Storage: "ok", Now: 1_000_000, Session: `{"first":100000,"last":940000}`}) if !o.Reload { t.Fatalf("a stale start time made the page give up at once: %+v", o) } } func TestPendingScriptFallsBackToWindowName(t *testing.T) { o := runPendingScript(t, "", jsTab{Storage: "throws", WindowNames: true, Now: 1_000_000}) if !o.Reload || o.Window == "" { t.Fatalf("with sessionStorage throwing, window.name was not used: %+v", o) } // ...and window.name carries the window across reloads. o = runPendingScript(t, "", jsTab{Storage: "throws", WindowNames: true, Now: 1_000_000, WindowName: `{"first":905000,"last":995000,"k":"carlos-pending:x.go.tito.example"}`}) if o.Reload || o.Heading != goneHeading { t.Fatalf("window.name state did not end the window: %+v", o) } } func TestPendingScriptWithNoStorageNeverLoops(t *testing.T) { o := runPendingScript(t, "", jsTab{Storage: "throws", WindowNames: false, Now: 1_000_000}) if o.Reload || o.Heading != goneHeading { t.Fatalf("with no storage at all the page reloaded instead of giving up: %+v", o) } }