[TaskAgile]JestとVTUを使用してVue(2)をテスト


じっさいしけんコード
// RegisterPage.spec.js
import { mount } from '@vue/test-utils';
import RegisterPage from '@/views/RegisterPage';

jest.mock('@/services/registration');

describe('RegisterPage.vue', () => {
  let wrapper, fieldUsername, fieldPassword, fieldEmailAddress, buttonSubmit;
  const mockRouter = {
    push: jest.fn(),
  };

  beforeEach(() => {
    wrapper = mount(RegisterPage, {
      global: {
        mocks: {
          $router: mockRouter,
        },
        /* or
        plugins: [router]
        */
      },
    });
    fieldUsername = wrapper.find('#username');
    fieldEmailAddress = wrapper.find('#emailAddress');
    fieldPassword = wrapper.find('#password');
    buttonSubmit = wrapper.find('form button[type="submit"]');
  });

  afterAll(() => {
    jest.restoreAllMocks();
  });

  it('마운트 시, 컨텐츠가 올바르게 렌더링 되어야 한다', () => {
    expect(wrapper.find('.logo').attributes('src')).toEqual(
      '/static/images/logo.png'
    );

    expect(wrapper.find('.tagline').text()).toEqual(
      'Open source task management tool'
    );

    expect(fieldUsername.element.value).toEqual('');
    expect(fieldEmailAddress.element.value).toEqual('');
    expect(fieldPassword.element.value).toEqual('');
    expect(buttonSubmit.text()).toEqual('Create account');
  });

  it('데이터 모델의 초기값이 빈 문자열이어야 한다.', () => {
    expect(wrapper.vm.form.username).toEqual('');
    expect(wrapper.vm.form.emailAddress).toEqual('');
    expect(wrapper.vm.form.password).toEqual('');
  });

  it('폼의 입력과 데이터 모델의 바인딩이 정상적으로 되야 한다.', async () => {
    const form = wrapper.vm.form;
    const username = 'tkppp';
    const emailAddress = '[email protected]';
    const password = 'password1';

    await fieldUsername.setValue(username);
    await fieldEmailAddress.setValue(emailAddress);
    await fieldPassword.setValue(password);

    expect(fieldUsername.element.value).toEqual(form.username);
    expect(fieldEmailAddress.element.value).toEqual(form.emailAddress);
    expect(fieldPassword.element.value).toEqual(form.password);
  });

  it('폼 제출 이벤트 핸들러에 "submitForm"이 등록되어야 한다.', async () => {
    const spyFn = jest.spyOn(wrapper.vm, 'submitForm')

    await buttonSubmit.trigger('submit');
    expect(spyFn).toBeCalled();
  });

  it('새로운 유저의 경우, 회원가입이 성공해야 한다', async () => {
    wrapper.vm.form.username = 'tkppp';
    wrapper.vm.form.emailAddress = '[email protected]';
    wrapper.vm.form.password = 'password1';
    await buttonSubmit.trigger('submit')
    expect(mockRouter.push).toHaveBeenCalledWith({ name: 'LoginPage' });
    
  });

  it('등록된 유저의 경우, 회원가입이 실패하고 실패 메세지를 표시해야 한다.', async () => {
    wrapper.vm.form.emailAddress = 'exist@local';
    expect(wrapper.find('.failed').isVisible()).toBe(false);
    await buttonSubmit.trigger('submit')
    expect(wrapper.find('.failed').isVisible()).toBe(true);
  });
});
変更点へんこうてん
テスト:フォームの入力とデータモデルのバインドは正常でなければなりません.
// 기존 책 코드
it('test name', () => {
    const username = 'tkppp';
    const emailAddress = '[email protected]';
    const password = 'password1';

    wrapper.vm.form.username = username
    wrapper.vm.form.emailAddress = emailAddress
    wrapper.vm.form.password = password
    expect(fieldUsername.element.value).toEqual(username);
    expect(fieldEmailAddress.element.value).toEqual(emailAddress);
    expect(fieldPassword.element.value).toEqual(password);
})
既存の本のテストでinputの値が更新されず、テストに失敗しました.パッキンオブジェクトのvmによるデータ変更は、再レンダリングされない場合があります.したがって、非同期関数setValue()で入力値を変更し、バインドされたデータが正しく変更されているかどうかを確認してテストを変更します.
テスト:フォームコミットイベントハンドラにsubmitFormを登録する必要があります.
// 기존 책 코드
it('test name', () => {
    const stub = jest.fn()
    wrapper.setMethods({submitform: stub})
    buttonSubmit.trigger('submit')
    expect(stub).tobeCalled()
})
setMethods()関数は破棄され,Vue 3試験では完全に消失した.ということで、spyOnラッピング機を通ります.vmオブジェクトのsubmitForm()関数を監視することでテストを変更しました.
テスト:新しいプレイヤーに対して、会員加入は成功しなければならない.&登録したプレイヤーの場合、会員登録に失敗し、失敗情報を表示する必要があります.
// 기존 책 코드
it('새로운 유저의 경우, 회원가입이 성공해야 한다', () => {
    const stub = jest.fn()
    wrapper.vm.$router.push = stub
    wrapper.vm.form.username = 'tkppp';
    wrapper.vm.form.emailAddress = '[email protected]';
    wrapper.vm.form.password = 'password1';
    wrapper.vm.sumitForm()
    wrapper.vm.$nextTick(() => {
    	expect(stub).toHaveCalledWith({name: 'LoginPage'})
    }
})
  
it('등록된 유저의 경우, 회원가입이 실패하고 실패 메세지를 표시해야 한다.', () => {
    wrapper.vm.form.emailAddress = '...'
    expect(wrapper.find('.failed').isVisible()).toBe(false)
    wrapper.vm.submitForm()
    wrapper.vm.$nextTick(null, () => {
    	expect(wrapper.find('.failed').isVisible()).toBe(true)
    })
})
最も困難なテストは$nextTick()でレンダリングを完了した後にテストを行いますが、テストは失敗しました.これは、レンダリングをトリガする非同期関数の実行が$nextTick()で保証されないためである.この問題を解決するために、VTUの公式文書はいくつかの解決策を提出した.
  • フリップフロップ()関数非同期運転
  • plushPromises()によるタスクキューのパージ
  • done()関数
  • を使用
    詳細については、正式な書類を参照してください.
    テスト:登録サービス
    本の中でmoxiosという外部ライブラリを使ってaxiosモジュールをテストしました.jestです.axiosモジュールをmock(「axios」)でシミュレートし、mock Implementation()を使用してaxiosをシミュレートします.postの偽関数を実装してテストします.
    import axios from 'axios';
    import registrationService from '@/services/registration';
    
    jest.mock('axios');
    
    describe('services/registration', () => {
      beforeEach(() => {});
    
      afterEach(() => {
        jest.restoreAllMocks();
      });
    
      it('요청이 성공하면, 성공 응답이 호출자에게 전달되어야 한다.', async () => {
        axios.post.mockImplementation(() =>
          Promise.resolve({
            status: 200,
            data: {
              result: 'success',
            },
          })
        );
    
        const response = await registrationService.register();
        expect(response.data.result).toEqual('success');
      });
    
      it('요청이 실패하면, 실패 응답이 호출자에게 전달되어야 한다.', async () => {
        axios.post.mockImplementation(() =>
          Promise.reject({
            status: 400,
            data: {
              message: 'Bad request',
            },
          })
        );
        try{
          await registrationService.register();
        }catch(e){
          console.log(e)
          expect(e.data.message).toEqual('Bad request');
        }
      });
    });