Evgen
Evgen

Reputation: 1338

WebTestClient check that jsonPath contains sub string

In MockMvc there is an ability to assert that jsonPath contains substing

.andExpect(jsonPath("$.error.message")
.value(containsString("message")))

I wonder if there a nice way to do the same for WebTestClient, the syntax is a bit different

webClient.post().uri("/test")
                .contentType(MediaType.APPLICATION_JSON)
                .body(Mono.just(MyRequest), MyRequest.class)
                .exchange()
                .expectStatus().isBadRequest()
                .expectBody()
                .jsonPath("$.message").isEqualTo("message")

But I've found only isEqualTo method that related to it.

It could be done with exctracting getBodyAsString() from WebTestClient.BodyContentSpec but it doesn't look good.

Upvotes: 10

Views: 23314

Answers (6)

Pete Glasser
Pete Glasser

Reputation: 1

Here's something that seems to work but doesn't:

.jsonPath("$.message").toString().contains("textYoureLookingFor")

It returns true whether the text is there or not.

Upvotes: 0

Vitaly Chura
Vitaly Chura

Reputation: 870

As of Spring Framework 5 (not sure which version) the following can be used:

.jsonPath("message")
                .value(Matchers.containsString(<your_string>));

Upvotes: 6

Asriel
Asriel

Reputation: 133

I had the problem that my response body was plain text, not JSON and neither

.jsonPath("$[?(@ contains 'my substring')]").exists() nor

.jsonPath("$[?(@ =~ /.*my substring.*/)]").hasJsonPath() returned a value.

So I fetched and processed the body manually:

ResponseSpec resp = testClient.get().uri(myUrl).exchange();
resp.expectBody(String.class).consumeWith(respBody -> {
    assertTrue(respBody.getResponseBody().contains("my substring"));
});

Upvotes: 1

emvidi
emvidi

Reputation: 1310

WebTestClient WebFlux Spring Boot 2.3.4:

wtc.post()
   .uri(CREATE_ACCOUNT_URL)
   .contentType(APP_MEDIA_TYPE)
   .accept(APP_MEDIA_TYPE)
   .bodyValue(json)
   .exchange()
   .expectStatus().isBadRequest()
   .expectBody()
   .consumeWith(this::dumpToScreen)
   .jsonPath("$.timestamp").isNotEmpty()
   .jsonPath("$.path").isEqualTo(CREATE_ACCOUNT_URL)
   .jsonPath("$.status").isEqualTo(HttpStatus.BAD_REQUEST.value())
   .jsonPath("$.error").isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())
   .jsonPath("$.message").isEqualTo(WebExchangeBindingException.MESSAGE)
   .jsonPath("$.reason").exists()
   .jsonPath("$.reason.size()").isEqualTo(2)
   .jsonPath("$.reason.password.size()").isEqualTo(1)
   .jsonPath("$.reason.password").isEqualTo(EXC_MSG_NOT_NULL)
   .jsonPath("$.reason.email.size()").isEqualTo(1)
   .jsonPath("$.reason.email").isEqualTo(EXC_MSG_NOT_NULL);
   // When having more than 1 message
   //.jsonPath("$.reason.email").value(containsInAnyOrder(EXC_MSG_NOT_NULL, EXC_MSG_NOT_BLANK));

Upvotes: 3

makson
makson

Reputation: 2273

Check out the following example for discovering how to perform rest API tests using WebTestClient:

testClient.post().uri(URL,"value")
            .header("Authorization", "Basic " + Base64Utils
                    .encodeToString((loginInner + ":" + passwordInner).getBytes(UTF_8)))
            .exchange()
            .expectStatus()
            .isEqualTo(HttpStatus.BAD_REQUEST)
            .expectBody()
            .jsonPath("$.value_A").isEqualTo("100")
            .jsonPath("$.value_B").isEqualTo("some text")
            .jsonPath("$.value_C").isNotEmpty();

Upvotes: 6

Sam Brannen
Sam Brannen

Reputation: 31267

There is currently (as of Spring Framework 5.0.4) no support for Hamcrest matchers for use with WebTestClient.

However, you can use a regular expression to test if a JsonPath exists where an element contains a given substring.

For example, I just verified the following in Spring's own test suite. Note that the /persons URL returns a list of person objects (i.e., new Person("Jane"), new Person("Jason"), new Person("John")) and that the Person class has a name property.

this.client.get().uri("/persons")
        .accept(MediaType.APPLICATION_JSON_UTF8)
        .exchange()
        .expectStatus().isOk()
        .expectBody()
        // The following determines if at least one person is returned with a
        // name containing "oh", and "John" matches that.
        .jsonPath("$[?(@.name =~ /.*oh.*/)].name").hasJsonPath();

Thus, for your use case, I assume the following might work:

.jsonPath("$[?(@.error.message =~ /.*substring.*/)].error.message").hasJsonPath()

Another option would be to use consumeWith(...) instead of jsonPath(...) and then use Spring's JsonPathExpectationsHelper directly (which is what MockMvc uses internally).

Please let me know what works for you.

p.s. SPR-16574 may potentially address this shortcoming in Spring 5.x.

Upvotes: 9

Related Questions