# @effect-firebase/mock 中文文档

规范地址：https://npmcn.com/package/%40effect-firebase/mock/

版本：1\.0\.1
npm 元数据更新时间：2026-10-08T13:55:30.155Z
中文译文更新时间：2026-11-13T19:17:01.934Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40effect-firebase/mock
原文对照：https://npmcn.com/package/%40effect-firebase/mock/?lang=original
项目主页：https://github.com/fwal/effect-firebase#readme
源码仓库：https://github.com/fwal/effect-firebase

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：77.6 kB，30 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：effect ^4\.0\.0，effect-firebase 1\.0\.1
- 首次发布：2025-10-10T08:39:43.766Z
- 最新版本发布：2026-10-08T13:55:29.745Z
- 近 30 天下载量：3108（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：40（近 12 个月 39 个）

## 中文简介

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

## 安装

```sh
npm install @effect-firebase/mock
```

也可以使用：`pnpm add @effect-firebase/mock`、`yarn add @effect-firebase/mock`、`bun add @effect-firebase/mock`

## README

# @ effect- firebase/ mock (英语)

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

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

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

## 安装

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

## 使用量

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

```typescript
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` 和流解码 完全像真实数据:

```typescript
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` 已编码数据 :

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

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

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

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

## 模拟状态

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

```typescript
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` 必须使用不需要额外编码服务的模型.

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

```typescript
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`](https://npmcn.com/package/%40effect-firebase/devtools) 面板基于:

```typescript
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` 语义学)——消费者必须在状态恢复后重新订阅,例如通过刷新拥有溪流的原子/平流.

## 多个存储器

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

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

## 处理错误

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

```typescript
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 模拟器套件](https://firebase.google.com/docs/emulator-suite)。 。 。 .

## 许可证

麻省理工学院

## 常见问题

### @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 和提交记录判断。

