@effect-firebase/mock

中文文档
1.0.1发布于 2026/10/08MITTypeScriptES Module构建来源已验证近 30 天下载 3108

记忆中,反应中 FirestoreService 实施测试和开发效应防火基地应用。 不需要Firebase连接 .

中文使用文档
文档目录11 节
  1. 安装
  2. 使用量
  3. 固定设备
  4. 模拟状态
  5. 从外部驱动后端
  6. 多个存储器
  7. 处理错误
  8. B. 个别方法
  9. NaN 字段值
  10. 限制
  11. 许可证

@ effect- firebase/ mock (英语)

记忆中,反应中 FirestoreService 实施测试和开发效应防火基地应用。 不需要Firebase连接 .

模拟器是一个小的模拟后端 用于 开发者经验数字 :

  • 固定设备 ——种子硬码模型通过您真正的计划,所以读取锻炼精确的解码路径生产数据.
  • 反应流 —— 说 streamDoc 编号 : streamQuery 正在直播:写作和运行时间切换将新的排放推入已订阅的溪流,就像 onSnapshot。 。 。 .
  • 模拟状态 ——翻转之间的任何收藏 data, (中文(简体) ), empty, (中文(简体) ), loading 财务报告和审定财务报表 error 运行时间 MockController,并注意您的 UI 旋转器,空出和出错路径渲染而不涉及后端 .
  • 延迟模拟 ——为每次行动增加人为延迟.
  • 写忠诚 ——服务器时间戳在写作时实现, delete编号 :arrayUnion编号 :arrayRemove编号 :increment 哨兵受到尊重,询问(在哪里、命令By、光标、限制、收集组)在进程中得到评价.

安装

npm install --save-dev @effect-firebase/mock

使用量

提供 layer 替换真正的管理员或客户端层:

import { Effect, Option } from 'effect';
import { layer as mockFirestore } from '@effect-firebase/mock';

await Effect.runPromise(
  Effect.gen(function* () {
    const repo = yield* PostRepository;

    const postId = yield* repo.add({
      title: 'Test',
      content: '...',
      status: 'draft',
    });
    const post = yield* repo.getById(postId);
    expect(Option.getOrThrow(post).title).toBe('Test');
  }).pipe(Effect.provide(mockFirestore())),
);

以 Firestore.makeRepository 仅需要的效果 FirestoreService,所以提供模拟层一次覆盖所有它们。 每个 Effect.provide(layer()) 呼叫得到一个新鲜的内存存储,所以测试默认是孤立的.

固定设备

用硬码模型来种子后端. 文件通过模型的图案编码,所以 getById, (中文(简体) ), query 和流解码 完全像真实数据:

import { fixture, layer } from '@effect-firebase/mock';
import { DateTime } from 'effect';

const posts = fixture(PostModel, {
  collectionPath: 'posts',
  idField: 'id',
  docs: [
    new PostModel({
      id: PostId.make('1'),
      title: 'Hello world',
      content: '...',
      createdAt: DateTime.makeUnsafe('2024-01-01'),
      // ...
    }),
  ],
});

const mock = layer({ fixtures: [posts] });

对于没有模型设计的文档,请使用 rawFixture 已编码数据 :

import { rawFixture } from '@effect-firebase/mock';

const settings = rawFixture('settings', {
  general: { theme: 'dark' },
});

要填入一页的音量(长列表,平面图,排版压力),则要填入一个数组上的地图—— fixture 使用任意 ReadonlyArray 模型类型:

const manyPosts = fixture(PostModel, {
  collectionPath: 'posts',
  idField: 'id',
  docs: Array.from({ length: 50 }, (_, i) => makePost(i)),
});

模拟状态

该层还提供了 MockController 在运行时驱动后端的服务—— 从测试、 dev 面板或 devtools 插件:

import { layer, MockController, MockState } from '@effect-firebase/mock';

Effect.gen(function* () {
  const controller = yield* MockController;

  // Live streams re-emit immediately:
  yield* controller.setState('posts', 'empty');
  yield* controller.setState('posts', 'loading'); // reads hang, streams go silent
  yield* controller.setState('posts', 'error'); // reads/writes fail: code 'unavailable'
  yield* controller.setState('posts', MockState.error('permission-denied'));
  yield* controller.setState('posts', 'data'); // back to normal

  // Apply to every collection at once:
  yield* controller.setState(MockState.All, 'loading');

  // Other controls:
  yield* controller.clearState('posts'); // drop a per-collection override
  yield* controller.setLatency('300 millis');
  yield* controller.seed(morePosts);
  yield* controller.setDoc('posts/raw', { title: 'Raw' }); // bypasses states and latency
  yield* controller.removeDoc('posts/raw');
  yield* controller.reset;

  // Inspect:
  const states = yield* controller.states;
  const docs = yield* controller.docs; // all docs keyed by full path
  // controller.changes is a Stream<StoreSnapshot> of every store change
});

MockState 还出口 data, (中文(简体) ), empty 财务报告和审定财务报表 loading 常数; MockState.error 使用 Firestore 错误代码或全码 FirestoreError. 传递给 layer编号 :make 财务报告和审定财务报表 controller.seed 必须使用不需要额外编码服务的模型.

国家也可以设立在以下前线:

const mock = layer({
  fixtures: [posts],
  states: { comments: 'loading' },
  latency: '200 millis',
});

收藏组查询( E)queryGroup 编号 : streamQueryGroup,或一个 存储器 group 视图)通过收藏ID解决状态,所以 states: { comments: 'loading' } 覆盖两个顶层 comments 收藏和目录 comments 每个家长的组合。 就像在Firestore一样, (单位:千美元) __name__ 光标( r)Query.orderByDocumentId在分组查询中必须是 完整文档路径 (e)posts/p1/comments/c1); 空ID失败 invalid-argument和真正的SDK一样 单一收集查询 拿个身份证明.

