Skip to content

Commit

Permalink
feat(named-leasing): Add lease-opportunity-capacity-update test (#211)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukedawilson authored and Luke Wilson committed Oct 14, 2020
1 parent f189f53 commit b7127b6
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/openactive-integration-tests/config/default.json
Expand Up @@ -27,7 +27,7 @@
"simple-book-with-payment": true,
"multiple-sellers": true,
"payment-reconciliation-detail-validation": null,
"booking-window": null,
"booking-window": true,
"customer-requested-cancellation": true,
"cancellation-window": null,
"seller-requested-cancellation": null,
Expand Down
Expand Up @@ -70,7 +70,7 @@ The tests for these features are fully stubbed, and are not yet implemented.
| notifications | Opportunity attendance updates ([opportunity-attendance-updates](./notifications/opportunity-attendance-updates/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#opportunity-attendance-updates) | Allowing the broker to recieve updates for when an attendee attends an event | |
| payment | Payment reconciliation detail validation ([payment-reconciliation-detail-validation](./payment/payment-reconciliation-detail-validation/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#payment-reconciliation-detail-validation) | Booking with valid, invalid, and missing Payment details | |
| restrictions | Booking restrictions ([booking-restrictions](./restrictions/booking-restrictions/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#booking-restrictions) | Support for genderRestriction, ageRestriction and additionalAdmissionRestriction | |
| restrictions | validFromBeforeStartDate booking window ([booking-window](./restrictions/booking-window/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#definition-of-a-bookable-opportunity-and-offer-pair) | Duration of window before an opportunity where it is bookable | |
| restrictions | validFromBeforeStartDate booking window ([booking-window](./restrictions/booking-window/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#definition-of-a-bookable-opportunity-and-offer-pair) | Duration of window before an opportunity where it is bookable | [TestOpportunityBookableWithinValidFromBeforeStartDate](https://openactive.io/test-interface#TestOpportunityBookableWithinValidFromBeforeStartDate) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 |
| tax | Business-to-business Tax Calculation (TaxGross) ([business-to-business-tax-calculation-gross](./tax/business-to-business-tax-calculation-gross/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#business-to-business-tax-calculation-by-booking-system-is-optional) | Tax calculation when the customer is of type Organization (business-to-business), when the seller has taxMode TaxGross | |
| tax | Business-to-business Tax Calculation (TaxNet) ([business-to-business-tax-calculation-net](./tax/business-to-business-tax-calculation-net/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#business-to-business-tax-calculation-by-booking-system-is-optional) | Tax calculation when the customer is of type Organization (business-to-business), when the seller has taxMode TaxNet | |
| tax | Business-to-consumer Tax Calculation (TaxGross) ([business-to-consumer-tax-calculation-gross](./tax/business-to-consumer-tax-calculation-gross/README.md)) | [Optional](https://www.openactive.io/open-booking-api/EditorsDraft/#business-to-consumer-tax-calculation-by-booking-system-is-mandatory) | Tax calculation when the customer is of type Person (business-to-consumer), when the seller has taxMode TaxGross | |
Expand Down
Expand Up @@ -7,9 +7,28 @@ Duration of window before an opportunity where it is bookable
https://www.openactive.io/open-booking-api/EditorsDraft/#definition-of-a-bookable-opportunity-and-offer-pair

Coverage Status: **none**
### Test prerequisites
Opportunities that match the following criteria must exist in the booking system (for each configured `bookableOpportunityTypesInScope`) for the configured primary Seller in order to use `useRandomOpportunities: true`. Alternatively the following `testOpportunityCriteria` values must be supported by the [test interface](https://openactive.io/test-interface/) of the booking system for `useRandomOpportunities: false`.

[TestOpportunityBookableWithinValidFromBeforeStartDate](https://openactive.io/test-interface#TestOpportunityBookableWithinValidFromBeforeStartDate) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1

*Note the test coverage for this feature is currently nonexistent. The test suite does not yet include non-stubbed tests for this feature.*


## 'Implemented' tests

Update `default.json` within `packages/openactive-integration-tests/config/` as follows to enable 'Implemented' testing for this feature:

```json
"implementedFeatures": {
...
"booking-window": true,
...
}
```

| Identifier | Name | Description | Prerequisites per Opportunity Type |
|------------|------|-------------|---------------|
| [opportunity-in-range-c1-c2](./implemented/opportunity-in-range-c1-c2-test.js) | Running C1 and C2 for opportunity in range should succeed | Booking an opportunity within the specified booking window | [TestOpportunityBookableWithinValidFromBeforeStartDate](https://openactive.io/test-interface#TestOpportunityBookableWithinValidFromBeforeStartDate) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 |


@@ -0,0 +1,49 @@
const { FeatureHelper } = require('../../../../helpers/feature-helper');
const { GetMatch, C1, C2 } = require('../../../../shared-behaviours');

/**
* @typedef {import('chakram').ChakramResponse} ChakramResponse
*/

FeatureHelper.describeFeature(module, {
testCategory: 'restriction',
testFeature: 'booking-window',
testFeatureImplemented: true,
testIdentifier: 'opportunity-in-range-c1-c2',
testName: 'Running C1 and C2 for opportunity in range should succeed',
testDescription: 'Booking an opportunity within the specified booking window',
testOpportunityCriteria: 'TestOpportunityBookableWithinValidFromBeforeStartDate',
controlOpportunityCriteria: 'TestOpportunityBookable',
},
(configuration, orderItemCriteria, featureIsImplemented, logger, state, flow) => {
beforeAll(async () => {
await state.fetchOpportunities(orderItemCriteria);
});

describe('Get Opportunity Feed Items', () => {
(new GetMatch({
state, flow, logger, orderItemCriteria,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('C1', () => {
(new C1({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('C2', () => {
(new C2({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});
});
@@ -0,0 +1 @@
export const TestOpportunityBookableWithinValidFromBeforeStartDate: import("../types/Criteria").Criteria;
@@ -1,13 +1,21 @@
export type Opportunity = {
[k: string]: any;
};
export type Offer = {
[k: string]: any;
'@type': string;
'@id': string;
};
export type OpportunityConstraint = (opportunity: import("../types/Opportunity").Opportunity) => boolean;
export type Criteria = {
name: string;
opportunityConstraints: [string, import("../types/Criteria").OpportunityConstraint][];
offerConstraints: [string, import("../types/Criteria").OfferConstraint][];
};
/**
* @typedef {import('../types/Opportunity').Opportunity} Opportunity
* @typedef {import('../types/Offer').Offer} Offer
* @typedef {import('../types/Criteria').OpportunityConstraint} OpportunityConstraint
* @typedef {import('../types/Criteria').Criteria} Criteria
*/
/**
Expand Down Expand Up @@ -42,3 +50,8 @@ export function getType(opportunity: Opportunity): string;
* remainingUses, therefore the return value may be null-ish.
*/
export function getRemainingCapacity(opportunity: Opportunity): number | null | undefined;
/**
* @param {Offer} offer
* @param {Opportunity} opportunity
*/
export function mustBeWithinBookingWindow(offer: Offer, opportunity: Opportunity): boolean;
@@ -0,0 +1,18 @@
const { InternalTestOpportunityBookable } = require('./internal/InternalTestOpportunityBookable');
const { createCriteria, mustBeWithinBookingWindow } = require('./criteriaUtils');

const TestOpportunityBookableWithinValidFromBeforeStartDate = createCriteria({
name: 'TestOpportunityBookableWithinValidFromBeforeStartDate',
opportunityConstraints: [],
offerConstraints: [
[
'Must be within booking window',
mustBeWithinBookingWindow,
],
],
includeConstraintsFromCriteria: InternalTestOpportunityBookable,
});

module.exports = {
TestOpportunityBookableWithinValidFromBeforeStartDate,
};
22 changes: 22 additions & 0 deletions packages/test-interface-criteria/src/criteria/criteriaUtils.js
@@ -1,5 +1,9 @@
const moment = require('moment');

/**
* @typedef {import('../types/Opportunity').Opportunity} Opportunity
* @typedef {import('../types/Offer').Offer} Offer
* @typedef {import('../types/Criteria').OpportunityConstraint} OpportunityConstraint
* @typedef {import('../types/Criteria').Criteria} Criteria
*/

Expand Down Expand Up @@ -55,9 +59,27 @@ function getRemainingCapacity(opportunity) {
return opportunity.remainingAttendeeCapacity !== undefined ? opportunity.remainingAttendeeCapacity : opportunity.remainingUses;
}

/**
* @param {Offer} offer
* @param {Opportunity} opportunity
*/
function mustBeWithinBookingWindow(offer, opportunity) {
if (!offer || !offer.validFromBeforeStartDate) {
return false;
}

const now = moment();
const start = moment(opportunity.startDate);
const duration = moment.duration(offer.validFromBeforeStartDate);

const valid = start.subtract(duration) <= now;
return valid;
}

module.exports = {
createCriteria,
getId,
getType,
getRemainingCapacity,
mustBeWithinBookingWindow,
};
2 changes: 2 additions & 0 deletions packages/test-interface-criteria/src/criteria/index.js
Expand Up @@ -3,6 +3,7 @@ const { TestOpportunityBookableFree } = require('./TestOpportunityBookableFree')
const { TestOpportunityBookablePaid } = require('./TestOpportunityBookablePaid');
const { TestOpportunityBookableNoSpaces } = require('./TestOpportunityBookableNoSpaces');
const { TestOpportunityBookableFiveSpaces } = require('./TestOpportunityBookableFiveSpaces');
const { TestOpportunityBookableWithinValidFromBeforeStartDate } = require('./TestOpportunityBookableWithinValidFromBeforeStartDate');
const { TestOpportunityBookableCancellable } = require('./TestOpportunityBookableCancellable');
const { TestOpportunityNotBookableViaAvailableChannel } = require('./TestOpportunityNotBookableViaAvailableChannel');
const { TestOpportunityBookableOutsideValidFromBeforeStartDate } = require('./TestOpportunityBookableOutsideValidFromBeforeStartDate');
Expand All @@ -15,6 +16,7 @@ module.exports = {
TestOpportunityBookablePaid,
TestOpportunityBookableNoSpaces,
TestOpportunityBookableFiveSpaces,
TestOpportunityBookableWithinValidFromBeforeStartDate,
TestOpportunityBookableCancellable,
TestOpportunityNotBookableViaAvailableChannel,
TestOpportunityBookableOutsideValidFromBeforeStartDate,
Expand Down
@@ -1,7 +1,7 @@
const moment = require('moment');

const { InternalCriteriaFutureScheduledOpportunity } = require('../internal/InternalCriteriaFutureScheduledOpportunity');
const { getRemainingCapacity, createCriteria } = require('../criteriaUtils');
const { getRemainingCapacity, createCriteria, mustBeWithinBookingWindow } = require('../criteriaUtils');

/**
* @typedef {import('../../types/Criteria').OpportunityConstraint} OpportunityConstraint
Expand All @@ -24,6 +24,13 @@ function mustHaveBookableOffer(offer, opportunity) {
&& (!offer.validFromBeforeStartDate || moment(opportunity.startDate).subtract(moment.duration(offer.validFromBeforeStartDate)).isBefore());
}

/**
* @type {OfferConstraint}
*/
function mustIfThereIsABookableWindowBeWithinIt(offer, opportunity) {
return !(offer && offer.validFromBeforeStartDate) || mustBeWithinBookingWindow(offer, opportunity);
}

/**
* Internal criteria which almost implements https://openactive.io/test-interface#TestOpportunityBookable
* but handily leaves out anything related to openBookingFlowRequirement, so
Expand All @@ -39,6 +46,10 @@ const InternalTestOpportunityBookable = createCriteria({
],
],
offerConstraints: [
[
'Must, if there is a bookahead window, be within it',
mustIfThereIsABookableWindowBeWithinIt,
],
[
'Must have "bookable" offer',
mustHaveBookableOffer,
Expand Down

0 comments on commit b7127b6

Please sign in to comment.