Testing Spring Boot apps with MochaJS

This article is about testing REST APIs in a Spring Boot application using MochaJS during integration tests phase in Maven.

Why?

This may sound like reinventing the wheel, but believe me - there are some good reasons. I'm working on a SPA web app using REST to communicate with a stateless Spring Boot app, and these are the pros I considered:

  • Mocha is really easy - First off, I'm talking about integration test, and not unit tests (where JUnit just shines). Although Spring offers some nice solutions for REST controllers testing, I find Java too verbose to write simple things like posting a JSON to a server URL and test its result. With mocha I write complex tests with just a few lines of code.
  • Testing final code ready for deployment - It is common an app to have different behaves during development and production, for example, disable some local caches when in development mode. Spring offers a maven plugin that executes integration tests just after packaging the project, i.e, the code that will be tested is the one that is ready to be deployed.
  • Fast coding and testing - Writing integration tests in Spring is not difficult, but it is so time consuming. I'm working on a Spring Boot app that takes from 15 to 20 seconds to start up in my local computer (and it is not a slow one), and every time I want to run a test I must run and wait for the server to start up. Working with Mocha, I run the app once and execute tests as many times I want. Great when you are writing your test scripts.
  • The language of the web - This is really important. When you write your REST API, you must have in mind that it might be consumed by a browser, for example. When writing tests in Mocha you will post requests and send results the same way it would be done in a web app, i.e, using JavaScript, which becomes a great source of reference when implementing it a web app.
  • A good companion for continuous integration tools - We use Jenkins to build the system on every source code change, and because integration tests are part of Maven building process, we can guarantee that Mocha test scripts will run on every build.

The example

I'll demonstrate a very simple Spring Boot app with a single REST controller to be tested by Mocha. I'm using Maven to build and test the application. I also want Maven to do all the work, like resolve dependency management (both Java and NodeJS), start the application and run Mocha during integration test. The bottom line is, I want Maven to do all that with the command:

$ mvn clean verify

I'm using the verify phase because it is the one that will trigger the integration-test phase inside Maven.

The full source code of this example is available at
https://github.com/rmemoria/spring-boo-mocha-example

I've created an initial Spring Boot app using the generator at
http://start.spring.io/

And I declared a REST controller that exposes a REST API to ping back the given name with the word 'Hello':

@RestController
@RequestMapping("/api")
public class TestRestController {

    @RequestMapping(value = "/hello", method = RequestMethod.POST, consumes = { "text/plain" })
    @ResponseBody
    public String sqyHello(@RequestBody String name) {
        System.out.println(name);
        return "Hello " + name;
    }
}

If you run the app it can be easily tested with CURL

$ curl --data "world" http://localhost:8080/api/hello -H "Content-Type:text/plain"

And you get

Hello world

Ok, let's create the Mocha script.

I want to have the flexibility to run my Mocha scripts from the command line, so I installed Mocha globally:

$ npm install -g mocha

I also declared a package.json file in the project root. This file is used by NPM to install all dependencies (command npm install) and execute the Mocha test scripts (command npm test).

{
  "name": "spring-boo-mocha-example",
  "version": "1.0.0",
  "description": "Spring boot app using Mocha for integration tests",
  "dependencies": {
    "mocha": "^3.1.2",
    "supertest": "^2.0.1"
  },
  "devDependencies": {},
  "scripts": {
    "test": "mocha tests/index.js"
  },
...
}

Supertest is a npm module to test HTTP servers. It will make easier to post HTTP requests to the server and test its result.

The test script is in the tests folder, in the index.js file:

var HOST = 'http://localhost:8080';

var agent = require('supertest').agent(HOST);
var assert = require('assert');


describe('Simple API test', function() {

    it('Hello', function(done) {
        var req = 'World';

        agent.post('/api/hello')
            .expect(200)
            .set('Content-Type', 'text/plain')
            .send(req)
            .end((err, res) => {
                assert.equal('Hello ' + req, res.text);
                done();
            });
    });
});

It is a very simple test that will make a request to http://localhost:8080/api/hello URL and check its result.

If you want to test your script, you'll have to start the server first

$ mvn clean package
$ java -jar target/spring-boot-mocha-example-0.0.1-SNAPSHOT.jar

With the server up and running, just call the Mocha script

$ mocha tests\index.js

