Skip to content

Instantly share code, notes, and snippets.

@dotherightthing
Last active October 3, 2019 12:54
Show Gist options
  • Save dotherightthing/18969796aea141ab297210b83c3f62ce to your computer and use it in GitHub Desktop.
Save dotherightthing/18969796aea141ab297210b83c3f62ce to your computer and use it in GitHub Desktop.
[Unit testing: Handling dependencies] #quokka #funfunfunction #cypress #mocks #dependencyinjection

Unit Testing: Handling dependencies

I'm already familiar with unit testing, but there are gaps in my knowledge.

I like to test real code, so I have been trying to test some of my custom Gulp modules.

Problem 1: Can't test modules with dependencies

Module:

// gulp-modules/helpers.js
// the module I want to test
// it imports two dependencies
// removing these two imports and their uses prevents the Cypress error
import color from 'gulp-color';
import log from 'fancy-log';

const sentenceToCamelCase = ( sentence ) => { ... }

Test:

// cypress/integration/spec.js
// import the module I want to test
import { sentenceToCamelCase } from '../../gulp-modules/helpers';

Cypress:

Uncaught Error: Unable to parse

I'm currently unable to test my Gulp modules in Cypress, because those modules have dependencies, which are imported using ES6 module import.

It feels like this should be a common problem, but after much Googling the closest answers I have are:

A) Cypress doesn't support import

The error Uncaught Error: Unable to parse tends to come from something the parser does not understand. It is possible that Cypress or what it is running on does not support import.

  • (answer to question on Wes Bos ES6 Slack channel)

or

B) Code should be tested in isolation, i.e. I should mock the dependencies

I read an article about rewiremock but it too fails, before I even call rewiremock:

RewireMock config:

// rewiremock.js
import rewiremock from 'rewiremock';
// import rewiremock from '../../node_modules/rewiremock/lib/index.js'; // also fails

// settings
rewiremock.overrideEntryPoint( module ); // this is important
export { rewiremock };

Test:

// spec.js
import rewiremock from '../helpers/rewiremock';

Cypress:

Uncaught TypeError: require.resolve is not a function

Research

So with more Googling, I'm now watching Fun Fun Function's Unit testing in JavaScript and it is very good.

And I learned about Quokka,

a rapid prototyping playground

which is a fun way to test code in the same file that it is authored in.

if ( !decorateLog( {
  textstring: 'A pass'
} ).match( /^\[32m A pass\[0m$/ ) ) {
  throw new Error( 'does not match' );
}

And for some reason my import is no longer throwing errors in Cypress. Perhaps the fancy-log plugin was incompatible with ES6/Cypress?

Takeouts:

  • a test runner functions like a linter for the code logic
  • unit tests/assertions are like a series of examples, of how to call the function under test
  • 'dependency injection' involves passing a dependency into a function, rather than requireing it first
  • a Quokka sandbox allows us to test that APIs work as we assume in our mocks, or adjust our mocks accordingly

Solution!

After watching the second video on Mocking,

  • I removed import log from 'fancy-log' from decorate-log.js (which is the file imported into my test)
  • I added log as an argument of decorateLog (this is known as dependency injection)
  • This allows me to pass a safe fakeLog function during my test, effectively testing decorateLog in isolation
  • The problematic real fancy-log is now only imported in lint.js, where decorateLog() is called
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment