paroi-tech / direct-vuex

Use and implement your Vuex store with TypeScript types. Compatible with the Vue 3 composition API.
Creative Commons Zero v1.0 Universal
258 stars 14 forks source link

How to mock the store #58

Open 304NotModified opened 4 years ago

304NotModified commented 4 years ago

Hi! Thanks for this awesome library.

We are converting our code to this library and it works great. Except...the snapshot tests created with Jest.

How could we mock the store?

For example this stripped Vue component:

Notes.Vue

<template>
    <div>
      <h1>Notes</h1>
      <div v-for="note in notes" :key="note.code">
        <div>
            <b-field :label="note.title">
              <b-input :value="note.text" type="textarea" :id="note.code" rows="4"></b-input>
            </b-field>
        </div>
    </div>
</template>

<script lang="ts">
import { NoteModel } from '@/components/notes/NoteModel';
import Vue from 'vue';
import store from '@/components/store/store';

export default Vue.extend({
  computed: {
    notes: {
      get(): NoteModel[] {
        const notesInStore = store.state.notes;
        return notesInStore;
      }
    },
  },
});
</script>

Jest Test

import { shallowMount } from '@vue/test-utils';
import Notes from '@/components/notes/Notes.vue';
import { StoreState } from '@/components/store/store';
import { NoteModel } from '@/services/NoteModel';

describe('Notes', () => {

  it('Test labels', () => {  
    // Arrange
    let state = new StoreState();
    state.notes.push(new NoteModel({title: 'my title', code: 'code1', text: 'Some note' }));
    const store = new Vuex.Store({
        state: state,
        mutations: mutations,
        actions: actions
    });

    // Act
    const wrapper = shallowMount(Notes, { store });

    // Assert
    expect(wrapper.findAll(`b-field-stub`).at(0).attributes('label')).toEqual('my title');
  });
});

This won't work as we don't this.$store in the component anymore. I tried also this.$store.direct but this yields null in the Jest test.

Is there a way to get this test working?

304NotModified commented 4 years ago

polite bump @paleo

ShadowCoder22 commented 3 years ago

I would also like to know how we can achieve this. I have written my code to utilize this as it yields very readable syntax. The downfall that I have run into is that any component that uses the store for state storage fails the test because some part of the data, be it the getters/module.getters is undefined

paleo commented 3 years ago

You write new Vuex.Store. Could it be possible to use createDirectStore instead?

304NotModified commented 3 years ago

yes createDirectStore is also fine in the tests. Tried that before, but failed to get things working.

paleo commented 3 years ago

In your code:

    const store = new Vuex.Store({
        state: state,
        mutations: mutations,
        actions: actions
    });

    // Act
    const wrapper = shallowMount(Notes, { store });

… I guess it should be something like:

    const store = createDirectStore({
        state: state,
        mutations: mutations,
        actions: actions
    });

    // Act
    const wrapper = shallowMount(Notes, { store: store.original });
304NotModified commented 3 years ago

Will try that, but to be clear, could that work with the current import of the store? (the recommendation) (in the vue component, not the test)

import store from '@/components/store/store';
paleo commented 3 years ago

could that work with the current import of the store? (the recommendation) (in the vue component, not the test)

It should work.

ShadowCoder22 commented 3 years ago

This doesn't seem to work for me. I import the store in the component and try to mock the store in the test file. The test just fails due to anything which reads from the store being undefined

import Vuex from 'vuex'
import { createDirectStore } from 'direct-vuex'
import { mount, shallowMount, createLocalVue } from '@vue/test-utils'
...

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

describe('Order.vue', () => {
  const nextOrder = {
    id: 1,
    ...
  }
  let store

  beforeEach(() => {
    store = createDirectStore({
      modules: {
        order: {
          getters: {
            getOrder: () => id => nextOrder
          }
        }
      }
    })
  })

  it('Renders', async () => {
    const wrapper = shallowMount(Order, {
      store: store.original
    })

    ...
  })
})