WireMock-Net / WireMock.Net

WireMock.Net is a flexible product for stubbing and mocking web HTTP responses using advanced request matching and response templating. Based on the functionality from http://WireMock.org, but extended with more functionality.
Apache License 2.0
1.36k stars 200 forks source link

JsonPathMatcher does not match json body nested objects #965

Closed timurnes closed 12 months ago

timurnes commented 1 year ago

Describe the bug

JsonPathMatcher example in official documentation does not match json body with nested fields: Pattern: $.things[?(@.name == 'RequiredThing')] Json: { "things": { "name": "RequiredThing" } }

First-level fields match works correctly

Expected behavior:

JsonPathMatcher correctly matches json body with nested fields

Test to reproduce

[Fact]
public void JsonPathMatcher_IsMatch_JsonStringWithNestedObjects()
{
    // Assign
    var json = "{ \"things\": { \"name\": \"RequiredThing\" } }";
    var matcher = new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]");

    // Act 
    double match = matcher.IsMatch(json);

    // Assert 
    Check.That(match).IsEqualTo(1);
}

The checked value is different from the expected one.
The checked value:
    [0]
The expected value:
    [1]

Other related info

The same pattern works correctly with another json from example: { "things": [ { "name": "RequiredThing" }, { "name": "Wiremock" } ] }

StefH commented 12 months ago

https://github.com/WireMock-Net/WireMock.Net/pull/966

StefH commented 12 months ago

@timurnes You can check version 1.5.31-ci-17598

https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions

timurnes commented 12 months ago

@StefH Thanks, 1.5.31-ci-17598 works correctly. Waiting for release package version :)

Update: It doesn't. Please take a look on my next comment

timurnes commented 12 months ago

@StefH The fix is working only with first-level nested objects. It seems that the root cause is deeper (looking on your commits - Newtonsoft.Json?). This test fails:

[Fact]
public void JsonPathMatcher_IsMatch_JsonStringWithNestedObjects()
{
    // Assign
    var json = "{ \"things\": { \"nested\": { \"name\": \"RequiredThing\" } } }";
    var matcher = new JsonPathMatcher("$.things.nested[?(@.name == 'RequiredThing')]");

    // Act 
    double match = matcher.IsMatch(json);

    // Assert 
    Check.That(match).IsEqualTo(1);
}
StefH commented 12 months ago

@timurnes You are correct. My fix is just a workaround for the first level. To make it work for all levels, I need to call the code recursive. I'll check this.

BTW you know that you also can use a https://github.com/WireMock-Net/WireMock.Net/wiki/Request-Matching#dynamic-linq-linqmatcher

Which is much easier to use:

"things.nested.name == \"RequiredThing\""
timurnes commented 12 months ago

@StefH Sure, I used JsonPartialMatcher when I discovered that JsonPathMatcher does not work correctly - it looks better for my case

StefH commented 12 months ago

@timurnes Making the fix recursive is not that easy, so for now I'll merge this PR as-is.