自动化测试的使用示例

单元测试

react 17 使用 @wojtekmaj/enzyme-adapter-react-17

对方法进行 wrap

点击查看代码
'should call method once with argument': function () {
  var object = { method: function () {} };
  var spy = sinon.spy(object, 'method');
  object.method(1);
  assert(spy.withArgs(1).calledOnce);
}

import { shallow } from 'enzyme'
import sinon from 'sinon';

describe('测试 demo', () => {
    const onButtonClick = sinon.spy()
    const children = (
        <div className="demo" onClick={onButtonClick}>
            demo
        </div>
    )
    const warrper = shallow(<div>{children}</div>)

    test('测试渲染dom结构', () => {
        expect(warrper.find('.demo')).toHaveLength(1)
    })

    test('测试子元素时', () => {
        expect(warrper.contains(children)).toEqual(true)
    })

    test('测试点击事件', () => {
        warrper.find('.demo').simulate('click')
        expect(onButtonClick).toHaveProperty('callCount', 1)
    })
})

class类组件

点击查看代码
export const findTestWrapper = (wrapper, tag) => {
    return wrapper.find(`[data-test="${tag}"]`);
}

describe('输入框内容随用户输入变化', () => {
    const wrapper = shallow(<Header />);
    const inputElem = findTestWrapper(wrapper, 'input');
    const userInput = '今天要学习 Jest';
    inputElem.simulate('change', {
      target: { value: userInput}
    });
    expect(wrapper.state('value')).toEqual(userInput);
});

hooks function组件

点击查看代码
describe('<TestComponent />', () => {
    let wrapper;
    const setState = jest.fn();
    const useStateSpy = jest.spyOn(React, 'useState')
    useStateSpy.mockImplementation((init) => [init, setState]);
  
    beforeEach(() => {
      wrapper = Enzyme.shallow(<TestComponent />);
    });
  
    afterEach(() => {
      jest.clearAllMocks();
    });
  
    describe('Count Up', () => {
      it('calls setCount with count + 1', () => {
        wrapper.find('#count-up').props().onClick();
        expect(setState).toHaveBeenCalledWith(1);
      });
    });
  
    describe('Count Down', () => {
      it('calls setCount with count - 1', () => {
        wrapper.find('#count-down').props().onClick();
        expect(setState).toHaveBeenCalledWith(-1);
      });
    });
  
    describe('Zero', () => {
      it('calls setCount with 0', () => {
        wrapper.find('#zero-count').props().onClick();
        expect(setState).toHaveBeenCalledWith(0);
      });
    });
});

describe('模拟React的useState 方法,并调用', () => {
    const setState = jest.fn();
    const useStateSpy = jest.spyOn(React, 'useState');
    const useStateMock: any = (initState: any) => [initState, setState];
    useStateSpy.mockImplementation(useStateMock);
    const wrapper = shallow(<LoginStatus />);
    React.useState('150');
    expect(useStateSpy).toHaveBeenCalledWith('150');
    expect(useStateSpy).toHaveBeenCalled();
  });

测试 dva effects

点击查看代码
import { expect } from 'chai';
import { runSaga, effects } from 'dva/saga';

describe('Account Manage', function() {
  describe('info', function() {
    const {
      state,
      effects: {
        edit
      }
    } = require('../src/account/models/info');

    it('should dispatch saveInfo action when editing', async function() {
      const dispatched = [];
      const payload = { username: 'name' };
      const result = await runSaga({
        dispatch: (action) => dispatched.push(action),
        getState: () => state
      }, edit, { payload }, effects).done;

      expect(dispatched).toHaveLengthOf(1);
      expect(dispatched[0]).toHaveProperty('type', 'saveInfo');
    });
  });
});

组件测试

Enzyme

  • shallow:浅渲染,可以用simulate进行交互模拟
  • render:静态渲染,需要测试对子组件进行判断
  • mount:完全渲染,可以用simulate进行交互模拟,需要测试组件的生命周期。
点击查看代码
import { expect } from 'chai';
import React from 'react';
import { mount } from 'enzyme';
import { effects } from 'dva/saga';

const { put } = effects;

describe('Banner', function() {
  const Banner = require('../src/components/Banner');

  it('should render correctly', async function() {
    const wrapper = mount(<Banner dispatch={put}/>);
    // wait async request
    await new Promise((resolve) => setTimeout(resolve, 2000));

    expect(wrapper.state('bannerData')).to.have.lengthOf.at.least(1);
    expect(wrapper.find('.slick-list')).to.have.lengthOf.above(1);
  });
});

集成测试

编写第一个 React 集成测试中的例子

git clone git@github.com:montezume/calculator.git

点击查看代码
import React from "react";
import userEvent from "@testing-library/user-event";
import { render, screen } from "@testing-library/react";
import App from "./App";

describe("negative numbers", () => {
  describe("when we add -5 to 2", () => {
    it("equals -3", () => {
      render(<App />);
      userEvent.click(screen.getByRole("button", { name: "5" }));
      userEvent.click(screen.getByRole("button", { name: "+/-" }));
      userEvent.click(screen.getByRole("button", { name: "+" }));
      userEvent.click(screen.getByRole("button", { name: "2" }));
      userEvent.click(screen.getByRole("button", { name: "=" }));

      expect(screen.getByText("-3")).toBeInTheDocument();

      // clear the screen
      userEvent.click(screen.getByRole("button", { name: "AC" }));

      expect(screen.queryByText("-3")).not.toBeInTheDocument();
    });
  });
});

E2E 测试

点击查看代码
/ launch server
import ready from '../../server';
import { expect } from 'chai';
import puppeteer from 'puppeteer';

describe('Account', function() {
  // set a long timeout
  this.timeout(60000);

  describe('log in', function() {
    it('should log in correctly', async function() {
      const browser = await puppeteer.launch();
      const page = await browser.newPage();

      // wait dev server ready
      await ready();
      await page.goto('http://localhost:8000/account/login', { 'waitUntil': 'networkidle0' });
	    await page.type('#username', 'smalldragonluo');
	    await page.type('#password', 'pwd');
	    await page.click('#submit');
			// ...
      const result = await page.$eval('#result', (element) => {
        return element.innerHTML
      })
      expect(result).to.equal('Success!');
      
      await browser.close();
    });
  });
});
posted @ 2022-03-10 13:47  远方的少年🐬  阅读(78)  评论(0编辑  收藏  举报