@equinor/fusion-framework-vitest-plugin-react-app

中文文档
2.0.5发布于 2026/11/12ISCTypeScriptES Module近 30 天下载 2965

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

中文使用文档
文档目录14 节
  1. 安装
  2. 文档
  3. 概览
  4. 入境点
  5. 快开始
  6. 打开AppHook
  7. 基本用途
  8. 为指定的用户获取一个符号
  9. 重用预建的父合并实例
  10. 渲染组件
  11. 示例: 主张加载和出错状态
  12. 测试App
  13. 应用测试VitePlugin
  14. 页:1

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

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

说明: 要求数 vitest-browser-react (同类依赖)和Vitest's 浏览器模式 为项目配置的——这些渲染 帮助者在真实浏览器中挂载真实组件, 而不是 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 (既存储于私人田地后)默地放下一切.

安装

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提供的同级依赖关系.

文档

任务指南
理解软件包并选择主题概览
安装、配置和运行第一个应用测试开始
覆盖 Vitest 默认或解决非标准应用文件配置
制作固定装置、明确制作选项和应用程序生命周期测试高级用途
诊断设置、浏览器、应用分辨率和网络故障解决问题
种子认证、上下文、书签、地标、HTTP、分析、遥测模块模拟
理解浏览器模式默认或选择另一个渲染器为什么浏览器模式是默认的
移动已有的 @testing-library/react/jsdom 套房在这个软件包上移动已存在的应用程序
在应用、框架、模块、 HTTP 和跑步测试之间选择选择测试层

概览

从应用模块范围读取的任何钩子或组件—— 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数字 :

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

export default defineProject();

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

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 函数 :

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

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

签署:

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 一样 实例 : 被制取的钩子 —— 驱动模块时,钩子本身不会返回.

基本用途

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。获得的令牌既成为访问令牌,又成为活动账户:

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: '[email protected]',
            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)或通过多个渲染电话共享一个实例:

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状态的组件.

签署:

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数字 :

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();
});

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

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 得到相同的被嘲弄的范围 自动接通.

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();
});

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

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 接线.

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 共发布 34 个版本,首次发布于 2026/08/16;过去 12 个月发布了 34 个版本。

版本发布日期距今
2.0.5latest2026/11/121 天前
2.0.5-next.0next2026/11/112 天前
2.0.42026/11/112 天前
2.0.4-next.22026/10/2915 天前
2.0.4-next.12026/10/2816 天前
2.0.4-next.02026/10/2816 天前

其他发布通道:trusted-publishing-20261015 → 1.0.16-trusted-publishing-20261015-9dfe7602cd2a49a8a9df00d62c26e7304a82a85a,next → 2.0.5-next.0。

关于 @equinor/fusion-framework-vitest-plugin-react-app 的常见问题

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