无法拦截 Cypress API 调用

Can't intercept Cypress API call



我一直坚持使用 Cypress 固定装置。无法使用 SSR 和导航路由拦截 XHR 请求。

cypress/integration/page.js:

const fetch = require("unfetch")

describe("/about", () => {
  beforeEach(() => {
    cy.visit("/", { // Visit home page to trigger SSR
      onBeforeLoad (win) {
        win.fetch = fetch // replace fetch with xhr implementation
      },
    })
  })

  it("Has a correct title", () => {
    cy.server()
    cy.fixture("about").then(about => { 
      // about object is correct here, like {title: "About+"}
      cy.route("GET", "http://localhost:8080/api/documents/url", about) // Not sure where .route should be
      cy.get(".main > :nth-child(1) > a").click() // Navigate to the /about page
      cy.route("GET", "http://localhost:8080/api/documents/url", about) // Tried both ways
      // This hits my server API without stubbing, getting {title: "About"}
      cy.title().should("eq", "About+") // About != About+
    })
  })
})

cypress/fixtures/about.json:

{"title": "About+"}

我在 Dev Tools 中看到一个 XHR 请求 (type=xhr),它没有使用上面的 about 存根对象,而是命中了真实的 API。为什么?仔细检查 URL 和方法——100% 相同。难道route耦合到visit而忽略了基于点击的路由?!

再次检查,我找到了解决办法。让我分享给大家感兴趣的细节:

1) 我使用 Next.js which is an excellent tool for SSR but it doesn't allow you to disable server-side rendering (yet) according to this and this 个问题。

2) 您可以将 Cypress 与 SSR 页面一起使用,但通过这种方式,您只能测试真实的 HTML。这意味着您必须将测试耦合到真实数据(在大多数情况下不好)或存根数据库本身(慢)。通常,您想存根 HTTP 请求。

3) Cypress 无法对 fetch 请求进行存根,并且使用基于 XHR 的实现模拟 fetch 比我想象的要棘手。

首先你需要:

// cypress/integration/your-test.js
Cypress.on('window:before:load', (win) => {
  delete win.fetch
})

然后:

// pages/your-page.js
Entry.getInitialProps = async function() {
  window.fetch = require("unfetch").default
  ...
} 

我尝试的删除和更新代码行的其他组合没有产生积极的结果。例如,当我在测试文件中有 window.fetch = 行时它不起作用并且 fetch.toString() 给出了 "native code"。不知道为什么,没有时间进一步探索。

Axios 解决了上述问题,但我不喜欢用额外的东西来膨胀我的包。您可以注入基于 XHR 的 fetch 仅用于测试。

4) 最重要的缺失部分。您需要等待路线。

it("Has a correct title", () => {
  cy.visit("/")
  cy.server()
  cy.route("GET", "http://localhost:8080/api/documents/url/about", {title: "About+"}).as("about")
  cy.get("[href='/about']").click()
  cy.wait("@about") // !!!
  cy.get("h1").contains("About+")
})