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 article: making Sinon work with complex setups #2540

Merged
merged 18 commits into from
Oct 3, 2023
Merged

Conversation

fatso83
Copy link
Contributor

@fatso83 fatso83 commented Aug 13, 2023

Purpose

Wrote an article with-step-by-step instructions in how one can figure out what is preventing you from getting Sinon to work in most environments, and show three different approaches that all enable you to use Sinon in mocking dependencies.

This is basically an elaboration of what I wrote in #2528

Rendered as PDF: Case study: real world dependency stubbing.pdf

Testing in Jekyll:

  • have Ruby 2.7.8 with Bundler installed
  • cd docs; bundle install; npm run serve-docs

@codecov
Copy link

codecov bot commented Aug 13, 2023

Codecov Report

All modified lines are covered by tests ✅

Comparison is base (cb5b962) 95.95% compared to head (1b4424d) 95.95%.

❗ Current head 1b4424d differs from pull request most recent head f3cb812. Consider uploading reports for the commit f3cb812 to get more accurate results

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2540   +/-   ##
=======================================
  Coverage   95.95%   95.95%           
=======================================
  Files          40       40           
  Lines        1904     1904           
=======================================
  Hits         1827     1827           
  Misses         77       77           
Flag Coverage Δ
unit 95.95% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

docs/assets/js/prism.js Dismissed Show dismissed Hide dismissed
docs/assets/js/prism.js Dismissed Show dismissed Hide dismissed
@fatso83 fatso83 mentioned this pull request Aug 22, 2023
To better understand the example and get a good description of what seams are, we recommend that you read the [seams (all 3 web pages)][seams] excerpt from [Working Effectively with Legacy Code][legacy] before proceeding.
This guide targets the CommonJS module system, made popular by NodeJS. There are other module systems, but until recent years this was the de-facto module system and even when the actual EcmaScript Module standard arrived in 2015, transpilers and bundlers can still _output_ code as CJS modules. For instance, Typescript outputs CJS modules per default as of 2023, so it is still relevant, as your `import foo from './foo'` might still end up being transpiled into `const foo = require('./foo')` in the end.

<!-- TODO: input link to the other article on stubbing ESM -->
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I should add that link now 😅


The important difference to note about the object `Other` is that the property `toBeMocked` is a simple writable _value_ in the case of `ts-node` and a non-configurable _getter_ in the case of SWC. It being a getter is not a problem for Sinon, as we have a multitude of options for replacing those, but if `configurable` is set to `false` Sinon cannot really do anything about it.

If we take a look at
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Incomplete sentence 🤦‍♂️

> [Working code][pure-di]

This technique works regardless of language, module systems, bundlers and tool chains, but requires slight modifications of the SUT to allow modifying it. You also do not get help from Sinon in automatically resetting state.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could add a link to the ongoing PR I made to address this


## Use pure dependency injection

> [Working code][pure-di]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Include link to section on testing in Single Page Apps In Depth

https://singlepageappbook.com/maintainability3.html#testing-interactions-between-modules

@assertnotnull
Copy link

Nice article!

@fatso83 fatso83 merged commit f8c20e5 into main Oct 3, 2023
11 checks passed
@fatso83 fatso83 deleted the docs-how-to branch October 3, 2023 07:56
@kasir-barati
Copy link

Thanks for the article @fatso83, just a comment. What if one does not want to use swc? and configure its jest in a way to export the configureable objects?

@fatso83
Copy link
Contributor Author

fatso83 commented Oct 10, 2023

Screenshot_20231010-090742.png

See the two highlighted sections. This is not meant as a guide on SWC or Typescript, which was just chosen as a popular and slightly complicated example that could be used to show different techniques. It's a general guide on how you can analyse the situation and figure out how to work around it once you know what's going on.

I don't know your particular case and what the issue is, but we're not really a support channel, use StackOverflow or ChatGPT for that. We are interested in improving docs to avoid confusion, of course, so any tips is worth mentioning.

Wrt Jest I used it with Typescript and Sinon in a previous project. I remember that as working fairly well. Jest has control over the entire runtime, so it can do magic a library cannot 🪄 AFAIK we used the built-in jest.mock(...) for replacing dependencies. You can then choose to either create the stubs using Sinon or Jest. It's mostly a matter of preference. I don't know how to configure Jest to do what you propose, but I think you would need a plugin at least. Maybe even write it yourself.

A newer approach of the old manual DI, is the "no extra tooling needed" approach that was just exposed with the new sandbox.replace.usingAccessor. That allows for tests that will work the same in Jest or Mocha or any other runner. You should check it out. I should of course update the article to mention that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants