Necesito verificar que todas las llamadas de transacción se hayan realizado correctamente. Aquí está el ejemplo:
module.js
const functionUnderTest = async (helper) => { await helper.transaction(async (transaction) => { await helper.doSomething(); await helper.doSomething2(); await helper.expectedToBeCalled(); console.log("done"); }); }; module.exports = { functionUnderTest, };El problema viene, que por alguna razón con sinon no puedo verificar que la última llamada se haya realizado, sin embargo, siempre se imprime el mensaje "hecho".
Aquí cómo se ve la salida
$ npm run test > sinon-test@1.0.0 test > mocha module ✔ the former function should be called done 1) the latter function should be called done 1 passing (7ms) 1 failing 1) module the latter function should be called: AssertionError: expected stub to have been called at least once, but it was never called at Context.<anonymous> (test/module.test.js:31:48) at processTicksAndRejections (node:internal/process/task_queues:96:5)Las pruebas en sí se representan a continuación.
helpers/chai.js
const chaiAsPromised = require("chai-as-promised"); const chaiSinon = require("sinon-chai"); chai.use(chaiSinon); chai.use(chaiAsPromised); module.exports = { expect: chai.expect }; test/module.test.js
const { expect } = require("./helpers/chai"); const sinon = require("sinon"); const { functionUnderTest } = require("../module"); describe("module", function () { let sandbox; let mockHelper; const transaction = {}; beforeEach(function () { sandbox = sinon.createSandbox(); mockHelper = { transaction: sandbox.stub().callsArgWithAsync(0, transaction), doSomething: sandbox.stub().resolves({}), doSomething2: sandbox.stub().resolves({}), expectedToBeCalled: sandbox.stub().resolves({}), }; }); afterEach(function () { sandbox.restore(); }); it("the former function should be called", async function () { await functionUnderTest(mockHelper); expect(mockHelper.doSomething).to.be.called; }); it("the latter function should be called", async function () { await functionUnderTest(mockHelper); expect(mockHelper.expectedToBeCalled).to.be.called; }); });Para que sea completo y fácil de probar, he creado un repositorio con el que puedes jugar: https://github.com/vichugunov/sinon-test
mi pregunta son:
PD: si la llamada await helper.doSomething2() está comentada, las pruebas están pasando
No entiende las versiones asíncronas callsArg* y yields* para stubs. Vea este PR , la diferencia es que las versiones asíncronas callsArg* harán lo siguiente:
- En el entorno Node, la devolución de llamada se difiere con
process.nextTick.- En un navegador, la devolución de llamada se difiere con
setTimeout(callback, 0).
No espera a que se complete la función de devolución de llamada asincrónica. async/await en el caso de prueba solo puede esperar a que se complete la función asíncrona await helper.transaction() , no su devolución de llamada asíncrona.
La versión de sincronización de callsArg* llamará a la devolución de llamada inmediatamente. Puede echar un vistazo a este problema , cuando debería usar versiones asincrónicas callsArg* .
Por lo tanto, cuando el caso de prueba realiza una aserción, la función asincrónica como helper.expectedTobecalled() no se completa.
Debe usar callsFake() para proporcionar una devolución de llamada de código auxiliar asíncrono para el método helper.transaction() e invocarlo con async/await .
P.ej
module.js :
const functionUnderTest = async (helper) => { await helper.transaction(async (transaction) => { await helper.doSomething(); await helper.doSomething2(); await helper.expectedToBeCalled(); console.log('done'); }); }; module.exports = { functionUnderTest }; module.test.js :
const sinon = require('sinon'); const { functionUnderTest } = require('./module'); describe('module', function () { let sandbox; let mockHelper; const transaction = {}; beforeEach(function () { sandbox = sinon.createSandbox(); mockHelper = { transaction: sandbox.stub().callsFake(async (callback) => { await callback(transaction); }), doSomething: sandbox.stub().resolves({}), doSomething2: sandbox.stub().resolves({}), expectedToBeCalled: sandbox.stub().resolves({}), }; }); afterEach(function () { sandbox.restore(); }); it('the former function should be called', async function () { await functionUnderTest(mockHelper); sinon.assert.calledOnce(mockHelper.doSomething); }); it('the latter function should be called', async function () { await functionUnderTest(mockHelper); sinon.assert.calledOnce(mockHelper.expectedToBeCalled); }); });Resultado de la prueba:
module done ✓ the former function should be called done ✓ the latter function should be called 2 passing (5ms)