How to Build and Test WebAssembly in CI

Automating the build and test process for WebAssembly (Wasm) ensures code reliability and accelerates development. This guide provides a straightforward, step-by-step walkthrough on how to set up a continuous integration (CI) pipeline to compile and validate Wasm code, using GitHub Actions as the example platform.

Step 1: Define the Toolchain

Before configuring the pipeline, identify the language and toolchain used to compile your code to WebAssembly. The setup requirements differ depending on your source language:

This guide demonstrates a Rust-based Wasm workflow, as it is currently the most common configuration for web-based Wasm deployments.

Step 2: Create the CI Configuration File

Create a configuration file in your repository. For GitHub Actions, create a file named .github/workflows/wasm-ci.yml.

name: WebAssembly CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Install Rust toolchain
      uses: dtolnay/rust-toolchain@stable
      with:
        targets: wasm32-unknown-unknown

    - name: Install wasm-pack
      run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
        node-id: 20

    - name: Build WebAssembly
      run: wasm-pack build --target web

    - name: Run Tests
      run: wasm-pack test --headless --chrome

Step 3: Configure the Environment

The runner requires specific dependencies to execute tests. Because Wasm code runs in a browser environment or a JavaScript runtime, your CI runner must have those environments installed.

Step 4: Compile the WebAssembly Code

To compile the source code, invoke your language’s compiler target within the CI environment.

In the YAML configuration, this is achieved via:

wasm-pack build --target web

This command compiles the Rust code into a .wasm binary and generates the corresponding JavaScript glue code required to load the module in a web browser.

Step 5: Run Unit and Integration Tests

Wasm tests typically run in one of two environments:

  1. Node.js (Server-side): Fastest execution time; ideal for computational logic that does not require browser APIs.
  2. Headless Browsers (Client-side): Runs inside a virtualized browser (Chrome, Firefox, or Safari) to ensure compatibility with web platforms.

To execute tests in a headless browser during the CI run, use:

wasm-pack test --headless --chrome

If you are testing in a Node.js environment, run:

wasm-pack test --node

Step 6: Cache Dependencies

To speed up subsequent CI runs, cache your build dependencies. For Rust, caching the target/ directory and the Cargo registry reduces execution times significantly.

Add the following step to your workflow file before the build step:

- name: Cache Cargo dependencies
  uses: actions/cache@v4
  with:
    path: |
      ~/.cargo/registry
      ~/.cargo/git
      target/
    key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}