如何在Jest测试DOM中渲染Module Federation远程组件?
如何在Jest+React Testing Library中实际渲染Module Federation组件进行测试
我正在为React.js应用编写Jest测试,使用React Testing Library。应用中导入了Module Federation组件,需要找到实际渲染这些联邦组件的测试方法,不能仅mock它们,因为需要验证测试DOM中的真实渲染结果。
我参考了Zack Jackson的《Federated Unit Tests?!》视频建议,但不知道如何在项目中落地实现。
我的测试代码
describe('DropDown Selector Tests', () => { test('Should render all passed-in dropdowns', () => { render(<DropDownContainer dropdowns={dropdowns} />); screen.debug(); // 打印DOM树 dropdowns.forEach((drop_down, index) => { const element = screen.getByTestId(`dropdown-select-${index}`); expect(document.body.contains(element)).toBe(true); const firtItem: DropdownSelectItemProps = drop_down.items[0] as DropdownSelectItemProps const firstLabelText: string = firtItem.label as string; const dropDown = screen.getByLabelText(firstLabelText); expect(document.body.contains(dropDown)).toBe(true); }); }); })
DropDownContainer容器组件
import React, { ReactElement } from 'react'; import { DropdownSelect, DropdownSelectProps } from 'federated/Components'; import './DropDownContainer.scss'; export interface DropDownContainerProps { /** 下拉列表集合 */ dropdowns: DropdownSelectProps[] } /** * 接收下拉列表集合,在响应式容器中组织展示 * @param props * @returns */ const DropDownContainer = (props: DropDownContainerProps) => { const { dropdowns } = props; return ( <div className='sort-container' data-testid='dropdown-container'> { dropdowns.map((d, index) => { return ( <div data-testid={`dropdown-select-${index}`} key={index} > <DropdownSelect key={index} className='sort' {...d} /> </div> ) }) } </div> ) } export default DropDownContainer;
测试渲染的DOM结果
<body> <div> <div class="sort-container" data-testid="dropdown-container" > <div data-testid="dropdown-select-0" /> <div data-testid="dropdown-select-1" /> <div data-testid="dropdown-select-2" /> <div data-testid="dropdown-select-3" /> </div> </div> </body>
可见DropdownSelect组件并未被渲染。正常渲染时,组件DOM应该如下:
预期正常渲染的DOM结构
<div class="sort-container"> <div id="sui-dropdown-select-0" class="sui-dropdown-select sort" aria-label="sui-dropdown-select-0"> Sale Type:<select style="display: none;"> <option id="Sale Type1" value="Sale Type1">Sale Type1</option> <option id="Sale Type2" value="Sale Type2">Sale Type2</option> </select> <div class="sui-dropdown-select-nice-select sui-dropdown-select-right"> <span class="sui-dropdown-select-current">Show All</span> </div> </div> <div id="sui-dropdown-select-1" class="sui-dropdown-select sort" aria-label="sui-dropdown-select-1"> Market:<select style="display: none;"> <option id="West" value="West">West</option> <option id="East" value="East">East</option> </select> </div>
Webpack配置
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const { FederatedTypesPlugin } = require('@module-federation/typescript'); const { ModuleFederationPlugin } = webpack.container; const federationConfig = require('./federationConfig'); const package = require('../package.json'); const { NativeFederationTestsHost, NativeFederationTestsRemote } = require('@module-federation/native-federation-tests/webpack'); // 根据开发/生产环境设置homepage const homepage = process.env.HOMEPAGE ?? `/${(package.homepage ?? '')}`.replace("//", "/"); module.exports = { experiments: { topLevelAwait: true }, entry: { main: path.join(__dirname, '../src/index.ts'), }, module: { rules: [ // 内联SVG资源 { test: /\.svg/, type: 'asset/inline' }, // 加载TypeScript文件 { test: /\.(js|jsx|tsx|ts)$/, loader: 'ts-loader', exclude: /node_modules/, }, ], }, plugins: [ new ModuleFederationPlugin(federationConfig), new FederatedTypesPlugin({ federationConfig, }), new HtmlWebpackPlugin({ template: 'public/index.html', title: 'internalbilling', filename: 'index.html', chunks: ['main'], publicPath: homepage, }), new NativeFederationTestsRemote({ federationConfig }), new NativeFederationTestsHost({ federationConfig }) ], resolve: { extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'], }, };
federationConfig配置
const dependencies = require('../package.json').dependencies; module.exports = { name: 'myapp'.toLowerCase(), remotes: { federated: `federated@https://media.CompanyA.com/cdn/js/CompanyAUI/remoteEntry.js` }, filename: 'remoteEntry.js', shared: { ...dependencies, 'react': { singleton: true, requiredVersion: dependencies['react'], }, 'react-dom': { singleton: true, requiredVersion: dependencies['react-dom'], }, }, };
package.json中的Jest配置
"jest": { "preset": "ts-jest", "clearMocks": true, "collectCoverage": true, "coverageDirectory": "coverage", "moduleDirectories": [ "node_modules", "@mf-types" ], "moduleFileExtensions": [ "js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node" ], "moduleNameMapper": { "^companyA/Components/(.*)$": "./@mf-types/companyA/Components.d.ts" }, "reporters": [ "default" ], "rootDir": "./ClientApp", "testEnvironment": "jsdom", "globals": { "transform": { "^.\\.scss$": "jest-scss-transform", "^.\\.[t|j]sx?$": "babel-jest" }, "verbose": true }, "transform": { "^.+\\.scss$": "jest-scss-transform", "^.+\\.tsx?$": "ts-jest" }, "setupFilesAfterEnv": [ "<rootDir>/configs/jest.setup.ts" ] }
已尝试的方法
- 使用mock,但不符合需求,因为需要验证联邦组件的实际渲染结果
- 尝试配置项目以渲染联邦组件,但未成功
内容的提问来源于stack exchange,提问作者Yulia
相关产品推荐
相关产品推荐

