# @equinor/fusion-framework-vitest-plugin-react-app 中文文档

规范地址：https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/

版本：2\.0\.5
npm 元数据更新时间：2026-11-12T10:05:57.272Z
中文译文更新时间：2026-11-13T23:11:46.069Z
软件包许可：ISC

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

原始 npm 页面：https://www.npmjs.com/package/%40equinor/fusion-framework-vitest-plugin-react-app
原文对照：https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/?lang=original
源码仓库：https://github.com/equinor/fusion-framework

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

- 包体积（解压后）：973 kB，52 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：11 个
- peer 依赖：rxjs ^7\.0\.0，vite ^8\.0\.0，react ^18\.0\.0 \|\| ^19\.0\.0，vitest ^5\.0\.0，react-dom ^18\.0\.0 \|\| ^19\.0\.0，playwright ^1\.0\.0，@types/react ^18\.0\.0 \|\| ^19\.0\.0，vitest-browser-react ^2\.3\.0，@vitest/browser-playwright ^5\.0\.0
- 首次发布：2026-08-16T13:57:26.759Z
- 最新版本发布：2026-11-12T10:05:57.060Z
- 近 30 天下载量：2965（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：34（近 12 个月 34 个）

## 中文简介

Vite插件解决应用程序的表征,配置,模块配置作为测试的虚拟模块.

## 安装

```sh
npm install @equinor/fusion-framework-vitest-plugin-react-app
```

也可以使用：`pnpm add @equinor/fusion-framework-vitest-plugin-react-app`、`yarn add @equinor/fusion-framework-vitest-plugin-react-app`、`bun add @equinor/fusion-framework-vitest-plugin-react-app`

## README

# @ equinor/ inform-framework-vitest-plugin- react-app (英语)

Vite 插件和 Vitest 帮助在真实中测试 Fusion Framework React 应用程序, 模拟支持的应用模块范围——相同 `FrameworkProvider` + 键 `ModuleProvider` 筑巢 `renderApp`编号 :`createComponent` 电线在生产,与真实 `event`编号 :`http`编号 :`msal` 模块 管道和只有网络边界是假的.

> **说明:** 要求数 `vitest-browser-react` (同类依赖)和Vitest's [浏览器模式](https://vitest.dev/guide/browser/) 为项目配置的——这些渲染 帮助者在真实浏览器中挂载真实组件, 而不是 `happy-dom`编号 :`jsdom`。 。 。 .

需要时使用此软件包 :

-   **将组件或钩子对准真实的应用模块** —— 说 `useAppModule`, (中文(简体) ), `useAccessToken`, (中文(简体) ), `useCurrentContext`, (中文(简体) ), `useCurrentBookmark`, (中文(简体) ), `useAppSetting`类似 钩子是真实的 而不是每次试验都用手拍.
-   **对照应用程序的表单、配置和模块配置器进行测试** 一样 解决管道 `ffc app build`编号 :`ffc app dev` 虚拟模块 `appTestVitePlugin`。 。 。 .
-   **通过测试文件共享种子固定默认值** —— 说 `testApp`页:1 `vitest` `test` 延长 与 `appEnv`编号 :`configureApp`编号 :`app`编号 :`render`编号 :`renderHook` 固定装置,而不是重复 每一个电话。 每一次测试仍然有新鲜感 `fusion`编号 :`app` 实例; 只有种子 默认是共享的,而不是在测试之间声明.
-   **假冒一个端点的 URL 而不丢失其它配置** —— 说 `mergeEnvConfig` 合并 `environment`编号 :`endpoints` 覆盖到一个 `AppEnv`是因为 `config`; 分布在以下的平面天体: `AppConfig` (既存储于私人田地后)默地放下一切.

## 安装

```sh
pnpm add -D vitest@^5 playwright @vitest/browser-playwright@^5 vitest-browser-react@^2.3.0 \
  @equinor/fusion-framework-vitest-plugin-react-app
pnpm exec playwright install chromium
```

React,React DOM,RxJS,和Vite是通常由app提供的同级依赖关系.

## 文档

