programing

jest 및 avoriaz를 사용할 때 Vuejs의 컴포넌트에서 비동기 메서드를 테스트하는 방법

goodcopy 2022. 8. 13. 23:23
반응형

jest 및 avoriaz를 사용할 때 Vuejs의 컴포넌트에서 비동기 메서드를 테스트하는 방법

예를 들어 다음과 같은 컴포넌트가 있습니다.

<template>
<div id="app">
  <button class="my-btn" @click="increment">{{ val }}</button>
</div>
</template>

<script>
export default {
  data() {
    return {
      val: 1,
    };
  },
  methods: {
    increment() {
      fetch('httpstat.us/200').then((response) => {
        this.val++;
      }).catch((error) => {
        console.log(error);
      });
    },
  },
}
</script>

바이올린을 간단한 데모로서 체크할 수도 있습니다.

이 컴포넌트의 유닛 테스트를 하기 위해 코드를 이렇게 작성했습니다.

// Jest used here
test('should work', () => {
  // wrapper was generated by using avoriaz's mount API
  // `val` was 1 when mounted.
  expect(wrapper.data().val).toBe(1);
  // trigger click event for testing
  wrapper.find('.my-btn')[0].trigger('click');
  // `val` should be 2 when the button clicked.
  // But how can I force jest to wait until `val` was set?
  expect(wrapper.data().val).toBe(2);
});

그 이후로 효과가 없었다.expect전에 실행했다fetch'는 끝났는데 약속 기능이 끝날 때까지 농담은 어떻게 기다려야 할지 모르겠어요.
이 사용 사례에서 테스트하려면 어떻게 해야 합니까?

