在 _app 中模拟 Next.js getInitialProps

Mat*_*mas 2 server-side-rendering next.js cypress

我正在尝试找到一种方法来模拟Next.js's getInitialProps

我目前正在使用 cypress 运行 E2E 测试,但无法找到一种方法来模拟服务器端获取,而不需要启动模拟服务器来进行获取。我很好奇是否有人找到了更好的方法?

谢谢你!

Suc*_*UKR 14

从 NextJs 文档的此页面开始:NextJs - getInitialProps

很高兴知道:getInitialProps是一个遗留 API。我们建议使用getStaticPropsorgetServerSideProps代替。

我决定仅使用getServerSideProps- 希望这能转化为您特定的 SSR 方法。


之前的例子

Gleb Bahmutov 在Mock Network When using Next.js getServerSideProps Call上有一篇关于此问题的博客,但它是 Cypress v9 项目,并且存储库尚未更新到 Cypress 10+(这不是一个好兆头)。

无论如何,我尝试在 Cypress 12.17.0 中运行此存储库,但 NextJs 服务器不断重新启动 Cypress GUI(反之亦然),因此我猜测有关不在 Cypress 节点进程内启动服务器的警告是有效的。


使用 NextJs 自定义服务器

参考:NextJs 自定义服务器

自定义 Next.js 服务器允许您 100% 以编程方式启动服务器,以便使用自定义服务器模式

实际上我在GeeksForGeeks上使用过这个,但我认为你使用哪一个并不重要。

以 Gleb 的应用程序和规范为起点,我向global.fetch()应用程序getServerSideProps调用中使用的方法添加了一个简单的补丁。

步骤是

  • mocks.json使用您想要测试的模拟数据创建一个文件
  • 启动自定义服务器
  • 导航至localhost:3000检查应用程序是否已启动
  • 启动cypress open并运行规范

/服务器/服务器.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')
 })
})
Run Code Online (Sandbox Code Playgroud)

/服务器/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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

/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)
})
Run Code Online (Sandbox Code Playgroud)

结果

在此输入图像描述

删除实现模拟的 server.js 块

在此输入图像描述

局限性

您无法在 Cypress 测试中即时设置模拟数据,因为服务器在测试开始之前就已经运行。

可以通过cy.exec()启动和停止服务器来实现此目的,但我没有尝试过。

如果可以重新启动服务器,则mocks.json可以从测试内部进行更改,但我很高兴在静态文件中设置模拟,因为它降低了复杂性。