Git Product home page Git Product logo

epic-marbles's Introduction

@mixer/epic-marbles

rxjs-style marble testing for your epics. See the tests for this repository (testception!) for an example of what this looks like.

Example

import { EpicTestFactory } from '@mixer/epic-marbles';
import { expect } from 'chai';

import { greeterActions } from './greeter.actions';
import { greetingEpic } from './greeter.epics';

const epic = new EpicTestFactory<RootActions, IState, IDependencies>();

it('says hello', () =>
  epic
    // pass your epic function right in!
    .test(greetingEpic)
    // easily mock your dependent services
    .service('greeter', mockGreeterService)
    // set up your state changes
    .states('-a-b', {
      a: { user: 'bob' },
      b: { user: 'jim' },
    })
    // send an action:
    .send('-a', {
      a: doGreeting(),
    })
    // expect that your epic emits actions
    .test('-a-b', {
      // match simple actions
      a: greeterActions.greet({ name: 'bob' }),
      // or define custom callbacks to run
      b: action => {
        expect(action).to.deep.equal(greeterActions.greet({ name: 'jim' }));
      },
    })
    // (optional): custom callback to be executed after test is finished
    .after(() => {
      // a good place to assert that mock methods have been called
      expect(mockGreeterService.hello).to.have.been.calledTwice;
    }));

Error Output

Errors look something like this:

Expected: -(a b) ----(c d)
Actual:   -(a ?1)----(c d)

Expectations:
  ✔ a@1: DID_SAY "HELLO"
  ✖ b@1: DID_SAY "wut"
  ✔ c@6: DID_SAY "BYE"
  ✔ d@6: DID_SAY "BYEBYE"

Unmatched/Extraneous Actions:
  ?1@1: DID_SAY "HELLOHELLO"

First, you'll see a marble representation of the expected and the actual timeline. The characters in these timelines will match the expectation passed to .test(), and any unknown actions will be prefixed with ?.

The, the list of expectations are shown, along with any extra actions that were unexpected. In this test, we matched all but one of our expectations. Here, we missed one expected action, and had an extra one in its place.

API

EpicTest.singleAction(action)

Schedules a single action to be fired into the epic under test.

EpicTest.singleState(states)

Sets the Redux state to test against. This won't change for the duration of the test.

EpicTest.send(marbles, actions)

Schedules a list of actions to be sent. Marbles is an rxjs marble string, see the syntax for this here. All syntax is fully supported.

The second parameter should map the marble characters to actions to send at that time. For example:

.send('-a--(bc)', {
  a: firstAction(),
  b: secondAction(),
  c: thirdAction(),
})

EpicTest.states(marbles, states)

Schedules a list of state changes to occur. Marbles is an rxjs marble string, see the syntax for this here. All syntax is fully supported.

The second parameter should map the marble characters to a list of states to send at that time.

EpicTest.service(serviceName, mock)

Mocks one of the service passed as the third arguments to your epics. Pairs well with Sinon.js. Note that all your services should return either a plain value or Observable. Marble testing is synchronous, so asynchronous functions like callbacks or promises won't wor.

import { of } from 'rxjs';

// ...
.service('greeter', {
  greet: (name: string) => of(`Hello ${name}`),
})

EpicTest.test(marbles, expectations)

Assets that the given set of actions are output from your test. Marbles is an rxjs marble string, see the syntax for this here. All syntax is fully supported. If you don't expect anything from the test, you can omit both arguments or call it with an empty marble list, such as .test('---').

The second parameter should map the marble characters to a list of expectations. These should be either action objects, which we'll check for deep equality against what the epic outputs, or functions that take the action as an output and check against it. For example:

.test('-a-b', {
  // match simple actions
  a: greeterActions.greet({ name: 'bob' }),
  // or define custom callbacks to run
  b: action => {
    expect(action).to.deep.equal(greeterActions.greet({ name: 'jim' }));
    expect(mockGreeterService.hello).to.have.been.calledTwice;
  },
})

epic-marbles's People

Contributors

connor4312 avatar dryzhkov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.