如何拦截 cypress 的服务器端 api 调用

Eas*_*Lin 7 nuxt.js cypress

我使用 Nuxt.js 作为前端框架,使用 Laravel 作为 API 服务器,并使用 Cypress 编写一些 e2e 测试。我尝试使用cy.intercept减少 asyncData api 调用,但未能成功拦截 api 调用,我的测试规范如下所示:

const siteUrl = Cypress.env('site_url')
const apiUrl = Cypress.env('api_url')
describe('Post Test', () => {
  beforeEach(() => {
    cy.intercept('GET', `${apiUrl}/post`, {
      fixture: 'post.json',
    })
  })
  it('should render posts same as mock data', () => {
    cy.visit(`/post`)
    cy.contains('some posts from mock data')
  })
})

Run Code Online (Sandbox Code Playgroud)

我的 posts/index.vue 看起来像这样:

<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.description }}</p>
  </div>
</template>

<script>
  export default {
    async asyncData({ params, $http }) {
      const post = await $http.$get(`${apiUrl}/post`)
      return { post }
    }
  }
</script>
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,在 asyncData 挂钩中,Nuxt.js 仍会向 Laravel 发送实际请求,要求发布数据。我已经读过这个问题,但仍然想问是否有其他方法可以使用 Cypress 拦截来自服务器端的 api 调用?

Ric*_*sen 8

当您运行具有服务器端渲染的 Nuxt 应用程序时,asyncData()会在服务器上进行调用。

接收到的数据被添加到页面底部的“水合”功能,然后提供给赛普拉斯浏览器。所以cy.intercept()永远不会接电话。

处理它的一种方法是在测试期间模拟服务器,这可以在任务中完成

/cypress/plugins/index.js

let server;      // static reference to the mock server
                 // so we can close and re-assign on 2nd call

module.exports = (on, config) => {
  on('task', {
    mockServer({ interceptUrl, fixture }) {

      const fs = require('fs')
      const http = require('http')
      const { URL } = require('url')

      if (server) server.close();       // close any previous instance

      const url = new URL(interceptUrl)
      server = http.createServer((req, res) => {
        if (req.url === url.pathname) {
          const data = fs.readFileSync(`./cypress/fixtures/${fixture}`)
          res.end(data)
        } else {
          res.end()
        }
      })

      server.listen(url.port)
      console.log(`listening at port ${url.port}`)

      return null
    },
  })
}
Run Code Online (Sandbox Code Playgroud)

测试

const apiUrl = Cypress.env('api_url');   // e.g "http://localhost:9000"

cy.task('mockServer', { interceptUrl: `${apiUrl}/post`, fixture: 'post.json' })
cy.visit('/post')

// a different fixture
cy.task('mockServer', { interceptUrl: `${apiUrl}/post`, fixture: 'post2.json' })
cy.visit('/post')
Run Code Online (Sandbox Code Playgroud)

赛普拉斯.json

{
  "baseUrl": "http://localhost:3000",
  "env": {
    "api_url": "http://localhost:9000"
  }
}
Run Code Online (Sandbox Code Playgroud)

笔记

  • Nuxt 应用程序必须看到相同的内容apiUrl
  • 模拟服务器将始终是主机名:localhost

另一种方法

请参阅在 Cypress 测试期间控制 Next.js 服务器端数据

这个想法是在页面从服务器到达时拦截该页面并修改其水合功能。

您让生产 API 服务器保持运行状态以进行测试,以便 SSR 正常获取。

function interceptHydration( interceptUrl, fixture, key ) {
  cy.fixture(fixture).then(mockData => {
    cy.intercept(
      interceptUrl,
      (req) => {
        req.continue(res => {
          // look for "key" in page body, replace with fixture
          const regex = new RegExp(`${key}:\s*{([^}]*)}`)
          const mock = `${key}: ${JSON.stringify(mockData)}`
          res.body = res.body.replace(regex, mock)
        })
      }
    )
  })
}

it('changes hydration data', () => {
  interceptHydration( '/post', 'post', 'post' )
  cy.visit('/post')
  cy.get('h1').contains('post #2')   // value from fixture
})
Run Code Online (Sandbox Code Playgroud)