rastrillo / fiesta Public

Run the cache drive where the cache works

TestADemoComesBackFromTheCacheInTheStoredScheme needs a real back/forward cache restore, which only full Chromium gives; the headless shell the fleet links as chromium never restores, and the Makefile gives full Chromium to check and internal/gallery/history only. In internal/gallery it would fail on the fleet naming the engine's reason rather than test the restore. It moves, unchanged in what it drives and asserts, into internal/gallery/history beside the other cache legs, with the four small helpers it needs there (the frame document's path, the manifest's default state, a fatal Run, a JSON read) and its two readings, schemeMarkJS and schemeOf. stage_browser_test.go keeps the first-paint drive, which needs no restore, and drops the strconv import the cache drive alone used.

Run in the history role (make browser.internal.gallery.history, the FULL_CHROMIUM package): TestTheSchemeFollowsAPageBackFromTheCache, TestTheSwitchersAddressIsNeverLeftChanged and TestADemoComesBackFromTheCacheInTheStoredScheme all pass, the last in 4.4s with every return a real restore.

Gated with make ci in a detached /var/tmp worktree at 992b61e with the two earlier fixes and these two files copied in, every role green.
Human

Prompt

Astra on Task 5's fixes: TestADemoComesBackFromTheCacheInTheStoredScheme (stage_browser_test.go:359) needs full Chromium but internal/gallery runs on the headless shell; move it into internal/gallery/history (the package Task 3 set up on full Chromium, Makefile:187), with whatever helper it needs there, and confirm it runs and passes in that role.

From this commit's own message. The prompt ledger has no entries for it — which is what a squashed, rebased or amended commit looks like, and what every commit looks like in a repo without a ledger.

Summary

The demo cache drive moves from internal/gallery to internal/gallery/history, the package the Makefile runs on full Chromium, with the helpers it needs; it passes in that role.
Agent notes
frameDoc and defaultState are local to history because frameFile and mustDefault are test helpers of package gallery. If galleryrig grows a frame-path helper, both can use it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 448955d06dbd8843bf9a7c9ad0c5c0f38d9981e4 parent 0e06678
2 files changed, +193 −126
  • internal/gallery/history/demo_cache_browser_test.go +190 −0
  • internal/gallery/stage_browser_test.go +3 −126

CI passed — run details

CI log
=== gofmt ===
=== no-rastrillo ===
go test -run '^(TestFiestaNeverImportsRastrillo|TestThePublicPackagesLinkNoBrowser)$' -count=1 .
ok  	amadan.net/rastrillo/fiesta	0.107s
=== size ===
go test ./internal/build -run '^TestTheOneLinkIsUnder25KiBGzipped$' -count=1 -v
=== RUN   TestTheOneLinkIsUnder25KiBGzipped
    build_test.go:138: fiesta-plain.css: 152856 bytes, 22303 bytes gzipped (21.8 KiB of the 25.0 KiB limit)
    build_test.go:138: fiesta-signal.css: 152951 bytes, 22414 bytes gzipped (21.9 KiB of the 25.0 KiB limit)
    build_test.go:138: fiesta.css: 155770 bytes, 23018 bytes gzipped (22.5 KiB of the 25.0 KiB limit)
--- PASS: TestTheOneLinkIsUnder25KiBGzipped (0.02s)
PASS
ok  	amadan.net/rastrillo/fiesta/internal/build	0.020s
=== suite ===
--- shard 0 of 15 ---
==> shard 0 of 15: make root
go build ./...
go vet ./...
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 go test -count=1 ./...
ok  	amadan.net/rastrillo/fiesta	1.306s
ok  	amadan.net/rastrillo/fiesta/check	5.787s
ok  	amadan.net/rastrillo/fiesta/cmd/fiesta	91.426s
ok  	amadan.net/rastrillo/fiesta/example	0.230s
ok  	amadan.net/rastrillo/fiesta/internal/axe	0.175s
ok  	amadan.net/rastrillo/fiesta/internal/build	1.875s
ok  	amadan.net/rastrillo/fiesta/internal/codeview	0.010s
ok  	amadan.net/rastrillo/fiesta/internal/gallery	81.278s
?   	amadan.net/rastrillo/fiesta/internal/harness	[no test files]
ok  	amadan.net/rastrillo/fiesta/internal/markup	0.007s
ok  	amadan.net/rastrillo/fiesta/internal/nodetest	0.460s
ok  	amadan.net/rastrillo/fiesta/internal/site	4.225s
ok  	amadan.net/rastrillo/fiesta/internal/tokens	0.007s
ok  	amadan.net/rastrillo/fiesta/internal/www	78.522s
--- shard 1 of 15 ---
==> shard 1 of 15: make staticcheck
go run honnef.co/go/tools/cmd/staticcheck@v0.8.2 -tags browser ./...
--- shard 2 of 15 ---
==> shard 2 of 15: make govulncheck
go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./...
=== Symbol Results ===

