www.2527.com_澳门新葡8455手机版_新京葡娱乐场网址_
做最好的网站

之单元测验Web前端,使用验证

2020-03-14 07:38 来源:未知
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] ]) })})

}

yarn unit:pass现在测试通过了!

actions: {

测试通过!

并且store.dispatch仍旧返回Promise

getters 通常被包裹在computed属性中。请记住,这个测试就是为了在给定 store 中的当前 state 时,确保组件行为的正确性。我们不测试fullname的实现或是要瞧瞧getters是否工作。这意味着我们可以简单地替换掉真实 store,或使用computed加载选项 mock 掉 store。测试可以重写为:

Vuex允许我们将store分割到模块。每一个模块都有自己的state, mutation,action, getters,甚至是嵌套子模块从上到下进行类似的分割。

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

doneCount: 'doneTodosCount'

不同于向 getter 传入真实的poodles(译注:刚刚测试过的另一个 getter),我们传入的是一个它可能返回的结果。因为之前写过一个测试了,所以我们知道它是工作正常的。这使得我们把测试逻辑单独聚焦于poodlesByAge。

context.commit('increment')

要做到这个也有两种刚才提及的方式。一种是籍由createLocalVue使用一个真正的 Vuex store,另一种是使用一个 mock store。让我们再次审视它们,这次是在 mutations 和 actions 的语境中。

import { mapState } from 'vuex'

运行该测试给我们这些报错:

getters: {

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 } }) })})

amount:10

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

在store创建之后,你可以使用store.registerModule方法注册模块。

3.2 - 编写测试

store.registerModule('myModule',{})

鉴于一个 getter 只是一个接收一个state对象作为首个参数的 JavaScript 函数,所以测试起来非常简单。我将把测试写在getters.spec.js文件中,代码如下:

Vuex是一个专为Vue.js应用程序开发 的状态管理模式,集中式存储管理应用的所有组件状态。

开始写测试,并让报错信息指引我们的开发:

actions: {

根据我们感兴趣的模块,从创建一个 Vuex store 开始。我在测试内部声明了模块,但在真实 app 中,你可能需要引入组件依赖的模块。其后我们把dispatch方法替换为一个jest.fnmock,并对它做了断言。

})

  1. 1 - 创建组件

}

poodlesByAge: 取得所有poodles,并接受一个年龄参数

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

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

actions: {

5.3 - 用一个 mock store 测试 action

return store.state.count

mutations 一般遵循一套模式:取得一些数据,可能进行一些处理,然后将数据赋值给 state。

根据结果,是否有正确的 mutation 被 commit

状态管理包含以下几个部分状态:

  1. 总结

return state.count this.localCount

可以直接 mock 掉 Vuex 的 API (dispatch和commit)

const store = new Vue.Store({

我们将使用 TDD 进行开发。mutation 是这样开头的:

commit('someOtherMutation')

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

在一个模块化的打包系统中,您必须显式地通过Vue.use()来安装Vuex。

使用上述技术,getters同样易于测试。首先,是用于测试的组件:

}

对于 getters 我们将测试:

resolve()

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

const store = new Vuex.Store({

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" } ) })})

increment (state, n) {

对数据进行一些处理(可选)

mutations: {

poodlesByAge则更有趣一点了。传入一个 getter 的第二个参数是其他getters。我们正在测试的是poodlesByAge,所以我们不想将poodles的实现牵扯进来。我们通过 stub 掉getters.poodles取而代之。这将给我们对测试更细粒度的控制。

template: '

action 的测试应该断言:

}

4.3 - 测试getters

分发Action

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) }) }}))

2.提交mutation是更改状态的唯一方法,并且这个过程是同步的。

async的 getters 也是可能的。它们可以通过和测试asyncactions 的相同技术被测试。

const Counter = {

我们考虑一个用两个 getters 操作一个 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) })})

2.当需要在对象上提交新属性时,你应该使用

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

'

让我看看使用mocks加载选项编写测试的情况:

│   └── ...

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.") } }}

安装

在这些例子里,我们将测试一个ComponentWithButtons组件:

//...

当单独地测试getters时,你需要手动传入 state

}

