• bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
  • bids: 0 +10
  • bidders: 0 +10
  • completed auctions: 0 +10
  • next fall of the hammer: 0 ending now
  • sold lots: 0 +10
Job openings (3)

03.05.2021

Smoke Testing with Jest and GraphQL

One important capability in our QA strategy is to run smoke tests against remote service endpoints, to check that they are healthy. In this article, we share our approach, walking you through some examples.

written by Tatjana Statescu

When it comes to implementing our QA strategy, one important capability is our ability to run smoke tests against remote service endpoints, to check that they are healthy. This provides us quick feedback after each deployment.

We implement our health checks as GraphQL endpoints, and we use Jest to test them from a CI/CD pipeline. In this article, we share our approach, walking you through some examples.

Why Jest?

Jest is a JavaScript testing framework that focuses on simplicity. Our Unit tests are also written in Jest, so it is easy to write and maintain API tests in the same format.

Setting up Jest

First of all, let’s install Jest:

                npm install --save-dev jest
            

To run tests easily and control the configuration, we create a jest.config.js file. It is possible to use the Jest command line runner and pass options as flags, but for convenience reasons Jest allows to use configuration file in JSON, TypeScript, and JavaScript format.

Here is our Jest config:

jest.config.js
                module.exports = {
  testEnvironment: "node",
  runner: "groups",
  reporters:  ["default", "jest-junit"],
  extraGlobals: [],
  testTimeout: 10000,
};
            

We use “groups” test runner. it allows us to use tags in the tests and execute specific groups of tests with Jest.

Since we want to have a possibility to see individual test results, which can be also interpreted by our CI/CD pipeline we use jest-junit which produces a JUnit format result file.

We add a shortcut script to execute smoke tests to the package.json file:

package.json
                {
.
.
.
"scripts": {
    "test": "jest",
    "test-smoke": "jest --group=smoke",
  },
.
.
.
}
            

The health check test

First to make it clearer what we are talking about here’s an approximate architecture that we are testing:

Here, we have two API Gateway services that are in front of two business services. The API Gateways provide a specific API for a particular use case, and the business services give general functionality. We need to ensure that the entire API a Facade service gives is available.

Let’s create a test folder and the test case:

                mkdir tests
cd tests
            

We also need to install Axios HTTP client to allow performing HTTP requests:

                npm install axios
            

And to make requests to the GraphQL server we need a GraphQL client, for that let’s install apollo-boost:

                npm install apollo-boost graphql cross-fetch
            

And finally the test case. The example given illustrates a microservice architecture with API Gateways in front of the various services:

tests/healthcheck.test.js
                import axios from 'axios'
import 'cross-fetch/polyfill';
import { getGraphQLClient } from './utils/getGQLClient';
import { getBaseUrl, getAPIGatewayDNSUrl } from './utils/environment'
import { SERVICE2_HEALTHCHECK } from './fixtures-healthcheck'
 
axios.defaults.adapter = require('axios/lib/adapters/http')
 
let url
 
beforeAll( async () => {
    url = {
        base: {},
        APIGatewayDNS: {}
    }  
    url["base"]["postcode-lookup"] = await getBaseUrl('postcode-lookup')
    url["base"]["vat-validator"] = await getBaseUrl('vat-validator')
    url["APIGatewayDNS"]["postcode-lookup"] = url["base"]["postcode-lookup"]
    url["APIGatewayDNS"]["vat-validator"] = await getAPIGatewayDNSUrl('vat-validator')
});
 
/**
 * System smoke tests
 * @group smoke
 */
