Skip to content

Idea: Type-safe mocks registry #191

@eegli

Description

@eegli

While I really like the idea proposed in #175, there are a few flaws to it (still, thanks for pushing this @liveFreeOrCode!).

Since mockInstances and _mockClasses are static on MVCObject, every child instance will have the same mixed-array containing itself and other children. There's no type-safety.

I thought that maybe we can have some kind of global mocks registry with type-safe getters per class that inherits from MVCObject. Consider the following example:

A simple jest implementation:

const jest_ = {
  fn() {
    return () => {
      // Jest stuff
      console.log("I'm a mock!");
    };
  }
};

A global mock registry (not exposed in the package):

const MOCKS_REGISTRY = new Map<string, any[]>();

The mocked classes:

class MVCObject {
  constructor() {
    const ctr = this.constructor;
    const existing = MOCKS_REGISTRY.get(ctr.name) || [];
    MOCKS_REGISTRY.set(ctr.name, [...existing, this]);
  }
  parentMethod = jest_.fn();
}

class GoogleMap extends MVCObject {
  mapMethod = jest_.fn();
}

class GoogleMarker extends MVCObject {
  markerMethod = jest_.fn();
}

Now every child class instantiation will have its unique key in the registry. The mock instances are exposed like so:

function getMockInstances<T extends { new (...args: any[]): {} }>(
  constructor: T
): InstanceType<T>[] {
  return MOCKS_REGISTRY.get(constructor.name) || [];
}

Usage:

new MVCObject();

new GoogleMap();
new GoogleMap();
new GoogleMap();

new GoogleMarker();

const mvcs = getMockInstances(MVCObject); // [MVCObject]
const maps = getMockInstances(GoogleMap); // [GoogleMap, GoogleMap, GoogleMap]
const markers = getMockInstances(GoogleMarker); //  [GoogleMarker]

mvcs[0].parentMethod(); // (property) MVCObject.parentMethod: () => void
maps[0].parentMethod(); // (property) MVCObject.parentMethod: () => void
markers[0].markerMethod(); // (property) GoogleMarker.markerMethod: () => void

Now all methods (inherited and own) are inferred correctly. Of course, it's still up to the users to decide if mock instances have been created (meaning that the length of the returned mocks array is larger than 0).

// Does not exist on google.maps
getMockInstances(class X {}); // []

I made a little sandbox to experiment: https://codesandbox.io/s/charming-wind-xyqfh?file=/src/index.ts

Let me know what you think. It's just an idea and maybe worth exploring.

Metadata

Metadata

Assignees

No one assigned

    Labels

    releasedtriage meI really want to be triaged.type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions