VueJS 和 Jest。使用本地导入的 mixin 测试组件

VueJS and Jest. Testing component with local imported mixin

我正在通过重新创建 MineOS 界面来学习 VueJS。我在没有实际调用后端的情况下复制了一堆功能。我 运行 遇到了单元测试问题。 看起来我已尽我所能,但我认为我的 mixin 方法没有被调用。 我想我正在做的是:

  1. 用我的测试模拟 store/state(我已经在我的登录规范中完成了)。
  2. 模拟 mixin 使用的操作并分配给应该在 mixin 中映射的存储。
  3. 用 235 填充 java_xmx 输入,然后触发输入事件。
  4. 触发下一个价格变动
  5. 查询动作以查看它是否被调用。

测试mixins全局导入和mock的唯一方法是?

javaoptions.vue

<template>
  <div class="tile is-vertical">
    <div class="tile is-child has-text-left">
      <b-dropdown
        aria-role="list"
        @change="updateConfig('java', 'jarfile', $event)"
      >
        <template #trigger="{ active }">
          <b-button
            label="Change runnable JAR to:"
            :icon-right="active ? 'menu-up' : 'menu-down'"
          />
        </template>
        <b-dropdown-item aria-role="listitem" value="minecraft_server_17.1.jar"
          >minecraft_server_17.1.jar</b-dropdown-item
        >
      </b-dropdown>
    </div>
    <div class="tile is-child has-text-left">
      <div class="tile">
        <b-field label="Memory Allocation (Heapsize)">
          <div class="tile is-vertical">
            <div class="tile is-child">
              <b-field class="has-addons">
                <p class="control">
                  <b-button class="button is-static">-Xmx</b-button>
                </p>
                <b-input
                  id="java_xmx"
                  :lazy="true"
                  type="number"
                  @input="updateConfig('java', 'java_xmx', $event)"
                ></b-input>
                <p class="control">
                  <b-button class="button is-static">MB</b-button>
                </p>
              </b-field>
            </div>
            <div class="tile is-child">
              <b-field class="has-addons">
                <p class="control">
                  <b-button class="button is-static">-Xms</b-button>
                </p>
                <b-input
                  id="java_xms"
                  type="number"
                  :lazy="true"
                  @input="updateConfig('java', 'java_xms', $event)"
                ></b-input>
                <p class="control">
                  <b-button class="button is-static">MB</b-button>
                </p>
              </b-field>
            </div>
            <div class="tile is-child">
              <b-field label="Additional Java arguments:">
                <b-input
                  id="java_tweaks"
                  placeholder="-XX:+DisableExplicitGC"
                  :lazy="true"
                  @input="updateConfig('java', 'java_tweaks', $event)"
                />
              </b-field>
            </div>
            <div class="tile is-child">
              <b-field label="Additional Jar arguments:">
                <b-input
                  id="jar_args"
                  placeholder="nogui"
                  :lazy="true"
                  @input="updateConfig('java', 'jar_args', $event)"
                />
              </b-field>
            </div>
          </div>
        </b-field>
      </div>
    </div>
  </div>
</template>

<script>
import updateConfigMixin from '@/mixins/updateconfig-mixin.js';

export default {
  name: 'JavaOptions',
  mixins: [updateConfigMixin],
  computed: {},
  methods: {},
};
</script>

<style lang="scss" scoped></style>

JavaSettings.spec.js

import { mount, createLocalVue } from '@vue/test-utils';
import JavaOptions from '@/components/partials/java_settings/javaoptions.vue';
import Buefy from 'buefy';
import Vuex from 'vuex';

const localVue = createLocalVue();

localVue.use(Vuex);
localVue.use(Buefy);

describe('JavaOptions.vue', () => {
  let actions;
  let store;

  beforeEach(() => {
    actions = {
      updateServerConfigAction: jest.fn(),
    };

    store = new Vuex.Store({
      actions,
      selected: { config: { java_xmx: '' } },
    });
  });

  it("expect 'updateServerConfigAction' to be called on setting change", async () => {
    const wrapper = mount(JavaOptions, {
      store,
      localVue,
      attachTo: document.body,
    });

    const java_xmx = wrapper.find('#java_xmx');
    java_xmx.element.value = 235;
    java_xmx.trigger('input');
    await wrapper.vm.$nextTick();
    expect(java_xmx.element.value).toBe('235');
    expect(wrapper.vm.updateServerConfigAction).toHaveBeenCalled();
  });
});

updateconfig-mixin.js

import cloneDeep from 'clone-deep';
import { mapActions, mapState } from 'vuex';

export default {
  computed: {
    ...mapState({ config: state => state.selected.config }),
  },
  methods: {
    ...mapActions(['updateServerConfigAction']),
    updateConfig(section, propKey, newVal) {
      const config = cloneDeep(this.config);
      const selectedSection = config[section];
      selectedSection[propKey] = newVal;
      this.updateServerConfigAction(config);
    },
  },
};

终端输出

peter@peter-VirtualBox:/usr/development/mineos-vue$ npm run -s test:unit
 FAIL  tests/unit/JavaSettings.spec.js
  ● JavaOptions.vue › expect 'updateServerConfigAction' to be called on setting change

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      36 |     await wrapper.vm.$nextTick();
      37 |     expect(java_xmx.element.value).toBe('235');
    > 38 |     expect(actions.updateServerConfigAction).toHaveBeenCalled();
         |                                              ^
      39 |   });
      40 | });
      41 |

      at Object.it (tests/unit/JavaSettings.spec.js:38:46)

 PASS  tests/unit/Login.spec.js
-----------------------------------|----------|----------|----------|----------|-------------------|
File                               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------------------------|----------|----------|----------|----------|-------------------|
All files                          |       50 |      100 |    33.33 |       50 |                   |
 components/partials               |      100 |      100 |      100 |      100 |                   |
  Login.vue                        |      100 |      100 |      100 |      100 |                   |
 components/partials/java_settings |      100 |      100 |      100 |      100 |                   |
  javaoptions.vue                  |      100 |      100 |      100 |      100 |                   |
 mixins                            |        0 |      100 |        0 |        0 |                   |
  updateconfig-mixin.js            |        0 |      100 |        0 |        0 |     6,11,12,13,14 |
-----------------------------------|----------|----------|----------|----------|-------------------|

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

终于想通了!

有几个问题需要修复才能通过整个测试。 目前的问题是 mixin 似乎没有在测试中使用。 我需要改变 @input="updateConfig('java', 'java_xmx', $event)"@input.native="updateConfig('java', 'java_xmx', $event)" 当然! .native.

然后我发现我没有嘲笑我的状态并且不得不这样做。

测试的最终代码是

import { mount, createLocalVue } from '@vue/test-utils';
import JavaOptions from '@/components/partials/java_settings/javaoptions.vue';
import Buefy from 'buefy';
import Vuex from 'vuex';

const localVue = createLocalVue();

localVue.use(Vuex);
localVue.use(Buefy);

describe('JavaOptions.vue', () => {
  let actions;
  let store;

  beforeEach(() => {
    actions = {
      updateServerConfigAction: jest.fn(),
    };

    store = new Vuex.Store({
      actions,
      state: { selected: { config: { java: { java_xmx: '' } } } },
    });
  });

  it("expect 'updateServerConfigAction' to be called on setting change", async () => {
    const wrapper = mount(JavaOptions, {
      store,
      localVue,
      attachTo: document.body,
    });

    const java_xmx = wrapper.find('#java_xmx');
    await java_xmx.setValue(235);

    expect(java_xmx.element.value).toBe('235');
    expect(actions.updateServerConfigAction).toHaveBeenCalled();
  });
});