3

I have a little tricky requirement in Karate. I have a set of baseURL's in my karate.config which are chosen based on the implementation. Here is the snippet of it:

 if (env == 'qa') {
  config.apiKey = apiKey;
  config.tsp_api = 'https://api.qa.tceu.net';
  config.svt_dcm = 'https://svt.qa.tceu.net';
  config.acn_dcm = 'https://acn.qa.tceu.net';
  config.sos_dcm = 'https://sos.qa.tceu.net';
  config.cust_dcm = 'https://cust.qa.tceu.net';

Here tsp,svt,acn,sos,cust are some actions.

I have a feature file which passes the action as a parameter:

# Vehicle Initiates the action
 When def Perform_Report_Notification = call read('./../common/performActionNotification.feature') { action: '#(action)' } 

In the called performActionNotification.feature, I need to pick up the url from the karate.config file based on the action that is passed. For example if the action is sos, then the url should be sos_dcm. If the action is svt then the url should be svt_dcm

Here is the snippet from performActionNotification.feature and what I am currently doing for sos:

Given url sos_dcm
And path '/AU/v1.0/TSP/'+ action
And request RequestPayload
When method post
Then status 200

I want to implement something like an if then else similar to:

if (action == 'sos') 
then myurl == 'sos_dcm'
else if (action == 'acn')
then myurl == 'acn_dcm'
else if (action == 'svt')
then myurl == 'svt_dcm'

Given url myurl
And...
And...
...

I tried a sort of a hack and it works but its not a clean way of doing it. Instead of reading the URL from karate.config I am hardcoding it this way:

Given url 'https://'+act+'.qa.tceu.net'

One more thing I tried was

* def myurl = action +'_dcm' #so if action is acn then the variable myurl would be acn_dcm
Given url myurl 
...
....

But this hardcodes the url as 'acn_dcm' instead of picking the defined url up from karate.config.

Can someone kindly suggest the best way to implement this?

Mihir
  • 491
  • 5
  • 21
  • Honestly, not sure this is worth the effort. If you use a variable for the one part of your url that is changing, you still have to set it somewhere. – anutter Dec 03 '19 at 17:29

4 Answers4

4

Here is a hint. JSON is actually a pretty useful data-structure (think hash-map or dictionary) and you can lookup a value without needing an if statement.

* def data =
"""
{
  qa: {
     sos: 'https://sos.qa.tceu.net',
     acn: 'https://acn.qa.tceu.net'  
  }  
}
"""
* def env = 'qa'
* def urls = data[env]
* def action = 'sos'
* def actionUrl = urls[action]
* match actionUrl == 'https://sos.qa.tceu.net'

This should get you on your way :)

EDIT - also see this: https://stackoverflow.com/a/67868935/143475

Peter Thomas
  • 54,465
  • 21
  • 84
  • 248
  • Thanks @Peter for this. Is there a way I can match the actionUrl from the karate.config file. The reason is I want to have all the end points defined in the config file. Should any end point change, I want to avoid the situation of making changes in the feature of js files. Instead of having these URLs, can we have something like : match actionUrl == sos_dcm and this value comes from karate.config? – Mihir Dec 04 '19 at 11:31
  • 'I want to avoid the situation of making changes in the feature *of* js files ' corrected to 'I want to avoid the situation of making changes in the feature *or* js files' in the above – Mihir Dec 04 '19 at 11:44
  • @Mihir sorry you lost me. can you give an example in Java or JS of what you are trying. Karate can’t do any “magic”. If you can’t do what you want in a programming language - quite likely you can’t in karate :) – Peter Thomas Dec 04 '19 at 11:55
  • 1
    @Mihir and please note - `actionUrl` can very well come from the config if it is defined - like a global variable. what else do you need !? – Peter Thomas Dec 04 '19 at 12:01
  • 1
    I wrote a comment and deleted it as your explanation above answers it. Thanks @Peter – Mihir Dec 04 '19 at 12:08
3

I've finally used Peter's most elegant solution and it works like a charm!

Here's what I've finally implemented that does not need hardcoding of the endpoint URL's and is driven by endpoints in the karate.config file.

  * def data =
        """
        {
        qa: {
                    sos: '#(sos_dcm)', # sos_dcm endpoint defined in karate.config file
                    acn: '#(acn_dcm)',
                    svt: '#(svt_dcm)' 
                }  
        }
        """
        * def env = karate.properties['env']; # Driven by maven commandline arg -Denv=qa as an example
        * def urls = data[env]
        * def action = act  # act comes from the calling feature file and has values - sos/acn/svt
        * def myUrl = urls[action]

        Given url myUrl
        ...
        ...
Mihir
  • 491
  • 5
  • 21
2

I would suggest looking into using javascript for your conditional logic

So the javascript function takes a param of action and then the if and else statements returns the variable of the url that you need.

Perform the javascript function before you make the request call. and use the variable that is returned by js to determine the logic.

make that js file a common function that can be accessed by multiple feature files.

function determineUrl(action) {
  var url = "${urDefaultUrl}";
  if (action == "sos") url == "${full url}";
  else if (action == "acn") url == "${full url}";
  return url;
}

Then in your feature file

 * def urlDecider = 'classpath to your js function'
 * myUrl = urlDecider(action)
 * url myUrl
 * Given path .... 
Jawad Kalia
  • 286
  • 2
  • 16
  • do not use ur config file anymore. – Jawad Kalia Dec 03 '19 at 17:47
  • Thanks @Jawad. This is a nice solution too. but is there a way we can drive the full url coming from karate.config? The reason as explained above for Peter's solution too is the fact that should the end point change, we need to make changes in all the files we are declaring them. If it could be driven by karate.config file alone, this avoids us having to maintain the urls. – Mihir Dec 04 '19 at 11:34
1

For the sake of the community learning, there is one other way I figured out on similar lines of Jawad's solution is using a Java function. They do exactly the same thing as Jawad's solution but just that its a java class doing it. If a project has java class files, then to maintain consistency this solution can be used too.

Here is the how the class file looks:

public class DCMUrlDecider {

    static String dcmURL="";
    public static String getDCMUrl(String action) {
        if (action.matches("sos")) 
            { 
            dcmURL = "https://sos.qa.tceu.net";
            }
          else if (action.matches("acn")) 
              {
              dcmURL = "https://acn.qa.tceu.net";
              }
          else if (action.matches("svt")) 
              {
              dcmURL = "https://svt.qa.tceu.net";
              }

        return dcmURL;

    }
}

And here is the associated code snippet from the feature file:

 * def dcmURLDecider = Java.type('com.TCEU.KarateTests.DCMUrlDecider')  
 * def myUrl = dcmURLDecider.getDCMUrl(act)

 Given url myUrl
 ....
 .....

Once again this means we are still hardcoding URLs in the java class files. Need to learn a way of doing it via karate.config files if possible.

Mihir
  • 491
  • 5
  • 21