Coming soon:


High-confidence browser testing

Why use WebCheck?

  • Reduce testing effort

    Generate thousands of test cases instead of writing them manually. Lower the maintenance burden of your browser testing by writing concise specifications with looser coupling to your implementation.

  • Find complex bugs

    WebCheck simulates complex and unexpected user behavior using generative random testing. When the specification is violated, WebCheck finds a minimal failing example.

  • Understand your system

    Focus on specifying your system, not on writing test cases. A specification lets you run WebCheck, but can also increase your team's understanding of the system.

  • Adopt gradually

    WebCheck works with any web application that renders DOM elements. Start simple, and gradually refine your specification to increase coverage and confidence.

What does it look like?

The following specification is for a record player, with a button that toggles between the paused and playing states.

readyWhen = ".record-player"
It waits for a DOM element matching the CSS selector .record-player before taking any action.
buttonText =
  map _.textContent (queryOne ".play-pause" { textContent })
This helper definition finds an optional text for the play/pause button.
actions = clicks
WebCheck generates click actions for all clickable elements.
proposition =
  let playing = buttonText == Just "Pause"
      paused = buttonText == Just "Play"
      play = paused && next playing
      pause = playing && next paused
  in paused && always (play || pause)
A proposition describes the correctness of a web application. Here we start in the paused state, and a valid transition is either play or pause.

Now, let's run WebCheck with a broken implementation of the record player. We get a minimal behavior that violates the specification:

$ webcheck RecordPlayer.spec.purs record-player.html
Running test with size: 10
Test failed. Shrinking...
1. State
  • .play-pause
      - textContent = "Play"
2. click button[0]
3. State
  • .play-pause
      - textContent = "Pause"
4. click button[0]
5. State
  • .play-pause
      - textContent = "undefined"

Looks like pausing broke the record player!


Interested in WebCheck? Great! It's is currently in the making. Early prototypes showed very promising results, and a simple specification found inconsistencies in two mainstream implementations of TodoMVC.

The first publicly available version will likely be a SaaS product, possibly with a free version for open-source projects. Longer-term plans include:

  • an integrated online editor for writing specifications
  • powerful debugging and introspection tools for troubleshooting failed tests
  • tight integration with GitHub, GitLab, and various CI services

If you're wondering how it works under the hood, detailed blogs post are coming. In the meantime, I wrote a quick reply on

Subscribe to the newsletter below and get updates on the project, and find me on Twitter and give feedback. I'm interested in discussing how WebCheck could fit your project!

Stay Tuned

The newsletter is powered by ButtonDown.