diff --git a/packages/openactive-broker-microservice/package-lock.json b/packages/openactive-broker-microservice/package-lock.json index d3552eb4fd..4fce6935f1 100644 --- a/packages/openactive-broker-microservice/package-lock.json +++ b/packages/openactive-broker-microservice/package-lock.json @@ -159,9 +159,9 @@ } }, "@openactive/data-models": { - "version": "2.0.262", - "resolved": "https://registry.npmjs.org/@openactive/data-models/-/data-models-2.0.262.tgz", - "integrity": "sha512-EbSjwhHDgkEWNvftCV8jFWI1YrLLvU4+klshQgY6OpYbzxYDHkkjZb73tM7Ij6M8qnzOc/k9FJoj87c86l4GYg==" + "version": "2.0.271", + "resolved": "https://registry.npmjs.org/@openactive/data-models/-/data-models-2.0.271.tgz", + "integrity": "sha512-hjrVPzftlelX4+nCJpWzkZJLyXETuv/dTDGRA0HSjXIKPti6zSdJho+NWvY5OiNYREQ+RgDuwzPK0ZSoL0cDuw==" }, "@openactive/openactive-openid-test-client": { "version": "file:../openactive-openid-test-client", diff --git a/packages/openactive-broker-microservice/package.json b/packages/openactive-broker-microservice/package.json index 5181cdce24..8a396b780f 100644 --- a/packages/openactive-broker-microservice/package.json +++ b/packages/openactive-broker-microservice/package.json @@ -15,7 +15,7 @@ "license": "MIT", "dependencies": { "@openactive/data-model-validator": "^2.0.52", - "@openactive/data-models": "^2.0.262", + "@openactive/data-models": "^2.0.271", "@openactive/openactive-openid-test-client": "file:../openactive-openid-test-client", "@openactive/rpde-validator": "^2.0.9", "@openactive/test-interface-criteria": "file:../test-interface-criteria", diff --git a/packages/openactive-integration-tests/package-lock.json b/packages/openactive-integration-tests/package-lock.json index 3cb9263fff..5e901a3463 100644 --- a/packages/openactive-integration-tests/package-lock.json +++ b/packages/openactive-integration-tests/package-lock.json @@ -942,9 +942,9 @@ } }, "@openactive/data-models": { - "version": "2.0.262", - "resolved": "https://registry.npmjs.org/@openactive/data-models/-/data-models-2.0.262.tgz", - "integrity": "sha512-EbSjwhHDgkEWNvftCV8jFWI1YrLLvU4+klshQgY6OpYbzxYDHkkjZb73tM7Ij6M8qnzOc/k9FJoj87c86l4GYg==" + "version": "2.0.271", + "resolved": "https://registry.npmjs.org/@openactive/data-models/-/data-models-2.0.271.tgz", + "integrity": "sha512-hjrVPzftlelX4+nCJpWzkZJLyXETuv/dTDGRA0HSjXIKPti6zSdJho+NWvY5OiNYREQ+RgDuwzPK0ZSoL0cDuw==" }, "@openactive/openactive-openid-test-client": { "version": "file:../openactive-openid-test-client", diff --git a/packages/openactive-integration-tests/package.json b/packages/openactive-integration-tests/package.json index 4d6998b153..fa67f5a123 100644 --- a/packages/openactive-integration-tests/package.json +++ b/packages/openactive-integration-tests/package.json @@ -18,7 +18,7 @@ "eslintConfig": {}, "dependencies": { "@openactive/data-model-validator": "^2.0.52", - "@openactive/data-models": "^2.0.262", + "@openactive/data-models": "^2.0.271", "@openactive/openactive-openid-test-client": "file:../openactive-openid-test-client", "@openactive/test-interface-criteria": "file:../test-interface-criteria", "async-mutex": "^0.3.1", diff --git a/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md b/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md index 4005877727..3409164d67 100644 --- a/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md +++ b/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md @@ -39,7 +39,7 @@ This feature is **required** by the Open Booking API specification, and so must | [incomplete-customer-details](./implemented/incomplete-customer-details-test.js) | Expect an IncompleteCustomerDetailsError when customer details are missing the required email property | Run each of C2 and B for a valid opportunity, with customer details missing the required email property, expecting an IncompleteCustomerDetailsError to be returned (C1 is ignored because customer details are not accepted for C1) | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x8 | | [incomplete-order-item-no-offer](./implemented/incomplete-order-item-no-offer-test.js) | Test for IncompleteOrderItemError with missing `acceptedOffer` | Test for IncompleteOrderItemError (at C1, C2 and B). If there is a missing `acceptedOffer` property on the OrderItem. | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 | | [incomplete-order-item-no-opportunity](./implemented/incomplete-order-item-no-opportunity-test.js) | Test for IncompleteOrderItemError with missing `orderedItem` | Test for IncompleteOrderItemError (at C1, C2 and B). If there is a missing `orderedItem` property on the OrderItem. | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 | -| [opportunity-in-past](./implemented/opportunity-in-past-test.js) | Expect an OpportunityOfferPairNotBookableError when opportunity is in the past | Runs C1, C2 and B for an opportunity in the past, expecting an OpportunityOfferPairNotBookableError to be returned at C1 and C2, and an UnableToProcessOrderItemError to be returned at B | [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | +| [opportunity-in-past](./implemented/opportunity-in-past-test.js) | Expect an OpportunityOfferPairNotBookableError when opportunity is in the past | Runs C1, C2 and B for an opportunity in the past, expecting an OpportunityOfferPairNotBookableError to be returned at C1, C2, and B | [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | | [unknown-endpoint](./implemented/unknown-endpoint-test.js) | Expect an UnknownOrIncorrectEndpointError for requests to unknown endpoints | Send a request to an endpoint that does not exist, and expect an UnknownOrIncorrectEndpointError to be returned | | diff --git a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-offer-test.js b/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-offer-test.js index f63c45fe9f..eae6ab4e97 100644 --- a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-offer-test.js +++ b/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-offer-test.js @@ -3,7 +3,7 @@ const { FlowStageUtils, FlowStageRecipes, } = require('../../../../helpers/flow-stages'); -const { itShouldIncludeErrorForOnlyPrimaryOrderItems, itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors'); +const { itShouldIncludeErrorForOnlyPrimaryOrderItems } = require('../../../../shared-behaviours/errors'); /** * @typedef {import('../../../../helpers/flow-stages/c1').C1FlowStageType} C1FlowStageType @@ -48,7 +48,7 @@ FeatureHelper.describeFeature(module, { FlowStageUtils.describeRunAndRunChecks({ doCheckIsValid: false, doCheckSuccess: false }, c2, () => { itShouldIncludeIncompleteOrderItemErrorWhereRelevant(c2); }); - FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + FlowStageUtils.describeRunAndRunChecks({ doCheckIsValid: false, doCheckSuccess: false }, bookRecipe.firstStage, () => { + itShouldIncludeIncompleteOrderItemErrorWhereRelevant(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-opportunity-test.js b/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-opportunity-test.js index 15473cd841..45e6ec298f 100644 --- a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-opportunity-test.js +++ b/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/incomplete-order-item-no-opportunity-test.js @@ -3,7 +3,7 @@ const { FlowStageUtils, FlowStageRecipes, } = require('../../../../helpers/flow-stages'); -const { itShouldIncludeErrorForOnlyPrimaryOrderItems, itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors'); +const { itShouldIncludeErrorForOnlyPrimaryOrderItems } = require('../../../../shared-behaviours/errors'); /** * @typedef {import('../../../../helpers/flow-stages/c1').C1FlowStageType} C1FlowStageType @@ -48,7 +48,7 @@ FeatureHelper.describeFeature(module, { FlowStageUtils.describeRunAndRunChecks({ doCheckIsValid: false, doCheckSuccess: false }, c2, () => { itShouldIncludeIncompleteOrderItemErrorWhereRelevant(c2); }); - FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + FlowStageUtils.describeRunAndRunChecks({ doCheckIsValid: false, doCheckSuccess: false }, bookRecipe.firstStage, () => { + itShouldIncludeIncompleteOrderItemErrorWhereRelevant(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js b/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js index d18a3b774a..482057cb43 100644 --- a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js +++ b/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js @@ -1,6 +1,6 @@ const { FeatureHelper } = require('../../../../helpers/feature-helper'); const { FlowStageRecipes, FlowStageUtils } = require('../../../../helpers/flow-stages'); -const { itShouldIncludeErrorForOnlyPrimaryOrderItems, itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors'); +const { itShouldIncludeErrorForOnlyPrimaryOrderItems } = require('../../../../shared-behaviours/errors'); /** * @typedef {import('../../../../helpers/flow-stages/c1').C1FlowStageType} C1FlowStageType @@ -13,7 +13,7 @@ FeatureHelper.describeFeature(module, { testFeatureImplemented: true, testIdentifier: 'opportunity-in-past', testName: 'Expect an OpportunityOfferPairNotBookableError when opportunity is in the past', - testDescription: 'Runs C1, C2 and B for an opportunity in the past, expecting an OpportunityOfferPairNotBookableError to be returned at C1 and C2, and an UnableToProcessOrderItemError to be returned at B', + testDescription: 'Runs C1, C2 and B for an opportunity in the past, expecting an OpportunityOfferPairNotBookableError to be returned at C1, C2, and B', // The primary opportunity criteria to use for the primary OrderItem under test testOpportunityCriteria: 'TestOpportunityBookableInPast', // The secondary opportunity criteria to use for multiple OrderItem tests @@ -43,6 +43,6 @@ FeatureHelper.describeFeature(module, { itShouldIncludeOpportunityOfferPairNotBookableErrorWhereRelevant(c2); }); FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + itShouldIncludeOpportunityOfferPairNotBookableErrorWhereRelevant(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-but-not-supplied-test.js b/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-but-not-supplied-test.js index 06737cc689..1d0e793064 100644 --- a/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-but-not-supplied-test.js +++ b/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-but-not-supplied-test.js @@ -1,7 +1,6 @@ const chai = require('chai'); const { FeatureHelper } = require('../../../../helpers/feature-helper'); const { FlowStageRecipes, FlowStageUtils } = require('../../../../helpers/flow-stages'); -const { itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors'); FeatureHelper.describeFeature(module, { testCategory: 'details-capture', @@ -21,10 +20,10 @@ FeatureHelper.describeFeature(module, { FlowStageUtils.describeRunAndCheckIsSuccessfulAndValid(fetchOpportunities); FlowStageUtils.describeRunAndCheckIsSuccessfulAndValid(c1); - FlowStageUtils.describeRunAndCheckIsValid(c2, () => { + function itShouldReturnAnIncompleteIntakeFormError(flowStage) { it('should return an IncompleteIntakeFormError on the OrderItem', () => { const positionsOfOrderItemsThatNeedIntakeForms = Object.keys(c1.getOutput().positionOrderIntakeFormMap).map(parseInt); - const orderItemsThatNeedIntakeForms = c2.getOutput().httpResponse.body.orderedItem + const orderItemsThatNeedIntakeForms = flowStage.getOutput().httpResponse.body.orderedItem .filter(orderItem => positionsOfOrderItemsThatNeedIntakeForms.includes(orderItem.position)); for (const orderItem of orderItemsThatNeedIntakeForms) { @@ -34,8 +33,13 @@ FeatureHelper.describeFeature(module, { chai.expect(incompleteIntakeFormErrors).to.have.lengthOf.above(0); } }); + } + + FlowStageUtils.describeRunAndCheckIsValid(c2, () => { + itShouldReturnAnIncompleteIntakeFormError(c2); }); + FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + itShouldReturnAnIncompleteIntakeFormError(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-invalid-details-supplied-test.js b/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-invalid-details-supplied-test.js index da4d55f4bf..467c29ed4a 100644 --- a/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-invalid-details-supplied-test.js +++ b/packages/openactive-integration-tests/test/features/details-capture/additional-details-capture/implemented/additional-details-required-invalid-details-supplied-test.js @@ -1,7 +1,6 @@ const chai = require('chai'); const { FeatureHelper } = require('../../../../helpers/feature-helper'); const { FlowStageRecipes, FlowStageUtils } = require('../../../../helpers/flow-stages'); -const { itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors'); FeatureHelper.describeFeature(module, { testCategory: 'details-capture', @@ -22,10 +21,10 @@ FeatureHelper.describeFeature(module, { FlowStageUtils.describeRunAndCheckIsSuccessfulAndValid(fetchOpportunities); FlowStageUtils.describeRunAndCheckIsSuccessfulAndValid(c1); - FlowStageUtils.describeRunAndCheckIsValid(c2, () => { - it('should return an IncompleteAttendeeDetailsError on the OrderItem', () => { + function itShouldReturnAnInvalidIntakeFormError(flowStage) { + it('should return an InvalidIntakeFormError on the OrderItem', () => { const positionsOfOrderItemsThatNeedIntakeForms = Object.keys(c1.getOutput().positionOrderIntakeFormMap).map(parseInt); - const orderItemsThatNeedIntakeForms = c2.getOutput().httpResponse.body.orderedItem + const orderItemsThatNeedIntakeForms = flowStage.getOutput().httpResponse.body.orderedItem .filter(orderItem => positionsOfOrderItemsThatNeedIntakeForms.includes(orderItem.position)); for (const orderItem of orderItemsThatNeedIntakeForms) { @@ -35,8 +34,12 @@ FeatureHelper.describeFeature(module, { chai.expect(incompleteIntakeFormErrors).to.have.lengthOf.above(0); } }); + } + + FlowStageUtils.describeRunAndCheckIsValid(c2, () => { + itShouldReturnAnInvalidIntakeFormError(c2); }); FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + itShouldReturnAnInvalidIntakeFormError(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/features/details-capture/attendee-details-capture/implemented/attendee-details-not-included-test.js b/packages/openactive-integration-tests/test/features/details-capture/attendee-details-capture/implemented/attendee-details-not-included-test.js index e41ca54305..38f1e53162 100644 --- a/packages/openactive-integration-tests/test/features/details-capture/attendee-details-capture/implemented/attendee-details-not-included-test.js +++ b/packages/openactive-integration-tests/test/features/details-capture/attendee-details-capture/implemented/attendee-details-not-included-test.js @@ -2,7 +2,6 @@ const _ = require('lodash'); const chai = require('chai'); const { FeatureHelper } = require('../../../../helpers/feature-helper'); const { FlowStageRecipes, FlowStageUtils } = require('../../../../helpers/flow-stages'); -const { itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors'); FeatureHelper.describeFeature(module, { testCategory: 'details-capture', @@ -22,12 +21,12 @@ FeatureHelper.describeFeature(module, { FlowStageUtils.describeRunAndCheckIsSuccessfulAndValid(fetchOpportunities); FlowStageUtils.describeRunAndCheckIsSuccessfulAndValid(c1); - FlowStageUtils.describeRunAndCheckIsValid(c2, () => { + function itShouldReturnAnIncompleteAttendeeDetailsError(flowStage) { it('should return an IncompleteAttendeeDetailsError on the OrderItem', () => { const positionsOfOrderItemsThatNeedAttendeeDetails = c1.getOutput().httpResponse.body.orderedItem .filter(orderItem => !_.isNil(orderItem.attendeeDetailsRequired)) .map(orderItem => orderItem.position); - const orderItemsThatNeedAttendeeDetails = c2.getOutput().httpResponse.body.orderedItem + const orderItemsThatNeedAttendeeDetails = flowStage.getOutput().httpResponse.body.orderedItem .filter(orderItem => positionsOfOrderItemsThatNeedAttendeeDetails.includes(orderItem.position)); for (const orderItem of orderItemsThatNeedAttendeeDetails) { @@ -37,8 +36,13 @@ FeatureHelper.describeFeature(module, { chai.expect(incompleteIntakeFormErrors).to.have.lengthOf.above(0); } }); + } + + FlowStageUtils.describeRunAndCheckIsValid(c2, () => { + itShouldReturnAnIncompleteAttendeeDetailsError(c2); }); + FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + itShouldReturnAnIncompleteAttendeeDetailsError(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/features/payment/prepayment-required-unavailable/implemented/prepayment-required-unavailable-conflict-error-test.js b/packages/openactive-integration-tests/test/features/payment/prepayment-required-unavailable/implemented/prepayment-required-unavailable-conflict-error-test.js index c923a73beb..b5f72929b8 100644 --- a/packages/openactive-integration-tests/test/features/payment/prepayment-required-unavailable/implemented/prepayment-required-unavailable-conflict-error-test.js +++ b/packages/openactive-integration-tests/test/features/payment/prepayment-required-unavailable/implemented/prepayment-required-unavailable-conflict-error-test.js @@ -1,6 +1,6 @@ const { FeatureHelper } = require('../../../../helpers/feature-helper'); const { FlowStageRecipes, FlowStageUtils } = require('../../../../helpers/flow-stages'); -const { itShouldReturnAnOpenBookingError, itShouldIncludeErrorForOnlyPrimaryOrderItems } = require('../../../../shared-behaviours/errors'); +const { itShouldIncludeErrorForOnlyPrimaryOrderItems } = require('../../../../shared-behaviours/errors'); /** * @typedef {import('../../../../helpers/flow-stages/c1').C1FlowStageType} C1FlowStageType @@ -70,6 +70,6 @@ FeatureHelper.describeFeature(module, { itShouldIncludeOpportunityIsInConflictErrorWhereRelevant(c2); }); FlowStageUtils.describeRunAndCheckIsValid(bookRecipe.firstStage, () => { - itShouldReturnAnOpenBookingError('UnableToProcessOrderItemError', 409, () => bookRecipe.firstStage.getOutput().httpResponse); + itShouldIncludeOpportunityIsInConflictErrorWhereRelevant(bookRecipe.firstStage); }); }); diff --git a/packages/openactive-integration-tests/test/shared-behaviours/validation.js b/packages/openactive-integration-tests/test/shared-behaviours/validation.js index 244b644107..d408578504 100644 --- a/packages/openactive-integration-tests/test/shared-behaviours/validation.js +++ b/packages/openactive-integration-tests/test/shared-behaviours/validation.js @@ -99,9 +99,14 @@ function shouldBeValidResponse(getter, name, logger, options, opportunityCriteri const statusCode = response.response && response.response.statusCode; const statusMessage = response.response && response.response.statusMessage; - // Note C1Response and C2Response are permitted to return 409 errors of type `OrderQuote`, instead of `OpenBookingError` - if ((statusCode < 200 || statusCode >= 300) && !(statusCode === 409 && (options.validationMode === 'C1Response' || options.validationMode === 'C2Response'))) { - optionsWithRemoteJson.validationMode = 'OpenBookingError'; + // Note C1Response, C2Response, BResponse and PResponse are permitted to return 409 errors of type `OrderQuote`, `OrderProposal`, or `Order` instead of `OpenBookingError` + if (statusCode < 200 || statusCode >= 300) { + // TODO: Test suite should assert whether the response is expected to be an OrderItemError, instead of basing validation on the response status code + if (statusCode === 409 && (options.validationMode === 'C1Response' || options.validationMode === 'C2Response' || options.validationMode === 'BResponse' || options.validationMode === 'PResponse')) { + optionsWithRemoteJson.validationMode = `${options.validationMode}OrderItemError`; + } else { + optionsWithRemoteJson.validationMode = 'OpenBookingError'; + } // little nicer error message for completely failed responses. if (!body) {