Ang*_*ias 5 testing jestjs next.js
我试图在项目中实现 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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
ps:我知道覆盖率不是最重要的,但对于这个项目来说,100% 的覆盖率是必要的。
通常使用 NextJS,我们需要测试 2 个案例,初始/服务器 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(),
],
};
};
Run Code Online (Sandbox Code Playgroud)
文件 __tests__/pages/_document.js
在发布测试文件之前,非常重要的一件事是存根上下文,ctx并MyDocument.getInitialProps = async ctx => {模拟ctx.renderPage将在文档代码中备份和调用的内容。此调用的结果是另一个函数,也需要在其他函数中调用该函数才能达到该部分的最大覆盖范围。要获得有关使用内容的提示,您只需在文档中记录 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>
),
};
},
};
Run Code Online (Sandbox Code Playgroud)
这是完整的测试文件,它也处理浅渲染:
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);
});
});
Run Code Online (Sandbox Code Playgroud)
编辑1----- 我的MockProviders文件只是用于代码分解,而不是在每个测试中级联添加提供程序组件,然后如果您需要添加另一个提供程序来更改所有测试文件,那么您只需更改那一个 MockProvider 文件。它是一个嘲笑之王,因为你在测试时注入了自己的 props,这与你在实际应用程序中注入的正常值不同。
import { MuiThemeProvider } from '@material-ui/core/styles';
import { StateProvider } from '../src/states/store';
import theme from '../src/themes';
const MockProviders = props => {
return (
<StateProvider {...props}>
<MuiThemeProvider theme={theme}>{props.children}</MuiThemeProvider>
</StateProvider>
);
};
export default MockProviders;
Run Code Online (Sandbox Code Playgroud)
因为我使用 Provider 来管理状态,并使用React.useContextProvider 来管理 MaterialUI 主题,所以我将它们级联添加,能够传递额外的 props,并在内部渲染子组件。
| 归档时间: |
|
| 查看次数: |
3323 次 |
| 最近记录: |