All Projects → jfairbank → Redux Saga Test Plan

jfairbank / Redux Saga Test Plan

Licence: mit
Test Redux Saga with an easy plan.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Redux Saga Test Plan

StoreCleanArchitecture-NET
This is a basic project to demonstrate an introduction about the implementation of Clean Architecture on .NET
Stars: ✭ 19 (-98.33%)
Mutual labels:  unit-testing, integration-testing
awesome-javascript-testing
🔧 Awesome JavaScript testing resources
Stars: ✭ 28 (-97.53%)
Mutual labels:  unit-testing, integration-testing
MockitoIn28Minutes
Learn Mockito from In28Minutes
Stars: ✭ 95 (-91.63%)
Mutual labels:  unit-testing, integration-testing
react-native-ecommerce
E-commerce mobile application developed using React Native 👔 🎩
Stars: ✭ 60 (-94.71%)
Mutual labels:  unit-testing, redux-saga
Dredd
Language-agnostic HTTP API Testing Tool
Stars: ✭ 3,770 (+232.16%)
Mutual labels:  unit-testing, integration-testing
SqlInMemory
SqlInMemory is a library for creating SqlServer database on Memory instead of hard disk, at last Drops and Disposes database when you're done with it. This is useful for Integration Testing.
Stars: ✭ 24 (-97.89%)
Mutual labels:  unit-testing, integration-testing
Aspnetcore Tests Sample
A project to help demonstrate how to do unit, integration and acceptance tests with an web api project using ASP.NET Core and Angular 7 front end.
Stars: ✭ 40 (-96.48%)
Mutual labels:  unit-testing, integration-testing
Hexagonal-architecture-ASP.NET-Core
App generator API solution template which is built on Hexagnonal Architecture with all essential feature using .NET Core
Stars: ✭ 57 (-94.98%)
Mutual labels:  unit-testing, integration-testing
Vue Testing Examples
Advanced testing with vuejs. When you need to go beyond Getting started section and see some real world example with everything that proper tests should have.
Stars: ✭ 288 (-74.63%)
Mutual labels:  unit-testing, integration-testing
React Native Navigation Redux Starter Kit
React Native Navigation(v2) Starter Kit with Redux, Saga, ESLint, Babel, Jest and Facebook SDK 😎
Stars: ✭ 271 (-76.12%)
Mutual labels:  unit-testing, redux-saga
toUUID
Simple integer to UUID generator for unit and integration tests written in Java or Kotlin
Stars: ✭ 12 (-98.94%)
Mutual labels:  unit-testing, integration-testing
Java Dns Cache Manipulator
🌏 A simple 0-dependency thread-safe Java™ lib/tool for setting dns programmatically without touching host file, make unit/integration test portable.
Stars: ✭ 557 (-50.93%)
Mutual labels:  unit-testing, integration-testing
springboot-junit5-mockito2
Show case for how to use junit 5 and mockito 2 for unit testing and integration test in spring boot 2
Stars: ✭ 18 (-98.41%)
Mutual labels:  unit-testing, integration-testing
Fineract-CN-mobile
DEPRECATED project - Check the Apache fineract-cn-mobile project instead
Stars: ✭ 17 (-98.5%)
Mutual labels:  unit-testing, integration-testing
pythonista-chromeless
Serverless selenium which dynamically execute any given code.
Stars: ✭ 31 (-97.27%)
Mutual labels:  unit-testing, integration-testing
MealsCatalogue
Flutter application using base architecture component like BLoC pattern, RxDart, Http, SQFlite, Flavor, Unit Testing (Mockito), Instrumentation Testing and etc 🔥
Stars: ✭ 45 (-96.04%)
Mutual labels:  unit-testing, integration-testing
Onion Architecture Asp.net Core
WhiteApp API solution template which is built on Onion Architecture with all essential feature using .NET 5!
Stars: ✭ 196 (-82.73%)
Mutual labels:  unit-testing, integration-testing
Dntframeworkcore
Lightweight and Extensible Infrastructure for Building Web Applications - Web Application Framework
Stars: ✭ 208 (-81.67%)
Mutual labels:  unit-testing, integration-testing
springboot-keycloak-mongodb-testcontainers
Goals: 1) Create a Spring Boot application that manages books; 2) Use Keycloak as authentication and authorization server; 3) Test using Testcontainers; 4) Explore the utilities and annotations that Spring Boot provides when testing applications.
Stars: ✭ 18 (-98.41%)
Mutual labels:  unit-testing, integration-testing
Codeception
Full-stack testing PHP framework
Stars: ✭ 4,401 (+287.75%)
Mutual labels:  unit-testing, integration-testing

