我正在尝试找到一种方法来嘲笑
Next.js
的 getInitialProps
。
我目前正在使用 Cypress 运行 e2e 测试,但我找不到一种方法来模拟服务器端获取,而不需要启动模拟服务器来进行获取。我很好奇是否有人找到了更好的方法?
从 NextJs 文档的这一页开始:NextJs - getInitialProps
很高兴知道:
是一个旧版 API。我们建议使用getInitialProps
或getStaticProps
代替。getServerSideProps
我决定仅使用
getServerSideProps
- 希望这能转化为您特定的 SSR 方法。
之前的例子
Gleb Bahmutov 在此处有一篇关于此问题的博客使用 Next.js getServerSideProps 调用时模拟网络,但它是 Cypress v9 项目,并且存储库尚未更新到 Cypress 10+(这不是一个好兆头)。
无论如何,我尝试在 Cypress 12.17.0 中运行此存储库,但 NextJs 服务器不断重新启动 Cypress GUI(反之亦然),因此我猜测有关不在 Cypress 节点进程内启动服务器的警告是有效的。
使用 NextJs 自定义服务器
自定义 Next.js 服务器允许您以 100% 编程方式启动服务器,以便使用 自定义服务器模式。
实际上我用的是GeeksForGeeks上的那个,但我认为你使用哪一个并不重要。
以 Gleb 的应用程序和规范为起点,我向应用程序的
global.fetch()
调用中使用的 getServerSideProps
方法添加了一个简单的补丁。
步骤是
mocks.json
文件localhost:3000
检查应用程序是否已启动cypress open
并运行规范/服务器/server.js
使用
/node ./server/server.js
在终端中运行或添加 package.json
脚本。
const next = require('next')
const http = require('http')
const mocks = require('./mocks.json')
const app = next({dev: process.env.NODE_ENV !== 'production'})
/* Cypress mocking for getServerSideProps */
const originalFetch = global.fetch
global.fetch = (url) => {
const mock = mocks[url]
if (mock) {
return new Response(JSON.stringify(mock.body), {status: mock.status})
} else {
return originalFetch(url)
}
}
/* "standard" NextJs custom server */
app.prepare().then(() => {
const server = http.createServer((req, res) => {
console.log('req.url', req.url)
// Handle API routes
if (req.url.startsWith('/api')) {
// Your API handling logic here
} else {
// Handle Next.js routes
return app.getRequestHandler()(req, res)
}
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
/server/mocks.json
{
"https://icanhazdadjoke.com/": { // exact match to URL called in the app
"statusCode": 200,
"body": {
"id": "NmbFtH69hFd",
"joke": "Our wedding was so beautiful, even the cake was in tiers",
"status": 200
}
}
}
/cypress/e2e/spec.cy.js
const mocks = require('../../server/mocks.json')
it('getServerSideProps returns mock', () => {
cy.visit('http://localhost:3000')
cy.get('[data-cy="joke"]')
.should('have.text', mocks['https://icanhazdadjoke.com/'].body.joke)
})
结果
删除实现模拟的 server.js 块
限制
您无法在 Cypress 测试中动态设置模拟数据,因为服务器在测试开始之前就已经运行了。
也许可以使用
cy.exec()
来启动和停止服务器,但我没有尝试过。
如果可以重新启动服务器,则可以从测试内部更改
mocks.json
,但我很高兴在静态文件中设置模拟,因为它降低了复杂性。