从外部驱动后端

make() 返回一个控点,而不只是一层:与 layer(),加直接访问控制器作为纯值。 每个控制器效果都不需要服务, 因此 React 组件、 故事书装饰器或测试助手可以使用 Effect.runPromise 直接说 这就是 @effect-firebase/devtools 面板基于:

import { Effect } from 'effect';
import { Atom } from 'effect/reactivity';
import { make } from '@effect-firebase/mock';

const mock = make({ fixtures: [posts] });

// Provide mock.layer to your app runtime (all provides share one store)...
const runtime = Atom.runtime(mock.layer);

// ...and drive the same store from anywhere:
await Effect.runPromise(mock.controller.setState('posts', 'loading'));

关于语义的说明:

  • empty 影响只读; 写仍然停留在商店中.
  • loading 暂停读取 财务报告和审定财务报表 写作,而活的溪流停止了排放。 在装入状态翻转前, 流已订阅 .
  • error 每个呼叫都失效 一个活流失败 最终 (比对) onSnapshot 语义学)——消费者必须在状态恢复后重新订阅,例如通过刷新拥有溪流的原子/平流.

多个存储器

为每个收藏提供一个带有固定装置的模拟层;每个寄存器都从同一商店读取:

const program = Effect.gen(function* () {
  const posts = yield* PostRepository;
  const users = yield* UserRepository;
  // ...
}).pipe(Effect.provide(layer({ fixtures: [posts, users] })));

处理错误

缺少的文件是 Option.none()不是失败 使用 error 状态以运行失败路径 :

await Effect.runPromise(
  Effect.gen(function* () {
    const controller = yield* MockController;
    yield* controller.setState('posts', 'error');
    const repo = yield* PostRepository;
    return yield* repo.query(Query.limit(10));
  }).pipe(
    Effect.provide(layer()),
    Effect.catchTag('FirestoreError', (e) => Effect.succeed(e.code)), // 'unavailable'
  ),
);

B. 个别方法

对于一个简单的测试双倍 没有内幕商店, MockFirestoreService(overrides) 返回 a FirestoreService 层由您通过的方法所构建; 任何您删除的方法在调用时都会丢出“ 未执行的” .

NaN 字段值

消防仓库和正规化 NaN,该模型沿用其语义:

  • 订购 —— 说 NaN 顺序如下: -Infinity这样 orderBy 列出第一个升起和最后一个降起. Timestamp 财务报告和审定财务报表 GeoPoint 子字段对其数组使用相同的规则.
  • 平等 (单位:千美元)==, (中文(简体) ), !=(b) —— NaN 仅等于 NaN。此驱动器也 arrayUnion 编号 : arrayRemove 脱出,所以存储 NaN 既不能吸收,也不能被有限价值所吸收.
  • 范围过滤器 (单位:千美元)<, (中文(简体) ), <=, (中文(简体) ), >, (中文(简体) ), >=)——a NaN 字段值完全从区域扫描中排除,即使下面有排序 -Infinity 页:1 orderBy。 。 。 .
  • in - 从不匹配 NaN 字段值,即使带有 NaN 候选( 不同于 == NaN,该匹配).
  • not-in - 总是包括 NaN 字段值,不论候选名单.
  • 生活流 —— 说 streamDoc 编号 : streamQuery 检测a NaN- 作为实际变化向数字过渡(存储) NaN 和重犯,而不加以毁灭 NaN- 等同一切比较.

限制

  • 只有记忆——重启进程之间没有持久性
  • 查询在进程中得到评价——行为可能与边缘案例的真火炉不同(复合指数要求没有执行, not-in编号 :!= 单语义简化,a NaN 查询 操作 例如 where('v', '<', NaN) 不被验证——真实的Firstore拒绝使用 invalid-argument,模拟返回空/有序结果;仅 NaN 字段值语义被模拟)
  • 模拟状态在每个收集路径(或 '*' 通配符),不是每个查询;收藏组查询通过收藏ID解决其状态
  • 没有安保规则评价
  • withTransaction 财务报告和审定财务报表 withBatch 直接运行效果——不重复、不回滚和不进行舞台写作
  • 没有多客户同步

对于需要完整Firestore语义的测试,请使用 Firebase 模拟器套件。 。 。 .

许可证

麻省理工学院

版本与发布记录

@effect-firebase/mock 共发布 40 个版本,首次发布于 2025/10/10;过去 12 个月发布了 39 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.1latest2026/10/081 个月前
1.0.02026/10/051 个月前
1.0.0-beta.9beta2026/09/231 个月前
1.0.0-beta.82026/09/211 个月前
1.0.0-beta.72026/09/141 个月前
1.0.0-beta.62026/09/112 个月前

关于 @effect-firebase/mock 的常见问题

@effect-firebase/mock 是什么?

记忆中,反应中 FirestoreService 实施测试和开发效应防火基地应用。 不需要Firebase连接 .

如何安装 @effect-firebase/mock?

在项目目录运行 npm install @effect-firebase/mock,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:effect(^4.0.0)、effect-firebase(1.0.1)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@effect-firebase/mock 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@effect-firebase/mock 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@effect-firebase/mock 可以商用吗?

@effect-firebase/mock 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@effect-firebase/mock 的下载量有多少?

根据 npm 官方下载统计,@effect-firebase/mock 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,108 次,日均约 104 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@effect-firebase/mock 还在维护吗?

最新版本 1.0.1 发布于 2026/10/08(1 个月前);至今共发布 40 个版本,其中过去 12 个月发布了 39 个;首次发布于 2025/10/10。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。