曾 俊

曾 俊

1660310669

使用 Jest 对 Vuex 模块进行单元测试

如果您正在构建一个中型到大型的 SPA,您很可能会遇到想要更好地处理 Vue 组件状态的情况。

在任何应用程序中,多个组件都依赖于同一个状态。让我们假设来自不同组件的多个动作想要改变相同的状态。为了克服这些挑战,Vuex帮助我们维护整个应用程序的状态。

在本文中,我将指导您在TypeScript 中实现一个 Vuex 模块,然后使用 Jest 对其进行单元测试。本教程的完整代码可在vuex-test GitHub 存储库中获得;随意分叉它。让我们开始吧!

什么是 Vuex?

Vuex 是Vue 应用程序的状态管理模式和库,允许您在应用程序中使用集中状态管理,帮助您利用类似 Flux 的架构。Vuex store包含四个核心概念:

  1. 状态
  2. 吸气剂
  3. 突变
  4. 行动

状态对象包含您希望在存储中拥有的数据,包括您的所有应用程序级状态,作为唯一的事实来源。状态中定义的属性可以是任何数据类型,包括字符串、数字、对象或数组。

如果您想根据存储状态获得派生状态,例如,计算项目列表、过滤集合或在其他模块或组件中使用相同的派生状态集,您可以定义 getters

另一方面,突变是我们改变状态的唯一方法。突变总是同步的,有效载荷是可选的。您可以通过提交,即MUTATION_NAMEpayload. 始终建议从动作中调用突变。

动作可以执行异步操作并提交突变。动作处理程序接收一个上下文对象,该对象在存储实例上公开相同的方法或属性集。

您可以使用context.gettersandcontext.state来获取状态并context.commit调用突变。action-name您可以使用和调用动作处理程序payload,它们是从商店中的其他动作调用的。

Vuex 模块图

Vuex 架构

创建一个 Vuex 模块

随着应用程序大小的增加,您的商店可能会变得臃肿。为了防止这种情况,Vuex 允许您将 store 拆分为 modules。每个模块都可以包含自己的状态、getter、突变和动作。

例如,让我们创建一个用于管理待办事项列表的应用程序。首先,新建一个待办事项模块,负责获取所有待办事项并根据需要更新状态。

我们的目标是为中大型应用程序构建模块,因此,最好将突变类型、称为函数的操作和模块实现拆分到单独的文件中:

  • mutation-types.ts: 包含所有函数名
  • actions.ts: 负责所有异步操作
  • index.ts: 模块实现
import { IToDo } from '@/types/todo';
import {Module, VuexModule, Mutation, Action} from 'vuex-module-decorators';
import TodoActions from './actions';
import * as mutationTypes from './mutation-types';

@Module({namespaced: true, name: "Todos"})
export class ToDoModule extends VuexModule {
  todos:Array<IToDo> = [];
  loading = false;
  get completedTodos(){
    return this.todos.filter((todo:IToDo)=> todo.completed);
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_STARTED]() {
    this.loading = true;
  }
  @Mutation
  \[mutationTypes.ON_FETCH_TODOS_SUCCESS\](data: Array<IToDo>) {
    this.loading = false;
    this.todos = data;
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_FAILED]() {
    this.loading = false;
    this.todos = [];
  }

  @Action({rawError: true})
  public async fetchTodos():Promise<void> {
      try {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_STARTED);
          const response: Array<IToDo> = await TodoActions.fetchTodos();
          this.context.commit(mutationTypes.ON_FETCH_TODOS_SUCCESS, response);
        } catch (error) {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_FAILED);
        }
  }

}

上面的代码片段包含以下实现:

  • fetchTodos Action:从 REST API 中获取待办事项并提交变更
  • ON_FETCH_TODOS_STARTED突变:更新loading状态属性
  • ON_FETCH_TODOS_SUCCESS突变:更新todos状态数组
  • ON_FETCH_TODOS_FAILED突变:重置todos和更新loading为假
  • completedTodosgetter:仅获取已完成的待办事项

初始化测试

我们将使用Jest 框架进行单元测试;Jest 只是一个 JavaScript 测试框架,可以使用任何基于节点的包管理器(如 npm 或 Yarn)轻松安装。使用 Jest 的优势很少,例如,Jest 测试并行运行,包括内置代码覆盖,并支持隔离测试、模拟和快照测试。

您可以通过创建商店、将 Vuex 附加到 Vue 并注册商店来初始化测试。localVue是作用域的 Vue 构造函数,我们可以在不影响全局 Vue 构造函数的情况下对其进行更改。下面的代码片段将初始化商店:

describe('Todos Module', function() {
    let store: any;
    let todosInstance: ToDoModule;

    beforeEach(function() {
      localVue.use(Vuex);
      store = new Vuex.Store({});
      registerStoreModules(store);
      todosInstance = getModule(ToDoModule, store);
    });

    it('should exists', function() {
      expect(todosInstance).toBeDefined();
    });
});

测试动作

todos模块中,我们创建了fetchTodos从 REST API 获取数据并使用突变填充状态的操作。由于 REST API 是一个外部调用,我们可以使用 Jest 函数模拟它,然后验证它是否被调用以及状态是否正在更新:

