Karate Series | Session 6 | Karate Config

What we explore in this series

Karate Basics
GET API
POST API
PUT API
DELETE API

Karate Config
Karate Reports

Karate config is nothing but a javascript function that returns a JSON object. The config file should be named karate-config.js and placed under classpath (src/test/java). At the time of startup, Karate will search for the config file in the classpath and read the configurations automatically.

The config file plays a crucial role in the application. It can be used to store global variables, set URLs, headers, authentication details, etc. It can also be used to define environments and the values of the variables can be dynamically changed based on the running environment.

The karate-config.js will be re-processed for every scenario. We can change this behavior by calling karate.callSingle() function.

A sample file is given below.

function fn() {
    var config = {
        author: 'Deepesh Darshan',
        baseURL: 'https://reqres.in/api'
    };

    var env = karate.env;
    karate.log('Given Env: ', env);
    if (env == 'dev') {
        config.baseURL = 'https://reqres.in/dev/api'
    } else if (env == 'prod') {
        config.baseURL = 'https://reqres.in/prod/api'
    } else if (env == 'local') {
        config.baseURL = 'https://reqres.in/api'
    }

    karate.configure('connectTimeout', 5000);
    karate.configure('readTimeout', 5000);
    return config;
}

Here, the baseURL is set as https://reqres.in/api. We can dynamically change the value of this variable based on the current running environment. We can set configuation settings like connectTimeout and readTimeout in the config file. We can also configure proxy settings, headers, cookies, etc in the config file.

The environment can be defined either in the TestRunner.java or by the maven command line, and it will be taken on runtime by the Karate.

// Java configuration
System.setProperty("karate.env", "local");

//mvn command line
mvn test -DargLine="-Dkarate.env=prod"

Now let’s go through different scenarios.

Scenario 1

Accessing config file value

  #Accessing config file value
  Scenario: Config Author Demo
    Given print author

We’ve already defined a global variable namely author and set its value ‘Deepesh Darshan‘ in karate-config.js. Karate will automatically read the config file and read the variable. So in the feature file, we can directly access the variable.

See the output of the above scenario:

17:16:43.553 [pool-1-thread-1] INFO com.intuit.karate - found scenario at line: 8 - ^Config Author Demo$
17:16:43.702 [ForkJoinPool-1-worker-1] INFO com.intuit.karate - Given Env:   
17:16:43.755 [ForkJoinPool-1-worker-1] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $
17:16:43.775 [ForkJoinPool-1-worker-1] INFO com.intuit.karate - [print] Deepesh Darshan

Scenario 2

Accessing config file and calling GET API

Feature: Config Demo  

  Background:
    * url baseURL
    * header Accept = 'application/json'

  #Get request with config file value
  Scenario: Config Get Demo 1
    Given path '/users?page=2'
    When method GET
    Then status 200
    And print response

The baseURL, declared in the background, will get its value from the config file (it will take the default value, as the environment is not yet set), and using this we can run the scenario. Please note, in the given scenario, we never defined or declared any URLs, but still, it will call the GET API. The output of the scenario is given below:

17:20:57.082 [ForkJoinPool-1-worker-1] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $
17:20:57.083 [ForkJoinPool-1-worker-1] INFO com.intuit.karate - [print] {
  "per_page": 6,
  "total": 12,
  "data": [
    {
      "color": "#98B2D1",
      "year": 2000,
      "name": "cerulean",
      "id": 1,
      "pantone_value": "15-4020"
    },
    {
      "color": "#C74375",
      "year": 2001,
      "name": "fuchsia rose",
      "id": 2,
      "pantone_value": "17-2031"
    },
    {
      "color": "#BF1932",
      "year": 2002,
      "name": "true red",
      "id": 3,
      "pantone_value": "19-1664"
    },
    {
      "color": "#7BC4C4",
      "year": 2003,
      "name": "aqua sky",
      "id": 4,
      "pantone_value": "14-4811"
    },
    {
      "color": "#E2583E",
      "year": 2004,
      "name": "tigerlily",
      "id": 5,
      "pantone_value": "17-1456"
    },
    {
      "color": "#53B0AE",
      "year": 2005,
      "name": "blue turquoise",
      "id": 6,
      "pantone_value": "15-5217"
    }
  ],
  "page": 1,
  "total_pages": 2,
  "support": {
    "text": "To keep ReqRes free, contributions towards server costs are appreciated!",
    "url": "https://reqres.in/#support-heading"
  }
}

