js_test.go raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 package main_test
4
5 import (
6 "bytes"
7 "context"
8 "errors"
9 "image"
10 "image/png"
11 "io"
12 "net/http"
13 "net/http/httptest"
14 "os/exec"
15
16 "github.com/chromedp/cdproto/runtime"
17 "github.com/chromedp/chromedp"
18
19 )
20
21 type JSTestDriver struct {
22 driverBase
23
24 // ctx is the chromedp context.
25 ctx context.Context
26 }
27
28 func (d *JSTestDriver) Start(path string) {
29 if raceEnabled {
30 d.Skipf("js/wasm doesn't support -race; skipping")
31 }
32
33 // First, build the app.
34 dir := d.tempDir("gio-endtoend-js")
35 d.gogio("-target=js", "-o="+dir, path)
36
37 // Second, start Chrome.
38 opts := append(chromedp.DefaultExecAllocatorOptions[:],
39 chromedp.Flag("headless", *headless),
40 )
41
42 actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
43 d.Cleanup(cancel)
44
45 ctx, cancel := chromedp.NewContext(actx,
46 // Send all logf/errf calls to t.Logf
47 chromedp.WithLogf(d.Logf),
48 )
49 d.Cleanup(cancel)
50 d.ctx = ctx
51
52 if err := chromedp.Run(ctx); err != nil {
53 if errors.Is(err, exec.ErrNotFound) {
54 d.Skipf("test requires Chrome to be installed: %v", err)
55 return
56 }
57 d.Fatal(err)
58 }
59 pr, pw := io.Pipe()
60 d.Cleanup(func() { pw.Close() })
61 d.output = pr
62 chromedp.ListenTarget(ctx, func(ev interface{}) {
63 switch ev := ev.(type) {
64 case *runtime.EventConsoleAPICalled:
65 switch ev.Type {
66 case "log", "info", "warning", "error":
67 var b bytes.Buffer
68 b.WriteString("console.")
69 b.WriteString(string(ev.Type))
70 b.WriteString("(")
71 for i, arg := range ev.Args {
72 if i > 0 {
73 b.WriteString(", ")
74 }
75 b.Write(arg.Value)
76 }
77 b.WriteString(")\n")
78 pw.Write(b.Bytes())
79 }
80 }
81 })
82
83 // Third, serve the app folder, set the browser tab dimensions, and
84 // navigate to the folder.
85 ts := httptest.NewServer(http.FileServer(http.Dir(dir)))
86 d.Cleanup(ts.Close)
87
88 if err := chromedp.Run(ctx,
89 chromedp.EmulateViewport(int64(d.width), int64(d.height)),
90 chromedp.Navigate(ts.URL),
91 ); err != nil {
92 d.Fatal(err)
93 }
94
95 // Wait for the gio app to render.
96 d.waitForFrame()
97 }
98
99 func (d *JSTestDriver) Screenshot() image.Image {
100 var buf []byte
101 if err := chromedp.Run(d.ctx,
102 chromedp.CaptureScreenshot(&buf),
103 ); err != nil {
104 d.Fatal(err)
105 }
106 img, err := png.Decode(bytes.NewReader(buf))
107 if err != nil {
108 d.Fatal(err)
109 }
110 return img
111 }
112
113 func (d *JSTestDriver) Click(x, y int) {
114 if err := chromedp.Run(d.ctx,
115 chromedp.MouseClickXY(float64(x), float64(y)),
116 ); err != nil {
117 d.Fatal(err)
118 }
119
120 // Wait for the gio app to render after this click.
121 d.waitForFrame()
122 }
123