| 任务 | 指南 |
| --- | --- |
| 理解软件包并选择主题 | [概览](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/overview.md) |
| 安装、配置和运行第一个应用测试 | [开始](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/getting-started.md) |
| 覆盖 Vitest 默认或解决非标准应用文件 | [配置](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/configuration.md) |
| 制作固定装置、明确制作选项和应用程序生命周期测试 | [高级用途](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/advanced.md) |
| 诊断设置、浏览器、应用分辨率和网络故障 | [解决问题](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/troubleshooting.md) |
| 种子认证、上下文、书签、地标、HTTP、分析、遥测 | [模块模拟](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/module-mocks.md) |
| 理解浏览器模式默认或选择另一个渲染器 | [为什么浏览器模式是默认的](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/why-browser-mode.md) |
| 移动已有的 `@testing-library/react`/jsdom 套房在这个软件包上 | [移动已存在的应用程序](https://npmcn.com/package/%40equinor/fusion-framework-vitest-plugin-react-app/docs/migrating-an-existing-app.md) |
| 在应用、框架、模块、 HTTP 和跑步测试之间选择 | [选择测试层](https://npmcn.com/package/framework/docs/testing-choosing-a-layer.md) |

## 概览

从应用模块范围读取的任何钩子或组件—— `useAppModule`, (中文(简体) ), `useAccessToken`, (中文(简体) ), `useCurrentContext`, (中文(简体) ), `useCurrentBookmark`, (中文(简体) ), `useAppSetting`,等等——或 从父框架通过 `useFramework`,需要运行在同一供应商的巢穴 `renderApp`编号 :`createComponent` 电线生产:a `FrameworkProvider` (家长融合) 实例) `ModuleProvider` (应用程序自己的模块).

`renderAppHook` 财务报告和审定财务报表 `renderAppComponent` 为你建造巢穴,使用 `mockFramework` (单位:千美元)`@equinor/fusion-framework/mock`和 `mockAppModules` (单位:千美元)`@equinor/fusion-framework-app/mock`(b) —— 页:1 **真实** `event`编号 :`http`编号 :`msal` 模块管道。 只请求种子中间软件的答案 被伪造; 没有匹配的中间软件的请求仍然到达真正的网络。 这意味着:

-   SAML 默认“ 测试用户” 中的标志配置为零 —— `useAccessToken`编号 :`useToken` 解决一个真正、结构上有效的(未签名的)JWT.
-   `event` 发送和聆听真实 `FrameworkEvent`编号.
-   任何对 HTTP 端点( 如 app 本身的表单、 设置) 的交谈都会被解答 由一个模拟客户端而不是一个真实的网络呼叫——见每个钩子自己的文件什么的 预接线与种子所需(例如通过) `enableBookmarkMock`, (中文(简体) ), `enableContextMock`, (中文(简体) ), `enableFeatureFlagMock`,或一个 `configurator.http.addMiddleware(...)` 路由器).

使用 `renderAppHook` 用于隔离的钩 `renderAppComponent` 当你需要断言时 输出(例如装入/error状态、DOM结构) `testApp` 或 `/test` 输入点 `test`编号 :`render` 当一个文件中的几个案例共享一个种子范围时.

## 入境点

-   **`@equinor/fusion-framework-vitest-plugin-react-app`** —— 说 `appTestVitePlugin`, (中文(简体) ), `renderAppComponent`, (中文(简体) ), `renderAppHook`, (中文(简体) ), `testApp`。没有针对应用程序的解决方案;您通过 `env`编号 :`configure` 你自己来.
-   **`@equinor/fusion-framework-vitest-plugin-react-app/test`** —— 说 `test`, (中文(简体) ), `render`。要求 `appTestVitePlugin` 登记在册 `vitest.config.ts`· ; `appEnv`编号 :`configureApp` 解决 自动从应用程序的显示器、配置和模块配置器中选择.
-   **`@equinor/fusion-framework-vitest-plugin-react-app/config`** —— 说 `defineProject`登记册 `appTestVitePlugin`无头的 Playwright/Chrimium, 包含测试文件, 以及懒惰的进口 在接受普通 Vitest 配置时进行热身操作 .

## 快开始

在您的应用程序中使用浏览器已准备好的项目配置 `vitest.config.ts`数字 :

```ts
import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';

export default defineProject();
```

然后使用预选种子 `test` 固定装置——无每一次试验 `appEnv`编号 :`configureApp` 线条 :

```tsx
import { expect } from 'vitest';
import { test } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
import { App } from '../App';

test('renders the app', async ({ render }) => {
  const screen = await render(<App />);
  await expect.element(screen.getByRole('heading')).toBeVisible();
});
```

