DEV Community

André Silva
André Silva

Posted on

How to mock Nuxt client-only component with Jest

Hi! This is my first post and I hope you find it useful to your day-to-day unit testing for your current project.

Problem

Let's say you are working on a Nuxt project with SSR and there's a component that you want/need to render only on the client side. This situation may arise because you need to integrate, for instance, a 3rd party application.

Fortunately, Nuxt has a neat component that does exactly that: <client-only>

As seen on the official Nuxt docs:

This component is used to purposely render a component only on client-side.

For this particular example, let's imagine you have the index page with just two components: Component A and Component B (the one you need to be rendered only on the client side).

Index page

<template>
  <div class="container">
    <div>
      <h1 class="title">
        nuxt-mock-client-only
      </h1>
      <div class="components">
        <ComponentA />
        <client-only>
          <ComponentB />
        </client-only>
      </div>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Component A

<template>
  <div class="component-a">
    <p>Hello from component A!</p>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Component B

<template>
  <div class="component-b">
    <p>Hello from component B!</p>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

You then run the generate command in order to generate the static pages and you get the following html inside the body tag:

<div data-server-rendered="true" id="__nuxt">
  <!---->
  <div id="__layout">
    <div>
      <div class="container">
        <div>
          <h1 class="title">
            nuxt-mock-client-only
          </h1>
          <div class="components">
            <div class="component-a" data-v-363149cc>
              <p data-v-363149cc>Hello from component A!</p>
            </div>
            <!---->
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Ok, cool, the client-only strategy worked flawlessly. We are only seeing the component A in the html!

But what happens when you run the unit tests? Let's try one simple test:

import { shallowMount } from '@vue/test-utils';
import Index from '@/pages';

describe('Index', () => {
  it('should match the snapshot', () => {
    const wrapper = shallowMount(Index);
    expect(wrapper.element).toMatchSnapshot();
  });
});
Enter fullscreen mode Exit fullscreen mode

Well... 😓😓

console.error node_modules/vue/dist/vue.common.dev.js:630
    [Vue warn]: Unknown custom element: <client-only> - did you register the component correctly? For recursive components, make sure to provide
 the "name" option.

    found in

    ---> <Anonymous>
           <Root>
Enter fullscreen mode Exit fullscreen mode

Oops.. jest does not recognize that client-only component.

vue-test-utils stubs to the rescue

Yeah, as the header suggests, we will use the stubs prop in order to mock this client-only component.

More about vue-test-utils config stubs here.

Having in mind that another client only rendering situation may be needed somewhere else in the project, you could create a mocked component to be used as part of your jest configuration.

Steps to do it

1) Create a setup config file, for example, setup.jest.js, under utils/tests/setup-jest.js

2) Add the following content to the newly created setup file:

import { config } from '@vue/test-utils';

// Mock Nuxt client-side component
config.stubs['client-only'] = '<div><slot /></div>';
Enter fullscreen mode Exit fullscreen mode

3) Go to your jest.config.js file and add the setupFiles prop like so:

setupFiles: ['<rootDir>/utils/tests/setup-jest.js'],
Enter fullscreen mode Exit fullscreen mode

Note: You can check more about the setupFiles here in the official docs.

Important information about step 2

For simplicity sake, I just set directly the mocked html (as a string) to the config.stubs['client-only'], but you should use the following approach (I'm saying you should simply because stubs that use strings are deprecated and will be removed from the next vue-test-utils major release):

1) Create a mock vue file - myAwesomeClientOnlyMock.vue

<template>
  <div>
    <slot />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

2) Import it inside the setup-jest.js file and use it like this:

import { config } from '@vue/test-utils';
import myAwesomeClientOnlyMock from 'wherever you saved your mocked vue file';

// Mock Nuxt client-side component
config.stubs['client-only'] = myAwesomeClientOnlyMock;
Enter fullscreen mode Exit fullscreen mode

Run the test again and the client-only component will be mocked with no issues at all ✔️

Feel free to share other ways to handle this particular situation in the comments section!

Some sources:

Latest comments (2)

Collapse
 
leonorpanas profile image
Nora Panagiotidou

Awesome! You saved me some time, thank you!

Collapse
 
alousilva profile image
André Silva

Glad I could help :)