Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hmsk/jest-matcher-vue-test-utils
✨ Cute jest matchers to test Vue components with vue-test-utils
https://github.com/hmsk/jest-matcher-vue-test-utils
jest jest-matchers vue vue-test-utils
Last synced: 21 days ago
JSON representation
✨ Cute jest matchers to test Vue components with vue-test-utils
- Host: GitHub
- URL: https://github.com/hmsk/jest-matcher-vue-test-utils
- Owner: hmsk
- Created: 2018-08-16T17:55:43.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2024-10-11T13:54:08.000Z (about 1 month ago)
- Last Synced: 2024-10-11T15:44:58.106Z (about 1 month ago)
- Topics: jest, jest-matchers, vue, vue-test-utils
- Language: TypeScript
- Homepage:
- Size: 1.33 MB
- Stars: 33
- Watchers: 3
- Forks: 3
- Open Issues: 24
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# jest-matcher-vue-test-utils
[![npm](https://img.shields.io/npm/v/jest-matcher-vue-test-utils.svg?style=for-the-badge)](https://www.npmjs.com/package/jest-matcher-vue-test-utils)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/hmsk/jest-matcher-vue-test-utils/Node%20CI?style=for-the-badge)](https://github.com/hmsk/jest-matcher-vue-test-utils/actions?query=workflow%3A%22Node+CI%22)Cute matchers for [Jest](https://facebook.github.io/jest) to test Vue components with [Vue Test Utils](https://vue-test-utils.vuejs.org/).
You can write tests for Vue component/store intuitively ⚡️
```ts
it("Emits 'select' event by clicking PrimaryButton", () => {
const wrapper = shallowMount(Component);
expect(wrapper.emitted().select).toBeUndefined();
wrapper.find(PrimaryButton).vm.$emit("click");
expect(wrapper.emitted().select[0]).toBeTruthy();
});
```becomes
```ts
it("Emits 'select' event by clicking PrimaryButton", () => {
const wrapper = shallowMount(Component);
expect(() => {
wrapper.find(PrimaryButton).vm.$emit("click");
}).toEmit(wrapper, "select");
});
```And all matchers have type definition and doc 💇♂️
![190607_jest_matcher_infer](https://user-images.githubusercontent.com/85887/59101871-316fb600-88df-11e9-9ce1-54e5231c2bf6.gif)
# Installation
Get from npm:
```sh
$ npm install -D jest-matcher-vue-test-utils
```Then, register matchers on your jest process:
```js
import vueTestUtilMatchers from "jest-matcher-vue-test-utils";
expect.extend({ ...vueTestUtilMatchers });
```## Provided Matchers
### Existence on Wrapper
#### `toShow`
Assert the function shows a content on Wrapper of vue-test-utils
```js
// error-message.vue
message
...
data: function () {
return {
isError: false
}
},
methods: {
showError () {
this.isError = true;
}
}
``````js
import Component from "./error-message.vue";it("show error by showError", async () => {
return expect(async () => {
wrapper.vm.showError();
await wrapper.vm.$nextTick();
}).toShow(wrapper, "p.error"); // Passes
});
```#### `toHide`
Assert the function hides a content on Wrapper of vue-test-utils
```js
// error-message.vue
message
...
data: function () {
return {
isError: true
}
},
methods: {
hideError () {
this.isError = false;
}
}
``````js
import Component from "./error-message.vue";it("show error by showError", async () => {
return expect(async () => {
wrapper.vm.hideError();
await wrapper.vm.$nextTick();
}).toHide(wrapper, "p.error"); // Passes
});
```### Events on Wrapper
#### `toEmit` / `toEmitOnRoot`
Assert the action emits the event (with the payload optionally) on Wrapper of vue-test-utils
```js
// event.vue
Click Me
module.exports = {
methods: {
emitEvent (e) {
this.$emit("special", e);
}
}
}```
```js
import Component from "./event.vue";it("emits special event by click", () => {
const wrapper = shallowMount(Component);
expect(() => wrapper.trigger("click")).toEmit(wrapper, "special"); // Passes
expect(() => wrapper.trigger("click")).toEmit(wrapper, "special", "clicked"); // Passes
});
```Async function is supported as well.
```js
it("emits special event by click", async () => {
const wrapper = shallowMount(Component);
return expect(async () => triggersEventAsynchronously()).toEmit(wrapper, "special", "clicked"); // Passes
});
````toEmitOnRoot` inspects whether the event is emitted on `$root` of Vue instance.
#### `toHaveEmitted` / `toHaveEmittedOnRoot`
Assert the event is emitted (with the payload optionally) on Wrapper of vue-test-utils
```js
// event.vue
Click Me
module.exports = {
methods: {
emitEvent (e) {
this.$emit("special", e);
}
}
}```
```js
import Component from "./event.vue";it("emits special event by click", () => {
const wrapper = shallowMount(Component);
wrapper.trigger("click");
expect(wrapper).toHaveEmitted("special"); // Passes
expect(wrapper).toHaveEmitted("special", "clicked"); // Passes
});
````toHaveEmittedOnRoot` inspects whether the event is emitted on `$root` of Vue instance.
### Vuex actions/mutations
#### `toDispatch`
Assert the function dispatches Vuex action on the component
```js
// click-store.vue
Click Me
module.exports = {
methods: {
dispatchStore (e) {
this.$store.dispatch('awesomeAction', e);
}
}
}```
```js
import Component from "./click-store.vue";it("Dispatches the action on store by click", () => {
const wrapper = shallowMount(Component);
expect(() => {
wrapper.trigger("click");
}).toDispatch(wrapper, "awesomeAction"); // Passesexpect(() => {
wrapper.trigger("click");
}).toDispatch(wrapper, "awesomeAction", 'click'); // Passes
});
```Async function is supported as well.
```js
it("dispatches the action on store by click", async () => {
return expect(async () => {
dispatchEventAsynchronosly();
}).toDispatch(wrapper, "awesomeAction", 'click'); // Passes
});
```#### `toCommit` (TBD)
Assert the store mutation is committed
```js
// click-store.vue
Click Me
module.exports = {
methods: {
commitStore (e) {
this.$store.commit('importantMutation', e);
}
}
}```
```js
import Component from "./click-store.vue";it("Commits the mutation on store by click", () => {
const wrapper = shallowMount(Component);
expect(() => {
wrapper.trigger("click");
}).toCommit(wrapper, "importantMutation"); // Passesexpect(() => {
wrapper.trigger("click");
}).toCommit(wrapper, "importantMutation", 'click'); // Passes
});
```#### `toHaveDispatched`
Assert a component has dispatched Vuex action
```js
// click-store.vue
Click Me
module.exports = {
methods: {
dispatchStore (e) {
this.$store.dispatch('awesomeAction', e);
}
}
}```
```js
import Component from "./click-store.vue";
import { vuexPlugin } from "jest-matcher-vue-test-utils";it("Dispatches the action on store by click", () => {
const store = new Vuex.Store({
actions: dispatchStore() {},
plugins: [vuexPlugin()] // Requires adding plugin to use `toHaveDispatched` matcher
});const wrapper = shallowMount(Component, { store })
wrapper.trigger("click");
expect(wrapper).toHaveDispatched("awesomeAction"); // Passes
expect(wrapper).toHaveDispatched("awesomeAction", "click"); // Passes
});
```### Prop Validations
#### `toBeValidProps`
Assert that a prop set is valid for a component
```js
// name-require-and-fullname-is-validated-component.vue
props: {
name: {
type: String,
required: true
}
fullname: {
validator: function (val) {
return !!val && val.match(/.+\s.+/);
}
}
}
``````js
import Component from "./name-require-and-fullname-is-validated-component.vue";it("component validates props", () => {
expect(Component).toBeValidProps({ name: "required name", fullName: "Kengo Hamasaki" }); // Passes
expect(Component).toBeValidProps({ fullName: "Kengo Hamasaki" }); // Fails
expect(Component).toBeValidProps({ name: "required name", fullName: "Kengo" }); // Fails
});
```#### `toBeValidProp`
Assert that a single prop is valid for a component
```js
// name-require-component.vue
props: {
name: {
type: String,
required: true
}
}
``````js
import Component from "./name-require-component.vue";it("component validates props", () => {
expect(Component).toBeValidProp("name", "Required Name"); // Passes
expect(Component).toBeValidProp("name", null); // Fails as required
expect(Component).toBeValidProp("name", 123}); // Fails as typecheck
});
```#### `toRequireProp`
Assert that a component requires a prop
```js
// name-require-component.vue
props: {
name: {
type: String,
required: true
}
}
``````js
import Component from "./name-require-component.vue";it("component requires name prop", () => {
expect(Component).toRequireProp("name"); // Passes
expect(Component).toRequireProp("birthday"); // Fails
});
```#### `toHaveDefaultProp`
Assert that a component gives default to a prop
```js
// default-address-component.vue
props: {
address: {
type: String,
default: "Kitakyushu, Japan"
}
}
``````js
import Component from "./default-address-component.vue";it("component gives default value for address prop", () => {
expect(Component).toHaveDefaultProp("address", "Kitakyushu, Japan"); // Passes
expect(Component).toHaveDefaultProp("address", "San Francisco, US"); // Fails
});
```#### `toBeValidPropWithTypeCheck`
Assert that a component validates a prop with type
```js
// takes-zipcode-component.vue
props: {
zipcode: {
type: String
}
}
``````js
import Component from "./takes-zipcode-component.vue";it("component validates zipcode prop", () => {
expect(Component).toBeValidPropWithTypeCheck("zipcode", "94103"); // Passes
expect(Component).toBeValidPropWithTypeCheck("zipcode", 94103); // Fails
});
```#### `toBeValidPropWithCustomValidator`
Assert that a component validates a prop with custom validator
```js
// fullname-is-validated-component.vue
props: {
fullname: {
validator: function (val) {
return !!val && val.match(/.+\s.+/);
}
}
}
``````js
import Component from "./fullname-is-validated-component.vue";it("component validates fullname prop", () => {
expect(Component).toBeValidPropWithCustomValidator("fullname", "Kengo Hamasaki"); // Passes
expect(Component).toBeValidPropWithCustomValidator("fullname", "Kengo"); // Fails
});
```# Config
We can configure the matchers. Currently accepting *mountOptions* property to give options for `shallowMount` which is running in inside of matchers.
```js
import vueTestUtilMatchers, { config } from "jest-matcher-vue-test-utils";
import { createLocalVue } from "@vue/test-utils";config({
mountOptions: { localVue: createLocalVue() }
});
```# License
MIT, Copyright (c) 2018- Kengo Hamasaki