或者,在平地上 `describe`编号 :`it` 文档, 等同 `render` 函数 :

```tsx
import { describe, expect, it } from 'vitest';
import { render } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
import { App } from '../App';

describe('App', () => {
  it('renders the app', async () => {
    const { getByRole } = await render(<App />);
    await expect.element(getByRole('heading')).toBeVisible();
  });
});
```

## 打开AppHook

将钩子放入真实的,模拟的应用模块范围.

**签署:**

```ts
function renderAppHook<Result, Props = undefined, TModules = unknown, TEnv extends AppEnv = AppEnv>(
  render: (initialProps?: Props) => Result,
  options?: {
    configure?: AppMockConfigureFn<TModules, TEnv>;
    env?: TEnv;
    fusion?: Fusion;
  } & Omit<RenderHookOptions<Props>, 'wrapper'>,
): Promise<RenderHookResult<Result, Props> & { fusion: { framework: Fusion; app: AppModulesInstance<TModules> } }>;
```

| 选项 | 说明 |
| --- | --- |
| `configure` | 回电转发到 `mockAppModules` 用于种子应用镜模块(书签、上下文、地物旗、msal等) |
| `env` | 应用程序环境( 明显); 默认为通用独立 `test-app` |
| `fusion` | 父合并实例; 默认为新鲜 `mockFramework` 正在使用此应用程序的自带设备 |

任何其他 `renderHook` 选项(例如). `initialProps`页:1 结果包含 常规 `renderHook` 返回值(`result`, (中文(简体) ), `rerender`, (中文(简体) ), `unmount`+) 加上 (中文(简体) ) `fusion` 一样 实例 : 被制取的钩子 —— 驱动模块时,钩子本身不会返回.

### 基本用途

```tsx
import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app';
import { useAccessToken } from '@equinor/fusion-framework-react-app/msal';

test('resolves an access token', async () => {
  const { result } = await renderAppHook(() => useAccessToken({ scopes: ['User.Read'] }));
  await vi.waitFor(() => expect(result.current.pending).toBe(false));
  expect(result.current.token).toBeDefined();
});
```

### 为指定的用户获取一个符号

当测试需要身份要求时, 配置 SAL 模拟器的符号源 默认 `Test User`。获得的令牌既成为访问令牌,又成为活动账户:

```tsx
import { createMockToken } from '@equinor/fusion-framework-module-msal/mock';
import { useAccessToken } from '@equinor/fusion-framework-react-app/msal';
import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app';

test('acquires a token for a named user', async () => {
  const { result, fusion } = await renderAppHook(
    () => useAccessToken({ scopes: ['User.Read'] }),
    {
      configure: (configurator) =>
        configurator.msal.setAcquireToken(({ clientId, scopes }) =>
          createMockToken({
            aud: clientId,
            scp: scopes.join(' '),
            name: 'Ada Lovelace',
            preferred_username: 'ada@equinor.com',
            oid: 'ada-lovelace',
          }),
        ),
    },
  );

  await vi.waitFor(() => expect(result.current.pending).toBe(false));
  expect(fusion.framework.modules.auth.account?.name).toBe('Ada Lovelace');
});
```

### 重用预建的父合并实例

构建 `fusion` 当测试需要预置父级模块时, 实例 (单位:千美元)`http`, (中文(简体) ), `context`, (中文(简体) ), `serviceDiscovery`)或通过多个渲染电话共享一个实例:

```tsx
import { mockFramework } from '@equinor/fusion-framework/mock';
import { enableAppManifestMock } from '@equinor/fusion-framework-app/mock';
import type { AppModule } from '@equinor/fusion-framework-module-app';
import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app';
import { useAccessToken, useCurrentAccount } from '@equinor/fusion-framework-react-app/msal';

const env = { manifest: { appKey: 'test-app', displayName: 'Test App', description: '', type: 'standalone' as const } };

test('shares one fusion instance across two renders', async () => {
  const fusion = await mockFramework<[AppModule]>((configurator) =>
    enableAppManifestMock(configurator, env),
  );

  const { result: a } = await renderAppHook(() => useAccessToken({ scopes: ['User.Read'] }), { fusion });
  const { result: b } = await renderAppHook(() => useCurrentAccount(), { fusion });
});
```

