1

I am trying to write JSON schema for the below response. The response is dynamic it can be a person details or organization details. If the customerType in the response is person, then the response will contain person object (organization object will not be available). If the customerType is org, organization details will be included in the response (person object will not be available). Two different flavors of the expected response is given below

{
    "customerType" : "person",
    "person" : {
        "fistName" : "A",
        "lastName" : "B"
    },
    "id" : 1,
    "requestDate" : "2021-11-11"
}

{
    "customerType" : "org",
    "organization" : {
        "orgName" : "A",
        "orgAddress" : "B"
    },
    "id" : 2,
    "requestDate" : "2021-11-11"
}

I am trying to valid the above condition using the schema as given below

{
    "customerType" : "#string",
    "organization" : "#? karate.match(response.customerType, 'org').pass ? karate.match(_, organizationSchema).pass : true)",
    "person" : "#? karate.match(response.customerType, 'person').pass ? karate.match(_, personSchema).pass : true"),
    "id" : "#number",
    "requestDate" : "#string"
}

The problem I am currently facing is that, if customerType in the response is person, it throws below error

all key-values did not match, expected has un-matched keys: [organization]

Is there any way I can specify in the schema that if person object is available, organization object will not be available and vice versa

stackoverflow
  • 2,134
  • 3
  • 19
  • 35

1 Answers1

1

If you insist on doing this in one "single" schema, then Karate is not the tool for you. Otherwise, read on.

Karate encourages re-use of schema "chunks". Here are two possible solutions to your requirement. I hope you do more reading on how you can embed JS inside Karate script, and manipulate JSON before doing a match, there are even ways to "merge" JSON using karate.merge() if you really get fancy. You don't need to always do "exact" matches, sometimes contains gets the job done just fine.

* def personSchema = { firstName: '#string', lastName: '#string' }
* def orgSchema = { orgName: '#string', orgAddress: '#string' }
* def schema = { customerType: '#string', id: '#number' }

* def response1 = { customerType: 'person', person: { firstName: 'Foo', lastName: 'Bar' }, id: 1 }
* match response1 contains schema
* def extra = response1.person ? { person: '#(personSchema)' } : { organization: '#(orgSchema)' }
* match response1 contains extra

* def response2 = { customerType: 'org', organization: { orgName: 'Foo', orgAddress: 'Bar' }, id: 2 }
* if (response2.person) schema.person = personSchema; else schema.organization = orgSchema
* match response2 == schema

All that said, I strongly discourage "clever" tests like this, it just leads to maintainability issues. Please just stick to plain-vanilla scenarios as far as possible and set up your test / request so that you 100% know what the response is going to be. Please take some time and read this: https://stackoverflow.com/a/50350442/143475

Peter Thomas
  • 54,465
  • 21
  • 84
  • 248