describe('Tests health check endpoints', () => {
    it.each(['postcode-lookup', 'vat-validator'])('should receive OK from service 1 through %s API Gateway', async (module) => {  
        const response = await axios.get( url.base[module] + '/api/v1/healthcheck')
          .catch(function (error) {
            console.log(error);
          });
          expect(response.status).toBe(200);
          expect(response.data.healthy).toBeTruthy;
        });
    it.each(['postcode-lookup', 'vat-validator'])('should receive OK from %s API Gateway', async (module) => {  
        const response = await axios.get( url.APIGatewayDNS[module] + '/healthcheck')
            .catch(function (error) {
            console.log(error);
            });
            expect(response.status).toBe(200);
            expect(response.data.healthy).toBeTruthy;
        });
    it.each(['postcode-lookup', 'vat-validator'])('should should receive OK from service 2 through %s API Gateway', async (module) => {  
        const client = getGraphQLClient(url.APIGatewayDNS[module] + '/'); 
        const response = await client.query({
            query: SERVICE2_HEALTHCHECK }
            );
            expect(response.data.healthcheck.healthy).toBeTruthy;
        });   
});
            

Some explanations on the code:

                it.each
            

is a great solution for data-driven tests, it allows us to write the test once and pass data in.

In the first test, we make simple GET calls to the /healthcheck endpoints of ‘service 1’. The request goes through both API Gateways to make sure the connection between the API Gateways and the service is also working. We use Axios HTTP client that allows us to make an HTTP request with node.js.

In the second test, we make GET calls to the /healthcheck endpoints of ‘postcode-lookup’ API Gateway and ‘vat-validator’ API Gateway endpoints.

In the third test, we make a GraphQL request using ApolloClient to test both API Gateway connection to ‘service 2’ and the health of ‘service 2’.

Here is how we set it up ApolloClient:

getGQLClient.js
                import ApolloClient from 'apollo-boost';
 
export const getGraphQLClient = (baseUrl) => {
  return new ApolloClient({
    uri: baseUrl + 'graphql',
    request: (operation) => {
      operation.setContext({
        timeout: 20000
      })
    },
    onError: (e) => { console.log(e) },
  });
}
            

Running smoke tests

To run tests just execute

                npm run test-smoke
            

And here is the result:

Article by
Tatjana Statescu

Tatjana is QA lead at AURENA Tech. “The only thing better than finding a bug early is preventing it entirely”: With this in mind, Tatjana makes sure that quality is built into all development stages.

More articles

04.03.2024

AURENA Tech Winter Games 2024

Having successfully found snow and ice, we spent a fun day together in the Styrian mountains.

08.01.2024

AURENA Tech welcomes new team members

We are happy to welcome two new colleagues to our engineering team: Frontend Lead Patrick Niebrzydowski and Senior Frontend Engineer Dmytro Barylo.

28.12.2023

AURENA celebrates milestone with 200,000 bidders

Andrea Brezina was the lucky one to register as our 200,000th bidder - AURENA welcomes her with a gift voucher just before Christmas.

20.10.2023

Meet our Backend Lead Christian Prohinig

After working for companies like Bitpanda and Dynatrace, Christian Prohinig now joins the engineering team of AURENA Tech as Backend Lead.

22.08.2023

AURENA Tech Team Event 2023

Amazing weather, amazing locations, and – most importantly – amazing people: Two days of culinary delights, adventure, and relaxation in Austria.

Open positions

AURENA.tech
text
Senior Node.js Developer (f/m/x)

This role offers you the opportunity to lead middleware and microservice development at AURENA Tech.

  • Leoben or fully remote
  • Fulltime, permanent
  • Starts at € 69,300 p.a.
AURENA.tech
text
CI/CD Automation Engineer (f/m/x)

In this role you will design and maintain CI/CD pipelines, manage Docker containers and support the team with test automation.

  • Leoben or fully remote
  • Fulltime, permanent
  • Starts at € 51,800 p.a.
AURENA.tech
text
Senior Cloud Engineer AWS (f/m/x)

In this role you will design, develop and maintain AWS infrastructure with Terraform and manage our Kubernetes clusters.

  • Leoben or fully remote
  • Fulltime, permanent
  • Starts at € 69,300 p.a.