testing - 如何使用 Jest 在 Next 中测试 _document
问题描述
我试图在一个项目中实现 100% 的覆盖率,这是我无法测试的唯一文件,因为我不知道如何去做。
我什至不知道从哪里开始。
我正在使用 Jest 和 React 测试库。该项目使用 NextJS。
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
ps:我知道覆盖率不是最重要的,但对于这个项目来说,100% 是必要的。
解决方案
通常使用 NextJS,我们需要测试 2 个案例,Initial/Server Props 部分和 React 组件部分。你的只有getInitialProps
. 测试可能因配置而异。我将为未来的读者发布这两种情况的配置和测试,并希望它可以成为至少涵盖大部分内容的坚实基础。
文件 pages/_document.js
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '@material-ui/core/styles';
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Lato"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
MyDocument.getInitialProps = async ctx => {
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
文件 __tests__/pages/_document.js
在发布测试文件之前,非常重要的事情是存根上下文,ctx
并MyDocument.getInitialProps = async ctx => {
模拟ctx.renderPage
将在文档代码中备份并调用的内容。此调用的结果是另一个函数,也需要在 other 中调用以达到该部分的最大覆盖率。要获得使用什么的提示,您可以简单地在文档中记录 ctx 并查看该函数的外观。存根和模拟可以是这样的:
const ctx = {
renderPage: (options = {}) => {
// for coverage, call enhanceApp and App
if (typeof options.enhanceApp === 'function') {
// pass a functional component as parameter
const app = options.enhanceApp(() => <div>App Rendered</div>);
app();
}
return {
html: <div>App Rendered</div>,
head: (
<head>
<title>App Title</title>
</head>
),
};
},
};
这是完整的测试文件,它也处理浅渲染:
import { createShallow } from '@material-ui/core/test-utils';
import MockProviders from '../../tests/MockProviders';
import MyDocument from '../../pages/_document';
/** @test {Document Component getInitialProps} */
describe('Document Component getInitialProps', () => {
const ctx = {
asPath: '/', // not necessary, but useful for testing _app.js
res: {
writeHead: jest.fn(),
end: jest.fn(),
}, // not necessary but useful for testing other files
renderPage: (options = {}) => {
// for coverage, call enhanceApp and App
console.log('options', options);
if (typeof options.enhanceApp === 'function') {
const app = options.enhanceApp(() => <div>App Rendered</div>);
console.log('app', app);
app();
}
return {
html: <div>App Rendered</div>,
head: (
<head>
<title>App Title</title>
</head>
),
};
},
};
it('should return finalize html, head and styles in getInitialProps', async () => {
const result = await MyDocument.getInitialProps(ctx);
// Log to see the structure for your assertion if any expectation
// console.log(result);
expect(result.html.props.children).toBe('App Rendered');
expect(result.head.props.children.props.children).toBe('App Title');
expect(result.styles[0].props.id).toBe('jss-server-side');
});
});
/** @test {Document Component} */
describe('Document Component', () => {
const shallow = createShallow();
const wrapper = shallow(
<MockProviders>
<MyDocument />
</MockProviders>
);
const comp = wrapper.find('MyDocument').dive();
// console.log(comp.debug());
it('should render Document components Html', () => {
expect(comp.find('Html')).toHaveLength(1);
expect(comp.find('Head')).toHaveLength(1);
expect(comp.find('body')).toHaveLength(1);
expect(comp.find('Main')).toHaveLength(1);
expect(comp.find('NextScript')).toHaveLength(1);
});
});
推荐阅读
- javascript - 重音字符 ` 会导致错误,并且何时被缩小
- ios - Flutter:swift编译器错误:无法在引用成员-Edit#2中推断上下文基础
- javascript - 如何使用 React 在 Next.js 中导出 const 值?
- applescript - 无法使用 Applescript 调整窗口大小
- pyspark - 在 Spark 数据帧中执行 MapReduce
- java - 在 javafx 项目中播放音乐的方法不会导致音乐播放
- python - 可以用什么代替嵌套循环来加速
- c# - C#嵌套类与没有多态性的子类之间的区别
- java - 谁能确定我在处理这个 API 请求时做错了什么?
- php - Laravel Nova:修改内容并删除图像时从磁盘中删除图像