>

使用说明,之单元测试【必发88官网】

- 编辑:www.bifa688.com -

使用说明,之单元测试【必发88官网】

时间: 2019-12-28阅读: 76标签: 测试

安装

原文:-testing-handbook/testing-vuex.html

npm

万般来讲 Vue 组件会在偏下位置和 Vuex 发生互相:

npm install vuex --save

commit 一个 mutationdispatch 一个 action通过$store.state或 getters 访问 state

在叁个模块化的打包系统中,您必得显式地因而Vue.use(State of Qatar来设置Vuex。

要针对 Vuex 进行的单元测量试验,都是基于 Vuex store 的当前 state 来断言组件行为是不是平常的;并无需知道 mutators、actions 或 getters 的切切实实贯彻。

import Vue from 'vue'

1 - 测试 Mutations

import Vuex from 'vuex'

由于 mutations 正是不感觉奇的 JavaScript 函数,所以单独地质衡量试它们特别轻便。

Vue.use(Vuex)

mutations 平常服从一套方式:获得局地数目,大概张开一些管理,然后将数据赋值给 state。

Vuex是叁个专为Vue.js应用程序开拓的景况管理格局,集中式存款和储蓄管理应用的持有组件状态。

举例说多个ADD_POSTmutation 的概述如下:一旦被完成,它将从 payload 中获取一个post对象,并将post.id增加到state.postIds中;它也会将特别 post 对象以post.id为 key 加多到state.posts对象中。那便是在应用中应用 Vuex 的多个普通的格局。

意况管理包涵以下多少个部分景况:

大家将使用 TDD 进行付出。mutation 是这么开首的:

state驱动应用的数据源;

export default { SET_POST(state, { post }) { }}

view以生命方式将state映射到视图。

千帆竞发写测量试验,并让报错新闻指点我们的花销:

actions响应在view上的顾客书输入引致的意况变化。

import mutations from "@/store/mutations.js"describe("SET_POST", () = { it("adds a post to the state", () = { const post = { id: 1, title: "Post" } const state = { postIds: [], posts: {} } mutations.SET_POST(state, { post }) expect(state).toEqual({ postIds: [1], posts: { "1": post } }) })})

帮衬大家管理分享状态,中山高校型单页面应用。

以yarn test:unit运营测量试验将时有发生以下错误音信:

state

FAIL tests/unit/mutations.spec.js SET_POST › adds a post to the state expect(received).toEqual(expected) Expected value to equal: {"postIds": [1], "posts": {"1": {"id": 1, "title": "Post"}}} Received: {"postIds": [], "posts": {}}

纯净状态树,Vuex使用单一状态树用叁个目的就隐含了百分百的使用层级状态。

让大家从将post.id参预state.postIds起头:

在Vue组件中得到Vuex状态。

export default { SET_POST(state, { post }) { state.postIds.push(post.id) }}

由于Vuex的动静存款和储蓄是响应式的,从store实例中读取状态最简便的方法

现在yarn test:unit会产生:

不怕在总计属性中回到某些状态。

Expected value to equal: {"postIds": [1], "posts": {"1": {"id": 1, "title": "Post"}}}Received: {"postIds": [1], "posts": {}}

创造多个Counter组件

postIds看起来蛮好了。以后大家只须求将 post 参加state.posts。限于 Vue 反应式系统的做事措施大家敬敏不谢轻巧地写成post[post.id] = post来增多post。基本上,你必要利用Object.assign或...操作符创立一个新的靶子。此处我们将应用...操作符将 post 赋值到state.posts:

const Counter = {

export default { SET_POST(state, { post }) { state.postIds.push(post.id) state.posts = { ...state.posts, [post.id]: post } }}

template: '

测试通过!

{{ count }}

2 - 测试 actions

'

单身地质衡量试 actions 是极其轻巧的。那和单独地质度量试 mutations 极其之相通。

computed: {

一律的,大家会遵照叁个常见的 Vuex 格局创制二个 action:

count (){

发起八个向 API 的异步诉求

return store.state.count

对数码进行部分拍卖(可选)

根据 payload 的结果 commit 一个 mutation

}

此处有一个认证action,用来将 username 和 password 发送到外界 API 以检讨它们是还是不是合作。然后其验明正身结果将被用来通过 commit 叁个SET_AUTHENTICATEDmutation 来更新 state,该 mutation 将表明结果作为 payload。

}

import axios from "axios"export default { async authenticate({ commit }, { username, password }) { const authenticated = await axios.post("/api/authenticate", { username, password }) commit("set_authenticated", authenticated) }}

每便store.state.count变化的时候,都会再一次求取总括属性,何况触发更

action 的测验应该断言:

新相关的DOM

是或不是采取了不错的 API 端?

Vuex通过store选项,提供了一种体制将情状从根组件『注入』到每叁个子零器件

payload 是或不是科学?

中(需调用Vue.use(Vuex)):

听他们说结果,是不是有正确的 mutation 被 commit

const app = new Vue({

让我们进行下去并编辑测量试验,并让报错新闻指点我们。

el:'#app',

2.1 - 编写测量检验

//把store对象提要求“store”选项,那足以把store的实例注入全部的子组件

describe("authenticate", () = { it("authenticated a user", async () = { const commit = jest.fn() const username = "alice" const password = "password" await actions.authenticate({ commit }, { username, password }) expect(url).toBe("/api/authenticate") expect(body).toEqual({ username, password }) expect(commit).toHaveBeenCalledWith( "SET_AUTHENTICATED", true) })})

store,

因为axios是异步的,为担保 Jest 等到测验完了后才施行,大家须求将其表明为async并在其后await那么些actions.authenticate的调用。不然的话(译注:即假设不使用 async/await 而单独将 3 个expect断言放入异步函数的then(State of Qatar中)测量试验会早于expect断言实现,何况大家将获得一个常绿的 -- 一个不会停业的测量试验。

components: {Counter},

运营以上测验会给我们上面包车型大巴报错音讯:

template: '

FAIL tests/unit/actions.spec.js authenticate › authenticated a user SyntaxError: The string did not match the expected pattern. at XMLHttpRequest.open (node_modules/jsdom/lib/jsdom/living/xml) at dispatchXhrRequest (node_modules/axios/lib/adapters/xhr.js:45:13) at xhrAdapter (node_modules/axios/lib/adapters/xhr.js:12:10) at dispatchRequest (node_modules/axios/lib/core/dispatchRequest.js:59:10)

'

本条怪诞来自axios的某处。大家呼吁了多个对/api...的呼吁,并且因为我们运营在叁个测量检验情况中,所以而不是真有一个服务器在拍卖央求,那就引致了错误。大家也从没定义url或body-- 大家将要减轻掉axios错误后做那三个。

})

因为运用了 Jest,大家得以用jest.mock轻巧地 mock 掉 API 调用。咱们将用三个 mock 版本的axios替代真实的,使大家能更加多地垄断(monopoly卡塔尔(قطر‎其行为。Jest 提供了ES6 Class Mocks,极其适于 mockaxios。

通过在根实例中登记store选项,该store实例会注册入到跟组件下的保有

axios的 mock 看起来是那样的:

子组件,且子组件能因此this.$store访问到。更新counter的实现:

let url = ''let body = {}jest.mock("axios", () = ({ post: (_url, _body) = { return new Promise((resolve) = { url = _url body = _body resolve(true) }) }}))

const Counter = {

大家将url和body保存到了变量中以便断言正确的日子端点选择了科学的 payload。因为大家不想已毕真正的端点,用三个明亮 resolve 的 promise 模拟二遍得逞的 API 调用就够了。

template : '

yarn unit:pass现在测量检验通过了!

{{ count }}

2.2 - 测试 API Error

',

笔者只是测量试验过了 API 调用成功的状态,而测验全部产出的可能意况也是人命关天的。让我们编辑四个测量试验应对发出错误的场所。本次,大家将先编制测量检验,再补全实现。

computed: {

测验能够写成这么:

count this.$store.state.count

it("catches an error", async () = { mockError = true await expect(actions.authenticate({ commit: jest.fn() }, {})) .rejects.toThrow("API Error occurred.")})

}

大家要找到一种免强axiosmock 抛出乖谬的办法。正如mockError变量代表的那么。将axiosmock 更新为:

}

let url = ''let body = {}let mockError = falsejest.mock("axios", () = ({ post: (_url, _body) = { return new Promise((resolve) = { if (mockError) throw Error() url = _url body = _body resolve(true) }) }}))

mapState扶植函数

只有当三个 ES6 类 mock 功用域外的(out-of-scope)变量以mock为前缀时,Jest 才允许访谈它。现在我们差不离地赋值mockError = true然后axios就能够抛出荒唐了。

当二个零件必要获得两个情形时候,将那些意况都宣称为总结属性会稍为冗余。

运转该测验给我们这一个报错:

为了消除这几个标题,大家能够使用mapState支持函数援助大家生成总括属性。

FAIL tests/unit/actions.spec.js authenticate › catchs an error expect(function).toThrow(string) Expected the function to throw an error matching: "API Error occurred." Instead, it threw: Mock error

//在独立营造的本子中帮衬函数为Vuex.mapState

中标的抛出了叁个错误... 却不要大家意在的不胜。更新authenticate以高达目标:

import { mapState } from 'vuex'

export default { async authenticate({ commit }, { username, password }) { try { const authenticated = await axios.post("/api/authenticate", { username, password }) commit("SET_AUTHENTICATED", authenticated) } catch (e) { throw Error("API Error occurred.") } }}

export default {

今昔测验通过了。

computed: mapState({

2.3 - 改良

//箭头函数能够使代码更简短

昨天你驾驭如何独立地质度量试 actions 了。起码还或许有一项潜在的修正可感到之,那正是将axiosmock 实现为叁个manual mock(-mocksState of Qatar。那蕴涵在node_modules的同级成立五个__mocks__目录并在其间贯彻mock 模块。Jest 将机关使用__mocks__中的 mock 落到实处。在 Jest 站点和因特互连网有多量什么样做的事例。

count: state => state.count,

3 - 测试 getters

//传字符串参数‘count’等同于‘state => state.count’

getters 也是习以为常的 JavaScript 函数,所以单独地质衡量试它们等同特别轻松;所用本事雷同于测量检验 mutations 或 actions。

countAlias: 'count',

小编们思虑一个用多少个 getters 操作三个 store 的案例,看起来是那样的:

//为了可以接收‘this’获取局地情形,必得运用正规函数

const state = { dogs: [ { name: "lucky", breed: "poodle", age: 1 }, { name: "pochy", breed: "dalmatian", age: 2 }, { name: "blackie", breed: "poodle", age: 4 } ]}

countPlusLocalState(state) {

对于 getters 大家将测量检验:

return state.count this.localCount

poodles: 拿到富有poodles

}

poodlesByAge: 获得富有poodles,并收受三个年龄参数

})

3.1 - 创建 getters

}

首先,创建 getters。

当映射的精兵简政属性的名目与state的子节点名称一致时,我们也

export default { poodles: (state) = { return state.dogs.filter(dog = dog.breed === "poodle") }, poodlesByAge: (state, getters) = (age) = { return getters.poodles.filter(dog = dog.age === age) }}

能够给mapState传贰个字符串数组。

并从未什么样非常令人兴奋的 -- 记住 getter 能够承当任何的 getters 作为第叁个参数。因为大家已经有多个poodlesgetter 了,能够在poodlesByAge中复用它。通过在poodlesByAge再次回到三个担任参数的函数,我们能够向 getters 中流传参数。poodlesByAgegetter 用法是那般的:

computed: mapState([

computed: { puppies() { return this.$store.getters.poodlesByAge(1) }}

//映射this.count为store.state.count

让大家从测验poodles最先吧。

'count'

3.2 - 编写测量试验

])

由于三个 getter 只是贰个抽出一个state对象作为第2个参数的 JavaScript 函数,所以测验起来特轻易。小编将把测量试验写在getters.spec.js文件中,代码如下:

零零部件依然保有局地情形。

import getters from "../../src/store/getters.js"const dogs = [ { name: "lucky", breed: "poodle", age: 1 }, { name: "pochy", breed: "dalmatian", age: 2 }, { name: "blackie", breed: "poodle", age: 4 }]const state = { dogs }describe("poodles", () = { it("returns poodles", () = { const actual = getters.poodles(state) expect(actual).toEqual([ dogs[0], dogs[2] ]) })})

Getters

Vuex 会自动将state传入 getter。因为大家是单身地质度量试 getters,所以还得手动传入state。除却,我们正是在测量检验一个平凡的 JavaScript 函数。

一时大家须要从store中的state中 的state中派生一些状态,列如对列表进

poodlesByAge则更有趣一点了。传入多个 getter 的第一个参数是别的getters。大家正在测验的是poodlesByAge,所以大家不想将poodles的兑现牵扯进来。我们经过 stub 掉getters.poodles取代他。那将给我们对测量检验更细粒度的主宰。

行过滤并酌量。

describe("poodlesByAge", () = { it("returns poodles by age", () = { const poodles = [ dogs[0], dogs[2] ] const actual = getters.poodlesByAge(state, { poodles })(1) expect(actual).toEqual([ dogs[0] ]) })})

computed: {

分歧于向 getter 传入真实的poodles(译注:刚刚测量试验过的另七个getter),我们传入的是四个它或然回到的结果。因为事情未发生前写过二个测量检验了,所以大家领略它是做事健康的。那使得大家把测量试验逻辑单独集中于poodlesByAge。

doneTodosCount() {

async的 getters 也是可能的。它们得以因此和测验asyncactions 的均等本领被测量试验。

return this.$store.state.todos.filter(todo => todo.done).length

4 - 测验组件内的 Vuex:state 和 getters

}

今昔来寻访 Vuex 在事实上组件中的表现。

}

4.1 - 使用createLocalVue测试$store.state

Vuex允许大家再store中定义getters (能够感觉是stroe的计量属性卡塔尔(قطر‎

在三个惯常的 Vue 应用中,我们运用Vue.use(Vuex卡塔尔(قطر‎来设置 Vuex 插件,并将三个新的 Vuex store 传入 app 中。假使大家也在三个单元测量试验中做相符的事,那么,全体单元测验都得选用那多少个Vuex store,即便测量检验中一贯用不到它。vue-test-utils提供了贰个createLocalVue方法,用来为测量试验提供二个有时Vue实例。让大家看看哪些运用它。首先,是四个基于 store 的 state 渲染出二个 username 的ComponentWithGetters组件。

Getters接受state作为其首先个参数。

template div div  {{ username }} /div /div/templatescriptexport default { name: "ComponentWithVuex", data() { return { username: this.$store.state.username } }}/script

const store = new Vuex.Store({

我们能够动用createLocalVue创造叁个一时半刻的Vue实例,并用其设置 Vuex。而后我们将一个新的store传入组件的加载选项中。完整的测量检验看起来是如此的:

state: {

import Vuex from "vuex"import { shallowMount, createLocalVue } from "@vue/test-utils"import ComponentWithVuex from "@/components/ComponentWithVuex.vue"const localVue = createLocalVue()localVue.use(Vuex)const store = new Vuex.Store({ state: { username: "alice" }})describe("ComponentWithVuex", () = { it("renders a username using a real Vuex store", () = { const wrapper = shallowMount(ComponentWithVuex, { store, localVue }) expect(wrapper.find(".username").text()).toBe("alice") })})

todos:[

测量检验通过。创设三个新的localVue实例引进了有的旗帜文件(boilerplate),並且测验也十分短。假诺您有相当多接纳了 Vuex store 的零器件要测量试验,叁个代表情势是行使mocks加载选项,用以简化 store 的 mock。

{id:1, text: '...' ,done: true},

4.2 - 使用三个 mock 的 store

{id:2,text:'...',done: false}

经过利用mocks加载选项,能够 mock 掉全局的$store对象。那意味着你无需利用createLocalVue,或创办贰个新的 Vuex store 了。使用此项技能,以上测验能够重写成这么:

]

it("renders a username using a mock store", () = { const wrapper = shallowMount(ComponentWithVuex, { mocks: { $store: { state: { username: "alice" } } } }) expect(wrapper.find(".username").text()).toBe("alice")})

},

自身个人更爱好这种完毕。全体必需的数目被声称在测验之中,相同的时候它也更紧密一点儿。当然二种技能都很有用,并从未哪一种越来越好哪一种更差之分。

getters: {

4.3 - 测试getters

doneTodos: state => {

应用上述技艺,getters相符轻易测量试验。首先,是用来测量检验的组件:

return state.todos.filter(todo=> todo.done)

template div  {{ fullname }} /div/templatescriptexport default { name: "ComponentWithGetters", computed: { fullname() { return this.$store.getters.fullname } }}/script

}

我们想要断言组件精确地渲染了客户的fullname。对于该测量检验,大家不关注fullname来自何方,组件渲染正常就能够。

}

先看看用诚实的 Vuex store 和createLocalVue,测验看起来是那样的:

})

const localVue = createLocalVue()localVue.use(Vuex)const store = new Vuex.Store({ state: { firstName: "Alice", lastName: "Doe" }, getters: { fullname: (state) = state.firstName   " "   state.lastName }})it("renders a username using a real Vuex getter", () = { const wrapper = shallowMount(ComponentWithGetters, { store, localVue }) expect(wrapper.find(".fullname").text()).toBe("Alice Doe")})

Getters会暴光为store.getters对象:

测验很紧密 -- 唯有两行代码。可是也引进了累累装置代码 -- 大家基本上海重机厂建了 Vuex store。二个代替方式是引进有着真正 getters 的实际的 Vuex store。那将引进测试中的另一项重视,当开辟二个大意系时,Vuex store 大概由另一个人程序猿开荒,也许有可能未有落到实处。

store.getters.doneTodos // [{id:1,text: '...',done:true}]

让自家看看使用mocks加载选项编写测量试验的意况:

Getter也得以选用其他getters作为第贰个参数:

it("renders a username using computed mounting options", () = { const wrapper = shallowMount(ComponentWithGetters, { mocks: { $store: { getters: { fullname: "Alice Doe" } } } }) expect(wrapper.find(".fullname").text()).toBe("Alice Doe")})

getters: {

以往全方位所需的数目都含有在测量试验中了。太棒了!笔者特心仪那一个,因为测量试验是全富含的(fully contained),理解组件应该做怎么样所需的具有知识都都包蕴在测量试验中。

doneTodosCount: (state,getters) => {

运用computed加载选项,我们居然能让测量检验变得更简便易行。

return getters.doneTodos.length

4.4 - 用computed来模拟 getters

}

getters 平日棉被服装进在computed属性中。请深深记住,这一个测量试验正是为着在给定 store 中的当前 state 时,确定保证组件行为的不利。大家不测量检验fullname的兑现或是要瞧瞧getters是不是职业。那表示大家得以总结地更替掉实在 store,或接纳computed加载选项 mock 掉 store。测验能够重写为:

}

it("renders a username using computed mounting options", () = { const wrapper = shallowMount(ComponentWithGetters, { computed: { fullname: () = "Alice Doe" } }) expect(wrapper.find(".fullname").text()).toBe("Alice Doe")})

store.getters.doneTodosCount  // -> 1

那比以前多少个测量检验更轻巧了,况兼照旧发挥了组件的用意。

大家可相当的轻易的在其他组件中应用

4.5 -mapState和mapGetters辅辅助选举项

computed: {

上述本领都能与 Vuex 的mapState和mapGetters辅助选项结合起来职业。大家能够将ComponentWithGetters更新为:

doneTodosCount() {

import { mapGetters } from "vuex"export default { name: "ComponentWithGetters", computed: { ...mapGetters([ 'fullname' ]) }}

return this.$store.getters.doneTodosCount

测量试验依然通过。

}

5 - 测量试验组件内的 Vuex:mutations 和 actions

}

恰巧探讨过测验使用了$store.state和$store.getters的零件,这两个都用来将近年来事态提供给组件。而当断言叁个零零件精确commit 了叁个 mutation 或 dispatch 了一个 action 时,大家真正想做的是断言$store.commit和$store.dispatch以准确的管理函数(要调用的 mutation 或 action)和 payload 被调用了。

mapGetters扶助函数

要达成那几个也是有二种刚才提起的点子。一种是籍由createLocalVue使用贰个当真的 Vuex store,另一种是运用叁个 mock store。让大家再一次审视它们,这一次是在 mutations 和 actions 的语境中。

mapGetters协助函数仅仅是store中的getters映射到有的计算属性。

  1. 1 - 创制组件

import {mapGetter} form 'vuex'

在这里些事例里,大家将测量试验贰个ComponentWithButtons组件:

export default {

template div button @click="handleCommit" Commit /button button @click="handleDispatch" Dispatch /button button @click="handleNamespacedDispatch" Namespaced Dispatch /button /div/templatescriptexport default { name: "ComponentWithButtons", methods: { handleCommit() { this.$store.commit("testMutation", { msg: "Test Commit" }) }, handleDispatch() { this.$store.dispatch("testAction", { msg: "Test Dispatch" }) }, handleNamespacedDispatch() { this.$store.dispatch("namespaced/very/deeply/testAction", { msg: "Test Namespaced Dispatch" }) } }}/script

computed: {

5.2 - 用一个当真的 Vuex store 测量检验 mutation

//使用对象进行运算符将getters混入

让我们先来编排三个测量检验 mutation 的ComponentWithButtons.spec.js。请牢牢记住,大家要证实两件事:

...mapGetters([

正确的 mutation 是否被 commit 了?

‘doneTodosCount’,

payload 正确吗?

'anotherGetter'

我们将应用createLocalVue以制止污染全局 Vue 实例。

])

import Vuex from "vuex"import { createLocalVue, shallowMount } from "@vue/test-utils"import ComponentWithButtons from "@/components/ComponentWithButtons.vue"const localVue = createLocalVue()localVue.use(Vuex)const mutations = { testMutation: jest.fn()}const store = new Vuex.Store({ mutations })describe("ComponentWithButtons", () = { it("commits a mutation when a button is clicked", async () = { const wrapper = shallowMount(ComponentWithButtons, { store, localVue }) wrapper.find(".commit").trigger("click") await wrapper.vm.$nextTick() expect(mutations.testMutation).toHaveBeenCalledWith( {}, { msg: "Test Commit" } ) })})

}

专心测验被标志为await并调用了nextTick。

}

上面包车型地铁测验中有超多代码 -- 即便并不曾什么让人欢腾的专门的学问时有发生。大家创设了四个localVue并 use 了 Vuex,然后创造了二个 store,传入贰个 Jest mock 函数 (jest.fn(卡塔尔卡塔尔国替代testMutation。Vuex mutations 总是以三个参数的款式被调用:第八个参数是现阶段 state,第二个参数是 payload。因为我们并不曾为 store 表明任何 state,大家预料它被调用时首先个参数会是一个空对象。首个参数预期为{ msg: "Test Commit" },也正是硬编码在组件中的那样。

若是您想讲三个getter属性另取名字,使用对象性时

有广大范例代码要去写,但那是个表明组件行为正确性的适用而有效的措施。另一种替代方式mock store 须求的代码越来越少。让大家来探视哪些以这种方式编写多个测量试验并断言testAction被 dispatch 了。

mapGetters({

5.3 - 用一个 mock store 测试 action

//映射this.doneCount为store.getters.doneTodosCount

让大家来看看代码,然后和前面包车型大巴测验类比、相比一下。请牢牢记住,大家要验证:

doneCount: 'doneTodosCount'

正确的 action 被 dispatch 了

})

payload 是健康的

Mutations

it("dispatches an action when a button is clicked", async () = { const mockStore = { dispatch: jest.fn() } const wrapper = shallowMount(ComponentWithButtons, { mocks: { $store: mockStore } }) wrapper.find(".dispatch").trigger("click") await wrapper.vm.$nextTick() expect(mockStore.dispatch).toHaveBeenCalledWith( "testAction" , { msg: "Test Dispatch" })})

更正Vuex的store中的状态的独步天下方法正是交给mutation Vuex中的mutation

那比前一个例子要紧密多了。未有localVue、未有Vuex-- 分歧于在前八个测验中大家用testMutation: jest.fn(卡塔尔mock 掉了commit后会触发的函数,此番咱们实在 mock 了dispatch函数自己。因为$store.dispatch只是二个通常的 JavaScript 函数,大家有力量做到那一点。而后大家断言第二个参数是不易的 action 管理函数名testAction、第三个参数 payload 也没有错。大家不关心实际爆发的 -- 那能够被单独地质度量试。本次测量检验的目标正是轻易地表明单击七个开关会 dispatch 精确的带 payload 的 action。

可怜相近于事件,每一个mutation都有叁个字符串的 事件类型 和回调函数。那么些

行使真实的 store 或 mock store 全凭个人喜好。都以不利的。主要的业务是你在测量检验组件。

回调函数正是大家实际张开状态改善之处。何况她会接收state作为第一个参数。

5.4 - 测验二个 Namespaced Action (或 Mutation卡塔尔

const store = new Vue.Store({

其多少个也是最后的例子体现了另一种测量检验贰个 action 是还是不是被以科学的参数 dispatch (或是 mutation 被 commit)的主意。那构成了上述切磋过的两项技艺-- 二个实际的Vuexstore,和一个 mock 的dispatch方法。

state: {

it("dispatch a namespaced action when button is clicked", async () = { const store = new Vuex.Store() store.dispatch = jest.fn() const wrapper = shallowMount(ComponentWithButtons, { store, localVue }) wrapper.find(".namespaced-dispatch").trigger("click") await wrapper.vm.$nextTick() expect(store.dispatch).toHaveBeenCalledWith( 'namespaced/very/deeply/testAction', { msg: "Test Namespaced Dispatch" } )})

count: 1

遵照大家感兴趣的模块,从创立叁个 Vuex store 起头。作者在测量试验之中宣称了模块,但在切实地工作 app 中,你大概需求引进组件注重的模块。其后大家把dispatch方法替换为贰个jest.fnmock,并对它做了断言。

},

  1. 总结

mutations: {

mutations和getters都只是惯常的 JavaScript 函数,它们得以、也应当,被区分于主 Vue 应用而单独地质衡量试

inctement (state) {

当单独地质度量试getters时,你须求手动传入 state

state.count

一经一个 getter 使用了别样 getters,你应当用相符期望的回到结果 stub 掉前面一个。那将给大家对测量检验越来越细粒度的垄断(monopoly卡塔尔(قطر‎,并令你聚集于测量试验中的 getter

}

测验三个 action 时,可以行使 Jest ES6 class mocks,并应当同一时间测量检验其成功和破产的气象

}

能够接收createLocalVue和实际 Vuex store 测量检验$store.state和getters

})

能够使用mocks加载选项 mock 掉$store.state和getters等

当接触四个项目为increment的mutation时,调用此函数。”要提醒叁个

能够采用computed加载选项以设置 Vuex getter 的指望值

mutation handler,你必要以相应的type调用store.commit方法

能够一向 mock 掉 Vuex 的 API (dispatch和commit卡塔尔(قطر‎

store.commit('increment')

能够透过二个 mock 的dispatch函数使用三个真诚的 Vuex store

付出载荷(Payload卡塔尔(قطر‎

--End--

您能够向store.commit传入额外的参数,即mutation的负载:

探究关心大伙儿号:fewelife

mutations: {

increment (state, n) {

state.count = n

}

}

store.commit('increment', 10)

在抢先三分之一情形下,载荷应该是一个指标,那样能够分包四个字段而且记录mutation会更易读。

mutations: {

increment (state,payload) {

state.count = payload.amount

}

}

store.commit('increment', {

amount:10

})

对象风格的交付格局

付给mutation的另一种办法直接使用带有type属性的目的:

store.commit({

type: 'increment',

amount:10

})

当使用对象风格的交给方式,整个对象作为载荷传给mutation函数,由此handler保持不改变:

mutations: {

increment (state, payload) {

state.count = payload.amount

}

}

Mutations需据守vue的响应准绳

既然Vuex的store中的状态是响应式的,那么当大家转移状态时,监视状态的vue更新,那也意味值Vue中的mutation也须要与利用Vue同样遵循一些注意事项。

1.最佳提前在你的store中开始化好全部的所急需的习性。

2.当必要在对象上付出新属性时,你应有利用

Vue.set(obj, 'newProp', 123)

应用新对象替代老对象state.obj= {...state.obj ,newProp: 123}

选拔常量代替Mutation事件类型

选择常量代替mutation事件类型在各样Flux完毕中是很宽泛的形式

export const SOME_MUTATION = 'SOME_MUTATION';

import Vuex from 'vuex'

import {SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({

state:{...}

mutations: {

//大家可以利用ES二〇一五风格的估摸属性命名意义来使用贰个常量作为函数名

[SOME_MUTATION] (state) {

//  mutate state

}

}

})

mutation必需是手拉手函数

一条注重的标准是念念不要忘记mutation必需是一道函数。

mutations: {

someMutation (state) {

api.callAsyncMethod(() => {

state.count

})

}

}

在组件中提交Mutations

您能够在组件中使用this.$store.commit('xxx'State of Qatar提交mutation,大概使应用mapMutations辅助函数将创立中的methods映射为store.commit调用(必要在根节点注入store卡塔尔国

import {mapMutations} from 'vuex'

expor default {

methods: {

mapMutations([

methods: {

mapMutations([

'increment'  //映射this.increment()为this.$store.commit('increment')

]),

mapMutations({

add: 'increment'  //映射this.add()为this.$store.commit('increment')

})

}

])

}

}

Actions

在mutation中混异步调用会促成你的前后相继很难调节和测量试验。

Actions

Action肖似于mutation,分裂在于。

Action提交的是mutation ,并非直接退换状态。

Action能够包含自由异步操作。

注册三个简短的action

const store = new Vuex.Store({

state: {

count:0

},

mutations: {

increment (state) {

state.count

}

},

actions: {

increment (context){

context.commit('increment')

}

}

})

Action函数选取七个与store实例具有相符方法和品质的context对象,由此你能够调用context.commit提交二个mutation,恐怕通过context.state和

context.getters来得到state和getters当大家在其后介绍到Modules时,

你就领悟context对象为何不是store实例自己了。

actions: {

increment({commit}){

commit('increment')

}

}

分发Action

Action通过store.dispatch方法触发:

store.dispatch('increment')

大家得以在action内部实践异步操作。

actions: {

incrementAsync({commit}){

setTimeout(() => {

commit('increment')

},1000)

}

}

Actions协助雷同的负荷形式和目的方式张开分发

//以载重方式分发

store.dispatch('incrementAsync',{

amount:10

})

//以指标格局分发

store.dispatch({

type: 'incrementAsync',

amount:10

})

在组件中分发Action

你在组件中选用this.$store.dispatch('xxx'卡塔尔分发action,恐怕利用map Actions协助函数将零零器件的methods映射为store.dispatch调用

import {mapActions } from 'vuex'

export default{

methods:([

'increment'  //映射this.increment()为this.$store.dispatch('increment')

])

mapActions({

add: 'inctement'    //映射this.add()为this.$store.dispatch('increment')

})

}

组合Actions

Action平时是异步的,那么如何知道action几时截止。

您须要明白store.dispatch可以拍卖被处触发的action的回调函数重回的Promise

何况store.dispatch照旧重临Promise

actions: {

actionA({commit}){

return new Promise((resolve)=>{

setTimeout (() => {

commit('someMutation')

resolve()

},1000)

})

}

}

今昔您能够

store.dispatch('actionA').then(()=>{

//...

})

在另贰个action中也得以

actions: {

actionB({dispath,commit}){

return dispatch('actionA').then(() => {

commit('someOtherMutation')

})

}

}

大家选择async/ await

//假如getData(State of Qatar和getOther(State of Qatar重回的是三个Promis

actions:{

async actionA ({commit}){

commit('gotData',await getData())

},

async actionB({dispatch,commit}){

await dispatch('actionA')  //等待actionA完成

commit('goOtherData', await getOtherData())

}

}

Modules

采纳单一状态树,当应用变的超级大的时候,store对象会变的重合不堪。

Vuex允许大家将store分割到模块。每三个模块都有自身的state, mutation,action, getters,以致是嵌套子模块从上到下实行近似的撤销合并。

const moduleA = {

state: {...},

mutations: {...}

actions: {...}

getters:{...}

}

const moduleA = {

state: {...},

mutations: {...}

actions: {...}

}

const store = new Vuex.Store({

modules: {

a:moduleA,

b:moduleB

}

})

store.state.a   // -> moduleA的状态

store.state.b // -> moduleB的状态

模块的有个别情状

对于模块内部的mutation和getter,选拔的第四个参数是模块的一部分情状。

const moduleA = {

state: {count:0},

mutations: {

increment (state) {

//  state模块的部分情况

state.count

}

},

getters: {

doubleCount (state) {

return state.count * 2

}

}

}

同一对于模块内部的action, context.state是一些景况,根节点的窗台石context.rootState:

const moduleA = {

actions: {

incrementIfOddOnRootSum ({state, commit ,rootState}) {

if((state.count rootState.count) %2 ===1){

commit('increment')

}

}

}

}

对此模块内部的getter,跟节点状态会作为第五个参数:

const  moduleA = {

getters: {

getters: {

sumWithRootCount (state,getters,rootState) {

return state.count rootState.count

}

}

}

}

命名空间

模块内部的action, mutation ,和getter今后还是注册在全局命名空间    那样保障了多少个模块能够响应同一mutation或action.也能够通过丰盛前缀 大概 后缀的

措施隔绝各类模块,避防冲突。

//定义getter, action ,和mutation的名目为常量,以模块名‘todo’为前缀。

export  const  DONE_COUNT = 'todos/DONE_COUNT'

export  const  FETCH_ALL =  'todos/FETCH_ALL'

export  const TOGGLE_DONE = 'todos/TOGGLE_DONE'

import * as types form '../types'

//使用增添了然前缀的称谓定义,getter, action和mutation

const todosModule = {

state : {todo: []},

getters: {

[type.DONE_COUNT]  (state) {

}

}

actions: {

[types.FETCH_ALL] (context,payload) {

}

},

mutations: {

[type.TOGGLE_DONE] (state, payload)

}

}

模块动态注册

在store创制之后,你能够使用store.registerModule方法注册模块。

store.registerModule('myModule',{})

模块的情形将是store.state.myModule.

模块动态注册效能能够使让其余Vue插件为了利用的store附加新模块

其一来划分Vuex的景况管理。

项目布局

Vuex并不限定你的代码构造。不过它规定了部分索要信守的平整:

1.施用层级的意况应该凑集到单个store对象中。

2.交由mutation是改动状态的独一情势,并且那几个进度是一齐的。

3.异步逻辑应该封装到action里面。

若果您据守上述准则,怎么样组织代码随你便。借令你的store文件太大,

只需将action、mutation、和getters分割到独门的文本

对此大型应用,大家会愿意把Vuex相关代码分割到模块中。上边是连串组织示例

├── index.html

├── main.js

├── api │

└── ... #抽取出API请求

├── components

│   ├── App.vue

│   └── ...

└── store

├── index.js     #我们构建立模型块并导出store的地点

├── actions.js        #根品级的action

├── mutations.js      #根等级的mutation

└── modules

├── cart.js       #购物网店模特块

└── products.js   #产物模块

本文由必发88官网发布,转载请注明来源:使用说明,之单元测试【必发88官网】