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

Unable to specify JsonProvider when making MVC jsonPath() assertion #31423

Closed
DevDengChao opened this issue Oct 13, 2023 · 10 comments
Closed

Unable to specify JsonProvider when making MVC jsonPath() assertion #31423

DevDengChao opened this issue Oct 13, 2023 · 10 comments
Labels
in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) status: superseded An issue that has been superseded by another

Comments

@DevDengChao
Copy link

DevDengChao commented Oct 13, 2023

{
    "firstName": "John",
    "lastName": "doe",
    "age": 26,
    "address": {
        "streetAddress": "naist street",
        "city": "Nara",
        "postalCode": "630-0192"
    },
    "phoneNumbers": [
        {
            "type": "iPhone",
            "number": "0123-4567-8888"
        },
        {
            "type": "home",
            "number": "0123-4567-8910"
        }
    ]
}
mockMvc.perform(get("/user/John"))
    .andExpect(jsonPath("$.phoneNumbers[*].type").value( ??? ));

I was trying to make an assertion like something above, but there is no proper matcher helpers currently for the default JsonProvider (JsonSmartJsonProvider).
I opened netplex/json-smart-v2#162 to asking for JsonSmartMatchers as I cannot change what JsonProvider jsonPath() uses now.

This prevents me from choosing other JsonProvider who might have matcher helpers already.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 13, 2023
@DevDengChao
Copy link
Author

DevDengChao commented Oct 13, 2023

I suggest add a jsonPathResultMatchers.using(Class<T extends JsonProvider> provider) to allow us choosing another JsonProvider.

@DevDengChao
Copy link
Author

Related issue: json-path/JsonPath#918

@DevDengChao
Copy link
Author

I found https://github.com/lukas-krecan/JsonUnit might helps me.

@sbrannen sbrannen changed the title Unable to specify JsonProvider when making MVC jsonPath() assertion Unable to specify JsonProvider when making MVC jsonPath() assertion Nov 1, 2023
@sbrannen sbrannen added in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) labels Nov 1, 2023
@sbrannen
Copy link
Member

sbrannen commented Nov 1, 2023

Hi @DevDengChao,

I was trying to make an assertion like something above, but there is no proper matcher helpers currently for the default JsonProvider (JsonSmartJsonProvider).

Are you saying the default JsonProvider fails to parse your JSON content?

Or are you saying that Spring's JsonPathResultMatchers does not provide a method that would support your use case?

Or are you saying something else? If so, please expound.

Thanks

@sbrannen sbrannen added the status: waiting-for-feedback We need additional information before we can continue label Nov 1, 2023
@DevDengChao
Copy link
Author

are you saying that Spring's JsonPathResultMatchers does not provide a method that would support your use case?

Yes, there is no helper methods I can use to assert something is a json array which contains certain elements.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 1, 2023
@DevDengChao
Copy link
Author

Even one of the JsonProvider implementation has such api, I can not switch between implementations jsonPath() uses now.

@sbrannen
Copy link
Member

sbrannen commented Nov 1, 2023

are you saying that Spring's JsonPathResultMatchers does not provide a method that would support your use case?

Yes, there is no helper methods I can use to assert something is a json array which contains certain elements.

You are free to use any core Hamcrest matcher as well as any matchers from third-party libraries or matchers that you create yourself.

For the specific use case you've outlined, the following test class demonstrates that it's possible with built-in matchers from Hamcrest.

import org.junit.jupiter.api.Test;

import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static org.hamcrest.CoreMatchers.either;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;

class JsonPathArrayTests {

	private MockMvc mockMvc= standaloneSetup(new PersonController())
		.defaultRequest(get("/").accept(MediaType.APPLICATION_JSON))
		.alwaysExpect(status().isOk())
		.alwaysExpect(content().contentType("application/json"))
		.build();

	@Test
	void getPerson() throws Exception {
		String phoneNumberTypes = "$.phoneNumbers[*].type";

		mockMvc.perform(get("/person"))
			.andExpect(jsonPath(phoneNumberTypes).isArray())
			.andExpect(jsonPath(phoneNumberTypes).value(everyItem(either(is("iPhone")).or(is("home")))));
	}

	@RestController
	private static class PersonController {

		@RequestMapping("/person")
		String get() {
			return """
				{
				    "firstName": "John",
				    "lastName": "doe",
				    "age": 26,
				    "address": {
				        "streetAddress": "naist street",
				        "city": "Nara",
				        "postalCode": "630-0192"
				    },
				    "phoneNumbers": [
				        {
				            "type": "iPhone",
				            "number": "0123-4567-8888"
				        },
				        {
				            "type": "home",
				            "number": "0123-4567-8910"
				        }
				    ]
				}
				""";
		}
	}

}

@sbrannen
Copy link
Member

sbrannen commented Nov 1, 2023

Even one of the JsonProvider implementation has such api, I can not switch between implementations jsonPath() uses now.

I agree that it could be useful to provide a custom (or non-default) JsonProvider if you are facing issues with parsing, but I don't see how changing the default JsonProvider would benefit your use case.

@DevDengChao
Copy link
Author

DevDengChao commented Nov 1, 2023

@sbrannen Thanks for your code snippet, I should dig Hamcrest more before opening this issue.

I don't see how changing the default JsonProvider would benefit your use case.

As I metioned in netplex/json-smart-v2#162 (comment), something like https://github.com/Crunc/hamcrest-json-matchers provides some helper methods which could make assertions on json array, but it dosen't compatible with JsonSmart json array, if I could switch to other JsonProvider implementations, then I can choose to use such libs instead of write a long chain of Hamcrest matchers myself.

@rstoyanchev
Copy link
Contributor

I've created #31651 to open up JsonPathExpectationsHelper so you can follow that instead.

@rstoyanchev rstoyanchev closed this as not planned Won't fix, can't repro, duplicate, stale Nov 22, 2023
@rstoyanchev rstoyanchev added status: superseded An issue that has been superseded by another and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Nov 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) status: superseded An issue that has been superseded by another
Projects
None yet
Development

No branches or pull requests

4 participants