And if everything is ok, you may see something like

  Simple API test
    ✓ Hello


  1 passing (26ms)

Integrating with Maven

In order to have Maven doing all the work, I'm using 2 extra plugins:

  • Frontend-maven-plugin - Download and install Node and NPM locally, and also integrates other Node tools to Maven lifecycle;
  • Spring-boot-maven-plugin - provides Spring Boot support in Maven, allowing you to package executable jar or war archives and run an application “in-place”.

So this is how things work when I execute a $ mvn clean verify in the root project folder:

1. Maven will clean up the target folder, because of the clean argument of the mvn command.

2. Maven will install Node and NPM locally in the project root folder, using the frontend-maven-plugin during the generate-resources phase. It will also run the command npm install. It is all achieved with the following declaration in the pom.xml file:

<plugins>
    ...
          <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>1.1</version>

                <configuration>
                    <nodeVersion>v5.6.0</nodeVersion>
                    <npmVersion>3.3.12</npmVersion>
                </configuration>
                <executions>
                    <execution>
                        <id>Install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>npm install</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>

3. Maven will continue its default lifecycle of compiling and packing the project;

4. Before reaching the verify phase, the spring-boot-maven-plugin will be called to start the application (during the pre-integration-test phase):

   <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>1.3.5.RELEASE</version>
        <configuration>
            <mainClass>com.example.mocha.SpringBootMochaExampleApplication</mainClass>
        </configuration>
        <executions>
            <execution>
                <id>pre-integration-test</id>
                <goals>
                    <goal>start</goal>
                </goals>
                <configuration>
                    <mainClass>com.example.mocha.SpringBootMochaExampleApplication</mainClass>
                    <maxAttempts>60000</maxAttempts>
                </configuration>
            </execution>
            ...

5. The frontend-maven-plugin will be called again (during integration-test phase) to run Mocha script tests thought NPM:

<plugin>
        <groupId>com.github.eirslett</groupId>
        <artifactId>frontend-maven-plugin</artifactId>
        <version>1.1</version>

        <configuration>
            <nodeVersion>v5.6.0</nodeVersion>
            <npmVersion>3.3.12</npmVersion>
        </configuration>
        <executions>
      ...
            <execution>
                <id>integration-test</id>
                <goals>
                    <goal>npm</goal>
                </goals>
                <phase>integration-test</phase>
                <configuration>
                    <arguments>test</arguments>
                </configuration>
            </execution>
        </executions>
</plugin>

6. And finally, during the post-integration-test phase, the application is stopped by the spring-boot-maven-plugin:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.3.5.RELEASE</version>
    <configuration>
        <mainClass>com.example.mocha.SpringBootMochaExampleApplication</mainClass>
    </configuration>
    <executions>
        ...
        <execution>
            <id>post-integration-test</id>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

In case of error during integration tests with Mocha, Maven interrupts its execution displaying the error produced by Mocha.

Good luck.

Original content: http://rmemoria.blogspot.com.br/2016/11/testing-spring-boot-apps-with-mochajs.html

Creating a tree view using React.js

This article is a tutorial about how to create an extendable tree view component using the awesome React.js framework.

The idea

It’s been quite common in projects I've been working with to display information in a tree view, and dealing with that in an HTML page and pure javascript is always painful. So I decided to create a tree view component using React.js that I could easily customize it, from a simple tree to a tree view table, with not much work.

For the impatient:

Dependencies

In this example, my tree view will have the following dependencies:

The component

I want the tree view to expose the minimum and most meaningful set of properties to the parent component. Ideally, the parent component should not deal with implementation details of a tree, like controlling the collapsing and expanding of nodes. So my TreeView component will expose the following properties:

  • getNodesData = function(parent) - Called every time the TreeView must retrieve the children of a parent node. It will return an array of data. The data returned has no relation with the TreeView but just to serve as a reference when communicating with the parent component. For example, when expanding an specific node, the data retrieved before is passed as a parameter representing the node. For asynchronous operation, the function may return a promise.
  • checkLeaf = function(data) - Optional - Just to check if the given data returned from getNodesData() represents a leaf (returning true) or if the node representing the data has children to display (returning false);
  • innerRender = function(data) - Must return a react component or a string as the label that will be displayed beside the node;
  • outerRender = function(comp, data) - Optional - Allows the parent to wrap the node inside another react component. It will allow to create complex compositions, like columns.