it('fetchTodos action should fill todos state', async function() {
      // arrange
      const todosMocked = todos as Array<IToDo>;
       // act
      jest.spyOn(TodoActions, 'fetchTodos').mockImplementation(
        (): Promise<Array<IToDo>> => {
          return Promise.resolve(todosMocked);
        }
      );
      await todosInstance.fetchTodos();
      // assert
      expect(todosInstance.todos.length >0).toEqual(true);
      expect(TodoActions.fetchTodos).toHaveBeenCalled();
});

测试吸气剂

Getter 函数只返回状态对象。在我们的示例中,我们有一个 getter 函数,completedTodos它应该返回已完成的待办事项:

  it('completedTodos getter should return only completed todos', async function() {
      // arrange
      const completedTodos = todosInstance.completedTodos;
      // assert
      expect(completedTodos.every((todo:IToDo)=> todo.completed)).toEqual(true);
    });

测试突变

正如我们已经知道的,突变是改变状态的唯一方法。我们可以ON_FETCH_TODOS_SUCCESS通过发送模拟待办任务并验证状态是否被修改来测试突变。

下面的代码片段用于 success突变。这同样适用于startedanderror突变:

it('ON_FETCH_TODOS_SUCCESS mutation should update given todos',  function() {
      // arrange 
      const todosTest = [
        {
          userId: 13,
          id: 12,
          title: "Move to new city",
          completed: false
        },
        {
          userId: 15,
          id: 21,
          title: "Finish a novel",
          completed: true
        },
      ];
      // act
      todosInstance.ON_FETCH_TODOS_SUCCESS(todosTest);
      // assert
      expect(todosInstance.todos.length).toEqual(2);
      expect(todosInstance.todos).toEqual(todosTest);
    });

结论

在本教程中,我们通过使用 TypeScript 和 Jest 创建和单元测试 Vuex 模块来了解 Vuex。我们介绍了 Vuex 存储的四个核心概念,包括状态、getter、突变和动作。借助 Vuex 的集中状态管理,您可以简化应用程序并利用类似 Flux 的架构。

我希望你学到了一些新东西,如果你有任何问题,一定要发表评论。快乐编码! 

来源:https ://blog.logrocket.com/unit-testing-vuex-modules-jest/

 #jest #vuex 

What is GEEK

Buddha Community

使用 Jest 对 Vuex 模块进行单元测试
曾 俊

曾 俊

1660310669

使用 Jest 对 Vuex 模块进行单元测试

如果您正在构建一个中型到大型的 SPA,您很可能会遇到想要更好地处理 Vue 组件状态的情况。

在任何应用程序中,多个组件都依赖于同一个状态。让我们假设来自不同组件的多个动作想要改变相同的状态。为了克服这些挑战,Vuex帮助我们维护整个应用程序的状态。

在本文中,我将指导您在TypeScript 中实现一个 Vuex 模块,然后使用 Jest 对其进行单元测试。本教程的完整代码可在vuex-test GitHub 存储库中获得;随意分叉它。让我们开始吧!

什么是 Vuex?

Vuex 是Vue 应用程序的状态管理模式和库,允许您在应用程序中使用集中状态管理,帮助您利用类似 Flux 的架构。Vuex store包含四个核心概念:

  1. 状态
  2. 吸气剂
  3. 突变
  4. 行动

状态对象包含您希望在存储中拥有的数据,包括您的所有应用程序级状态,作为唯一的事实来源。状态中定义的属性可以是任何数据类型,包括字符串、数字、对象或数组。

如果您想根据存储状态获得派生状态,例如,计算项目列表、过滤集合或在其他模块或组件中使用相同的派生状态集,您可以定义 getters

另一方面,突变是我们改变状态的唯一方法。突变总是同步的,有效载荷是可选的。您可以通过提交,即MUTATION_NAMEpayload. 始终建议从动作中调用突变。

动作可以执行异步操作并提交突变。动作处理程序接收一个上下文对象,该对象在存储实例上公开相同的方法或属性集。

您可以使用context.gettersandcontext.state来获取状态并context.commit调用突变。action-name您可以使用和调用动作处理程序payload,它们是从商店中的其他动作调用的。

Vuex 模块图

Vuex 架构

创建一个 Vuex 模块

随着应用程序大小的增加,您的商店可能会变得臃肿。为了防止这种情况,Vuex 允许您将 store 拆分为 modules。每个模块都可以包含自己的状态、getter、突变和动作。

例如,让我们创建一个用于管理待办事项列表的应用程序。首先,新建一个待办事项模块,负责获取所有待办事项并根据需要更新状态。

我们的目标是为中大型应用程序构建模块,因此,最好将突变类型、称为函数的操作和模块实现拆分到单独的文件中:

  • mutation-types.ts: 包含所有函数名
  • actions.ts: 负责所有异步操作
  • index.ts: 模块实现
import { IToDo } from '@/types/todo';
import {Module, VuexModule, Mutation, Action} from 'vuex-module-decorators';
import TodoActions from './actions';
import * as mutationTypes from './mutation-types';