No vulnerabilities found.

Your code is affected by 0 vulnerabilities.
This scan also found 2 vulnerabilities in packages you import and 5
vulnerabilities in modules you require, but your code doesn't appear to call
these vulnerabilities.
Use '-show verbose' for more details.
--- shard 3 of 15 ---
==> shard 3 of 15: make gitleaks
go run github.com/zricethezav/gitleaks/v8@v8.30.1 git --no-banner --redact --log-opts='--full-history --diff-filter=tuxdb HEAD' .
3:00AM INF Unknown SCM platform. Use --platform to include links in findings. host=amadan.net
3:00AM INF 1 commits scanned.
3:00AM INF scanned ~6231653 bytes (6.23 MB) in 4.31s
3:00AM INF no leaks found
--- shard 4 of 15 ---
==> shard 4 of 15: make browser.internal.harness
./hack/gotest.sh browser 'internal.harness'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
ok  	amadan.net/rastrillo/fiesta/internal/harness	12.351s
--- shard 5 of 15 ---
==> shard 5 of 15: make browser.check~1of3
./hack/gotest.sh browser 'check~1of3'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 1 of 3 of ./check/ runs 95 of 286 tests
ok  	amadan.net/rastrillo/fiesta/check	228.183s
--- shard 6 of 15 ---
==> shard 6 of 15: make browser.check~2of3
./hack/gotest.sh browser 'check~2of3'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 2 of 3 of ./check/ runs 95 of 286 tests
ok  	amadan.net/rastrillo/fiesta/check	244.164s
--- shard 7 of 15 ---
==> shard 7 of 15: make browser.check~3of3
./hack/gotest.sh browser 'check~3of3'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 3 of 3 of ./check/ runs 96 of 286 tests
ok  	amadan.net/rastrillo/fiesta/check	247.192s
--- shard 8 of 15 ---
==> shard 8 of 15: make browser.internal.gallery~1of4
./hack/gotest.sh browser 'internal.gallery~1of4'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 1 of 4 of ./internal/gallery/ runs 1 of 104 tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	119.717s
--- shard 9 of 15 ---
==> shard 9 of 15: make browser.internal.gallery~2of4
./hack/gotest.sh browser 'internal.gallery~2of4'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 2 of 4 of ./internal/gallery/ runs 32 of 104 tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	106.336s
--- shard 10 of 15 ---
==> shard 10 of 15: make browser.internal.gallery~3of4
./hack/gotest.sh browser 'internal.gallery~3of4'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 3 of 4 of ./internal/gallery/ runs 35 of 104 tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	82.111s
--- shard 11 of 15 ---
==> shard 11 of 15: make browser.internal.gallery~4of4
./hack/gotest.sh browser 'internal.gallery~4of4'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 4 of 4 of ./internal/gallery/ runs 36 of 104 tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	101.321s
--- shard 12 of 15 ---
==> shard 12 of 15: make browser.internal.gallery.history
./hack/gotest.sh browser 'internal.gallery.history'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
ok  	amadan.net/rastrillo/fiesta/internal/gallery/history	34.555s
--- shard 13 of 15 ---
==> shard 13 of 15: make browser.internal.www~1of2
./hack/gotest.sh browser 'internal.www~1of2'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 1 of 2 of ./internal/www/ runs 17 of 34 tests
ok  	amadan.net/rastrillo/fiesta/internal/www	133.649s
--- shard 14 of 15 ---
==> shard 14 of 15: make browser.internal.www~2of2
./hack/gotest.sh browser 'internal.www~2of2'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 2 of 2 of ./internal/www/ runs 17 of 34 tests
ok  	amadan.net/rastrillo/fiesta/internal/www	120.470s
diff --git a/internal/gallery/history/demo_cache_browser_test.go b/internal/gallery/history/demo_cache_browser_test.go
new file mode 100644
index 0000000..175a6e6
--- /dev/null
+++ b/internal/gallery/history/demo_cache_browser_test.go
@@ -0,0 +1,190 @@
+//go:build browser
+
+package history
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/chromedp/chromedp"
+
+ "amadan.net/rastrillo/fiesta"
+ "amadan.net/rastrillo/fiesta/example"
+ "amadan.net/rastrillo/fiesta/internal/harness"
+)
+
+// A shell demo opened in a tab of its own, left and come back to from
+// the back/forward cache, in the scheme stored while it was away.
+
+// frameDoc is the path of one state's frame document within the tree.
+func frameDoc(theme, locale, name, state string) string {
+ return theme + "/" + locale + "/frames/" + name + "/" + state + ".html"
+}
+
+// defaultState is the manifest's default state for name.
+func defaultState(t *testing.T, name string) string {
+ t.Helper()
+ m, err := example.Load(fiesta.FS())
+ if err != nil {
+ t.Fatal(err)
+ }
+ state, ok := m.Default(name)
+ if !ok || state == "" {
+ t.Fatalf("the manifest has no default state for %s", name)
+ }
+ return state
+}
+
+func run(t *testing.T, ctx context.Context, actions ...chromedp.Action) {
+ t.Helper()
+ if err := chromedp.Run(ctx, actions...); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// readJSON evaluates a JS expression returning a JSON string into v.
+func readJSON(t *testing.T, ctx context.Context, js string, v any) {
+ t.Helper()
+ var raw string
+ if err := chromedp.Run(ctx, chromedp.Evaluate(js, &raw)); err != nil {
+ t.Fatalf("evaluating: %v\n%s", err, js)
+ }
+ if err := json.Unmarshal([]byte(raw), v); err != nil {
+ t.Fatalf("decoding %q: %v", raw, err)
+ }
+}
+
+// schemeMarkJS reports the scheme menu's buttons and which is marked.
+const schemeMarkJS = `JSON.stringify([...document.querySelectorAll("[rst-scheme] button")].map(b => ({
+ V: b.form && b.form.elements.scheme ? b.form.elements.scheme.value : "",
+ Cur: b.getAttribute("aria-current") || ""
+})))`
+
+// schemeOf reads the root's scheme attribute and computed color-scheme.
+const schemeOf = `JSON.stringify({Theme: document.documentElement.getAttribute("data-theme") || "", Scheme: getComputedStyle(document.documentElement).colorScheme})`
+
+// TestADemoComesBackFromTheCacheInTheStoredScheme: a demo opened in a
+// tab of its own, left for the gallery, whose stored scheme changes
+// while it is away, comes back from the back/forward cache in the new
+// scheme with its menu marked: Dark to Light, then Light to System, on
+// the scheme menu's document; and Dark to Light on the sidebar demo,
+// left by a click into its page. The control first, every time: the
+// return really was a cache restore (pageshow.persisted, and the same
+// navigation start as before), since a document reloaded instead would
+// pass on start-up code alone and prove nothing about the pageshow
+// handler. Back is history.back() from the page itself, polled for:
+// chromedp's NavigateBack waits for a load a restored page never fires,
+// and its node waits never resolve after a history navigation
+// (check/menus_browser_test.go).
+//
+// Full Chromium only, which is why it is in this package: the headless
+// shell never restores a page from the cache (hack/gotest.sh's
+// FULL_CHROMIUM note), and on it this fails naming the engine's reason
+// rather than passing on a reload.
+func TestADemoComesBackFromTheCacheInTheStoredScheme(t *testing.T) {
+ rig := harness.New(t, func(string) http.Handler { return treeHandler(t) })
+ ctx, cancel := context.WithTimeout(rig.Context(), 3*time.Minute)
+ defer cancel()
+ theme := fiesta.ThemeNames()[0]
+ index := indexHref(theme, "en")
+ menu := frameDoc(theme, "en", "scheme-menu", defaultState(t, "scheme-menu"))
+ sidebar := frameDoc(theme, "en", "layout-sidebar", defaultState(t, "layout-sidebar"))
+ page := frameDoc(theme, "en", "layout-sidebar-page", defaultState(t, "layout-sidebar-page"))
+
+ run(t, ctx,
+ addInit(`addEventListener("pageshow", function (e) { window.__restored = e.persisted; });`),
+ chromedp.EmulateViewport(1280, 900),
+ chromedp.Navigate(rig.Origin+index),
+ chromedp.WaitReady("body"),
+ chromedp.Evaluate(`localStorage.setItem("fiesta-scheme", "dark"); "ok"`, new(string)),
+ )
+
+ readRoot := func(where, wantTheme, wantScheme string) {
+ t.Helper()
+ until(t, ctx, where, `document.readyState === "complete"`)
+ var got struct{ Theme, Scheme string }
+ readJSON(t, ctx, schemeOf, &got)
+ if got.Theme != wantTheme {
+ t.Errorf("%s: <html> carries data-theme=%q, want %q", where, got.Theme, wantTheme)
+ }
+ if got.Scheme != wantScheme {
+ t.Errorf("%s: color-scheme computes %q, want %q", where, got.Scheme, wantScheme)
+ }
+ }
+ readMark := func(where, scheme string) {
+ t.Helper()
+ var buttons []struct{ V, Cur string }
+ readJSON(t, ctx, schemeMarkJS, &buttons)
+ if len(buttons) == 0 {
+ t.Fatalf("%s: no scheme menu button; the mark would be read off nothing", where)
+ }
+ for _, b := range buttons {
+ if (b.V == scheme) != (b.Cur == "true") {
+ t.Errorf("%s: the %s button is aria-current=%q; %s alone is marked", where, b.V, b.Cur, scheme)
+ }
+ }
+ }
+ // away leaves the document (leave is the statement that does), waits
+ // to be at awayAt, changes the stored scheme there (store), goes
+ // back, and requires the return to be a cache restore of the
+ // document whose path ends in back.
+ away := func(where, leave, awayAt, store, back string) {
+ t.Helper()
+ var started float64
+ run(t, ctx, chromedp.Evaluate(`performance.getEntriesByType("navigation")[0].startTime + performance.timeOrigin`, &started))
+ run(t, ctx, chromedp.Evaluate(`window.__restored = undefined; `+leave+`; true`, nil))
+ until(t, ctx, where+", away", `location.pathname.endsWith("`+awayAt+`") && document.readyState === "complete"`)
+ run(t, ctx, chromedp.Evaluate(store+`; history.back(); true`, nil))
+ until(t, ctx, where+", back", `location.pathname.endsWith("`+back+`") && window.__restored !== undefined`)
+ var raw string
+ run(t, ctx, chromedp.Evaluate(`JSON.stringify({Restored: window.__restored === true,
+ Started: performance.getEntriesByType("navigation")[0].startTime + performance.timeOrigin,
+ Why: JSON.stringify((performance.getEntriesByType("navigation")[0] || {}).notRestoredReasons || null)})`, &raw))
+ var r struct {
+ Restored bool
+ Started float64
+ Why string
+ }
+ if err := json.Unmarshal([]byte(raw), &r); err != nil {
+ t.Fatalf("%s: decoding %q: %v", where, raw, err)
+ }
+ if !r.Restored || r.Started != started {
+ t.Fatalf("%s: the return was not a back/forward cache restore (persisted %v, navigation %s then %s; the engine says %s); the engine must be full Chromium and the tree handler must not send Cache-Control: no-store",
+ where, r.Restored, strconv.FormatFloat(started, 'f', 0, 64), strconv.FormatFloat(r.Started, 'f', 0, 64), r.Why)
+ }
+ }
+
+ // The scheme menu's document: Dark, then Light on the way back, then
+ // System on the way back.
+ run(t, ctx, chromedp.Navigate(rig.Origin+mountPrefix+menu), chromedp.WaitReady("body"))
+ readRoot("the menu document", "dark", "dark")
+ readMark("the menu document", "dark")
+ toIndex := `location.assign("` + index + `")`
+ menuPath := "/" + menu
+ away("Dark to Light", toIndex, "/index.html", `localStorage.setItem("fiesta-scheme", "light")`, menuPath)
+ readRoot("the menu document back from the cache with Light stored", "light", "light")
+ readMark("the menu document back from the cache with Light stored", "light")
+ away("Light to System", toIndex, "/index.html", `localStorage.removeItem("fiesta-scheme")`, menuPath)
+ readRoot("the menu document back from the cache with nothing stored", "", "light dark")
+ readMark("the menu document back from the cache with nothing stored", "system")
+
+ // The shell demo: Dark, into its page by the nav, Light on the way back.
+ run(t, ctx,
+ chromedp.Evaluate(`localStorage.setItem("fiesta-scheme", "dark"); "ok"`, new(string)),
+ chromedp.Navigate(rig.Origin+mountPrefix+sidebar),
+ chromedp.WaitReady("body"),
+ )
+ readRoot("the sidebar demo", "dark", "dark")
+ away("the sidebar demo, Dark to Light", `document.querySelector("[rst-shell-nav] a").click()`, "/"+page, `localStorage.setItem("fiesta-scheme", "light")`, "/"+sidebar)
+ readRoot("the sidebar demo back from the cache with Light stored", "light", "light")
+
+ // A fresh navigation before the screen: after a history
+ // navigation chromedp's node waits never resolve, so the flush of
+ // the page's problems is taken on a document loaded anew.
+ run(t, ctx, chromedp.Navigate(rig.Origin+mountPrefix+menu), chromedp.WaitReady("body"))
+ rig.Screen("body", "the scheme menu's document in Light")
+}
diff --git a/internal/gallery/stage_browser_test.go b/internal/gallery/stage_browser_test.go
index 4a26f15..6b02225 100644
--- a/internal/gallery/stage_browser_test.go
+++ b/internal/gallery/stage_browser_test.go
@@ -7,7 +7,6 @@ import (
"encoding/json"
"math"
"net/http"
- "strconv"
"strings"
"testing"
"time"
@@ -21,7 +20,9 @@ import (
// The frame document as a browser lays it out: the padding the frame
// style gives a component and withholds from a whole page, the social
// sign-in card as an app would show it, and a demo opened in a tab of
-// its own in the reader's scheme before first paint and after Back.
+// its own in the reader's scheme before first paint. The same demo
+// coming back from the back/forward cache is in the history package,
+// on full Chromium.
// TestTheSocialSignInButtonsStackAndCarryTheirMarks: the social sign-in
// screen is markup an app copies, so what it looks like in the frame is
@@ -335,127 +336,3 @@ func TestADemoOpenedInItsOwnTabKeepsTheScheme(t *testing.T) {
readMark("the scheme menu's document")
rig.Screen("body", "the scheme menu's document in Dark")
}
-
-// schemeOf reads the root's scheme attribute and computed color-scheme.
-const schemeOf = `JSON.stringify({Theme: document.documentElement.getAttribute("data-theme") || "", Scheme: getComputedStyle(document.documentElement).colorScheme})`
-
-// TestADemoComesBackFromTheCacheInTheStoredScheme: a demo opened in a
-// tab of its own, left for the gallery, whose stored scheme changes
-// while it is away, comes back from the back/forward cache in the new
-// scheme with its menu marked: Dark to Light, then Light to System, on
-// the scheme menu's document; and Dark to Light on the sidebar demo,
-// left by a click into its page. The control first, every time: the
-// return really was a cache restore (pageshow.persisted, and the same
-// navigation start as before), since a document reloaded instead would
-// pass on start-up code alone and prove nothing about the pageshow
-// handler. Back is history.back() from the page itself, polled for:
-// chromedp's NavigateBack waits for a load a restored page never fires,
-// and its node waits never resolve after a history navigation
-// (check/menus_browser_test.go).
-//
-// Full Chromium only: the headless shell never restores a page from
-// the cache (hack/gotest.sh's FULL_CHROMIUM note), and on it this fails
-// naming the engine's reason rather than passing on a reload.
-func TestADemoComesBackFromTheCacheInTheStoredScheme(t *testing.T) {
- rig := harness.New(t, func(string) http.Handler { return newTree(t, nil) })
- ctx, cancel := context.WithTimeout(rig.Context(), 3*time.Minute)
- defer cancel()
- theme := fiesta.ThemeNames()[0]
- index := href(theme + "/en/index.html")
- menu := frameFile(theme, "en", "scheme-menu", mustDefault(t, "scheme-menu"))
- sidebar := frameFile(theme, "en", "layout-sidebar", mustDefault(t, "layout-sidebar"))
- page := frameFile(theme, "en", "layout-sidebar-page", mustDefault(t, "layout-sidebar-page"))
-
- mustRun(t, ctx,
- addInit(`addEventListener("pageshow", function (e) { window.__restored = e.persisted; });`),
- chromedp.EmulateViewport(1280, 900),
- chromedp.Navigate(rig.Origin+index),
- chromedp.WaitReady("body"),
- chromedp.Evaluate(`localStorage.setItem("fiesta-scheme", "dark"); "ok"`, new(string)),
- )
-
- readRoot := func(where, wantTheme, wantScheme string) {
- t.Helper()
- until(t, ctx, where, `document.readyState === "complete"`)
- var got struct{ Theme, Scheme string }
- at(t, ctx, schemeOf, &got)
- if got.Theme != wantTheme {
- t.Errorf("%s: <html> carries data-theme=%q, want %q", where, got.Theme, wantTheme)
- }
- if got.Scheme != wantScheme {
- t.Errorf("%s: color-scheme computes %q, want %q", where, got.Scheme, wantScheme)
- }
- }
- readMark := func(where, scheme string) {
- t.Helper()
- var buttons []struct{ V, Cur string }
- at(t, ctx, schemeMarkJS, &buttons)
- if len(buttons) == 0 {
- t.Fatalf("%s: no scheme menu button; the mark would be read off nothing", where)
- }
- for _, b := range buttons {
- if (b.V == scheme) != (b.Cur == "true") {
- t.Errorf("%s: the %s button is aria-current=%q; %s alone is marked", where, b.V, b.Cur, scheme)
- }
- }
- }
- // away leaves the document (leave is the statement that does), waits
- // to be at awayAt, changes the stored scheme there (store), goes
- // back, and requires the return to be a cache restore of the
- // document whose path ends in back.
- away := func(where, leave, awayAt, store, back string) {
- t.Helper()
- var started float64
- mustRun(t, ctx, chromedp.Evaluate(`performance.getEntriesByType("navigation")[0].startTime + performance.timeOrigin`, &started))
- mustRun(t, ctx, chromedp.Evaluate(`window.__restored = undefined; `+leave+`; true`, nil))
- until(t, ctx, where+", away", `location.pathname.endsWith("`+awayAt+`") && document.readyState === "complete"`)
- mustRun(t, ctx, chromedp.Evaluate(store+`; history.back(); true`, nil))
- until(t, ctx, where+", back", `location.pathname.endsWith("`+back+`") && window.__restored !== undefined`)
- var raw string
- mustRun(t, ctx, chromedp.Evaluate(`JSON.stringify({Restored: window.__restored === true,
- Started: performance.getEntriesByType("navigation")[0].startTime + performance.timeOrigin,
- Why: JSON.stringify((performance.getEntriesByType("navigation")[0] || {}).notRestoredReasons || null)})`, &raw))
- var r struct {
- Restored bool
- Started float64
- Why string
- }
- if err := json.Unmarshal([]byte(raw), &r); err != nil {
- t.Fatalf("%s: decoding %q: %v", where, raw, err)
- }
- if !r.Restored || r.Started != started {
- t.Fatalf("%s: the return was not a back/forward cache restore (persisted %v, navigation %s then %s; the engine says %s); the engine must be full Chromium and the tree handler must not send Cache-Control: no-store",
- where, r.Restored, strconv.FormatFloat(started, 'f', 0, 64), strconv.FormatFloat(r.Started, 'f', 0, 64), r.Why)
- }
- }
-
- // The scheme menu's document: Dark, then Light on the way back, then
- // System on the way back.
- mustRun(t, ctx, chromedp.Navigate(rig.Origin+href(menu)), chromedp.WaitReady("body"))
- readRoot("the menu document", "dark", "dark")
- readMark("the menu document", "dark")
- toIndex := `location.assign("` + index + `")`
- menuPath := "/" + menu
- away("Dark to Light", toIndex, "/index.html", `localStorage.setItem("fiesta-scheme", "light")`, menuPath)
- readRoot("the menu document back from the cache with Light stored", "light", "light")
- readMark("the menu document back from the cache with Light stored", "light")
- away("Light to System", toIndex, "/index.html", `localStorage.removeItem("fiesta-scheme")`, menuPath)
- readRoot("the menu document back from the cache with nothing stored", "", "light dark")
- readMark("the menu document back from the cache with nothing stored", "system")
-
- // The shell demo: Dark, into its page by the nav, Light on the way back.
- mustRun(t, ctx,
- chromedp.Evaluate(`localStorage.setItem("fiesta-scheme", "dark"); "ok"`, new(string)),
- chromedp.Navigate(rig.Origin+href(sidebar)),
- chromedp.WaitReady("body"),
- )
- readRoot("the sidebar demo", "dark", "dark")
- away("the sidebar demo, Dark to Light", `document.querySelector("[rst-shell-nav] a").click()`, "/"+page, `localStorage.setItem("fiesta-scheme", "light")`, "/"+sidebar)
- readRoot("the sidebar demo back from the cache with Light stored", "light", "light")
-
- // A fresh navigation before the screen: after a history
- // navigation chromedp's node waits never resolve, so the flush of
- // the page's problems is taken on a document loaded anew.
- mustRun(t, ctx, chromedp.Navigate(rig.Origin+href(menu)), chromedp.WaitReady("body"))
- rig.Screen("body", "the scheme menu's document in Light")
-}