jbrumwell / mock-knex

A mock knex adapter for simulating a database during testing
MIT License
240 stars 71 forks source link

Multiple trackers #76

Closed Gotusso closed 5 years ago

Gotusso commented 6 years ago

Hi there,

I think I found an issue while debugging a test case. I noticed that we have multiple tests where each one sets up a new mocked knex connection, but then the results are mixed up. It more or less comes to this:

const knex = require('knex');
const mock = require('mock-knex');
const assert = require('assert');

const connector = (fn) => {
  const instance = knex({
    client: 'pg',
  });

  mock.mock(instance);
  const tracker = mock.getTracker();

  tracker.install();
  tracker.on('query', (query) => {
    query.response(fn(query));
  });

  return instance;
};

const db1 = connector(() => {
  return 1;
});
const db2 = connector(() => {
  return 2;
});

db1.select('foo').from('bar').then(result => {
  console.log(result);
  assert(result === 1);
});
Promise {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined }
> 2
Unhandled rejection AssertionError [ERR_ASSERTION]: false == true
    at db1.select.from.then.result (repl:3:3)
    at bound (domain.js:301:14)
    at runBound (domain.js:314:12)
    at tryCatcher (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/promise.js:693:18)
    at Async._drainQueue (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues (/Users/franco/fiit/workout-api/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:781:20)
    at tryOnImmediate (timers.js:743:5)
    at processImmediate [as _immediateCallback] (timers.js:714:5)

I had a quick look and I think mock.getTracker() should not return a singleton, is that right? Or am I misunderstanding the API in any way?

jsumners commented 5 years ago

It's been over a year. Any sort of response would be welcome.

jbrumwell commented 5 years ago

@Gotusso @jsumners my apologies for missing this, we currently only support a single tracker, https://github.com/colonyamerican/mock-knex/blob/master/src/tracker.js#L38, you can mock multiple connections but they will all be reported to the same tracker.

BadgerBadgerBadgerBadger commented 5 years ago

@jbrumwell Any plans to change this? Would be super helpful for my workflow as well.

jalovatt commented 4 years ago

Obviously it's been a year since the previous comment, but I just spent an entire day banging my head against the same problem and wanted to share the workaround I came up with.

We have mock-knex wrapped in another class that also handles setting up a GraphQL schema, resolvers, etc, so we can easily test whether the correct SQL requests are being made. Switching from import mockKnex from 'mock-knex' to a dynamic require allows us to use Jest's resetModules function to wipe the module cache:

class KnexTester {
  constructor() {
    this.knex = knex(...knex config here...);

    jest.resetModules();
    const mockKnex = require(`${process.cwd()}/node_modules/mock-knex`);

    mockKnex.mock(this.knex);
    const tracker = mockKnex.getTracker();
    tracker.install();

    ...other setup...
  }
}

describe('a test block', () => {
  const tester = new KnexTester();

  test(...
});

describe('another test block', () => {
  const tester = new KnexTester();

  test(...
});