Next.js参加了开发课程,该课程使该图书馆过时采用了测试方法。下一页测试器维护者建议使用浏览器测试。
Next.js的缺少DOM集成测试工具
给定下一个库路由,此库将在JSDOM中渲染匹配页面,并提供从Next.js的路由系统和数据获取方法得出的预期道具。
import { getPage } from 'next-page-tester' ;
import { screen , fireEvent } from '@testing-library/react' ;
describe ( 'Blog page' , ( ) => {
it ( 'renders blog page' , async ( ) => {
const { render } = await getPage ( {
route : '/blog/1' ,
} ) ;
render ( ) ;
expect ( screen . getByText ( 'Blog' ) ) . toBeInTheDocument ( ) ;
fireEvent . click ( screen . getByText ( 'Link' ) ) ;
await screen . findByText ( 'Linked page' ) ;
} ) ;
} ) ; 该库背后的想法是尽可能地与接下来的方式相关。JS在不启动服务器的情况下工作,并在本地JSDOM环境中渲染输出。
为了提供有价值的测试经验next-page-tester复制了实际next.js应用程序:
head元素)安装的应用程序是交互式的,可以使用任何DOM测试库进行测试(例如@testing-library/react )。
next-page-tester将会照顾:
getServerSideProps , getInitialProps或getStaticProps )_app和_document组件包装页面Link , router.push , router.replace模拟客户端导航redirect返回next/router , next/head , next/link , next/config和环境变量 getPage接受选项对象并返回4个值:
import { getPage } from 'next-page-tester' ;
const { render , serverRender , serverRenderToString , page } = await getPage ( {
options ,
} ) ; type : () => { nextRoot: HTMLElement<NextRoot> }
返回: #__next next根元素。
除非您有高级用例,否则您应该主要使用此方法。在引擎盖下,它调用serverRender() ,然后将React应用程序安装/水合到JSDOM #__next root Element中。这是用户访问页面时会得到/看到的。
type : () => { nextRoot: HTMLElement<NextRoot> }
返回: #__next next根元素。
将服务器端的输出渲染到DOM中,但不会安装反应。使用它来测试下一步的方式。JS在以下情况下呈现:
type : () => { html: string }
将服务器端的输出渲染为HTML字符串。这是一种没有副作用的纯方法。
类型: React.ReactElement<AppElement>
应用程序的反应元素。
| 财产 | 描述 | 类型 | 默认 |
|---|---|---|---|
| 路线(强制性) | 下一个路线(必须以/开始) | string | - |
| req | 增强默认模拟请求对象 | req => req | - |
| res | 增强默认模拟的响应对象 | res => res | - |
| 路由器 | 增强默认模拟的下一个路由器对象 | router => router | - |
| useapp | 渲染自定义应用程序组件 | boolean | true |
| 渲染文档组件 | boolean | false | |
| Nextroot | 绝对通往Next的路径。JS根文件夹 | string | 自动检测到 |
| dotenvfile | .env文件保存环境变量的相对路径 | string | - |
| 包装纸 | 包装器文件的绝对路径。对于用模拟的提供商装饰组件树有用。 | string | - |
| 共享模型 | 应保留客户端和服务器上下文之间身份的模块列表。 | string[] | [] |
如果您的页面/组件导入文件类型不是Node.js本地处理的(例如样式表,图像, .svg ,...),则应配置测试环境以正确处理它们。例如,如果开玩笑,您可能想配置一些moduleNameMapper 。
next-page-tester希望遇到JSDOM环境。如果使用开玩笑将这一行添加到您的jest配置:
"testEnvironment" : "jsdom" ,由于Next.js并非旨在在JSDOM环境中运行,因此我们需要设置默认的JSDOM ,以允许更平稳的测试体验。默认情况下, next-page-tester将:
window.scrollTo和IntersectionObserver模拟但是,您可以选择通过将NPT_SKIP_AUTO_SETUP ENV变量设置为true来跳过自动清理和帮助者的初始化。您可以像这样cross-env做:
cross - env NPT_SKIP_AUTO_SETUP = true jest如果使用Jest V26,则可能需要修补它,以便使用适当的服务器/客户端环境加载模块。维护工作将针对最新的开玩笑版本。
在示例文件夹下,我们正在记录next-page-tester启用的测试案例。
next-page-tester只着眼于仅支持Next.js和Jest的最后一个版本:
| 下一页 - 塔斯特 | next.js | 笑话 |
|---|---|---|
| V0.1.0-> V0.7.0 | v9.xx | v26.xx |
| V0.8.0-> V0.22.0 | V10.0.0-> v10.0.7 | |
| V0.23.0-> v0.25.x | v10.0.8-> v11.0.x | |
| V0.26.0-> v0.27.x | v10.0.8-> v11.0.x | v27.xx |
| V0.28.0-> V0.28.x | V11.1.0 | |
| V0.29.0 + | v11.1.1-> v11.x | |
| V0.31.0 + | v12.1.0 | |
| V0.32.0 + | v12.1.1 + |
自从:
请注意,我们不能保证支持Next.js的未来版本的支持。即使是补丁或次要版本也可能会破坏。在这种情况下,您必须等待发布新的next-page-tester版。
贡献非常欢迎,我们会尽力支持外部贡献者。
req和res对象是用节点莫克斯-HTTP模拟的strict模式下使用TypeScript时,可能有必要安装@types/react-dom和@types/webpackuseDocument选项useDocument选项是部分实现的,可能是不稳定的。
模拟网络请求的第一种建议方法是与Mock service worker和Mirage JS等库在网络层进行模拟。
另一种可行的方法可能包括用诸如fetch-mock之类的库模拟全局fetch对象。
如果您想要一种更传统的方法,涉及嘲笑负责获取数据的用户陆地模块,则需要考虑一个额外的步骤:由于“客户端”和“服务器”渲染之间的next-page-tester隔离隔离了模块,因此在测试(客户端上下文)中创建的模拟(例如,在服务器上下文中都无法执行)(例如,数据获取方法)。
为了克服这一问题,我们需要通过通过sharedModules选项传递“客户端”和“服务器”上下文之间的“污染”此类模块以在“客户端”和“服务器”上下文之间的身份。
test ( 'as a user I want to mock a module in client & server environment' , async ( ) => {
const stub = jest . spyOn ( api , 'getData' ) . mockReturnValue ( Promise . resolve ( 'data' ) )
const { render } = await getPage ( {
route : '/page' ,
nextRoot ,
sharedModules : [ ` ${ process . cwd ( ) } /src/path/to/my/module` ] ,
} ) ;
expect ( stub ) . toHaveBeenCalledTimes ( 1 ) ; // this was executed in your data fetching method
}您可以通过将cookie附加到document.cookie来设置getPage 。 next-page-tester将将cookie传播到ctx.req.headers.cookie ,以便它们可用于数据获取方法。这也适用于随后的获取方法由客户端导航触发的调用。
test ( 'authenticated page' , async ( ) => {
document . cookie = 'SessionId=super=secret' ;
document . cookie = 'SomeOtherCookie=SomeOtherValue' ;
const { render } = await getPage ( {
route : '/authenticated' ,
} ) ;
render ( ) ;
} ) ;注意: document.cookie不会自动清理。每次测试后,您都必须手动清除它,以使所有内容保持孤立。
next.js Link组件调用window.scrollTo在单击时,该crollto在JSDOM环境中未实现。为了解决错误,您应该设置测试环境或提供自己的window.scrollTo 。
此警告意味着您的页面在服务器和浏览器之间呈现不同。这可以是预期的行为,也可以是您代码中的错误。
此警告意味着您在渲染过程中的应用程序执行了一些尚未嘲笑的网络请求。您应该找到它们并根据需要进行模拟。
trailingSlash选项_error页面debug选项来记录执行信息谢谢这些好人(表情符号钥匙):
安德里亚·卡拉罗(Andrea Carraro) ? | Matejšnuderl ? | 杰森·威廉姆斯 ? | Arelaxend ? | kfazinic ? | Tomasz Rondio ? | 亚历山大·门德斯(Alexander Mendes) |
Jan Sepke ? | Davidorchard ? | doaa ismael ? | 安德鲁·赫尔(Andrew Hurle) ? | Massimeddu-Sonic ? | 杰西·特尔福德(Jess Telford) ? | 约瑟夫 ? |
Gergo Tolnai ? | 布雷特 ? | 弗拉德·伊拉金 | 丹尼尔·斯托克曼(Daniel Stockman) | Madeuz | 德里克·奥斯丁博士 ? | feargal ? |
Jan R. Biasi ? | OtávioAugusto Soares ? |
该项目遵循全企业规范。欢迎任何形式的贡献!