diff --git a/crates/test/README.md b/crates/test/README.md index ef5bd8e6..ff794d32 100644 --- a/crates/test/README.md +++ b/crates/test/README.md @@ -1,167 +1,7 @@ # `wasm-bindgen-test` -This crate is an experimental test harness for `wasm32-unknown-unknown`, with -the goal of allowing you to write tests as you normally do in Rust and then -simply: - -``` -cargo test --target wasm32-unknown-unknown -``` - -This project is still in the early stages of its development so there's not a -ton of documentation just yet, but a taste of how it works is: - -* First, install the test runner. - - ``` - cargo install --path crates/cli - ``` - - (this comes with the normal `wasm-bindgen` CLI tool - -* Next, add this to your `.cargo/config`: - - ```toml - [target.wasm32-unknown-unknown] - runner = 'wasm-bindgen-test-runner' - ``` - -* Next, configure your project's dev-dependencies: - - ```toml - [dev-dependencies] - # or [target.'cfg(target_arch = "wasm32")'.dev-dependencies] - wasm-bindgen-test = { git = 'https://github.com/rustwasm/wasm-bindgen' } - ``` - -* Next, write some tests! - - ```rust - // in tests/wasm.rs - extern crate wasm_bindgen_test; - - use wasm_bindgen_test::*; - - #[wasm_bindgen_test] - fn pass() { - assert_eq!(1, 1); - } - - #[wasm_bindgen_test] - fn fail() { - assert_eq!(1, 2); - } - ``` - -* And finally, execute your tests: - - ``` - $ cargo test --target wasm32-unknown-unknown - Finished dev [unoptimized + debuginfo] target(s) in 0.11s - Running /home/.../target/wasm32-unknown-unknown/debug/deps/wasm-4a309ffe6ad80503.wasm - running 2 tests - - test wasm::pass ... ok - test wasm::fail ... FAILED - - failures: - - ---- wasm::fail output ---- - error output: - panicked at 'assertion failed: `(left == right)` - left: `1`, - right: `2`', crates/test/tests/wasm.rs:14:5 - - JS exception that was thrown: - RuntimeError: unreachable - at __rust_start_panic (wasm-function[1362]:33) - at rust_panic (wasm-function[1357]:30) - at std::panicking::rust_panic_with_hook::h56e5e464b0e7fc22 (wasm-function[1352]:444) - at std::panicking::continue_panic_fmt::had70ba48785b9a8f (wasm-function[1350]:122) - at std::panicking::begin_panic_fmt::h991e7d1ca9bf9c0c (wasm-function[1351]:95) - at wasm::fail::ha4c23c69dfa0eea9 (wasm-function[88]:477) - at core::ops::function::FnOnce::call_once::h633718dad359559a (wasm-function[21]:22) - at wasm_bindgen_test::__rt::Context::execute::h2f669104986475eb (wasm-function[13]:291) - at __wbg_test_fail_1 (wasm-function[87]:57) - at module.exports.__wbg_apply_2ba774592c5223a7 (/home/alex/code/wasm-bindgen/target/wasm32-unknown-unknown/wbg-tmp/wasm-4a309ffe6ad80503.js:61:66) - - - failures: - - wasm::fail - - test result: FAILED. 1 passed; 1 failed; 0 ignored - - error: test failed, to rerun pass '--test wasm' - ``` - -And that's it! You've now got a test harness executing native wasm code inside -of Node.js and you can use `cargo test` as you normally would for workflows. - -## Asynchronous Tests - -Not all tests can execute immediately and some may need to do "blocking" work -like fetching resources and/or other bits and pieces. To accommodate this -asynchronous tests are also supported through the `futures` crate: - -```rust -#[wasm_bindgen_test(async)] -fn my_test() -> impl Future { - // ... -} -``` - -The test will pass if the future resolves without panicking or returning an -error, and otherwise the test will fail. - -This support is currently powered by the `wasm-bindgen-futures` crate. - -## Running Tests in Headless Browsers - -Add this to the root of your test crate: - -```rust -wasm_bindgen_test_configure!(run_in_browser); -``` - -### Configuring Which Browser is Used - -If one of the following environment variables is set, then the corresponding -WebDriver and browser will be used. If none of these environment variables are -set, then the `$PATH` is searched for a suitable WebDriver implementation. - -#### `GECKODRIVER=path/to/geckodriver` - -Use Firefox for headless browser testing, and `geckodriver` as its -WebDriver. - -The `firefox` binary must be on your `$PATH`. - -[Get `geckodriver` here](https://github.com/mozilla/geckodriver/releases) - -#### `CHROMEDRIVER=path/to/chromedriver` - -Use Chrome for headless browser testing, and `chromedriver` as its -WebDriver. - -The `chrome` binary must be on your `$PATH`. - -[Get `chromedriver` here](http://chromedriver.chromium.org/downloads) - -#### `SAFARIDRIVER=path/to/safaridriver` - -Use Safari for headless browser testing, and `safaridriver` as its -WebDriver. - -This is installed by default on Mac OS. It should be able to find your Safari -installation by default. - -### Debugging Headless Browser Tests - -Set the `NO_HEADLESS=1` environment variable and the browser tests will not run -headless. Instead, the tests will start a local server that you can visit in -your Web browser of choices, and headless testing should not be used. You can -then use your browser's devtools to debug. +[**Read the "Testing with `wasm-bindgen-test`" section of the +guide!**](https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/index.html) ## Components diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index ee461f01..0468e4d3 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -64,7 +64,15 @@ -------------------------------------------------------------------------------- -- [Contributing](./contributing/index.md) +- [Testing with `wasm-bindgen-test`](./wasm-bindgen-test/index.md) + - [Usage](./wasm-bindgen-test/usage.md) + - [Writing Asynchronous Tests](./wasm-bindgen-test/asynchronous-tests.md) + - [Testing in Headless Browsers](./wasm-bindgen-test/browsers.md) + - [Continuous Integration](./wasm-bindgen-test/continuous-integration.md) + +-------------------------------------------------------------------------------- + +- [Contributing to `wasm-bindgen`](./contributing/index.md) - [Testing](./contributing/testing.md) - [Internal Design](./contributing/design/index.md) - [JS Objects in Rust](./contributing/design/js-objects-in-rust.md) diff --git a/guide/src/wasm-bindgen-test/asynchronous-tests.md b/guide/src/wasm-bindgen-test/asynchronous-tests.md new file mode 100644 index 00000000..880c6cbd --- /dev/null +++ b/guide/src/wasm-bindgen-test/asynchronous-tests.md @@ -0,0 +1,41 @@ +# Writing Asynchronous Tests + +Not all tests can execute immediately and some may need to do "blocking" work +like fetching resources and/or other bits and pieces. To accommodate this +asynchronous tests are also supported through the `futures` and +`wasm-bindgen-futures` crates. + +To write an asynchronous test: + +1. Change `#[wasm_bindgen_test]` into `#[wasm_bindgen_test(async)]` + +2. Change the return type of the test function to `impl Future` + +The test will pass if the future resolves without panicking or returning an +error, and otherwise the test will fail. + +## Example + +```rust +extern crate futures; +extern crate js_sys; +extern crate wasm_bindgen_futures; + +use futures::Future; +use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::JsFuture; + +#[wasm_bindgen_test(async)] +fn my_async_test() -> impl Future { + // Create a promise that is ready on the next tick of the micro task queue. + let promise = js_sys::Promise::resolve(&JsValue::from(42)); + + // Convert that promise into a future and make the test wait on it. + JsFuture::from(promise) + .map(|x| { + assert_eq!(x, 42); + }) + .map_err(|_| unreachable!()) +} +``` diff --git a/guide/src/wasm-bindgen-test/browsers.md b/guide/src/wasm-bindgen-test/browsers.md new file mode 100644 index 00000000..cf947956 --- /dev/null +++ b/guide/src/wasm-bindgen-test/browsers.md @@ -0,0 +1,71 @@ +# Testing in Headless Browsers + +## Configure Your Test Crate + +Add this to the root of your test crate, e.g. `$MY_CRATE/tests/wasm.rs`: + +```rust +use wasm_bindgen_test::wasm_bindgen_test_configure; + +wasm_bindgen_test_configure!(run_in_browser); +``` + +## Configuring Which Browser is Used + +> ⚡ If you are using `wasm-pack`, skip this step! Instead, use `wasm-pack test +> --chrome`, `wasm-pack test --firefox`, or `wasm-pack test --safari`. +> `wasm-pack` will automatically download and configure the appropriate +> WebDriver client for you. + +If one of the following environment variables is set, then the corresponding +WebDriver and browser will be used. If none of these environment variables are +set, then the `$PATH` is searched for a suitable WebDriver implementation. + +#### `GECKODRIVER=path/to/geckodriver` + +Use Firefox for headless browser testing, and `geckodriver` as its +WebDriver. + +The `firefox` binary must be on your `$PATH`. + +[Get `geckodriver` here](https://github.com/mozilla/geckodriver/releases) + +#### `CHROMEDRIVER=path/to/chromedriver` + +Use Chrome for headless browser testing, and `chromedriver` as its +WebDriver. + +The `chrome` binary must be on your `$PATH`. + +[Get `chromedriver` here](http://chromedriver.chromium.org/downloads) + +#### `SAFARIDRIVER=path/to/safaridriver` + +Use Safari for headless browser testing, and `safaridriver` as its +WebDriver. + +This is installed by default on Mac OS. It should be able to find your Safari +installation by default. + +## Running the Tests in the Headless Browser + +Once the tests are configured to run in a headless browser, executing the tests +is the same: + +```bash +cargo test --target wasm32-unknown-unknown + +# or, if you're using wasm-pack +wasm-pack test --headless --chrome --firefox --safari +``` + +### Debugging Headless Browser Tests + +> If you're using `wasm-pack`, omitting the `--headless` flag will disable +> headless mode, and allow you to debug failing tests in your browser's +> devtools. + +Set the `NO_HEADLESS=1` environment variable and the browser tests will not run +headless. Instead, the tests will start a local server that you can visit in +your Web browser of choices, and headless testing should not be used. You can +then use your browser's devtools to debug. diff --git a/guide/src/wasm-bindgen-test/continuous-integration.md b/guide/src/wasm-bindgen-test/continuous-integration.md new file mode 100644 index 00000000..71331de1 --- /dev/null +++ b/guide/src/wasm-bindgen-test/continuous-integration.md @@ -0,0 +1,63 @@ +# Setting Up Continuous Integration with `wasm-bindgen-test` + +This page contains example configurations for running `wasm-bindgen-test`-based +tests in various CI services. + +Is your favorite CI service missing? [Send us a pull +request!](https://github.com/rustwasm/wasm-bindgen) + +## Travis CI + +```yaml +language: rust +rust: nightly + +addons: + firefox: latest + chrome: stable + +install: + - rustup target add wasm32-unknown-unknown + - cargo install wasm-bindgen-cli + # Install node.js with nvm. + - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash + - source ~/.nvm/nvm.sh + - nvm install v10.5 + # Install chromedriver. + - curl --retry 5 -LO https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip + - unzip chromedriver_linux64.zip + # Install geckodriver. + - curl --retry 5 -LO https://github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-linux64.tar.gz + - tar xf geckodriver-v0.21.0-linux64.tar.gz + +script: + # Test in Chrome. + - CHROMEDRIVER=$(pwd)/chromedriver cargo test --target wasm32-unknown-unknown + # Test in Firefox. + - GECKODRIVER=$(pwd)/geckodriver cargo test --target wasm32-unknown-unknown +``` + +## AppVeyor + +```yaml +install: + - ps: Install-Product node 10 + - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V + - rustup target add wasm32-unknown-unknown + - cargo install wasm-bindgen-cli + +build: false + +test_script: + # Test in Chrome. chromedriver is installed by default in appveyor. + - set CHROMEDRIVER=C:\Tools\WebDriver\chromedriver.exe + - cargo test --target wasm32-unknown-unknown + - set CHROMEDRIVER= + # Test in Firefox. geckodriver is also installed by default. + - set GECKODRIVER=C:\Tools\WebDriver\geckodriver.exe + - cargo test --target wasm32-unknown-unknown +``` diff --git a/guide/src/wasm-bindgen-test/index.md b/guide/src/wasm-bindgen-test/index.md new file mode 100644 index 00000000..3667d7f7 --- /dev/null +++ b/guide/src/wasm-bindgen-test/index.md @@ -0,0 +1,17 @@ +# Testing on `wasm32-unknown-unknown` with `wasm-bindgen-test` + +The `wasm-bindgen-test` crate is an experimental test harness for Rust programs +compiled to wasm using `wasm-bindgen` and the `wasm32-unknown-unknown` +target. + +## Goals + +* Write tests for wasm as similar as possible to how you normally would write + `#[test]`-style unit tests for native targets. + +* Run the tests with the usual `cargo test` command but with an explicit wasm + target: + + ``` + cargo test --target wasm32-unknown-unknown + ``` diff --git a/guide/src/wasm-bindgen-test/usage.md b/guide/src/wasm-bindgen-test/usage.md new file mode 100644 index 00000000..837ea7de --- /dev/null +++ b/guide/src/wasm-bindgen-test/usage.md @@ -0,0 +1,110 @@ +# Using `wasm-bindgen-test` + +## Install the Test Runner + +> ⚡ If you are using `wasm-pack`, skip this step! `wasm-pack test` will +> automatically ensure that the right version of the test runner is installed. + +The test runner comes along with the main `wasm-bindgen` CLI tool. Make sure to +replace "X.Y.Z" with the same version of `wasm-bindgen` that you already have in +`Cargo.toml`! + +```shell +cargo install wasm-bindgen-cli --vers "X.Y.Z" +``` + +## Configure `.cargo/config` to use the Test Runner + +> ⚡ If you are using `wasm-pack`, skip this step! `wasm-pack test` will +> automatically configure `cargo test` to use the `wasm-bindgen` test runner. + +Add this to `$MY_CRATE/.cargo/config`: + +```toml +[target.wasm32-unknown-unknown] +runner = 'wasm-bindgen-test-runner' +``` + +## Add `wasm-bindgen-test` to Your `Cargo.toml`'s `[dev-dependencies]` + +Make sure to replace "X.Y.Z" with the same version of `wasm-bindgen` that you +have in the `[dependencies]` section! + +```toml +[dev-dependencies] +wasm-bindgen-test = "X.Y.Z" +``` + +## Write Some Tests + +Create a `$MY_CRATE/tests/wasm.rs` file: + +```rust +extern crate wasm_bindgen_test; +use wasm_bindgen_test::*; + +#[wasm_bindgen_test] +fn pass() { + assert_eq!(1, 1); +} + +#[wasm_bindgen_test] +fn fail() { + assert_eq!(1, 2); +} +``` + +Writing tests is the same as normal Rust `#[test]`s, except we are using the +`#[wasm_bindgen_test]` attribute. + +One other difference is that the tests **must** be in the root of the crate, or +within a `pub mod`. Putting them inside a private module will not work. + +## Execute Your Tests + +> ⚡ If you are using `wasm-pack`, run `wasm-pack test` instead! For more +> details, run `wasm-pack test --help`. + +Run the tests by specifying the `wasm32-unknown-unknown` target when running +`cargo test`. By default, the tests are run in Node.js, but you can [configure +tests to run inside headless browsers](./browsers.html) as well. + +```shell +$ cargo test --target wasm32-unknown-unknown + Finished dev [unoptimized + debuginfo] target(s) in 0.11s + Running /home/.../target/wasm32-unknown-unknown/debug/deps/wasm-4a309ffe6ad80503.wasm +running 2 tests + +test wasm::pass ... ok +test wasm::fail ... FAILED + +failures: + +---- wasm::fail output ---- + error output: + panicked at 'assertion failed: `(left == right)` + left: `1`, + right: `2`', crates/test/tests/wasm.rs:14:5 + + JS exception that was thrown: + RuntimeError: unreachable + at __rust_start_panic (wasm-function[1362]:33) + at rust_panic (wasm-function[1357]:30) + at std::panicking::rust_panic_with_hook::h56e5e464b0e7fc22 (wasm-function[1352]:444) + at std::panicking::continue_panic_fmt::had70ba48785b9a8f (wasm-function[1350]:122) + at std::panicking::begin_panic_fmt::h991e7d1ca9bf9c0c (wasm-function[1351]:95) + at wasm::fail::ha4c23c69dfa0eea9 (wasm-function[88]:477) + at core::ops::function::FnOnce::call_once::h633718dad359559a (wasm-function[21]:22) + at wasm_bindgen_test::__rt::Context::execute::h2f669104986475eb (wasm-function[13]:291) + at __wbg_test_fail_1 (wasm-function[87]:57) + at module.exports.__wbg_apply_2ba774592c5223a7 (/home/alex/code/wasm-bindgen/target/wasm32-unknown-unknown/wbg-tmp/wasm-4a309ffe6ad80503.js:61:66) + + +failures: + + wasm::fail + +test result: FAILED. 1 passed; 1 failed; 0 ignored + +error: test failed, to rerun pass '--test wasm' +```