Skip to content
Published alpha · next channelRead as Markdown

Watch a failure shrink ​

An order belongs to a customer. Its lines belong to that order, and its total must equal the sum of the line prices. Those relationships should survive shrinking.

This demo tests a deliberately false rule: every order fits the selected budget. Find an order that breaks it, reveal the real shrink result, then replay that failure. Change the seed or budget to explore a different run.

Rule under test: every order costs at most 40 cents.

Choose a seed, then find a failing order. All work stays in this browser.

What actually runs ​

The website executes the tested scenario recipe using createScenario, scenarioArbitrary, checkFixtureProperty and replayFixtureProperty. The same recipe is compiled and tested against clean package tarballs by pnpm test:examples.

The arbitrary produces one to six line prices between 1 and 100 cents. It makes at most 50 property checks before shrinking a failure. Each shrink rebuilds the customer, order and lines from the reduced prices. No requests leave the browser, and the demo runs a fixed recipe rather than arbitrary uploaded JavaScript.

The shrink result is the result of this search, not a guarantee of a globally smallest counterexample. A passing bounded run does not prove a rule correct. Replay checks the recipe, budget, provider and engine identities before reusing the recorded seed and shrink path. Changing the budget invalidates an old replay.

Use the same pattern in a test ​

ts
import * as fc from 'fast-check';
import { createScenario } from '@mimlet/core';
import { scenarioArbitrary, checkFixtureProperty } from '@mimlet/fast-check';

const identity = { fingerprint: 'basket/v1', provider: 'my-test@1' };
const cart = createScenario()
  .node('prices', [], () => [] as number[])
  .node('total', ['prices'], ({ prices }) => prices.reduce((sum, n) => sum + n, 0));
const baskets = scenarioArbitrary(
  fc.array(fc.integer({ min: 1, max: 100 }), { minLength: 1, maxLength: 10 }),
  (prices) => cart.override('prices', () => prices),
  { ...identity, seed: 42 }
);

// Deliberately false property: inspect its report without making the example fail CI.
export const report = checkFixtureProperty(baskets, (basket) => basket.total < 5, {
  identity,
  seed: 12345,
  numRuns: 100,
});
// Shrinking recomputes total from prices; the minimal counterexample is { prices: [5], total: 5 }.
// In a real test, use assertFixtureProperty so a failed property fails the test.

Continue with correlated scenarios, sessions and replay, or the fast-check reference.

Mimlet · alpha · MIT licensed