@Module({namespaced: true, name: "Todos"})
export class ToDoModule extends VuexModule {
  todos:Array<IToDo> = [];
  loading = false;
  get completedTodos(){
    return this.todos.filter((todo:IToDo)=> todo.completed);
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_STARTED]() {
    this.loading = true;
  }
  @Mutation
  \[mutationTypes.ON_FETCH_TODOS_SUCCESS\](data: Array<IToDo>) {
    this.loading = false;
    this.todos = data;
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_FAILED]() {
    this.loading = false;
    this.todos = [];
  }

  @Action({rawError: true})
  public async fetchTodos():Promise<void> {
      try {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_STARTED);
          const response: Array<IToDo> = await TodoActions.fetchTodos();
          this.context.commit(mutationTypes.ON_FETCH_TODOS_SUCCESS, response);
        } catch (error) {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_FAILED);
        }
  }

}

上面的代码片段包含以下实现:

  • fetchTodos Action:从 REST API 中获取待办事项并提交变更
  • ON_FETCH_TODOS_STARTED突变:更新loading状态属性
  • ON_FETCH_TODOS_SUCCESS突变:更新todos状态数组
  • ON_FETCH_TODOS_FAILED突变:重置todos和更新loading为假
  • completedTodosgetter:仅获取已完成的待办事项

初始化测试

我们将使用Jest 框架进行单元测试;Jest 只是一个 JavaScript 测试框架,可以使用任何基于节点的包管理器(如 npm 或 Yarn)轻松安装。使用 Jest 的优势很少,例如,Jest 测试并行运行,包括内置代码覆盖,并支持隔离测试、模拟和快照测试。

您可以通过创建商店、将 Vuex 附加到 Vue 并注册商店来初始化测试。localVue是作用域的 Vue 构造函数,我们可以在不影响全局 Vue 构造函数的情况下对其进行更改。下面的代码片段将初始化商店:

describe('Todos Module', function() {
    let store: any;
    let todosInstance: ToDoModule;

    beforeEach(function() {
      localVue.use(Vuex);
      store = new Vuex.Store({});
      registerStoreModules(store);
      todosInstance = getModule(ToDoModule, store);
    });

    it('should exists', function() {
      expect(todosInstance).toBeDefined();
    });
});

测试动作

todos模块中,我们创建了fetchTodos从 REST API 获取数据并使用突变填充状态的操作。由于 REST API 是一个外部调用,我们可以使用 Jest 函数模拟它,然后验证它是否被调用以及状态是否正在更新:

it('fetchTodos action should fill todos state', async function() {
      // arrange
      const todosMocked = todos as Array<IToDo>;
       // act
      jest.spyOn(TodoActions, 'fetchTodos').mockImplementation(
        (): Promise<Array<IToDo>> => {
          return Promise.resolve(todosMocked);
        }
      );
      await todosInstance.fetchTodos();
      // assert
      expect(todosInstance.todos.length >0).toEqual(true);
      expect(TodoActions.fetchTodos).toHaveBeenCalled();
});

测试吸气剂

Getter 函数只返回状态对象。在我们的示例中,我们有一个 getter 函数,completedTodos它应该返回已完成的待办事项:

  it('completedTodos getter should return only completed todos', async function() {
      // arrange
      const completedTodos = todosInstance.completedTodos;
      // assert
      expect(completedTodos.every((todo:IToDo)=> todo.completed)).toEqual(true);
    });

测试突变

正如我们已经知道的,突变是改变状态的唯一方法。我们可以ON_FETCH_TODOS_SUCCESS通过发送模拟待办任务并验证状态是否被修改来测试突变。

下面的代码片段用于 success突变。这同样适用于startedanderror突变:

it('ON_FETCH_TODOS_SUCCESS mutation should update given todos',  function() {
      // arrange 
      const todosTest = [
        {
          userId: 13,
          id: 12,
          title: "Move to new city",
          completed: false
        },
        {
          userId: 15,
          id: 21,
          title: "Finish a novel",
          completed: true
        },
      ];
      // act
      todosInstance.ON_FETCH_TODOS_SUCCESS(todosTest);
      // assert
      expect(todosInstance.todos.length).toEqual(2);
      expect(todosInstance.todos).toEqual(todosTest);
    });

结论

在本教程中,我们通过使用 TypeScript 和 Jest 创建和单元测试 Vuex 模块来了解 Vuex。我们介绍了 Vuex 存储的四个核心概念,包括状态、getter、突变和动作。借助 Vuex 的集中状态管理,您可以简化应用程序并利用类似 Flux 的架构。

我希望你学到了一些新东西,如果你有任何问题,一定要发表评论。快乐编码! 

来源:https ://blog.logrocket.com/unit-testing-vuex-modules-jest/

 #jest #vuex 

藤本  結衣

藤本 結衣

1660393320

Jest を使用した Vuex モジュールの単体テスト

中規模から大規模の SPA を構築している場合、Vue コンポーネントの状態をより適切に処理したい状況に遭遇する可能性があります。

どのアプリケーションでも、複数のコンポーネントが同じ状態に依存しています。異なるコンポーネントからの複数のアクションが同じ状態を変更したいと考えてみましょう。これらの課題を克服するために、Vuexはアプリケーション全体で状態を維持するのに役立ちます。

この記事では、TypeScript で Vuex モジュールを実装し、Jest を使用してユニット テストを行う方法を説明します。このチュートリアルの完全なコードは、vuex-test GitHub リポジトリで入手できます。気軽にフォークしてください。始めましょう!

