diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/HsOfficeScenarioTests.java b/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/HsOfficeScenarioTests.java index 124d3731..735d51a6 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/HsOfficeScenarioTests.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/HsOfficeScenarioTests.java @@ -634,8 +634,7 @@ class HsOfficeScenarioTests extends ScenarioTest { """) .given("communityOfHeirsOfficePhoneNumber", "+49 40 666666") .given("communityOfHeirsEmailAddress", "lena.stadland@example.org") - .doRun() - .keep(); + .doRun(); } } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java b/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java index d37337df..7e62d535 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java @@ -31,38 +31,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase response.getFromBody("uuid"), "Even in production data we expect this query to return just a single result." // TODO.impl: add constraint? - ); - - obtain("Person: Erbengemeinschaft %{nameOfDeceasedPerson}", () -> - httpPost("/api/hs/office/persons", usingJsonBody(""" - { - "personType": "UNINCORPORATED_FIRM", - "tradeName": "Erbengemeinschaft %{nameOfDeceasedPerson}", - "givenName": ${givenName???}, - "familyName": ${familyName???} - } - """)) - .expecting(HttpStatus.CREATED).expecting(ContentType.JSON) - ); - -// obtain("Contact: Erbengemeinschaft %{nameOfDeceasedPerson}", () -> -// httpPost("/api/hs/office/contacts", usingJsonBody(""" -// { -// "caption": "Erbengemeinschaft %{nameOfDeceasedPerson}", -// "postalAddress": { -// "name": "Erbengemeinschaft %{nameOfDeceasedPerson}", -// %{communityOfHeirsPostalAddress} -// }, -// "phoneNumbers": { -// "office": ${communityOfHeirsOfficePhoneNumber} -// }, -// "emailAddresses": { -// "main": ${communityOfHeirsEmailAddress} -// } -// } -// """)) -// .expecting(HttpStatus.CREATED).expecting(ContentType.JSON) -// ); + ).extractValue("partnerRel.holder.uuid", "Person: %{nameOfDeceasedPerson}"); obtain("Partner-Relation: Erbengemeinschaft %{nameOfDeceasedPerson}", () -> httpPost("/api/hs/office/relations", usingJsonBody(""" @@ -70,9 +39,10 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase -// httpPost("/api/hs/office/persons", usingJsonBody(""" -// { -// "personType": "NATURAL_PERSON", -// "givenName": ${representativeGivenName}, -// "familyName": ${representativeFamilyName} -// } -// """)) -// .expecting(HttpStatus.CREATED).expecting(ContentType.JSON), -// "A community of heirs needs at least one representative.", -// "If there are more than one, each needs their own contact" -// ); + .extractUuidAlias("contact.uuid", "Contact: Erbengemeinschaft %{nameOfDeceasedPerson}") + .extractUuidAlias("holder.uuid", "Person: Erbengemeinschaft %{nameOfDeceasedPerson}"); obtain("Representative-Relation: %{representativeGivenName} %{representativeFamilyName} for Erbengemeinschaft %{nameOfDeceasedPerson}", () -> httpPost("/api/hs/office/relations", usingJsonBody(""" @@ -125,7 +79,7 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase httpPost("/api/hs/office/relations", usingJsonBody(""" @@ -148,6 +102,8 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase httpGet("/api/hs/office/relations?relationType=REPRESENTATIVE&personUuid=%{Person: %{representativeGivenName} %{representativeFamilyName}}") + .expecting(OK).expecting(JSON).expectArrayElements(1), + path("[0].anchor.tradeName").contains("Erbengemeinschaft %{nameOfDeceasedPerson}"), + path("[0].holder.familyName").contains("%{representativeFamilyName}") + ); + + // TODO.test: Verify Debitor, Membership, Coop-Shares and Coop-Assets once implemented } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/scenarios/JsonOptional.java b/src/test/java/net/hostsharing/hsadminng/hs/scenarios/JsonOptional.java index f5c829c6..6fff42df 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/scenarios/JsonOptional.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/scenarios/JsonOptional.java @@ -1,5 +1,7 @@ package net.hostsharing.hsadminng.hs.scenarios; +import java.util.Objects; +import java.util.UUID; public final class JsonOptional { @@ -41,4 +43,12 @@ public final class JsonOptional { } return jsonValue == null ? null : jsonValue.toString(); } + + public UUID givenUUID() { + try { + return UUID.fromString(Objects.toString(jsonValue)); + } catch(final IllegalArgumentException e) { + throw new ClassCastException("expected a UUID, but got '" + jsonValue + "'"); + } + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/scenarios/TestReport.java b/src/test/java/net/hostsharing/hsadminng/hs/scenarios/TestReport.java index a3199da6..028e679a 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/scenarios/TestReport.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/scenarios/TestReport.java @@ -169,4 +169,8 @@ public class TestReport { return "unknown"; } } + + public boolean isSilent() { + return silent > 0; + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/scenarios/UseCase.java b/src/test/java/net/hostsharing/hsadminng/hs/scenarios/UseCase.java index f8b1da80..095a4ff5 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/scenarios/UseCase.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/scenarios/UseCase.java @@ -122,12 +122,12 @@ public abstract class UseCase> { return new JsonTemplate(jsonTemplate); } - public final void obtain( + public final HttpResponse obtain( final String title, final Supplier http, final Function extractor, final String... extraInfo) { - withTitle(title, () -> { + return withTitle(title, () -> { final var response = http.get().keep(extractor); Arrays.stream(extraInfo).forEach(testReport::printPara); return response; @@ -261,6 +261,10 @@ public abstract class UseCase> { public final class HttpResponse { + private final HttpMethod httpMethod; + private final String uri; + private final String requestBody; + @Getter private final java.net.http.HttpResponse response; @@ -270,6 +274,8 @@ public abstract class UseCase> { @Getter private UUID locationUuid; + private boolean reported = false; + @SneakyThrows public HttpResponse( final HttpMethod httpMethod, @@ -277,6 +283,9 @@ public abstract class UseCase> { final String requestBody, final java.net.http.HttpResponse response ) { + this.httpMethod = httpMethod; + this.uri = uri; + this.requestBody = requestBody; this.response = response; this.status = HttpStatus.valueOf(response.statusCode()); if (this.status == HttpStatus.CREATED) { @@ -284,22 +293,24 @@ public abstract class UseCase> { assertThat(location).startsWith("http://localhost:"); locationUuid = UUID.fromString(location.substring(location.lastIndexOf('/') + 1)); } - - reportRequestAndResponse(httpMethod, uri, requestBody); } public HttpResponse expecting(final HttpStatus httpStatus) { + optionallyReportRequestAndResponse(); assertThat(HttpStatus.valueOf(response.statusCode())).isEqualTo(httpStatus); return this; } public HttpResponse expecting(final ContentType contentType) { + optionallyReportRequestAndResponse(); assertThat(response.headers().firstValue("content-type")) .contains(contentType.toString()); return this; } public HttpResponse keep(final Function extractor) { + optionallyReportRequestAndResponse(); + final var alias = nextTitle != null ? ScenarioTest.resolve(nextTitle, DROP_COMMENTS) : resultAlias; assertThat(alias).as("cannot keep result, no alias found").isNotNull(); @@ -309,11 +320,15 @@ public abstract class UseCase> { } public HttpResponse keepAs(final String alias) { + optionallyReportRequestAndResponse(); + ScenarioTest.putAlias(nonNullAlias(alias), locationUuid); return this; } public HttpResponse keep() { + optionallyReportRequestAndResponse(); + final var alias = nextTitle != null ? ScenarioTest.resolve(nextTitle, DROP_COMMENTS) : resultAlias; assertThat(alias).as("cannot keep result, no title or alias found for locationUuid: " + locationUuid).isNotNull(); @@ -322,6 +337,8 @@ public abstract class UseCase> { @SneakyThrows public HttpResponse expectArrayElements(final int expectedElementCount) { + optionallyReportRequestAndResponse(); + final var rootNode = objectMapper.readTree(response.body()); assertThat(rootNode.isArray()).as("array expected, but got: " + response.body()).isTrue(); @@ -333,6 +350,8 @@ public abstract class UseCase> { @SneakyThrows public HttpResponse expectObject() { + optionallyReportRequestAndResponse(); + final var rootNode = objectMapper.readTree(response.body()); assertThat(rootNode.isArray()).as("object expected, but got array: " + response.body()).isFalse(); return this; @@ -360,14 +379,23 @@ public abstract class UseCase> { return assertThat(getFromBodyAsOptional(path).givenAsString()); } + public HttpResponse reportWithResponse() { + return reportRequestAndResponse(true); + } + @SneakyThrows - private void reportRequestAndResponse(final HttpMethod httpMethod, final String uri, final String requestBody) { + private HttpResponse reportRequestAndResponse(final boolean unconditionallyWithResponse) { + if (reported) { + throw new IllegalStateException("request report already generated"); + } // the title if (nextTitle != null) { - testReport.printLine("\n### " + ScenarioTest.resolve(nextTitle, KEEP_COMMENTS) + "\n"); + testReport.printPara("### " + ScenarioTest.resolve(nextTitle, KEEP_COMMENTS)); } else if (resultAlias != null) { - testReport.printLine("\n### Create " + resultAlias + "\n"); + testReport.printPara("### Create " + resultAlias); + } else if (testReport.isSilent()) { + testReport.printPara("### Untitled Section"); } else { fail("please wrap the http...-call in the UseCase using `withTitle(...)`"); } @@ -379,11 +407,19 @@ public abstract class UseCase> { // the response testReport.printLine("=> status: " + status + " " + (locationUuid != null ? locationUuid : "")); - if (httpMethod == HttpMethod.GET || status.isError()) { + if (unconditionallyWithResponse || httpMethod == HttpMethod.GET || status.isError()) { testReport.printJson(response.body()); } testReport.printLine("```"); testReport.printLine(""); + return this; + } + + @SneakyThrows + private void optionallyReportRequestAndResponse() { + if (!reported) { + reportRequestAndResponse(false); + } } private String nonNullAlias(final String alias) { @@ -393,7 +429,14 @@ public abstract class UseCase> { return alias == null ? "unknown alias -- " + onlyVisibleInGeneratedMarkdownNotInSource : alias; } - public HttpResponse extract(final String jsonPath, final String resolvableName) { + public HttpResponse extractUuidAlias(final String jsonPath, final String resolvableName) { + final var resolvedName = ScenarioTest.resolve(resolvableName, DROP_COMMENTS); + final var resolvedJsonPath = getFromBodyAsOptional(jsonPath).givenUUID(); + ScenarioTest.putAlias(resolvedName, resolvedJsonPath); + return this; + } + + public HttpResponse extractValue(final String jsonPath, final String resolvableName) { final var resolvedName = ScenarioTest.resolve(resolvableName, DROP_COMMENTS); final var resolvedJsonPath = getFromBodyAsOptional(jsonPath).givenAsString(); ScenarioTest.putProperty(resolvedName, resolvedJsonPath);