Skip to content

Test what your app means.

A four-panel comic titled Exact Match. A developer writes a test that checks an alert's exact text, thinking it will break the second anyone touches the copy. Two weeks later a PM makes the error message friendlier and the test fails. The developer pastes in the new string. A week later the PM changes the copy back and asks whether the test broke again. The developer says no, they found a better way to do testing, and the screen shows a passing assertion that reads: the alert tells the user how to recover.

semantic-assert lets you assert the requirement instead. Write the claim the way the PRD states it, hand it to a model that acts as the judge, and keep the pass/fail threshold in your code. Thanks to latest AI, it's fast, cheap, and reliable.

ts
const alert = page.getByRole("alert");
await alert.waitFor({ state: "visible" });
await judge.expectPageTo("The alert explains how to recover from the error", {
  region: alert,
});

That's the Playwright fixture. For API responses and other JSON, use the framework-independent core judge.

Start with a problem you've probably hit

Or one of these:

How it works

Every semantic assertion follows the same three steps:

  1. Capture state. Return JSON from your app, or let the Playwright adapter snapshot a page.
  2. Write claims. Describe what a user should be able to tell from that state. Related claims travel in one request.
  3. Assert the result. The judge compares the probabilities that come back with your thresholds, and fails the test when a claim doesn't clear its bar.

Who's the judge?

By default, Jev, TypeSafe's first System One model. Jev doesn't generate text. You give it state and a yes/no or multiple-choice question, and it returns a typed answer with a calibrated probability. That's what lets a threshold in your code act as a real pass mark. Any Provider implementation can stand in for it; see providers.

One evaluation by default

Assertions evaluate once (timeoutMs: 0). A Playwright region waits up to 5 s for its element to attach before that single evaluation, so locator assertions still auto-wait. If content settles later than that, wait for it with Playwright first. For state that's genuinely changing, opt into repeated checks with a positive timeoutMs. Usage metrics record every call, its tokens, and the time spent waiting on the provider.

Where semantic assertions fit

Use semantic assertions forKeep ordinary assertions for
Whether an error gives a concrete recovery stepWhether the alert is visible
Whether a reply promises a refundExact order IDs and status codes
Whether a response answers the customer's questionCounts, totals, and arithmetic
Whether a highlighted passage supports a claimExact CSS values and class names

Model judgments are probabilistic

Calibrate thresholds with both good and bad examples from your own app. A passing assertion is the model's assessment, not proof of correctness.

Get started

Follow the quick start for a runnable check, then add the Playwright adapter for HTML and browser tests.