Giter VIP home page Giter VIP logo

wasmbrowsertest's Introduction

wasmbrowsertest Build Status

Run Go wasm tests easily in your browser.

If you have a codebase targeting the wasm platform, chances are you would want to test your code in a browser. Currently, that process is a bit cumbersome:

  • The test needs to be compiled to a wasm file.
  • Then loaded into an HTML file along with the wasm_exec.js.
  • And finally, this needs to be served with a static file server and then loaded in the browser.

This tool automates all of that. So you just have to type GOOS=js GOARCH=wasm go test, and it automatically executes the tests inside a browser !

Quickstart

  • go install github.com/agnivade/wasmbrowsertest@latest. This will place the binary in $GOPATH/bin, or $GOBIN, if that has a different value.
  • Rename the binary to go_js_wasm_exec.
  • Add $GOBIN to $PATH if it is not already done.
  • Run tests as usual: GOOS=js GOARCH=wasm go test.
  • You can also take a cpu profile. Set the -cpuprofile flag for that.

Ok, but how does the magic work ?

go test allows invocation of a different binary to run a test. go help test has a line:

-exec xprog
	    Run the test binary using xprog. The behavior is the same as
	    in 'go run'. See 'go help run' for details.

And go help run says:

By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog:
	'xprog a.out arguments...'.
If the -exec flag is not given, GOOS or GOARCH is different from the system
default, and a program named go_$GOOS_$GOARCH_exec can be found
on the current search path, 'go run' invokes the binary using that program,
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
cross-compiled programs when a simulator or other execution method is
available.

So essentially, there are 2 ways:

  • Either have a binary with the name of go_js_wasm_exec in your $PATH.
  • Or set the -exec flag in your tests.

Use whatever works for you.

How is a CPU profile taken ?

A CPU profile is run during the duration of the test, and then converted to the pprof format so that it can be natively analyzed with the Go toolchain.

Can I run something which is not a test ?

Yep. GOOS=js GOARCH=wasm go run main.go also works. If you want to actually see the application running in the browser, set the WASM_HEADLESS variable to off like so WASM_HEADLESS=off GOOS=js GOARCH=wasm go run main.go.

Can I use this inside Travis ?

Sure.

Add these lines to your .travis.yml

addons:
  chrome: stable

install:
- go install github.com/agnivade/wasmbrowsertest@latest
- mv $GOPATH/bin/wasmbrowsertest $GOPATH/bin/go_js_wasm_exec
- export PATH=$GOPATH/bin:$PATH

Now, just setting GOOS=js GOARCH=wasm will run your tests using wasmbrowsertest. For other CI environments, you have to do something similar.

Can I use this inside Github Action?

Sure.

Add these lines to your .github/workflows/ci.yml

PS: adjust the go version you need in go-version section

on: [push, pull_request]
name: Unit Test
jobs:
  test:
    strategy:
      matrix:
        go-version: [1.xx.x]
        os: [ubuntu-latest]
    runs-on: ${{ matrix.os }}
    steps:
    - name: Install Go
      uses: actions/setup-go@v2
      with:
        go-version: ${{ matrix.go-version }}
    - name: Install chrome
      uses: browser-actions/setup-chrome@latest
    - name: Install dep
      run: go install github.com/agnivade/wasmbrowsertest@latest
    - name: Setup wasmexec
      run: mv $(go env GOPATH)/bin/wasmbrowsertest $(go env GOPATH)/bin/go_js_wasm_exec
    - name: Checkout code
      uses: actions/checkout@v2

What sorts of browsers are supported ?

This tool uses the ChromeDP protocol to run the tests inside a Chrome browser. So Chrome or any blink-based browser will work.

Why not firefox ?

Great question. The initial idea was to use a Selenium API and drive any browser to run the tests. But unfortunately, geckodriver does not support the ability to capture console logs - mozilla/geckodriver#284. Hence, the shift to use the ChromeDP protocol circumvents the need to have any external driver binary and just have a browser installed in the machine.

A tip on coverage data using go 1.20 or later:

Code coverage changes introduced in go 1.20 produce multiple coverage data files in binary format.

In wasmbrowsertest, file system operations for coverage files occur via HTTP API calls.

Prefer using -test.gocoverdir=/path/to/coverage instead of -test.coverprofile=coverage.out when coverage data is needed. This will prevent http api calls that would read all the coverage data files and write the larger coverage.out file.

In a subsequent step, use go tool covdata -i /path/to/coverage -o coverage.out or similar to process coverage data files into the desired output format. An additional benefit is that multiple test coverage runs that write their data to the same coverage directory can be merged together with this command.

Errors

total length of command line and environment variables exceeds limit

If the error total length of command line and environment variables exceeds limit appears, then the current environment variables' total size has exceeded the maximum when executing Go Wasm binaries.

To resolve this issue, install cleanenv and use it to prefix your command.

For example, if these commands are used:

export GOOS=js GOARCH=wasm
go test -cover ./...

The new commands should be the following:

go install github.com/agnivade/wasmbrowsertest/cmd/cleanenv@latest

export GOOS=js GOARCH=wasm
cleanenv -remove-prefix GITHUB_ -- go test -cover ./...

The cleanenv command above removes all environment variables prefixed with GITHUB_ before running the command after the --. The -remove-prefix flag can be repeated multiple times to remove even more environment variables.

wasmbrowsertest's People

Contributors

agnivade avatar frankreh avatar gregory-ledray avatar hajimehoshi avatar jalextowle avatar johnstarich avatar kenshaw avatar mlctrez avatar realpy avatar reusee avatar testwill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

wasmbrowsertest's Issues

Is there away to click "OK" on an alert window?

Great project. I am toying around with wasm/golang and wanted to use your tool to write tests for a POC I am working on.

I have a go function that is calling alert("some message") in the browser in a failure condition and that makes the test hang when I call that function. Is there any way I can click the OK button on the pop-up that appears?

Accept permission

Some API's needs a permission from the user, such as Notfication API, Credential Management API, Geolocation API. There's many APIs that need explicit permission from the user.

