package wasm
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os/exec"
"regexp"
"strings"
"testing"
"time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/chromedp"
)
func run(t *testing.T, cmdline string) error {
args := strings.Fields(cmdline)
return runargs(t, args...)
}
func runargs(t *testing.T, args ...string) error {
cmd := exec.Command(args[0], args[1:]...)
b, err := cmd.CombinedOutput()
t.Logf("Command: %s; err=%v; full output:\n%s", strings.Join(args, " "), err, b)
if err != nil {
return err
}
return nil
}
func chromectx(t *testing.T) context.Context {
// looks for locally installed Chrome
ctx, ccancel := chromedp.NewContext(context.Background(), chromedp.WithErrorf(t.Errorf), chromedp.WithDebugf(t.Logf), chromedp.WithLogf(t.Logf))
t.Cleanup(ccancel)
// Wait for browser to be ready.
err := chromedp.Run(ctx)
if err != nil {
t.Fatalf("failed to start browser: %s", err.Error())
}
ctx, tcancel := context.WithTimeout(ctx, 30*time.Second)
t.Cleanup(tcancel)
return ctx
}
func startServer(t *testing.T) (string, *httptest.Server) {
tmpDir := t.TempDir()
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, `
Test
`, r.FormValue("file"))
return
}
fsh.ServeHTTP(w, r)
})
server := httptest.NewServer(h)
t.Logf("Started server at %q for dir: %s", server.URL, tmpDir)
t.Cleanup(server.Close)
return tmpDir, server
}
// waitLog blocks until the log output equals the text provided (ignoring whitespace before and after)
func waitLog(logText string) chromedp.QueryAction {
return waitInnerTextTrimEq("#log", strings.TrimSpace(logText))
}
// waitLogRe blocks until the log output matches this regular expression
func waitLogRe(restr string) chromedp.QueryAction {
return waitInnerTextMatch("#log", regexp.MustCompile(restr))
}
// waitInnerTextTrimEq will wait for the innerText of the specified element to match a specific text pattern (ignoring whitespace before and after)
func waitInnerTextTrimEq(sel string, innerText string) chromedp.QueryAction {
return waitInnerTextMatch(sel, regexp.MustCompile(`^\s*`+regexp.QuoteMeta(innerText)+`\s*$`))
}
// waitInnerTextMatch will wait for the innerText of the specified element to match a specific regexp pattern
func waitInnerTextMatch(sel string, re *regexp.Regexp) chromedp.QueryAction {
return chromedp.Query(sel, func(s *chromedp.Selector) {
chromedp.WaitFunc(func(ctx context.Context, cur *cdp.Frame, execCtx runtime.ExecutionContextID, 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 !re.MatchString(ret) {
// 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)
})
}