Internally, the TreeView will store a tree model in its state. This tree will be initialized with the root nodes, and as children are loaded, the tree model is updated.

Declaring the component

Let's create a new file called tree-view.jsx and declare the TreeView class

import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

// load css styles
import './tree-view.less';

export default class TreeView extends React.Component {
render() {
 // get the root nodes
 const root = this.state ? this.state.root : null;

 // roots were not retrieved ?
 if (!root) {
  const self = this;
  this.loadNodes(null)
   .then(res => self.setState({ root: res }));
  return null;
 }

 return <div className="tree-view">{this.createNodesView(root)}</div>;
}
}

I see it as a good practice to declare one class per file, so the TreeView class is declared as exported and default.
The render function is quite straightforward - It simply checks if the root nodes are available, load them if not, and delegate the rendering to the function createNodesView.

Retrieving the tree nodes

Before rendering the tree, the TreeView must have at least the root nodes. Nodes are created based on an array returned from the parent component. The content of the array is not relevant to the TreeView. The elements will be used to create nodes and make reference to them when communicating with the parent component. So, whenever the TreeView needs to retrieve the children of a node, it will call the function loadNodes:

loadNodes(parent) {
 const func = this.props.onGetNodes;

 if (!func) {
   return null;
 }

 const pitem = parent ? parent.item : undefined;
 let res = func(pitem);

 // is not a promise ?
 if (!res || !res.then) {
  // force node resolution by promises
  res = Promise.resolve(res);
 }

 // create nodes wrapper when nodes are resolved
 const self = this;
 return res.then(items => {
  if (!items) {
   return [];
  }

  const nodes = self.createNodes(items);
  return nodes;
 });
}
  • Line 9 asks the parent component to send the array of children data relative to the parent node. The first call will ask for data of the root node, so parent will be null. Subsequent calls will inform the node data as the parent.
  • Line 12 checks if the result from onGetNodes is a promise. If not, embed it into a promise.
  • Line 19 waits for the promise to resolve. Once it is resolved, it will contain the array of nodes data.
  • Line 24 creates the node objects from the data returned of the parent component.

Node objects will store the state of the node, like if it is a leaf or not, and if it is collapsed or expanded. The implementation of the createNodes function is:

createNodes(items) {
 const funcInfo = this.props.checkLeaf;
 return items.map(item => {
  const leaf = funcInfo ? funcInfo(item) : false;
  return { item: item, state: 'collapsed', children: null, leaf: leaf };
 });
}
  • Line 4 asks the parent component if the data representing the node is a leaf or a node with other children. Notice that the initial state of the node is 'collapsed', but the node may have the states 'expanding' and 'expanded';
  • Line 5 creates the object that will store information about the node;

This function will return an array of node objects used internally by the TreeView.

Displaying the tree

Displaying the tree is nothing but creating the components that will be rendered based on the node tree model stored in the component state. In order to display the tree, the TreeView component will travesse all visible nodes and create react components from them. This is done by the createNodesView() function, called from the render() function:

createNodesView() {
 const self = this;
 
 // recursive function to create the expanded tree in a list
 const mountList = function(nlist, level, parentkey) {
  let count = 0;
  const lst = [];
 
  nlist.forEach(node => {
   const key = (parentkey ? parentkey + '.' : '') + count;
   const row = self.createNodeRow(node, level, key);
 
   lst.push(row);
   if (node.state !== 'collapsed' && !node.leaf && node.children) {
    lst.push(mountList(node.children, level + 1, key));
   }
   count++;
  });
 
  // the children div key
  const divkey = (parentkey ? parentkey : '') + 'ch';
 
  // children are inside a ReactCSSTransitionGroup, in order to animate collapsing/expanding events
  return (
   <ReactCSSTransitionGroup key={divkey + 'trans'} transitionName="node"
    transitionLeaveTimeout={250} transitionEnterTimeout={250} >
    {lst}
   </ReactCSSTransitionGroup>
   );
 };
 
 return mountList(this.state.root, 0, false);
}
  • Line 5 declares an internal function that will recursively travesse the node tree. It will receive the node list, the level of the list in the tree and the parent key used as the key of the react component;
  • Line 10 creates the key based on the parent key and the index of the node in the list;
  • Line 11 creates the react component, by invoking the createNodeRow function;
  • Line 14 checks if the node in the loop is expanded and contains child nodes. If so, call the function recursively;
  • Line 25 is used a react add-on to give animation to the node when it is collapsed or expanded;
  • Line 32 Is where the function is called, returning the list of components to be displayed