要针对 Vuex 进行的单元测试,都是基于 Vuex store 的当前 state 来断言组件行为是否正常的;并不需要知道 mutators、actions 或 getters 的具体实现。

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

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

回调函数就是我们实际进行状态更改的地方。并且他会接受state作为第一个参数。

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

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

让我们来看看代码,然后和前面的测试类比、对比一下。请记住,我们要验证:

doneTodosCount: (state,getters) => {

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" })})

store.dispatch('increment')

mutations和getters都只是普通的 JavaScript 函数,它们可以、也应该,被区别于主 Vue 应用而单独地测试

export const SOME_MUTATION = 'SOME_MUTATION';

2 - 测试 actions

项目结构

让我们从测试poodles开始吧。

const app = new Vue({

我们要找到一种强制axiosmock 抛出错误的方法。正如mockError变量代表的那样。将axiosmock 更新为:

组件仍然保有局部状态。

单独地测试 actions 是非常容易的。这和单独地测试 mutations 非常之相似。

mutation必须是同步函数

正确的 action 被 dispatch 了

Action函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state和

这里有一个认证action,用来将 username 和 password 发送到外部 API 以检查它们是否匹配。然后其认证结果将被用于通过 commit 一个SET_AUTHENTICATEDmutation 来更新 state,该 mutation 将认证结果作为 payload。

你可以向store.commit传入额外的参数,即mutation的载荷:

发起一个向 API 的异步请求

doneTodos: state => {

5.2 - 用一个真正的 Vuex store 测试 mutation

每次store.state.count变化的时候,都会重新求取计算属性,并且触发更

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

})

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") })})

template : '

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

为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性。

可以使用createLocalVue和真实 Vuex store 测试$store.state和getters

非常类似于事件,每个mutation都有一个字符串的 事件类型 和回调函数。这个

让我们从将post.id加入state.postIds开始:

}

测试可以写成这样:

},

2.2 - 测试 API Error

mapMutations([

可以通过一个 mock 的dispatch函数使用一个真实的 Vuex store

Actions支持同样的载荷方式和对象方式进行分发

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

export  const  DONE_COUNT = 'todos/DONE_COUNT'

搜索关注公众号:fewelife

actions: {

现在来看看 Vuex 在实际组件中的表现。

})

是否使用了正确的 API 端?

},

这比之前两个测试更简洁了,并且仍然表达了组件的意图。

Action类似于mutation,不同在于。

由于 mutations 就是普通的 JavaScript 函数,所以单独地测试它们非常容易。

computed: {

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": {}}

computed: {

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

}

4.5 -mapState和mapGetters辅助选项

const Counter = {

第三个也是最终的例子展示了另一种测试一个 action 是否被以正确的参数 dispatch (或是 mutation 被 commit)的方式。这结合了以上讨论过的两项技术 -- 一个真实的Vuexstore,和一个 mock 的dispatch方法。

})

以yarn test:unit运行测试将产生以下错误信息:

}

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

import {mapGetter} form 'vuex'

payload 是正常的

}

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

}

4.2 - 使用一个 mock 的 store

}

我们将url和body保存到了变量中以便断言正确的时间端点接收了正确的 payload。因为我们不想实现真正的端点,用一个理解 resolve 的 promise 模拟一次成功的 API 调用就够了。

}

--End--

npm

现在测试通过了。

}

使用真实的 store 或 mock store 全凭个人喜好。都是正确的。重要的事情是你在测试组件。

return state.count * 2

成功的抛出了一个错误... 却并非我们期望的那个。更新authenticate以达到目的:

1.应用层级的状态应该集中到单个store对象中。

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

Vue.use(Vuex)

这个错误来自axios的某处。我们发起了一个对/api...的请求,并且因为我们运行在一个测试环境中,所以并不是真有一个服务器在处理请求,这就导致了错误。我们也没有定义url或body-- 我们将在解决掉axios错误后做那些。

}

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")})

}

因为axios是异步的,为保证 Jest 等到测试完成后才执行,我们需要将其声明为async并在其后await那个actions.authenticate的调用。不然的话(译注:即假如不使用 async/await 而仅仅将 3 个expect断言放入异步函数的then()中)测试会早于expect断言完成,并且我们将得到一个常绿的 -- 一个不会失败的测试。