Redux Saga Test Plan

npm Travis branch Codecov

Test Redux Saga with an easy plan.

Redux Saga Test Plan makes testing sagas a breeze. Whether you need to test exact effects and their ordering or just test your saga put's a specific action at some point, Redux Saga Test Plan has you covered.

Redux Saga Test Plan aims to embrace both integration testing and unit testing approaches to make testing your sagas easy.

Table of Contents

Documentation

Integration Testing

Requires global Promise to be available

One downside to unit testing sagas is that it couples your test to your implementation. Simple reordering of yielded effects in your saga could break your tests even if the functionality stays the same. If you're not concerned with the order or exact effects your saga yields, then you can take an integrative approach, testing the behavior of your saga when run by Redux Saga. Then, you can simply test that a particular effect was yielded during the saga run. For this, use the expectSaga test function.

Simple Example

Import the expectSaga function and pass in your saga function as an argument. Any additional arguments to expectSaga will become arguments to the saga function. The return value is a chainable API with assertions for the different effect creators available in Redux Saga.

In the example below, we test that the userSaga successfully puts a RECEIVE_USER action with the fakeUser as the payload. We call expectSaga with the userSaga and supply an api object as an argument to userSaga. We assert the expected put effect via the put assertion method. Then, we call the dispatch method with a REQUEST_USER action that contains the user id payload. The dispatch method will supply actions to take effects. Finally, we start the test by calling the run method which returns a Promise. Tests with expectSaga will always run asynchronously, so the returned Promise resolves when the saga finishes or when expectSaga forces a timeout. If you're using a test runner like Jest, you can return the Promise inside your Jest test so Jest knows when the test is complete.

import { call, put, take } from 'redux-saga/effects';
import { expectSaga } from 'redux-saga-test-plan';

function* userSaga(api) {
  const action = yield take('REQUEST_USER');
  const user = yield call(api.fetchUser, action.payload);

  yield put({ type: 'RECEIVE_USER', payload: user });
}

it('just works!', () => {
  const api = {
    fetchUser: id => ({ id, name: 'Tucker' }),
  };

  return expectSaga(userSaga, api)
    // Assert that the `put` will eventually happen.
    .put({
      type: 'RECEIVE_USER',
      payload: { id: 42, name: 'Tucker' },
    })

    // Dispatch any actions that the saga will `take`.
    .dispatch({ type: 'REQUEST_USER', payload: 42 })

    // Start the test. Returns a Promise.
    .run();
});

Mocking with Providers

expectSaga runs your saga with Redux Saga, so it will try to resolve effects just like Redux Saga would in your application. This is great for integration testing, but sometimes it can be laborious to bootstrap your entire application for tests or mock things like server APIs. In those cases, you can use providers which are perfect for mocking values directly with expectSaga. Providers are similar to middleware that allow you to intercept effects before they reach Redux Saga. You can choose to return a mock value instead of allowing Redux Saga to handle the effect, or you can pass on the effect to other providers or eventually Redux Saga.

expectSaga has two flavors of providers, static providers and dynamic providers. Static providers are easier to compose and reuse, but dynamic providers give you more flexibility with non-deterministic effects. Here is one example below using static providers. There are more examples of providers in the docs.

import { call, put, take } from 'redux-saga/effects';
import { expectSaga } from 'redux-saga-test-plan';
import * as matchers from 'redux-saga-test-plan/matchers';
import { throwError } from 'redux-saga-test-plan/providers';
import api from 'my-api';

