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 🙏

© 2025 – Pkg Stats / Ryan Hefner

terse-mock

v2.0.0

Published

Easy mock creation and automocking

Downloads

303

Readme

JS/TS Tests in a Couple of Lines

License: MIT coverage

The goal of this project is to make it easier to create mocks and stubs and to reduce the amount of code when writing tests in general.

Install

npm (terse-mock on npm):

npm install --save-dev terse-mock

yarn

yarn add --dev terse-mock 

Introduction

terse-mock is intended to use as an addition to existing test frameworks such as Jest.
The module provides a number of functions:

terse-mock is tested with Jest so Jest tests are used in examples below.

Typical usage

import { tmock } from 'terse-mock';

test('some test', () => {
  // ARRANGE
  const mock = tmock([ // create mock
    [m => m.prop1.prop2, true], // setup mock value
    [m => m.f('some value').prop3, 7], // setup mock value
    [m => m.f('some other value'), {}], // setup mock value
  ]);

  // ACT
  const res = sut(mock); // pass mock to system under test

  // ASSERT
  const unmockedRes = tunmock(res); // remove possible proxies (optional but strongly recommended)
  expect(unmockedRes).toEqual(expectedResult); // check expectations
});

Features

Deep automocking

Normally one need to setup all mock values to get sut work.

Suppose we have a SUT:

function sut(obj) {
  const r1 = obj.getSomething(true).doSomething();
  const r2 = r1 ? obj.getSomethingElse('a').length : null;
  const r3 = obj.getSomethingElse('b', true);

  return {
    prop1: r1,
    prop2: r2,
    prop3: r3,
  };
}

The test for the whole return value could be like:

test('should return expected result under certain conditions', () => {
  // ARRANGE
  const mock = tmock([
    [m => m.getSomething(true).doSomething(), true],
    [m => m.getSomethingElse('a').length, 1],
    [m => m.getSomethingElse('b', true), 'something'],
  ]);

  // ACT
  const res = sut(mock);

  // ASSERT
  expect(tunmock(res)).toEqual({
    prop1: true,
    prop2: 1,
    prop3: 'something',
  });
});

Auto-mocking feature allows you to skip initialisation of mock values without breaking the sut.
Let's say you want to test only prop1 and don't care about prop2 and prop3.
Then the test could be like:

test('should prop1 have some value under some conditions', () => {
  // ARRANGE
  const mock = tmock([
    [m => m.getSomething(true).doSomething(), true],
  ]);

  // ACT
  const res = sut(mock);

  // ASSERT
  expect(tunmock(res).prop1).toBe(true);
});

Or even

test('should prop1 have some value under some conditions, shortest test', () => {
  // ARRANGE
  const mock = tmock();

  // ACT
  const res = sut(mock);

  // ASSERT
  expect(tunmock(res).prop1).toBe('<mock>.getSomething(true).doSomething()');
});
Test Suites: 1 passed, 1 total

Here prop1 contains the path it got the value from.

Setting mock values

For the SUT defined above make mock return different values for property so we could test all code paths:

test.each([
  ['should prop2 have some value under some conditions', true, 10],
  ['should prop2 be null under some other conditions', false, null],
])('%s', (__, doSomethingResult, expectedResult) => {
  // ARRANGE
  const mock = tmock([
    [m => m.getSomething(true).doSomething(), doSomethingResult],
    [m => m.getSomethingElse('a').length, 10],
  ]);

  // ACT
  const res = sut(mock);

  // ASSERT
  expect(tunmock(res).prop2).toBe(expectedResult);
});

Stubs

If one need neither automocking nor checking function calls then it worth using stubs rather then mocks. terse-mock stubs are plain js objects, fast and straightford.

test('stub demo', () => {
  // ARRANGE
  const stub = tstub([
    [s => s.a.aa, 0],
    [s => s.f(), 'result'],
    [s => s.b, { bb: 1 }],
  ]);

  // ASSERT
  expect(stub).toEqual({
    a: { aa: 0 },
    f: expect.any(Function),
    b: { bb: 1 },
  });
  expect(stub.f()).toEqual('result');
});

