Hong  Nhung

Hong Nhung

1660302960

Kiểm Tra đơn Vị Mô-đun Vuex Với Jest

Nếu bạn đang xây dựng một SPA quy mô vừa đến lớn, rất có thể bạn sẽ gặp phải những tình huống mà bạn muốn xử lý tốt hơn trạng thái của các thành phần Vue của mình.

Trong bất kỳ ứng dụng nào, nhiều thành phần phụ thuộc vào cùng một trạng thái. Hãy tưởng tượng rằng nhiều hành động từ các thành phần khác nhau muốn thay đổi cùng một trạng thái. Để vượt qua những thách thức này, Vuex giúp chúng tôi duy trì trạng thái trên toàn ứng dụng.

Trong bài viết này, tôi sẽ hướng dẫn bạn triển khai mô-đun Vuex trong TypeScript, sau đó đơn vị kiểm tra nó bằng Jest . Mã hoàn chỉnh cho hướng dẫn này có sẵn tại kho lưu trữ GitHub vuex-test ; cảm thấy tự do để phân nhánh nó. Bắt đầu nào!

Vuex là gì?

Vuex là một mẫu và thư viện quản lý trạng thái cho các ứng dụng Vue cho phép bạn sử dụng quản lý trạng thái tập trung trong các ứng dụng của mình, giúp bạn tận dụng lợi thế của kiến ​​trúc giống như Flux. Cửa hàng Vuex chứa bốn khái niệm cốt lõi:

  1. Tiểu bang
  2. Getters
  3. Đột biến
  4. Hành động

Đối tượng trạng thái chứa dữ liệu bạn muốn có trong cửa hàng, bao gồm tất cả trạng thái cấp ứng dụng của bạn, đóng vai trò là nguồn chân lý duy nhất. Các thuộc tính được xác định trong trạng thái có thể là bất kỳ kiểu dữ liệu nào, bao gồm một chuỗi, số, đối tượng hoặc mảng.

Nếu bạn muốn có một trạng thái dẫn xuất dựa trên trạng thái lưu trữ, ví dụ: đếm danh sách các mục, lọc bộ sưu tập hoặc sử dụng cùng một nhóm trạng thái dẫn xuất trong các mô-đun hoặc thành phần khác, bạn có thể xác định getters .

Mặt khác, đột biến là cách duy nhất chúng ta có thể thay đổi trạng thái. Các đột biến luôn đồng bộ và tải trọng là tùy chọn. Bạn có thể gọi một đột biến thông qua cam kết, tức là, MUTATION_NAMEhoặc payload. Nó luôn được khuyến khích để gọi các đột biến từ các hành động.

Các hành động có thể thực hiện các hoạt động không đồng bộ và thực hiện các đột biến. Trình xử lý hành động nhận được một đối tượng ngữ cảnh hiển thị cùng một tập hợp các phương thức hoặc thuộc tính trên phiên bản store.

Bạn có thể sử dụng context.getterscontext.stateđể có được trạng thái và context.commitgọi các đột biến. Bạn có thể gọi các trình xử lý hành động bằng cách sử dụng action-namepayloadvà chúng được gọi từ các hành động khác trong cửa hàng.

Sơ đồ mô-đun Vuex

Kiến trúc Vuex

Tạo mô-đun Vuex

Khi kích thước ứng dụng của bạn tăng lên, cửa hàng của bạn có thể trở nên cồng kềnh. Để ngăn chặn điều này, Vuex cho phép bạn chia cửa hàng thành các mô-đun . Mỗi mô-đun có thể chứa trạng thái, nhận diện, đột biến và hành động của riêng nó.

Ví dụ, hãy tạo một ứng dụng để quản lý danh sách việc cần làm. Đầu tiên, hãy tạo một mô-đun mới cho các hoạt động cần làm, mô-đun này chịu trách nhiệm nhận tất cả các mục cần làm và cập nhật trạng thái khi cần thiết.

