Running JavaScript Tests for the Joomla CMS

From Joomla! Documentation

Other languages:
English • ‎français

Introduction

Joomla! core currently has some custom written JavaScript libraries used in performing various tasks. This documentation is about the environment setup used in Joomlaǃ 3 for testing those JavaScript libraries and how to write new tests. For Running JavaScript Tests for Joomla 4.x please see JavaScript Tests for Joomla 4.

When you checkout the staging branch of Joomla from Github.com, you will see a folder named "tests" which contains a folder named "javascript". This "javascript" folder contains the JavaScript tests written to cover the aforementioned JavaScript libraries. The tests are written using the Jasmine framework, Karma is used as the test runner and the tests are run on a Firefox web browser.

Before you can run the tests, you need to install some software on your local workstation (see Prerequisites section below). This document explains how to run and create your own tests from your local workstation.

Prerequisites

The testing environment requires your local machine to have Node.js installed in it. To install Node.js, please go to the Node.js official web site, download the respective setup for your operating system and install it by following the installation wizard. NPM (Node Package Manager) is used to manage and setup the JavaScript testing environment.

Install dependencies (packages)

Open a command line and navigate to the directory "tests/javascript"

Execute command npm install This will install all the dependencies to the "tests/javascript/node_modules" directory. If a node_modules folder does not exist, a folder will be automatically created by npm.

Starting the Karma server and running the tests

Execute the command npm test
This starts the webserver and a Firefox will automatically open. Then the tests would be run and the detailed results will be shown in the command line itself.

What the above command does is execute node tests/javascript/node_modules/karma/bin/karma start karma.conf.js in the background.

A video demonstration on running the JavaScript tests is available here.

The magic inside

The karma.conf.js file mentioned in the command for starting the Karma server, as the name suggests, is the configuration file for the Karma server. Shown below is a screenshot of it.

A screenshot of the karma.conf.js Karma configuration file

Let's have a look at the important configurations that makes everything run together smoothly.

The files attribute contains a list of files that the Karma server is going to serve. Unless specified in here, no tests can access any file. The set of files currently specified here are the third party JavaScript libraries like jQuery and jasmine-jquery, the set of Joomla! custom JavaScript libraries, the set of spec files that contain test cases along with the files that set up the spec executions and the files that contains the HTML fixtures the libraries are tested on and finally some sample images. We have these aforementioned files specified with the included: false option because we are using require.js for that purpose. The only file that will be both LOADED and INCLUDED from karma itself will be the test-main.js file generated from require.js. From there on, require.js takes care of including the other loaded files.

The exclude attribute does what the name suggests and is used since the "media/system/js" directory contains both the minified as well as the uncompressed version of the same library. We need to exclude the uncompressed versions from the loaded files list and that's what this exactly does.

Preprocessors attribute has the externally added coverage reporter specified in it. The output in the command line is also made verbose by the verbose reporter. Autowatch is set to true so that whenever a change to any loaded file is made, the Karma server would detect that and rerun the tests. This makes the life of the tester easy.

The browsers attribute accepts an array of browsers that we need the tests to be run on and currently has only Firefox set. In order to use any other browser, the relevant browser launcher needs to be installed and of course you need to have that browser installed on your local machine.
For example, to use Chrome browser, navigate to "tests/javascript/js" directory from a command line and execute command npm install karma-chrome-launcher --save-dev
And add Chrome to the browsers list. singleRun attribute when set to true, automatically stops the Karma server once the tests finish running. That obviously would not be what we expect when we have autowatch also set to true. Therefore for the ease of development the option is set to false. Still it is possible to run the server in the 'single run' fashion by passing --single-run option in the karma start command. karma start karma.conf.js --single-run

The next important file we need to look at is the test-main.js file which is an auto generated file from require.js. We use require.js in this setup to make dynamic loading of dependencies in test specs possible.

Two important changes are done to the auto generated file.

  • The first is the paths attribute set in in the require configuration. These paths allow us to have aliases assigned to specific JavaScript files. This way for example, whenever we need to add "tests/javascript/node_modules/jquery/dist/jquery.min.js" as a dependency, all we need to do is to specify the alias jquery in the dependency list.
  • The next change made to the auto generated file is the 'shim' attribute. This is a very simple option where we get to specify the dependencies among the paths set above. For example: shim: {jasmineJquery: ['jquery']} tells require.js to load jquery before loading jasmineJquery.

Writing new tests

Test cases are stored in a modular fashion inside the "tests/javascript/" directory where we have a specific directory allocated for a specific JavaScript library. Inside of that directory lies two JavaScript files, one containing the test cases(spec.js) and one containing any setup code necessary to run the tests(spec-setup.js). The HTML content that needs to be loaded to the DOM for the tests to run are kept inside a directory named "fixtures" and inside it lies the fixture.html file. fixture.html file simply contains pure HTML.

The spec-setup.js mostly does appending of the required HTML fixtures to the DOM. The test setup uses a plugin called RequireJSText that allows dynamic loading of HTML files also possible. Only difference is that the dependency is prefixed with text!. For example, to load the fixture with an alias fixtureHtml, the dependency specified should be text!fixtureHtml.

The tests written so far extensively uses the library jasmine-jquery which is like and extension of the jQuery functions specifically designed for use with Jasmine.

Travis integration

The Travis integration is made simply by modifying the .travis.yml file to install the necessary dependencies of the project and finally call tests/javascript/node_modules/karma/bin/karma start karma.conf.js --single-run.

Code templates

spec.js

/**
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 * @package     Joomla
 * @subpackage  JavaScript Tests
 * @since       __DEPLOY_VERSION__
 * @version     1.0.0
 */

define(['jquery', 'testsRoot/{LIBRARY}/spec-setup', 'jasmineJquery', {DEPENDENCIES}], function ($) {
    describe({LIBRARY_NAME}, function () {
        it('should perform expected task', function () {
            expect({SOME_VALUE}).toEqual({SOME_VALUE});
        });
    });
});

spec-setup.js

/**
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 * @package     Joomla
 * @subpackage  JavaScript Tests
 * @since       __DEPLOY_VERSION__
 * @version     1.0.0
 */

define(['jquery', 'text!testsRoot/{LIBRARY}/fixtures/fixture.html', 'libs/{LIBRARY}', 'jasmineJquery', {DEPENDENCIES}], function ($, fixture) {
    $('body').append(fixture);
    
    //Any further setup code needed
});

fixtures/fixture.html

<div id="{LIBRARY}js">
    <div id={TEST_CASE_REFERENCE}>
        {HTML_CONTENT}
    </div>
</div>