inctement (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) }}

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

测试很紧凑 -- 只有两行代码。不过也引入了很多设置代码 -- 我们基本上重建了 Vuex store。一个替代方法是引入有着真正 getters 的真实的 Vuex store。这将引入测试中的另一项依赖,当开发一个大系统时,Vuex store 可能由另一位程序员开发,也可能尚未实现。

//  state模块的局部状态

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

})

上述技术都能与 Vuex 的mapState和mapGetters辅助选项结合起来工作。我们可以将ComponentWithGetters更新为:

└── store

通过使用mocks加载选项,可以 mock 掉全局的$store对象。这意味着你不需要使用createLocalVue,或创建一个新的 Vuex store 了。使用此项技术,以上测试可以重写成这样:

getters: {

使用computed加载选项,我们甚至能让测试变得更简单。

}

我们想要断言组件正确地渲染了用户的fullname。对于该测试,我们不关心fullname来自何方,组件渲染正常就行。

当映射的计算属性的名称与state的子节点名称相同时,我们也

可以使用computed加载选项以设置 Vuex getter 的期望值

'count'

让我们先来编写一个测试 mutation 的ComponentWithButtons.spec.js。请记住,我们要验证两件事:

}

payload 是否正确?

})

我们将使用createLocalVue以避免污染全局 Vue 实例。

‘doneTodosCount’,

测试通过。创建一个新的localVue实例引入了一些样板文件(boilerplate),并且测试也很长。如果你有好多使用了 Vuex store 的组件要测试,一个替代方法是使用mocks加载选项,用以简化 store 的 mock。

actions: {

注意测试被标记为await并调用了nextTick。

return state.count rootState.count

3.1 - 创建 getters

├── api │

让我们进行下去并编写测试,并让报错信息指引我们。

[SOME_MUTATION] (state) {

并没有什么特别令人兴奋的 -- 记住 getter 可以接受其他的 getters 作为第二个参数。因为我们已经有一个poodlesgetter 了,可以在poodlesByAge中复用它。通过在poodlesByAge返回一个接受参数的函数,我们可以向 getters 中传入参数。poodlesByAgegetter 用法是这样的:

increment (state) {

我个人更喜欢这种实现。所有必须的数据被声明在测试内部,同时它也更紧凑一点儿。当然两种技术都很有用,并没有哪种更好哪种更差之分。

},

首先,创建 getters。

[types.FETCH_ALL] (context,payload) {

我们可以使用createLocalVue创建一个临时的Vue实例,并用其安装 Vuex。而后我们将一个新的store传入组件的加载选项中。完整的测试看起来是这样的:

├── main.js

刚刚讨论过测试使用了$store.state和$store.getters的组件,这两者都用来将当前状态提供给组件。而当断言一个组件正确 commit 了一个 mutation 或 dispatch 了一个 action 时,我们真正想做的是断言$store.commit和$store.dispatch以正确的处理函数(要调用的 mutation 或 action)和 payload 被调用了。

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

通常来说 Vue 组件会在以下方面和 Vuex 发生交互:

}

测试一个 action 时,可以使用 Jest ES6 class mocks,并应该同时测试其成功和失败的情况

}

3 - 测试 getters

actions: {

4.1 - 使用createLocalVue测试$store.state

})

5.4 - 测试一个 Namespaced Action (或 Mutation)

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

测试仍然通过。

const  moduleA = {

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] ]) })})

注册一个简单的action

比如一个ADD_POSTmutation 的概述如下:一旦被实现,它将从 payload 中获取一个post对象,并将post.id添加到state.postIds中;它也会将那个 post 对象以post.id为 key 添加到state.posts对象中。这即是在应用中使用 Vuex 的一个通常的模式。

使用常量替代mutation事件类型在各种Flux实现中是很常见的模式

正确的 mutation 是否被 commit 了?

模块的局部状态