Vuexとは?

Vuex は、Vue アプリケーションの状態管理パターンおよびライブラリであり、アプリケーションで集中状態管理を使用できるようにし、Flux のようなアーキテクチャを活用するのに役立ちます。Vuex ストアには、次の4 つのコア コンセプトが含まれています。

  1. ゲッター
  2. 突然変異
  3. 行動

状態オブジェクトには、すべてのアプリケーション レベルの状態を含め、ストアに保持するデータが含まれており、信頼できる唯一の情報源として機能します。状態で定義されるプロパティは、文字列、数値、オブジェクト、配列など、任意のデータ型にすることができます。

アイテムのリストを数えたり、コレクションをフィルタリングしたり、他のモジュールやコンポーネントで同じ一連の派生状態を使用したりするなど、ストアの状態に基づいて派生状態が必要な場合は、getter を定義できます。

一方、突然変異は、状態を変更できる唯一の方法です。ミューテーションは常に同期的であり、ペイロードはオプションです。コミット、つまり、MUTATION_NAMEまたはを介し​​てミューテーションを呼び出すことができますpayload。アクションからミューテーションを呼び出すことを常にお勧めします。

アクションは、非同期操作を実行し、ミューテーションをコミットできます。アクション ハンドラーは、ストア インスタンスで同じメソッドまたはプロパティのセットを公開するコンテキスト オブジェクトを受け取ります。

とを使用context.getterscontext.stateて状態を取得し、context.commitミューテーションを呼び出すことができます。action-nameとを使用してアクション ハンドラーを呼び出すことができますpayload。これらは、ストア内の他のアクションから呼び出されます。

Vuex モジュール図

Vuex アーキテクチャ

Vuex モジュールを作成する

アプリケーションのサイズが大きくなると、ストアが肥大化する可能性があります。これを防ぐために、Vuex ではストアをモジュールに分割できます。各モジュールには、独自の状態、ゲッター、ミューテーション、およびアクションを含めることができます。

例として、To Do リストを管理するアプリケーションを作成してみましょう。まず、To Do 操作用の新しいモジュールを作成します。このモジュールは、すべての To Do アイテムを取得し、必要に応じて状態を更新します。

私たちの目標は、中規模から大規模なアプリケーション用のモジュールを構築することです。したがって、ミューテーション タイプ、関数と呼ばれるアクション、およびモジュールの実装を別々のファイルに分割することをお勧めします。

  • mutation-types.ts: すべての関数名が含まれます
  • actions.ts: すべての非同期操作を担当
  • index.ts: モジュールの実装
import { IToDo } from '@/types/todo';
import {Module, VuexModule, Mutation, Action} from 'vuex-module-decorators';
import TodoActions from './actions';
import * as mutationTypes from './mutation-types';

@Module({namespaced: true, name: "Todos"})
export class ToDoModule extends VuexModule {
  todos:Array<IToDo> = [];
  loading = false;
  get completedTodos(){
    return this.todos.filter((todo:IToDo)=> todo.completed);
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_STARTED]() {
    this.loading = true;
  }
  @Mutation
  \[mutationTypes.ON_FETCH_TODOS_SUCCESS\](data: Array<IToDo>) {
    this.loading = false;
    this.todos = data;
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_FAILED]() {
    this.loading = false;
    this.todos = [];
  }

  @Action({rawError: true})
  public async fetchTodos():Promise<void> {
      try {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_STARTED);
          const response: Array<IToDo> = await TodoActions.fetchTodos();
          this.context.commit(mutationTypes.ON_FETCH_TODOS_SUCCESS, response);
        } catch (error) {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_FAILED);
        }
  }

}

上記のコード スニペットには、次の実装が含まれています。

  • fetchTodos Action: REST API から To Do アイテムを取得し、ミューテーションをコミットします。
  • ON_FETCH_TODOS_STARTED突然変異:loading状態属性を更新します
  • ON_FETCH_TODOS_SUCCESS突然変異:todos状態配列を更新します
  • ON_FETCH_TODOS_FAILED突然変異: をリセットし、false としてtodos更新しますloading
  • completedTodosgetter: 完了した ToDo 項目のみを取得します

テストの初期化

単体テストには Jest フレームワークを使用します。Jest は、npm や Yarn などのノードベースのパッケージ マネージャーで簡単にインストールできる JavaScript テスト フレームワークです。Jest を使用する利点はほとんどありません。たとえば、Jest テストは並列で実行され、組み込みのコード カバレッジが含まれ、分離されたテスト、モック、およびスナップショット テストがサポートされます。

ストアを作成し、Vuex を Vue にアタッチし、ストアを登録することで、テストを初期化できます。localVueグローバル Vue コンストラクターに影響を与えずに変更できる、スコープ付きの Vue コンストラクターです。以下のコード スニペットはストアを初期化します。

describe('Todos Module', function() {
    let store: any;
    let todosInstance: ToDoModule;

    beforeEach(function() {
      localVue.use(Vuex);
      store = new Vuex.Store({});
      registerStoreModules(store);
      todosInstance = getModule(ToDoModule, store);
    });

    it('should exists', function() {
      expect(todosInstance).toBeDefined();
    });
});

