接纳说明,之单元测验

时间:2020-03-23 01:17来源:亚洲城ca88唯一官方网站
时间: 2019-12-28阅读: 76标签: 测试 安装 原文:-testing-handbook/testing-vuex.html npm 日常性来讲 Vue 组件会在偏下方面和 Vuex 发生相互: npm install vuex --save commit 一个 mutationdispatch 一个 action通过

时间: 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(卡塔尔(قطر‎来设置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(卡塔尔国中)测量试验会早于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替代真实的,使大家能更加多地调控其作为。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对象作为第二个参数的 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,第3个参数是 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方法

亚洲城ca88唯一官方网站,能够一直 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'卡塔尔提交mutation,只怕使利用mapMutations协助函数将构建中的methods映射为store.commit调用(必要在根节点注入storeState of Qatar

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(卡塔尔重临的是叁个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   #出品模块

编辑:亚洲城ca88唯一官方网站 本文来源:接纳说明,之单元测验

关键词: 亚洲城ca88