Mục tiêu của chúng tôi là xây dựng mô-đun cho các ứng dụng quy mô vừa đến lớn, do đó, tốt hơn là nên chia các loại đột biến, hành động được gọi là chức năng và triển khai mô-đun thành các tệp riêng biệt:

  • mutation-types.ts: Chứa tất cả các tên hàm
  • actions.ts: Chịu trách nhiệm cho tất cả các hoạt động không đồng bộ
  • index.ts: Triển khai mô-đun
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ạn mã ở trên chứa cách triển khai sau:

  • fetchTodos Action: Tìm nạp các mục việc cần làm từ API REST và thực hiện các đột biến
  • ON_FETCH_TODOS_STARTEDđột biến: Cập nhật loadingthuộc tính trạng thái
  • ON_FETCH_TODOS_SUCCESSđột biến: Cập nhật todosmảng trạng thái
  • ON_FETCH_TODOS_FAILEDđột biến: Đặt lại todosvà cập nhật loadinglà sai
  • completedTodosgetter: Chỉ nhận các mục việc cần làm đã hoàn thành

Khởi tạo các bài kiểm tra

Chúng tôi sẽ sử dụng khuôn khổ Jest để thử nghiệm đơn vị ; Jest chỉ đơn giản là một khung kiểm tra JavaScript có thể dễ dàng cài đặt với bất kỳ trình quản lý gói dựa trên nút nào, như npm hoặc Yarn. Có một số lợi ích khi sử dụng Jest, ví dụ, các bài kiểm tra Jest chạy song song, bao gồm khả năng phủ mã tích hợp và hỗ trợ các bài kiểm tra riêng biệt, kiểm tra mô phỏng và ảnh chụp nhanh.

Bạn có thể khởi tạo thử nghiệm bằng cách tạo cửa hàng, gắn Vuex vào Vue và đăng ký cửa hàng. localVuelà hàm tạo Vue phạm vi mà chúng ta có thể thay đổi mà không ảnh hưởng đến hàm tạo Vue toàn cục. Đoạn mã dưới đây sẽ khởi tạo cửa hàng:

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

Kiểm tra các hành động

Trong todosmô-đun, chúng tôi đã tạo fetchTodoshành động tìm nạp dữ liệu từ API REST và lấp đầy trạng thái bằng cách sử dụng các đột biến. Vì REST API là một lệnh gọi bên ngoài, chúng ta có thể mô phỏng nó bằng cách sử dụng hàm Jest, sau đó xác thực xem nó có đang được gọi hay không và trạng thái đang được cập nhật:

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

Kiểm tra getters

Các hàm Getter chỉ đơn giản là trả về đối tượng trạng thái. Trong ví dụ của chúng tôi, chúng tôi có một hàm getter, hàm completedTodosnày sẽ trả về các mục việc cần làm đã hoàn thành:

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

Kiểm tra đột biến

Như chúng ta đã biết, đột biến là cách duy nhất để thay đổi trạng thái. Chúng tôi có thể kiểm tra sự ON_FETCH_TODOS_SUCCESSđột biến bằng cách gửi các nhiệm vụ cần làm giả và xác nhận xem trạng thái có được sửa đổi hay không.

Đoạn mã dưới đây dành cho  successđột biến. Điều tương tự cũng áp dụng cho các đột biến startederror:

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

Sự kết luận

Trong hướng dẫn này, chúng ta đã tìm hiểu về Vuex bằng cách tạo và thử nghiệm đơn vị mô-đun Vuex với TypeScript và Jest. Chúng tôi đã đề cập đến bốn khái niệm cốt lõi của cửa hàng Vuex, bao gồm trạng thái, getters, đột biến và hành động. Với quản lý trạng thái tập trung của Vuex, bạn có thể đơn giản hóa ứng dụng của mình và tận dụng lợi thế của kiến ​​trúc giống Flux.

Tôi hy vọng bạn đã học được điều gì đó mới và hãy để lại bình luận nếu bạn có bất kỳ câu hỏi nào. Chúc bạn viết mã vui vẻ! 

Nguồn: https://blog.logrocket.com/unit-testing-vuex-modules-jest/

 #jest #vuex 

What is GEEK

Buddha Community

