github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/cmd/gogio/js_test.go (about)

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