javascriptautomated-testscypresscypress-intercept

Intercepting a real data response


I have a problem with data stubbing in Cypress 6. I am trying to implement the exchange of real data from the server to custom data. I read the docs and came to the conclusion that

describe("test", () => {
    it("intercept", () => {
        cy.intercept("http://localhost:3000/spoons", (req) => {
            req.reply((res) => {
                let { body } = res;
                body.newProperty = "new";
                console.log(res.body);
                return body;
            });
        });
    });
});

will be the solution, however... body in networking for request http://localhost:3000/spoons returns to me

{
    "sizes": [
        "huge",
        "small"
    ],
    "colors": [
        "yello",
        "brown"
    ],
    "build": {
        "back": true,
        "front": true
    }
}

but in the console.log as it shows what res.body has, it gets an empty console.log as if it had nothing res.body in it.

Edit #1 About internal "server" I made just simple express server with a website which make fetch request to have easy another request in "Networking". It was made just as a battlefield to train intercept and other stuff. There is the only endpoint to this /spoons

server.js:

const express = require("express");
const app = express();
const port = 3000;
const path = require("path");

const obj = {
  sizes: ["huge", "small"],
  colors: ["yello", "brown"],
  build: {
    back: true,
    front: true,
  },
};

app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname + "/index.html"));
});

app.get("/spoons", (req, res) => {
  res.json(obj);
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body></body>
  <script>
    console.log(fetch("http://localhost:3000/spoons"));
  </script>
</html>

Solution

  • It works for intercepting external network requests,

    /// <reference types="@cypress/fiddle" />
    
    const test = {
      html: `
        <script>
          fetch('https://jsonplaceholder.typicode.com/todos/1')
        </script>
      `,
      test: `
      cy.intercept('https://jsonplaceholder.typicode.com/todos/1', req => {
        req.reply((res) => {
          let { body } = res;
          body.newProperty = "new";
          console.log(res.body);
          return body;
        });
      })
      `
    }
    it('test', () => {
      cy.runExample(test)
    })
    

    This logs

    {
      completed: false,
      id: 1,
      newProperty: "new",           // added by intercept
      title: "delectus aut autem",
      userId: 1
    }
    

    Can you explain the api server and client ports in more detail?


    I set up your server, and found it works ok.

    The only thing I changed was to add a no-store header to the server response (stops browser seeing status code '304').

    Without it every second refresh of the Cypress test cy.intercept() did not trigger. That may actually be fixable in the test by adding a full route matcher to cy.intercept() instead of just the url.

    app.use((req, res, next) => {
      res.set('Cache-Control', 'no-store')
      next()
    })
    
    app.get("/", (req, res) => {...
    

    I also modified the script in the app to console.log in .then(), otherwise you just get the promise object.

    <script>
      fetch('http://localhost:3000/spoons')
        .then(res => res.json())
        .then(res => console.log('app', res))
    </script>
    

    This is the spec I used.

    it('test', () => {
      cy.intercept('http://localhost:3000/spoons', req => {
        req.reply((res) => {
          let { body } = res;
          body.newProperty = "new";
          console.log('intercept', res.body);
          return body;
        });
      })
      cy.visit('../app/intercept-mod-response-local-server-2.html')
    })