Как написать Redux Saga Test с помощью насмешливых селекторов и / или магазина с избыточностью - PullRequest
1 голос
/ 30 января 2020

Контекст: Я новичок в написании тестов Redux Saga и использую React Boilerplate для разработки приложения, в котором для тестирования используется Jest. Шаблон очень модульный и сложный, и мне трудно понять, как даже начать писать тест, чтобы смоделировать селекторы и указать состояние для моей Saga для использования в тесте.

В Saga я использую Реселект (в файле «./selectors»), чтобы получить «Имя пользователя» и «Пароль» из редуктора, присвоить им константу, используя yield select, и используя это, чтобы выполнить вызов API. Я не думаю, что моя проблема в тестировании высказывания саги, но высмеивает состояние и селекторы в саге, чтобы имитировать c, что информация для входа была заполнена и может быть извлеченным из состояния.

import { takeLatest, call, put, select } from 'redux-saga/effects';
import { loginSuccess, loginFailed } from '../App/actions';
import { ON_LOGIN } from '../App/constants';
import {
  makeSelectUsername,
  makeSelectPassword,
} from './selectors';
import api from '../../utils/api';

// LISTENER
export default function* loginRequestListener() {
  yield takeLatest(ON_LOGIN, login);
}

// WORKER
export function* login() {
  const loginParams = {
    username: yield select(makeSelectUsername()),
    password: yield select(makeSelectPassword()),
    isForceLoginAttempt: yield select(makeSelectIsForceLogin()),
  };

    try {
      const user = yield call(api.user.login, loginParams);
      yield put(loginSuccess(user));
    } catch (error) {
      yield put(loginFailed(error.response.data));
    }
}

По сути, я ищу способ запуска саги в тесте, чтобы внутри саги я мог "заставить" объект loginParams использовать "fakeState" для селекторов, чтобы использовать вместо этого, так как, очевидно, здесь не существует состояния:

const fakeState = {username: 'test', password: 'test'}

export function* login() {
  const loginParams = {
    username: yield select(makeSelectUsername()) // 'test'
    password: yield select(makeSelectPassword()) // 'test'
  };

Я рассматривал redux-saga-tester как средство для проверки саги, я просто предполагаю, что понятия не имею, где начать с точки зрения насмешки над состоянием в тесте, в котором моя сага может назначить константы ... Я думаю, что оттуда я справлюсь с остальными.

Есть кто-нибудь, особенно если вы работали с образцом , есть какие-либо предложения?

Ответы [ 2 ]

0 голосов
/ 31 января 2020

redux-saga-test-plan - самая популярная библиотека для тестирования саг.

http://redux-saga-test-plan.jeremyfairbank.com/

0 голосов
/ 31 января 2020

Мы используем redux-saga-tester в нашем приложении, способ, которым мы справились с этим - не путем перехода в ложное состояние, мы используем метод .next, а затем возвращаем ожидаемый результат для данного конкретного теста. , См. Ниже примеры того, что я описываю.

const activeOrderId = '1111';

//returns the value for a isConnected boolean
  it.next('should get isConnected', (result) => {
    expect(result).toEqual(select(getIsConnected));
    return true;
  });

// returns the value for an activeOrderId
  it.next('should get activeOrderId', (result) => {
    expect(result).toEqual(select(getActiveOrderId));
    return activeOrderId;
  });`

Преимущество этого метода в том, что вам не нужно определять большое «поддельное состояние» для всех ваших саг и что вы тестируете каждый из них. Сага отделена от этого. В любом случае у вас должны быть отдельные тесты для ваших селекторов, чтобы убедиться, что они работают правильно. Основная проблема сагового тестирования в целом заключается в том, что если в вашей саге есть какой-либо поток управления (если / еще), то, похоже, лучшая стратегия для полного тестирования всего - это написать совершенно другой поток тестирования для этой саги. Скажем, у вас есть

isConnected = yield select(getIsConnected)
if(isConnected) {
   // do x
} else {
   // do y
}

, мы справились с этим, написав два описания. Один, где мы установим isConnected в true (как в примере выше), а другой, где мы установим его в false, который будет выглядеть следующим образом:

    //returns the value for a isConnected boolean
  it.next('should get isConnected', (result) => {
    expect(result).toEqual(select(getIsConnected));
    return false;
  });

Если вам нужно передать полезную нагрузку в сагу, Вы можете справиться с этим с помощью функции sagaHelper, например:

  it.next = sagaHelper(login({
     username: 'testUsername',
     password: 'testPassword',
     // etc
  }));

Надеюсь, это поможет!

...