lundi 13 janvier 2020

How do I mock an imported class definition with sinon

I can't seem to properly mock an import in my spec file and I am wondering if anyone can see what I am missing.

Here is the exported class for my Database connection

import Knex from 'knex';
import { merge } from 'lodash';
import knexfile from '../knexfile';

class Database {
  private knexInstance: Knex;
  private config: object;

  connect(options = {}): void {
    if (this.knexInstance) {
      return;
    }
    this.config = merge({}, knexfile, options);
    this.knexInstance = Knex(this.config);
  }

  get query(): Knex {
    if (!this.knexInstance) {
      this.connect();
    }

    return this.knexInstance;
  }

  close(done): void {
    if (!this.knexInstance) {
      done();
      return;
    }

    this.knexInstance.destroy(done);
  }
}

export default new Database();

Here is the action file that is trying to use the database file.

import db from '../../database';
const tableName = 'attempts';

export const typeDef = `
  extend type Query {
    attempt(id: String): Attempt!
  }

  extend type Mutation {
    createAttempt(questionId: String!, attemptId: String!, choiceId: String): Attempt
  }

  type Attempt {
    id: String!
    correctanswers: Int!
    userid: String!
    examid: String!
  }
`;

export const resolvers = {
  Query: {
    attempt(_, { id = '' }) {
      return db
        .query(tableName)
        .where({ id })
        .first();
    },
  },
  Mutation: {
    async createAttempt(root, args) {
      const [answer] = await db
        .query(tableName)
        .insert(args)
        .returning('*');

      return answer;
    },
  },
};

And here is my test file.

import { createSandbox } from 'sinon';
import { resolvers } from './answer';
import db from '../../database';
import * as should from 'should';

const sandbox = createSandbox();

describe('Answer', () => {
  afterEach(() => sandbox.restore());

  describe('Query Answer', () => {
    it('should return answer by id', async () => {
      const expected = { id: 'xxx' };
      const firstSpy = sandbox.fake.resolves(expected);
      const whereSpy = sandbox.fake.resolves({
        first: firstSpy,
      });

      // This stub never seems to get called. It doesn't look like the import is ever being replaced with the stub in the implementation file.
      const querySpy = sandbox.stub(db, 'query').callsFake(() => {
        return Promise.resolve({
          where: whereSpy,
        });
      });
      const inputId = '100';

      const result = await resolvers.Query.answer(null, { id: inputId });
      sandbox.assert.calledOnce(querySpy);
      sandbox.assert.calledOnce(whereSpy);
      sandbox.assert.calledOnce(firstSpy);
      result.should.deepEqual(expected);
    });
  });
});

When I run the tests it doesn't look like the import is ever being replaced with the stub in the implementation file and I don't see why.

Aucun commentaire:

Enregistrer un commentaire