nw-pbt-typescript

TypeScript/JavaScript property-based testing with fast-check framework and arbitraries

322 stars

Best use case

nw-pbt-typescript is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

TypeScript/JavaScript property-based testing with fast-check framework and arbitraries

Teams using nw-pbt-typescript should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/nw-pbt-typescript/SKILL.md --create-dirs "https://raw.githubusercontent.com/nWave-ai/nWave/main/nWave/skills/nw-pbt-typescript/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/nw-pbt-typescript/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How nw-pbt-typescript Compares

Feature / Agentnw-pbt-typescriptStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

TypeScript/JavaScript property-based testing with fast-check framework and arbitraries

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# PBT TypeScript -- fast-check

## Framework Selection

**fast-check** is the dominant PBT framework for TypeScript/JavaScript. No serious competitors.

- 8+ years mature, very actively maintained
- First-class TypeScript types
- Zero runtime dependencies
- Used by jest, jasmine, fp-ts, ramda, js-yaml

## Quick Start

```typescript
import fc from 'fast-check';

test('sort is idempotent', () => {
  fc.assert(
    fc.property(fc.array(fc.integer()), (arr) => {
      const sorted = [...arr].sort((a, b) => a - b);
      const twice = [...sorted].sort((a, b) => a - b);
      expect(sorted).toEqual(twice);
    }),
    { numRuns: 1000 }
  );
});
```

## Generator (Arbitrary) Cheat Sheet

### Primitives
```typescript
fc.integer()                          // any safe integer
fc.integer({ min: 0, max: 99 })
fc.nat()                              // non-negative integer
fc.float()
fc.double()
fc.string()
fc.string({ minLength: 1, maxLength: 50 })
fc.boolean()
fc.constant(null)
fc.constantFrom(1, 2, 3)             // pick from values
```

### Collections
```typescript
fc.array(fc.integer())
fc.array(fc.integer(), { minLength: 1, maxLength: 10 })
fc.set(fc.integer())
fc.dictionary(fc.string(), fc.integer())
fc.tuple(fc.integer(), fc.string())
```

### Combinators
```typescript
fc.oneof(fc.integer(), fc.string())   // union
fc.option(fc.integer())               // T | null

// Map
fc.integer().map(n => n * 2)          // even integers

// Filter
fc.integer().filter(n => n > 0)
// Prefer: fc.integer({ min: 1 })

// Chain (dependent generation)
fc.array(fc.integer(), { minLength: 1 }).chain(
  arr => fc.tuple(fc.constant(arr), fc.integer({ min: 0, max: arr.length - 1 }))
)

// Record
fc.record({
  name: fc.string({ minLength: 1 }),
  age: fc.integer({ min: 0, max: 150 }),
  active: fc.boolean(),
})

// Frequency (weighted)
fc.frequency(
  { weight: 80, arbitrary: fc.char() },
  { weight: 10, arbitrary: fc.constant(' ') },
  { weight: 1,  arbitrary: fc.constantFrom('.', '-') }
)
```

### Recursive
```typescript
const jsonArb = fc.letrec(tie => ({
  value: fc.oneof(
    fc.constant(null), fc.boolean(), fc.integer(), fc.string(),
    fc.array(tie('value')), fc.dictionary(fc.string(), tie('value'))
  ),
})).value;
```

## Stateful Testing (Model-Based)

```typescript
import fc from 'fast-check';

type Model = { items: Map<string, number> };

class PutCommand implements fc.Command<Model, MyStore> {
  constructor(readonly key: string, readonly value: number) {}
  check = (m: Readonly<Model>) => true;
  run(m: Model, r: MyStore): void {
    r.put(this.key, this.value);
    m.items.set(this.key, this.value);
  }
  toString = () => `put(${this.key}, ${this.value})`;
}

class GetCommand implements fc.Command<Model, MyStore> {
  constructor(readonly key: string) {}
  check(m: Readonly<Model>): boolean {
    return m.items.has(this.key);  // precondition
  }
  run(m: Model, r: MyStore): void {
    expect(r.get(this.key)).toBe(m.items.get(this.key));
  }
  toString = () => `get(${this.key})`;
}

const allCommands = [
  fc.tuple(fc.string(), fc.integer()).map(([k, v]) => new PutCommand(k, v)),
  fc.string().map(k => new GetCommand(k)),
];

test('store matches model', () => {
  fc.assert(
    fc.property(fc.commands(allCommands), (cmds) => {
      const setup = () => ({
        model: { items: new Map() },
        real: new MyStore(),
      });
      fc.modelRun(setup, cmds);
    })
  );
});
```

