Lerna Monorepo Mocha Setup (JavaScript)

In this article I show you how to setup a lerna JavaScript monorepo for testing with mocha (MochaJS).

Step 1. Install lerna and mocha globally

Install lerna and mocha globally using npm.

If you don’t have npm installed, click here.

  • Open up a terminal window
  • Run the following (the $ indicates that you are at a command line prompt - you should only type in what comes after the symbol):
$ npm install -g lerna mocha

Because the packages are installed globally, you won’t need to do this again for new projects.

Step 2. Create a monorepo project

  • Change to a parent folder for all of your projects
  • Create a new folder for a new lerna monorepo project:
$ mkdir lerna-javascript-example
$ cd lerna-javascript-example

Step 3. Decide how you want to handle versioning

There are two ways to handle package versioning in lerna:

  • fixed - (the default) every package is published with the same version
    • for fixed versioning you would initialize with lerna init
  • independent - packages are published independently with their own version
    • for independent versioning you would initialize with lerna init --independent

The focus of this article is on testing and not publishing. So for this example you can just go with the default (fixed).

  • Initialize lerna:
$ lerna init
$ npm install
  • Verify that the following files and folders are listed:
lerna.json
node_modules
package-lock.json
package.json
packages

Step 4. Create a .gitignore file

  • Create a new file called .gitignore
  • On a Mac you can use this command:
$ touch .gitignore
  • Open .gitignore in a text editor
  • Paste the following into the file and save it:
node_modules/
lerna-debug.log
npm-debug.log

Step 5. Create a package

  • Create a new package:
$ lerna create demo-tools
  • Fill in the details (replace @mitchallen with your npm scope, if any):
package name: (demo-tools) @mitchallen/demo-tools
version: (0.0.0) 
description: Demo tools module
keywords: demo
homepage: 
license: (ISC) 
entry point: (lib/demo-tools.js) 
git repository: 

You should see a message about a new packages folder and package.json file.

The path for the json file should be something like this:

  • lerna-javascript-example/packages/demo-tools/package.json

The contents should be echoed to the console and look something like this:

{
  "name": "@mitchallen/demo-tools",
  "version": "0.0.0",
  "description": "Demo tools module",
  "keywords": [
    "demo"
  ],
  "author": "Mitch Allen <...>",
  "homepage": "",
  "license": "ISC",
  "main": "lib/demo-tools.js",
  "directories": {
    "lib": "lib",
    "test": "__tests__"
  },
  "files": [
    "lib"
  ],
  "scripts": {
    "test": "echo \"Error: run tests from root\" && exit 1"
  }
}
  • Confirm when prompted

This article doesn’t cover publishing. But if you are planning to publish the package at some point, be sure to add a publishConfig section to package.json in the package folder.

For example:

"publishConfig": {
  "access": "public"
},

Step 6. Create the library

  • Replace the code in packages/demo-tools/lib/demo-tools.js with the following and save it:
"use strict";

module.exports = {
  add: (a,b) => a + b,
  subtract: (a,b) => a - b
}; 

It’s a simple module that has two functions:

  • add - returns the addition of two arguments
  • subtract - returns the subtraction of one argument from another

Step 7. Add a test script to the package

  • Add this to the scripts section of the demo-tools package.json file:
"scripts": { 
  "test": "mocha __tests__/*.test.js"
}
  • Remember to add this script whenever you add a new package

Step 8. Write the demo-tools test cases

  • Edit packages/demo-tools/__tests__/demo-tools.test.js
  • Replace all code in the file with the following and save it:
'use strict';

var assert = require('assert');

const demoTools = require('..');

describe('demo-tools', function () {
  context('smoke test', function () {
    it('add should add two numbers together', function (done) {
      assert.strictEqual(demoTools.add(100,200),300);
      done();
    });
    it('subtract should subtract one number from another', function (done) {
      assert.strictEqual(demoTools.subtract(100,200),-100);
      done();
    });
  });
});

Step 9. Run the tests

Run the tests with the following command:

$ lerna run test

You should see the mocha test results for your package.

When you have more than one package, the command will run all test scripts in all packages.

Step 10. Add a second package

Add a second package called demo-main, just like you did for the first package:

$ lerna create demo-main
  • Replace the code in packages/demo-main/lib/demo-main.js with the following (replace YOUR-SCOPE in the require statement with your npm scope (in my case that would be @mitchallen)):
"use strict";

var tools = require('@YOUR-SCOPE/demo-tools');

module.exports = demoMain;

function demoMain(a,b,c) {
    // return a + b - c
    return tools.subtract(tools.add(a,b),c);
}

The code uses functions from the demo-tools library to calculate and return a value.

This is to prove that the demo-main package can require (import) the tools package using the lerna framework.

But first you need to add a dependency.

Step 11. Add a dependency

For the code to work, you have to use lerna to add the tools package as a dependency for the main package.

  • To create a dependency, you would run a command like this:
lerna add @YOUR-SCOPE/LIBRARY --scope=@YOUR-SCOPE/PACKAGE
  • Substitite YOUR-SCOPE with your npm scope
  • Substitute LIBRARY with the name of the library that the package needs
  • Substitute PACKAGE with the name of the package that needs to use the library

Here is an example:

  • Run this command (substitute mitchallen with your npm scope):
$ lerna add @mitchallen/demo-tools --scope=@mitchallen/demo-main
  • Verify that the dependency was added to the package.json for demo-main:
  "dependencies": {
    "@mitchallen/demo-tools": "^0.0.0"
  }
  • Your scope in the dependency should be different from mine

Step 12. Write the demo-main test cases

  • Edit packages/demo-main/__tests__/demo-main.test.js
  • Replace all code in the file with the following and save the file:
"use strict";

var assert = require('assert');

const demoMain = require('..');

describe('demo-main', function () {
  context('smoke test', function () {
    it('should add first two numbers and subtract the third', function (done) {
      const a = 100, b = 200, c = 50;
      const expected = a + b - c;
      assert.strictEqual(demoMain( a, b, c ), expected );
      done();
    });
  });
});
  • Add a test script to the child packages package.json file and save it:
"scripts": {
  "test": "mocha __tests__/*.test.js"
},

Step 13. Run all the tests

Run all the tests like you did before with:

$ lerna run test

You should see results for both packages.

Run tests for just one package

To run the tests for just one package, use the scope command (substitute my scope for your scope):

$ lerna run test --scope @mitchallen/demo-tools

If you are in a packages folder, you can also run the tests like this:

$ npm test

Once everything passes, you have the option to publish to npm or a private repo. But that’s beyond the scope of this article.

Troubleshooting

No rights to install lerna globally

  • On a Mac or Linux, try putting sudo in front of the command

Get the Error: run tests from root

  • This actually might mean that you forgot to add the test script for a package

Conclusion

In this article you learned how to:

  • Setup a lerna JavaScript monorepo for testing using mocha (MochaJS)
  • Add multiple packages
  • Add mocha for testing
  • Create dependencies between packages without the need for linking or publishing

References

  • Lerna - A tool for managing JavaScript projects with multiple packages [1]



About the Author

Mitch Allen tests cloud services for a robotics company in New England.