アクションのテスト

todosモジュールでは、REST API からデータをフェッチし、ミューテーションを使用して状態を埋めるアクションを作成しましたfetchTodos。REST API は外部呼び出しであるため、Jest 関数を使用してそれをモックし、それが呼び出されて状態が更新されているかどうかを検証できます。

it('fetchTodos action should fill todos state', async function() {
      // arrange
      const todosMocked = todos as Array<IToDo>;
       // act
      jest.spyOn(TodoActions, 'fetchTodos').mockImplementation(
        (): Promise<Array<IToDo>> => {
          return Promise.resolve(todosMocked);
        }
      );
      await todosInstance.fetchTodos();
      // assert
      expect(todosInstance.todos.length >0).toEqual(true);
      expect(TodoActions.fetchTodos).toHaveBeenCalled();
});

ゲッターのテスト

ゲッター関数は単に状態オブジェクトを返します。completedTodosこの例では、完了した To-Do 項目を返すゲッター関数 が 1 つあります。

  it('completedTodos getter should return only completed todos', async function() {
      // arrange
      const completedTodos = todosInstance.completedTodos;
      // assert
      expect(completedTodos.every((todo:IToDo)=> todo.completed)).toEqual(true);
    });

変異のテスト

すでに知っているように、ミューテーションは状態を変更する唯一の方法です。ON_FETCH_TODOS_SUCCESSモック ToDo タスクを送信し、状態が変更されているかどうかを検証することで、ミューテーションをテストできます。

以下のコード スニペットは successミューテーション用です。started同じことがおよびerrorミューテーションにも当てはまります。

it('ON_FETCH_TODOS_SUCCESS mutation should update given todos',  function() {
      // arrange 
      const todosTest = [
        {
          userId: 13,
          id: 12,
          title: "Move to new city",
          completed: false
        },
        {
          userId: 15,
          id: 21,
          title: "Finish a novel",
          completed: true
        },
      ];
      // act
      todosInstance.ON_FETCH_TODOS_SUCCESS(todosTest);
      // assert
      expect(todosInstance.todos.length).toEqual(2);
      expect(todosInstance.todos).toEqual(todosTest);
    });

結論

このチュートリアルでは、TypeScript と Jest を使用して Vuex モジュールを作成し、ユニット テストすることで、Vuex について学びました。状態、ゲッター、ミューテーション、アクションを含む、Vuex ストアの 4 つの主要な概念について説明しました。Vuex の集中状態管理により、アプリケーションを簡素化し、Flux のようなアーキテクチャを活用できます。

何か新しいことを学んでいただければ幸いです。ご不明な点がありましたら、コメントを残してください。ハッピーコーディング! 

ソース: https://blog.logrocket.com/unit-testing-vuex-modules-jest/ 

#jest #vuex 

Unit Testing Vuex Modules with Jest

If you’re building a medium to large-scale SPA, chances are you’ll run into situations where you want to better handle the state of your Vue components.

In any application, multiple components depend on the same piece of state. Let’s imagine that multiple actions from different components would like to mutate the same state. To overcome these challenges, Vuex helps us to maintain state across the application.

In this article, I’ll guide you through implementing a Vuex module in TypeScript, then unit testing it using Jest. The complete code for this tutorial is available at the vuex-test GitHub repository; feel free to fork it. Let’s get started!

See more at: https://blog.logrocket.com/unit-testing-vuex-modules-jest/

#jest #vuex 

Léon  Peltier

Léon Peltier

1660306812

Test Unitaire Des Modules Vuex Avec Jest

Si vous construisez un SPA de moyenne à grande échelle, il y a de fortes chances que vous rencontriez des situations où vous souhaitez mieux gérer l'état de vos composants Vue.

Dans toute application, plusieurs composants dépendent du même élément d'état. Imaginons que plusieurs actions de différents composants voudraient faire muter le même état. Pour surmonter ces défis, Vuex nous aide à maintenir l'état de l'application.

Dans cet article, je vais vous guider dans l'implémentation d'un module Vuex dans TypeScript, puis le tester unitairement à l'aide de Jest . Le code complet de ce didacticiel est disponible dans le référentiel GitHub de vuex-test ; n'hésitez pas à le bifurquer. Commençons!

Qu'est-ce que Vuex ?

Vuex est un modèle de gestion d'état et une bibliothèque pour les applications Vue qui vous permet d'utiliser la gestion d'état centralisée dans vos applications, vous aidant à tirer parti de l'architecture de type Flux. Le magasin Vuex contient quatre concepts de base :

  1. État
  2. Getters
  3. mutation
  4. Actions

L' objet d'état contient les données que vous souhaitez avoir dans le magasin, y compris tout votre état au niveau de l'application, servant de source unique de vérité. Les propriétés définies dans l'état peuvent être n'importe quel type de données, y compris une chaîne, un nombre, un objet ou un tableau.

Si vous souhaitez avoir un état dérivé basé sur l'état du magasin, par exemple, compter la liste des éléments, filtrer la collection ou utiliser le même ensemble d'états dérivés dans d'autres modules ou composants, vous pouvez définir des getters .

