~eliasnaur/gio

ref: 6a9a87046221602d1a323887cd619e75c81cc24e gio/cmd/gogio/js_test.go -rw-r--r-- 3.2 KiB
6a9a8704Sebastien Binet app{,/internal/window}: make app.Main blocking on desktop platforms 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// SPDX-License-Identifier: Unlicense OR MIT

package main_test

import (
	"bytes"
	"context"
	"errors"
	"image"
	"image/png"
	"io"
	"net/http"
	"net/http/httptest"
	"os/exec"

	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/chromedp"

	_ "gioui.org/unit" // the build tool adds it to go.mod, so keep it there
)

type JSTestDriver struct {
	driverBase

	// ctx is the chromedp context.
	ctx context.Context
}

func (d *JSTestDriver) Start(path string) {
	if raceEnabled {
		d.Skipf("js/wasm doesn't support -race; skipping")
	}

	// First, build the app.
	dir := d.tempDir("gio-endtoend-js")
	d.gogio("-target=js", "-o="+dir, path)

	// Second, start Chrome.
	opts := append(chromedp.DefaultExecAllocatorOptions[:],
		chromedp.Flag("headless", *headless),

		// The default would be use-gl=desktop when there's a GPU we can
		// use, falling back to use-gl=swiftshader otherwise or when we
		// are running in headless mode. Swiftshader allows full WebGL
		// support with just a CPU.
		//
		// Unfortunately, many Linux distros like Arch and Alpine
		// package Chromium without Swiftshader, so we can't rely on the
		// defaults above. use-gl=egl works on any machine with a GPU,
		// even if we run Chrome in headless mode, which is OK for now.
		//
		// TODO(mvdan): remove all of this once these issues are fixed:
		//
		//    https://bugs.archlinux.org/task/64307
		//    https://gitlab.alpinelinux.org/alpine/aports/issues/10920
		chromedp.Flag("use-gl", "egl"),
	)

	actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
	d.Cleanup(cancel)

	ctx, cancel := chromedp.NewContext(actx,
		// Send all logf/errf calls to t.Logf
		chromedp.WithLogf(d.Logf),
	)
	d.Cleanup(cancel)
	d.ctx = ctx

	if err := chromedp.Run(ctx); err != nil {
		if errors.Is(err, exec.ErrNotFound) {
			d.Skipf("test requires Chrome to be installed: %v", err)
			return
		}
		d.Fatal(err)
	}
	pr, pw := io.Pipe()
	d.Cleanup(func() { pw.Close() })
	d.output = pr
	chromedp.ListenTarget(ctx, func(ev interface{}) {
		switch ev := ev.(type) {
		case *runtime.EventConsoleAPICalled:
			switch ev.Type {
			case "log", "info", "warning", "error":
				var b bytes.Buffer
				b.WriteString("console.")
				b.WriteString(string(ev.Type))
				b.WriteString("(")
				for i, arg := range ev.Args {
					if i > 0 {
						b.WriteString(", ")
					}
					b.Write(arg.Value)
				}
				b.WriteString(")\n")
				pw.Write(b.Bytes())
			}
		}
	})

	// Third, serve the app folder, set the browser tab dimensions, and
	// navigate to the folder.
	ts := httptest.NewServer(http.FileServer(http.Dir(dir)))
	d.Cleanup(ts.Close)

	if err := chromedp.Run(ctx,
		chromedp.EmulateViewport(int64(d.width), int64(d.height)),
		chromedp.Navigate(ts.URL),
	); err != nil {
		d.Fatal(err)
	}

	// Wait for the gio app to render.
	d.waitForFrame()
}

func (d *JSTestDriver) Screenshot() image.Image {
	var buf []byte
	if err := chromedp.Run(d.ctx,
		chromedp.CaptureScreenshot(&buf),
	); err != nil {
		d.Fatal(err)
	}
	img, err := png.Decode(bytes.NewReader(buf))
	if err != nil {
		d.Fatal(err)
	}
	return img
}

func (d *JSTestDriver) Click(x, y int) {
	if err := chromedp.Run(d.ctx,
		chromedp.MouseClickXY(float64(x), float64(y)),
	); err != nil {
		d.Fatal(err)
	}

	// Wait for the gio app to render after this click.
	d.waitForFrame()
}