Mock back-end for UI testing (Angular)
Tags: angular, webdev, testing, mock
Published: 2021-02-22 19:49:08

*Original post with additional details available at:* [https://allthingsangular.com/angular-and-wiremock-integration-for-ui-testing/](https://allthingsangular.com/angular-and-wiremock-integration-for-ui-testing/)


This post describes how to integrate **Angular** and **WireMock** (a mock HTTP back-end server). **Protractor**, along side **Jasmine** is used to create **User Interface (UI) tests**. At the same time, Protractor provides integration point between Angular and WireMock.

### Table of Content
* Integrating Angular and WireMock (via Protractor)
* Using Angular and WireMock (via Protractor)
* Conclusion

#Integrating Angular and WireMock (via Protractor)
WireMock is started as a standalone instance and is used as a HTTP mock server. Protractor is configured to automatically start WireMock instance before executing tests. Protractor is also configured to stop WireMock instance after all tests are executed.

Integration process is demonstrated on a newly created Angular application.

### Create a demo project
* Create a new Angular application using Angular CLI 
```sh
$ ng new wiremock-demo
```

### Download WireMock
* Under wiremock-demo/e2e create a new wiremock-config folder
```
$ mkdir wiremock-config
```

* Download WireMock standalone under wiremock-demo/e2e/wiremock-config/

```sh
$ curl https://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/2.27.2/wiremock-standalone-2.27.2.jar --output wiremock-standalone.jar
```

* Check that wiremock-standalone.jar can be started
```sh
$ java -jar wiremock-standalone.jar --port 9000
```

* Check that you can access the server from the new terminal window or a browser
```sh
$ curl localhost:9000/api
```

* If everything is OK you should see the following message
```text
No response could be served as there are no stub mappings in this WireMock instance.
```

* Stop WireMock standalone by pressing `Control + c`

### Configure WireMock to serve predefined responses
WireMock can be configured to serve predefined responses via
* JSON over HTTP
* JSON configuration file

In this example, JSON configuration file is used.

When started, WireMock server creates two folders under the current one (e.g. wiremock-demo/e2e/wiremock-config), mappings and __files. Folders are only created if they don’t already exist and won’t be deleted when the WireMock instance is stopped.

To serve predefined response and validate they are working fine:
* Create a new `hello-world.json` file under mappings folder
* Add following content to `hello-world.json` file 
```json
{
    "request": {
        "method": "GET",
        "url": "/api/hello-world"
    },
    "response": {
        "status": 200,
        "body": "Hello World!"
    }
}
```
* Start previously stopped instance of WireMock standalone server
```sh
$ java -jar wiremock-standalone.jar --port 9000
```
* Validate that configured response is served
```sh
$ curl localhost:9000/api/hello-world
```
* If everything is OK you should see the following message ```json
Hello World!
```

### Configure Protractor to start WireMock before executing tests
Protractor provides a lot of configuration options. One of them is a `beforeLaunch()` callback function. It is executed only once, before tests are started. It’s main purpose is to bring up test dependencies.

To start WireMock standalone before tests are executed, update `protractor.conf.js` with following content
* Import function for spawning a new process
```js
const { spawn } = require('child_process')
```
* Start a WireMock standalone before executing tests 
```js
beforeLaunch: async function () {
    // spawns a new process 
    spawn(
      // the command to run
      'java',
      // list of string arguments
      ['-jar', './e2e/wiremock-config/wiremock-standalone.jar', '--port=9000'],
      // options is used to configure the pipes that are established between the parent and child process.
      { stdio: ['pipe', 'inherit', 'inherit']}
    );
```
* Additional check is needed to confirm WireMock server is ready to serve responses. Updated `beforeLaunch()` with following content (add after spawning a new WireMock process)
```js
for (let i = 0; i < 5; i++) {
      try {
        const response = await fetch('http://localhost:9000/__admin/mappings')
        if (response.ok) {
          const data = await response.json();
          console.log("mappings: ", data)
          break;
        } else {
          throw new HTTPResponseError(response);
        }
      } catch (error) {
        console.log(error);
        await delay(1000)
      }
    }
```
* Add `node-fetch` as a dependency
```js
npm i node-fetch --save
```
* Import fetch
```js
const fetch = require("node-fetch");
```
* Introduce a delay by adding following function to the end of the `protractor.conf.js`
```js
const delay = ms => new Promise(res => setTimeout(res, ms));
```

### Configure Protractor to stop WireMock after executing tests

Protractor provides another callback function `afterLaunch()` which is called only once, before the program exits. It is called after all tests have finished running and the WebDriver instance has been shut down.

Update `protractor.conf.js` to shut down WireMock standalone instance after tests are executed.

* Import function for synchronously spawning a new process
```js
const { spawnSync } = require('child_process')
```
* Stop WireMock standalone after tests are done and WebDriver is closed
```js
afterLaunch: function () {
    // spawns a new synchronous process
    // the function will not return until the child process has been fully closed
    spawnSync('sh', ['-c', 'lsof -t -i :9000 | xargs kill -9'])
  }
```


# Using Angular and WireMock (via Protractor)

Once WireMock is up and running, point you service to it (instead of the real back-end previously used). 

 **Potential problems**
* Cross-Origin Request Blocked which you can fix by adding `--enable-stub-cors` flag when starting WireMock. It enables automatic sending of cross-origin response headers.

# Conclusion
Testing at different levels is of crucial importance for the project success. It provides assurance that the application is working correctly and brings promised value. WireMock provides an excellent HTTP mock server that can be useful in integration and/or E2E tests.

**Sources**
* https://martinfowler.com/bliki/TestPyramid.html
* http://agiletesting.blogspot.com/2006/02/thoughts-on-giving-successful-talk.html
* https://www.symphonious.net/2015/04/30/making-end-to-end-tests-work/
* https://www.james-willett.com/the-evolution-of-the-testing-pyramid/
* https://www.subject-7.com/blog/2021/01/19/rethinking-the-testing-pyramid
* http://wiremock.org/docs/
* https://www.protractortest.org/
    Large scale Angular testing with Protractor | Andres Dominguez | BuzzJS Summer 2016
* https://github.com/angular/protractor
* https://www.selenium.dev/selenium/docs/api/javascript/index.html
* https://github.com/angular/protractor/blob/master/lib/config.ts
* https://jasmine.github.io/pages/getting_started.html
* https://nodejs.org/api/child_process.html#child_process_child_process
* https://github.com/node-fetch/node-fetch
* http://wiremock.org/docs/api/#tag/Stub-Mappings/paths/~1__admin~1mappings/get
* Photo by [Anders Jildén](https://unsplash.com/@andersjilden?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unsplash