Kiểm Tra đơn Vị Mô-đun Vuex Với Jest
Hong  Nhung

Hong Nhung

1660302960

Kiểm Tra đơn Vị Mô-đun Vuex Với Jest

Nếu bạn đang xây dựng một SPA quy mô vừa đến lớn, rất có thể bạn sẽ gặp phải những tình huống mà bạn muốn xử lý tốt hơn trạng thái của các thành phần Vue của mình.

Trong bất kỳ ứng dụng nào, nhiều thành phần phụ thuộc vào cùng một trạng thái. Hãy tưởng tượng rằng nhiều hành động từ các thành phần khác nhau muốn thay đổi cùng một trạng thái. Để vượt qua những thách thức này, Vuex giúp chúng tôi duy trì trạng thái trên toàn ứng dụng.

Trong bài viết này, tôi sẽ hướng dẫn bạn triển khai mô-đun Vuex trong TypeScript, sau đó đơn vị kiểm tra nó bằng Jest . Mã hoàn chỉnh cho hướng dẫn này có sẵn tại kho lưu trữ GitHub vuex-test ; cảm thấy tự do để phân nhánh nó. Bắt đầu nào!

Vuex là gì?

Vuex là một mẫu và thư viện quản lý trạng thái cho các ứng dụng Vue cho phép bạn sử dụng quản lý trạng thái tập trung trong các ứng dụng của mình, giúp bạn tận dụng lợi thế của kiến ​​trúc giống như Flux. Cửa hàng Vuex chứa bốn khái niệm cốt lõi:

  1. Tiểu bang
  2. Getters
  3. Đột biến
  4. Hành động

Đối tượng trạng thái chứa dữ liệu bạn muốn có trong cửa hàng, bao gồm tất cả trạng thái cấp ứng dụng của bạn, đóng vai trò là nguồn chân lý duy nhất. Các thuộc tính được xác định trong trạng thái có thể là bất kỳ kiểu dữ liệu nào, bao gồm một chuỗi, số, đối tượng hoặc mảng.

Nếu bạn muốn có một trạng thái dẫn xuất dựa trên trạng thái lưu trữ, ví dụ: đếm danh sách các mục, lọc bộ sưu tập hoặc sử dụng cùng một nhóm trạng thái dẫn xuất trong các mô-đun hoặc thành phần khác, bạn có thể xác định getters .

Mặt khác, đột biến là cách duy nhất chúng ta có thể thay đổi trạng thái. Các đột biến luôn đồng bộ và tải trọng là tùy chọn. Bạn có thể gọi một đột biến thông qua cam kết, tức là, MUTATION_NAMEhoặc payload. Nó luôn được khuyến khích để gọi các đột biến từ các hành động.

Các hành động có thể thực hiện các hoạt động không đồng bộ và thực hiện các đột biến. Trình xử lý hành động nhận được một đối tượng ngữ cảnh hiển thị cùng một tập hợp các phương thức hoặc thuộc tính trên phiên bản store.

Bạn có thể sử dụng context.getterscontext.stateđể có được trạng thái và context.commitgọi các đột biến. Bạn có thể gọi các trình xử lý hành động bằng cách sử dụng action-namepayloadvà chúng được gọi từ các hành động khác trong cửa hàng.

Sơ đồ mô-đun Vuex

Kiến trúc Vuex

Tạo mô-đun Vuex

Khi kích thước ứng dụng của bạn tăng lên, cửa hàng của bạn có thể trở nên cồng kềnh. Để ngăn chặn điều này, Vuex cho phép bạn chia cửa hàng thành các mô-đun . Mỗi mô-đun có thể chứa trạng thái, nhận diện, đột biến và hành động của riêng nó.

Ví dụ, hãy tạo một ứng dụng để quản lý danh sách việc cần làm. Đầu tiên, hãy tạo một mô-đun mới cho các hoạt động cần làm, mô-đun này chịu trách nhiệm nhận tất cả các mục cần làm và cập nhật trạng thái khi cần thiết.

