03-property-testing
Effect-TS 4 property-based testing — Schema Arbitrary, fast-check, and generative test patterns
- License 许可
- MIT
- 最近更新
- 2026-05-31
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- 03-property-testing
- license
- MIT
- description
- Effect-TS 4 property-based testing — Schema Arbitrary, fast-check, and generative test patterns
- compatibility
- opencode
03 SKILL.md 正文
Property-Based Testing
Schema Arbitrary — generate test data from schemas
Effect Schema can derive fast-check arbitraries automatically.
import { Arbitrary, FastCheck, Schema } from "effect";
const User = Schema.Struct({
id: Schema.String,
age: Schema.Number.pipe(Schema.between(0, 120)),
active: Schema.Boolean,
});
const arb = Arbitrary.make(User);
FastCheck.assert(
FastCheck.property(arb, (user) => {
// property must hold for all generated users
expect(user.age).toBeGreaterThanOrEqual(0);
expect(user.age).toBeLessThanOrEqual(120);
}),
);
it.effect.prop — built-in property test runner
import { it } from "@effect/vitest";
import { Schema } from "effect";
it.effect.prop("encode then decode is identity", [Schema.String, Schema.Number], ([str, num]) =>
Effect.gen(function* () {
const pair = { str, num };
const encoded = yield* Schema.encode(MySchema)(pair);
const decoded = yield* Schema.decode(MySchema)(encoded);
assert.deepStrictEqual(decoded, pair);
}),
);
Plain fast-check in Vitest
import { FastCheck } from "effect";
import { test } from "vitest";
test("sort is idempotent", () => {
FastCheck.assert(
FastCheck.property(FastCheck.array(FastCheck.integer()), (arr) => {
const sorted = [...arr].sort();
expect([...sorted].sort()).toEqual(sorted);
}),
);
});
Custom arbitraries
import { Arbitrary, FastCheck } from "effect";
// Combine arbitraries
const nonEmptyString = FastCheck.string({ minLength: 1 });
const modelId = FastCheck.string({ minLength: 3 }).map((s) => `vendor/${s}`);
// Use with property test
FastCheck.assert(
FastCheck.property(modelId, (id) => {
expect(id).toContain("/");
}),
);
Schema constraints for tighter arbitraries
const BoundedAge = Schema.Number.pipe(Schema.int(), Schema.between(0, 120));
const NonEmptyTitle = Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200));
const Task = Schema.Struct({
id: Schema.String.pipe(Schema.brand("TaskId")),
title: NonEmptyTitle,
age: BoundedAge,
});
// Arbitrary respects all constraints
const arb = Arbitrary.make(Task);
Round-trip property (encode → decode)
A fundamental property for any Schema with a transformation:
test("Schema round-trip", () => {
FastCheck.assert(
FastCheck.property(Arbitrary.make(MySchema), (value) => {
const encoded = Schema.encodeSync(MySchema)(value);
const decoded = Schema.decodeSync(MySchema)(encoded);
expect(decoded).toEqual(value);
}),
);
});
04 同仓库更多 Skills
tmux-workflow
Development workflow with tmux — run dev servers, Storybook, and background processes in persistent sessions with live logs, while keeping OpenCode free for chat
04-anti-patterns
React anti-patterns to avoid — manual JSX repetition, useEffect misuse, reference instability, prop drilling, conditional hooks, and common performance traps
03-state-management
React state management patterns — lifting state, colocation, URL state, server state with TanStack Query, local state with useState/useReducer
02-component-composition
React component composition patterns — render props, compound components, list rendering with map, slot patterns, and layout primitives
01-fp-style
React functional programming style — pure components, hooks conventions, Effect Atom integration, and Tailwind patterns
react-animation
React animation with react/motion (Framer Motion) — declarative animations, gestures, layout animations, and performance best practices