D'un autre côté, les mutations sont le seul moyen de changer l'état. Les mutations sont toujours synchrones et la charge utile est facultative. Vous pouvez appeler une mutation via le commit, c'est-à-dire MUTATION_NAMEou payload. Il est toujours recommandé d'appeler des mutations à partir d'actions.

Les actions peuvent effectuer des opérations asynchrones et valider les mutations. Les gestionnaires d'action reçoivent un objet de contexte qui expose le même ensemble de méthodes ou de propriétés sur l'instance de magasin.

Vous pouvez utiliser context.getterset context.statepour obtenir l'état et context.commitappeler des mutations. Vous pouvez appeler des gestionnaires d'action à l'aide de action-nameet payload, et ils sont appelés à partir d'autres actions du magasin.

Schéma des modules Vuex

Architecture Vuex

Créer un module Vuex

À mesure que la taille de votre application augmente, votre magasin peut devenir gonflé. Pour éviter cela, Vuex vous permet de diviser le magasin en modules . Chaque module peut contenir son propre état, getters, mutations et actions.

A titre d'exemple, créons une application pour gérer une liste de tâches. Tout d'abord, créez un nouveau module pour les opérations à faire, qui est responsable de l'obtention de tous les éléments à faire et de la mise à jour de l'état si nécessaire.

Notre objectif est de construire le module pour des applications à moyenne et grande échelle, par conséquent, il est préférable de diviser les types de mutation, les actions appelées fonctions et l'implémentation du module dans des fichiers séparés :

  • mutation-types.ts: Contient tous les noms de fonction
  • actions.ts: Responsable de toutes les opérations asynchrones
  • index.ts: L'implémentation du module
import { IToDo } from '@/types/todo';
import {Module, VuexModule, Mutation, Action} from 'vuex-module-decorators';
import TodoActions from './actions';
import * as mutationTypes from './mutation-types';

@Module({namespaced: true, name: "Todos"})
export class ToDoModule extends VuexModule {
  todos:Array<IToDo> = [];
  loading = false;
  get completedTodos(){
    return this.todos.filter((todo:IToDo)=> todo.completed);
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_STARTED]() {
    this.loading = true;
  }
  @Mutation
  \[mutationTypes.ON_FETCH_TODOS_SUCCESS\](data: Array<IToDo>) {
    this.loading = false;
    this.todos = data;
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_FAILED]() {
    this.loading = false;
    this.todos = [];
  }

  @Action({rawError: true})
  public async fetchTodos():Promise<void> {
      try {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_STARTED);
          const response: Array<IToDo> = await TodoActions.fetchTodos();
          this.context.commit(mutationTypes.ON_FETCH_TODOS_SUCCESS, response);
        } catch (error) {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_FAILED);
        }
  }

}

L'extrait de code ci-dessus contient l'implémentation suivante :

  • fetchTodos Action: Récupère les éléments à faire de l'API REST et valide les mutations
  • ON_FETCH_TODOS_STARTEDmutation : met à jour l' loadingattribut d'état
  • ON_FETCH_TODOS_SUCCESSmutation : met à jour le todostableau d'état
  • ON_FETCH_TODOS_FAILEDmutation : Réinitialise todoset met à jour loadingcomme faux
  • completedTodosgetter : Obtient uniquement les éléments à faire qui sont terminés

Initialiser les tests

Nous utiliserons le framework Jest pour les tests unitaires ; Jest est simplement un framework de test JavaScript qui peut être facilement installé avec n'importe quel gestionnaire de packages basé sur un nœud, comme npm ou Yarn. L'utilisation de Jest présente peu d'avantages, par exemple, les tests Jest s'exécutent en parallèle, incluent une couverture de code intégrée et prennent en charge les tests isolés, les simulations et les tests instantanés.

Vous pouvez initialiser le test en créant un magasin, en attachant Vuex à Vue et en enregistrant le magasin. localVueest le constructeur Vue scoped que nous pouvons modifier sans affecter le constructeur Vue global. L'extrait de code ci-dessous initialisera le magasin :

describe('Todos Module', function() {
    let store: any;
    let todosInstance: ToDoModule;

    beforeEach(function() {
      localVue.use(Vuex);
      store = new Vuex.Store({});
      registerStoreModules(store);
      todosInstance = getModule(ToDoModule, store);
    });

    it('should exists', function() {
      expect(todosInstance).toBeDefined();
    });
});

Actions de test

Dans le todosmodule, nous avons créé l' fetchTodosaction, qui récupère les données d'une API REST et remplit l'état à l'aide de mutations. Étant donné que l'API REST est un appel externe, nous pouvons la simuler à l'aide d'une fonction Jest, puis valider si elle est appelée et si l'état est mis à jour :

it('fetchTodos action should fill todos state', async function() {
      // arrange
      const todosMocked = todos as Array<IToDo>;
       // act
      jest.spyOn(TodoActions, 'fetchTodos').mockImplementation(
        (): Promise<Array<IToDo>> => {
          return Promise.resolve(todosMocked);
        }
      );
      await todosInstance.fetchTodos();
      // assert
      expect(todosInstance.todos.length >0).toEqual(true);
      expect(TodoActions.fetchTodos).toHaveBeenCalled();
});

Tester les getters

