Search code examples
vue.jsvuejs2jestjsweb-componentvue-test-utils

Testing vue with a web component


My application is using astrouxds web components and I am getting a warning in my tests that I would like to fix. I'm also not sure how to assert on a value in the web component.

  console.error node_modules/vue/dist/vue.runtime.common.dev.js:621
    [Vue warn]: Unknown custom element: <rux-toggle> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
    
    found in
    
    ---> <App>
           <Root>

I have setup an example application here. It uses rux-toggle as an example.

The application has a simple template and script in a .vue file.

<template>
  <div id="app">
    <rux-toggle
        id="app-toggle"
        :checked="toggle"
        @click.prevent="toggle = !toggle"></rux-toggle> {{ toggle }}
  </div>
</template>

<script>

export default {
  name: 'App',
  computed: {
    toggle: {
      get() {
        return this.$store.state.toggle
      },
      set(value) {
        this.$store.commit('setToggle', value)
      }
    }
  }
}
</script>

The test uses mount to create a wrapper and test that the web component is checked.

import Vuex from 'vuex';
import {createLocalVue, mount} from '@vue/test-utils';
import storeConfig from '@/store'
import App from '@/App'

describe("App", () => {
  let localVue;
  let store;
  let wrapper;

  beforeEach(() => {
    localVue = createLocalVue();
    localVue.use(Vuex);
    store = new Vuex.Store(storeConfig);
    wrapper = mount(App, {store, localVue});
  });

  it("test toggle default", () => {
    const result = wrapper.find('#app-toggle').checked;
    expect(result).toEqual(true);
  })
})

The test fails with:

Error: expect(received).toEqual(expected) // deep equality

Expected: true
Received: undefined

I'm not exactly sure how to get the checked value of the web component to do the assertion correctly.

Things I have tried

  1. Switched from shallowMount to mount
  2. Register globally using Vue.component(rux-toggle, RuxToggle)
  3. Added Vue.config.productionTip = false to jest setup

Solution

  • The rux-toggle component is only registered in main.js, leading to the warnings/errors you observed.

    Regarding your attempts:

    1. Switched from shallowMount to mount

    Custom elements must be explicitly registered by your own code, and mount isn't going to do that for you.

    1. Register globally using Vue.component(rux-toggle, RuxToggle)

    RuxToggle from @astrouxds/rux-toggle is a LitElement, which does not meet the requirements of a Vue component definition that Vue.component() expects.

    1. Added Vue.config.productionTip = false to jest setup

    That merely disables a browser console warning about using the developent build in production, and has nothing to do with custom elements or component registration. Perhaps you meant to use Vue.config.ignoredElements = ['rux-toggle'], which would mute the warning about unknown custom elements (this is actually unnecessary in unit tests), but it does not register the custom element.

    Solution

    To properly use rux-toggle in your tests:

    1. Create a Jest setup file that registers rux-toggle. Importing it is enough to do that, as the custom element registration happens as a side effect.

      // tests/jest.setup.js
      import '@astrouxds/rux-toggle'
      
    2. Configure Jest to use the setup file:

      // jest.config.js
      module.exports = {
        setupFiles: ['<rootDir>/tests/jest.setup.js'],
      }
      
    3. Configure Jest to transpile @astrouxds/rux-toggle:

      // jest.config.js
      module.exports = {
        transformIgnorePatterns: ['/node_modules//(?!@astrouxds/rux-toggle)'],
      }
      
    4. Your project uses jest 24.9.0, which depends on jsdom 15, which does not support Custom Elements. To enable Custom Elements in this version of Jest, install jest-environment-jsdom-sixteen:

      npm install -D jest-environment-jsdom-sixteen
      
    5. Configure Jest to use that test environment:

      // jest.config.js
      module.exports = {
        testEnvironment: 'jest-environment-jsdom-sixteen',
      }
      
    6. Update your test to read the checked attribute with attributes('checked'), and verify the value is "true" (attributes are string values):

      it("test toggle default", () => {
        const result = wrapper.find('#app-toggle').attributes('checked');
        expect(result).toEqual('true');
      })
      

    GitHub PR