Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sinon.promise() implementation #2369

Merged
merged 2 commits into from May 25, 2021
Merged

Add sinon.promise() implementation #2369

merged 2 commits into from May 25, 2021

Conversation

mantoni
Copy link
Member

@mantoni mantoni commented May 6, 2021

Purpose (TL;DR)

This is an implementation of the feature request described in #2367 (sinon.promise()).

Background

The state of a promise can only be controlled by the promise itself. Also, promises do not expose their state, which makes it difficult to work with them in tests.

Solution

The sinon.promise([executor]) function returns a new promise with this additional API:

  • status: The internal status of the promise, one of pending, resolved or rejected.
  • resolvedValue: The promise resolved value.
  • rejectedValue: The promise rejected value.
  • resolve(value): Resolves the promise with the given value. Throws if the promise is not pending.
  • reject(value): Rejects the promise with the given value. Throws if the promise is not pending.

A new promise can be created with a custom executor. This may be a fake or stub instance, or a custom function. If the custom executor resolves or rejects the promise, the above fields are populated accordingly.

Example:

var promise = sinon.promise(function (resolve) {
  resolve(42);
});

assert.equals(promise.status, "pending");
await promise;
assert.equals(promise.status, "resolved");
assert.equals(promise.resolvedValue, 42);

Furthermore the promise.resolve(value) and promise.reject(value) functions return promises, so that the caller can await until the sinon promise has settled. These promises always resolve successfully.

Example:

var promise = sinon.promise();
var error = new Error();

await promise.reject(error);

assert.equals(promise.status, "rejected");
assert.same(promise.rejectedValue, error);

How to verify

  1. Check out this branch
  2. npm install
  3. npm test

Checklist for author

  • npm run lint passes
  • References to standard library functions are cached.

@mantoni mantoni marked this pull request as ready for review May 6, 2021 19:19
@mantoni mantoni requested review from mroderick and fatso83 May 6, 2021 19:19
Copy link
Member

@mroderick mroderick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good 👍

Would you mind adding some documentation in the Jekyll site, so users can learn how to use it?

lib/sinon/promise.js Outdated Show resolved Hide resolved
Comment on lines 9 to 17
promise
.then(function (val) {
status = "fulfilled";
value = val;
})
.catch(function (reason) {
status = "rejected";
value = reason;
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason not to use await wrapped in try/catch instead of then/catch on the promise?

Suggested change
promise
.then(function (val) {
status = "fulfilled";
value = val;
})
.catch(function (reason) {
status = "rejected";
value = reason;
});
try {
status = "fulfilled";
value = await promise;
} catch (reason) {
status = "rejected";
value = reason;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there is a good reason: We don't want to await the promise, because we want to know if the promise is still pending. I committed your suggestion, but then there's a test failure and I reverted.

@mantoni
Copy link
Member Author

mantoni commented May 7, 2021

Thanks for reviewing. Before spending time on writing documentation, I wanted to get some feedback.

We can keep iterating on this PR for a bit until everyone is happy with the API and implementation.

@mantoni
Copy link
Member Author

mantoni commented May 19, 2021

I have made some minor changes and added a documentation page. I cannot see the new documentation page locally for reasons I don't understand.

@mroderick mroderick added the semver:minor changes will cause a new minor version label May 20, 2021
@fatso83
Copy link
Contributor

fatso83 commented May 20, 2021

@mantoni This is a problem with the docs setup: it does not have a way of showing release-source (not copied to site), so you will not see your changes until they have been versioned ... This is less than great, but I have fixed it locally by manualyl including release-source in the build and not commiting the change.

@fatso83 fatso83 merged commit 7f271ff into master May 25, 2021
@fatso83 fatso83 deleted the sinon-promise branch May 25, 2021 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver:minor changes will cause a new minor version
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants