Exploring Cypress component testing by intercepting getServerSideProps requests

I'm struggling to find a way to intercept the getServerSideProps when using cypress component testing.

After extensive research, I found some useful resources:

Link 1

Link 2

Link 3

Link 4

If you're interested, you can also check out this example repository: Example Repo

The objective is to achieve the following:

cypress/plugins/index.ts

const http = require('http');
const next = require('next');
const nock = require('nock');

// Start the Next.js server when Cypress starts
module.exports = async (on, config) => {
  const app = next({ dev: true });
  const handleNextRequests = app.getRequestHandler();
  await app.prepare();

  on('dev-server:start', async () => {
    const customServer = new http.Server(async (req, res) => {
      return handleNextRequests(req, res);
    });
    await new Promise<void>((resolve, reject) => {
      customServer.listen(3000, err => {
        if (err) {
          return reject(err);
        }
        console.log('> Ready on http://localhost:3000');
        resolve();
      });
    });

    return customServer;
  });

  on('task', {
    clearNock() {
      nock.restore();
      nock.clearAll();

      return null;
    },

    async nock({ hostname, method, path, statusCode, body }) {
      nock.activate();

      console.log({ hostname, method, path, statusCode, body });

      method = method.toLowerCase();
      nock(hostname)[method][path].reply(statusCode, body);

      return null;
    },
  });

  return config;
};

components/AddProperty/index.spec.ct.tsx

import { mount } from '@cypress/react';
import Component from './index';

beforeEach(() => {
  cy.task('clearNock');
});

it.only('queries the api', () => {
  cy.fixture('properties').then((properties: Property[]) => {
    cy.task('nock', {
      path: '/api/address?q=*',
      method: 'GET',
      statusCode: 200,
      body: {
        json: function () {
          return [{ id: '42', adressebetegnelse: 'Beverly Hills' } as Partial<Property>];
        },
      },
    });
    cy.intercept('GET', '/api/address?q=*', properties).as('getProperties');

    mount(<Component />);

    cy.contains('Beverly Hills');

    cy.get('input').type('Some address{enter}');

    cy.wait('@getProperties').its('response.statusCode').should('eq', 200);

    properties.forEach(property => {
      cy.contains(property.adressebetegnelse);
    });
  });
});

However, the tests won't run properly. Any insights or tips would be appreciated!

https://i.sstatic.net/KhC4q.jpg

Answer №1

You have created a component test that utilizes the mount() function to render and display the component. This test essentially functions as a standard React test, as mount() from '@cypress/react' is essentially a wrapper for react-testing-library.

It's important to note that in this case, you are testing React specifically, not Next.

Since your component does not explicitly call getServerSideProps, any efforts within the test or plugin will not actually test this functionality.


To get your test to work, I followed Gleb's example provided in the link you shared, substituted your application, and created an integration test that involves NextJS (and consequently calls getServerSideProps).

Here are the main changes I had to make:

  • Moved getServerSideProps to a page (I used Home page) since NextJS won't trigger it on a component.

  • Corrected the spelling (you originally had getServersideProps).

  • Added a return value to getServerSideProps.

  • Removed the cy.intercept, as the nock task handles the interception process.

Here is the test code:

