【问题标题】:How do I intercept server-side api calls by cypress如何拦截 cypress 的服务器端 api 调用
【发布时间】:2021-07-16 08:36:13
【问题描述】:

我使用 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')
  })
})

我的帖子/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>

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

【问题讨论】:

    标签: nuxt.js cypress


    【解决方案1】:

    当您运行带有服务器端渲染的 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
        },
      })
    }
    

    测试

    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')
    

    cypress.json

    {
      "baseUrl": "http://localhost:3000",
      "env": {
        "api_url": "http://localhost:9000"
      }
    }
    

    注意

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

    另一种方法

    Control Next.js Server-Side Data During Cypress Tests

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

    您让生产 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
    })
    

    【讨论】:

    • 有效!现在我只需要扩展它以支持 HTTP 方法,谢谢!我能问一下你是怎么解决这个问题的吗?我在 Cypress 官方文档上找不到它
    • 从您的描述看来,start-server-and-test 似乎是要走的路,选择最简单的服务器(节点 http)似乎更容易将其包装在任务中 - 对于任何人来说,整个事情都不那么大惊小怪知道赛普拉斯。
    • interceptHydration函数引用的关键参数是什么?
    猜你喜欢
    • 2023-04-02
    • 2017-08-30
    • 2023-01-06
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    相关资源
    最近更新 更多