In fact, each react component of a node is created by the createNodeRow function, that takes the node object, the level in the tree and node key as parameter:

createNodeRow(node, level, key) {
   const p = this.props;
 
    // get the node inner content
    const content = p.innerRender ? p.innerRender(node.item) : node.item;
 
    // get the icon to be displayed
    const icon = this.resolveIcon(node);
 
    const waitIcon = node.state === 'expanding' ?
  <div className="fa fa-refresh fa-fw fa-spin" /> : null;
    // the content
    const nodeIcon = node.leaf ?
        icon :
        <a className="node-link" onClick={this.nodeClick} data-item={key}>
            {icon}
        </a>;
 
    const nodeRow = (
        <div key={key} className="node" style={{ marginLeft: (level * 16) + 'px' }}>
            {nodeIcon}
            {content}
        </div>
        );
 
    // check if wrap the component inside another one
    // provided by the parent component
    return p.outerRender ? p.outerRender(nodeRow, node.item) : nodeRow;
}
  • Line 5 gets the content that will be displayed beside the node collapse/expand button;
  • Line 8 gets the icon to be displayed as the collapse/expand button, by invoking resolveIcon;
  • Line 11 checks if the node is being expanded. If so, it will include an animated icon spinning while the node is loaded.
  • Line 13 generates the control to display the collapse/expand button. If it is not a leaf, the control will be an anchor, so the user will be able to collapse or expand the node.
  • Line 19 creates the node row, wrapping button and content inside a single div.
  • Line 28 if the parent component provided the property outerRender, it will be called to wrap the node row inside another component.

And this is the implementation of the function that will return the icon to display according to the node state:

resolveIcon(node) {
    let icon;
    if (node.leaf) {
        icon = 'circle-thin';
    }
    else {
        icon = node.state !== 'collapsed' ? 'minus-square-o' : 'plus-square-o';
    }
 
 
    var className = 'fa fa-' + icon + ' fa-fw';
    return <i className={className} />;
}

It uses Font Awesome to display the icon in the node tree.

Adding animation to the collapsing/expanding event

If you notice, when clicking on the plus or minus button, the tree is not collapsed or expanded immediately, but there is a quick animation that slides the children up or down smoothly. This effect is achieved with the animation features of CSS3 and the React add-on animation. One of the coolest features of Webpack is that you can embed CSS styles per javascript module. This is done by including it in the import section:

import from 'tree-view.less'

And the TreeView css style is

.tree-view {
 .title {
  font-weight: bold;
 }
 
 .node-link {
  cursor: pointer;
 }
}
 
.node-enter, .node-leave {
 display: block;
 overflow: hidden;
}
 
.node-enter {
 max-height: 0;
}
 
.node-enter.node-enter-active {
 max-height: 500px;
 transition: max-height 250ms ease-in;
}
 
.node-leave {
 max-height: 500px;
}
 
.node-leave.node-leave-active {
 max-height: 0px;
 transition: max-height 250ms ease-out;
}
 
.node-row {
 border-top: 1px solid #f0f0f0;
}

Actually it is not CSS, but Less, which gives a lot of extra features to create your CSS styles. Behind the scenes, Webpack transform this less file in css and embed it in the TreeView code. In order to give that smooth animation of nodes collapsing and expanding, these CSS elements are automatically included and removed by the react add-on animation module, which is applied in the function createNodesView:

createNodesView() {
  ..
  ..
  ..
 
  return (
   <ReactCSSTransitionGroup key={divkey + 'trans'} transitionName="node"
    transitionLeaveTimeout={250} transitionEnterTimeout={250} >
    {lst}
   </ReactCSSTransitionGroup>
   );

Conclusion

The TreeView is a basic component, but it can be easily customized and modified. In the source code at the top of this page, I made a lot of small improvements in the TreeView, like the possibility to change the icons being displayed and a property to display a header title at the top of the tree. Modify it as you wish. Have fun...

The original link for this post is here