function* userSaga(api) {
  try {
    const action = yield take('REQUEST_USER');
    const user = yield call(api.fetchUser, action.payload);
    const pet = yield call(api.fetchPet, user.petId);

    yield put({
      type: 'RECEIVE_USER',
      payload: { user, pet },
    });
  } catch (e) {
    yield put({ type: 'FAIL_USER', error: e });
  }
}

it('fetches the user', () => {
  const fakeUser = { name: 'Jeremy', petId: 20 };
  const fakeDog = { name: 'Tucker' };

  return expectSaga(userSaga, api)
    .provide([
      [call(api.fetchUser, 42), fakeUser],
      [matchers.call.fn(api.fetchPet), fakeDog],
    ])
    .put({
      type: 'RECEIVE_USER',
      payload: { user: fakeUser, pet: fakeDog },
    })
    .dispatch({ type: 'REQUEST_USER', payload: 42 })
    .run();
});

it('handles errors', () => {
  const error = new Error('error');

  return expectSaga(userSaga, api)
    .provide([
      [matchers.call.fn(api.fetchUser), throwError(error)]
    ])
    .put({ type: 'FAIL_USER', error })
    .dispatch({ type: 'REQUEST_USER', payload: 42 })
    .run();
});

Notice we pass in an array of tuple pairs (or array pairs) that contain a matcher and a fake value. You can use the effect creators from Redux Saga or matchers from the redux-saga-test-plan/matchers module to match effects. The bonus of using Redux Saga Test Plan's matchers is that they offer special partial matchers like call.fn which matches by the function without worrying about the specific args contained in the actual call effect. Notice in the second test that we can also simulate errors with the throwError function from the redux-saga-test-plan/providers module. This is perfect for simulating server problems.

Example with Reducer

One good use case for integration testing is testing your reducer too. You can hook up your reducer to your test by calling the withReducer method with your reducer function.

import { put } from 'redux-saga/effects';
import { expectSaga } from 'redux-saga-test-plan';

const initialDog = {
  name: 'Tucker',
  age: 11,
};

function reducer(state = initialDog, action) {
  if (action.type === 'HAVE_BIRTHDAY') {
    return {
      ...state,
      age: state.age + 1,
    };
  }

  return state;
}

function* saga() {
  yield put({ type: 'HAVE_BIRTHDAY' });
}

it('handles reducers and store state', () => {
  return expectSaga(saga)
    .withReducer(reducer)

    .hasFinalState({
      name: 'Tucker',
      age: 12, // <-- age changes in store state
    })

    .run();
});

Unit Testing

If you want to ensure that your saga yields specific types of effects in a particular order, then you can use the testSaga function. Here's a simple example:

import { testSaga } from 'redux-saga-test-plan';

function identity(value) {
  return value;
}

function* mainSaga(x, y) {
  const action = yield take('HELLO');

  yield put({ type: 'ADD', payload: x + y });
  yield call(identity, action);
}

const action = { type: 'TEST' };

it('works with unit tests', () => {
  testSaga(mainSaga, 40, 2)
    // advance saga with `next()`
    .next()

    // assert that the saga yields `take` with `'HELLO'` as type
    .take('HELLO')

    // pass back in a value to a saga after it yields
    .next(action)

    // assert that the saga yields `put` with the expected action
    .put({ type: 'ADD', payload: 42 })

    .next()

    // assert that the saga yields a `call` to `identity` with
    // the `action` argument
    .call(identity, action)

    .next()

    // assert that the saga is finished
    .isDone();
});

Extending inspect options

To see large effect objects while Expected & Actual result comparison you'll need to extend inspect options. Example:

import util from 'util';
import testSaga from 'redux-saga-test-plan';

import { testableSaga } from '../sagas';

describe('Some sagas to test', () => {
  util.inspect.defaultOptions.depth = null;

  it('testableSaga', () => {
    testSaga(testableSaga)
    .next()
    .put({ /* large object here */ })
    .next()
    .isDone();
  });
});

Install

yarn add redux-saga-test-plan --dev
npm install --save-dev redux-saga-test-plan
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].