sinon.promise()

Created on 3 May 2021  路  4Comments  路  Source: sinonjs/sinon

When testing callback based code, we can create fakes that yield (e.g. sinon.fake.yield(null, "result")), and we can also programatically invoke the callback somewhere in a test (e.g. myFake.callback(null, "result")).

When testing promise based code, we only have the first option with sinon.fake.resolves("result"), and there is no convenient way to have a fake return a promise and control when it is invoked.

I'm currently helping myself with something like this:

const resolver = sinon.fake();
const promise = new Promise(resolver);
const fake = sinon.fake.returns(promise);

// trigger something

resolver.firstCall.firstArg("result");
await promise;

Proposal

Here is an example using fakes, but this would work the same way with stubs:

const promise = sinon.promise();
const fake = sinon.fake.returns(promise);

// trigger something

await promise.resolve("result");

The sinon promise could be a regular promise and expose these additional functions:

  • resolve(value)
  • reject(value)

and these properties:

  • resolvedValue
  • rejectedValue

Please let me know your thoughts.

Feature Request Help wanted

Most helpful comment

Here is a simple, runnable example:

'use strict';

const fs = require('fs/promises');

async function readPackageJson() {
  const json = await fs.readFile('package.json', 'utf8');
  return JSON.parse(json);
}

// ----------------------------------------------------------------

const assert = require('assert');
const sinon = require('sinon');

describe('readPackageJson', () => {
  afterEach(() => {
    sinon.restore();
  });

  it('reads package.json before invoking JSON.parse with result', async () => {
    const resolver = sinon.fake();
    const promise = new Promise(resolver);
    sinon.replace(fs, 'readFile', sinon.fake.returns(promise));
    sinon.replace(JSON, 'parse', sinon.fake.returns({}));

    readPackageJson();

    sinon.assert.calledWith(fs.readFile, 'package.json', 'utf8');
    sinon.assert.notCalled(JSON.parse);

    const json = '{"version":"1.0.0"}';
    // The following causes the promise to resolve and the await to complete in the implementation.
    // It would read nicer as `await promise.resolve(json)`.
    resolver.firstCall.firstArg(json);
    await promise;

    sinon.assert.calledWith(JSON.parse, json);
  });
});

All 4 comments

This seems like a great addition

I don't understand the examples ...

Here is a simple, runnable example:

'use strict';

const fs = require('fs/promises');

async function readPackageJson() {
  const json = await fs.readFile('package.json', 'utf8');
  return JSON.parse(json);
}

// ----------------------------------------------------------------

const assert = require('assert');
const sinon = require('sinon');

describe('readPackageJson', () => {
  afterEach(() => {
    sinon.restore();
  });

  it('reads package.json before invoking JSON.parse with result', async () => {
    const resolver = sinon.fake();
    const promise = new Promise(resolver);
    sinon.replace(fs, 'readFile', sinon.fake.returns(promise));
    sinon.replace(JSON, 'parse', sinon.fake.returns({}));

    readPackageJson();

    sinon.assert.calledWith(fs.readFile, 'package.json', 'utf8');
    sinon.assert.notCalled(JSON.parse);

    const json = '{"version":"1.0.0"}';
    // The following causes the promise to resolve and the await to complete in the implementation.
    // It would read nicer as `await promise.resolve(json)`.
    resolver.firstCall.firstArg(json);
    await promise;

    sinon.assert.calledWith(JSON.parse, json);
  });
});

Now I get it. Thank you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JakobJingleheimer picture JakobJingleheimer  路  3Comments

stephanwlee picture stephanwlee  路  3Comments

andys8 picture andys8  路  4Comments

akdor1154 picture akdor1154  路  4Comments

zimtsui picture zimtsui  路  3Comments