0

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
John Mercier
  • 1,637
  • 3
  • 20
  • 44
  • 1
    Why exactly are you importing the `RuxToggle` component in your main.js file and not in the App.vue file and add it properly to the components property of your App.vue component? – Braks Jul 26 '21 at 15:18
  • 1
    If you want to register it globally you should add `Vue.component('rux-toggle', RuxToggle)` to the main.js file. Else it makes no sense to import the component like that and ignore that eslint tells you you're doing something fishy :D – Braks Jul 26 '21 at 15:20
  • I'm not 100% sure from what I saw the imported file has `customElements.define('rux-toggle', RuxToggle);` at the bottom. I thought maybe this should be global rather than in each component that uses it. – John Mercier Jul 26 '21 at 15:24
  • Registering it globally causes a different error in the browser. `Class constructor RuxToggle cannot be invoked without 'new'" found in ---> at src/App.vue ` – John Mercier Jul 26 '21 at 15:26
  • 1
    Yeah no I'm just dumb, I actually thought the rux thing is a "normal" component but after considering your question it's obviously a web component you want to use :D Sorry for that. There is another answer to this question that I believe might solve your issue. It's right [here](https://stackoverflow.com/questions/61912836/avoid-vue-warn-when-using-custom-tags) – Braks Jul 26 '21 at 15:30
  • There aren't any issues when the app runs. I don't see the warning in the browser. It is only happening in tests where I have to assert on the component. – John Mercier Jul 26 '21 at 15:36
  • 1
    You might be able to avoid those by adding a setup file for jest (you're using jest I assume?) So add a `index.js` or `index.ts` file to your test directory or wherver. In it you'll put `Vue.config.productionTip = false;`. Then add `setupFiles: ["/tests/index.ts"]` to your jest.config.js file. – Braks Jul 26 '21 at 15:42
  • I tried that and the warnings still show. I also added to the question that the test is actually failing. I'm not sure how to get the `checked` value out of the web component. – John Mercier Jul 26 '21 at 15:50
  • Mh... that sucks. Maybe [this](https://stackoverflow.com/questions/57478484/how-to-test-custom-web-component-with-jest) can provide a solution? – Braks Jul 26 '21 at 15:53

1 Answers1

1

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

tony19
  • 125,647
  • 18
  • 229
  • 307