Projects:JS Testing Infrastructure/Specs
Contents |
Requirements
Background
Goals
The main goal of this project is to provide a modern infrastructure to develop new frontend code backed up by a suite of unit tests that are fast to run and provides us safety to refactor and still ensures the code works properly. This infrastructure should provide developers:
- A Test Runner to execute test suites in local with no need of using a browser (i.e. using Node.js)
- Utilities to provide mock/stubs and spies that lets us abstract the layers outside the SuT and decoupling the infrastructure from the test
- Coverage analysis to determine which classes/lines of code are actually covered by test cases
Current status in Openbravo
Most of our current testing efforts are centered around the functional tests performed with Selenium, that basically simulates the user interaction with the application via browser. Currently there are thousands of tests both for the backoffice and the WebPOS, and running all of them would last hours, making then unsuitable for TDD practices.
In the frontend side, the only infrastructure available for unit testing are the [ui-test-suite powered by QUnit]. This infrastructure is used to run javascript code in the browser with an open Openbravo session and with all resources available. This infrastructure is currently used to test a small portion of the backoffice frontend codebase (47 assertions).
In the backend side, however. we actually use JUnit to perform unit tests and integration testing against a live Openbravo instance.
Javascript testing frameworks
There are a number of unit testing frameworks available for Javascript (Mocha, Jest, Jasmine, QUnit, Ava, ... ). From all these options, finally considered two options:
Mocha
Mocha is a framework that lets us run javascript tests both on Node.js and on the server side. Mocha is just a test runner that can be extensible using libraries. It is often combined with Chai to provide assertion functions and Sinon to be able to use mock, spies or stubs.
It is a mature project with a significant user base.
Jest
Jest is a testing framework created by Facebook and currently used as the default testing framework in create-react-app. Unlike Mocha, it is an opinionated test runner and provides its own assertion and mocking methods. The main advantage is that it runs out-of-the-box and has good integration with technologies like React, Babel or Typescript.
Finally we chose Jest
Feature-wise, both frameworks are almost identical. Although Mocha was de the de-facto standard for javascript testing for some years, Jest gained a huge popularity since the release of it latest stable version (24), which included support of Typescript among other improvements. Also, the community is much more active in Jest and it's a project backed by companies like Facebook and Twitter.
The most important downside found in Jest is that the performance running tests is poorer than in Mocha, but testing both frameworks we felt quite comfortable with Jest and ended up with a feeling that it "just works".
User Guide
Installation
Since PR19Q3, with the inclusion of the new Linter and Formatter tools, nodejs and npm should be installed. All dependencies can be installed just by running:
npm install
Usage
Creating new tests
Unit tests should be created under a web-test folder and filename should be suffixed with .test.js.
Now you can require() your subject under test and start creating test cases. See Jest documentation for reference.
Sample test file
require('../web/org.openbravo.client.application/js/utilities/ob-utilities-date'); describe('org.openbravo.client.application - OB.Utilities.Date', () => { beforeEach(() => { // Execute this before each test }); afterEach(() => { // Execute this after each test }); it('The year where we should change century in 2 digits year format is 50', () => { expect(OB.Utilities.Date.centuryReference).toEqual(50); }); // Describe blocks can be nested to group test cases describe('OB.Utilities.Date.normalizeDisplayFormat', () => { it('function works', () => { const normalizedFormat = OB.Utilities.Date.normalizeDisplayFormat('DD-MM-YYYY'); expect(normalizedFormat).toEqual('%d-%m-%Y'); }); it('function works with other input', () => { const normalizedFormat = OB.Utilities.Date.normalizeDisplayFormat('DD-MM-YY'); expect(normalizedFormat).toEqual('%d-%m-%y'); }); }); });
Run tests/coverage
To run all unit tests available in an Openbravo instance (both Core and all installed modules), run the following command:
npm test
Testing can be limited to a particular module adding the path at the end of the command:
npm test modules/org.openbravo.mobile.core/
If, along with the test, you want to see a coverage report, run:
npm run coverage
![]() | Tests should be placed in web-test folder, and files should have the suffix .test.js.
This is a valid path for a test class: modules/org.openbravo.mymodule/web-test/mycomponent.test.js |
Dependencies for testing
In some very specific scenarios, your code under test may require the usage of some javascript library as a dependency but you cannot import this library using node.js's require (i.e. Backbone).
In those cases, you can create a package.json file in the root folder in your module and add your dependencies as devDependencies:
{ "name": "my-module", "version": "1.0.0", "private": true, "scripts": { "test": "echo \"Run tests from root\"; exit 1" }, "repository": "<your module repo path here>", "author": "Openbravo SLU", "license": "SEE LICENSE IN legal/Openbravo_license.txt", "devDependencies": { "underscore": "=1.3.3", "backbone": "=0.9.10" } }
Then, next time you run npm install in the root folder of Openbravo, modules dependencies will be installed as well and stored in root's node_modules.
Once installed, you can import the libraries using require:
const _ = require('underscore'); const Backbone = require('backbone');
![]() | Even if your desired package is already present in node_modules, you can't assume this package is available unless you explicitly reference it in your module's package.json |
Html reports
Both 'npm test' and 'npm run coverage' automatically generates html reports that will be stored in test-reports/ folder in the root of the project.
Jest Unit Tests
Generated by 'npm test' and 'npm run coverage'. Report is located in test-reports/jest-report.html. Contains the result of the unit test, with error backtraces of failing tests and graphical data of time spent running tests among other things
Coverage
Generated only by 'npm run coverage' and located in test-reports/coverage. Contains all coverage reports in various formats. Html report is located in test-reports/coverage/lcov-report/index.html