vlucas / frisby

Frisby is a REST API testing framework built on Jest that makes testing API endpoints easy, fast, and fun.
http://frisbyjs.com
1.53k stars 201 forks source link

Loop through JSON object in Expect()? #579

Closed Cenric closed 2 years ago

Cenric commented 2 years ago

Basically, I have two identically structured objects and am trying to expect exact values based off a json object that is structured like

"object": [
     {
          "key": "value"
     },
     {
          "key": "value"
     }
]

I am using the statement

.expect('json', 'object.*', { 'key': json.object[0].key })

but this only works for matching the first object in the array and not the rest if i want each object to all have matching keys. I can loop through the expect json fine, but not the other json object to match the two values. Any idea what I can do here?

H1Gdev commented 2 years ago

Looks like it's working.

const frisby = require('frisby');

it('issue 579.', () => {
  let json = {
    "object": [
      {
        "key": "value"
      },
      {
        "key": "value2"
      }
    ]
  };
  return frisby.fromJSON(json)
    .expect('json', 'object.*', { 'key': json.object[0].key });
});

AssertionError [ERR_ASSERTION]: Response [ {"key":"value2"} ] does not contain provided JSON [ {"key":"value"} ]

What kind of result do you expect ?

Cenric commented 2 years ago

Sorry, maybe wasn't being clear enough. To clarify, there are two data structures here - the results, and the json that I am trying to match the results to. Instead of json.object[0].key I am trying to do something like json.object[*].key to traverse through my json and match the "object.*" result one by one, side by side with my json. But can't find a way to loop through my json the same way I am looping through my result with "object.*"

H1Gdev commented 2 years ago

I'm not sure about the data structure...

Does it mean that arrays of object are in no particular order ?

If so, you need to use an advanced validator such as Joi.

Cenric commented 2 years ago

Let me give a better example - I have a json file such as

let json = {
    "compareList": [
      {
        "key": "value"
      },
      {
        "key": "value2"
      }
    ]
  };

and then in my post call that returns another json object, the structure is

"object": [
      {
        "key": "value"
      },
      {
        "key": "value2"
      }
    ]
  };

I want to compare the two, so the expect would look something like: .expect('json', 'object.*', { 'key': json.compareList[0].key });

I am trying to make sure that my original json list. compareList, matches exactly what the POST call is returning which is object. So as I am expecting and traversing through the object with object.*, I also want to traverse through my compareList side by side and make sure that object[0] == compareList[0], etc.

Sorry if this is confusing, been a long day :(

H1Gdev commented 2 years ago

Does this meet your expectations ?

it('issue 579 (2).', () => {
  let json = {
    "compareList": [
      {
        "key": "value"
      },
      {
        "key": "value2"
      }
    ]
  };
  let res = {
    "object": [
      {
        "key": "value"
      },
      {
        "key": "value2"
      }
    ]
  };
  return frisby.fromJSON(res)
    .expect('jsonStrict', 'object', json.compareList); // use jsonStrict
});
Cenric commented 2 years ago

Ah yes that helps a lot, now what if there were two keys in each object and I only wanted to compare the second key?

let json = {
    "compareList": [
      {
        "key": "value",
        "key2": "value2"
      },
      {
        "key": "value",
        "key2": "value2"
      }
    ]
  };

I tried .expect('jsonStrict', 'object.key2', json.compareList.key2); but didn't work

H1Gdev commented 2 years ago
  1. All key2 values are the same.
    .expect('jsonStrict', 'object.*.key2', 'value2');
  2. All key2 values contain the same value.
    .expect('json', 'object.*.key2', /^value/);
  3. key2 values depend on index.
    .expect('jsonStrict', 'object[0].key2', 'value0')
    .expect('jsonStrict', 'object[1].key2', 'value1');
  4. All key2 values matche one of list.
    .expect('json', 'object.*.key2', ['value0', 'value1', 'value2']);
Cenric commented 2 years ago

Thank you so much!

Cenric commented 2 years ago

@H1Gdev Hello, sorry, ran into another problem - I have real data this time. My data structure is

"keywords": [
            {
                "contentKey": "56765868574",
                "keyword": "hellokeywords"
            },
            {
                "contentKey": "123214556765765",
                "keyword": "newTestValue"
            },
            {
                "contentKey": "123129312948198",
                "keyword": "sundaykey"
            }
        ],

and as per suggested I have tried using .expect('json', 'keywords.?.keyword', ['hellokeywords','newTestValue','sundaykey']) or .expect('json', 'keywords.*.keyword', ['hellokeywords','newTestValue','sundaykey'])

but I keep getting Response [ "sundaykey" ] does not contain provided JSON [ ["hellokeywords","newTestValue","sundaykey"] ]

H1Gdev commented 2 years ago

I misunderstood how to use Array... I think regex is appropriate for this case.

.expect('json', 'keywords.*.keyword', /^hellokeywords$|^newTestValue$|^sundaykey$/)
H1Gdev commented 2 years ago

FYI

Array is used when checking in no particular order as follows.

it('JSON Array', () => {
  let json = ['a', 'b', 'c'];
  return frisby.fromJSON(json)
    .expect('json', ['c', 'a', 'b']);
});
Cenric commented 2 years ago

That did the trick. Thank you for being as helpful as always!