javascriptreactjsnext.jscypressnock

Nock JS mocking tool produces error `Right-hand side of 'instanceof' is not an object`


I am trying to use this tool called Nock JS

https://www.npmjs.com/package/nock

with a Next JS, React demo app tested using Cypress

• Next JS 13.4

• Cypress 12.17.1

• React 18.2

e2e/homepage.cy.js



describe('weather app spec', () => {
  it('can load the current weather', () => {


    const nock = require('nock')

    const scope = nock('https://api.openweathermap.org')
      .get('/data/2.5/weather')
      .reply(200, {
      "coord":  {
           "lon": -73.9629,
           "lat": 40.6884
      },
      "weather"  :
        [{"id": 211, "main": "scattered clouds", "description": "scattered clouds", "icon": "11d"}, {
          "id": 500,
          "main": "Rain",
          "description": "scattered clouds",
          "icon": "10d"
      }],
      "base" : "stations",
      "main":
      {
        "temp": 299.25,
        "feels_like": 299.25,
        "temp_min": 296.15,
        "temp_max": 303.46,
        "pressure": 1014,
        "humidity": 75
      }

    })

    cy.visit('/')
    cy.get('#__next').should('contain', "Click to get your weather")
    cy.contains('Get Weather').click()

    cy.contains("Current weather is scattered clouds")
  })
})

If the test does not have nock, the test passes (expected behavior):

enter image description here

Of course, I don't want to call the Open weather API every time i run the test, and now the test is hard-coded to "scattered clouds" which will change as the weather changes.

So I want Nock to mock the HTTP response from the external API, fixing it in place for all test runs

However, if I add the line scope = nock('https://api.openweathermap.org') (you see above), I get:

Right-hand side of 'instanceof' is not an object

enter image description here

Although I don't think it is related to why Nock is giving me this error, for reference, here is implementation code:


import {useRouter} from 'next/router'
import {useState, useEffect, useRef} from 'react'

export async function getServerSideProps(context) {
  // Fetch data from external API
  const OPEN_WEATHER_MAP_API_KEY = process.env.OPEN_WEATHER_APP_API_KEY

  const query = context.query

  const lat = query.lat
  const long = query.long

  if (lat && long) {
    const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&appid=${OPEN_WEATHER_MAP_API_KEY}`;

    const res = await fetch(url)
      .then(res => res.json())
      .then(
        (result) => {
          if (Number(result.cod) === 200) {
            // success result
            const weatherSummary = result.weather[0].description;
            const k_temp = result.main.temp;
            return {forecastSuccess: true,  weatherSummary, temp: k_temp}
          } else {
            return {forecastSuccess: false}
          }
        }
      )
    return {props: res}
  } else {
    return {props: {}}
  }
}


export default function Home({forecastSuccess, weatherSummary, temp}) {
  const router = useRouter();

  const [lat, setLat] = useState(undefined);
  const [long, setLong] = useState(undefined);

  const getLocationAndWeather =  () => {
    navigator.geolocation.getCurrentPosition(async (location) => {
      setLat(location.coords.latitude)
      setLong(location.coords.longitude)
    })
  }

  useEffect(() => {
    if (lat && long) {
      refreshData();
    }
  }, [lat, long])
  const refreshData = () => {
    router.replace(`${router.asPath}?lat=${lat}&long=${long}`);
  }

  return (
    <>
      <p>Click to get your weather:</p>
      <br />
      <input type={"submit"} onClick={ getLocationAndWeather } data-test-id={'get-weather-button'} value={"Get Weather"}/>

      <h1>
        { forecastSuccess && `Current weather is ${weatherSummary}`}
      </h1>
      <h2>
        { forecastSuccess && `${temp} °F`}
      </h2>
      <br />
    </>
  )
}

Solution

  • NockJS is a Node library, so most likely you can't import it into the test (which runs in the browser) and run it there.

    I have a semi-answer here Mocking Next.js getInitialProps in _app which might suit your need.

    Essentially,


    NockJs not compatable with NextJs SSR?

    One thing I forgot to mention is that NextJs show the experimental NodeJs fetch() in their example (see above link)

    import { NextPageContext } from 'next'
     
    Page.getInitialProps = async (ctx: NextPageContext) => {
      const res = await fetch('https://api.github.com/repos/vercel/next.js')
      ...
    

    But Nock says

    Warning nock is currently not compatible with Node's experimental native fetch implementation.
    See #2397

    I mention this in case you are following the NextJs example.

    You can use NodeJs http as an alternative, but that would require you to downgrade your app.