Les fonctions getter renvoient simplement l'objet d'état. Dans notre exemple, nous avons une fonction getter, completedTodos, qui doit renvoyer les tâches à faire terminées :

  it('completedTodos getter should return only completed todos', async function() {
      // arrange
      const completedTodos = todosInstance.completedTodos;
      // assert
      expect(completedTodos.every((todo:IToDo)=> todo.completed)).toEqual(true);
    });

Tester les mutations

Comme nous le savons déjà, les mutations sont le seul moyen de changer l'état. Nous pouvons tester la ON_FETCH_TODOS_SUCCESSmutation en envoyant des tâches fictives et en validant si l'état est modifié.

L'extrait de code ci-dessous est pour la  successmutation. Il en va de même pour les mutations startedet :error

it('ON_FETCH_TODOS_SUCCESS mutation should update given todos',  function() {
      // arrange 
      const todosTest = [
        {
          userId: 13,
          id: 12,
          title: "Move to new city",
          completed: false
        },
        {
          userId: 15,
          id: 21,
          title: "Finish a novel",
          completed: true
        },
      ];
      // act
      todosInstance.ON_FETCH_TODOS_SUCCESS(todosTest);
      // assert
      expect(todosInstance.todos.length).toEqual(2);
      expect(todosInstance.todos).toEqual(todosTest);
    });

Conclusion

Dans ce didacticiel, nous avons découvert Vuex en créant et en testant un module Vuex avec TypeScript et Jest. Nous avons couvert les quatre concepts de base d'un magasin Vuex, y compris l'état, les getters, les mutations et les actions. Avec la gestion d'état centralisée de Vuex, vous pouvez simplifier votre application et tirer parti de l'architecture de type Flux.

J'espère que vous avez appris quelque chose de nouveau, et assurez-vous de laisser un commentaire si vous avez des questions. Bon codage ! 

Source : https://blog.logrocket.com/unit-testing-vuex-modules-jest/

 #jest #vuex 

Mélanie  Faria

Mélanie Faria

1660306440

Testes Unitários De Módulos Vuex Com Jest

Se você estiver construindo um SPA de médio a grande porte, é provável que você se depare com situações em que deseja lidar melhor com o estado de seus componentes Vue.

Em qualquer aplicação, vários componentes dependem do mesmo estado. Vamos imaginar que várias ações de diferentes componentes gostariam de alterar o mesmo estado. Para superar esses desafios, o Vuex nos ajuda a manter o estado em todo o aplicativo.

Neste artigo, orientarei você na implementação de um módulo Vuex no TypeScript e, em seguida, no teste de unidade usando Jest . O código completo deste tutorial está disponível no repositório GitHub vuex-test ; sinta-se livre para bifurcá-lo. Vamos começar!

O que é Vuex?

Vuex é um padrão e biblioteca de gerenciamento de estado para aplicativos Vue que permite usar o gerenciamento de estado centralizado em seus aplicativos, ajudando você a aproveitar a arquitetura semelhante ao Flux. A loja Vuex contém quatro conceitos principais:

  1. Estado
  2. Getters
  3. Mutações
  4. Ações

O objeto de estado contém os dados que você deseja ter no armazenamento, incluindo todo o estado no nível do aplicativo, servindo como a única fonte de verdade. As propriedades definidas no estado podem ser qualquer tipo de dados, incluindo uma string, número, objeto ou array.

Se você quiser ter um estado derivado baseado no estado da loja, por exemplo, contando a lista de itens, filtrando a coleção ou usando o mesmo conjunto de estado derivado em outros módulos ou componentes, você pode definir getters .

Por outro lado, as mutações são a única maneira de mudar o estado. As mutações são sempre síncronas e a carga útil é opcional. Você pode chamar uma mutação por meio do commit, ou seja, MUTATION_NAMEou payload. É sempre recomendado chamar mutações de ações.

As ações podem realizar operações assíncronas e confirmar as mutações. Os manipuladores de ação recebem um objeto de contexto que expõe o mesmo conjunto de métodos ou propriedades na instância de armazenamento.

Você pode usar context.getterse context.statepara obter o estado e context.commitchamar mutações. Você pode chamar manipuladores de ação usando action-namee payload, e eles são chamados de outras ações dentro da loja.

Diagrama de Módulos Vuex

Arquitetura Vuex

Criar um módulo Vuex

À medida que o tamanho do seu aplicativo aumenta, sua loja pode ficar inchada. Para evitar isso, o Vuex permite dividir a loja em módulos . Cada módulo pode conter seu próprio estado, getters, mutações e ações.

Como exemplo, vamos criar um aplicativo para gerenciar uma lista de tarefas. Primeiro, crie um novo módulo para operações de pendências, que é responsável por obter todas as pendências e atualizar o estado conforme necessário.

Nosso objetivo é construir o módulo para aplicações de médio a grande porte, portanto, é melhor dividir os tipos de mutação, ações chamadas funções e a implementação do módulo em arquivos separados:

  • mutation-types.ts: Contém todos os nomes de funções
  • actions.ts: Responsável por todas as operações assíncronas
  • index.ts: A implementação do módulo
import { IToDo } from '@/types/todo';
import {Module, VuexModule, Mutation, Action} from 'vuex-module-decorators';
import TodoActions from './actions';
import * as mutationTypes from './mutation-types';