업데이트 나는 nextTick을 시도했지만 운이 없었다.

 PASS  src/Sample.spec.js
  Sample.vue
    ✓ should work (31ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.46s
Ran all test suites.
  console.error node_modules/vue/dist/vue.runtime.common.js:477
    [Vue warn]: Error in nextTick: "Error: expect(received).toBe(expected)

    Expected value to be (using ===):
      2
    Received:
      1"

  console.error node_modules/vue/dist/vue.runtime.common.js:564
    { Error: expect(received).toBe(expected)

    Expected value to be (using ===):
      2
    Received:
      1
        at /path/to/sample-project/src/Sample.spec.js:16:30
        at Array.<anonymous> (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:699:14)
        at nextTickHandler (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:646:16)
        at <anonymous>
        at process._tickCallback (internal/process/next_tick.js:188:7)
      matcherResult: 
       { actual: 1,
         expected: 2,
         message: [Function],
         name: 'toBe',
         pass: false } }

여기 완전한 테스트 코드가 있습니다.

import { mount } from 'avoriaz';
import Sample from './Sample.vue';
import Vue from 'vue';

/* eslint-disable */

describe('Sample.vue', () => {

  test('should work', () => {
    const wrapper = mount(Sample);
    // console.log(wrapper.data().val);
    expect(wrapper.data().val).toBe(1);
    wrapper.find('.my-btn')[0].trigger('click');
    Vue.nextTick(() => {
        // console.log(wrapper.data().val);
        expect(wrapper.vm.val).toBe(2);
        done();
    })
  });

})

업데이트 2 추가done하지만 여전히 작동하지 않습니다.여기 오류 메시지가 있습니다.

  console.error node_modules/vue/dist/vue.runtime.common.js:477
    [Vue warn]: Error in nextTick: "Error: expect(received).toBe(expected)

    Expected value to be (using ===):
      2
    Received:
      1"

  console.error node_modules/vue/dist/vue.runtime.common.js:564
    { Error: expect(received).toBe(expected)

    Expected value to be (using ===):
      2
    Received:
      1
        at /path/to/sample-project/src/Sample.spec.js:16:30
        at Array.<anonymous> (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:699:14)
        at nextTickHandler (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:646:16)
        at <anonymous>
        at process._tickCallback (internal/process/next_tick.js:188:7)
      matcherResult: 
       { actual: 1,
         expected: 2,
         message: [Function],
         name: 'toBe',
         pass: false } }

 FAIL  src/Sample.spec.js (7.262s)
  ● Sample.vue › should work

    Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

      at pTimeout (node_modules/jest-jasmine2/build/queueRunner.js:53:21)
      at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:523:19)
      at ontimeout (timers.js:469:11)
      at tryOnTimeout (timers.js:304:5)
      at Timer.listOnTimeout (timers.js:264:5)

  Sample.vue
    ✕ should work (5032ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        8.416s
Ran all test suites.

짧은 이야기: 도움을 받다flush-promises(npm i -D flush-promises를 호출합니다.await flushPromises()직전에Vue.nextTick.

좀 더 긴 이야기지만EmailVerification.vue와의 컴포넌트submit다음과 같은 방법을 사용합니다.

    submit () {
    this.successMessage = ''
    this.verifyError = null
    this.isVerifying = true

    this.verifyEmail({ 'key': this.key })
      .then(() => {
        this.isVerifying = false
        this.successMessage = 'Email verified, great! Thanks a lot. &nbsp; <i class="fa fa-home"></i><a href="/">Home</a>'
      })
      .catch((error) => {
        this.isVerifying = false
        this.verifyError = error
      })
  }

다음은 저의 완전한 테스트 패스입니다.

const localVue = createLocalVue()
localVue.use(Vuex)

const $route = {
  path: '/verify-email/:key',
  params: { key: 'dummy_key' },
  query: { email: 'dummy@test.com' }
}

describe('EmailVerification.vue', () => {
  describe('Methods', () => {
    let localAuth = { namespaced: true }
    let store
    let wrapper

    beforeEach(() => {
      localAuth.actions = {
        verifyEmail: jest.fn().mockReturnValueOnce()
      }

      store = new Vuex.Store({
        namespaced: true,
        modules: { auth: localAuth },
        strict: true
      })

      wrapper = shallowMount(EmailVerification, {
        localVue,
        store,
        stubs: {
          RouterLink: RouterLinkStub
        },
        mocks: {
          $route
        }
      })
    })

    it('should trigger verifyEmail when button is clicked', async (done) => {
      const data = { key: 'another_dummy_key' }
      wrapper.setData(data)
      const button = wrapper.find('button')

      expect(wrapper.vm.isVerifying).toBeFalsy()
      expect(wrapper.vm.verifyError).toBeNull()
      expect(button.attributes().disabled).toBeUndefined()

      button.trigger('click')

      expect(localAuth.actions.verifyEmail).toHaveBeenCalled()
      expect(localAuth.actions.verifyEmail.mock.calls[0][1]).toEqual(data)

      expect(button.attributes().disabled).toBeDefined()
      expect(wrapper.vm.isVerifying).toBeTruthy()
      expect(wrapper.vm.verifyError).toBeNull()

      const inputArray = wrapper.findAll('input')
      expect(inputArray.at(0).attributes().disabled).toBeDefined()
      expect(inputArray.at(1).attributes().disabled).toBeDefined()

      await flushPromises()

      wrapper.vm.$nextTick(() => {
        expect(wrapper.vm.isVerifying).toBeFalsy()
        expect(wrapper.vm.verifyError).toBeNull()
        done()
      })
    })
  })
})

그런 다음 의 반환값을 사용하여 재생합니다.jest.fn()오류를 반환하고 테스트하기 위한 모의 함수입니다.

주의: 저는 아보리아즈가 아닌 농담과 모카를 사용하고 있습니다.

테스트 내부와 를 사용해야 합니다.

test('should work', (done) => {
  expect(wrapper.data().val).toBe(1);
  wrapper.find('.my-btn')[0].trigger('click');
    Vue.nextTick(() => {
        expect(wrapper.vm.val).toBe(3);
        done()
    })
});

언급URL : https://stackoverflow.com/questions/45542213/how-to-test-async-method-in-vuejss-component-when-using-jest-and-avoriaz

반응형