Skip to content

Instantly share code, notes, and snippets.

@mattapperson
Created June 29, 2019 20:52
Show Gist options
  • Save mattapperson/7b32d0260b3661c4c217285018212390 to your computer and use it in GitHub Desktop.
Save mattapperson/7b32d0260b3661c4c217285018212390 to your computer and use it in GitHub Desktop.

Automocking thoughts

Allow users to create mocks using 2 APIs... Consumers or providors could write mocks using these tools...

// This block only runs if recording live
await ifLiveBlock(async () => {
  await new Promise(resolve => {
    const pipe = spawn("mongod", ["--dbpath=<LOCATION>", "--port", "1223"]);
    pipe.stdout.on("data", function(data) {
      if (data.indexOf("started") !== -1) {
        resolve();
      }
    });
  });
});

// if CLI flag / env var is set to record, this returns the live server results
// if not, it returns a snapshotted version. When live the above ifLiveBlock would have
// started the server it would connect to making the process seamless
const results = await memorized("Mocked query for bar", async () => {
  const client = await mongodb.connect({ port: 1223 });
  return client.query({ foo: "bar" });
});

// In the above call to memorizeMock we have a name, a function that conditionaly called
// if we are "recording" or the snapshotted response if playing back.

Pros:

  • one test/mock file, and one step... No need to write a test that generates the mocks first, allowing it to feel a lot more like Jest snapshots.
  • This not only allows for tests to be run as unit tests... but if the CI flag is on also as intigration tests. All with a single test being written!
  • No setup to ensure is working localy or a CI... enviorment starting or not is not programaticly controlled in the test itself

That's the API... in practice it would look more like this:

///////////////////////
// user.test.js
///////////////////////
test("user creation works", () => {
  const user = require("../user");
  return user.create("mitchell", 22);
});

///////////////////////
// ./__mocks__/user.js
///////////////////////
const user = jest.genMockFromModule("../user");

// If the tests using this mock are live, this runs, otherwise it does not
await ifLiveBlock(async () => {
  await new Promise(resolve => {
    const pipe = spawn("mongod", ["--dbpath=<LOCATION>", "--port", "1223"]);
    pipe.stdout.on("data", function(data) {
      if (data.indexOf("started") !== -1) {
        resolve();
      }
    });
  });
});

// If live, this returns data from the live mongodb server,
// otherwise it returns from the memorized data saved to a snapshot
user.create = (name, age) => {
  return await memorized(`create-user`,
  async () => {
    const mongodb = require('mongodb');
    const client = await mongodb.connect({ port: 1223 });
    return await client.insert({ name, age });
  }, [...args]
  // ˆˆ matches all args to the snapshot data
);
};

module.exports = user;

If memorized/ifLiveBlock use an env var to toggle live vs mocked data, then this becomes Test framework agnostic.

This API/setup also means I can make use of all the advantages of this regardless of if I am the providor OR the consumer of the mocks, meaning I don't need to get buy-in from the entire team or company to use it.

@mattapperson
Copy link
Author

Yes, but this would still require one of the following:

  1. enough buy-in from the provider to use toMatchMock.
  2. write my own test that uses toMatchMock.

Or am I missing something?

If I am not missing something, this is a major issue.

Based on your blogs I think this is both correct and an intended “feature”... it just does not work well for all use-cases... including mine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment