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

New API: default sandbox and fake #1586

Closed
wants to merge 40 commits into from
Closed

Conversation

mroderick
Copy link
Member

@mroderick mroderick commented Oct 11, 2017

This PR is a solution for the proposal in #1559

This PR should not be merged into master until we have given it a good trial in real world projects.

Contributions (code, fixes, tests, documentation) are very welcome. Please make pull requests into this branch.

I'll keep the branch up to date by pulling from master at intervals. Once we're happy with the branch, then I'll rebase against master and get rid of the merge commits.

Tasks

  • Make the main sinon object a default sandbox
  • Create sandbox.replace method
  • Document sandbox.replace
  • Create sandbox.replaceGetter method
  • Document sandbox.replaceGetter
  • Create sandbox.replaceSetter method
  • Document sandbox.replaceSetter
  • Create sinon.fake
  • Clean unwanted methods from fake [.withArguments, etc]
  • Document sinon.fake
  • Put release candidates on npm as sinon@next to get feedback

To try it out in your project directly from source

  1. Clone the repo
  2. git checkout default-sandbox-and-fake
  3. npm link
  4. In your project: npm link sinon
  5. Run your tests

Once we start publishing release candidates on npm, then we'll add instructions for testing in your projects here.

@mroderick mroderick added the semver:major changes will cause a new major version label Oct 11, 2017
lib/sinon.js Outdated
create: deprecated.wrap(
createSandbox,
// eslint-disable-next-line max-len
"`sandbox.create()` is deprecated. Use default sandbox at `sinon.sandbox` or create new sandboxes with `sinon.createSandbox()` or `new sinon.Sandbox()`"
Copy link
Contributor

@fatso83 fatso83 Oct 11, 2017

Choose a reason for hiding this comment

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

create new sandboxes with sinon.createSandbox() or `new sinon.Sandbox()

Why have two ways of creating sandboxes? We just made a new factory function.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll remove the second way and tidy up the documentation. Thanks

@mroderick
Copy link
Member Author

Should we expose the Sandbox prop if we don't mean to mean to make it public?

In the current version of the branch (5883852), that property is not exposed.

> var sinon = require('./lib/sinon');
undefined

> typeof sinon.Sandbox
'undefined'

@mroderick mroderick force-pushed the default-sandbox-and-fake branch 2 times, most recently from 7b2953a to dc8e063 Compare November 11, 2017 09:07
@mroderick
Copy link
Member Author

Ping @sinonjs/sinon-core

This is getting close to being reviewable, however two of the tests are failing in Chromium.

Any ideas why that might be?

@mantoni
Copy link
Member

mantoni commented Dec 29, 2017

@mroderick Nice work! I had a look at the failing tests. It's proxyquire changing the instance, so actual instanceof Sandbox also returns false. What you can do to fix the tests is adding sinon = require("../lib/sinon"); or use proxyquire only where it's actually needed.

@@ -178,6 +176,10 @@ This is equivalent to calling both `stub.resetBehavior()` and `stub.resetHistory

*Updated in `sinon@2.0.0`*

*Since `sinon@5.0.0`*

You can reset all stubs using `sinon.reset()`
Copy link
Member

Choose a reason for hiding this comment

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

Clarify what this resets. I assume it's behavior and history here, right?


*Since `sinon@5.0.0`*

You can reset behaviour of all stubs using `sinon.resetHistory()`
Copy link
Member

@fearphage fearphage Dec 29, 2017

Choose a reason for hiding this comment

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

Typo: resetHistory doesn't reset behavior.

Also do we consistently use the Old English (British?) spelling of behavior in the docs? The actual method name uses the American English spelling.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also do we consistently use the Old English (British?) spelling of behavior in the docs? The actual method name uses the American English spelling.

My natural language uses (mostly) British English spelling. Sometimes when writing code and documentation, that spelling slips through.

(I wonder if there's a spelling linter where you can set the language preference)

@sinonjs sinonjs deleted a comment from coveralls Jan 1, 2018
@sinonjs sinonjs deleted a comment from coveralls Jan 1, 2018
@sinonjs sinonjs deleted a comment from coveralls Jan 1, 2018
@mroderick
Copy link
Member Author

Tests are passing now (Travis was having a bit of a day). If you don't have any further comments for this PR, then I'll rewrite the history to read better.

Do we need more documentation of fake? Are you happy with me publishing it as sinon@next?


function noop() {}

var hasFunctionNameSupport = typeof noop.name !== "undefined";
Copy link
Member

Choose a reason for hiding this comment

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

noop.name === 'noop' is a bit more straight forward.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, thanks :)

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 96.516% when pulling e9a978b on default-sandbox-and-fake into ca9e2fa on master.

@sinonjs sinonjs deleted a comment from coveralls Jan 2, 2018
Copy link
Member

@lucasfcosta lucasfcosta left a comment

Choose a reason for hiding this comment

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

This idea is great!

This solves all the problems we've had with inconsistent APIs and regressions and adds a better and simpler API at the same time.

I can't wait to get this on the codebase!

Awesome job.

I've left a few comments regarding the docs, but I still gotta review the code itself.

I was really busy in the last couple months because I was moving to London, so now that I'm all set up I will be able to come back and work with you some more 😄

(I missed y'all btw)


### Fakes with behaviour

Fakes can be created with behaviour, which cannot be changed once the fake has been created.
Copy link
Member

Choose a reason for hiding this comment

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

IMO it would be good to point out that it is possible to do a restore as mentioned here and that would be enough for the user to get the original property back into the object.

As a user I think that would be something I'd like to know how to do as soon as I read that:

[a fake] cannot be changed once the fake has been created

Copy link
Member Author

Choose a reason for hiding this comment

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

replace and restore belong together. Fakes are created separately from replacing properties.

Fakes are just one possible argument to replace, you could use something else if you wanted to (like mock, spy or stub ... or even Date).

I'd like to keep the documentation focused, so not mention topics that are not necessary for understanding the current topic. With that in mind, I think that mentioning replace in the documentation about creating fakes with behaviour, would reduce the focus and make the text a bit confusing.

Copy link
Member

Choose a reason for hiding this comment

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

I totally understand, but then maybe we could rephrase this to make it more specific.

The first time I read this I had the strong impression that you would not be able to restore any property replaced with a fake.

The wording is a bit difficult though, what do y'all think? 🤔

Copy link
Member

Choose a reason for hiding this comment

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

@lucasfcosta I think the documentation already points out that replace is a sandbox method that may use a fake as an argument. The standbox can then be restored. There is nothing to restore in the fake itself. I agree with @mroderick here that talking about restore here would make the documentation more confusing.

// 42
```

When you want to restore the replaced properties, `sinon.restore` method.
Copy link
Member

Choose a reason for hiding this comment

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

Even though this is really simple it might be worth having an example added.

Also, I'd add another header for this to make it as visible as possible given the importance of this method.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, I've pushed new commits


Creates a sandbox object with spies, stubs, and mocks.
Since `sinon@5.0.0`, the `sinon` object is a default sandbox. Unless you have a very advanced setup or need a special configuration, you probably want to just use that one.
Copy link
Member

Choose a reason for hiding this comment

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

I think I'd also add a line here explaining why this change happened and how this makes testing easier, especially mentioning how useful it is to clear/restore all methods at once without having to create lots of sandboxes on each test.

Copy link
Member Author

Choose a reason for hiding this comment

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

At first I agreed with you, and wrote some documentation.

But then I thought about it some more. The motivation is only really interesting when you're transitioning from earlier versions to this MAJOR version. Once you're over that hump, stating that in the documentation just adds noise.

Instead, I've put details into the migration guide for v5, and have pushed a new commit with that.


`replacement` can be any value, including `spies`, `stubs` and `fakes`.

This method only works on non-accessor properties, for replacing accessors, use `sandbox.replaceGetter()` and `sandbox.replaceSetter()`.
Copy link
Member

Choose a reason for hiding this comment

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

This is great idea btw.

Since we've been dealing with getters/setters we've had a lot of trouble making the APIs generic enough to deal with them, but I guess that encapsulating that logic into separate methods is a lot better and allows us to avoid having lots of special conditions and a complex control-flow.

@mroderick
Copy link
Member Author

I've tried using this branch with an internal project with 1793 tests, most of them using Sinon. I am happy to report, that there were no problems.

It would be great if someone else could take it for a spin, before we publish it as sinon@next.


describe('myFunction', function() {
afterEach(function () {
this.sandbox.restore();
Copy link
Member

Choose a reason for hiding this comment

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

this.

Copy link
Member Author

Choose a reason for hiding this comment

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

You saw nothing! Nothing!

@fatso83
Copy link
Contributor

fatso83 commented Jan 9, 2018

I also

  1. checked out this branch
  2. ran npm link in the sinon repo
  3. ran npm link sinon and npm test in a project with 200 tests - many sinon

All green 😄

Word of warning: I write really simple tests and I don't have access to projects from my previous employers that had much more elaborate setups. But at least initial impressions are good! And the fact that internal sinon tests pass is very promising.

@mroderick
Copy link
Member Author

Thanks @fatso83. I'll try to find some time in near future to put a sinon@next on npm, then we can ask the bigger audience to try it out.

@mroderick
Copy link
Member Author

This is now on npm as sinon@next

@mroderick mroderick mentioned this pull request Feb 25, 2018
11 tasks
@mroderick
Copy link
Member Author

This has been replaced by #1700

@mroderick mroderick closed this Feb 25, 2018
@mroderick mroderick deleted the default-sandbox-and-fake branch February 25, 2018 08:31
glasserc added a commit to Kinto/kinto-http.js that referenced this pull request Apr 9, 2018
* Update tests to include bucket:create permission

* Use sinon.createSandbox instead of sinon.sandbox.create

This seems to be the first of many consequences from
sinonjs/sinon#1586 and
sinonjs/sinon#1700. I'm not sure what the
final result of all of this will be -- we might not even need this
sandbox any more, because a default one is created for us -- but at
some point in the future, we'll probably have to rewrite everything
that uses a stub(), and I prefer to wait until then to make any
drastic changes. This just silences the warnings until then.

* Try to make tests work on both kinto versions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver:major changes will cause a new major version
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants