Testing Lightning Components in production with mocha-aura

Yuriy Sannikov
4 min readAug 14, 2017

--

Couple months ago I posted an article about unit testing Lighting components with mocha-aura library. Mocha-aura allows developers to create mocha unit tests and run it under NodeJS environment. Most of Aura Lightning calls are emulated so you have no dependency with Salesforce at all. This approach has a lot of advantages:

  1. Tests and code coverage runs really fast
  2. You can gather code coverage metrics for your Aura Lighting components
  3. Create DRY test code using latest ECMAScript features with Babel
  4. No need to deal with Nightwatch/Selenium
  5. All tests are synchronous, even Apex callbacks and timers

By now, we adopted this library to test production code for our most critical product. Since then a lot of pain points were addressed. Let me share some of the best practices and tricks with you.

Global Scope Variables

Salesforce exposes $A variable to the window namespace. It gives access to various Aura services. Lightning component javascript code might access to some global object such as document, window, sessionStorage, location and your custom library code. In order to make your mocha-aura tests works you have to define these fake objects on NodeJS global object.

These objects stays on global object for the entire test lifecycle. Some of developers rely on global ‘leftovers’ from other tests and do not set up them correctly. This might lead to sporadic test failures. Especially after adding new tests or cleaning up global object.

First best practice would be: Add to global object only needed objects, delete these objects from global object after your test suite.

Asynchronous Operations

Mocha-aura library simplifies Apex call testing by making it synchronous. With sinon fake timers you can make setTimeout and setInterval callback calls synchronous as well. Most common mistake here is that developers forget to mock timers and do not test callback code. Timers will fire sporadically and test might fail.

Synchronous Apex Call test
Synchronous setTimeout/setInterval test

Track Immutable Aura Calls

A good practice would be to test any code branches in your application. It’s trivial to do if tested code has some side effects. For example put some data to the component. You can get result value and compare against expected value using component.get(…) call.

Immutable calls are really hard to test. They does not change any state on a component or event so it’s impossible to know whether such method has been called or not.

Here is an event handler code. You need to test second if condition has been executed if panelId matches but id doesn’t. How to do that?

With mocha-aura and sinonjs you can test it. Mocha-aura automatically wraps on-demand any mocha-aura call with sinon stub. Thus you can use expect() syntax to check if event.getParam() has been called with proper args.

expect(event.getParam).to.have.been.calledWith('panelId')
expect(event.getParam).to.have.been.calledWith('id')
expect(component.get).to.have.been.calledWith('v.id')

Callbacks Testing

There are some scenarios when you need to test callbacks. mocha-aura handles Apex callbacks pretty well so you usually do not need to worry about it. Situation changes with timers. You can leverage sinonjs to mock browser timer functions.

Use Component Adapters

Most probably you’re using some component library for your project. This library contains your custom input fields, buttons, input selects and other common components. These components has some methods and properties on it. In order to properly test a code using such components you need to set it up again with mock functions and properties.

To avoid this tedious exercise mocha-aura provides ability to register your own component adapters. Let’s say, you have BaseUI library and you need to define adapter for InputField on it.

// Import useComponentAdapters from mocha-aura
const {
apexCallFactory, ..., useComponentAdapters
} = require('mocha-aura/aura');
// Import adapters from code above
const { baseUIAdapters } = require('baseUIAdapters');
// Register your custom adapters
useComponentAdapters(baseUIAdapters);

Having this set up you might send adapter name to the componentFactory call as a second argument. The following code would work as expected. A vaidate() method would be defined by your adapter code.

const inputFieldComponent = componentFactory({},
'BaseUI:InputField');
expect(inputFieldComponent.validate).not.to.have.been.called;

Also, any call to $A.createComponent method would create a component and apply proper component adapter to it.

$A.createComponent('markup://BaseUI:InputField',
{'aura:id': 'myInputField'},
(component, status) => {
expect(component.validate).not.to.have.been.called;
}
)

What’s next? We are using Istanbul for code coverage. It’s a great tool to check coverage metrics.

However, it’s not enough. One big challenge I’m facing right now is how to automatically track and help developers to see which logic was not tested. Sometimes Aura component set up complex data structures to the component, but test has no code to check it. Code coverage tools like Istanbul shows that these lines were covered, but they are not.

A solution I’m working on right now would track all component mutations under test. Then check wether all these changes has been tested and automatically generate proper test code in a warning message to tests these changes.

For more information and test cases with mocha-aura please refer github wiki page.

--

--