karatekid5088
karatekid5088

Reputation: 81

Karate - custom assertion in expected JSON schema

I'm looking to perform custom assertions on fields in JSON loaded from file.

I understand that we have fuzzy matching, but I'd like to perform something more custom e.g. have a function which parses a date as a LocalDateTime:

public class DateUtil {
public static boolean matchesMyDateFormat(String dateStr) {
    try {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        LocalDateTime.parse(dateStr, formatter);
    } catch (DateTimeParseException e) {
        return false;
    }
    return true;
}

}

This would be called by the following:

* def matchesMyDateFormat =
"""
function fn(dateX){
  return Java.type('com.karate.DateUtil').matchesMyDateFormat(dateX);
}
"""

* def expected = read('expected.json')
* def actual = read('actual.json')
* match expected == actual

Where expected.json looks like this:

{
   "date1" : "#? matchesMyDateFormat(_)"
}

NB this is specifically for JSON loaded from file and not on JSON which is specified in the feature file itself (e.g. like for isValidTime() here: https://github.com/intuit/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/schema-like.feature).

Few reasons for wishing to do it this way:

NB: I've read through the docs and the other SO answers related to date assertions and believe this is a slightly different ask.

Is the above possible to do in Karate at the moment?

Upvotes: 3

Views: 1219

Answers (2)

karatekid5088
karatekid5088

Reputation: 81

What I was trying was in fact a valid use-case (as is the alternative solution kindly suggested by Peter Thomas in his answer).

The reason my particular variation wasn't working was this error:

07:22:50.421 assertion failed: path: $.date1, actual: '#? matchesMyDateFormat(_)', expected: '2020-06-10T14:44:57.060Z', reason: not equal

I noticed with a fresh pair of eyes that I should flip the match statement from:

* match expected == actual

To:

* match actual == expected

This way is required in order for Karate to work its magic and call the custom function in expected.json.

Upvotes: 2

Peter Thomas
Peter Thomas

Reputation: 58058

You can add functions in karate-config.js which will be "global". For example:

var config = {};
config.isValidDate = read('classpath:is-valid-date.js');
return config;

Now you can use isValidDate(_) in any feature. Note that JS functions can take multiple arguments, e.g:

* match foo == { bar: "#? isValidDate(_, 'MYFORMAT')" }

In 0.9.6.RC4 we made improvements so that you can move complex conditional logic and even match operations into re-usable JS files: https://github.com/intuit/karate/issues/1202

Be warned, doing a lot of this may lead to un-readable tests: https://stackoverflow.com/a/54126724/143475

One hint, you can use karate.forEach() to extract all date-fields into an array and then a single match each may work.

Finally, if you still feel there is "too much code in your feature files", I don't know, maybe you need to consult a magician.

Upvotes: 2

Related Questions