Difference between revisions of "JavaScript Tests for Joomla4"

From Joomla! Documentation

(Marked this version for translation)
(Several more markup changes.)
 
(One intermediate revision by the same user not shown)
Line 5: Line 5:
  
 
<translate><!--T:2-->
 
<translate><!--T:2-->
For Running JavaScript Tests for the Joomla 3.x please see [[S:MyLanguage/Running_JavaScript_Tests_for_the_Joomla_CMS|Running JavaScript Tests for the Joomla CMS]].
+
For Running JavaScript tests for the Joomla 3.x, please see [[S:MyLanguage/Running_JavaScript_Tests_for_the_Joomla_CMS|Running JavaScript Tests for the Joomla CMS]].
Joomla! 4.x core currently has some custom written JavaScript libraries used in performing various tasks. This documentation is about the environment setup used in Joomla! 4.x for testing those JavaScript libraries and how to write new tests.</translate>
+
The Joomla! 4.x core has some custom written JavaScript libraries used in performing various tasks. This documentation is about the environment setup used in Joomla! 4.x for testing those JavaScript libraries and how to write new tests.</translate>
  
<translate><!--T:37--> You can find the current version of the tests on Github.com in the repo https://github.com/joomla/test-javascript.</translate>
+
<translate><!--T:37--> You can find the current version of the tests on GitHub.com in the [https://github.com/joomla/test-javascript repository].</translate>
  
<translate><!--T:3--> When you checkout the 4.0-dev branch of [https://github.com/joomla/joomla-cms 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.</translate>
+
<translate><!--T:3--> When you checkout the 4.0-dev branch of [https://github.com/joomla/joomla-cms 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.</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$ ls
 
$ ls
 
acceptance.suite.yml  Gemfile              package.json
 
acceptance.suite.yml  Gemfile              package.json
Line 30: Line 30:
 
drone-package.json    modules
 
drone-package.json    modules
 
$
 
$
</source>
+
</syntaxhighlight>
  
 
<translate>
 
<translate>
 
<!--T:4-->
 
<!--T:4-->
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.</translate>
+
Before you can run the tests, you need to install some software on your local workstation. (See the Prerequisites section below). This document explains how to run and create your own tests from your local workstation.</translate>
 
<translate>
 
<translate>
 
==Prerequisites== <!--T:5-->
 
==Prerequisites== <!--T:5-->
 
</translate>
 
</translate>
<translate><!--T:6--> The testing environment requires your local machine to have Node.js installed in it. To install Node.js, please go to the [https://nodejs.org/en/ 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.</translate>
+
<translate><!--T:6--> The testing environment requires your local machine to have Node.js installed in it. To install Node.js, please go to the [https://nodejs.org/en/ Node.js] official web site, download the version 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.</translate>
 
 
  
 
<translate>
 
<translate>
==Install dependencies (packages)== <!--T:7-->
+
==Install Dependencies (Packages)== <!--T:7-->
</translate>  
+
</translate>
 
<translate>
 
<translate>
 
<!--T:8-->
 
<!--T:8-->
 
Open a command line and navigate to the root directory of Joomla 4.x.</translate>
 
Open a command line and navigate to the root directory of Joomla 4.x.</translate>
  
<translate><!--T:9--> Execute command</translate> <tt>npm install</tt>
+
<translate><!--T:9--> Execute command</translate> ''npm install''
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$ npm install
 
$ npm install
 
...
 
...
 
added 1354 packages in 193.687s
 
added 1354 packages in 193.687s
 
$
 
$
</source>
+
</syntaxhighlight>
 
<translate>
 
<translate>
 
<!--T:10-->
 
<!--T:10-->
This will install all the dependencies to the ''"/node_modules"'' directory. If a ''/node_modules'' folder does not exist, a folder will be automatically created by npm. It is OK, if you see some warnings, but you should not see an error message. This will give you a full setup that might be different from the automated testing setup. For automated testing we are using the drone-package.json. If you are rename package.json to package.json.save and drone-package.json to package.json before you run npm install you will get a lighter setup and you will using the versions we are using in our automated testing setup.</translate>
+
This will install all the dependencies to the ''/node_modules'' directory. If a ''/node_modules'' folder does not exist, a folder will be automatically created by npm. It is OK, if you see some warnings, but you should not see an error message. This will give you a full setup that might be different from the automated testing setup. For automated testing we are using ''drone-package.json''. If you are rename ''package.json'' to ''package.json.save'' and ''drone-package.json'' to ''package.json'' before you run ''npm install'', you will get a lighter setup and you will be using the versions we are using in our automated testing setup.</translate>
 +
<translate>
 +
==Starting the Karma Server and Running the Tests== <!--T:11-->
 +
</translate>
 +
 
 
<translate>
 
<translate>
==Starting the Karma server and running the tests== <!--T:11-->
+
<!--T:12--> Execute the command</translate>''npm run test''
</translate>  
 
  
<translate><!--T:12--> Execute the command</translate><tt>npm run test</tt> <br />
+
<translate>
<translate><!--T:13--> This starts the web server and automatically opens the browser Firefox. Then the tests would be run and the detailed results will be shown in the command line itself.</translate>
+
<!--T:13--> This starts the web server and automatically opens the Firefox browser. Then the tests will run and the detailed results will be shown in the command line.</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
[33m05 02 2018 13:10:01.666:WARN [watcher]: [39mAll files matched by "/var/www/html/JOOMLA/joomla4/joomla-cms/media/system/js/core.js" were excluded or matched by prior matchers.
 
[33m05 02 2018 13:10:01.666:WARN [watcher]: [39mAll files matched by "/var/www/html/JOOMLA/joomla4/joomla-cms/media/system/js/core.js" were excluded or matched by prior matchers.
 
[32m05 02 2018 13:10:02.009:INFO [karma]: [39mKarma v2.0.0 server started at http://0.0.0.0:9876/
 
[32m05 02 2018 13:10:02.009:INFO [karma]: [39mKarma v2.0.0 server started at http://0.0.0.0:9876/
Line 80: Line 82:
 
  - Firefox 58.0.0 (Ubuntu 0.0.0): 125 tests
 
  - Firefox 58.0.0 (Ubuntu 0.0.0): 125 tests
 
   - 125 ok
 
   - 125 ok
</source>
+
</syntaxhighlight>
  
<translate><!--T:14--> What the above command does is execute <tt>node node_modules/karma/bin/karma start karma.conf.js --single-run</tt> in the background. You can check this specification in the script section of the file <tt>package.json</tt></translate>
+
<translate><!--T:14--> The above command executes ''node node_modules/karma/bin/karma start karma.conf.js --single-run'' in the background. You can check this specification in the script section of the ''package.json'' file.</translate>
  
 
<translate>
 
<translate>
==The magic inside== <!--T:15-->
+
==The Magic Inside== <!--T:15-->
</translate>  
+
</translate>
<translate><!--T:16--> The ''karma.conf.js'' file mentioned in the command for starting the Karma server and that you can find in the root of Joomlaǃ 4.x, is the configuration file for the Karma server. Below you can see the content of this file.</translate>
+
<translate><!--T:16--> The ''karma.conf.js'' file mentioned in the command for starting the Karma server and that you can find in the root of Joomlaǃ 4.x, is the configuration file for the Karma server. Below is the content of this file.</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
// Karma configuration
 
// Karma configuration
  
Line 95: Line 97:
 
config.set({
 
config.set({
  
// base path that will be used to resolve all patterns (eg. files, exclude)
+
// base path that will be used to resolve all patterns (e.g. files, exclude)
 
basePath: '',
 
basePath: '',
  
Line 186: Line 188:
 
});
 
});
 
};
 
};
</source>
+
</syntaxhighlight>
 
<translate>
 
<translate>
 
<!--T:17-->
 
<!--T:17-->
Let's have a look at the important configurations that makes everything run together smoothly.</translate>
+
Let's have a look at the important configurations that make everything run smoothly.</translate>
  
<translate><!--T:18--> 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</translate>  
+
<translate><!--T:18--> The ''files'' attribute contains a list of files that the Karma server is going to serve. Unless specified here, no tests can access any file. The set of files currently specified here are the</translate>
 
<translate><!--T:19-->
 
<translate><!--T:19-->
* third party JavaScript libraries like jQuery and jasmine-jquery,
+
* third party JavaScript libraries like jQuery and jasmine-jquery,
* the set of Joomla! custom JavaScript libraries,  
+
* 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 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.</translate>  
+
* the files that contains the HTML fixtures the libraries are tested on and finally some sample images.</translate>
  
<translate><!--T:20--> We have these files specified with the <tt>included: false</tt> 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.</translate>
+
<translate><!--T:20--> We have these 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.</translate>
  
<translate><!--T:21--> 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.</translate>
+
<translate><!--T:21--> 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 does.</translate>
 
<translate>
 
<translate>
 
<!--T:22-->
 
<!--T:22-->
Line 207: Line 209:
 
<translate><!--T:23--> 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.</translate>
 
<translate><!--T:23--> 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.</translate>
  
<translate><!--T:24--> 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.</translate><br />
+
<translate><!--T:24--> The ''browsers'' attribute accepts an array of browsers that the tests 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.</translate>
  
<translate><!--T:25--> If <tt>singleRun</tt> is set to <tt>true</tt>, Karma will start and capture all configured browsers, run tests and then exit with an exit code of 0 or 1 depending on whether all tests passed or any tests failed.<tt>singleRun</tt> a <br>That obviously would not be what we expect when we have <tt>autowatch</tt> 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 <tt>--single-run</tt> option in the karma start command - as we do.</translate>
+
<translate><!--T:25--> If ''singleRun'' is set to ''true'', Karma will start and capture all configured browsers, run tests and then exit with an exit code of 0 or 1 depending on whether all tests passed or any tests failed. That obviously would not be what we expect when we have ''autowatch'' also set to true. 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.</translate>
<tt>node node_modules/karma/bin/karma start karma.conf.js --single-run</tt>
+
''node node_modules/karma/bin/karma start karma.conf.js --single-run''
  
<translate><!--T:26--> 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. You can find this file in the folder <tt>/test/javascript/</tt>.</translate>
+
<translate><!--T:26--> The next important file to look at is ''test-main.js'' which is an auto-generated file from ''require.js''. We use ''require.js'' to make the dynamic loading of dependencies in test specs possible. You can find this file in the folder ''/test/javascript/''.</translate>
  
<translate><!--T:27--> Below you can see the content of this file.</translate>
+
<translate><!--T:27--> Below you can see the contents of this file.</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
const allTestFiles = [];
 
const allTestFiles = [];
 
const TEST_REGEXP = /(spec|test)\.js$/i;
 
const TEST_REGEXP = /(spec|test)\.js$/i;
Line 276: Line 278:
 
callback: window.__karma__.start
 
callback: window.__karma__.start
 
});
 
});
</source>
+
</syntaxhighlight>
<translate><!--T:28--> Two important changes are done to the auto generated file.</translate>
+
<translate><!--T:28--> Two important changes are made to the auto-generated file.</translate>
<translate><!--T:29--> * 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 ''"node_modules/jquery/dist/jquery.min"'' as a dependency, all we need to do is to specify the alias <tt>jquery</tt> in the dependency list.</translate>
+
<translate><!--T:29--> * The first is the ''paths'' attribute set in in the require configuration. These paths allow us to have aliases assigned to specific JavaScript files. Whenever we need to add ''node_modules/jquery/dist/jquery.min'' as a dependency, all we do is specify the alias ''jquery'' in the dependency list.</translate>
<translate><!--T:30--> * 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: <tt>shim: {jasmineJquery: ['jquery']}</tt> tells ''require.js'' to load jquery before loading jasmineJquery.</translate>
+
<translate><!--T:30--> * The next change made to the auto-generated file is the ''shim'' attribute. This is a 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.</translate>
  
 
<translate>
 
<translate>
==Writing new tests== <!--T:31-->
+
==Writing New Tests== <!--T:31-->
</translate>  
+
</translate>
<translate><!--T:32--> 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'').</translate>  
+
<translate><!--T:32--> 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 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'').</translate>
<translate><!--T:33--> 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.</translate>
+
<translate><!--T:33--> 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. The ''fixture.html'' file simply contains pure HTML.</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
-tests
 
-tests
 
--javascript
 
--javascript
Line 294: Line 296:
 
---spec-setup.js
 
---spec-setup.js
 
---spec.js
 
---spec.js
</source>
+
</syntaxhighlight>
 
 
<translate><!--T:34--> The ''spec-setup.js'' mostly does appending of the required HTML fixtures to the DOM. The test setup uses a plugin called <tt>RequireJSText</tt> that allows dynamic loading of HTML files also possible. Only difference is that the dependency is prefixed with <tt>text!</tt>. For example, to load the fixture with an alias <tt>fixtureHtml</tt>, the dependency specified should be <tt>text!fixtureHtml</tt>. You can find this plugin in the folder <tt>/node-modules</tt> For more information see http://requirejs.org/.</translate>
 
  
 +
<translate><!--T:34--> The ''spec-setup.js'' appends the required HTML fixtures to the DOM. The test setup uses the ''RequireJSText'' plugin that allows dynamic loading of HTML files. The only difference is that the dependency is prefixed with ''text!''. For example, to load the fixture with an alias ''fixtureHtml'', the dependency should be ''text!fixtureHtml''. You can find this plugin in the folder ''/node-modules''. For more information see https://requirejs.org/.</translate>
  
 
<translate>
 
<translate>
==Code example== <!--T:35-->
+
==Code Example== <!--T:35-->
</translate>  
+
</translate>
<translate><!--T:36--> On the end of the article [[S:MyLanguage/Running_JavaScript_Tests_for_the_Joomla_CMS|Running JavaScript Tests for the Joomla CMS]] you can find some Code templates. Here you see a code example.</translate>
+
<translate><!--T:36--> At the end of the [[S:MyLanguage/Running_JavaScript_Tests_for_the_Joomla_CMS|Running JavaScript Tests for the Joomla CMS]] article you can find some Code templates. Here is a code example.</translate>
  
 
'''spec.js'''
 
'''spec.js'''
<source lang="javascript">
+
<syntaxhighlight lang="javascript">
 
define(['jquery', 'testsRoot/calendar/spec-setup', 'jasmineJquery'], function ($) {
 
define(['jquery', 'testsRoot/calendar/spec-setup', 'jasmineJquery'], function ($) {
 
beforeAll(function () {
 
beforeAll(function () {
Line 338: Line 339:
 
});
 
});
 
});
 
});
</source>
+
</syntaxhighlight>
  
 
'''spec-setup.js'''
 
'''spec-setup.js'''
  
<source lang="javascript">
+
<syntaxhighlight lang="javascript">
 
define(['jquery', 'text!testsRoot/calendar/fixtures/fixture.html', 'libs/fields/calendar'], function ($, fixture) {
 
define(['jquery', 'text!testsRoot/calendar/fixtures/fixture.html', 'libs/fields/calendar'], function ($, fixture) {
  
Line 349: Line 350:
 
});
 
});
  
</source>
+
</syntaxhighlight>
 
 
  
 
'''fixtures/fixture.html'''
 
'''fixtures/fixture.html'''
<source lang="xml">
+
<syntaxhighlight lang="xml">
 
<div id="calendarjs">
 
<div id="calendarjs">
 
<form name="formTest" onsubmit="return false">
 
<form name="formTest" onsubmit="return false">
Line 387: Line 387:
 
</form>
 
</form>
 
</div>
 
</div>
 
+
</syntaxhighlight>
</source>
 
  
 
<noinclude>
 
<noinclude>

Latest revision as of 15:03, 17 October 2022

Other languages:
Deutsch • ‎English • ‎français

Introduction[edit]

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

You can find the current version of the tests on GitHub.com in the repository.

When you checkout the 4.0-dev 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.

$ ls
acceptance.suite.yml  Gemfile              package.json
administrator         htaccess.txt         phpunit.xml.dist
appveyor-phpunit.xml  images               plugins
build                 includes             README.md
build.js              index.php            README.txt
build.xml             installation         RoboFile.dist.ini
cache                 Jenkinsfile          RoboFile.php
cli                   jenkins-phpunit.xml  robots.txt.dist
codeception.yml       karma.conf.js        scss-lint.yml
components            language             templates
composer.json         layouts           -> test
composer.lock         libraries            tmp
configuration.php     LICENSE.txt          travisci-phpunit.xml
dev                   media                web.config.txt
drone-package.json    modules
$

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

Prerequisites[edit]

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 version 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)[edit]

Open a command line and navigate to the root directory of Joomla 4.x.

Execute command npm install

$ npm install
...
added 1354 packages in 193.687s
$

This will install all the dependencies to the /node_modules directory. If a /node_modules folder does not exist, a folder will be automatically created by npm. It is OK, if you see some warnings, but you should not see an error message. This will give you a full setup that might be different from the automated testing setup. For automated testing we are using drone-package.json. If you are rename package.json to package.json.save and drone-package.json to package.json before you run npm install, you will get a lighter setup and you will be using the versions we are using in our automated testing setup.

Starting the Karma Server and Running the Tests[edit]

Execute the commandnpm run test

This starts the web server and automatically opens the Firefox browser. Then the tests will run and the detailed results will be shown in the command line.

[33m05 02 2018 13:10:01.666:WARN [watcher]: [39mAll files matched by "/var/www/html/JOOMLA/joomla4/joomla-cms/media/system/js/core.js" were excluded or matched by prior matchers.
[32m05 02 2018 13:10:02.009:INFO [karma]: [39mKarma v2.0.0 server started at http://0.0.0.0:9876/
[32m05 02 2018 13:10:02.010:INFO [launcher]: [39mLaunching browser Firefox with unlimited concurrency
[32m05 02 2018 13:10:02.015:INFO [launcher]: [39mStarting browser Firefox
[32m05 02 2018 13:10:04.159:INFO [Firefox 58.0.0 (Ubuntu 0.0.0)]: [39mConnected on socket 0l2b3VhoFFUVyWitAAAA with id 91983742
[33m05 02 2018 13:10:04.493:WARN [web-server]: [39m404: /uri
[32m05 02 2018 13:10:04.556:INFO [Firefox 58.0.0 (Ubuntu 0.0.0)]: [39mStarting tests 91983742
Firefox 58.0.0 (Ubuntu 0.0.0): Executed 0 of 125 SUCCESS (0 secs / 0 secs)
...
Browser results:

 - Firefox 58.0.0 (Ubuntu 0.0.0): 125 tests
   - 125 ok

The above command executes node node_modules/karma/bin/karma start karma.conf.js --single-run in the background. You can check this specification in the script section of the package.json file.

The Magic Inside[edit]

The karma.conf.js file mentioned in the command for starting the Karma server and that you can find in the root of Joomlaǃ 4.x, is the configuration file for the Karma server. Below is the content of this file.

// Karma configuration

module.exports = function (config) {
	config.set({

		// base path that will be used to resolve all patterns (e.g. files, exclude)
		basePath: '',

		// frameworks to use
		// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
		frameworks: ['jasmine-ajax', 'jasmine', 'requirejs'],

		// list of files / patterns to load in the browser
		files: [
			{pattern: 'media/system/js/polyfills/webcomponents/webcomponents-ce.min.js', included: true, served: true, watched: true},
			{pattern: 'node_modules/jquery/dist/jquery.min.js', included: false},
			{pattern: 'node_modules/jasmine-jquery/lib/jasmine-jquery.js', included: false},
			{pattern: 'node_modules/text/text.js', included: false},
			{pattern: 'media/vendor/bootstrap/js/bootstrap.min.js', included: false},
			{pattern: 'media/vendor/jquery-ui/js/jquery.ui.core.min.js', included: false},
			{pattern: 'media/vendor/jquery-ui/js/jquery.ui.sortable.min.js', included: false},
			{pattern: 'media/system/js/*.js', included: false},
			{pattern: 'media/system/js/core.js', included: false,served: true, watched: true},
			{pattern: 'media/system/js/legacy/*.js', included: false},
			{pattern: 'media/system/js/fields/*.js', included: false},
			{pattern: 'media/vendor/joomla-custom-elements/js/joomla-alert.min.js', included: false, served: true, watched: true},
			{pattern: 'media/system/js/fields/calendar-locales/*.js', included: false},
			{pattern: 'media/system/js/fields/calendar-locales/date/gregorian/*.js', included: false},
			{pattern: 'tests/javascript/**/fixture.html', included: false},
			{pattern: 'tests/javascript/**/spec.js', included: false},
			{pattern: 'tests/javascript/**/spec-setup.js', included: false},
			{pattern: 'media/system/webcomponents/js/*.js', included: false},
			{pattern: 'images/*.png', included: false},

			'tests/javascript/test-main.js'
		],

		exclude: [
			'media/system/webcomponents/js/*-es5.js',
			'media/system/webcomponents/js/*.min.js',
			'media/system/webcomponents/js/*-es5.min.js',
		],

		// preprocess matching files before serving them to the browser
		// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
		preprocessors: {
			'**/system/js/*.js': ['coverage']
		},

		// coverage reporter configuration
		coverageReporter: {
			type : 'html',
			dir : 'build/coverage-js/'
		},

		// test results reporter to use
		// possible values: 'dots', 'progress'
		// available reporters: https://npmjs.org/browse/keyword/karma-reporter
		reporters: ['verbose', 'progress', 'coverage'],

		// web server port
		port: 9876,

		// enable / disable colors in the output (reporters and logs)
		colors: true,

		// level of logging
		// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
		logLevel: config.LOG_INFO,

		// enable / disable watching file and executing tests whenever any file changes
		autoWatch: true,

		// start these browsers
		// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
		browsers: ['Firefox'],

		// Continuous Integration mode
		// if true, Karma captures browsers, runs the tests and exits
		singleRun: false,

		// list of plugins
		plugins: [
			'karma-jasmine',
			'karma-jasmine-ajax',
			'karma-firefox-launcher',
			'karma-coverage',
			'karma-requirejs',
			'karma-verbose-reporter'
		],

		// Concurrency level
		// how many browser should be started simultaneous
		concurrency: Infinity
	});
};

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

The files attribute contains a list of files that the Karma server is going to serve. Unless specified 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 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 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 the tests 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.

If singleRun is set to true, Karma will start and capture all configured browsers, run tests and then exit with an exit code of 0 or 1 depending on whether all tests passed or any tests failed. That obviously would not be what we expect when we have autowatch also set to true. 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. node node_modules/karma/bin/karma start karma.conf.js --single-run

The next important file to look at is test-main.js which is an auto-generated file from require.js. We use require.js to make the dynamic loading of dependencies in test specs possible. You can find this file in the folder /test/javascript/.

Below you can see the contents of this file.

const allTestFiles = [];
const TEST_REGEXP = /(spec|test)\.js$/i;

// Get a list of all the test files to include
Object.keys(window.__karma__.files).forEach((file) => {
	if (TEST_REGEXP.test(file)) {
		// Normalize paths to RequireJS module names.
		// If you require sub-dependencies of test files to be loaded as-is (requiring file extension)
		// then do not normalize the paths
		const normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '');
		allTestFiles.push(normalizedTestModule);
	}
});

require.config({
	// Karma serves files under /base, which is the basePath from your config file
	baseUrl: '/base',

	paths: {
		'core': 'media/system/js/core.min',
		'jquery': 'node_modules/jquery/dist/jquery.min',
		'jui': 'media/vendor/jquery-ui/js/jquery.ui.core.min',
		'jui-sortable': 'media/vendor/jquery-ui/js/jquery.ui.sortable.min',
		'bootstrap': 'media/vendor/bootstrap/js/bootstrap.min',
		'jasmineJquery': 'node_modules/jasmine-jquery/lib/jasmine-jquery',
		'libs': 'media/system/js',
		'legacy_libs': 'media/system/js/legacy',
		'testsRoot': 'tests/javascript',
		'text': 'node_modules/text/text',
		'fields': 'media/system/js/fields',
		'calLang': 'media/system/js/fields/calendar-locales/en',
		'calDate': 'media/system/js/fields/calendar-locales/date/gregorian/date-helper',
		'JCE': 'media/system/webcomponents/js'
	},

	shim: {
		jasmineJquery: ['jquery'],
		bootstrap: ['jquery'],
		'jui-sortable': ['jquery'],
		'libs/validate': {
			deps: []
		},
		'libs/subform-repeatable': {
			deps: ['jquery', 'jui', 'jui-sortable']
		},
		'JCE/joomla-field-send-test-mail': {
			deps: ['jquery']
		},
		'libs/fields/calendar': {
			deps: ['calLang', 'calDate']
		}
	},

	// dynamically load all test files
	deps: allTestFiles,

	// we have to kickoff jasmine, as it is asynchronous
	callback: window.__karma__.start
});

Two important changes are made 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. Whenever we need to add node_modules/jquery/dist/jquery.min as a dependency, all we do is specify the alias jquery in the dependency list.
  • The next change made to the auto-generated file is the shim attribute. This is a 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[edit]

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 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. The fixture.html file simply contains pure HTML.

-tests
--javascript
---fixtures
----fixture.html
---spec-setup.js
---spec.js

The spec-setup.js appends the required HTML fixtures to the DOM. The test setup uses the RequireJSText plugin that allows dynamic loading of HTML files. The only difference is that the dependency is prefixed with text!. For example, to load the fixture with an alias fixtureHtml, the dependency should be text!fixtureHtml. You can find this plugin in the folder /node-modules. For more information see https://requirejs.org/.

Code Example[edit]

At the end of the Running JavaScript Tests for the Joomla CMS article you can find some Code templates. Here is a code example.

spec.js

define(['jquery', 'testsRoot/calendar/spec-setup', 'jasmineJquery'], function ($) {
	beforeAll(function () {
		var element = document.querySelector(".field-calendar"),
		    input = document.getElementById('jform_created'),
		    currentDate = new Date();

		input.value = currentDate.getFullYear() + '-09-01 05:17:00';
		input.setAttribute('data-alt-value', currentDate.getFullYear() + '-09-01 05:17:00');

		JoomlaCalendar.init(element);
	});

	describe('Calendar set for the input element', function () {
		it('Should have calendar element under the input element', function () {
			expect($('body')).toContainElement('.js-calendar');
		});

		it('Calendar should be hidden', function () {
			expect($('.js-calendar').css('display')).toEqual('none');
		});

		it('Should appear on button click', function (done) {
			$('#jform_created_btn').trigger('click');

            setTimeout(function() {
                expect($('.js-calendar').css('display')).toEqual('block');
                done();
            }, 200)

		});
	});
});

spec-setup.js

define(['jquery', 'text!testsRoot/calendar/fixtures/fixture.html', 'libs/fields/calendar'], function ($, fixture) {

	$('body').append(fixture);

});

fixtures/fixture.html

<div id="calendarjs">
	<form name="formTest" onsubmit="return false">
		<div class="field-calendar">
			<div class="input-append">
				<input type="text"
						id="jform_created"
						name="jform[created]"
						value=""
						size="22"
						placeholder="Created date."
						data-alt-value=""
						aria-invalid="false">
				<button type="button"
						class="btn btn-secondary"
						id="jform_created_btn"
						data-inputfield="jform_created"
						data-dayformat="%Y-%m-%d %H:%M:%S"
						data-button="jform_created_btn"
						data-firstday="0"
						data-weekend="0,6"
						data-today-btn="1"
						data-week-numbers="0"
						data-show-time="0"
						data-show-others="1"
						data-time-24="24"
						data-only-months-nav="0">
					<span class="icon-calendar"></span>
				</button>
			</div>
		</div>
		<input type="text" name="none-spec" id="cal-close-btn" value="" title="nonenne"/>
	</form>
</div>