gpt4 book ai didi

testing - 如何使用 Jest 在 Next 中测试 _document

转载 作者:行者123 更新时间:2023-12-05 06:00:34 24 4
gpt4 key购买 nike

我正试图在一个项目中实现 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 Component 部分。你的只有 getInitialProps。测试可能因配置而异。我会为 future 的读者发布这两种情况的配置和测试,并希望它能成为至少涵盖大部分内容的坚实基础。

文件 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

在发布测试文件之前,一件非常重要的事情是 Stub 上下文,ctx in MyDocument.getInitialProps = async ctx => { 并模拟 ctx.renderPage 会在文档代码中备份并调用。此调用的结果是另一个函数,也需要在其他函数中调用该函数以达到该部分的最大覆盖率。要获得有关使用什么的提示,您可以简单地在文档中记录 ctx 并查看函数的外观。 stub 和模拟可以是这样的:

    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);
});
});

编辑 1--------我的 MockProviders 文件只是为了代码分解,而不是在每次测试时级联添加 Providers 组件,以后如果需要更改所有测试文件,如果您需要添加另一个 Provider,那么您只需要更改那个 MockProvider 文件。它是自嘲之王,因为您在测试时将自己的 props 注入(inject)其中,这与您可能注入(inject)到实际应用程序中的正常值不同。

    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;

因为我使用一个 Provider 来通过 React.useContext 管理状态,并为 MaterialUI 主题使用一个 Provider,然后我将它们添加到级联中,能够传递额外的 Prop ,并渲染子组件里面。

关于testing - 如何使用 Jest 在 Next 中测试 _document,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67629091/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com