programing

Vue, Vuex: 이름을 앞지르고 조롱하는 구성 요소를 어떻게 유닛화하는지?

prostudy 2022. 4. 13. 20:58
반응형

Vue, Vuex: 이름을 앞지르고 조롱하는 구성 요소를 어떻게 유닛화하는지?

vue, vuex 및 vuetify를 사용하여 로그인 구성 요소를 만들고 있다.나는 매장에서 이름보다 앞선 인증 모듈을 사용하기로 결정했는데, 이것이 나에게 문제를 일으키고 있다.

TDD로 접근하고 있어.나의 e2e 테스트는 효과가 있다.그러나 mockStore를 사용하여 적절한 조치가 전송되었는지 검증해야 하는 이 단위 테스트를 작성했다.

describe('Login component', () => {
  let wrapper
  const mockStore = {
    dispatch: jest.fn(),
  }

  beforeEach(() => {
    wrapper = mount(Login, {
      localVue,
      mocks: { $store: mockStore },
      computed: {
        error: () => 'test error',
      },
      data: () => ({
        valid: true
      })
    })
  })

  it('should dispatch login action', async () => {
    wrapper.find('[data-test="username"]').setValue('username')
    wrapper.find('[data-test="password"]').setValue('password')
    await wrapper.vm.$nextTick()
    await wrapper.vm.$nextTick()
    wrapper.find('[data-test="login"]').trigger('click')
    await wrapper.vm.$nextTick()
    expect(mockStore.dispatch).toHaveBeenCalledWith(
      `auth/${LOGIN}`,
      { username: 'username', password: 'password' }
    )
  })
})

구성 요소만 사용 중임mapActions다음과 같은 방법으로:

...mapActions('auth', [LOGIN])

그리고 그것을 트리거하는 버튼:

      <v-btn
        color="info"
        @click="login({ username, password })"
        data-test="login"
        :disabled="!valid"
      >Login</v-btn>

내가 받는 오류는 다음과 같다.

[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'auth/' of undefined"

네임스페이스를 삭제하는 경우mapActions그러면 내가 받는 파견된 조치 이름은 이름 앞에 붙지 않고 (duh) 테스트가 실패한다.

    - Expected
    + Received

    - "auth/login",
    + "login",

실제로 다음과 같은 작업을 매핑하여 해결할 수 있었다.

...mapActions({ login: `auth/${LOGIN}` })

하지만 난 더 많은 액션이 있을 때 더 보기 흉해질 것이기 때문에 이름 앞지르는 버전을 사용하는 게 더 좋아.

vuex 소스 코드를 검색했는데 액세스하려고 하면 실패함_modulesNamespaceMap하지만 그건 내게 너무 복잡해

이것을 테스트하는 가장 좋은 방법은 무엇인가?조롱하는 것을 포기하고 이쯤에서 진짜 가게를 이용해야 할까?

여기서 사용할 수 있는 전체 프로젝트와 이 문제와 관련된 커밋은4a7e749d4

문서에 나와 있는 예시를 바탕으로, 나는 이것이 효과가 있어야 한다고 생각한다.

/* ... other imports and setup ... */
import Vuex from 'vuex'

describe('Login component', () => {
  let wrapper
  const actions = {
    login: jest.fn(),
  }
  const mockStore = new Vuex({
    modules: {
      auth: {
        namespaced: true,
        actions,
      },
    },
  })

  beforeEach(() => {
    wrapper = mount(Login, {
      localVue,
      mocks: { $store: mockStore },
      computed: {
        error: () => 'test error',
      },
      data: () => ({
        valid: true
      })
    })
  })

  it('should dispatch login action', async () => {
    wrapper.find('[data-test="username"]').setValue('username')
    wrapper.find('[data-test="password"]').setValue('password')
    await wrapper.vm.$nextTick()
    await wrapper.vm.$nextTick()
    wrapper.find('[data-test="login"]').trigger('click')
    await wrapper.vm.$nextTick()
    expect(actions.login).toHaveBeenCalled() // <-- pretty sure this will work
    expect(actions.login).toHaveBeenCalledWith({ // <-- not as sure about this one
      username: 'username',
      password: 'password',
    })
  })
})

Vue 3 Test Utils로 이동하는 모든 사용자는createLocalVue위의 답변이 의존하는 방법은 @vue/test-utilles에서 제거된다(https://next.vue-test-utils.vuejs.org/migration/#no-more-create localvue 참조).

대신, 그것은 다음 제품을 사용할 것을 권고한다.createStoreVuex의 방법.나는 이렇게 작업하면서 이름들을 추려낼 수 있었다.

/* ... other imports and setup ... */
import { mount } from "@vue/test-utils";
import Logon from "path/to/your/logon/component";
import { createStore } from "vuex";

describe('Login component', () => {

  const actions = {
    login: jest.fn(),
  };

  const mockStore = createStore({
    modules: {
      auth: {
        namespaced: true,
        actions,
      },
    },
  });

  let wrapper;

  beforeEach(() => {
    wrapper = mount(Login, {
      global: {
        plugins: [mockStore],
      },
    });
  });

  it('should dispatch login action', async () => {
     /*...test code goes here */
  })
})

참조URL: https://stackoverflow.com/questions/61431258/vue-vuex-how-to-unit-test-a-component-with-namespaced-store-and-mocking

반응형