spring-cloud-contract icon indicating copy to clipboard operation
spring-cloud-contract copied to clipboard

JsonPaths can't reference an object

Open benoitheinrich opened this issue 7 years ago • 4 comments

Bug report:

I'm using spring cloud contract version 2.0.2.RELEASE and when I'm generating code with the following contracts I'm getting 2 errors:

  1. The JSONArray import is missing in the test class
  2. The syntax isEqualTo(["Exit Counseling","Groovy Script","Groovy Script"]); is invalid in java

The java compiler complains with the following error:

illegal start of expression
 ';' expected

Please find below the contract and generated source code.

Thanks for help.

Contract:

description: some queries
request:
  url: /pendingFiles
  queryParameters:
    page: 0
    size: 10
  method: GET
  headers:
    Content-Type: application/json

response:
  status: 200
  headers:
    Content-Type: application/json;charset=UTF-8
  body:
  - workbookType: Exit Counseling
    username: John
    filename: 04_a_EXIT_COUNSELING.csv
    uploadedDate: '2018-11-07T16:51:28.000Z'
  - workbookType: Groovy Script
    username: John
    filename: exitConseling/triggerGraduating.groovy
    uploadedDate: '2018-11-07T16:51:28.000Z'
  - workbookType: Groovy Script
    username: John
    filename: exitConseling/triggerWithdrawn.groovy
    uploadedDate: '2018-11-07T16:51:28.000Z'
  matchers:
    body:
    - path: $..workbookType
      type: by_equality
    - path: $..username
      type: by_equality
    - path: $..filename
      type: by_equality
    - path: $..uploadedDate
      type: by_equality

Generated Test:

	@Test
	public void validate_shouldGetTheListOfPendingFiles() throws Exception {
		// given:
			RequestSpecification request = given()
					.header("Content-Type", "application/json");

		// when:
			Response response = given().spec(request)
					.queryParam("page","0")
					.queryParam("size","10")
					.get("/pendingFiles");

		// then:
			assertThat(response.statusCode()).isEqualTo(200);
			assertThat(response.header("Content-Type")).isEqualTo("application/json;charset=UTF-8");
		// and:
			DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
			assertThatJson(parsedJson).array().isEmpty();
		// and:
			assertThat(parsedJson.read("$..workbookType", JSONArray.class)).isEqualTo(["Exit Counseling","Groovy Script","Groovy Script"]);
			assertThat(parsedJson.read("$..username", JSONArray.class)).isEqualTo(["John","John","John"]);
			assertThat(parsedJson.read("$..filename", JSONArray.class)).isEqualTo(["04_a_EXIT_COUNSELING.csv","exitConseling\/triggerGraduating.groovy","exitConseling\/triggerWithdrawn.groovy"]);
			assertThat(parsedJson.read("$..uploadedDate", JSONArray.class)).isEqualTo(["2018-11-07T16:51:28.000Z","2018-11-07T16:51:28.000Z","2018-11-07T16:51:28.000Z"]);
	}

benoitheinrich avatar Nov 21 '18 10:11 benoitheinrich

Duplicate of https://github.com/spring-cloud/spring-cloud-contract/issues/363

You can't do it at the moment (reference an object, instead of a primitive). You can, however, call execute() to use a method

marcingrzejszczak avatar Nov 21 '18 11:11 marcingrzejszczak

Actually, it's not a duplicate of that one but it's related. I'll rename this issue and leave it as an enhancement

marcingrzejszczak avatar Nov 21 '18 11:11 marcingrzejszczak

Thanks @marcingrzejszczak for looking so quickly at this report :)

In your new title you're saying "can't reference an object", does it mean that this could work if what I was referencing was say an int ?

Just so you know I did try the following contract to check that and it does generate the same error code.

Contract:

description: |
  Stuff
request:
  url: /some
  queryParameters:
    page: 0
    size: 10
  method: GET
  headers:
    Content-Type: application/json

response:
  status: 200
  headers:
    Content-Type: application/json;charset=UTF-8
  body:
  - anInt: 1
    aDouble: 1.1
  - anInt: 2
    aDouble: 2.1
  - anInt: 3
    aDouble: 3.1

  # Those matchers are necessary for the code generator, otherwise the server tests won't work
  matchers:
    body:
    - path: $..anInt
      type: by_equality
    - path: $..aDouble
      type: by_equality

Generated Test:

	@Test
	public void validate_test() throws Exception {
		// given:
			RequestSpecification request = given()
					.header("Content-Type", "application/json");

		// when:
			Response response = given().spec(request)
					.queryParam("page","0")
					.queryParam("size","10")
					.get("/some");

		// then:
			assertThat(response.statusCode()).isEqualTo(200);
			assertThat(response.header("Content-Type")).isEqualTo("application/json;charset=UTF-8");
		// and:
			DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
			assertThatJson(parsedJson).array().isEmpty();
		// and:
			assertThat(parsedJson.read("$..anInt", JSONArray.class)).isEqualTo([1,2,3]);
			assertThat(parsedJson.read("$..aDouble", JSONArray.class)).isEqualTo([1.1,2.1,3.1]);
	}

The generator could instead generate an array on the fly like that:

			assertThat(parsedJson.read("$..anInt", JSONArray.class)).isEqualTo(new int[] {1,2,3});
			assertThat(parsedJson.read("$..aDouble", JSONArray.class)).isEqualTo(new double[] {1.1,2.1,3.1});

and then the missing import to org.json.JSONArray could be worked around with a change to the maven plugin configuration:

            <plugin>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-contract-maven-plugin</artifactId>
                <configuration>
                    <imports>
                        <import>org.json.JSONArray</import>
                    </imports>
                </configuration>
            </plugin>

I'm not sure where the code is generated in the plugin, but if you have some indication I could try to give it a look ;)

benoitheinrich avatar Nov 21 '18 11:11 benoitheinrich

@marcingrzejszczak It is really very strange that full body fromRequest().body() can be returned as json string with escaped symbols, and fromRequest().body('some.path') generate test class as not string, so test class can not be compiled

ijusti avatar Feb 26 '21 16:02 ijusti