vue-fragment
vue-fragment copied to clipboard
Jest Snapshots - Tutorial
Vue-Fragment is a great bridge between Vue 2 and 3, however it took a lot of effort to get it to work with snapshot testing. So I'm posting this here for anyone else that needs these steps.
Here is my simple component:
<template functional>
<fragment>
<strong>{{ props.items && props.items.length || '0' }}</strong>
{{ props.label }}<template v-if="!props.items || props.items.length !== 1">s</template>
</fragment>
</template>
<script>
export default {
name: 'NItems',
props: {
items: {
type: Array,
default: undefined
},
label: {
type: String,
required: true
}
}
};
</script>
Here is my test file:
import { mount, createLocalVue } from '@vue/test-utils';
import { Fragment } from 'vue-fragment';
import NItems from '@/components/NItems.vue';
describe('NItems.vue', () => {
let localVue;
beforeEach(() => {
jest.resetModules();
jest.doMock('../../../vue.config.js', function () {
return {
pluginOptions: {
jestSerializer: {
removeComments: true,
attributesToClear: ['fragment']
}
}
};
});
localVue = createLocalVue();
});
const wrapperOptions = (items, label) => {
return {
name: 'Test', // needed to prevent recursion error message
localVue,
// import in your component and vue-fragment
components: { NItems, Fragment },
// Vue-Fragment needs a parent element to attach to, so you must wrap your component in a div
template: '<div><n-items :label="label" :items="items" /></div>',
// Set your props as arguments for the wrapperOptions and pass them in to the parent <test> component's data
data: function () {
return { items, label };
}
};
};
test('Default props', async () => {
const wrapper = mount(wrapperOptions(undefined, 'Item'));
expect(wrapper)
.toMatchSnapshot();
});
});
This example includes a doMock. This is specifically for a Jest snapshot plugin that is required for this to work.
This Jest plugin must be installed for Vue-Fragment snapshots to work
- https://github.com/tjw-lint/jest-serializer-vue-tjw
That plugin will let you apply per-test settings for tweaking your snapshots. It has many improvements over the default snapshot serializer that comes with Vue-CLI.
Without the Jest-Serializer-Vue-TJW plugin (and those settings) the snapshots will look like this:
<div>
<!--fragment#ba77906b55#head-->
<strong fragment="ba77906b55">0</strong>
Items
<!--fragment#ba77906b55#tail-->
</div>
instead of this:
<div>
<strong fragment>0</strong>
Items
</div>
where the fragment ID (ba77906b55) is randomized on every test run (thus breaking the snapshots).
Thanks for this tutorial @TheJaredWilcurt
Thanks for the idea. You could also just replace the comments and attributes with regex. I decided for this instead of adding a library to do it.
describe('Table', () => {
it('renders table', () => {
const wrapper = mount(Component)
expect(getRenderedHTML(wrapper)).toMatchSnapshot()
})
function getRenderedHTML(wrapper) {
const html = wrapper.html()
// remove vue-fragment dynamic comments and attributes
return html.replace(/<!--fragment(.*)-->/g, '').replace(/fragment="(.*?)"/g, '')
}
})