重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
javascript-testing-expert by dubzzz/fast-check
npx skills add https://github.com/dubzzz/fast-check --skill javascript-testing-expert⚠️ 范围: 测试函数和组件,而非黑盒端到端测试。
🏅 主要目标: 将测试作为一种手段来...
🔧 推荐工具: vitest、fast-check、@fast-check/vitest、@testing-library/*、@vitest/browser-playwright、msw 作为开发依赖安装。
✅ 要 尝试安装缺失且相关的工具,仅针对 @fast-check/vitest 和浏览器测试进行推荐。
✅ 要 强烈建议用户安装缺失且相关的工具。
适应缺失的工具。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
✅ 要 在添加新测试时模仿项目中现有的测试结构
✅ 要 每个代码文件对应一个测试文件
👍 优先 使用 .spec.ts 扩展名(例如,fileName.ts → fileName.spec.ts),并且如果不存在现有测试结构,则与源文件放在一起
✅ 要 在使用 it 时,将 it 放在 describe 内部
👍 优先 使用 it 而非 test
✅ 要 用被测试函数的名称命名 describe
✅ 要 为每个被测试的函数使用一个专用的 describe
✅ 要 以 "should" 开头命名 it,并考虑名称应清晰、尽可能简洁,并且可以作为一个隐含前缀为 "it" 的句子来阅读
✅ 要 从简单且具有文档功能的测试开始
✅ 要 继续进行寻找边界情况的高级测试
❌ 不要 明确划分简单测试和高级测试,只需按正确顺序放置它们
✅ 要 将特定于文件的辅助函数放在所有 describe 之后,紧接在注释 // Helpers 下方,该注释表明为此文件定制的辅助函数的开始
✅ 要 遵循 AAA 模式并在测试中使其可见
it('should...', () => {
// 准备
code;
// 执行
code;
// 断言
code;
});
✅ 要 保持测试专注,尝试断言一个精确的方面
✅ 要 保持测试简单
👎 避免 在测试或其辅助函数中使用复杂逻辑
❌ 不要 测试内部细节
👍 优先 使用存根而非模拟,前者提供替代实现,后者有助于断言调用是否发生
为什么?通常,断言调用次数对函数用户来说并不关键,而纯粹是内部细节
❌ 不要 依赖网络调用,使用 msw 进行存根
✅ 要 在任何 it 使用模拟、间谍或修改全局变量的情况下,在 beforeEach 中重置全局变量和模拟
或者,在使用 vitest 时,您可以检查配置中是否启用了标志 mockReset、unstubEnvs 和 unstubGlobals,在这种情况下,默认会重置全局变量
👍 优先 为类似文档的测试使用真实数据
例如:如果需要构建用户实例,请使用真实姓名
❌ 不要 过度使用快照测试;仅在“快照中预期看到的内容”清晰时才进行快照
为什么?快照测试倾向于在快照中捕获过多细节,使得未来阅读者难以理解实际测试内容,从而难以更新
👍 优先 在形状和结构重要时使用快照(组件层次结构、属性、输出结构的非回归)
👍 优先 在最终渲染重要时使用截图(视觉样式、布局)
✅ 要 当被测试代码需要过多参数和/或过多模拟/存根来构建时(超过 10 个),警告开发者
为什么?难以测试的代码通常是一种代码异味,表明 API 需要更改。代码更难演进、更难推理,并且通常承担了太多职责。推荐单一职责原则(SRP)
✅ 要 尝试通过将重复逻辑提取到辅助函数中,使测试更短、阅读更快
✅ 要 将共享逻辑分组到具有清晰明确名称的函数下,为这些辅助函数遵循 SRP
例如:避免具有许多可选参数、执行多项操作的函数
❌ 不要 编写一个大型的 prepare 函数,供所有测试在其执行部分重用,而是使名称更清晰,并最终将其拆分为多个函数
✅ 要 确保如果去掉本应使测试通过的部分,你的测试会失败
例如:当你的测试说“当 Y 时应该做 X”时,确保如果没有 Y,它会在保留之前失败。
👎 避免 编写包含在未使用字段上指定硬编码值的实体的测试
测试内容示例
const user: User = {
name: 'Paul', // 未使用
birthday: '2010-02-03',
};
const age = computeAge(user);
//...
👍 优先 如果已安装,则利用 @fast-check/vitest
import { describe } from 'vitest';
import { it, fc } from '@fast-check/vitest';
describe('computeAge', () => {
it('应该计算出一个正数年龄', ({ g }) => {
// 准备
const user: User = {
name: g(fc.string), // 未使用
birthday: '2010-02-03',
};
// 执行
const age = computeAge(user);
// 断言
expect(age).toBeGreaterThan(0);
});
});
👍 优先 如果已安装 fast-check 但未安装 @fast-check/vitest,则利用 fast-check
👎 避免 编写依赖于不稳定值的测试
例如:在上面的示例中,computeAge 依赖于当前日期
备注:对于区域设置和许多其他平台相关值也是如此
👍 优先 使用 vi.setSystemTime 存根今天日期
👍 优先 使用 @fast-check/vitest 控制今天日期
为什么?与单独使用 vi.setSystemTime 不同,你会在每次运行时针对一个新的今天日期检查代码,但如果某一天它恰好失败,你将收到导致问题的确切日期的报告
// 准备
vi.setSystemTime(g(fc.date, { min: new Date('2010-02-04'), noInvalidDate: true }));
const user: User = {
name: g(fc.string), // 未使用
birthday: '2010-02-03',
};
👎 避免 编写依赖于随机值或实体的测试
👍 优先 如果已安装 @fast-check/vitest,则依赖它来控制随机生成的值,否则依赖 fast-check
✅ 要 对任何具有“总是”或“从不”概念的测试使用基于属性的测试
例如:名称为“当 Y 时应该总是做 X”或“当 Y 时应该从不做 X”
备注:将这些测试视为高级测试,并将它们放在文档测试之后,而不是与它们一起
👍 优先 使用基于属性的测试来检测边界情况,而不是逐一编写所有情况
❌ 不要 尝试使用基于属性的测试来测试 100% 的算法情况。为什么?基于属性的测试和基于示例的测试是互补的。基于属性的测试在发现边界情况和验证一般属性方面非常出色,而基于示例的测试提供了清晰的文档并涵盖了特定的重要场景。将两种方法结合使用以实现全面的测试覆盖。
// 对于所有字符串 a, b, c
// b 是 a + b + c 的子字符串
it.prop([fc.string(), fc.string(), fc.string()])('应该检测到子字符串', (a, b, c) => {
// 准备
const text = a + b + c;
const pattern = b;
// 执行
const result = isSubstring(text, pattern);
// 断言
expect(result).toBe(true);
});
✅ 要 将复杂逻辑从组件中提取到专用的、可测试的函数中
❌ 不要 测试零复杂度的琐碎组件逻辑
👍 优先 在使用 testing-library 时测试 DOM 结构和用户交互
👍 优先 在使用浏览器测试时测试视觉显示和用户交互
👍 优先 在 testing-library 和浏览器测试中,尽可能依赖 getByRole、getByLabelText、getByText 而不是 getByTestId 来通过可访问属性和用户可见文本进行查询
✅ 要 通过利用浏览器中的截图测试(如果可用)来确保设计系统组件以及更广泛的视觉组件的非视觉回归
✅ 要 如果无法运行截图测试,则回退到捕获 DOM 结构的快照测试
本节所有内容都假设我们处于基于属性的测试环境中!
⚠️ 重要: 当使用 @fast-check/vitest 中的 g 时,将任意函数(例如 fc.string、fc.date)及其参数作为单独的参数传递给 g,而不是调用它的结果。
正确:g(fc.string)、g(fc.date, { min: new Date('2010-01-01') })
错误:g(fc.string())、g(fc.date({ min: new Date('2010-01-01') }))
❌ 不要 直接生成输入
风险在于你可能最终在测试中重写被测试的代码
✅ 要 构造值来构建一些你知道预期结果的输入
❌ 不要 详细地期望返回值,在许多情况下,你将没有足够的细节来断言完整的值
✅ 要 期望返回值的某些方面和特征
❌ 绝对不要 在任意值上指定任何 maxLength,除非它是算法的要求
👍 优先 如果你觉得算法在大型输入上会花费很长时间,则指定 size: '-1'(默认情况下 fast-check 最多生成 10 个项目,因此仅在明确需要时使用 size)
例如:除非是字符串要求,否则不要使用 fc.string({maxLength: 5}) 或 fc.array(arb, {maxLength: 8})
❌ 绝对不要 在任意值上指定任何约束,除非是该任意值的要求,尽可能使用默认值
例如:如果算法应该接受任何整数,只需请求一个整数而不指定任何最小值和最大值
👎 避免 过度使用 .filter 和 fc.pre
为什么?它们会通过丢弃一些生成的值来减慢值的生成速度
👍 优先 使用任意值提供的选项直接生成有效值
例如:使用 fc.string({ minLength: 2 }) 而不是 fc.string().filter(s => s.length >= 2)
例如:使用 fc.integer({ min: 1 }) 而不是 fc.integer().filter(n => n >= 1),或者使用 fc.nat() 而不是 fc.integer().filter(n => n >= 0)
👍 优先 当 map 技巧可以避免过滤时,使用 map 而不是 filter
例如:使用 fc.nat().map(n => n * 2) 表示偶数
例如:使用 fc.tuple(fc.string(), fc.string()).map(([start, end]) => start + 'A' + end) 表示总是包含 'A' 字符的字符串
👍 优先 在谓词中使用的整数计算有溢出风险时(例如:对生成的值运行 pow、multiply..),使用 bigint 类型而非 number 类型
一些经典的属性:
✅ 要 当算法接受异步函数作为输入时,编写检查竞态条件并处理执行顺序的测试——由 fast-check 自动处理
✅ 要 利用 fast-check 及其 fc.scheduler() 任意值来测试依赖于异步函数的异步代码
转换:
it('应该按调用顺序解析', async () => {
// 准备
const seenAnswers = [];
const call = vi.fn().mockImplementation((v) => Promise.resolve(v));
// 执行
const queued = queue(call);
await Promise.all([queued(1).then((v) => seenAnswers.push(v)), queued(2).then((v) => seenAnswers.push(v))]);
// 断言
expect(seenAnswers).toEqual([1, 2]);
});
转换为:
it('应该按调用顺序解析', async () => {
await fc.assert(
fc.asyncProperty(fc.scheduler(), async (s) => {
// 准备
const seenAnswers = [];
const call = vi.fn().mockImplementation((v) => Promise.resolve(v));
// 执行
const queued = queue(s.scheduleFunction(call));
await s.waitFor(
Promise.all([queued(1).then((v) => seenAnswers.push(v)), queued(2).then((v) => seenAnswers.push(v))]),
);
// 断言
expect(seenAnswers).toEqual([1, 2]);
}),
);
});
如果使用 faker 来伪造数据,我们建议通过利用以下代码片段将任何伪造数据生成与 fast-check 连接起来:
// 来源:https://fast-check.dev/blog/2024/07/18/integrating-faker-with-fast-check/
import { Faker, Randomizer, base } from '@faker-js/faker';
import fc from 'fast-check';
class FakerBuilder<TValue> extends fc.Arbitrary<TValue> {
constructor(private readonly generator: (faker: Faker) => TValue) {
super();
}
generate(mrng: fc.Random, biasFactor: number | undefined): fc.Value<TValue> {
const randomizer: Randomizer = {
next: (): number => mrng.nextDouble(),
seed: () => {}, // 无操作,不支持种子更新,甚至可以抛出错误
};
const customFaker = new Faker({ locale: base, randomizer });
return new fc.Value(this.generator(customFaker), undefined);
}
canShrinkWithoutContext(value: unknown): value is TValue {
return false;
}
shrink(value: TValue, context: unknown): fc.Stream<fc.Value<TValue>> {
return fc.Stream.nil();
}
}
function fakerToArb<TValue>(generator: (faker: Faker) => TValue): fc.Arbitrary<TValue> {
return new FakerBuilder(generator);
}
使用示例
fc.assert(
fc.property(
fakerToArb((faker) => faker.person.firstName),
fakerToArb((faker) => faker.person.lastName),
(firstName, lastName) => {
// 代码
},
),
);
fast-check 和 @fast-check/vitest 的等价性示例 1.
// 使用 @fast-check/vitest
import { it, fc } from '@fast-check/vitest';
it('...', ({ g }) => {
//...
});
// 使用 fast-check
import { it } from 'vitest';
import fc from 'fast-check';
it('...', () => {
fc.assert(
fc.property(fc.gen(), (g) => {
//...
}),
);
});
示例 2.
// 使用 @fast-check/vitest
import { it, fc } from '@fast-check/vitest';
it.prop([...arbitraries])('...', (...values) => {
//...
});
// 使用 fast-check
import { it } from 'vitest';
import fc from 'fast-check';
it('...', () => {
fc.assert(
fc.property(...arbitraries, (...values) => {
//...
}),
);
});
示例 3. 如果 it 或 it.prop 的谓词是异步的,当仅使用 fast-check 时,属性必须通过 asyncProperty 实例化,并且 assert 必须被等待。
// 使用 @fast-check/vitest
import { it, fc } from '@fast-check/vitest';
it.prop([...arbitraries])('...', async (...values) => {
//...
});
// 使用 fast-check
import { it } from 'vitest';
import fc from 'fast-check';
it('...', async () => {
await fc.assert(
fc.asyncProperty(...arbitraries, async (...values) => {
//...
}),
);
});
每周安装次数
63
仓库
GitHub 星标数
4.8K
首次出现
2026年2月1日
安全审计
安装于
github-copilot57
codex57
opencode56
amp56
kimi-cli55
gemini-cli55
⚠️ Scope: Testing functions and components, not black-box e2e.
🏅 Main objectives: use tests as a way to...
🔧 Recommended tooling: vitest, fast-check, @fast-check/vitest, @testing-library/*, @vitest/browser-playwright, msw installed as devDependencies.
✅ Do try to install missing and relevant tooling, only recommend for @fast-check/vitest and browser testing.
✅ Do highly recommend user to install missing and relevant tooling.
✅ Do adapt yourself to missing tools.
✅ Do mimic the existing test structure of the project when adding new tests
✅ Do use one test file per code file
👍 Prefer using .spec.ts extension (e.g., fileName.ts → fileName.spec.ts) and colocated with the source file if no existing test structure is present
✅ Do put it within describe, when using it
👍 Prefer it over test
✅ Do name the describe with the name of the function being tested
✅ Do use a dedicated describe for each function being tested
✅ Do start naming it with "should" and considers that the name should be clear, as consise as possible and could be read as a sentence implicitly prefixed by "it"
✅ Do start with simple and documenting tests
✅ Do continue with advanced tests looking for edge-cases
❌ Don't delimitate explicitely simple from advanced tests, just but them in the right order
✅ Do put helper functions specific to the file after all the describes just below a comment // Helpers stating the beginning of the helpers tailored for this file
✅ Do follow the AAA pattern and make it visible in the test
it('should...', () => {
// Arrange
code;
// Act
code;
// Assert
code;
});
✅ Do keep tests focused, try to assert on one precise aspect
✅ Do keep tests simple
👎 Avoid complex logic in tests or its helpers
❌ Don't test internal details
👍 Prefer stubs over mocks, the first one provides an alternate implementation, the second one helps to assert on calls being done or not
Why? Often, asserting the number of calls is not something critical for the user of the function but purely an internal detail
❌ Don't rely on network call, stub it with msw
✅ Do reset globals and mocks in beforeEach if any it plays with mocks or spies or alter globals
Alternatively, when using vitest you could check if flags mockReset, unstubEnvs and unstubGlobals have been enabled in the configuration, in such case resetting globals is done by default
👍 Prefer realistic data for documentation-like tests
Eg.: use real names if you have to build instances of users
❌ Don't overuse snapshot tests; only snapshot things when the "what is expected to be seen in the snapshot" is clear
Why? Snapshots tests tend to capture too many details in the snapshot, making them hard to update given future reader is lost on what was the real thing being tested
👍 Prefer snapshots when shape and structure are important (component hierarchy, attributes, non-regression on output structure)
👍 Prefer screenshots when final render is important (visual styling, layout)
✅ Do warn developer when the code under tests requires too many parameters and/or too many mocks/stubs to be forged (more than 10)
Why? Code being hardly testable is often a code smell pinpointing an API having to be changed. Code is harder to evolve, harder to reason about and often handling too many responsibilities. Recommend the single-responsibility principle (SRP)
✅ Do try to make tests shorter and faster to read by factorizing recurrent logics into helper functions
✅ Do group shared logics under a function having a clear and explicit name, follow SRP for these helpers
Eg.: avoid functions with lots of optional parameters, doing several things
❌ Don't write a big prepare function re-used by all tests in their act part, but make the name clearer and eventually split it into multiple functions
✅ Do make sure your test breaks if you drop the thing supposed to make it pass
Eg.: When your test says "should do X when Y" makes sure that if you don't have Y it fails before keeping it.
👎 Avoid writing tests with entities specifying hardcoded values on unused fields
Example of test content
const user: User = {
name: 'Paul', // unused
birthday: '2010-02-03',
};
const age = computeAge(user);
//...
👍 Prefer leveraging @fast-check/vitest, if installed
import { describe } from 'vitest';
import { it, fc } from '@fast-check/vitest';
describe('computeAge', () => {
it('should compute a positive age', ({ g }) => {
// Arrange
const user: User = {
name: g(fc.string), // unused
birthday: '2010-02-03',
};
// Act
const age = computeAge(user);
// Assert
expect(age).toBeGreaterThan(0);
});
});
👍 Prefer leveraging fast-check, if installed but not @fast-check/vitest
👎 Avoid writing tests depending on unstable values
Eg.: in the example above computeAge depends on the current date
Remark: same for locales and plenty other platform dependent values
👍 Prefer stubbing today using vi.setSystemTime
👍 Prefer controlling today using @fast-check/vitest
Why? Contrary to vi.setSystemTime alone you check the code against one new today at each run, but if it happens to fail one day you will be reported with the exact date causing the problem
// Arrange
vi.setSystemTime(g(fc.date, { min: new Date('2010-02-04'), noInvalidDate: true }));
const user: User = {
name: g(fc.string), // unused
birthday: '2010-02-03',
};
👎 Avoid writing tests depending on random values or entities
👍 Prefer controlling randomly generated values by relying on @fast-check/vitest if installed, or fast-check otherwise
✅ Do use property based tests for any test with a notion of always or never
Eg.: name being "should always do x when y" or "should never do x when y"
Remark: consider these tests as advanced and put them after the documentation tests and not with them
👍 Prefer using property based testing for edge case detection instead of writing all cases one by one
❌ Don't try to test 100% of the algorithm cases using property-based testing Why? Property-based testing and example-based testing are complementary. Property-based tests are excellent for uncovering edge cases and validating general properties, while example-based tests provide clear documentation and cover specific important scenarios. Use both approaches together for comprehensive test coverage.
// for all a, b, c strings
// b is a substring of a + b + c
it.prop([fc.string(), fc.string(), fc.string()])('should detect the substring', (a, b, c) => {
// Arrange
const text = a + b + c;
const pattern = b;
// Act
const result = isSubstring(text, pattern);
// Assert
expect(result).toBe(true);
});
✅ Do extract complex logic from components into dedicated and testable functions
❌ Don't test trivial component logic that has zero complexity
👍 Prefer testing the DOM structure and user interactions when using testing-library
👍 Prefer testing the visual display and user interactions when using browser testing
👍 Prefer querying by accessible attributes and user-visible text by relying on getByRole, getByLabelText, getByText over getByTestId whenever possible for testing-library and browser testing
✅ Do ensure non visual regression of Design System components and more generally visual components by leveraging screenshot tests in browser when available
✅ Do fallback to snapshot tests capturing the DOM structure if screenshot tests cannot be ran
All this section considers that we are in the context of property based tests!
⚠️ Important: When using g from @fast-check/vitest, pass the arbitrary function (e.g., fc.string, fc.date) along with its arguments as separate parameters to g, not the result of calling it.
Correct: g(fc.string), g(fc.date, { min: new Date('2010-01-01') })
Incorrect: g(fc.string()), g(fc.date({ min: new Date('2010-01-01') }))
❌ Don't generate inputs directly
The risk being that you may end up rewriting the code being tested in the test
✅ Do construct values to build some inputs where you know the expected outcome
❌ Don't expect the returned value in details, in many cases you won't have enough details to be able to assert the full value
✅ Do expect some aspects and characteristics of the returned value
❌ NEVER specify any maxLength on an arbitrary if it is a not a requirement of the algorithm
👍 Prefer specifying a size: '-1' if you feel that the algorithm will take very long on large inputs (by default fast-check generates up to 10 items, so only use size when clearly required)
Eg.: No fc.string({maxLength: 5}) or fc.array(arb, {maxLength: 8}) except being a string requirement
❌ NEVER specify any constraint on an arbitrary if it is not a requirement of the arbitrary, use defaults as much as possible
Eg.: if the algorithm should accept any integer just ask an integer without specifying any min and max
👎 Avoid overusing .filter and fc.pre
Why? They slow down the generation of values by dropping some generated ones
👍 Prefer using options provided by arbitraries to directly generate valid values
Eg.: use fc.string({ minLength: 2 }) instead of fc.string().filter(s => s.length >= 2)
Eg.: use fc.integer({ min: 1 }) instead of fc.integer().filter(n => n >= 1), or use fc.nat() instead of fc.integer().filter(n => n >= 0)
👍 Prefer using map over filter when a map trick can avoid filtering
Eg.: use fc.nat().map(n => n * 2) for even numbers
Eg.: use fc.tuple(fc.string(), fc.string()).map(([start, end]) => start + 'A' + end) for strings always having an 'A' character
👍 Prefer bigint type over number type for integer computations used within predicates when there is a risk of overflow (eg.: when running pow, multiply.. on generated values)
Some classical properties:
✅ Do write tests checking for race conditions and playing with resolution order — automatically handled byfast-check — when an algorithm accepts asynchronous functions as input
✅ Do leverage fast-check and its fc.scheduler() arbitrary to test asynchronous code depending on asynchronous functions
Turn:
it('should resolve in call order', async () => {
// Arrange
const seenAnswers = [];
const call = vi.fn().mockImplementation((v) => Promise.resolve(v));
// Act
const queued = queue(call);
await Promise.all([queued(1).then((v) => seenAnswers.push(v)), queued(2).then((v) => seenAnswers.push(v))]);
// Assert
expect(seenAnswers).toEqual([1, 2]);
});
Into:
it('should resolve in call order', async () => {
await fc.assert(
fc.asyncProperty(fc.scheduler(), async (s) => {
// Arrange
const seenAnswers = [];
const call = vi.fn().mockImplementation((v) => Promise.resolve(v));
// Act
const queued = queue(s.scheduleFunction(call));
await s.waitFor(
Promise.all([queued(1).then((v) => seenAnswers.push(v)), queued(2).then((v) => seenAnswers.push(v))]),
);
// Assert
expect(seenAnswers).toEqual([1, 2]);
}),
);
});
If using faker to fake data, we recommend wiring any fake data generation within fast-check by leveraging this code snippet:
// Source: https://fast-check.dev/blog/2024/07/18/integrating-faker-with-fast-check/
import { Faker, Randomizer, base } from '@faker-js/faker';
import fc from 'fast-check';
class FakerBuilder<TValue> extends fc.Arbitrary<TValue> {
constructor(private readonly generator: (faker: Faker) => TValue) {
super();
}
generate(mrng: fc.Random, biasFactor: number | undefined): fc.Value<TValue> {
const randomizer: Randomizer = {
next: (): number => mrng.nextDouble(),
seed: () => {}, // no-op, no support for updates of the seed, could even throw
};
const customFaker = new Faker({ locale: base, randomizer });
return new fc.Value(this.generator(customFaker), undefined);
}
canShrinkWithoutContext(value: unknown): value is TValue {
return false;
}
shrink(value: TValue, context: unknown): fc.Stream<fc.Value<TValue>> {
return fc.Stream.nil();
}
}
function fakerToArb<TValue>(generator: (faker: Faker) => TValue): fc.Arbitrary<TValue> {
return new FakerBuilder(generator);
}
Example of usage
fc.assert(
fc.property(
fakerToArb((faker) => faker.person.firstName),
fakerToArb((faker) => faker.person.lastName),
(firstName, lastName) => {
// code
},
),
);
fast-check and @fast-check/vitestExample 1.
// with @fast-check/vitest
import { it, fc } from '@fast-check/vitest';
it('...', ({ g }) => {
//...
});
// with fast-check
import { it } from 'vitest';
import fc from 'fast-check';
it('...', () => {
fc.assert(
fc.property(fc.gen(), (g) => {
//...
}),
);
});
Example 2.
// with @fast-check/vitest
import { it, fc } from '@fast-check/vitest';
it.prop([...arbitraries])('...', (...values) => {
//...
});
// with fast-check
import { it } from 'vitest';
import fc from 'fast-check';
it('...', () => {
fc.assert(
fc.property(...arbitraries, (...values) => {
//...
}),
);
});
Example 3. If the predicate of it or it.prop is asynchronous, when using only fast-check the property has to be instantiated via asyncProperty and assert has to be awaited.
// with @fast-check/vitest
import { it, fc } from '@fast-check/vitest';
it.prop([...arbitraries])('...', async (...values) => {
//...
});
// with fast-check
import { it } from 'vitest';
import fc from 'fast-check';
it('...', async () => {
await fc.assert(
fc.asyncProperty(...arbitraries, async (...values) => {
//...
}),
);
});
Weekly Installs
63
Repository
GitHub Stars
4.8K
First Seen
Feb 1, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot57
codex57
opencode56
amp56
kimi-cli55
gemini-cli55
代码审查最佳实践指南:完整流程、安全与性能审查清单
12,400 周安装