aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
authorBrad Peabody <[email protected]>2020-05-23 05:12:01 -0700
committerGitHub <[email protected]>2020-05-23 14:12:01 +0200
commit95f509b109d4936bec9b6020cb34fbb4bd5cba16 (patch)
tree1aa22601dc454056c8f4d5c797efb786e931b281 /tests
parentdda576e80bb4217ba67700e377b441783edee62d (diff)
downloadtinygo-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.go34
-rw-r--r--tests/wasm/event_test.go47
-rw-r--r--tests/wasm/fmt_test.go43
-rw-r--r--tests/wasm/fmtprint_test.go39
-rw-r--r--tests/wasm/setup_test.go189
-rw-r--r--tests/wasm/testdata/chan.go16
-rw-r--r--tests/wasm/testdata/event.go31
-rw-r--r--tests/wasm/testdata/fmt.go8
-rw-r--r--tests/wasm/testdata/fmtprint.go11
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)
+}