December 28, 2020
Estimated Post Reading Time ~

How to write JS Unit Test cases for AEM ClientLibraries using JEST

This article demonstrates how to set up and run the Javascript Jest unit test for client libraries. As a part of this setup, code coverage will be produced by Jest. With this implementation, we will utilize the frontend-maven-plugin, where it makes it possible to run npm scripts apart of the maven build.

Most of the time, AEM developers must create new components in AEM with javascript rich experiences. These experiences may be allowing the end-users to toggle the navigation header, submit a search query, or even to control a slide show. Most of the time we would not need to build a full-blown complex Javascript heavy application using the latest ES6 syntax, ES6 javascript modules, Webpack, etc ReactJS, and AngularJS is not required.

With a not full-blown Javascript application, we are encouraged to write Javascript logic directly into a client library with ES5; with tools and libraries like Jquery, Underscore JS, Mustache JS, etc… so the Adobe Granite HTML Library Manager will be working as expected.

What is Jest?
Jest is the unit testing framework for front-end driven projects. It is developed and used by Facebook themselves.

Some features of Jest are:
  • Automatically find tests with files suffixed as test.js; example Header.test.js.
  • Supports dependency injection.
  • Supports mocks.
  • Runs your tests with a fake DOM implementation
  • and, Runs tests in parallel processes
Setup Introduction
This example is based on an AEM project built using the AEM project using the AEM Project Archetype 20.

For this example, I have created a javascript file of Helper.js that sits directly under the clientlib-site folder. This client library will exist in the AEM Project Archetype 20 build. Javascript tests should sit within the same directory as the Helper.js file under __tests__, as ./__tests__/Helper.test.js.



On a standard AEM application build, I will run mvn clean install. The application will build as follows:


The run down:
  • developer runs: mvn clean install.
  • The core bundle will be built, unit tests from the core maven module will be run.
  • onSuccess, proceed to the next step; onFail stop build.
  • Javascript Jest unit tests from the ui.apps maven module will be invoked, and code coverage from the Jest test will be produced.
  • onSuccess, proceed to the next step; onFail stop build.
  • The ui.apps.zip will live in the target folder.
How to Setup JEST on an AEM Project

This setup has been tested on the latest AEM Project Archetype 20 project build. If you wish to follow this tutorial, please first build the AEM Project Archetype 20 project.

1. Add Helper.js

// create file under directory
// ui.apps/src/main/content/jcr_root/apps/sourcedcode/clientlibs/clientlib-site/js/Helper.js


window.JestTest = window.JestTest || {};

JestTest.Helpers = (function () {

function add(num1, num2) {
return num1 + num2;
}

function divide(num1, num2) {
return _secretDivide(num1, num2);
}

function _secretDivide(num1, num2) {
return num1 / num2;
}

return {
add: add,
divide: divide
}

}());

2. Add Helper.test.js

// create file under directory
// ui.apps/src/main/content/jcr_root/apps/sourcedcode/clientlibs/clientlib-site/js/__tests__/Helper.test.js


require('../Helpers');
let Helpers = window.JestTest.Helpers;

beforeAll(() => {
Helpers = window.JestTest.Helpers;
});

afterAll(() => {
Helpers = {};
});

it('it should calculate additions as expected 1 + 2 = 3', () => {
expect(Helpers.add(1, 2)).toEqual(3);
});

it('it should calculate additions as expected 0 + 2 = 2', () => {
expect(Helpers.add(0, 2)).toEqual(2);
});

it('it should calculate divisions as expected 0 / 2 = 0', () => {
expect(Helpers.divide(0, 2)).toEqual(0);
});

3. Edit the ui.apps/pom.xml to exclude all directories of __tests__ from being built as apart of the AEM content package (ui.apps)

// add below configuration under -> ui.apps/pom.xml