### Race Condition Testing

```typescript
fc.assert(
  fc.property(fc.scheduler(), fc.commands(allCommands), async (s, cmds) => {
    const setup = () => ({
      model: { items: new Map() },
      real: new MyStore(s),  // system must use scheduler for async ops
    });
    await fc.scheduledModelRun(setup, cmds);
  })
);
```

Scheduler controls promise resolution order, enabling deterministic exploration of async interleavings.

## Test Runner Integration

```typescript
// Jest -- works out of the box
// Vitest -- works out of the box

// With @fast-check/jest (enhanced integration)
import { test } from '@fast-check/jest';
test.prop([fc.integer(), fc.integer()])('commutative addition', (a, b) => {
  expect(a + b).toBe(b + a);
});

// With @fast-check/vitest
import { test } from '@fast-check/vitest';
test.prop([fc.string()])('string length non-negative', (s) => {
  expect(s.length).toBeGreaterThanOrEqual(0);
});

// Replay failing tests
fc.assert(
  fc.property(fc.integer(), (n) => { /* ... */ }),
  { seed: 1234567890, path: '4:1:0' }  // from failure output
);
```

## Unique Features

- **Race condition detection**: `fc.scheduler()` controls async interleaving -- unique outside Erlang
- **Replay**: Seed + path for deterministic reproduction
- **Bias mode**: Automatically tests edge cases (0, -1, MAX_INT, empty) more often
- **Verbose mode**: Shows all generated values and shrink steps
- **Integrated shrinking**: Automatic via shrink trees, composes with generators
- **Size parameter**: `{ size: '+1' }` controls generation complexity growth

Related Skills

nw-ux-web-patterns

322
from nWave-ai/nWave

Web UI design patterns for product owners. Load when designing web application interfaces, writing web-specific acceptance criteria, or evaluating responsive designs.

nw-ux-tui-patterns

322
from nWave-ai/nWave

Terminal UI and CLI design patterns for product owners. Load when designing command-line tools, interactive terminal applications, or writing CLI-specific acceptance criteria.

nw-ux-principles

322
from nWave-ai/nWave

Core UX principles for product owners. Load when evaluating interface designs, writing acceptance criteria with UX requirements, or reviewing wireframes and mockups.

nw-ux-emotional-design

322
from nWave-ai/nWave

Emotional design and delight patterns for product owners. Load when designing onboarding flows, empty states, first-run experiences, or evaluating the emotional quality of an interface.

nw-ux-desktop-patterns

322
from nWave-ai/nWave

Desktop application UI patterns for product owners. Load when designing native or cross-platform desktop applications, writing desktop-specific acceptance criteria, or evaluating panel layouts and keyboard workflows.

nw-user-story-mapping

322
from nWave-ai/nWave

User story mapping for backlog management and outcome-based prioritization. Load during Phase 2.5 (User Story Mapping) to produce story-map.md and prioritization.md.

nw-tr-review-criteria

322
from nWave-ai/nWave

Review dimensions and scoring for root cause analysis quality assessment

nw-tlaplus-verification

322
from nWave-ai/nWave

TLA+ formal verification for design correctness and PBT pipeline integration

nw-test-refactoring-catalog

322
from nWave-ai/nWave

Detailed refactoring mechanics with step-by-step procedures, and test code smell catalog with detection patterns and before/after examples

nw-test-organization-conventions

322
from nWave-ai/nWave

Test directory structure patterns by architecture style, language conventions, naming rules, and fixture placement. Decision tree for selecting test organization strategy.

nw-test-design-mandates

322
from nWave-ai/nWave

Four design mandates for acceptance tests - hexagonal boundary enforcement, business language abstraction, user journey completeness, walking skeleton strategy, and pure function extraction

nw-tdd-review-enforcement

322
from nWave-ai/nWave

Test design mandate enforcement, test budget validation, 5-phase TDD validation, and external validity checks for the software crafter reviewer