cmd/gogio: extract endtoend driver base into a type

This type contains all the common bits, such as *testing.T, as well as
the channel and method used to wait for blocking until a frame is ready.

It also allows us to initialise this base separately from Start, which
keeps the exported method simpler to understand.

The base type is embedded into the specific driver types, so that the
code remains simple. While at it, start embedding *testing.T too, so
that we can write d.Fatalf instead of d.t.Fatalf. The drivers will only
have a small number of exported methods as per the interface, so it's
easy to keep those from colliding with the method set on T.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
This commit is contained in:
Daniel Martí
2020-02-05 15:26:02 +00:00
committed by Elias Naur
parent b8b8003a7a
commit ed8a0c4909
5 changed files with 109 additions and 119 deletions
+19 -25
View File
@@ -14,7 +14,6 @@ import (
"os"
"os/exec"
"strings"
"testing"
"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/chromedp"
@@ -23,34 +22,29 @@ import (
)
type JSTestDriver struct {
t *testing.T
frameNotifs chan bool
driverBase
// ctx is the chromedp context.
ctx context.Context
}
func (d *JSTestDriver) Start(t_ *testing.T, path string, width, height int) {
d.frameNotifs = make(chan bool, 1)
d.t = t_
func (d *JSTestDriver) Start(path string, width, height int) {
if raceEnabled {
d.t.Skipf("js/wasm doesn't support -race; skipping")
d.Skipf("js/wasm doesn't support -race; skipping")
}
// First, build the app.
dir, err := ioutil.TempDir("", "gio-endtoend-js")
if err != nil {
d.t.Fatal(err)
d.Fatal(err)
}
d.t.Cleanup(func() { os.RemoveAll(dir) })
d.Cleanup(func() { os.RemoveAll(dir) })
// TODO(mvdan): This is inefficient, as we link the gogio tool every time.
// Consider options in the future. On the plus side, this is simple.
cmd := exec.Command("go", "run", ".", "-target=js", "-o="+dir, path)
if out, err := cmd.CombinedOutput(); err != nil {
d.t.Fatalf("could not build app: %s:\n%s", err, out)
d.Fatalf("could not build app: %s:\n%s", err, out)
}
// Second, start Chrome.
@@ -75,21 +69,21 @@ func (d *JSTestDriver) Start(t_ *testing.T, path string, width, height int) {
)
actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
d.t.Cleanup(cancel)
d.Cleanup(cancel)
ctx, cancel := chromedp.NewContext(actx,
// Send all logf/errf calls to t.Logf
chromedp.WithLogf(d.t.Logf),
chromedp.WithLogf(d.Logf),
)
d.t.Cleanup(cancel)
d.Cleanup(cancel)
d.ctx = ctx
if err := chromedp.Run(ctx); err != nil {
if errors.Is(err, exec.ErrNotFound) {
d.t.Skipf("test requires Chrome to be installed: %v", err)
d.Skipf("test requires Chrome to be installed: %v", err)
return
}
d.t.Fatal(err)
d.Fatal(err)
}
chromedp.ListenTarget(ctx, func(ev interface{}) {
switch ev := ev.(type) {
@@ -111,7 +105,7 @@ func (d *JSTestDriver) Start(t_ *testing.T, path string, width, height int) {
}
args.Write(arg.Value)
}
d.t.Logf("console %s: %s", ev.Type, args.String())
d.Logf("console %s: %s", ev.Type, args.String())
}
}
})
@@ -119,17 +113,17 @@ func (d *JSTestDriver) Start(t_ *testing.T, path string, width, height int) {
// Third, serve the app folder, set the browser tab dimensions, and
// navigate to the folder.
ts := httptest.NewServer(http.FileServer(http.Dir(dir)))
d.t.Cleanup(ts.Close)
d.Cleanup(ts.Close)
if err := chromedp.Run(ctx,
chromedp.EmulateViewport(int64(width), int64(height)),
chromedp.Navigate(ts.URL),
); err != nil {
d.t.Fatal(err)
d.Fatal(err)
}
// Wait for the gio app to render.
waitForFrame(d.t, d.frameNotifs)
d.waitForFrame()
}
func (d *JSTestDriver) Screenshot() image.Image {
@@ -137,11 +131,11 @@ func (d *JSTestDriver) Screenshot() image.Image {
if err := chromedp.Run(d.ctx,
chromedp.CaptureScreenshot(&buf),
); err != nil {
d.t.Fatal(err)
d.Fatal(err)
}
img, err := png.Decode(bytes.NewReader(buf))
if err != nil {
d.t.Fatal(err)
d.Fatal(err)
}
return img
}
@@ -150,9 +144,9 @@ func (d *JSTestDriver) Click(x, y int) {
if err := chromedp.Run(d.ctx,
chromedp.MouseClickXY(float64(x), float64(y)),
); err != nil {
d.t.Fatal(err)
d.Fatal(err)
}
// Wait for the gio app to render after this click.
waitForFrame(d.t, d.frameNotifs)
d.waitForFrame()
}