In those case, the test "fails", because the user didn't accept the API permission. Of course, it should have a way to test this
fail condition (when user doesn't accept).

But, how I can test when the user accepts?

The current test doesn't seems to accept any permission. :\

Run examples

Is it possible to run examples?

package js_test

import "syscall/js"

func ExampleConsole() {
	console := js.Global().Get("console")
	console.Call("log", "1")
	// Output: 3
}
testing: open temp file: open /tmp/go-example-stdout-ExampleConsole-0.txt: not implemented on js
exit status 1

Can we make it not to redirect the output in a file? Or maybe make our own hack to check the stdout output?

"panic: newosproc: not implemented" when executing in travis

I may be doing something stupid, but perhaps someone else has seen this already:

$ GOOS=js GOARCH=wasm go test -exec wasmbrowsertest -v .

panic: newosproc: not implemented

fatal error: panic on system stack

runtime stack:

runtime.throw(0x525ee, 0x15)

	/home/travis/.gimme/versions/go/src/runtime/panic.go:1112 +0x7

panic(0x1df20, 0x71620)

	/home/travis/.gimme/versions/go/src/runtime/panic.go:893 +0x95

runtime.newosproc(...)

	/home/travis/.gimme/versions/go/src/runtime/os_js.go:116

runtime.newm1(0x440000)

	/home/travis/.gimme/versions/go/src/runtime/proc.go:1753 +0x17

runtime.newm(0x58540, 0x430800)

	/home/travis/.gimme/versions/go/src/runtime/proc.go:1732 +0xc

runtime.startm(0x0, 0x100000001)

	/home/travis/.gimme/versions/go/src/runtime/proc.go:1869 +0x1b

runtime.wakep()

	/home/travis/.gimme/versions/go/src/runtime/proc.go:1953 +0x4

runtime.newproc1(0x58430, 0x43c750, 0x0, 0x400180, 0x120e0002)

	/home/travis/.gimme/versions/go/src/runtime/proc.go:3487 +0x4d

runtime.newproc.func1()

	/home/travis/.gimme/versions/go/src/runtime/proc.go:3381 +0x2

runtime.systemstack(0x205a00)

	/home/travis/.gimme/versions/go/src/runtime/asm_wasm.s:166 +0x2

runtime.mstart()

	/home/travis/.gimme/versions/go/src/runtime/proc.go:1041

goroutine 1 [running]:

runtime.systemstack_switch()

	/home/travis/.gimme/versions/go/src/runtime/asm_wasm.s:177 fp=0x43c700 sp=0x43c6f8 pc=0x13b30000

runtime.newproc(0x0, 0x58430)

	/home/travis/.gimme/versions/go/src/runtime/proc.go:3380 +0x3 fp=0x43c740 sp=0x43c700 pc=0x125e0003

runtime.init.5()

	/home/travis/.gimme/versions/go/src/runtime/proc.go:242 +0x2 fp=0x43c758 sp=0x43c740 pc=0x120e0002

runtime.doInit(0x1c8280)

	/home/travis/.gimme/versions/go/src/runtime/proc.go:5414 +0xf fp=0x43c788 sp=0x43c758 pc=0x1288000f

runtime.main()

	/home/travis/.gimme/versions/go/src/runtime/proc.go:150 +0xf fp=0x43c7e0 sp=0x43c788 pc=0x120c000f

runtime.goexit()

	/home/travis/.gimme/versions/go/src/runtime/asm_wasm.s:428 +0x1 fp=0x43c7e8 sp=0x43c7e0 pc=0x13dc0001

FAIL	github.com/WIZARDISHUNGRY/wasm_websocket	0.582s

FAIL

The command "GOOS=js GOARCH=wasm go test -exec wasmbrowsertest -v ." exited with 1.

Error: command line too long

Hi ,
Thanks for your project.
I would like to migrate my test from travis to github actions and the test failed with "Error: command line too long"
Any idea why this error happening? I sucessfull run test on a ubuntu:latest container , the problem is on the github actions (maybe the go install is not on the default location)

error generating coverage report

First off ๐Ÿ˜Ž thanks for your work on this!

When a recent version of go I'm getting an error when generating code coverage:

error generating coverage report: output directory "/tmp/go-build888418937/b001/gocoverdir" inaccessible (err: stat /tmp/go-build888418937/b001/gocoverdir: not implemented on js); no coverage data written

go test . works with later versions of go but breaks when adding -cover

This repository contains my test case wbtexample

When running with go1.18.4 there are no errors.
shell script

When running with go1.20.7 I get the error generating coverage.
shell script

I've added logging statements in github.com/agnivade/wasmbrowsertest and have tracked it down to a non-zero exit code at main.go

I'm using google chrome 116.0.5845.96 on Ubuntu 22.04.3 LTS if that matters.

Tests work in real Chrome in Windows but not chromedp in WSL

Basically, for some reason my tests work in real Chrome but not when run in chromedp.

Full error which only occurs in WSL with chromedp:

[wasmbrowsertest]: 2020/02/04 23:01:50 main.go:214: {"type":"object","subtype":"error","className":"TypeError","description":"Ty
peError: Could not download wasm module","objectId":"{\"injectedScriptId\":2,\"id\":1}","preview":{"type":"object","subtype":"er
ror","description":"TypeError: Could not download wasm module","overflow":false,"properties":[{"name":"stack","type":"string","v
alue":"TypeError: Could not download wasm module"},{"name":"message","type":"string","value":"Could not download wasm module"}]}
}

See the source code: https://chromium.googlesource.com/chromium/src/+/70d7b68f1669306da4c713c7e4d4b0be97a13ab8/third_party/WebKit/Source/bindings/modules/v8/wasm/WasmResponseExtensions.cpp

And a tangentially related commit: https://chromium-review.googlesource.com/c/chromium/src/+/876103

Reproduction

Reproduction first involves getting the testing setup, and then getting the actual project to test against.

Testing Setup

git clone https://github.com/Gregory-Ledray/wasmbrowsertest
cd wasmbrowsertest
git checkout wasme2e

Then inspect the script test_build_install.sh for errors for your environment

chmod +rwx ./test_build_install.sh
./test_build_install.sh

Project to test against

first go somewhere outside a repo. Then...

git clone https://gitlab.com/polyapp-open-source/build-wasm
cd build-wasm
git checkout 1-create-and-run-integration-tests-which-require-a-browser

Inspect the test_build_run.sh script for errors in your environment.

This next step will start a convenient web server.

./test_build_run.sh

This next step is, finally, where the problem is.

./test_integration.sh

The Problem

Finally, we can see the problem. If you navigate to localhost:4200 and open dev tools, you see this, which is 100% exactly what I expect to see and is made possible by running the integration testing wasm file when you load the web server started with ./test_build_run.sh:

--- FAIL: TestAlwaysFail (0.00s)
wasm_exec.js:41     main_integration_test.go:20: always fail
wasm_exec.js:41 FAIL
(index):46 go program terminated
wasm_exec.js:487 Uncaught Error: Go program has already exited
    at global.Go._resume (wasm_exec.js:487)
    at wasm_exec.js:500
    at XMLHttpRequest.req.onload ((index):62)
_resume @ wasm_exec.js:487
(anonymous) @ wasm_exec.js:500
req.onload @ (index):62
load (async)
fetchWrapper @ (index):61
syscall/js.valueCall @ wasm_exec.js:327
syscall_js.valueCall @ wasm-0200847e-1263:1
syscall_js.Value.Call @ wasm-0200847e-1249:1
gitlab.com_polyapp_open_source_build_wasm_cmd_frontend.ButtonPressCallback @ wasm-0200847e-2843:1
gitlab.com_polyapp_open_source_build_wasm_cmd_frontend.TestButtonPressCallback @ wasm-0200847e-2848:1
testing.tRunner @ wasm-0200847e-2253:1
wasm_pc_f_loop @ wasm-0200847e-964:1
wasm_export_run @ wasm-0200847e-962:1
run @ wasm_exec.js:478
(anonymous) @ (index):45
Promise.then (async)
(anonymous) @ (index):41
(anonymous) @ (index):53

Now consider the output from running the test_integration script in build-wasm, which is running chromedp in headless mode:

integration testing WASM code GOOS=js; GOARCH=wasm
2020/02/04 23:22:12 reached special case
[wasmbrowsertest]: 2020/02/04 23:22:12 main.go:176: exit code seen: 0
[wasmbrowsertest]: 2020/02/04 23:22:12 main.go:214: {"type":"object","subtype":"error","className":"TypeError","description":"Ty
peError: Could not download wasm module","objectId":"{\"injectedScriptId\":2,\"id\":1}","preview":{"type":"object","subtype":"er
ror","description":"TypeError: Could not download wasm module","overflow":false,"properties":[{"name":"stack","type":"string","v
alue":"TypeError: Could not download wasm module"},{"name":"message","type":"string","value":"Could not download wasm module"}]}
}
integration testing everything else GOOS=default; GOARCH=default
ok      gitlab.com/polyapp-open-source/build-wasm/cmd/backend   (cached)
?       gitlab.com/polyapp-open-source/build-wasm/cmd/webserver [no test files]

There are 2 problems here, only 1 of which is baffling. First, the test failed yet a non-0 exit code was produced (this is fixed in #13 ). Second, we see the error is occurring because the wasm file did not download. I have no idea why my simple web server is capable of serving the WASM file to a real Chrome instance running on Windows yet this similar clone running inside wasmbrowsertest isn't able to serve to Chromium in headless mode. I'm especially baffled because I basically copied the server from the existing wasmbrowsertest web server in handler.go. For your amusement, you can mess with func (ws *simpleWebServer) ServeHTTP in wasmbrowsertest/main.go by, say, eliminating the special case for wasm code. Rebuild with the scripts as before and notice you get the same result.

Summary and Speculation

For some reason my tests work in real Chrome but not when run in chromedp.

One of the following could be true:

  1. Chromium in WSL seems to be handling a served WASM file differently than Chrome in Windows (by not loading it? - seems unlikely since it works with the regular wasmbrowsertest).
  2. github.com/chromedp/chromedp is not setting up Chromium correctly in WSL for it to receive said WASM file. This doesn't really make sense to me because chromedp has loaded the file correctly before, as noted above.
  3. There's something wrong with my test setup which leads the WASM file to not be downloaded by my wasmbrowsertest branch, but yet another web server I have works, and wasmbrowsertest 's regular setup also works. After staring at index.html for a while I don't see any important differences when we're calling WebAssembly.instantiateStreaming

I suppose I could also post this Issue on chromedp's repo, or just keep plugging away until i figure it out.

Need GPU disabled in chromedp to run

Could you include some examples please?

Background

I'm trying to get this working here:
https://gitlab.com/polyapp-open-source/build-wasm/-/merge_requests/1

Steps to reproduce

git clone https://gitlab.com/polyapp-open-source/build-wasm
cd build-wasm
git checkout -b "1-create-and-run-integration-tests-which-require-a-browser" "origin/1-create-and-run-integration-tests-which-require-a-browser"
chmod +rwx ./test_integration.sh
./test_integration.sh

And that last command hangs forever even if all tests in main_integration_test.go are commented out and I comment out everything in func main() in frontend/main.go

`total length of command line and environment variables exceeds limit` in GitHub Actions

Example: https://github.com/hajimehoshi/ebiten/actions/runs/3447009698/jobs/5752563468

There is a limitation of total environment variable lengths in wasm_exec.js (https://github.com/golang/go/blob/fcd14bdcbdfbb5b0c79cfecff95291837836a76d/misc/wasm/wasm_exec.js#L523-L525) and apparently the limitation is exceeded in GitHub Actions.

wasmbrowsertest is not to blame, but would it be possible to add a hack to suppress this error, or add a backdoor to pass an original wasm_exec.js?

goroutine support

how do i run the go scheduler, and goroutines/channels within my browser tests?

cross browser testing

this is designed for chrome.

anyone have any ideas about if we can extend this for Edge and Safari ?

update documentation regarding go 1.20 coverage tools

This issue to get your thoughts on a documentation update.
I think it would be a good add, but understand if it seems out of scope for this project's readme.

The code coverage tools introduced in go 1.20 produce multiple coverage data files in binary format, one of the drivers for #49

Using -test.coverprofie still works after #49 and produces the single coverage output file.

I'd like to submit a PR to add instructions (at a high level) that read:

  • When generating coverage with go 1.20 and later:
    • Prefer the -test.gocoverdir option instead of -test.coverprofile for coverage generation.
      • Having less data across the http fs api calls is the primary benefit.
    • Post process the coverage data files using the go covdata tool.
      • As in go tool covdata -i <gocoverdir> -o coverage.out
      • A additional benefit is that wasm and nonwasm coverage runs can be merged with this command.

Thanks,
Matt

wasmbrowsertest taking too long and not printing any output

https://travis-ci.com/nhooyr/websocket/jobs/288703981

--- FAIL: TestWasm (60.00s)
    conn_test.go:305: wasm test binary failed: signal: killed:

This is indicating the go test -exec=wasmbrowsertest command failed as it was killed by the 60s timeout.

travis config: https://github.com/nhooyr/websocket/blob/5afbe3c1d163117b5ff9df021aa4b14e6ab2e7b5/.travis.yml#L25-L31

go test invocation: https://github.com/nhooyr/websocket/blob/wasm/conn_test.go#L300-L307

wasm test: https://github.com/nhooyr/websocket/blob/5afbe3c1d163117b5ff9df021aa4b14e6ab2e7b5/ws_js_test.go

As you can see, even with the t.Fatal in the wasm test, wasmbrowsertest is timing out after 60s and prints no output. Any ideas why?

Support collecting code coverage

This is a very useful tool and I'm using it in https://github.com/nhooyr/websocket

It'd be nice to be able to collect coverage from via the -coverprofile flag to go test.

Right now I get:

$ env GOOS=js GOARCH=wasm go test   "-coverprofile=ci/out/coverage.prof"  "-coverpkg=./..." ./internal/wsjs
PASS
testing: open /var/folders/zd/5rls6whn363cpxvs_2h4fy6m0000gn/T/go-build284234120/b001/_cover_.out: not implemented on js

using -- to signify end of options

I've found supporting -- as an end of options argument useful in getting the remaining arguments passed to the wasm binary.

Perhaps you would consider implementing this too or looking at a PR I could provide. It is not quite as straight forward as letting the flag.Parse catch the --, but close.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.