Mục tiêu của chúng tôi là xây dựng mô-đun cho các ứng dụng quy mô vừa đến lớn, do đó, tốt hơn là nên chia các loại đột biến, hành động được gọi là chức năng và triển khai mô-đun thành các tệp riêng biệt:

  • mutation-types.ts: Chứa tất cả các tên hàm
  • actions.ts: Chịu trách nhiệm cho tất cả các hoạt động không đồng bộ
  • index.ts: Triển khai mô-đun
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ạn mã ở trên chứa cách triển khai sau:

  • fetchTodos Action: Tìm nạp các mục việc cần làm từ API REST và thực hiện các đột biến
  • ON_FETCH_TODOS_STARTEDđột biến: Cập nhật loadingthuộc tính trạng thái
  • ON_FETCH_TODOS_SUCCESSđột biến: Cập nhật todosmảng trạng thái
  • ON_FETCH_TODOS_FAILEDđột biến: Đặt lại todosvà cập nhật loadinglà sai
  • completedTodosgetter: Chỉ nhận các mục việc cần làm đã hoàn thành

Khởi tạo các bài kiểm tra

Chúng tôi sẽ sử dụng khuôn khổ Jest để thử nghiệm đơn vị ; Jest chỉ đơn giản là một khung kiểm tra JavaScript có thể dễ dàng cài đặt với bất kỳ trình quản lý gói dựa trên nút nào, như npm hoặc Yarn. Có một số lợi ích khi sử dụng Jest, ví dụ, các bài kiểm tra Jest chạy song song, bao gồm khả năng phủ mã tích hợp và hỗ trợ các bài kiểm tra riêng biệt, kiểm tra mô phỏng và ảnh chụp nhanh.

Bạn có thể khởi tạo thử nghiệm bằng cách tạo cửa hàng, gắn Vuex vào Vue và đăng ký cửa hàng. localVuelà hàm tạo Vue phạm vi mà chúng ta có thể thay đổi mà không ảnh hưởng đến hàm tạo Vue toàn cục. Đoạn mã dưới đây sẽ khởi tạo cửa hàng:

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

Kiểm tra các hành động

Trong todosmô-đun, chúng tôi đã tạo fetchTodoshành động tìm nạp dữ liệu từ API REST và lấp đầy trạng thái bằng cách sử dụng các đột biến. Vì REST API là một lệnh gọi bên ngoài, chúng ta có thể mô phỏng nó bằng cách sử dụng hàm Jest, sau đó xác thực xem nó có đang được gọi hay không và trạng thái đang được cập nhật:

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

Kiểm tra getters

Các hàm Getter chỉ đơn giản là trả về đối tượng trạng thái. Trong ví dụ của chúng tôi, chúng tôi có một hàm getter, hàm completedTodosnày sẽ trả về các mục việc cần làm đã hoàn thành:

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

Kiểm tra đột biến

Như chúng ta đã biết, đột biến là cách duy nhất để thay đổi trạng thái. Chúng tôi có thể kiểm tra sự ON_FETCH_TODOS_SUCCESSđột biến bằng cách gửi các nhiệm vụ cần làm giả và xác nhận xem trạng thái có được sửa đổi hay không.

Đoạn mã dưới đây dành cho  successđột biến. Điều tương tự cũng áp dụng cho các đột biến startederror:

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

Sự kết luận

Trong hướng dẫn này, chúng ta đã tìm hiểu về Vuex bằng cách tạo và thử nghiệm đơn vị mô-đun Vuex với TypeScript và Jest. Chúng tôi đã đề cập đến bốn khái niệm cốt lõi của cửa hàng Vuex, bao gồm trạng thái, getters, đột biến và hành động. Với quản lý trạng thái tập trung của Vuex, bạn có thể đơn giản hóa ứng dụng của mình và tận dụng lợi thế của kiến ​​trúc giống Flux.

Tôi hy vọng bạn đã học được điều gì đó mới và hãy để lại bình luận nếu bạn có bất kỳ câu hỏi nào. Chúc bạn viết mã vui vẻ! 

Nguồn: 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 

曾 俊

曾 俊

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 

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