Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: arrayContaining Matcher and the dynamic JSON keys. #108

Open
StasMarynych opened this issue Jul 20, 2023 · 7 comments
Open

Question: arrayContaining Matcher and the dynamic JSON keys. #108

StasMarynych opened this issue Jul 20, 2023 · 7 comments
Labels
question Further information is requested

Comments

@StasMarynych
Copy link

StasMarynych commented Jul 20, 2023

❔ Question

Are there any possibility to define the expected response in case of dynamic JSON keys (set of the different JSON objects)? For example something like arrayContaining in pact-js.

πŸ’¬ Context

The main problem is that the dynamic JSON objects are located in the array, so there can be more than 1 different object in the array. There is a predefined set of the possible objects, so if there are no any limitations I would consider implementing same matcher as in pact-js version. (I'd love to help with that or v4 specification implementation.)

JSON Sample

{
  "items": [
    {
      "id": "some-id1",
      "config": { 
        "foo": "true"
      }
    },
    {
      "id": "some-id2",
      "config": {
        "bar": { ... }
      }
    },
    {
      "id": "some-id3",
      "config": { 
        "baz": 100 
       }
    }
  ]
}

Notes:
By the way, there is an option to test such objects one by one (1 object in the array per test) using the provider state, but the main idea is to test the composition of such objects.

🀝 Relationships

Looks like in v4 specification combine operators could be used, so that will solve the issue as well.

@StasMarynych StasMarynych added the question Further information is requested label Jul 20, 2023
@StasMarynych
Copy link
Author

Just noticed that arrayContaining method is implemented in v3, are there any chances that we could easily add that matcher without v4 ?

@StasMarynych
Copy link
Author

StasMarynych commented Jul 23, 2023

I was able to implement some sort of arrayContains matcher in my fork. Response generation is ok, and also i tried to add matching rule by doing this:

processedMatcherValue.rules[${node_with_array_contains}] = AnyEncodable([
	"matchers": [
		"match": AnyEncodable("arrayContains"),
		"variants": AnyEncodable(${all_processed_variants})
	]
])

but arrayContains matching rules wont appear in output pact contact in case of the tests with mock server. (Encoding logic looks fine in PactBuilderTests)

PactBuilderTests:

let testBody: Any = [
	"data": [
		"foo": Matcher.ContainsLike([
			[
				"bar": Matcher.SomethingLike("string1")
			],
			[
				"baz": Matcher.SomethingLike("string2")
			]
		], useAllValues: true)
	]
]

Generated JSON: (Do we really need to duplicate internal array $.data.foo matchers if they are already located in the variants value? Or real expected values should be used instead of matcher rules in the variants key?)

matchingRules =         {
            body =             {
                "$.data.foo" =                 {
                    matchers =                     {
                        match = arrayContains;
                        variants =                         {
                            "$.data.foo[0].bar" =                             {
                                matchers =                                 (
                                                                        {
                                        match = type;
                                    }
                                );
                            };
                            "$.data.foo[1].baz" =                             {
                                matchers =                                 (
                                                                        {
                                        match = type;
                                    }
                                );
                            };
                        };
                    };
                };
                "$.data.foo[0].bar" =                 {
                    matchers =                     (
                                                {
                            match = type;
                        }
                    );
                };
                "$.data.foo[1].baz" =                 {
                    matchers =                     (
                                                {
                            match = type;
                        }
                    );
                };
            };
        };

But the final pact contacts doesn't include $.data.foo matching rules (Problem is in json format i guess, but I could not find any pact example with arrayContains matcher).

{
      "description": "Request for a an object with simpler contains like matcher",
      "providerStates": [
        {
          "name": "dynamic json"
        }
      ],
      "request": {
        "method": "GET",
        "path": "/articles/simpler/containsLikeMatcher"
      },
      "response": {
        "body": {
          "foo": [
            {
              "bar": {
                "key1": "value1",
                "key2": 123
              }
            },
            {
              "baz": {
                "key3": "value2",
                "key4": 456
              }
            }
          ]
        },
        "matchingRules": {
          "body": {
            "$.foo[0].bar.key1": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "type"
                }
              ]
            },
            "$.foo[0].bar.key2": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "integer"
                }
              ]
            },
            "$.foo[1].baz.key3": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "type"
                }
              ]
            },
            "$.foo[1].baz.key4": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "integer"
                }
              ]
            }
          }
        },
        "status": 200
      }

Data that passed into mock server also looks ok

@StasMarynych
Copy link
Author

Finally, got the example of arrayContains rule using pact_mock_server_cli. Will refactor matcher processing to match the appropriate format

"$.baz": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "arrayContains",
                  "variants": [
                    {
                      "index": 0,
                      "rules": {
                        "": {
                          "combine": "AND",
                          "matchers": [
                            {
                              "match": "equality"
                            }
                          ]
                        }
                      }
                    },
                    {
                      "index": 0,
                      "rules": {
                        "": {
                          "combine": "AND",
                          "matchers": [
                            {
                              "match": "equality"
                            }
                          ]
                        }
                      }
                    }
                  ]
                }
              ]
            }

@StasMarynych
Copy link
Author

Final results.

One of the tests:

Screenshot 2023-07-25 at 17 55 05

Generated JSON

{
      "description": "Request for a an object with contains like matcher",
      "providerStates": [
        {
          "name": "dynamic json"
        }
      ],
      "request": {
        "method": "GET",
        "path": "/articles/simpler/containsLikeMatcher"
      },
      "response": {
        "body": {
          "foo": {
            "bar": {
              "key1": "value1",
              "key2": 123
            }
          }
        },
        "matchingRules": {
          "body": {
            "$.foo": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "arrayContains",
                  "variants": [
                    {
                      "index": 0,
                      "rules": {
                        "bar.key1": {
                          "combine": "AND",
                          "matchers": [
                            {
                              "match": "type"
                            }
                          ]
                        },
                        "bar.key2": {
                          "combine": "AND",
                          "matchers": [
                            {
                              "match": "integer"
                            }
                          ]
                        }
                      }
                    },
                    {
                      "index": 1,
                      "rules": {
                        "baz.key3": {
                          "combine": "AND",
                          "matchers": [
                            {
                              "match": "type"
                            }
                          ]
                        },
                        "baz.key4": {
                          "combine": "AND",
                          "matchers": [
                            {
                              "match": "integer"
                            }
                          ]
                        }
                      }
                    }
                  ]
                }
              ]
            }
          }
        },
        "status": 200
      }

@surpher
Copy link
Owner

surpher commented Jul 27, 2023

Hey @StasMarynych
Sorry for late reply. I'm unfortunately quite far away from GitHub lately. I saw your closed PR, what happened there?

I've pulled the fork that refactored and massively rebased PactSwift code to take advantage of libpact_ffi more.
Changes are on this branch https://github.com/surpher/PactSwift/tree/feat/v2.0.0 and it has full on support for modern swift concurrency.

@StasMarynych
Copy link
Author

StasMarynych commented Jul 27, 2023

Hey @surpher , thats totally fine) np

That mr was opened by the accident actually. Firstly, I wanted to be sure that current version of libpact_ffi that is in PactSwiftMockServer package supports that new type of matcher at all. Now, I see that everything is ok. So, if there is no arrayContains matcher in https://github.com/surpher/PactSwift/tree/feat/v2.0.0 would it be better to create the MR based on this branch?

@surpher
Copy link
Owner

surpher commented Jul 28, 2023

Yes sure. There might be a caveat though where v2 is full on concurrency focused. Changes the set up and structure of pact tests.
Make sure that v2 fits your needs first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants