Skip to content

Conversation

@rhelmer
Copy link

@rhelmer rhelmer commented Jan 11, 2023

Run V2 unit tests using GitHub Actions.

@rhelmer rhelmer self-assigned this Jan 11, 2023
@rhelmer rhelmer changed the title [WIP] upgrade jest and babel-jest dep for ES6 transpiling support [WIP] run V2 tests using Github Actions Jan 11, 2023
@rhelmer rhelmer marked this pull request as draft January 11, 2023 01:45
@rhelmer rhelmer force-pushed the v2-tests-gh-action branch 3 times, most recently from cf61270 to f3dd389 Compare January 11, 2023 04:06
@rhelmer rhelmer changed the title [WIP] run V2 tests using Github Actions run V2 tests using Github Actions Jan 11, 2023
@rhelmer rhelmer changed the title run V2 tests using Github Actions run V2 unit tests using Github Actions Jan 11, 2023
@rhelmer rhelmer requested review from mansaj and toufali January 12, 2023 03:04
@rhelmer rhelmer marked this pull request as ready for review January 12, 2023 03:04
@rhelmer
Copy link
Author

rhelmer commented Jan 12, 2023

Here is my understanding of the Jest+ES situation, based on reviewing the docs and issue below:

Jest has some issues with ES modules, so this PR uses Babel to transpile. The alternative is to make some ugly modifications to the test code and enable experimental support in node:

  • https://jestjs.io/docs/ecmascript-modules
  • https://github.com/facebook/jest/issues/9430

I feel like using babel for now and then just removing it as node and jest stabilize would be easiest, but open to trying to go pure ES now if we want to. Note that it's not just enabling the experimental ES support in node, you also need to change the jest calls in the unit test code (per the docs above), e.g. jest.unstable_mockModule, and hoisting doesn't work yet with ES so you need to make that call first then do a dynamic import (const { myThing } = await import('myModule') - that's what I mean specifically by modifications to the test code.

Using Babel allows us to write the tests as ES and it gets transpiled to CJS which Jest understands, so you can write unit tests the normal way:

import { myThing } from 'myModule'
jest.mock('myModule') // myThing is now automatically mocked

Copy link
Member

@toufali toufali left a comment

Choose a reason for hiding this comment

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

Thanks for explaining the problem, and agreed that the workaround using jest.unstable_mockModule seems awful! I'm mostly on board with the Babel workaround, but a couple thoughts:

  • Should we be concerned with Jest testing babel-transformed code, but in production the code is not transformed? Wouldn't it be better to test the actual (un-transformed) code?
  • This blurb seems to suggest there's a block for Jest mocks to ever work nicely with ESM. It makes me wonder if Jest mocks will ever work without dynamic imports... If so, simply removing Babel in the future without code change may not be realistic?
  • Is the ability to use mocks the main reason for this work-around? If so, maybe we can just avoid their use? I've read mocks can sometimes suggest code-smell!
  • With all the above, should we consider a solution like esmock? It could be used with Jest, or maybe better (as the examples show) on top of the native Node 18+ test runner?

@rhelmer
Copy link
Author

rhelmer commented Jan 12, 2023

Thanks for explaining the problem, and agreed that the workaround using jest.unstable_mockModule seems awful! I'm mostly on board with the Babel workaround, but a couple thoughts:

* Should we be concerned with Jest testing babel-transformed code, but in production the code is not transformed?  Wouldn't it be better to test the actual (un-transformed) code?

Ideally yes.

* [This blurb](https://jestjs.io/docs/ecmascript-modules#module-mocking-in-esm) seems to suggest there's a block for Jest mocks to ever work nicely with ESM.  It makes me wonder if Jest mocks will ever work without dynamic imports...  If so, simply removing Babel in the future _without_ code change may not be realistic?

Hm, I think you're right, this might just be a consequence of moving to ES that imports are always hoisted to the top... we may need to use dynamic imports in the future no matter what, so it might be worth doing that now.

* Is the ability to use mocks the main reason for this work-around?  If so, maybe we can just avoid their use?  I've read mocks can sometimes suggest code-smell!

Do you have any references I can read? I'm not sure what the alternatives to mock would be for certain cases, wouldn't that imply that we need to modify the code to be testeable? I think the advantage of mocks is that the code under test doesn't need special modifications to be able to override behavior to be more appropriate in the test environment.

* With all the above, should we consider a solution like [esmock](https://www.npmjs.com/package/esmock)?  It could be used with Jest, or maybe better (as the examples show) on top of the native Node 18+ test runner?

This looks promising, thanks! I'll see if I can get this running. I feel like moving away from mocks completely would be a pretty large change, esmock looks like it might allow us to reuse more of the existing test code. Most of the test code I've seen so far seems pretty sensible (e.g. tests that nodemailer receives the expected inputs and overrides the ability to send outgoing email with a mock that can be inspected etc.)

@toufali
Copy link
Member

toufali commented Jan 12, 2023

Do you have any references I can read?

Yep, this is what I got into yesterday:
https://dev.to/kettanaito/when-should-i-not-use-mocks-in-testing-544e
https://chemaclass.medium.com/to-mock-or-not-to-mock-af995072b22e
https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a

Interesting to note the slight contradictions in the articles with regard to unit test mocks. I think the big take-away will always be "it depends".

@rhelmer rhelmer changed the title run V2 unit tests using Github Actions MNTOR-1101 run V2 unit tests using Github Actions Jan 13, 2023
@rhelmer
Copy link
Author

rhelmer commented Jan 13, 2023

Do you have any references I can read?

Yep, this is what I got into yesterday: https://dev.to/kettanaito/when-should-i-not-use-mocks-in-testing-544e https://chemaclass.medium.com/to-mock-or-not-to-mock-af995072b22e https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a

Interesting to note the slight contradictions in the articles with regard to unit test mocks. I think the big take-away will always be "it depends".

Thanks. I think it's worth digging into this more, right now we have a bunch of existing test code, although our coverage is quite low - I think it's worth continuing with mocking but we should consider whether there are better approaches.

I think in particular we'd benefit from end-to-end testing using Playwright or similar, which i know @mozrokafor already did some work on. I don't think the existing unit tests make excessive use of mocking, at least not the few that I have ported over so far (email-utils and the settings controller).

@rhelmer
Copy link
Author

rhelmer commented Jan 13, 2023

@toufali OK here's a different approach, using the minimal test runner Ava which is pure ES.

The API isn't quite mocha compatible but it's similar. I've ported over the tests that @mansaj added in ./src/*.test.js, neither of these use mocks, so I don't think we need to worry about introducing esmock or similar quite yet.

@rhelmer rhelmer requested a review from toufali January 13, 2023 04:10
@toufali
Copy link
Member

toufali commented Jan 13, 2023

Oh wow, this update looks fantastic and runs super fast! Awesome work – I appreciate the extra diligence here 🙌

Copy link
Collaborator

@mansaj mansaj left a comment

Choose a reason for hiding this comment

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

There were some more tests added into /utils yesterday just FYI

@rhelmer
Copy link
Author

rhelmer commented Jan 13, 2023

There were some more tests added into /utils yesterday just FYI

Thanks, I'll rebase and convert those over as well.

@rhelmer rhelmer force-pushed the v2-tests-gh-action branch from 91c9bef to 6a67bd6 Compare January 13, 2023 20:12
@rhelmer rhelmer merged commit 7c87ad2 into main Jan 13, 2023
@rhelmer rhelmer deleted the v2-tests-gh-action branch January 13, 2023 21:36
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