Karate: unify cookie for api and ui tests

Created on 1 Oct 2020  路  11Comments  路  Source: intuit/karate

based on feedback, team wants to do hybrid tests and port all cookies from the API http-client to the UI tests

we potentially need the reverse as well. right now thinking that making the JSON the same should be good enough so they can be passed around. to investigate

enhancement fixed hacktoberfest

All 11 comments

@ptrthomas - as discussed, Pls assign this to me. Thank you.

@ptrthomas - can you pls help me with some of the requirements for this issue? From my very limited knowledge, the Http Client is used for API testing and you possibly have something similar for UI testing - is the goal to have same cookies apply to both http clients as well as UI frameworks? Currently the cookies can be set via header[Set-Cookie] or set in DSL as following:

And cookie foo = {value:'bar', max-age:'0', path:'/search'}

Is the goal to have a common DSL to make the cookie available both to Http Clients as well as UI?

Thank you for you help in advance, looking forward to working on it.

@chaudharydeepak no worries. first have a look at how cookies work for UI tests: https://github.com/intuit/karate/tree/master/karate-core#cookieset and there is an example of creating a UI cookie one at a time

so the requirement is a simple way to just take ALL HTTP client responseCookies and add them to the UI driver. today it has to be done manually using a loop

the driver has getCookies() but is missing a setCookies(List<Map>) - ideally this line should be possible

* driver.setCookies(responseCookies)
OR
* driver.cookies = responseCookies

what I am not sure is if responseCookies shape is ready for UI, and may need a little bit of testing

@ptrthomas Thank you - I will checkout all above details and update here in a few days.

@ptrthomas - spend sometime today - I think I got gist of basic requirement - made some changes and tested out with following test case -

Scenario: pass cookie from API call to UI call
  Given path 'search', 'cookies'
  And cookie foo = {value:'bar', path:'/search'}
  When method get
  Then status 200
  And match response == '#[1]'
  And match response[0] contains { name: 'foo', value: 'bar' }

  Given driver demoBaseUrl + '/search/cookies'
  * print responseCookies
  When setCookies(responseCookies)
  Then match driver.cookies == '#[1]'

Now, we can see the cookie set in API call is passed over to driver UI call.

  • as you had mentioned, wrote setCookies method for driver interfaces / implementations.
  • 1 think I noticed is - responseCookies is received as a Map by setCookies method - so as-is implementation fails, since the conversion engine expects boolean values inside the cookie map vs they all come as string. So I wrote a simple transformation for that.
  • few other minor things.

I am not done yet with this - the commits are in my repo at https://github.com/chaudharydeepak/karate/commit/7f70e216b3b2052e5bb5f3af9307281d0665c429

I plan on further refactoring and will keep you posted. Thank you.

@ptrthomas - today I spent sometime trying to reverse the hybrid test scenario - i.e. set cookie in UI call and then make that available to api call -

Scenario: pass cookie from a UI call to a certain API call
  Given driver demoBaseUrl + '/search/cookies'
  Given def cookie2 = { name: 'hello', value: 'world' }
  When cookie(cookie2)
  Then match driver.cookies contains '#(^cookie2)'

  Given path 'search', 'cookies'
  * cookies driver.cookies
  When method get
  Then status 200
  And match response == '#[1]'
  And match response[0] contains { name: 'hello', value: 'world' }

Now, frankly I struggled a bit with coming up with a clean way to set driver.cookies to cookies for API call :). So instead, I wrote a bit of hack to deserialize driver.cookies [ which is a list of multiple cookies set in UI calls ] inside cookies method as following -

public void cookies(String expr) {
    if ( expr.trim().equalsIgnoreCase("driver.cookies"))
    {
      ScriptValue scriptValue = eval("driver.cookies");
      List<Map> mapList = scriptValue.getAsList();
      mapList.forEach( currCookieSet ->
     {
       Cookie cookie = new Cookie(String.valueOf(currCookieSet.get("name")),String.valueOf(currCookieSet.get("value")));
       request.setCookie(cookie);
     });
    }

so overall this is working.

Can you pls share any pointers / guidance around this scenario? I am thinking there is an easy way out already there before we try anything complex. Thank you.

@chaudharydeepak driver.cookies which is the same as driver.getCookies() should already return a List<Map> right - I thought it would "just work"

@ptrthomas Yeah it returns that - though because the way public void cookies(String expr) is currently written, it ends up throwing exception because of this line Map<String,Object> map = evalMapExpr(expr); - tries to evaluate the expression to a map vs its a list of map. https://github.com/chaudharydeepak/karate/blob/master/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java#L657

@chaudharydeepak ah I got it. okay, you can do a conditional, does this help ? you can do this inside void cookies(expr)

        ScriptValue value = Script.evalKarateExpression(expr, this);
        if (value.isMapLike()) {

        } else if (value.isListLike()) {
        }

@ptrthomas - yup, i took care of that already as exactly you mentioned - removed the hard-coded text etc 馃憤 ! will do some more testing / validations and push this for your review. Thank you.

I think this works now, here is the new, improved test-suite: https://github.com/intuit/karate/blob/develop/karate-e2e-tests/src/test/java/driver/04.feature

Was this page helpful?
0 / 5 - 0 ratings