rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1package check
2
3import (
4 "encoding/json"
5 "strings"
6 "testing"
7
8 "amadan.net/rastrillo/fiesta/internal/nodetest"
9)
10
11// A tap on the back control writes its record before any navigation
12// commits. When the reader then cancels the leave-page prompt and
13// follows some other link, the next page must slide forward: the record
14// was for a navigation that never happened. The real Back still slides
15// back. Here cancelling the prompt is one stub call; a browser drive
16// would have to dismiss the dialog over CDP and race the next click
17// against it, so this runs shell.js itself against stub pages in Node.
18func TestACancelledBackDoesNotSlideTheNextPageBack(t *testing.T) {
19 var got struct{ Taken, Cancelled string }
20 if err := json.Unmarshal(nodetest.Run(t, nodetest.Cmd{Args: []string{"node/shell_node.mjs"}}), &got); err != nil {
21 t.Fatal(err)
22 }
23 if got.Taken != "back" {
24 t.Errorf("Back tapped and taken: the up page slid %q, want back", got.Taken)
25 }
26 if got.Cancelled != "forward" {
27 t.Errorf("Back tapped, the prompt cancelled, then a link to another page followed: it slid %q, want forward", got.Cancelled)
28 }
29}
30
31// A view transition the browser skips rejects its promises though the
32// navigation succeeds, and with nothing to handle them the page logged
33// an uncaught AbortError, which also failed any browser test that
34// watches the console. 1.2.0's shell.js (Rastrillo d9c9ed13, 023740c5,
35// e5e35a3e and 6b1c5478) swallows exactly a skipped transition's
36// rejection, at startup, on pagereveal and on pageswap, and lets every
37// other error through. node/transition_node.mjs hands it each kind.
38func TestShellJSSwallowsOnlyASkippedTransition(t *testing.T) {
39 skippedTransitionsAreSwallowed(t, "shell.js")
40}
41
42// skippedTransitionsAreSwallowed runs node/transition_node.mjs against
43// one script and holds it to having checked every rejection: three
44// moments, three promises and eight reasons each, and one unrelated
45// rejection.
46func skippedTransitionsAreSwallowed(t *testing.T, script string) {
47 t.Helper()
48 var got struct{ Checked int }
49 out := nodetest.Run(t, nodetest.Cmd{
50 Args: []string{"node/transition_node.mjs", script},
51 })
52 if err := json.Unmarshal(out, &got); err != nil {
53 t.Fatal(err)
54 }
55 if want := 3*3*8 + 1; got.Checked != want {
56 t.Errorf("node/transition_node.mjs checked %d rejections against "+
57 "%s, want %d", got.Checked, script, want)
58 }
59}
60
61// transition.js is shell.js's transition handling alone, for a column,
62// stage or topbar page, which has no shell.js. It loads before the
63// stylesheets, because the browser can reject a skipped incoming
64// transition before pagereveal and a deferred script would miss it.
65func TestTransitionJSSwallowsOnlyASkippedTransition(t *testing.T) {
66 skippedTransitionsAreSwallowed(t, "transition.js")
67}
68
69// TestTheTwoTransitionObserversAreTheSame: shell.js and transition.js
70// each carry the code that swallows a skipped transition's rejection,
71// because each is a file a page loads on its own, with no build step
72// between this tree and the bytes a server sends. The price of two
73// copies is drift, so the two are held identical: the WeakSet and the
74// function, character for character, but for the function's name.
75func TestTheTwoTransitionObserversAreTheSame(t *testing.T) {
76 shell := transitionObserver(t, "shell.js", "observeTransition")
77 alone := transitionObserver(t, "transition.js", "observe")
78 renamed := strings.ReplaceAll(shell, "function observeTransition(",
79 "function observe(")
80 if renamed != alone {
81 t.Errorf("the transition observer differs between shell.js and "+
82 "transition.js:\n--- shell.js\n%s\n--- transition.js\n%s",
83 shell, alone)
84 }
85}
86
87// transitionObserver is one script's observer: the WeakSet declared
88// straight before it and the function itself. It fails the test when
89// the script has no such pair, so the comparison is never of nothing.
90func transitionObserver(t *testing.T, script, name string) string {
91 t.Helper()
92 const set = "var observed = new WeakSet();\n"
93 js := string(shippedScript(t, script))
94 body := functionBody(js, name)
95 at := strings.Index(js, set+strings.Repeat(" ", 2)+"function "+name+"(")
96 if body == "" || at < 0 {
97 t.Fatalf("%s has no %q followed by function %s", script,
98 strings.TrimSpace(set), name)
99 }
100 return set + body
101}
102