npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

jestor

v1.0.8

Published

Utility for creating mock implementation, defining how Jest mocks should behave

Downloads

19

Readme

jestor

NPM version NPM downloads MIT License Coverage

Utility for creating mock implementations for Jest mocks.

Usage

First add jestor as a devDependency.

npm install jestor --save-dev

or if you prefer Yarn:

yarn add jestor --dev

After that you can import jestor in your tests and use it in any test file:

import { jestor } from 'jestor'

it('should return 4 whan called with 44', function () {
  const mock = jest.fn()

  // define mock implementation using jestor api
  jestor(mock).whenCalledWith(44).return(4)

  expect(mock(44)).toBe(4)
})

Proceed to API section to see what else jestor can do for you.

API

jestor function accepts Jest mock as a single argument and returns an object with the following methods: whenCalledWith and followRules for defining single and multiple rules correspondingly.

Describing single rule

The best case for whenCalledWith is when you want to define only one rule:

import { jestor } from 'jestor'

it('should return 4 whan called with 44', function () {
  const mock = jest.fn()

  // whenCalledWith allows to define only a single rule
  jestor(mock).whenCalledWith(44).return(4)

  expect(mock(44)).toBe(4)
})

Describing multiple rules

If you want to define multiple rules, followRules should be used.
It accepts a function, which define what mock should do when the given condition is met:

it('should allow to define multiple rules', function () {
  const spy = jest.fn()
  jestor(spy).followRules((rules) => {
    rules.whenCalledWith(1).return(false)
    rules.whenCalledWith(2).return(true)
    rules.whenCalledWith('foo').resolveWith('foo')
    rules.whenCalledWith('bar').rejectWith('bar')
  })

  expect(spy(1)).toBe(false)
  expect(spy(2)).toBe(true)

  const foo = await spy('foo')
  expect(foo).toBe('foo')

  await spy('bar').catch((e) => {
    expect(e).toBe('bar')
  })
})

Describing conditions

As you've probably noticed, whenCalledWith is used directly in case of single rule, and inside callback function in case of multiple rules.
In both cases whenCalledWith is used for defining conditions for the arguments mock receives.

You can pass multiple arguments to whenCalledWith:

import { jestor } from 'jestor'

it('should return 6 whan called with 2 and 3', function () {
  const mock = jest.fn()

  // whenCalledWith accepts multiple arguments
  jestor(mock).whenCalledWith(2, 3).return(6)

  expect(mock(2, 3)).toBe(6)
})

You can pass any asymmetrical Expect matcher to whenCalledWith.
That includes matchers like anything, any, arrayContaining, etc.

For example:

import { jestor } from 'jestor'

it('should return 6 whan called with string and 3', function () {
  const mock = jest.fn()

  // whenCalledWith also accepts expect matchers
  jestor(mock).whenCalledWith(expect.any(String), 3).return(6)

  expect(mock('foo', 3)).toBe(6)
  expect(mock('baz', 3)).toBe(6)
})

Describing mock behavior

The whenCalledWith function returns an object which can be used to specify mock behavior - i.e. what should happen when mock is called with the given arguments.
For example, in jestor(mock).whenCalledWith(2, 3).return(6) sentence the part .return(6) describes mock behavior when it is called with arguments 2 and 3.

You can use the following behaviors:

.return(val)

Describes that the value val should be returned when mock is called:

import { jestor } from 'jestor'

it('should return 6 whan called with string and 3', function () {
  const mock = jest.fn()

  // tell jestor to return 6 when mock is called with 3
  jestor(mock).whenCalledWith(3).return(6)

  expect(mock(3)).toBe(6)
  expect(mock(2)).not.toBe(6)
})
.resolveWith(val)

Describes that the the promise resolved with val should be returned when mock is called:

import { jestor } from 'jestor'

it('should return resolved promise when resolveWith is used', function () {
  const mock = jest.fn()

  // tell jestor to return promise resolved with 6 when mock is called with 3
  jestor(mock).whenCalledWith(3).resolveWith(6)

  const promise = mock(3)

  // assert that we got a promise
  expect(promise.then).toBeDefined()

  // when called with value other than 3, we'll not get a promise,
  // as there is no jestor rule defined
  expect(mock(2)).toBe(undefined)

  // assert if we really got a promise resolved with 6
  const result = await promise
  expect(result).toBe(6)
})
.rejectWith(val)

Describes that the the promise rejected with val should be returned when mock is called:

import { jestor } from 'jestor'

it('should return rejected promise when rejectWith is used', function () {
  const mock = jest.fn()

  // tell jestor to return rejected promise
  jestor(mock).whenCalledWith(2).rejectWith('failure')

  // assert if we really got a promise rejected with 'failure'
  const err = await mock(2).catch((e) => e)
  expect(err).toBe('failure')
})
.throw(val)

Describes that value val should be thrown when mock is called:

import { jestor } from 'jestor'

it('should throw an exception when throw is used', function () {
  const mock = jest.fn()

  // tell jestor to throw
  jestor(mock).whenCalledWith(2).throw('exception')

  // assert if we really got an exception
  jestor(mock).whenCalledWith(2).throw('exception')
  expect(() => {
    spy(2)
  }).toThrow('exception')
})

Rationale

Let's imagine you have a mock, returned by jest.fn() and want to define its implementation in a way that you specify what to return based on received arguments. Something like this:

describe('my function', function() {
  it('should return a value', function() {
    const mock = jest.fn()
    mock.mockImplementation((obj1, obj2) => {
      if (obj1 === 'Alice') {
        return 'human'
      }
      if (typeof obj1 === 'number' && typeof obj2 === 'number') {
        return 'numbers'
      }
      if (typeof obj1 === 'function') {
        return 'function'
      }
    }))
  })
})

Writing such mock implementation is unpleasant experience, you end up writing a bunch of if statements and code quickly become messy.

Here is when jestor comes to rescue. With jestor test written above can be written as:

import { jestor } from 'jestor'

describe('my function', function () {
  it('should return a value', function () {
    const mock = jest.fn()
    jestor(mock).followRules((rules) => {
      rules.whenCalledWith('Alice').return('human')
      rules.whenCalledWith(expect.any(Number), expect.any(Number)).return('numbers')
      rules.whenCalledWith(expect.any(Function)).return('function')
    })
  })
})

Why jestor

It should have been named jester, as jester is a person who jests.
However, the names jester, jestr and even jster have been taken. As well as mocker and jocker.

License

MIT (http://www.opensource.org/licenses/mit-license.php)