--- title: ๐ŸŒฎ Techo Tuesday ๐ŸŒฎ Javascript ES Modules Test and Coverage Without Babel date: 2020-05-19 type: post categories: - technical - techo tuesday - coding - website tags: - coding - geek - javascript featured: js-es-modules-test.jpg featuredcaption: greed green is good comment: --- _things turning me on this week_
_โ˜•enjoy with a hot cupa java/script_
JavaScript has gotten _even better_ and you can now run 100% [ES Modules](/2019-09-techo-tuesday-javascript-es6-and-es-modules/) code "natively" through the entire node, JS, testing, and coverage (and more!) ecosystem. Picking the right tools that understand `ES Modules` is key - here we use `mocha` and `c8` (also show how to use `jasmine` (what is under `jest`) and `nyc`/. `istanbul` if desired). Bonus points? `sinon` for mocking. ## Sample code setup [demonstration minimal working git repository](https://github.com/traceypooh/js-es-modules-coverage-testing) ## Uses simply: mocha and c8 The goal is to avoid babel, transpiling, and any dynamic transform of the JS source/test code as possible. - [mocha](https://mochajs.org/) since it can understand ES Modules (and make `import`/`export` work nicely). - [c8](https://github.com/bcoe/c8) for code coverage (since it understands ES Modules) - [expectations](https://github.com/spmason/expectations) for `jest`/`jasmine` like testing, eg: `expect('hai'.length).toBe(3)` - [sinon](https://sinonjs.org/) for mocking, stubs, and spies (more below on that) There's a few _subtle_ things to get setup and "just right" to make it all work seamlessly. But once you know them, you're good to go. **If you prefer `jasmine`** - [see this prior setup](https://github.com/traceypooh/js-es-modules-coverage-testing/tree/jasmine-esm-nyc) ## Thus you can now write all your source and test code in the modern/future default 100% `ES Modules` (AKA `import` / `export`), eg: ```javascript import { foo, foobar } from '../src/foo.js' describe('foo()', function () { it('should return number plus one', function () { expect(foo(1)).toEqual(2) }) }) ``` ## run ```bash git clone https://github.com/traceypooh/js-es-modules-coverage-testing cd js-es-modules-coverage-testing npm install npm test ``` (or alternatively: `npx c8 mocha`) ## yields ```text > @ test /Users/tracey/dev/js-es-modules-coverage-testing > c8 mocha bar() โœ“ should return number minus one foo() โœ“ should return number plus one foobar() โœ“ should return same number goo() โœ“ should switch from 2 to 3 via a swap out โœ“ should switch from 2 to 3 via a mock 5 passing (11ms) ----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------|---------|----------|---------|---------|------------------- All files | 100 | 100 | 100 | 100 | bar.js | 100 | 100 | 100 | 100 | foo.js | 100 | 100 | 100 | 100 | goo.js | 100 | 100 | 100 | 100 | ----------|---------|----------|---------|---------|------------------- ``` ## the magic - in `package.json`, this tells `node` and scripts all `.js` files are ES Modules ```json { "type": "module", } ``` - in `package.json`, this tells `mocha` to preload `expectations` (for `jest`-like testing) ```json { "mocha": { "require": "expectations" } } ``` ## mocking, stubs, and spies _By Far,_ this is the most complicated thing to get right. I spent hours and hours over a few days on/off trying to get mocking to work (first with `jasmine`, then `sinon`). Fortunately, I found this lil' gem: - https://stackoverflow.com/a/46739544 Normally, ES Modules are _very locked down_ and hard to mock. By grouping all the export-ed methods via `export default Goo`, and importing via `import Goo from '../src/goo.js'`, we can replace methods if needed for testing. (Imagine needing to test something that live-fetches resources, etc.) - see [src/goo.js](https://github.com/traceypooh/js-es-modules-coverage-testing/blob/master/src/goo.js) - see [test/goo.test.js](https://github.com/traceypooh/js-es-modules-coverage-testing/blob/master/test/goo.test.js) **2020 as ever, is a _super-exciting_ time ๐Ÿฅณ for javascript!**