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

mockshot

v0.2.8

Published

Generate mocks from your snapshot tests

Downloads

11

Readme

Automatic mocks generation from snapshot tests

GitHub license npm version code style: prettier Tested with Jest

TL;DR

Imagine you could:

  1. Never manually write a mock again
  2. Have a guarantee that your mocks are always valid

Mockshot give you these superpowers, and more.

Overview

Snapshot testing may commonly be known for UI testing, but the mechanism itself can be used to test the shape of any object. Mockshot utilizes the artifacts of snapshot tests to generate mocks. The flow can be summarized:

  1. Write a Jest snapshot test for a method.
  2. Use the snapshot's output as blueprints for generating a mock.
  3. Let other methods use that mock in their tests.

In this flow, we test a method against its own mock, then expose this mock to the world. This means we are shifting the responsibility of generating a mock from the consumer to the source.

This pattern is called Test Coupling since two isolated unit tests are now coupled together by the same mock. A change in the source's interface will lead to a change in the mock and from there - to all consumer's tests.

Your unit test is now powerful as an integration test. Wow.

Usage

install

Mockshot requires the jest testing framework. Installation of Jest is not covered in this document.

After setting up Jest, simply yarn or npm Mockshot

$ yarn install mockshot

Quickstart

1. Write a test:

import "mockshot";
import { SomeClass } from "./SomeClass";

describe("SomeClass", () => {
  it("getSomeData should return the correct shape", () => {
    // Arrange
    const instance = new SomeClass();

    // Act
    const result = instance.getSomeData();
    // result === { foo: "bar" }

    // Assert with Mockshot
    expect(result).toMatchMock(SomeClass, "getSomeData", "success");
  });
});

2. Run the test to generate a snapshot:

$ jest './SomeClass.spec.ts'
 PASS  examples/simple/SomeClass.spec.ts
  SomeClass
    ✓ getSomeData should return the correct shape (5ms)

 › 1 snapshot written.
Snapshot Summary
 › 1 snapshot written from 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 written, 1 total
Time:        5.213s
Ran all test suites matching /.\/SomeClass.spec*/i.
✨  Done in 6.80s.

3. Run mockshot to generate a mock:

$ yarn run mockshot

The generated mock is now ready for use in ./mocks/SomeClassMocks.ts:

export class SomeClassMocks {
  static getSomeData(mock: "success"): any {
    switch (mock) {
      case "success":
        return {
          foo: "bar"
        };
      default:
        throw Error("Unknown mock: " + mock);
    }
  }
}

4. Consume the mock

import { UsingSomeClass } from "./UsingSomeClass";
import { SomeClassMocks } from "./mocks/SomeClass";

describe("UsingSomeClass", () => {
  it("Should parse getSomeData", () => {
    // Prepare the stub with our mock data
    const someClassMock = {
      getSomeData: () => SomeClassMocks.getSomeData("success")
    };
    const instance = new UsingSomeClass(someClassMock);

    // Now when UsingSomeClass will call getSomeData it will get { foo: "bar" }
  });
});

Key Features

  1. Mock any Javascript object using custom matchers.
  2. Special matchers for API responses for generating server mocks.
  3. Mocks are using Typescript for enhanced auto-complete.
  4. Special generators for class mocks, API server mocks and more.

Mockshot, In Depth

Introduction

Mockshot is an extension over Jest's snapshot mechanism. It uses toMatchSnapshot under the hood to create special annotated snapshots that can later be used buy a generator to construct JS or TS objects using AST.

Matchers

Matchers are the assert methods used during the test to generate the mock blueprints. They serialize the object and prepare its shape. We currently have 2 matchers:

toMatchMock - for mocking class method

toMatchMock(className: string, methodName: string, mockName: string, ignorePath: any[])

className: string | Object

The name of the class to mock. You can supply a string but it is better to provide the actual class. Mockshot will detect the class's name by looking at cls.constructor.name.

methodName: string

The name of the method response to mock. Unfortunately we can't auto detect the name of the method just by looking at its reference, so make sure this string is correct.

mockName

The name of the mock. Since each method can have multiple responses, we provide a name for each mock, ie - success or empty-list or error are some examples.

ignorePath

An array of paths to ignore. Since snapshot matches the objects, a non constant values like id or timestamp will change from test to test. You can provide an ignore path to ignore the content of this values. In that case, Mockshot will only check the existence of the keys and the type of the value, without looking at the content (ie, it will verify there is a key named id with value type string).

const value = SomeClass.getSomething();
expect(value).toMatchMock(SomeClass, "getSomething", "success", ["id"]);

toMatchApiMock - for mocking HTTP response

Same as previous matcher, but designed especially to serialize an HTTP response. In that case you don't need to supply a class or method name, since all required data as path, status and methods is infered from the object.

const value = await axios.get("http://somewhere.com/user");
expect(value).toMatchMock(value);

This will generate the following mock:

export class API {

    static get<T extends keyof getResponses>(url: T): getResponses[T] {
        switch (url) {
            case "/user":
                return { success:
                   { body:
                      { data: /* Response serialized here */ }
                    status: 'OK' },
                    statusCode: 200 } }
}

You can then use the mock:

import { API } from "./mocks";

const response = API.get("/user", success);
/**
 * response is now the same HTTP Response object as we had before
 * */
axios.get.mockImplementation(()=>response)

Generator

After you've created the snapshots you will run the generator. It will traverse the codebase, looking for snapshots created by Mockshot and generate and actual Typescript and Javascript files with your mocks, depending on their type (methods or api).

TBA