@Module({namespaced: true, name: "Todos"})
export class ToDoModule extends VuexModule {
  todos:Array<IToDo> = [];
  loading = false;
  get completedTodos(){
    return this.todos.filter((todo:IToDo)=> todo.completed);
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_STARTED]() {
    this.loading = true;
  }
  @Mutation
  \[mutationTypes.ON_FETCH_TODOS_SUCCESS\](data: Array<IToDo>) {
    this.loading = false;
    this.todos = data;
  }
  @Mutation
  [mutationTypes.ON_FETCH_TODOS_FAILED]() {
    this.loading = false;
    this.todos = [];
  }

  @Action({rawError: true})
  public async fetchTodos():Promise<void> {
      try {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_STARTED);
          const response: Array<IToDo> = await TodoActions.fetchTodos();
          this.context.commit(mutationTypes.ON_FETCH_TODOS_SUCCESS, response);
        } catch (error) {
          this.context.commit(mutationTypes.ON_FETCH_TODOS_FAILED);
        }
  }

}

O snippet de código acima contém a seguinte implementação:

  • fetchTodos Action: busca os itens de tarefas da API REST e confirma as mutações
  • ON_FETCH_TODOS_STARTEDmutação: atualiza o loadingatributo de estado
  • ON_FETCH_TODOS_SUCCESSmutação: atualiza a todosmatriz de estado
  • ON_FETCH_TODOS_FAILEDmutação: redefine o todose atualiza loadingcomo falso
  • completedTodosgetter: Obtém apenas os itens de tarefas que foram concluídos

Inicializar testes

Usaremos o framework Jest para testes unitários ; Jest é simplesmente uma estrutura de teste JavaScript que pode ser facilmente instalada com qualquer gerenciador de pacotes baseado em nó, como npm ou Yarn. Há poucas vantagens de usar o Jest, por exemplo, os testes do Jest são executados em paralelo, incluem cobertura de código integrada e dão suporte a testes isolados, simulações e testes de instantâneos.

Você pode inicializar o teste criando uma loja, anexando Vuex ao Vue e registrando a loja. localVueé o construtor Vue com escopo que podemos alterar sem afetar o construtor Vue global. O snippet de código abaixo inicializará a loja:

describe('Todos Module', function() {
    let store: any;
    let todosInstance: ToDoModule;

    beforeEach(function() {
      localVue.use(Vuex);
      store = new Vuex.Store({});
      registerStoreModules(store);
      todosInstance = getModule(ToDoModule, store);
    });

    it('should exists', function() {
      expect(todosInstance).toBeDefined();
    });
});

Ações de teste

No todosmódulo, criamos a fetchTodosação, que busca os dados de uma API REST e preenche o estado usando mutações. Como a API REST é uma chamada externa, podemos zombar dela usando uma função Jest e validar se ela está sendo chamada e o estado está sendo atualizado:

it('fetchTodos action should fill todos state', async function() {
      // arrange
      const todosMocked = todos as Array<IToDo>;
       // act
      jest.spyOn(TodoActions, 'fetchTodos').mockImplementation(
        (): Promise<Array<IToDo>> => {
          return Promise.resolve(todosMocked);
        }
      );
      await todosInstance.fetchTodos();
      // assert
      expect(todosInstance.todos.length >0).toEqual(true);
      expect(TodoActions.fetchTodos).toHaveBeenCalled();
});

Testando getters

As funções getter simplesmente retornam o objeto de estado. Em nosso exemplo, temos uma função getter, completedTodos, que deve retornar os itens de pendências concluídos:

  it('completedTodos getter should return only completed todos', async function() {
      // arrange
      const completedTodos = todosInstance.completedTodos;
      // assert
      expect(completedTodos.every((todo:IToDo)=> todo.completed)).toEqual(true);
    });

Testando mutações

Como já sabemos, as mutações são a única maneira de mudar o estado. Podemos testar a ON_FETCH_TODOS_SUCCESSmutação enviando tarefas simuladas e validando se o estado foi modificado.

O trecho de código abaixo é para a  successmutação. O mesmo se aplica para as mutações startede também:error

it('ON_FETCH_TODOS_SUCCESS mutation should update given todos',  function() {
      // arrange 
      const todosTest = [
        {
          userId: 13,
          id: 12,
          title: "Move to new city",
          completed: false
        },
        {
          userId: 15,
          id: 21,
          title: "Finish a novel",
          completed: true
        },
      ];
      // act
      todosInstance.ON_FETCH_TODOS_SUCCESS(todosTest);
      // assert
      expect(todosInstance.todos.length).toEqual(2);
      expect(todosInstance.todos).toEqual(todosTest);
    });

Conclusão

Neste tutorial, aprendemos sobre o Vuex criando e testando a unidade de um módulo Vuex com TypeScript e Jest. Cobrimos os quatro conceitos principais de uma loja Vuex, incluindo estado, getters, mutações e ações. Com o gerenciamento de estado centralizado do Vuex, você pode simplificar seu aplicativo e aproveitar a arquitetura semelhante ao Flux.

Espero que você tenha aprendido algo novo, e não se esqueça de deixar um comentário se tiver alguma dúvida. Boa codificação! 

Fonte: https://blog.logrocket.com/unit-testing-vuex-modules-jest/

 #jest #vuex