<!-- out of the box AEM Archetype 20 org.apache.jackrabbit setup -->
<plugin>
    <groupId>org.apache.jackrabbit</groupId>
    <artifactId>filevault-package-maven-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
        <group>com.sourcedcode</group>
        <embeddeds>
            <embedded>
                <groupId>com.sourcedcode</groupId>
                <artifactId>com.sourcedcode.core</artifactId>
                <target>/apps/sourcedcode/install</target>
            </embedded>
        </embeddeds>
        <subPackages>
            <subPackage>
                <groupId>com.adobe.cq</groupId>
                <artifactId>core.wcm.components.all</artifactId>
                <filter>true</filter>
            </subPackage>
            <subPackage>
                <groupId>com.adobe.cq</groupId>
                <artifactId>core.wcm.components.examples</artifactId>
                <filter>true</filter>
            </subPackage>
        </subPackages>


        <!-- custom excludes XML properties -->
        <excludes>
            <exclude>**/*test*</exclude>
        </excludes>
    </configuration>
</plugin>

4. Include the plugin com.github.eirslett, under ui.apps/pom.xml

// add below configuration under -> Setup ui.apps/pom.xml

<plugin>
    <groupId>com.github.eirslett</groupId>
    <artifactId>frontend-maven-plugin</artifactId>
    <version>${frontend-maven-plugin.version}</version>
    <configuration>
        <skip>${skipTests}</skip>
    </configuration>
    <executions>
        <execution>
            <id>install node and npm</id>
            <phase>validate</phase>
            <goals>
                <goal>install-node-and-npm</goal>
            </goals>
            <configuration>
                <nodeVersion>${node.version}</nodeVersion>
                <npmVersion>${npm.version}</npmVersion>
            </configuration>
        </execution>
        <execution>
            <id>npm ci</id>
            <phase>initialize</phase>
            <goals>
                <goal>npm</goal>
            </goals>
            <configuration>
                <arguments>install</arguments>
            </configuration>
        </execution>
        <execution>
            <id>npm run test</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>npm</goal>
            </goals>
            <configuration>
                <arguments>run test</arguments>
            </configuration>
        </execution>
    </executions>
</plugin>

5. Include shared maven project properties in parent/pom.xml

// add below configuration under -> parent/pom.xml

<properties>
    <!-- out of the box AEM Archetype 20 properties -->
    <aem.host>localhost</aem.host>
    <aem.port>4502</aem.port>
    <aem.publish.host>localhost</aem.publish.host>
    <aem.publish.port>4503</aem.publish.port>
    <sling.user>admin</sling.user>
    <sling.password>admin</sling.password>
    <vault.user>admin</vault.user>
    <vault.password>admin</vault.password>
    <core.wcm.components.version>2.5.0</core.wcm.components.version>
    <bnd.version>4.2.0</bnd.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <!-- custom properties -->
    <skipTests>false</skipTests>
    <frontend-maven-plugin.version>1.6</frontend-maven-plugin.version>
    <node.version>v10.15.0</node.version>
    <npm.version>6.5.0</npm.version>
</properties>

6. Setup ui.apps/package.json

// add below configuration under -> ui.apps/package.json

{
"name": "com.sourcedcode",
"version": "1.0.0",
"description": "This is an example of testing AEM component's clientlib (with JavaScript) using NodeJS and maven build",
"scripts": {
"test": "jest --coverage"
},
"author": "SourcedCode",
"license": "ISC",
"devDependencies": {
"babel-jest": "^23.6.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"jest": "^23.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1"
}
}


7. Add and Setup file ui.apps/.babelrc

// create a file names .babelrc
// add below configuration under -> ui.apps/.babelrc

{
"presets": ["babel-preset-es2015", "babel-preset-stage-2"]
}


The Results
On a successful build, the results will be as shown:


On a successful build, the Jest coverage report will be generated. You can find the generated reports under “ui.apps/coverage”. Click here to learn more about the Jest coverage.


Known Issues:
Please disregard marked [ERROR] tags, as this is a known issue #584. When your Javascript unit tests are invalid, the build will not be successful, and the build will not proceed.

To ensure that you do not lose confidence in the Maven Front-end Plugin, here is an example of Adobe using the same library in its production AEM Core Components project.

Last Tips
  • You can run mvn clean install -DskipTests=true if you want to build your AEM project without running Java or Javascript tests; this setup enabled you to do so.
  • You can also change directory (CD) into the ui.apps module, and run npm tests, to only run the Jest Tests.
Source: https://sourcedcode.com/blog/aem/how-to-write-javascript-unit-tests-for-aem-client-libraries-with-jest


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.