4

无法弄清楚使用 cypress 组件测试时如何拦截 getServerSideProps。

做了很多研究和最好的引导链接:

https://github.com/cypress-io/cypress/discussions/9328

https://www.youtube.com/watch?v=33Hq41O0bvU

https://glebbahmutov.com/blog/mock-network-from-server/

https://www.youtube.com/watch?v=xdVRVhUUgCI&feature=youtu.be

有这个例子回购:https ://github.com/norfeldt/proper/tree/ssr-stubing

我想做的是:

赛普拉斯/插件/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;
};

组件/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);
    });
  });
});

但它甚至不会运行测试

在此处输入图像描述

4

1 回答 1

3

您有一个组件测试,用于mount()编译和托管组件。这实际上是一个“正常”的 React 测试,因为mount()来自 '@cypress/react' 是 react-testing-library 的包装器。

因此,您不是在测试 Next,而是在测试 React。

请注意,getServerSideProps您的组件不会显式调用它,因此您在测试中不做任何事情或插件将对其进行测试。


我使用上面链接的 Gleb 示例让您的测试工作,替换您的应用程序并创建一个涉及 NextJS(因此调用getServerSideProps)的集成测试。

这些是我必须改变的关键

  • 移动getServerSideProps到一个页面(我使用主页)。NextJS 不会在组件上调用它

  • 改变拼写(你有getServersideProps

  • 将返回值添加到getServerSideProps

  • 取出 cy.intercept,因为 nock 任务正在执行拦截

这是测试

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

在插件/索引中,我将 nock 拦截器更改为

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

wherequery(true)只接受任何查询参数。使用回调.reply()允许控制台日志检查它是否正在捕获请求。

这是获取 ssrProps 的主页。

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">Tilføj ejendom</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
    },
  }
}

从评论来看,

将集成测试 SSR 模拟请求转换为组件测试不容易吗?

我仍然认为这是不可能的,并且与每种测试类型的目的相反。SSR 包括服务器,要对其进行测试,您需要进行 e2e 测试 - 线索就在名称中。

组件测试是一个扩展的单元测试——它执行自己的挂载并忽略服务器。

要在组件测试中测试 SSR,您必须以mount()某种方式进行扩展,从而为您提供额外的代码和潜在的错误。当 e2e 测试相当直接并完成工作时,IMO 毫无意义。

于 2022-02-02T06:19:42.453 回答