Creating functions that return different values per set of arguments

test('function that return different values per set of arguments demo', () => {
  // ARRANGE
  const f = tstub([
    [s => s(TM_ANY), 0],
    [s => s(), 1],
    [s => s('a'), 2],
    [s => s('b'), 3],
    [s => s('b', true), 4],
  ]);

  // ASSERT
  expect(f('something')).toEqual(0);
  expect(f()).toEqual(1);
  expect(f('a')).toEqual(2);
  expect(f('b')).toEqual(3);
  expect(f('b', true)).toEqual(4);
});

Interface mocks

Generic form of tmock/tstub is available if one wants to use benefits like static type checking and code completion

Static type checking and code completion

Call history

Module keeps history of function calls. The code below demonstrates how one can check call order and arguments passed to functions:

test('check calls demo', () => {
  // ARRANGE
  const mock = tmock([
    [m => m.f1(), 1],
  ]);

  // ACT
  mock.f1();
  mock.prop.f2(1, false);
  mock.prop.f2({ b: 'b' }).g(1);

  // ASSERT
  // All calls log
  expect(tinfo().callLog).toEqual([
    '<mock>.f1()',
    '<mock>.prop.f2(1, false)',
    `<mock>.prop.f2({b: 'b'})`,
    `<mock>.prop.f2({b: 'b'}).g(1)`,
  ]);
  // Examine arguments of a particular call
  expect(tinfo(mock.prop.f2).calls[1][0]).toEqual({
    b: 'b',
  });
  expect(tinfo(mock, m => m.prop.f2({ b: 'b' }).g).calls[0][0]).toBe(1);
});

This also can be useful for debugging purposes to examine all calls fo mocked functions in sut.

Automatic spies

terse-mock automatically creates spies for js functions found in values passed to tmock and tset. Calls to this functions get to call log and can be analyzed with tinfo.

test('automatic spies demo', () => {
  // ARRANGE
  const obj = {
    nestedObj: {
      f: function (n) { return n > 7 },
    },
  };
  const mock = tmock([m => m.obj, obj]);

  // ASSERT
  expect(mock.obj.nestedObj.f(7)).toBe(false);
  expect(mock.obj.nestedObj.f(8)).toBe(true);
  expect(tinfo(mock).callLog).toEqual([
    '<mock>.obj.nestedObj.f(7)',
    '<mock>.obj.nestedObj.f(8)',
  ]);
});

Using with 3rd party mocks

terse-mock can use 3rd party mocks to analyze calls to mocked functions. To do so one need to create adapter for 3rd party mock by implementing IExternalMock interface provided by the module and pass the adapter to tmock. The test demonstrates how to use Jest mocks for call analyzing:

const jestMock: IExternalMock = {
  create: () => jest.fn(),
};

test('using Jest function to analyze calls to mocked functions demo', () => {
  // ARRANGE
  tlocalopt({ externalMock: jestMock });
  const mock = tmock();

  // ACT
  mock.f(7);

  // ASSERT
  const externalMockForF = tinfo(mock.f).externalMock;
  expect(externalMockForF).toHaveBeenCalledTimes(1);
  expect(externalMockForF).toHaveBeenCalledWith(7);
});

3rd party mocks can also be used as return values for terse-mock mocks:

test('using Jest function as mock value demo', () => {
  // ARRANGE
  const jestFn = jest.fn();
  const mock = tmock({ f: jestFn });

  // ACT
  mock.f();

  // ASSERT
  expect(mock.f).toHaveBeenCalledTimes(1);
});

Module mocks

terse-mock mocks can be used as return values from Jest module factory for jest.mock()
Please note that the example below uses the alternative way of setting mock values, as it is well suited for such cases.

jest.mock('some-module', () => tmock('some-module', {
  someFunction: () => 'some value',
}));

Another example with expectation on mocked module function calls:

jest.mock('./module', () => tmock());
import { someFunction } from './module';
import { sut } from './sut-that-uses-module';

test('should call someFunction', () => {
  // ACT
  sut();

  // ASSERT
  expect(tinfo(someFunction).calls.length > 0).toBe(true);
});

Resetting mocks

Mock or any of its part can be reset by treset. That means that all mock touches, mock calls and mock values that were setup outside tmock and tset (e.g in sut) are cleared out from mock while values setup by tmock and tset persist. Calling treset with mock argument will also reset all nested mocks.

test('reset mocks demo', () => {
  // ARRANGE
  const mock = tmock([m => m.p.pp, 'val']);

  // Oparate mock in sut.
  mock.p = {}; // Replace value.
  mock.a.f().c = true; // Add new value.
  mock.b; // Touch.
  expect(tunmock(mock)).toEqual({ // Unmock to observe all mock values at once
    p: {},
    a: {
      f: expect.any(Function),
    },
    b: '<mock>.b',
  });

  // ACT
  treset(mock);

  // ASSERT
  expect(tunmock(mock)).toEqual({
    p: {
      pp: 'val',
    },
  });
});

Other

Some of minor features are listed below. Examine terse-mock tests for the rest of features and examples.

Alternative way of setting mock values

Besides setup tuples there is another way of setting mock values: initialization object. This option is well suited for module mocks.

test('two ways of setting mock values demo', () => {
  // ARRANGE
  const stub = tstub([
    { // with object
      a: 'value for a', // equivalent to tuple [s => s.a, 'value for a']
    },
    [s => s.b, 'value for b'], // with tuple
    [s => s.c, 'value for c'], // with tuple
  ]);

  // ASSERT
  expect(stub).toEqual({
    a: 'value for a',
    b: 'value for b',
    c: 'value for c',
  });
});

Import all at once

Module has default export with all module functions and constants.
Instead of

import { tmock, TM_ANY } from 'terse-mock';

const mock = tmock([m => m.f(TM_ANY), 1]);

one can write

import tm from 'terse-mock';

const mock = tm.mock([m => m.f(tm.ANY), 1]);

Nested mocks

terse-mock mocks can be freely used as mock values in tmock and tset.

test('nested mocks demo', () => {
  // ARRANGE
  const mock = tmock([
    [m => m.nestedMock, tmock([ // nested mock
      [mm => mm.prop1, 1],
    ])],
    [m => m.prop, 'val'],
  ]);
  mock.nestedMock.anotherProp = 5;

  // ASSERT
  expect(mock.nestedMock.prop1).toBe(1);
  expect(mock.nestedMock.anotherProp).toBe(5);
  expect(tunmock(mock)).toEqual({
    nestedMock: {
      prop1: 1,
      anotherProp: 5,
    },
    prop: 'val',
  });
});

Collapsing long arguments

By default module machinery shorten string representation of mock touches - it collapses the contents of objects, arrays and long mocks in functions arguments. If you need to see the contents of collapsed data, you can use the collapseLongValues option. Use collapseThreshold option to set the string length threshold after which the data will be collapsed.

test('collapsed output enabled/disabled demo', () => {
  // ARRANGE
  tlocalopt({
    collapseLongValues: true,
    collapseThreshold: 6,
  });

  // ACT
  const result = tmock().f(
    tmock('a').f(1), // length of 'a.f(1)' is 6
    { a: 1 }, // length of '{a: 1}' is 6
    [1, 2], // length of '[1, 2]' is 6
    tmock('aa').f(1), // length of 'aa.f(1)' > 6
    { a: 11 }, // length of '{a: 11}' > 6
    [1, 2, 3], // length of '[1, 2, 3]' > 6
  );

  // ASSERT
  expect(tunmock(result)).toBe('<mock>.f(a.f(1), {a: 1}, [1, 2], <...>, {...}, [...])');
});

Module options

tglobalopt allows to customise module settings e.g. to set default name for mocks or turn automocking on/of.
tlocalopt allows to override module settings temporarly untill the treset is called.

test('module options demo', () => {
  // ARRANGE
  tglobalopt({
    defaultMockName: 'newDefaultMockName',
  })
  const mock = tmock();

  // ACT
  const res = tunmock(mock.a);

  // ASSERT
  expect(res).toBe('newDefaultMockName.a');
});