Scenario 3

Calling a java method

In Karate, we can directly call java functions also. Here in this scenario, we have created a simple java class namely BdayWishHelper.java, and written a public method namely wish inside it. The method will accept a parameter of type string and return some string value.

package com.example.karate.helper;

public class BdayWishHelper {

    public String wish(final String name) {
        return "Happy Birthday " + name;
    }

}

We will call this method from the scenario and print the response.

  Scenario: Calling Java Method
    * def wishHelper =
    """
    function() {
      var Helper = Java.type('com.example.karate.helper.BdayWishHelper');
      var helperInstance = new Helper();
      return helperInstance.wish('Sourav');
    }
    """
    * def wish = call wishHelper
    * print wish

And, here’s the response:

18:05:38.136 [pool-1-thread-1] INFO com.intuit.karate - found scenario at line: 18 - ^Calling Java Method$
18:05:38.263 [ForkJoinPool-1-worker-1] INFO com.intuit.karate - Given Env:   
18:05:38.318 [ForkJoinPool-1-worker-1] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $
18:05:38.356 [ForkJoinPool-1-worker-1] INFO com.intuit.karate - [print] Happy Birthday Sourav

Scenario 4

Calling a Springboot endpoint

There’s nothing special in it as calling a REST endpoint has already been covered in one of the previous posts. The only change here is, we’ve created our own endpoint using Springboot this time and called it from Karate. So let’s see the GET endpoint.

KarateController.java

package com.example.karate.controller;

import com.example.karate.service.KarateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    private KarateService service;

    @Autowired
    private KarateController(KarateService service) {
        this.service = service;
    }

    @RequestMapping("/hello/{name}")
    public String hello(@PathVariable String name) {
        return service.hello(name);
    }
}

KarateService.java

package com.example.karate.service;

public interface KarateService {
    public String hello(final String name);
}

KarateServiceImpl.java

package com.example.karate.service;

import org.springframework.stereotype.Service;

@Service("karateService")
public class KarateServiceImpl implements KarateService {

    @Override
    public String hello(final String name) {
        return "Hello "+name;
    }
}

So, this endpoint does nothing but accepts an input parameter of type string and returns some string value. This is how we call this endpoint from Karate.

    Scenario: Springboot
      Given url 'http://localhost:8050/api/hello/Sachin'
      When method GET
      Then status 200
      And print response

And, here’s the response:

18:20:44.569 [ForkJoinPool-1-worker-1] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {}->http://localhost:8050][total available: 1; route allocated: 1 of 5; total allocated: 1 of 10]
18:20:44.569 [ForkJoinPool-1-worker-1] DEBUG com.intuit.karate - response time in milliseconds: 118.72
1 < 200
1 < Connection: keep-alive
1 < Content-Length: 12
1 < Content-Type: application/json
1 < Date: Tue, 15 Nov 2022 12:50:44 GMT
1 < Keep-Alive: timeout=60
Hello Sachin

Here’s the full feature file.

Feature: Config Demo

  Background:
    * url baseURL
    * header Accept = 'application/json'

  #Accessing config file value
  Scenario: Config Author Demo
    Given print author

  #Get request with config file value
  Scenario: Config Get Demo 1
    Given path '/users?page=2'
    When method GET
    Then status 200
    And print response

  Scenario: Calling Java Method
    * def wishHelper =
    """
    function() {
      var Helper = Java.type('com.example.karate.helper.BdayWishHelper');
      var helperInstance = new Helper();
      return helperInstance.wish('Sourav');
    }
    """
    * def wish = call wishHelper
    * print wish

    Scenario: Springboot
      Given url 'http://localhost:8050/api/hello/Sachin'
      When method GET
      Then status 200
      And print response

In this session, we’ve seen how to write config and make use of it in Karate. That’s all for now. Thank you!