rastrillo / fiesta Public

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

Plain git — no account needed to clone.

Download

Download this file

1//go:build browser
2
3package gallery
4
5import (
6 "context"
7 "net/http"
8 "testing"
9 "time"
10
11 "github.com/chromedp/cdproto/emulation"
12 "github.com/chromedp/chromedp"
13
14 "amadan.net/rastrillo/fiesta/internal/gallery/galleryrig"
15 "amadan.net/rastrillo/fiesta/internal/harness"
16)
17
18// The shared drive helpers, under the names the ported drives are
19// written with. One line each: the implementation is galleryrig's,
20// which the history package uses too, so the two cannot drift.
21// Fiesta's own drives keep newTree in a11y_browser_test.go, which
22// records every request as well.
23
24func treeHandler(t *testing.T) http.Handler {
25 t.Helper()
26 return galleryrig.Tree(t, render(t, mountPath), mountPath+"/")
27}
28
29func eagerly(t *testing.T, ctx context.Context, where string) {
30 t.Helper()
31 galleryrig.Eagerly(t, ctx, where)
32}
33
34func mobileSettle(t *testing.T, ctx context.Context, where string) {
35 t.Helper()
36 galleryrig.MobileSettle(t, ctx, where)
37}
38
39func addInit(js string) chromedp.Action { return galleryrig.AddInit(js) }
40
41func until(t *testing.T, ctx context.Context, where, expr string) {
42 t.Helper()
43 galleryrig.Until(t, ctx, where, expr)
44}
45
46func phoneRig(t *testing.T, opts ...harness.Option) *harness.Rig {
47 t.Helper()
48 return galleryrig.PhoneRig(t, func() http.Handler { return treeHandler(t) }, opts...)
49}
50
51func requireDrawnScrollbar(t *testing.T, ctx context.Context, where string) {
52 t.Helper()
53 galleryrig.RequireDrawnScrollbar(t, ctx, where)
54}
55
56func requireCoarse(t *testing.T, ctx context.Context) {
57 t.Helper()
58 galleryrig.RequireCoarse(t, ctx)
59}
60
61func settleMotion(t *testing.T, ctx context.Context, where string) {
62 t.Helper()
63 galleryrig.SettleMotion(t, ctx, where)
64}
65
66func noScripts(t *testing.T, ctx context.Context) context.Context {
67 t.Helper()
68 return galleryrig.NoScripts(t, ctx)
69}
70
71func requireScriptsOff(t *testing.T, ctx context.Context, where string) {
72 t.Helper()
73 galleryrig.RequireScriptsOff(t, ctx, where)
74}
75
76// TestTheRigServesTheTreeAtItsMount: the shared tree answers for a
77// file of the render under the mount and records a miss for a path
78// it has not got, so a drive that frames a missing document fails by
79// name. The bindings above are exercised by the drives that use them.
80func TestTheRigServesTheTreeAtItsMount(t *testing.T) {
81 files := render(t, mountPath)
82 var missed []string
83 h := galleryrig.TreeRecording(t, files, mountPath+"/", func(p string) { missed = append(missed, p) })
84 rig := harness.New(t, func(string) http.Handler { return h })
85 rig.Allow(http.MethodGet, mountPath+"/no-such-file.html", http.StatusNotFound)
86 ctx, cancel := context.WithTimeout(rig.Context(), 30*time.Second)
87 defer cancel()
88 var title string
89 mustRun(t, ctx,
90 chromedp.Navigate(rig.Origin+href("day/en/index.html")),
91 chromedp.WaitReady("body"),
92 chromedp.Evaluate(`document.title`, &title),
93 )
94 if title == "" {
95 t.Error("the Overview served through the rig has no title")
96 }
97 mustRun(t, ctx, chromedp.Navigate(rig.Origin+href("no-such-file.html")), chromedp.WaitReady("body"))
98 if len(missed) != 1 || missed[0] != href("no-such-file.html") {
99 t.Errorf("the rig recorded the misses %v, want the one path asked for", missed)
100 }
101}
102
103// TestTheSharedRigDrivesAPhone exercises every binding above on one
104// page, so a helper that stopped matching the markup fails here rather
105// than in the first ported drive that leans on it: a phone rig with a
106// drawn scrollbar, an init script that runs before the page, the frames
107// settled at a phone's width, motion waited out, a condition polled,
108// and a second tab with scripts off that proves it.
109func TestTheSharedRigDrivesAPhone(t *testing.T) {
110 rig := phoneRig(t, harness.WithScrollbars())
111 ctx, cancel := context.WithTimeout(rig.Context(), 2*time.Minute)
112 defer cancel()
113 mustRun(t, ctx,
114 addInit(`window.__galleryInit = true`),
115 chromedp.ActionFunc(func(c context.Context) error {
116 return emulation.SetDeviceMetricsOverride(320, 640, 1, false).Do(c)
117 }),
118 chromedp.Navigate(rig.Origin+href("day/en/button.html")),
119 chromedp.WaitReady("body"),
120 )
121 requireCoarse(t, ctx)
122 requireDrawnScrollbar(t, ctx, "button")
123 var init bool
124 mustRun(t, ctx, chromedp.Evaluate(`window.__galleryInit === true`, &init))
125 if !init {
126 t.Error("the init script did not run before the page's own")
127 }
128 eagerly(t, ctx, "button")
129 mobileSettle(t, ctx, "button")
130 settleMotion(t, ctx, "button")
131 until(t, ctx, "button", `document.querySelectorAll(".ds-view__frame[data-gallery-painted]").length > 0`)
132 var on bool
133 mustRun(t, ctx, chromedp.Evaluate(`document.documentElement.hasAttribute("data-gallery-js")`, &on))
134 if !on {
135 t.Error("the scripted tab did not run the gallery's script")
136 }
137
138 off := noScripts(t, rig.Context())
139 mustRun(t, off, chromedp.Navigate(rig.Origin+href("day/en/button.html")), chromedp.WaitReady("body"))
140 requireScriptsOff(t, off, "button with scripts off")
141 rig.Screen("main", "the button page on a phone")
142}
143