## 渲染组件

将一个组件在真实的、模拟的应用模块范围之内,与 `renderAppHook`。当您需要坚持输出而不是钩子时使用此选项 返回值——例如,具有自身装载/error状态的组件.

**签署:**

```ts
function renderAppComponent<TModules = unknown, TEnv extends AppEnv = AppEnv>(
  ui: ReactElement,
  options?: {
    configure?: AppMockConfigureFn<TModules, TEnv>;
    env?: TEnv;
    fusion?: Fusion;
  } & Omit<RenderOptions, 'wrapper'>,
): Promise<RenderResult & { fusion: { framework: Fusion; app: AppModulesInstance<TModules> } }>;
```

选项形状与 `renderAppHook`因为.. `configure`, (中文(简体) ), `env`, (中文(简体) ), `fusion` ——加任何其他 `vitest-browser-react` `render` 选项。 结果跟往常一样 `render` 返回值 (单位:千美元)`getByText`, (中文(简体) ), `container`, (中文(简体) ), `unmount`, ) 加上: `fusion` ——筑巢而非直接传播 输入结果,所以 `vitest-browser-react`自己返回的形状可以自由进化 永远 与之相会相会. `fusion.app` 相同的应用程序模块实例 读取通过 `useAppModule`编号 :`useAppModules`,以及 `fusion.framework` 是家长的融合 举个例子 直接通过模块 `fusion.app` 进行状态变化 初始渲染,无手摇 `mockAppModules`编号 :`ModuleProvider`数字 :

```tsx
import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
import type { ContextModule } from '@equinor/fusion-framework-module-context';
import { act } from 'react';
import { renderAppComponent } from '@equinor/fusion-framework-vitest-plugin-react-app';

test('reacts when the current context switches', async () => {
  const { getByText, fusion } = await renderAppComponent<[ContextModule]>(<App />, {
    configure: (configurator) =>
      enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA)),
  });

  await act(() => fusion.app.context.setCurrentContextByIdAsync(projectB.id));
  await expect.element(getByText(/project-b/)).toBeVisible();
});
```

### 示例: 主张加载和出错状态

```tsx
import { mockFramework } from '@equinor/fusion-framework/mock';
import { enableAppManifestMock } from '@equinor/fusion-framework-app/mock';
import type { AppManifest, AppModule } from '@equinor/fusion-framework-module-app';
import { renderAppComponent } from '@equinor/fusion-framework-vitest-plugin-react-app';
import { Apploader } from '@equinor/fusion-framework-react-app/apploader';

test('mounts the child app once its script loads', async () => {
  const manifest: AppManifest = {
    appKey: 'child-app',
    displayName: 'Child App',
    description: 'A child application',
    type: 'standalone',
    build: { version: '1.0.0', entryPoint: 'child-script.ts', assetPath: '' },
  };
  const fusion = await mockFramework<[AppModule]>((configurator) =>
    enableAppManifestMock(configurator, { manifest }, someFixturesUri),
  );

  const { container } = await renderAppComponent(<Apploader appKey="child-app" />, { fusion });

  // the loading state renders synchronously, before the script's dynamic import resolves
  expect(container.textContent).toContain('Loading child-app');
  await vi.waitFor(() => expect(container.textContent).toContain('mounted: child-app'));
});
```

## 测试App

`vitest`是因为 `test`,扩展为应用模块范围固定——替代 `renderAppComponent`编号 :`renderAppHook` 用于测试文件,其案件共用一个被嘲弄的范围: `appEnv`编号 :`configureApp` 成为套件级关切,每个文件(或 `describe` 块) `testApp.extend(...)`,而不是每个呼叫中重复的选项对象. `fusion`编号 :`app` 解决懒惰问题——这个测试只能去结构化 `app` 从来没有支付 渲染 任何东西,一个只有去结构 `render`编号 :`renderHook` 得到相同的被嘲弄的范围 自动接通.

```tsx
import { testApp } from '@equinor/fusion-framework-vitest-plugin-react-app';

testApp('resolves current context', async ({ app, render }) => {
  const screen = await render(<App />);
  expect(app.context).toBeDefined();
});
```

为每套套房中的测试播下一个模块:

