Tran B. V. Son
Tran B. V. Son

Reputation: 839

Spy function with params by Sinon.js

I'm trying to write some unit tests of code that uses typeorm without hitting the DB. And I'm using sinon for spy/stub/mock. This is my function.

  async updateDoingToFailedWithLock(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.manager
      .getRepository(Report)
      .createQueryBuilder("report")
      .useTransaction(true)
      .setLock("pessimistic_write")
      .update(Report)
      .set({ status: ReportStatus.FAILED })
      .where(`(status = "doing")`)
      .execute();
  }

I already wrote a fake test to make sure execute() is called by using spy function. But I want to test the params of these functions createQueryBuilder..., the sure the params are correct. I took a look at sinon document and it seems like sinon support test params by this API: spy().withArgs(arg1, arg2...).

But I'm not sure how to spy my function correctly.

describe("updateDoingToFailedWithLock()", (): void => {
    let sandbox: Sinon.SinonSandbox;

    beforeEach(() => (sandbox = Sinon.createSandbox()));
    afterEach(() => sandbox.restore);

    it("should be success", async (): Promise<void> => {
      const fakeManager = {
        getRepository: () => {
          return fakeManager;
        },
        createQueryBuilder: () => {
          return fakeManager;
        },
        useTransaction: () => {
          return fakeManager;
        },
        setLock: () => {
          return fakeManager;
        },
        update: () => {
          return fakeManager;
        },
        set: () => {
          return fakeManager;
        },
        where: () => {
          return fakeManager;
        },
        execute: () => {},
      };
      const fakeQueryRunner = {
        manager: fakeManager,
      };
      const connection = new typeorm.Connection({ type: "mysql" });
      const reportService = new ReportService();
      sandbox.stub(connection, "createQueryRunner").callsFake((): any => {
        return fakeQueryRunner;
      });

      const queryRunner = connection.createQueryRunner();
      const spy = sandbox.spy(fakeManager, "execute");

      reportService.updateDoingToFailedWithLock(queryRunner);
      expect(spy.calledOnce).be.true;
    });
  });

Any help is welcome. Thanks in advance!

Upvotes: 0

Views: 466

Answers (1)

deerawan
deerawan

Reputation: 8443

I saw your code and there's something can be improved:

  • Use returnsThis() to replace return fakeManager
  • Don't forget await when calling updateDoingToFailedWithLock
describe("updateDoingToFailedWithLock()", (): void => {
  let sandbox: sinon.SinonSandbox;

  beforeEach(() => (sandbox = sinon.createSandbox()));
  afterEach(() => sandbox.restore);

  it("should be success", async (): Promise<void> => {

    // using returnsThis()
    const fakeManager = {
      getRepository: sandbox.stub().returnsThis(),
      createQueryBuilder: sandbox.stub().returnsThis(),
      useTransaction: sandbox.stub().returnsThis(),
      setLock: sandbox.stub().returnsThis(),
      update: sandbox.stub().returnsThis(),
      set: sandbox.stub().returnsThis(),
      where: sandbox.stub().returnsThis(),
      execute: sandbox.stub().returnsThis(),      
    }

    const fakeQueryRunner = {
      manager: fakeManager,
    };

    const reportService = new ReportService();

    // having await here is important
    await reportService.updateDoingToFailedWithLock(fakeQueryRunner);


    expect(fakeManager.execute.calledOnce).to.be.true;
    expect(fakeManager.createQueryBuilder.calledWith('report')).to.be.true;
  });
});

Hope it helps

Upvotes: 1

Related Questions