How to add styles to jest snapshot while testing vue component? - vue.js

I had tried to use Jest for snapshot testing for Vue SFC. And I missed styles inside the generated snapshot file, only class names. Is it possible to add style rules to snapshot?
<template>
<div class="woof"></div>
</template>
<script>
import Vue from 'vue-class-component';
export default class Component extends Vue {};
</script>
<style lang="scss">
.woof {
background-color: red; // <- this part is missing inside snapshot file
}
</style>
import { shallowMount } from '#vue/test-utils';
import Component from './Component.vue';
describe('Component testing', () => {
it('looks as expected', () => {
const wrapper = shallowMount(Component);
expect(wrapper).toMatchSnapshot();
});
});

Related

is it available to call the methods where in the vue component from the plugin?

I wanted to access the vue.data or methods in the plugin.
no matter what I tried several times, it didn't work.
such as eventBus, Mixin etc...
so I'm curious about the possibility to call the methods like that.
thank you for reading this question.
here is the custom component.
<template>
<div>
<v-overlay :value="isProcessing">
<v-progress-circular indeterminate size="64"></v-progress-circular>
</v-overlay>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class ProgressCircular extends Vue {
private isProcessing: boolean;
startProcess() {
this.isProcessing = true;
}
}
</script>
and this is the plugin source.
import ProgressCircular from '#/components/ProgressCircular.vue';
import { VueConstructor } from 'vue';
import Vuetify from 'vuetify/lib';
import vuetify from './vuetify';
export default {
install(Vue: VueConstructor, options: any = {}) {
Vue.use(Vuetify);
options.vuetify = vuetify;
Vue.component('progress-circular', ProgressCircular);
Vue.prototype.$fireProgressing = function () {
// it didn't work
// I just wanted to access the method where in the Vue Component
// ProgressCircular.startProcess();
};
},
};
use the plugin syntax to extend vue like:
Vue.use({
install: Vue => {
Vue.prototype.$fireProgressing = () => {
};
}
});
or
Vue.use(YOURPLUGIN);
before you mount vue

Auto Import Components Inside A Component In Vue JS

I would like to know best practices to auto import components inside another component in vue 3.
Auto Import all components from src/components directory that start with "Base" e.g. BaseInput.vue, BaseSelect.vue etc. (Project Created Using Vue CLI)
src/views/EventCreate.vue
<template>
//template data here
</template>
<script>
import upperFirst from "lodash/upperFirst";
import camelCase from "lodash/camelCase";
//require.context function from webpack
const requireComponents = require.context(
"../components",
false,
/Base[A-Z]\w+\.(vue|js)$/
);
let comps = {};
requireComponents.keys().forEach((fileName) => {
//removing extension converting to valid component name e.g. "./base-input.vue" to "BaseInput"
const componentConfig = requireComponents(fileName);
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\/(.*)\.\w+$/, "$1"))
);
//add it to comps object with dynamic name
comps[componentName] = componentConfig.default || componentConfig;
});
export default{
components:{ ...comps }
//remaining exports here
}
</script>
<style scoped>
//style here
</style>

How to test a Vuex module action is called in Vue component mounted function?

I have a Vue component like this...
<template>
<div class="mapdiv"></div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import { mapViewModule } from "#/store/modules/MapViewModule";
#Component
export default class GeospatialMap extends Vue {
async mounted(): Promise<void> {
mapViewModule.initializeMapView(this.$el as HTMLDivElement);
}
}
</script>
<style scoped>
.mapdiv {
height: 700px;
width: 1000px;
}
</style>
...and I am trying to test that the mapViewModule.initalizeMapView function gets called, which is an action in my Vuex module.
I am using Jest and have looked to other answers such as: https://stackoverflow.com/a/66987942/2052752 but have had no luck....
import { shallowMount, createLocalVue } from "#vue/test-utils";
import Vuex from "vuex";
import GeospatialMap from "#/components/Geospatial.vue";
describe("GeospatialMap - ", () => {
const localVue = createLocalVue();
localVue.use(Vuex);
const modules = {
mapViewModule: {
state: {},
actions: {
initializeMapView: jest.fn()
},
namespaced: true
}
};
const store = new Vuex.Store({ modules });
shallowMount(GeospatialMap, { localVue, store });
it("when component created, initializes the map view", async () => {
expect(modules.mapViewModule.actions.initializeMapView).toHaveBeenCalled();
});
});
Simply put...the jest.fn says its not called in the console..
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
I'm not sure where it is going wrong. Am I not mocking the module action right?
I just want to test that the Vuex action gets called when this component is initialized.
Yep, you are not mocking the store right. And I also would like to say, that you are using the store in a little strange way but it is up to you.
I made some changes to component to make the decision of your problem as clear as possible.
<template>
<div class="mapdiv">
I am
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { mapViewModule } from '#/helpers/someModule' // there you put your path to the module
#Component
export default class GeospatialMap extends Vue {
mounted (): void {
mapViewModule.initializeMapView(this.$el as HTMLDivElement)
}
}
</script>
<style scoped>
.mapdiv {
height: 700px;
width: 1000px;
}
</style>
When your are calling mapViewModule.initializeMapView in mount hook you are just using simple js-function so I tried to mock that call by creating __mock__ folder in #/helpers/ with someModule.ts file in it with the code below:
// #/helpers/__mock__/someModule.ts
export const mapViewModule = {
initializeMapView: jest.fn((el: HTMLDivElement) => console.log('I am MOCK!!!', el))
}
Then in spec-file we must tell Jest to use our mock-file instead of real file like that:
import { shallowMount, Wrapper } from '#vue/test-utils'
import GeospatiaMap from '#/components/GeospatiaMap/GeospatiaMap.vue'
import { mapViewModule } from '#/helpers/someModule'
jest.mock('../../helpers/someModule.ts') // there you put your path to module you want to mock
let wrapper: Wrapper<GeospatiaMap & { [key: string]: any }>
describe('GeospatiaMap.vue', () => {
test('initializeMapView was called', () => {
wrapper = shallowMount(GeospatiaMap) // wrapper property is useless now but you can use it your future tests
expect(mapViewModule.initializeMapView).toBeCalled()
})
})
That's it. Hope that'd help.

Getting [Vue warn]: Unknown custom element: <b-modal> even though bootstrap-vue is registered

A BootstrapVue b-modal component in a custom Vue component loads correctly in the browser. However, when testing using mocha+mochapack, it generates a Vue warning that the b-modal element is not registered. The test is using a localVue object that has BootstrapVue registered. All other bootstrap custom elements seem to be loading correctly, and do not generate any warnings.
I tried various things, including importing BModal from 'bootstrap-vue' and registering it as a component directly, but still got the same error.
import {mount, createLocalVue} from "#vue/test-utils"
import MyCustomModal from '../js/MyCustomModal';
const localVue = createLocalVue();
import BootstrapVue from 'bootstrap-vue'
localVue.use(BootstrapVue);
describe('MyCustomModal', () => {
let wrapper = mount(MyCustomModal,{
localVue
});
it('the content is "this is the content"', () => {
expect(wrapper.find(".modal-content").text()).toEqual('this is the content');
});
});
The custom Vue component:
<template>
<b-modal>
<div class="modal-content">this is the content</div>
<b-form>
my form
</b-form>
</b-modal>
</template>
<script>
export default {
data(){
return {};
}
}
</script>
The tests run correctly and pass, but it outputs the Vue warning for the b-modal element. It doesn't output the warning for b-form.
If only shallowMount not work.
You can try stub your bootstrap's components individually.
Like this:
import {shallowMount} from "#vue/test-utils";
import { BModal, BForm } from 'bootstrap-vue';
import MyCustomModal from '../js/MyCustomModal';
describe('MyCustomModal', () => {
let wrapper = shallowMount(MyCustomModal,{
stubs: {
"b-modal": BModal,
"b-form": BForm
}
});
it('the content is "this is the content"', () => {
expect(wrapper.find(".modal-content").text()).toEqual('this is the content');
});
});
You need to set the attachToDocument: true flag when you mount b-modal (or your test component/app). It needs reference to the document/body in order for it to open (needs to add classes, etc to <body> as well as a few listeners.
import Vue from 'vue';
import {mount} from "#vue/test-utils"
import MyCustomModal from '../js/MyCustomModal';
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
describe('MyCustomModal', () => {
let wrapper = mount(MyCustomModal);
it('the content is "this is the content"', () => {
expect(wrapper.find(".modal-content").text()).toEqual('this is the content');
});
});
Try that.

How to get Component-scoped CSS WITHOUT using Single File Components?

Is it possible to get Component-scoped CSS i.e.
<style scoped>
...
</style>
WITHOUT using Single File Components?
For example, I have a component:
// MyComponent.ts
import { Vue, Component } from 'vue-property-decorator'
#Component({
template: '<h1>Not a Single File Component</h1>'
})
export default class MyComponent extends Vue {}
How can I add style such as:
h1 {
color: blue;
}
but have it scoped to MyComponent.ts only?
Since to use this component I would import it as:
import MyComponent from './MyComponent'
which is not a single file component and does not have a <style scoped>...</style>
You could do style binding like so:
#Component({
template: '<h1 :style="color: blue;">Not a Single File Component</h1>'
})
Alternatively, you could assign the h1 an id and reference the id in the stylesheet specifically.
#Component({
template: '<h1 id="whatever-this-is">Not a Single File Component</h1>'
})
...
<style>
#whatever-this-is {
color: blue;
}
</style>