diff options
author | Brad Peabody <[email protected]> | 2020-05-23 05:12:01 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2020-05-23 14:12:01 +0200 |
commit | 95f509b109d4936bec9b6020cb34fbb4bd5cba16 (patch) | |
tree | 1aa22601dc454056c8f4d5c797efb786e931b281 /tests | |
parent | dda576e80bb4217ba67700e377b441783edee62d (diff) | |
download | tinygo-95f509b109d4936bec9b6020cb34fbb4bd5cba16.tar.gz tinygo-95f509b109d4936bec9b6020cb34fbb4bd5cba16.zip |
wasm test suite (#1116)
* wasm: add test suite using headlless chrome
Diffstat (limited to 'tests')
-rw-r--r-- | tests/wasm/chan_test.go | 34 | ||||
-rw-r--r-- | tests/wasm/event_test.go | 47 | ||||
-rw-r--r-- | tests/wasm/fmt_test.go | 43 | ||||
-rw-r--r-- | tests/wasm/fmtprint_test.go | 39 | ||||
-rw-r--r-- | tests/wasm/setup_test.go | 189 | ||||
-rw-r--r-- | tests/wasm/testdata/chan.go | 16 | ||||
-rw-r--r-- | tests/wasm/testdata/event.go | 31 | ||||
-rw-r--r-- | tests/wasm/testdata/fmt.go | 8 | ||||
-rw-r--r-- | tests/wasm/testdata/fmtprint.go | 11 |
9 files changed, 418 insertions, 0 deletions
diff --git a/tests/wasm/chan_test.go b/tests/wasm/chan_test.go new file mode 100644 index 000000000..1cd08e664 --- /dev/null +++ b/tests/wasm/chan_test.go @@ -0,0 +1,34 @@ +package wasm + +import ( + "testing" + "time" + + "github.com/chromedp/chromedp" +) + +func TestChan(t *testing.T) { + + t.Parallel() + + err := run("tinygo build -o " + wasmTmpDir + "/chan.wasm -target wasm testdata/chan.go") + if err != nil { + t.Fatal(err) + } + + ctx, cancel := chromectx(5 * time.Second) + defer cancel() + + err = chromedp.Run(ctx, + chromedp.Navigate("http://localhost:8826/run?file=chan.wasm"), + waitLog(`1 +2 +4 +3 +true`), + ) + if err != nil { + t.Fatal(err) + } + +} diff --git a/tests/wasm/event_test.go b/tests/wasm/event_test.go new file mode 100644 index 000000000..d2b8340ce --- /dev/null +++ b/tests/wasm/event_test.go @@ -0,0 +1,47 @@ +// +build go1.14 + +package wasm + +import ( + "testing" + "time" + + "github.com/chromedp/chromedp" +) + +func TestEvent(t *testing.T) { + + t.Parallel() + + err := run("tinygo build -o " + wasmTmpDir + "/event.wasm -target wasm testdata/event.go") + if err != nil { + t.Fatal(err) + } + + ctx, cancel := chromectx(5 * time.Second) + defer cancel() + + var log1, log2 string + err = chromedp.Run(ctx, + chromedp.Navigate("http://localhost:8826/run?file=event.wasm"), + chromedp.WaitVisible("#log"), + chromedp.Sleep(time.Second), + chromedp.InnerHTML("#log", &log1), + waitLog(`1 +4`), + chromedp.Click("#testbtn"), + chromedp.Sleep(time.Second), + chromedp.InnerHTML("#log", &log2), + waitLog(`1 +4 +2 +3 +true`), + ) + t.Logf("log1: %s", log1) + t.Logf("log2: %s", log2) + if err != nil { + t.Fatal(err) + } + +} diff --git a/tests/wasm/fmt_test.go b/tests/wasm/fmt_test.go new file mode 100644 index 000000000..8b4fe8c75 --- /dev/null +++ b/tests/wasm/fmt_test.go @@ -0,0 +1,43 @@ +// +build go1.14 + +package wasm + +// NOTE: this should work in go1.13 but panics with: +// panic: syscall/js: call of Value.Get on string +// which is coming from here: https://github.com/golang/go/blob/release-branch.go1.13/src/syscall/js/js.go#L252 +// But I'm not sure how import "fmt" results in this. +// To reproduce, install Go 1.13.x and change the build tag above +// to go1.13 and run this test. + +import ( + "testing" + "time" + + "github.com/chromedp/chromedp" +) + +func TestFmt(t *testing.T) { + + t.Parallel() + + err := run("tinygo build -o " + wasmTmpDir + "/fmt.wasm -target wasm testdata/fmt.go") + if err != nil { + t.Fatal(err) + } + + ctx, cancel := chromectx(5 * time.Second) + defer cancel() + + var log1 string + err = chromedp.Run(ctx, + chromedp.Navigate("http://localhost:8826/run?file=fmt.wasm"), + chromedp.Sleep(time.Second), + chromedp.InnerHTML("#log", &log1), + waitLog(`did not panic`), + ) + t.Logf("log1: %s", log1) + if err != nil { + t.Fatal(err) + } + +} diff --git a/tests/wasm/fmtprint_test.go b/tests/wasm/fmtprint_test.go new file mode 100644 index 000000000..ebd1ffa99 --- /dev/null +++ b/tests/wasm/fmtprint_test.go @@ -0,0 +1,39 @@ +// +build go1.14 + +package wasm + +import ( + "testing" + "time" + + "github.com/chromedp/chromedp" +) + +func TestFmtprint(t *testing.T) { + + t.Parallel() + + err := run("tinygo build -o " + wasmTmpDir + "/fmtprint.wasm -target wasm testdata/fmtprint.go") + if err != nil { + t.Fatal(err) + } + + ctx, cancel := chromectx(5 * time.Second) + defer cancel() + + var log1 string + err = chromedp.Run(ctx, + chromedp.Navigate("http://localhost:8826/run?file=fmtprint.wasm"), + chromedp.Sleep(time.Second), + chromedp.InnerHTML("#log", &log1), + waitLog(`test from fmtprint 1 +test from fmtprint 2 +test from fmtprint 3 +test from fmtprint 4`), + ) + t.Logf("log1: %s", log1) + if err != nil { + t.Fatal(err) + } + +} diff --git a/tests/wasm/setup_test.go b/tests/wasm/setup_test.go new file mode 100644 index 000000000..7d5ffa675 --- /dev/null +++ b/tests/wasm/setup_test.go @@ -0,0 +1,189 @@ +package wasm + +import ( + "context" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "strings" + "testing" + "time" + + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/chromedp" +) + +var addr = flag.String("addr", ":8826", "Host:port to listen on for wasm test server") + +var wasmTmpDir string // set in TestMain to a temp directory for build output + +func TestMain(m *testing.M) { + flag.Parse() + + os.Exit(func() int { + + var err error + wasmTmpDir, err = ioutil.TempDir("", "wasm_test") + if err != nil { + log.Fatalf("unable to create temp dir: %v", err) + } + defer os.RemoveAll(wasmTmpDir) // cleanup even on panic and before os.Exit + + startServer(wasmTmpDir) + + return m.Run() + }()) + +} + +func run(cmdline string) error { + args := strings.Fields(cmdline) + return runargs(args...) +} + +func runargs(args ...string) error { + cmd := exec.Command(args[0], args[1:]...) + b, err := cmd.CombinedOutput() + log.Printf("Command: %s; err=%v; full output:\n%s", strings.Join(args, " "), err, b) + if err != nil { + return err + } + return nil +} + +func chromectx(timeout time.Duration) (context.Context, context.CancelFunc) { + + var ctx context.Context + + // looks for locally installed Chrome + ctx, _ = chromedp.NewContext(context.Background()) + + ctx, cancel := context.WithTimeout(ctx, timeout) + + return ctx, cancel +} + +func startServer(tmpDir string) { + + fsh := http.FileServer(http.Dir(tmpDir)) + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + if r.URL.Path == "/wasm_exec.js" { + http.ServeFile(w, r, "../../targets/wasm_exec.js") + return + } + + if r.URL.Path == "/run" { + fmt.Fprintf(w, `<!doctype html> +<html> +<head> +<title>Test</title> +<meta charset="utf-8"/> +</head> +<body> +<div id="main"></div> +<pre id="log"></pre> +<script> +window.wasmLogOutput = []; +(function() { + var logdiv = document.getElementById('log'); + var cl = console.log; + console.log = function() { + var a = []; + for (var i = 0; i < arguments.length; i++) { + a.push(arguments[i]); + } + var line = a.join(' ') + "\n"; + window.wasmLogOutput.push(line); + var ret = cl.apply(console, arguments) + var el = document.createElement('span'); + el.innerText = line; + logdiv.appendChild(el); + return ret + } +})() +</script> +<script src="/wasm_exec.js"></script> +<script> +var wasmSupported = (typeof WebAssembly === "object"); +if (wasmSupported) { + var mainWasmReq = fetch("/%s").then(function(res) { + if (res.ok) { + const go = new Go(); + WebAssembly.instantiateStreaming(res, go.importObject).then((result) => { + go.run(result.instance); + }); + } else { + res.text().then(function(txt) { + var el = document.getElementById("main"); + el.style = 'font-family: monospace; background: black; color: red; padding: 10px'; + el.innerText = txt; + }) + } + }) +} else { + document.getElementById("main").innerHTML = 'This application requires WebAssembly support. Please upgrade your browser.'; +} +</script> +</body> +</html>`, r.FormValue("file")) + return + } + + fsh.ServeHTTP(w, r) + }) + + log.Printf("Starting server at %q for dir: %s", *addr, tmpDir) + go func() { + log.Fatal(http.ListenAndServe(*addr, h)) + }() + +} + +func waitLog(logText string) chromedp.QueryAction { + return waitInnerTextTrimEq("#log", logText) +} + +// waitInnerTextTrimEq will wait for the innerText of the specified element to match a specific string after whitespace trimming. +func waitInnerTextTrimEq(sel, innerText string) chromedp.QueryAction { + + return chromedp.Query(sel, func(s *chromedp.Selector) { + + chromedp.WaitFunc(func(ctx context.Context, cur *cdp.Frame, ids ...cdp.NodeID) ([]*cdp.Node, error) { + + nodes := make([]*cdp.Node, len(ids)) + cur.RLock() + for i, id := range ids { + nodes[i] = cur.Nodes[id] + if nodes[i] == nil { + cur.RUnlock() + // not yet ready + return nil, nil + } + } + cur.RUnlock() + + var ret string + err := chromedp.EvaluateAsDevTools("document.querySelector('"+sel+"').innerText", &ret).Do(ctx) + if err != nil { + return nodes, err + } + if strings.TrimSpace(ret) != innerText { + // log.Printf("found text: %s", ret) + return nodes, errors.New("unexpected value: " + ret) + } + + // log.Printf("NodeValue: %#v", nodes[0]) + + // return nil, errors.New("not ready yet") + return nodes, nil + })(s) + + }) + +} diff --git a/tests/wasm/testdata/chan.go b/tests/wasm/testdata/chan.go new file mode 100644 index 000000000..8f10d1f8d --- /dev/null +++ b/tests/wasm/testdata/chan.go @@ -0,0 +1,16 @@ +package main + +func main() { + + ch := make(chan bool, 1) + println("1") + go func() { + println("2") + ch <- true + println("3") + }() + println("4") + v := <-ch + println(v) + +} diff --git a/tests/wasm/testdata/event.go b/tests/wasm/testdata/event.go new file mode 100644 index 000000000..4153774ff --- /dev/null +++ b/tests/wasm/testdata/event.go @@ -0,0 +1,31 @@ +package main + +import "syscall/js" + +func main() { + + ch := make(chan bool, 1) + + println("1") + + js.Global(). + Get("document"). + Call("querySelector", "#main"). + Set("innerHTML", `<button id="testbtn">Test</button>`) + + js.Global(). + Get("document"). + Call("querySelector", "#testbtn"). + Call("addEventListener", "click", + js.FuncOf(func(this js.Value, args []js.Value) interface{} { + println("2") + ch <- true + println("3") + return nil + })) + + println("4") + v := <-ch + println(v) + +} diff --git a/tests/wasm/testdata/fmt.go b/tests/wasm/testdata/fmt.go new file mode 100644 index 000000000..b51c564cd --- /dev/null +++ b/tests/wasm/testdata/fmt.go @@ -0,0 +1,8 @@ +package main + +import "fmt" + +func main() { + var _ fmt.Stringer + println("did not panic") +} diff --git a/tests/wasm/testdata/fmtprint.go b/tests/wasm/testdata/fmtprint.go new file mode 100644 index 000000000..1bad3361c --- /dev/null +++ b/tests/wasm/testdata/fmtprint.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + fmt.Println("test from fmtprint 1") + fmt.Print("test from fmtprint 2\n") + fmt.Print("test from fmtp") + fmt.Print("rint 3\n") + fmt.Printf("test from fmtprint %d\n", 4) +} |