```tsx
describe('with a seeded context module', () => {
  const test = testApp.extend(
    'configureApp',
    { injected: true },
    (): AppMockConfigureFn =>
      (configurator) =>
        enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA)),
  );

  test('starts on the seeded context', async ({ render }) => {
    const screen = await render(<App />);
    await expect.element(screen.getByText(projectA.title)).toBeVisible();
  });
});
```

## 应用测试VitePlugin

普通 Vite 插件 — Vitest 配置是 Vite 配置, 因此此插件直接在您自己注册 `vitest.config.ts`,不需要CLI命令。 它服务于申请表/配置 (解决的方式相同) `ffc app build`编号 :`ffc app dev` 和它自己的模块配置器 导出为虚拟模块,因此 `/test` 输入点 `test`编号 :`render` 不需要每次测试 `appEnv`编号 :`configureApp` 接线.

```ts
appTestVitePlugin({
  entrypoint?: string; // defaults to the resolved Vite/Vitest project root
  manifest?: string | AppManifestFn;
  config?: string | AppConfigFn;
  configure?: string; // defaults to the first of src/config.ts, src/config.tsx, src/config.js
});
```

`entrypoint`, (中文(简体) ), `manifest`,以及 `config` 被传送到同一清单/配置决议 `ffc app build`编号 :`ffc app dev` 使用量(从 `package.json`,合并为 a 当地 `app.manifest.ts` 如果有一个存在,加 `app.config.ts` )),为终点. `configure` 点 在应用程序的模块配置文件上——与 `manifest`编号 :`config`一定是真实的 在磁盘上的文件,因为它作为活程序代码再导出到测试捆绑中而不是 JSON-序列化数据. 明确要求 `manifest`编号 :`config`编号 :`configure` 文件没有 已存在抛出 `FileNotFoundError`;基于会话的浏览会无声地失败,回到 默认.

## 页:1

-   每一个助推器/助推器 `async` 总是 `await` 因为被嘲笑的应用模块 范围(应用显示,模块初始化)在第一次渲染前同步解决.
-   在默认集(书签、上下文、地物旗)之外种子一个模块需要自己的 模拟启用器通过 `configure` - 比如说. `enableBookmarkMock`, (中文(简体) ), `enableContextMock`, (中文(简体) ), `enableFeatureFlagMock` 从该模块自己的 `/mock` 潜行道.
-   `msal` 默认启用“ 测试用户” 的船舶—— 否 `configure` 需要,除非 测试关注特定账户或签约状态.
-   更喜欢这些帮手 而不是手摇 `mockFramework`, (中文(简体) ), `mockAppModules`, (中文(简体) ), `FrameworkProvider`, (中文(简体) ), 财务报告和审定财务报表 `ModuleProvider` 直接在每一个测试.

## 常见问题

### @equinor/fusion-framework-vitest-plugin-react-app 是什么？

Vite插件解决应用程序的表征,配置,模块配置作为测试的虚拟模块\.

### 如何安装 @equinor/fusion-framework-vitest-plugin-react-app？

在项目目录运行 npm install @equinor/fusion-framework-vitest-plugin-react-app，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：rxjs（^7\.0\.0）、vite（^8\.0\.0）、react（^18\.0\.0 \|\| ^19\.0\.0）、vitest（^5\.0\.0）、react-dom（^18\.0\.0 \|\| ^19\.0\.0）、playwright（^1\.0\.0）、@types/react（^18\.0\.0 \|\| ^19\.0\.0）、vitest-browser-react（^2\.3\.0）、@vitest/browser-playwright（^5\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @equinor/fusion-framework-vitest-plugin-react-app 支持 TypeScript 吗？

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

### @equinor/fusion-framework-vitest-plugin-react-app 支持 ESM 还是 CommonJS？

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

### @equinor/fusion-framework-vitest-plugin-react-app 可以商用吗？

@equinor/fusion-framework-vitest-plugin-react-app 使用 ISC 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @equinor/fusion-framework-vitest-plugin-react-app 的下载量有多少？

根据 npm 官方下载统计，@equinor/fusion-framework-vitest-plugin-react-app 在 2026/10/14 – 2026/11/12 这 30 天内被下载 2,965 次，日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @equinor/fusion-framework-vitest-plugin-react-app 还在维护吗？

最新版本 2\.0\.5 发布于 2026/11/12（1 天前）；至今共发布 34 个版本，其中过去 12 个月发布了 34 个；首次发布于 2026/08/16。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

