如何对Next.js动态组件进行单元测试?
How to unit test Next.js dynamic components?
Next.js dynamic()
HOC 组件并不是很容易测试。我现在有 2 个问题;
- 第一个笑话未能正确编译动态导入(
require.resolveWeak is not a function
- 似乎由下一个 babel 插件添加)
- 其次,我无法很好地了解
modules
逻辑;看起来它根本不是 运行 在尝试呈现动态组件时。
如果您遇到 Next8 的第一个问题,您可以使用以下方法模拟动态导入:
jest.mock('next-server/dynamic', () => () => 'Dynamic');
参考:
https://github.com/zeit/next.js/issues/6187#issuecomment-467134205
假设我们有这样一个组件(使用动态导入):
import dynamic from 'next/dynamic';
const ReactSelectNoSSR = dynamic(() => import('../components/select'), {
loading: () => <Input />,
ssr: false
});
export default () => (
<>
<Header />
<ReactSelectNoSSR />
<Footer />
</>
);
Next.js 提供的动态导入支持没有 提供在 Jest 环境中预加载动态导入组件的方法。
但是,感谢 jest-next-dynamic,我们可以渲染完整的组件树而不是加载占位符。
您需要像这样将 babel-plugin-dynamic-import-node 添加到您的 .babelrc
。
{
"plugins": ["babel-plugin-dynamic-import-node"]
}
然后,您可以使用 preloadAll()
来渲染组件而不是加载占位符。
import preloadAll from 'jest-next-dynamic';
import ReactSelect from './select';
beforeAll(async () => {
await preloadAll();
});
您可以将以下内容添加到您的 Jest 设置中:setupTests.ts
jest.mock('next/dynamic', () => () => {
const DynamicComponent = () => null;
DynamicComponent.displayName = 'LoadableComponent';
DynamicComponent.preload = jest.fn();
return DynamicComponent;
});
虽然这是一个 hacky 解决方案,但我所做的只是通过提取导入路径并返回该导入来简单地模拟 next/dynamic
:
jest.mock('next/dynamic', () => ({
__esModule: true,
default: (...props) => {
const matchedPath = /(.)*(\'(.*)\')(.)*/.exec(props[0].toString());
if (matchedPath) return require(matchedPath[3]);
else return () => <></>;
},
}));
以下将加载所需的组件。
您也可以使用类似的方法预先加载所有组件。
jest.mock('next/dynamic', () => ({
__esModule: true,
default: (...props) => {
const dynamicModule = jest.requireActual('next/dynamic');
const dynamicActualComp = dynamicModule.default;
const RequiredComponent = dynamicActualComp(props[0]);
RequiredComponent.preload
? RequiredComponent.preload()
: RequiredComponent.render.preload();
return RequiredComponent;
},
}));
Next.js dynamic()
HOC 组件并不是很容易测试。我现在有 2 个问题;
- 第一个笑话未能正确编译动态导入(
require.resolveWeak is not a function
- 似乎由下一个 babel 插件添加) - 其次,我无法很好地了解
modules
逻辑;看起来它根本不是 运行 在尝试呈现动态组件时。
如果您遇到 Next8 的第一个问题,您可以使用以下方法模拟动态导入:
jest.mock('next-server/dynamic', () => () => 'Dynamic');
参考:
https://github.com/zeit/next.js/issues/6187#issuecomment-467134205
假设我们有这样一个组件(使用动态导入):
import dynamic from 'next/dynamic';
const ReactSelectNoSSR = dynamic(() => import('../components/select'), {
loading: () => <Input />,
ssr: false
});
export default () => (
<>
<Header />
<ReactSelectNoSSR />
<Footer />
</>
);
Next.js 提供的动态导入支持没有 提供在 Jest 环境中预加载动态导入组件的方法。 但是,感谢 jest-next-dynamic,我们可以渲染完整的组件树而不是加载占位符。
您需要像这样将 babel-plugin-dynamic-import-node 添加到您的 .babelrc
。
{
"plugins": ["babel-plugin-dynamic-import-node"]
}
然后,您可以使用 preloadAll()
来渲染组件而不是加载占位符。
import preloadAll from 'jest-next-dynamic';
import ReactSelect from './select';
beforeAll(async () => {
await preloadAll();
});
您可以将以下内容添加到您的 Jest 设置中:setupTests.ts
jest.mock('next/dynamic', () => () => {
const DynamicComponent = () => null;
DynamicComponent.displayName = 'LoadableComponent';
DynamicComponent.preload = jest.fn();
return DynamicComponent;
});
虽然这是一个 hacky 解决方案,但我所做的只是通过提取导入路径并返回该导入来简单地模拟 next/dynamic
:
jest.mock('next/dynamic', () => ({
__esModule: true,
default: (...props) => {
const matchedPath = /(.)*(\'(.*)\')(.)*/.exec(props[0].toString());
if (matchedPath) return require(matchedPath[3]);
else return () => <></>;
},
}));
以下将加载所需的组件。 您也可以使用类似的方法预先加载所有组件。
jest.mock('next/dynamic', () => ({
__esModule: true,
default: (...props) => {
const dynamicModule = jest.requireActual('next/dynamic');
const dynamicActualComp = dynamicModule.default;
const RequiredComponent = dynamicActualComp(props[0]);
RequiredComponent.preload
? RequiredComponent.preload()
: RequiredComponent.render.preload();
return RequiredComponent;
},
}));