Nock JS 模拟工具产生错误“'instanceof' 的右侧不是对象”

Jas*_* FB 2 javascript reactjs nock next.js cypress

我正在尝试使用这个名为Nock JS的工具

\n

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

\n

使用Next JS,使用Cypress测试React演示应用程序

\n

\xe2\x80\xa2 下一个 JS 13.4

\n

\xe2\x80\xa2\xc2\xa0赛普拉斯 12.17.1

\n

\xe2\x80\xa2 反应 18.2

\n

e2e/homepage.cy.js

\n
\n\ndescribe(\'weather app spec\', () => {\n  it(\'can load the current weather\', () => {\n\n\n    const nock = require(\'nock\')\n\n    const scope = nock(\'https://api.openweathermap.org\')\n      .get(\'/data/2.5/weather\')\n      .reply(200, {\n      "coord":  {\n           "lon": -73.9629,\n           "lat": 40.6884\n      },\n      "weather"  :\n        [{"id": 211, "main": "scattered clouds", "description": "scattered clouds", "icon": "11d"}, {\n          "id": 500,\n          "main": "Rain",\n          "description": "scattered clouds",\n          "icon": "10d"\n      }],\n      "base" : "stations",\n      "main":\n      {\n        "temp": 299.25,\n        "feels_like": 299.25,\n        "temp_min": 296.15,\n        "temp_max": 303.46,\n        "pressure": 1014,\n        "humidity": 75\n      }\n\n    })\n\n    cy.visit(\'/\')\n    cy.get(\'#__next\').should(\'contain\', "Click to get your weather")\n    cy.contains(\'Get Weather\').click()\n\n    cy.contains("Current weather is scattered clouds")\n  })\n})\n\n
Run Code Online (Sandbox Code Playgroud)\n

如果测试没有 nock,则测试通过(预期行为):

\n

在此输入图像描述

\n

当然,我不想每次运行测试时都调用开放天气 API,现在测试被硬编码为“分散的云”,它会随着天气的变化而变化。

\n

所以我希望 Nock 模拟来自外部 API 的 HTTP 响应,为所有测试运行修复它

\n

但是,如果我添加该行scope = nock(\'https://api.openweathermap.org\')(如上所示),我会得到:

\n
Right-hand side of \'instanceof\' is not an object\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

虽然我不认为这与 Nock 给我这个错误的原因无关,但作为参考,这里是实现代码:

\n
\nimport {useRouter} from \'next/router\'\nimport {useState, useEffect, useRef} from \'react\'\n\nexport async function getServerSideProps(context) {\n  // Fetch data from external API\n  const OPEN_WEATHER_MAP_API_KEY = process.env.OPEN_WEATHER_APP_API_KEY\n\n  const query = context.query\n\n  const lat = query.lat\n  const long = query.long\n\n  if (lat && long) {\n    const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&appid=${OPEN_WEATHER_MAP_API_KEY}`;\n\n    const res = await fetch(url)\n      .then(res => res.json())\n      .then(\n        (result) => {\n          if (Number(result.cod) === 200) {\n            // success result\n            const weatherSummary = result.weather[0].description;\n            const k_temp = result.main.temp;\n            return {forecastSuccess: true,  weatherSummary, temp: k_temp}\n          } else {\n            return {forecastSuccess: false}\n          }\n        }\n      )\n    return {props: res}\n  } else {\n    return {props: {}}\n  }\n}\n\n\nexport default function Home({forecastSuccess, weatherSummary, temp}) {\n  const router = useRouter();\n\n  const [lat, setLat] = useState(undefined);\n  const [long, setLong] = useState(undefined);\n\n  const getLocationAndWeather =  () => {\n    navigator.geolocation.getCurrentPosition(async (location) => {\n      setLat(location.coords.latitude)\n      setLong(location.coords.longitude)\n    })\n  }\n\n  useEffect(() => {\n    if (lat && long) {\n      refreshData();\n    }\n  }, [lat, long])\n  const refreshData = () => {\n    router.replace(`${router.asPath}?lat=${lat}&long=${long}`);\n  }\n\n  return (\n    <>\n      <p>Click to get your weather:</p>\n      <br />\n      <input type={"submit"} onClick={ getLocationAndWeather } data-test-id={\'get-weather-button\'} value={"Get Weather"}/>\n\n      <h1>\n        { forecastSuccess && `Current weather is ${weatherSummary}`}\n      </h1>\n      <h2>\n        { forecastSuccess && `${temp} \xc2\xb0F`}\n      </h2>\n      <br />\n    </>\n  )\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Suc*_*UKR 5

NockJS 是一个 Node 库,因此您很可能无法将其导入测试(在浏览器中运行)并在那里运行。

我在这里有一个半答案Mocking Next.js getInitialProps in _app这可能适合您的需要。

本质上,

  • 在 NextJs SSR 中,几乎不可能在 Cypress 中模拟 API 请求,因为服务器在 Cypress 能够打开网页之前执行请求。

  • 您可以相当轻松地使用 NextJs 自定义服务器设置“静态”模拟,但这只允许一组模拟数据。

  • 理论上,您可以在设置模拟数据以适合特定测试cy.exec()之前使用 和 来配置模拟服务器以从测试内部启动和停止。cy.visit()

  • Gleb Bahmutov 有一个使用 Cypress 任务中的 NockJs 的示例,但它是用 Cypress v9 编写的,我无法将其升级到最新版本。但如果您想使用旧版本,这是一种可行的方法,也是您可以适应的将 NockJs 与 Cypress 结合使用的一个很好的示例。


NockJs 与 NextJs SSR 不兼容?

我忘记提及的一件事是 NextJsfetch()在他们的示例中展示了实验性的 NodeJs(参见上面的链接)

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

诺克

警告nock 目前与Node 的实验性本机 fetch实现 不兼容。
参见#2397

我提到这一点是为了防止您遵循 NextJs 示例。

您可以使用NodeJs http作为替代方案,但这需要您降级您的应用程序。