Original post with additional details available at: 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
$ 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/
$ 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
$ java -jar wiremock-standalone.jar --port 9000
- Check that you can access the server from the new terminal window or a browser
$ curl localhost:9000/api
- If everything is OK you should see the following message
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
{
"request": {
"method": "GET",
"url": "/api/hello-world"
},
"response": {
"status": 200,
"body": "Hello World!"
}
}
- Start previously stopped instance of WireMock standalone server
$ java -jar wiremock-standalone.jar --port 9000
- Validate that configured response is served
$ 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
const { spawn } = require('child_process')
- Start a WireMock standalone before executing tests
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)
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
npm i node-fetch --save
- Import fetch
const fetch = require("node-fetch");
- Introduce a delay by adding following function to the end of the
protractor.conf.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
const { spawnSync } = require('child_process')
- Stop WireMock standalone after tests are done and WebDriver is closed
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 on Unsplash
Top comments (0)