有好多样板代码要去写,但这是个验证组件行为正确性的恰当而有效的方式。另一种替代方法 mock store 需要的代码更少。让我们来看看如何以那种方式编写一个测试并断言testAction被 dispatch 了。

{{ count }}

2.3 - 改良

state.count = n

如果一个 getter 使用了其他 getters,你应该用符合期望的返回结果 stub 掉后者。这将给我们对测试更细粒度的控制,并让你聚焦于测试中的 getter

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

咱仅仅测试过了 API 调用成功的情况,而测试所有产出的可能情况也是重要的。让我们编写一个测试应对发生错误的情况。这次,我们将先编写测试,再补全实现。

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

根据 payload 的结果 commit 一个 mutation

mapMutations({

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

如果你想讲一个getter属性另取名字,使用对象性时

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" } )})

setTimeout(() => {

现在全部所需的数据都包含在测试中了。太棒了!我特喜欢这个,因为测试是全包含的(fully contained),理解组件应该做什么所需的所有知识都都包含在测试中。

getters:{...}

poodles: 取得所有poodles

amount:10

axios的 mock 看起来是这样的:

})

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)

doneTodosCount() {

运行以上测试会给我们下面的报错信息:

]),

在一个普通的 Vue 应用中,我们使用Vue.use(Vuex)来安装 Vuex 插件,并将一个新的 Vuex store 传入 app 中。如果我们也在一个单元测试中做同样的事,那么,所有单元测试都得接收那个 Vuex store,尽管测试中根本用不到它。vue-test-utils提供了一个createLocalVue方法,用来为测试提供一个临时Vue实例。让我们看看如何使用它。首先,是一个基于 store 的 state 渲染出一个 username 的ComponentWithGetters组件。

])

这比前一个例子要紧凑多了。没有localVue、没有Vuex-- 不同于在前一个测试中我们用testMutation: jest.fn()mock 掉了commit后会触发的函数,这次我们实际上 mock 了dispatch函数本身。因为$store.dispatch只是一个普通的 JavaScript 函数,我们有能力做到这点。而后我们断言第一个参数是正确的 action 处理函数名testAction、第二个参数 payload 也正确。我们不关心实际发生的 -- 那可以被单独地测试。本次测试的目的就是简单地验证单击一个按钮会 dispatch 正确的带 payload 的 action。

}

因为使用了 Jest,我们可以用jest.mock容易地 mock 掉 API 调用。我们将用一个 mock 版本的axios代替真实的,使我们能更多地控制其行为。Jest 提供了ES6 Class Mocks,非常适于 mockaxios。

组合Actions

2.1 - 编写测试

mutations: {

postIds看起来挺好了。现在我们只需要将 post 加入state.posts。限于 Vue 反应式系统的工作方式我们无法简单地写成post[post.id] = post来添加 post。基本上,你需要使用Object.assign或...操作符创建一个新的对象。此处我们将使用...操作符将 post 赋值到state.posts:

components: {Counter},

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")})

store.commit({

payload 正确吗?

})

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

}

1 - 测试 Mutations

export default{

上面的测试中有很多代码 -- 尽管并没有什么让人兴奋的事情发生。我们创建了一个localVue并 use 了 Vuex,然后创建了一个 store,传入一个 Jest mock 函数 (jest.fn()) 代替testMutation。Vuex mutations 总是以两个参数的形式被调用:第一个参数是当前 state,第二个参数是 payload。因为我们并没有为 store 声明任何 state,我们预期它被调用时第一个参数会是一个空对象。第二个参数预期为{ msg: "Test Commit" },也就是硬编码在组件中的那样。

store.commit('increment', 10)

先看看用真实的 Vuex store 和createLocalVue,测试看起来是这样的:

export  const TOGGLE_DONE = 'todos/TOGGLE_DONE'

4.4 - 用computed来模拟 getters

]

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

}

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

一条重要的原则是记住mutation必须是同步函数。

现在yarn test:unit会产生:

