Rstest

@module-federation/rstest 可在 Rstest 测试构建中启用 Module Federation。当测试需要加载真实的联邦远程模块,而不是通过 mock 替代联邦边界时,可以使用该插件。

支持范围

  • Rstest 的 Node 和 JSDOM 测试环境。
  • Rstest 浏览器模式。
  • URL 远程模块,例如 remote@http://localhost:3001/remoteEntry.js
  • 用于基于 Node 的集成测试的 commonjs ... 路径远程模块。
  • 自动为面向 Node 的测试构建启用 Rstest 联邦兼容模式。

版本要求

Tip

请使用 @rstest/core@0.11.4 或更高版本。Rstest 的联邦支持从 0.11.4 开始提供。

早于 0.11.4 的 Rstest 版本不包含该插件为 Node 测试构建启用的 federation 兼容模式。

快速开始

安装

npm
yarn
pnpm
bun
npm add @module-federation/rstest @rstest/core --save-dev

注册插件

rstest.config.ts
import { federation } from '@module-federation/rstest';
import { defineConfig } from '@rstest/core';

export default defineConfig({
  plugins: [
    federation({
      name: 'host',
      remotes: {
        'component-app': 'component_app@http://localhost:3001/remoteEntry.js',
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
      },
    }),
  ],
});
Warning

使用该插件时,请勿在 rstest.config.ts 中设置 federation: true。对于 Node 和 JSDOM 测试环境,@module-federation/rstest 会自动启用 Rstest 的联邦兼容模式。

像往常一样使用 Rstest 运行测试:

npx rstest run

复用 Rsbuild 联邦配置

如果测试项目已经注册了 @module-federation/rsbuild-plugin,调用 federation() 时无需传入任何选项:

rstest.config.ts
import {
  createModuleFederationConfig,
  pluginModuleFederation,
} from '@module-federation/rsbuild-plugin';
import { federation } from '@module-federation/rstest';
import { defineConfig } from '@rstest/core';

const options = createModuleFederationConfig({
  name: 'host',
  remotes: {
    'component-app': 'component_app@http://localhost:3001/remoteEntry.js',
  },
});

export default defineConfig({
  plugins: [
    pluginModuleFederation(options, {
      environment: 'rstest',
      target: 'node',
    }),
    federation(),
  ],
});

插件顺序很重要:请先注册 pluginModuleFederation,以便 federation() 能规范化同一组带类型的选项。这样只会创建一个 ModuleFederationPlugin,并避免重复配置远程模块。

测试联邦远程模块

在 Rstest 的 globalSetup 中构建或启动远程模块,然后像应用代码一样导入暴露的模块:

remote.test.ts
import { expect, it } from '@rstest/core';
import Button from 'component-app/Button';

it('loads a remote through a static import', () => {
  expect(Button).toBeDefined();
});

it('loads a remote through a dynamic import', async () => {
  const remote = await import('component-app/Button');
  expect(remote.default).toBeDefined();
});

官方的 Rstest 联邦示例组合了一个 HTTP 组件远程模块和一个本地构建的 commonjs ... 远程模块,并同时运行 Node 和 JSDOM 项目。

工作原理

对于 Node 和浏览器目标,dtsmanifestdev 的默认值都是 false;显式设置的值会被保留。

Node 测试默认配置

对于面向 Node 的 Rstest 构建,该插件会应用与 Node 运行时相匹配的 Module Federation 默认配置:

  • target: async-node
  • experiments.asyncStartup = true
  • CommonJS 容器输出;modulemodern-module 库类型会被规范化
  • @module-federation/node/runtimePlugin
  • 面向 Node 的联邦优化
  • 默认使用脚本远程传输方式

标准 URL 远程模块使用 remoteType: 'script'commonjs ... 等内联传输前缀会覆盖该默认值。

浏览器模式

Rstest 浏览器模式会根据解析后的 browser.enabled 配置自动检测:

请先安装 @rstest/browser 和 Playwright 浏览器。参阅 Rstest 浏览器模式设置

rstest.config.ts
import { federation } from '@module-federation/rstest';
import { defineConfig } from '@rstest/core';

export default defineConfig({
  browser: {
    enabled: true,
    provider: 'playwright',
  },
  plugins: [
    federation({
      name: 'browser_host',
      remotes: {
        app2: 'app2@http://localhost:3001/remoteEntry.js',
      },
    }),
  ],
});

浏览器模式在启用 experiments.asyncStartup 并应用上述共享默认配置时,会避免使用仅适用于 Node 的默认配置。只有在需要覆盖自动检测到的模式时,才显式传入 target

配置

federation(options, rstestOptions) 接受标准的 Module Federation 配置作为第一个参数。

federation(moduleFederationOptions, {
  target: 'node', // or 'browser'
});

moduleFederationOptions

Module Federation 配置项

rstestOptions

  • 类型:{ target?: 'node' | 'browser' }
  • 默认值:根据 Rstest 解析后的 browser.enabled 配置自动检测。浏览器模式默认为 'browser',其他构建默认为 'node'

生产者构建

请使用 @module-federation/rsbuild-plugin 或其他 Module Federation 构建插件来构建远程应用。@module-federation/rstest 仅用于消费这些远程模块的 Rstest 测试项目。

对于 Rsbuild 生产者,请继续参阅 Rsbuild 插件指南