Elaborate on "For the stubbing to work, the stubbed method cannot be destructured, neither in the module under test nor in the test."
DanKaplanSES opened this issue · comments
Is your feature request related to a problem? Please describe.
The How to stub a dependency of a module documentation says:
To stub a dependency (imported module) of a module under test you have to import it explicitly in your test and stub the desired method. For the stubbing to work, the stubbed method cannot be destructured, neither in the module under test nor in the test.
I'm not really sure what this bold part means. Does it mean you can't destructure the import
statement? If so, while I have found that to be true in the test file, I haven't found that the be true in the module under test. That makes me think I'm either:
- Misunderstanding what this sentence means.
- Reading out of date documentation.
Describe the solution you'd like
I'd like this sentence to be rewritten or expanded upon to clarify. If possible, an example would go a long way.
Describe alternatives you've considered
Additional context
Hi, @DanKaplanSES . I totally get that this is confusing. I have gone into depth on StackOverflow in explaining this a couple of times, one of which is this answer.
That should answer most questions you would have.
I could end it here, but maybe you - based on that - could suggest some rewording and/or example yourself, pushing a PR with the edited text? I am somewhat non-neutral about what I think of the text 😉
Does it mean you can't destructure the import statement?
Yes, in the CommonJS (CJS) world, which is what the world looked like when that article was written. All of it applies to that restriction.
Not in the test, because how would you modify the export of the dependency without an object to modify the export on?
Not in the SUT, because if you bind the reference, any changes to the export will not be affected.
BUT there's a catch
The world has moved on to EcmaScript Modules (ESM), and they are a bit of a different story. How they work is a bit of a mindbender, and it might explain what you are seeing, if you are using native ESM or ESM transpiled to CJS following the ESM spec. If you transpile ESM to a CJS target, you will probably see that the exports are in fact getters (accessor functions), meaning they are immutable.
All in all, this subject validates an update in this day and age, as the rules of the game have changed a bit with ESM.
Regarding this:
If so, while I have found that to be true in the test file, I haven't found that the be true in the module under test.
I am not sure how you can destructure an import in the SUT and have Sinon's modification to the dependency take effect in the SUT. Some actual code showing what you think is false would go a long way. Explaining this was way easier in the world of CJS 😓
Hi @fatso83 ,
Thanks for the reply. I should've mentioned I'm writing typescript that transpiles into "esnext". Here's an example project: https://stackblitz.com/edit/typescript-svngnu?file=mytest.spec.ts You can't run the tests, but if you look at files a.ts
, b.ts
and mytest.spec.ts
, you'll see that a.ts
destructures the b.ts
import and the test (should) pass. At least, I write examples like that all the time.
The docs say, "...neither in the module under test nor in the test," but isn't this an example of destructuring in the module?
I'd love to submit a PR after I understand this detail.
Hi, that example is not really runnable, as you assume different things in the test and the SUT. In the b.ts module you expose an object as export b
, which has a method called method
, whereas in the test you assume that b
is the method that you are replacing.
It's hard to discuss non-runnable code, as it makes what we are talking about ambiguous.
Anyway, if you use modules like b.ts
, then you are doing something quite different than what is talked about. Usually, you want to directly affect the exports of the modules you are working on. If you manipulate b.method
, that will work fine even if you have destructured the reference to b
, but then you are not stubbing any exports of the module, rather you are stubbing a field on an export of said module.
P.S. Please do read the answer I linked to. It should clarify some things.
Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.