doubleCount (state) {

现在你知道如何单独地测试 actions 了。至少还有一项潜在的改进可以为之,那就是将axiosmock 实现为一个manual mock(-mocks)。这包含在node_modules的同级创建一个__mocks__目录并在其中实现 mock 模块。Jest 将自动使用__mocks__中的 mock 实现。在 Jest 站点和因特网上有大量如何做的例子。

└── products.js   #产品模块

getters 也是普通的 JavaScript 函数,所以单独地测试它们同样非常容易;所用技术类似于测试 mutations 或 actions。

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

同样的,我们会遵循一个通常的 Vuex 模式创建一个 action:

Mutations需遵守vue的响应规则

Vuex 会自动将state传入 getter。因为我们是单独地测试 getters,所以还得手动传入state。除此之外,我们就是在测试一个普通的 JavaScript 函数。

},1000)

只有当一个 ES6 类 mock 作用域外的(out-of-scope)变量以mock为前缀时,Jest 才允许访问它。现在我们简单地赋值mockError = true然后axios就会抛出错误了。

}

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

])

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

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

mapGetters({

//把store对象提供给“store”选项,这可以把store的实例注入所有的子组件

在组件中分发Action

mutations: {...}

store.commit('increment')

同样对于模块内部的action, context.state是局部状态,根节点的窗台石context.rootState:

mapMutations([

mutations: {

mapState辅助函数

return this.$store.getters.doneTodosCount

methods: {

modules: {

},1000)

increment (state,payload) {

api.callAsyncMethod(() => {

新相关的DOM

const store = new Vuex.Store({

//使用添加了解前缀的名称定义,getter, action和mutation

increment({commit}){

}

创建一个Counter组件

return getters.doneTodos.length

state.count

我们可以在action内部执行异步操作。

}

actions:{

const moduleA = {

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

}

increment (state, payload) {

}

},

state.count

在另一个action中也可以

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

使用常量替代Mutation事件类型

getters: {

template: '

模块动态注册功能可以使让其他Vue插件为了应用的store附加新模块

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

}

actions: {...}

1.最好提前在你的store中初始化好所有的所需要的属性。

}

state.count

state: {...},

import Vue from 'vue'

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

}

│   ├── App.vue

对象风格的提交方式

count this.$store.state.count

}

在组件中提交Mutations

命名空间

},

export default {

[type.DONE_COUNT]  (state) {

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

expor default {

})

Action可以包含任意异步操作。

Modules

Getter也可以接受其他getters作为第二个参数:

模块的状态将是store.state.myModule.

在Vue组件中获得Vuex状态。

{{ count }}

const moduleA = {

//以载荷形式分发

Mutations

你需要明白store.dispatch可以处理被处触发的action的回调函数返回的Promise

increment (state) {

}

}

commit('increment')

state.count

方式隔离各个模块,以免冲突。

computed: mapState({

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

}

}

//以对象形式分发

store.commit('increment', {

}

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

})

mutations: {

mutations: {

async actionB({dispatch,commit}){

既然Vuex的store中的状态是响应式的,那么当我们变更状态时,监视状态的vue更新,这也意味值Vue中的mutation也需要与使用Vue一样遵守一些注意事项。

Vuex通过store选项,提供了一种机制将状态从根组件『注入』到每一个子组件

})

})

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

import Vuex from 'vuex'

我们利用async/ await

在mutation中混异步调用会导致你的程序很难调试。

el:'#app',

mapGetters辅助函数

state: {

}

对于大型应用,我们会希望把Vuex相关代码分割到模块中。下面是项目结构示例

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

Action通过store.dispatch方法触发:

//箭头函数可以使代码更简洁

Actions

state: {

count:0

commit('increment')

单一状态树,Vuex使用单一状态树用一个对象就包含了全部的应用层级状态。

Vuex允许我们再store中定义getters (可以认为是stroe的计算属性)

'anotherGetter'

count: state => state.count,

}

Vuex并不限制你的代码结构。但是它规定了一些需要遵守的规则:

帮助我们管理共享状态,中大型单页面应用。

const moduleA = {

mutations: {...}

countPlusLocalState(state) {

当触发一个类型为increment的mutation时,调用此函数。”要唤醒一个

import {mapActions } from 'vuex'

}

state

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

mutations: {

只要你遵守以上规则,如何组织代码随你便。如果你的store文件太大,

amount:10

state: {...},

}

commit('gotData',await getData())

},

只需将action、mutation、和getters分割到单独的文件

Getters接受state作为其第一个参数。

}

mutations: {

}

有时候我们需要从store中的state中 的state中派生一些状态,列如对列表进

todos:[

行过滤并计算。

',

export  const  FETCH_ALL =  'todos/FETCH_ALL'

const todosModule = {

'

}

computed: mapState([

提交mutation的另一种方式直接使用包含type属性的对象:

}

context.getters来获取state和getters当我们在之后介绍到Modules时,

amount:10

}

模块动态注册

someMutation (state) {

})

async actionA ({commit}){

})

[type.TOGGLE_DONE] (state, payload)

}

state: {count:0},

}

}

//在单独构建的版本中辅助函数为Vuex.mapState

})

}

actions: {

])

}

const moduleA = {

sumWithRootCount (state,getters,rootState) {

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

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

就是在计算属性中返回某个状态。

computed: {

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

mapGetters辅助函数仅仅是store中的getters映射到局部计算属性。

├── index.html

},

const store = new Vuex.Store({

doneTodosCount() {

})

getters: {

increment (context){

state : {todo: []},

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录mutation会更易读。

incrementAsync({commit}){

现在你可以

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

export default {

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

//  mutate state

模块内部的action, mutation ,和getter现在仍然注册在全局命名空间    这样保证了多个模块能够响应同一mutation或action.也可以通过添加前缀 或者 后缀的

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

Actions

Getters

}

可以给mapState传一个字符串数组。

})

//使用对象展开运算符将getters混入

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些冗余。

const store = new Vuex.Store({

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

├── components

incrementIfOddOnRootSum ({state, commit ,rootState}) {

//我们可以使用ES2015风格的计算属性命名功能来使用一个常量作为函数名

mutations: {

a:moduleA,

actions: {...}

state: {

}

├── cart.js       #购物车模块

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

import {mapMutations} from 'vuex'

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

store.dispatch('incrementAsync',{

npm install vuex --save

}

你在组件中使用this.$store.dispatch('xxx')分发action,或者使用map Actions辅助函数将组件的methods映射为store.dispatch调用

}

count (){

提交载荷(Payload)

└── modules

import * as types form '../types'

store.getters.doneTodosCount  // -> 1

type: 'increment',

由于Vuex的状态存储是响应式的,从store实例中读取状态最简单的方法

actionA({commit}){

对于模块内部的mutation和getter,接收的第一个参数是模块的局部状态。

Getters会暴露为store.getters对象:

getters: {

methods: {

type: 'incrementAsync',

actions响应在view上的用户书输入导致的状态变化。

count: 1

Action通常是异步的,那么如何知道action什么时候结束。

commit('increment')

import Vuex from 'vuex'

├── index.js     #我们组装模块并导出store的地方

}

//假设getData()和getOther()返回的是一个Promis

state驱动应用的数据源;

}

使用单一状态树,当应用变的很大的时候,store对象会变的臃肿不堪。

b:moduleB

commit('goOtherData', await getOtherData())

}

更改Vuex的store中的状态的唯一方式就是提交mutation Vuex中的mutation

state.count = payload.amount

}

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

store,

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

])

你可以在组件中使用this.$store.commit('xxx')提交mutation,或者使使用mapMutations辅助函数将组建中的methods映射为store.commit调用(需要在根节点注入store)

}

...mapGetters([

}

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

}

}

state.count = payload.amount

}

return new Promise((resolve)=>{

setTimeout (() => {

Action提交的是mutation ,而不是直接变更状态。

computed: {

mutations: {

store.dispatch({

以此来分割Vuex的状态管理。

getters: {

//为了能够使用‘this’获取局部状态,必须使用常规函数

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

actionB({dispath,commit}){

commit('someMutation')

state:{...}

}

你就知道context对象为什么不是store实例本身了。

methods:([

countAlias: 'count',

computed: {

我们可很容易的在任何组件中使用

mapActions({

TAG标签:
版权声明:本文由澳门新葡8455手机版发布于Web前端,转载请注明出处:之单元测验Web前端,使用验证