it.only('queries the api', () => {

  cy.task('nock', {
    hostname: 'http://localhost:3000',
    method: 'GET',      
    path: '/api/address',
    statusCode: 200,
    body: {
      json: function () {
        return [{ id: '42', adressebetegnelse: 'Beverly Hills' }];
      },
    },
  });

  cy.visit('http://localhost:3000')
  cy.contains('Beverly Hills')       // this is what comes from ssrProps

In the plugins/index file, I updated the nock interceptor to:

nock(hostname)[method](path)
  .query(true)
  .reply((uri, requestBody) => {
    console.log('nock uri', uri)
    return [
      200,
      { id: '42', adressebetegnelse: 'Beverly Hills' }
    ]
  })

The use of query(true) allows acceptance of any query parameters. By using a callback with .reply(), it enables checking if the request has been captured through a console log statement.

This is the Home page responsible for fetching the ssrProps data:

import PropertyList from '../components/PropertyList/index.js'
import Link from 'next/link'

export default function Home(props) {

  return (
    <div>
      <h1>Portfolio</h1>
      <PropertyList />
      <Link href="/add">Add property</Link>

      <!-- outputting the ssrProps value here -->
      <div>{props.ssrProps.adressebetegnelse}</div>

    </div>
  )
}

export async function getServerSideProps(context) {

  const res = await fetch(`http://localhost:3000/api/address?q=strandvejen`)   
  const data = await res.json()

  return {    
    props: {
      ssrProps: data
    },
  }
}

In response to comments,

Is it difficult to transform integration testing SSR mock requests into component testing?

I still maintain that it's not feasible and goes against the purpose of each type of test. SSR involves the server, and to effectively test it, end-to-end testing is required - the names hint at their intended usage.

Component testing serves as an enhanced unit test - it carries out its own rendering while bypassing the server.

To incorporate SSR testing into a component test would necessitate expanding mount() in complex ways, resulting in additional code and potential errors. In my opinion, it's redundant when an e2e test can straightforwardly accomplish the same goal.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a Typescript interface for a sophisticated response fetched from a REST API

I'm currently struggling with how to manage the response from VSTS API in typescript. Is there a way to handle this interface effectively? export interface Fields { 'System.AreaPath': any; 'System.TeamProject': string; 'Sys ...

Utilize Next.js with Axios for making an HTTP request to a Laravel Lumen endpoint, then showcase the retrieved data within the Next.js

I currently have a Next.js application that utilizes Axios to make calls to Lumen endpoints. The Axios HTTP client functions are organized in a separate folder named services/index.tsx, with sample code as follows: export const register = async (payload: a ...

What is the best technique for verifying the existence of data in the database before making updates or additions with Angular's observables?

I am facing a straightforward issue that I need help with in terms of using observables effectively. My goal is to search my database for a specific property value, and if it exists, update it with new data. If it does not exist, then I want to add the new ...

The JSON.stringify method in TypeScript/JavaScript does not align with the json-String parameter or request body in a Java controller

Currently, I am utilizing jdk 1.8 and have a rest endpoint in my Java controller: @PostMapping("/filters") public ResponseEntity<StatsDTO> listWithFilter( @RequestBody(required = false) String filter ) { try { ............... } } A test sn ...

What could be causing my TSC to constantly crash whenever I try to utilize MUI props?

Currently in the process of converting a JavaScript project using Next.js and Material UI to TypeScript. This is a snippet of code from one of my components. Whenever I include Props as an intersection type along with MUI's BoxProps, the TypeScript c ...

What are the distinctions between generic and discriminated types?

Hi there, I've been thinking of an idea but I'm not sure how to implement it or if it's even possible. Is there a way to create a type SomeType where the first property can be any value from the set T, but the second property cannot be the ...

Production environment sees req.cookies NEXTJS Middleware as undefined

Here is my latest middleware implementation: export async function middleware(request: NextRequest) { const token = request.headers.get('token') console.log(token) if (!token || token == undefined) { return NextResponse.redirect(new URL('/lo ...

What could be causing the lack of re-rendering in children components using redux-form?

When the parent component sends data, the children components do not re-render automatically. Re-rendering only occurs when a key is pressed on an input element. SMART User values from the state are sent by the smart component. If we add console.log(this. ...

Guide to setting up an interface-only project (along with its dependent projects) on NPM

I'm encountering two problems with my TypeScript project. Imagine I have a interface-only TypeScript project called myproject-api. My plan is to implement the interfaces in two separate projects named myproject-impl1 and myroject-impl2. I am utilizin ...

Encountering the error message "express.default is not a function" while attempting to start the node server within a container

Whenever I try to start my node server in a remote container, I keep encountering an error stating "express.default is not a function." Can anyone help me figure this out? Here's the content of my main.ts file: import * as express from 'express& ...

On two separate computers, create-next-app is encountering the identical error message: "Router received an invalid href parameter."

Just tested this on 2 different computers and I'm getting the same errors every time I create a brand-new project with create-next-app. Didn't used to get this error before. What happened? https://i.stack.imgur.com/7wOqA.jpg ...

The component I created seems to be having trouble recognizing the Slickr CSS that was

I have included Sick carousel's CSS in the root component by importing it like this: import React from 'react' import PropTypes from 'prop-types' import { ThemeProvider } from 'styled-components' import { ...

The JSX.Element cannot be assigned to a parameter of type ForwardRefRenderFunction

I am facing an issue while trying to export a React component and encountering a TypeScript error that I cannot seem to resolve. Here is the code for the component: import React, { useEffect, MutableRefObject, forwardRef, RefObject } from 're ...

The image component in Next.js is not displaying images from Cloudinary

In a previous instance, the author attempted to incorporate a standard DOM img: cloudinary image doesn't show up The solution provided was to specify cloudName and publicId properties for the Image component - <Image cloudName="doqurzmbt" ...

How can you utilize Angular Signals in combination with HostBinding to dynamically update styles?

Within a component called app-test, the following code is present: @Input({ transform: booleanAttribute }) reverse: boolean = false; @HostBinding('style.flex-direction') direction: string = this.reverse ? 'column-reverse' : &ap ...

How to access a TypeScript global variable from outside an Angular controller?

In my main.ts file, there is a global variable named rowTag which is an array of Tag[] entities. Additionally, I have an angular controller named TagMeController.ts. Below is the constructor of TagMeController: constructor($scope, $rootScope) { ...

Updating the status to PUBLISHED upon adding a comment via GRAPHQL stage

I have developed a small blog website using Nextjs, GraphQL, and GraphCMS. Currently, the create comment feature is functional, but I need to manually set the status to PUBLISHED in the CMS after creating a comment. I want the comment to automatically be s ...

The Type {children: Element; } is distinct and does not share any properties with type IntrinsicAttributes

I am encountering an issue in my React application where I am unable to nest components within other components. The error is occurring in both the Header component and the Search component. Specifically, I am receiving the following error in the Header co ...

Using Node.js to inject dependencies into the app.js file

As I work on my node.js and typescript application, I followed the approach outlined in an article by Brian Love. You can find a sample code for the server.ts file below: import * as bodyParser from "body-parser"; import * as cookieParser from "cookie-par ...

When executing the project, the information fails to appear on the screen

I am new to angular and I have been trying to use the http module to fetch data from my backend. In my user.component.html file, I have the following code: <tr *ngFor="let item of transporter.liste"> <td>{{item.name}}</td> ...