diff --git a/.github/workflows/live-api-test.yml b/.github/workflows/live-api-test.yml new file mode 100644 index 00000000..bfd9d570 --- /dev/null +++ b/.github/workflows/live-api-test.yml @@ -0,0 +1,20 @@ +name: Run test on the live API + +on: + schedule: + - cron: '0 12 * * *' + +jobs: + test: + name: Run test on live API + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 2 + ref: 'master' + - uses: bahmutov/npm-install@v1 + - name: Run jest + run: ./node_modules/.bin/cross-env npm test -- tests/unit/delivery-options/testLiveApi.spec.js --coverage=false + env: + NODE_ICU_DATA: node_modules/full-icu diff --git a/src/config/extraDeliveryConfig.js b/src/config/extraDeliveryConfig.js index 55adc0e6..09f3fa62 100644 --- a/src/config/extraDeliveryConfig.js +++ b/src/config/extraDeliveryConfig.js @@ -1,9 +1,13 @@ import * as CONFIG from '@/data/keys/configKeys'; -import { MYPARCEL, SENDMYPARCEL } from '@/data/keys/platformKeys'; +import { FEATURES_MONDAY_DELIVERY, FEATURES_SATURDAY_DELIVERY } from '@/data/carrierFeatures'; -const MONDAY = 1; -const FRIDAY = 5; -const SATURDAY = 6; +export const MONDAY = 1; +export const TUESDAY = 2; +export const WEDNESDAY = 3; +export const THURSDAY = 4; +export const FRIDAY = 5; +export const SATURDAY = 6; +export const SUNDAY = 0; /** * Settings for extra delivery days. @@ -12,23 +16,15 @@ const SATURDAY = 6; */ export const extraDeliveryConfig = [ { + cutoffTime: CONFIG.SATURDAY_CUTOFF_TIME, deliveryDay: MONDAY, dropOffDay: SATURDAY, - platforms: [MYPARCEL], - requires: [ - CONFIG.ALLOW_MONDAY_DELIVERY, - CONFIG.SATURDAY_CUTOFF_TIME, - ], - cutoffTime: CONFIG.SATURDAY_CUTOFF_TIME, + requires: FEATURES_MONDAY_DELIVERY, }, { + cutoffTime: CONFIG.FRIDAY_CUTOFF_TIME, deliveryDay: SATURDAY, dropOffDay: FRIDAY, - platforms: [SENDMYPARCEL], - requires: [ - CONFIG.ALLOW_SATURDAY_DELIVERY, - CONFIG.FRIDAY_CUTOFF_TIME, - ], - cutoffTime: CONFIG.FRIDAY_CUTOFF_TIME, + requires: FEATURES_SATURDAY_DELIVERY, }, ]; diff --git a/src/data/carrierFeatures.js b/src/data/carrierFeatures.js index 49eb32d3..7b1d4d89 100644 --- a/src/data/carrierFeatures.js +++ b/src/data/carrierFeatures.js @@ -27,7 +27,6 @@ export const FEATURES_EVENING_DELIVERY = [ */ export const FEATURES_MONDAY_DELIVERY = [ CONFIG.ALLOW_MONDAY_DELIVERY, - CONFIG.PRICE_MONDAY_DELIVERY, CONFIG.SATURDAY_CUTOFF_TIME, ]; @@ -86,7 +85,6 @@ export const FEATURES_PICKUP = [ */ export const FEATURES_SATURDAY_DELIVERY = [ CONFIG.ALLOW_SATURDAY_DELIVERY, - CONFIG.PRICE_SATURDAY_DELIVERY, CONFIG.FRIDAY_CUTOFF_TIME, ]; diff --git a/src/data/keys/configKeys.js b/src/data/keys/configKeys.js index f527620e..63ee2a9d 100644 --- a/src/data/keys/configKeys.js +++ b/src/data/keys/configKeys.js @@ -41,7 +41,6 @@ export const PRICE_PACKAGE_TYPE_MAILBOX = 'pricePackageTypeMailbox'; * For use with Monday delivery. */ export const ALLOW_MONDAY_DELIVERY = 'allowMondayDelivery'; -export const PRICE_MONDAY_DELIVERY = 'priceMondayDelivery'; export const SATURDAY_CUTOFF_TIME = 'saturdayCutoffTime'; /* @@ -49,7 +48,6 @@ export const SATURDAY_CUTOFF_TIME = 'saturdayCutoffTime'; */ export const ALLOW_SATURDAY_DELIVERY = 'allowSaturdayDelivery'; export const FRIDAY_CUTOFF_TIME = 'fridayCutoffTime'; -export const PRICE_SATURDAY_DELIVERY = 'priceSaturdayDelivery'; /* * Carrier settings object diff --git a/src/data/locales/be/config.js b/src/data/locales/be/config.js index 7e3bb092..4978b700 100644 --- a/src/data/locales/be/config.js +++ b/src/data/locales/be/config.js @@ -1,11 +1,10 @@ import * as CONFIG from '@/data/keys/configKeys'; -import { DEFAULT_MAX_PAGE_ITEMS, DEFAULT_PRICE } from '@/data/keys/settingsConsts'; +import { DEFAULT_MAX_PAGE_ITEMS } from '@/data/keys/settingsConsts'; export const config = { [CONFIG.LOCALE]: 'nl-BE', [CONFIG.ALLOW_SATURDAY_DELIVERY]: true, - [CONFIG.PRICE_SATURDAY_DELIVERY]: DEFAULT_PRICE, [CONFIG.FRIDAY_CUTOFF_TIME]: '15:00', /** diff --git a/src/delivery-options/config/configBus.js b/src/delivery-options/config/configBus.js index 506cc474..0498df95 100644 --- a/src/delivery-options/config/configBus.js +++ b/src/delivery-options/config/configBus.js @@ -213,6 +213,7 @@ export const createConfigBus = (eventCallee = null) => { this[item] = configuration[item]; }); + this.currentCarrier = Object.keys(configuration.config.carrierSettings)[0]; this.weekdays = getWeekdays(configuration.config.locale); document.dispatchEvent(new Event(EVENTS.UPDATE_DELIVERY_OPTIONS)); diff --git a/src/delivery-options/data/request/checkIsDropOffDay.js b/src/delivery-options/data/request/checkIsDropOffDay.js new file mode 100644 index 00000000..03df6ee3 --- /dev/null +++ b/src/delivery-options/data/request/checkIsDropOffDay.js @@ -0,0 +1,16 @@ +import * as CONFIG from '@/data/keys/configKeys'; +import { configBus as realConfigBus } from '@/delivery-options/config/configBus'; + +/** + * @param {Number} dropOffDay + * @param {import('@/delivery-options/config/configBus').configBus} configBus + * @param {Number} day + * + * @returns {Boolean} + */ +export function checkIsDropOffDay(dropOffDay, configBus = realConfigBus, day = new Date().getDay()) { + const dateMatches = day === dropOffDay; + const dateIsDropOffDay = configBus.get(CONFIG.DROP_OFF_DAYS).includes(day); + + return dateMatches && dateIsDropOffDay; +} diff --git a/src/delivery-options/data/request/getCutOffTime.js b/src/delivery-options/data/request/getCutOffTime.js index c3c3304f..c55a41bc 100644 --- a/src/delivery-options/data/request/getCutOffTime.js +++ b/src/delivery-options/data/request/getCutOffTime.js @@ -1,28 +1,21 @@ import * as CONFIG from '@/data/keys/configKeys'; -import { extraDeliveryConfig } from '@/config/extraDeliveryConfig'; +import { checkIsDropOffDay } from '@/delivery-options/data/request/checkIsDropOffDay'; +import { getExtraDropOffDay } from '@/delivery-options/data/request/getExtraDropOffDay'; import { configBus as realConfigBus } from '@/delivery-options/config/configBus'; /** * Get cutoff time for a special delivery day. Returns default cutoff time if the conditions for an extra delivery day * don't pass. * - * @param {import('@/delivery-options/config/configBus')} configBus - Optional parameter for easier testing. + * @param {import('@/delivery-options/config/configBus').configBus} configBus - Optional parameter for easier testing. * - * @returns {MyParcelDeliveryOptions.Config.cutoffTime} + * @returns {String} */ export function getCutOffTime(configBus = realConfigBus) { - const today = new Date().getDay(); + const extraDropOffDay = getExtraDropOffDay(configBus); + const todayIsExtraDropOffDay = extraDropOffDay && checkIsDropOffDay(extraDropOffDay.dropOffDay, configBus); - const extraDropOffDay = extraDeliveryConfig.find((setting) => { - const allowedForPlatform = setting.platforms.includes(configBus.get(CONFIG.PLATFORM)); - const todayIsExtraDay = today === setting.dropOffDay; - const requirementsFulfilled = setting.requires.every((requirement) => Boolean(configBus.get(requirement))); - const extraDayIsDropOffDay = configBus.get(CONFIG.DROP_OFF_DAYS).includes(setting.dropOffDay); - - return todayIsExtraDay && allowedForPlatform && extraDayIsDropOffDay && requirementsFulfilled; - }); - - return extraDropOffDay + return todayIsExtraDropOffDay ? configBus.get(extraDropOffDay.cutoffTime) : configBus.get(CONFIG.CUTOFF_TIME); } diff --git a/src/delivery-options/data/request/getExtraDropOffDay.js b/src/delivery-options/data/request/getExtraDropOffDay.js new file mode 100644 index 00000000..4f30d842 --- /dev/null +++ b/src/delivery-options/data/request/getExtraDropOffDay.js @@ -0,0 +1,21 @@ +import * as CONFIG from '@/data/keys/configKeys'; +import { CarrierConfigurationFactory } from '@/data/carriers/carrierConfigurationFactory'; +import { extraDeliveryConfig } from '@/config/extraDeliveryConfig'; +import { configBus as realConfigBus } from '@/delivery-options/config/configBus'; + +/** + * @param {import('@/delivery-options/config/configBus').configBus} configBus + * + * @returns {Object} + */ +export function getExtraDropOffDay(configBus = realConfigBus) { + const platform = configBus.get(CONFIG.PLATFORM); + const carrierConfiguration = CarrierConfigurationFactory.create(configBus.currentCarrier, platform); + + return extraDeliveryConfig.find((setting) => { + const allowedForCarrierAndPlatform = carrierConfiguration.hasFeature(setting.requires); + const requiredOptionsPresent = setting.requires.every(configBus.get); + + return allowedForCarrierAndPlatform && requiredOptionsPresent; + }); +} diff --git a/src/sandbox/translations/en.js b/src/sandbox/translations/en.js index c3454d39..7d8ed830 100644 --- a/src/sandbox/translations/en.js +++ b/src/sandbox/translations/en.js @@ -72,8 +72,6 @@ export const englishTranslations = { [`field.${CONFIG.PICKUP_LOCATIONS_MAP_TILE_LAYER_DATA}`]: 'Map tile layer data', [`field.${CONFIG.PRICE_EVENING_DELIVERY}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, [`field.${CONFIG.PRICE_EVENING_DELIVERY}`]: 'Evening delivery price', - [`field.${CONFIG.PRICE_MONDAY_DELIVERY}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, - [`field.${CONFIG.PRICE_MONDAY_DELIVERY}`]: 'Monday delivery price', [`field.${CONFIG.PRICE_MORNING_DELIVERY}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, [`field.${CONFIG.PRICE_MORNING_DELIVERY}`]: 'Morning delivery price', [`field.${CONFIG.PRICE_ONLY_RECIPIENT}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, @@ -83,8 +81,6 @@ export const englishTranslations = { [`field.${CONFIG.PRICE_PICKUP}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, [`field.${CONFIG.PRICE_PICKUP}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, [`field.${CONFIG.PRICE_PICKUP}`]: 'Pickup price', - [`field.${CONFIG.PRICE_SATURDAY_DELIVERY}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, - [`field.${CONFIG.PRICE_SATURDAY_DELIVERY}`]: 'Saturday delivery price', [`field.${CONFIG.PRICE_SIGNATURE}.description`]: `@:field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`, [`field.${CONFIG.PRICE_SIGNATURE}`]: 'Signature price', [`field.${CONFIG.PRICE_STANDARD_DELIVERY}.description`]: 'The amount of money you charge for this feature. If the amount is negative the price will appear green in the delivery options to show it\'s a discount.', diff --git a/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/cutoffTimeHasPassed.js b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/cutoffTimeHasPassed.js new file mode 100644 index 00000000..360089a6 --- /dev/null +++ b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/cutoffTimeHasPassed.js @@ -0,0 +1,13 @@ +import { createCutOffTimeDate } from '@Tests/helpers/createCutOffTimeDate'; + +/** + * @param {String} cutoffTime - Timestamp in HH:mm format. + * @param {import('dayjs').Dayjs} date + * + * @returns {import('dayjs').Dayjs} + */ +export function cutoffTimeHasPassed(cutoffTime, date) { + const cutOffTimeDate = createCutOffTimeDate(cutoffTime, date); + + return !date.isBefore(cutOffTimeDate); +} diff --git a/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/findExtraDelivery.js b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/findExtraDelivery.js new file mode 100644 index 00000000..5ce4c69c --- /dev/null +++ b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/findExtraDelivery.js @@ -0,0 +1,25 @@ +import { CarrierConfigurationFactory } from '@/data/carriers/carrierConfigurationFactory'; +import { extraDeliveryConfig } from '@/config/extraDeliveryConfig'; +import { platformCarrierMap } from '@/config/platform/platformCarrierMap'; + +/** + * Use passed args to find a valid extra delivery day. + * + * @param {Object} args + * @param {Number} dayOfWeek + * + * @returns {Object} + */ +export function findExtraDelivery(args, dayOfWeek) { + // Falls back to the first carrier for current platform. + const carrier = args.carrier ?? platformCarrierMap[args.platform][0]; + const carrierConfiguration = CarrierConfigurationFactory.create(carrier, args.platform); + + return extraDeliveryConfig.find((setting) => { + const isToday = setting.deliveryDay === dayOfWeek; + const hasDropOffDay = args.dropoff_days.includes(setting.dropOffDay); + const allowedForCarrierAndPlatform = carrierConfiguration.hasFeature(setting.requires); + + return isToday && hasDropOffDay && allowedForCarrierAndPlatform; + }); +} diff --git a/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getDropOffDay.js b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getDropOffDay.js new file mode 100644 index 00000000..a3db5933 --- /dev/null +++ b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getDropOffDay.js @@ -0,0 +1,18 @@ +/** + * Find the last possible dropoff day for a given delivery day. + * + * @param {import('dayjs').Dayjs} deliveryDay + * @param {String} dropOffDays + * @returns {import('dayjs').Dayjs} + */ +export function getDropOffDay(deliveryDay, dropOffDays) { + const dropOffDaysArray = dropOffDays.split(';').map(Number); + + let dropOffDay = deliveryDay.subtract(1, 'day'); + + while (!dropOffDaysArray.includes(dropOffDay.weekday())) { + dropOffDay = dropOffDay.subtract(1, 'day'); + } + + return dropOffDay; +} diff --git a/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getNextDeliveryOption.js b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getNextDeliveryOption.js index 4beb6d5a..d21998c2 100644 --- a/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getNextDeliveryOption.js +++ b/tests/__mocks__/@myparcel/js-sdk/dist/data/delivery-options/getNextDeliveryOption.js @@ -1,59 +1,54 @@ +import { MONDAY, SATURDAY, SUNDAY } from '@/config/extraDeliveryConfig'; import { MYPARCEL, SENDMYPARCEL } from '@/data/keys/platformKeys'; +import { cutoffTimeHasPassed } from '@Mocks/@myparcel/js-sdk/dist/data/delivery-options/cutoffTimeHasPassed'; import { dayjs } from '@Tests/dayjs'; -import { extraDeliveryConfig } from '@/config/extraDeliveryConfig'; +import { findExtraDelivery } from '@Mocks/@myparcel/js-sdk/dist/data/delivery-options/findExtraDelivery'; import { getDeliveryOptionsEntry } from './getDeliveryOptionsEntry'; +import { getDropOffDay } from '@Mocks/@myparcel/js-sdk/dist/data/delivery-options/getDropOffDay'; -const disallowedDays = { - [MYPARCEL]: [0, 1], - [SENDMYPARCEL]: [0, 6], +const daysWithoutDelivery = { + [MYPARCEL]: [MONDAY, SUNDAY], + [SENDMYPARCEL]: [SATURDAY, SUNDAY], }; /** * Returns the next available delivery date, very much like the actual responses from the API. This needs to be - * quite precise because we can't mock the current date with real api responses. + * quite precise because we can't mock the current date with real api responses. * * @param {Object} args * @param {Number} daysOffset + * @param {import('dayjs').Dayjs} date * * @returns {Object} */ -export function getNextDeliveryOption(args, daysOffset = 1) { - const next = () => getNextDeliveryOption(args, daysOffset + 1); +export function getNextDeliveryOption(args, daysOffset = 1, date = dayjs()) { + const next = () => getNextDeliveryOption(args, daysOffset + 1, date); - const today = dayjs().add(daysOffset, 'day'); - const dayOfWeek = today.weekday(); - const todayIsDisallowed = disallowedDays[args.platform].includes(dayOfWeek); - - let dropOffDay = dayOfWeek - 1; - - const extraDelivery = extraDeliveryConfig.find((config) => { - const isToday = config.deliveryDay === dayOfWeek; - const allowedInPlatform = config.platforms.includes(args.platform); - - return isToday && allowedInPlatform; - }); + const currentDeliveryDate = date.add(daysOffset, 'day'); + const dropOffDay = getDropOffDay(currentDeliveryDate, args.dropoff_days); + const currentDayOfWeek = currentDeliveryDate.weekday(); + const todayIsDisallowed = daysWithoutDelivery[args.platform].includes(currentDayOfWeek); + const extraDelivery = findExtraDelivery(args, currentDayOfWeek); + // Skip Saturday or Monday if its setting is not enabled. if (extraDelivery) { - // Skip Saturday or Monday if its setting is not enabled. - if (args[`${args.platform === MYPARCEL ? 'monday' : 'saturday'}_delivery`] !== 1) { + const extraDeliveryEnabled = args[`${args.platform === MYPARCEL ? 'monday' : 'saturday'}_delivery`] === 1; + const isExtraDropOffDay = dropOffDay.weekday() === extraDelivery.dropOffDay; + + if (!extraDeliveryEnabled || !isExtraDropOffDay) { return next(); } - - // With Monday delivery, for example, the dropoff day is Saturday instead of Sunday. - dropOffDay = extraDelivery.dropOffDay; } else if (todayIsDisallowed) { return next(); } - const dropOffDays = args.dropoff_days.split(';'); - - // If the drop off day for today is not enabled, skip. - if (!dropOffDays.includes(dropOffDay.toString())) { + // If today is the dropoff day, check if the cutoff time has passed. + if (date.isSame(dropOffDay) && cutoffTimeHasPassed(args.cutoff_time, date)) { return next(); } return { index: daysOffset, - data: getDeliveryOptionsEntry(today, !!extraDelivery), + data: getDeliveryOptionsEntry(currentDeliveryDate, !!extraDelivery), }; } diff --git a/tests/__mocks__/@myparcel/js-sdk/dist/data/fakeDeliveryOptionsResponse.js b/tests/__mocks__/@myparcel/js-sdk/dist/data/fakeDeliveryOptionsResponse.js index 36f7dcf4..c31ea2ef 100644 --- a/tests/__mocks__/@myparcel/js-sdk/dist/data/fakeDeliveryOptionsResponse.js +++ b/tests/__mocks__/@myparcel/js-sdk/dist/data/fakeDeliveryOptionsResponse.js @@ -24,8 +24,12 @@ export const fakeDeliveryOptionsResponse = jest.fn(); * @returns {Object[]} */ fakeDeliveryOptionsResponse.mockImplementation((args) => { - const deliveryDaysWindow = args.deliverydays_window || 1; - const dropOffDelay = args.dropoff_delay || 0; + args.deliverydays_window = args.deliverydays_window ?? 1; + args.dropoff_delay = args.dropoff_delay ?? 0; + args.dropoff_days = args.dropoff_days ?? [0, 1, 2, 3, 4, 5, 6]; + + const deliveryDaysWindow = args.deliverydays_window; + const dropOffDelay = args.dropoff_delay; let startIndex = dropOffDelay + 1; return Array diff --git a/tests/dayjs.js b/tests/dayjs.js index 92d61f5a..c808070d 100644 --- a/tests/dayjs.js +++ b/tests/dayjs.js @@ -1,6 +1,8 @@ +import customParseFormat from 'dayjs/plugin/customParseFormat'; import dayjs from 'dayjs'; import weekday from 'dayjs/plugin/weekday'; +dayjs.extend(customParseFormat); dayjs.extend(weekday); export { dayjs }; diff --git a/tests/helpers/createCutOffTimeDate.js b/tests/helpers/createCutOffTimeDate.js new file mode 100644 index 00000000..8ff48ffb --- /dev/null +++ b/tests/helpers/createCutOffTimeDate.js @@ -0,0 +1,13 @@ +import dayjs from 'dayjs'; + +/** + * @param {String} cutoffTime - String in HH:mm format. + * @param {import('dayjs').Dayjs} date + * + * @returns {import('dayjs').Dayjs} + */ +export function createCutOffTimeDate(cutoffTime, date = dayjs()) { + const [hour, minute] = cutoffTime.split(':'); + + return date.set('h', parseInt(hour)).set('m', parseInt(minute)); +} diff --git a/tests/helpers/getMockedDeliveryDateChoices.js b/tests/helpers/getMockedDeliveryDateChoices.js new file mode 100644 index 00000000..5d81493a --- /dev/null +++ b/tests/helpers/getMockedDeliveryDateChoices.js @@ -0,0 +1,31 @@ +import * as CONFIG from '@/data/keys/configKeys'; +import { UPDATED_DELIVERY_OPTIONS } from '@/config/eventConfig'; +import { mockDeliveryOptions } from '@Tests/unit/delivery-options/mockDeliveryOptions'; +import { waitForEvent } from '@Tests/waitForEvent'; + +/** + * Mock delivery options and returns the array of visible choices for the delivery date option. + * + * @param {Object} config + * + * @returns {String[]} + */ +export async function getMockedDeliveryDateChoices(config) { + const wrapper = mockDeliveryOptions({ + [CONFIG.KEY]: config, + }); + + await waitForEvent(UPDATED_DELIVERY_OPTIONS); + + let wrappers; + const deliveryDateOption = wrapper.findByTestId('deliveryDate__select__label'); + + // When delivery days window is 1 the only option is shown as text instead of a select option. + if (deliveryDateOption.exists()) { + wrappers = [deliveryDateOption]; + } else { + wrappers = wrapper.findAllByTestId('deliveryDate__select__option').wrappers; + } + + return wrappers.map((wrapper) => wrapper.element.getAttribute('data-test-choice')); +} diff --git a/tests/unit/delivery-options/deliveryMoment.spec.js b/tests/unit/delivery-options/deliveryMoment.spec.js index e978aa87..5da9b18e 100644 --- a/tests/unit/delivery-options/deliveryMoment.spec.js +++ b/tests/unit/delivery-options/deliveryMoment.spec.js @@ -1,27 +1,37 @@ -import * as CARRIERS from '@/data/keys/carrierKeys'; import * as CONFIG from '@/data/keys/configKeys'; +import { BPOST, DPD, POSTNL, RED_JE_PAKKETJE } from '@/data/keys/carrierKeys'; +import { FRIDAY, MONDAY, SATURDAY, SUNDAY, THURSDAY, TUESDAY, WEDNESDAY } from '@/config/extraDeliveryConfig'; import { MYPARCEL, SENDMYPARCEL } from '@/data/keys/platformKeys'; import MockDate from 'mockdate'; import { UPDATED_DELIVERY_OPTIONS } from '@/config/eventConfig'; +import { checkIsDropOffDay } from '@/delivery-options/data/request/checkIsDropOffDay'; +import dayjs from 'dayjs'; +import { getExtraDropOffDay } from '@/delivery-options/data/request/getExtraDropOffDay'; +import { getMockedDeliveryDateChoices } from '@Tests/helpers/getMockedDeliveryDateChoices'; +import { mockConfigBus } from '@Tests/unit/delivery-options/mockConfigBus'; import { mockDeliveryOptions } from '@Tests/unit/delivery-options/mockDeliveryOptions'; import { waitForEvent } from '@Tests/waitForEvent'; // Timestamps are before all cutoff times -const FRIDAY = '2020-03-13T10:00:00'; -const SATURDAY = '2020-03-14T10:00:00'; +const DATE_FRIDAY = '2020-03-13T10:00:00Z'; +const DATE_SATURDAY = '2020-03-14T10:00:00Z'; + +// After all cutoff times +const DATE_FRIDAY_AFTER_CUTOFF = '2020-03-13T18:00:00Z'; +const DATE_SATURDAY_AFTER_CUTOFF = '2020-03-14T18:00:00Z'; const configMyParcel = { [CONFIG.PLATFORM]: MYPARCEL, [CONFIG.DELIVERY_DAYS_WINDOW]: 7, // Includes Saturday - [CONFIG.DROP_OFF_DAYS]: [1, 2, 3, 4, 5, 6], + [CONFIG.DROP_OFF_DAYS]: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY], [CONFIG.DROP_OFF_DELAY]: 0, [CONFIG.SATURDAY_CUTOFF_TIME]: '14:30', [CONFIG.ALLOW_MONDAY_DELIVERY]: true, }; /** - * Delivery days window is always the same for SendMyParcel so it doesn't need to be set. + * Delivery days window is always the same for SendMyParcel, so it doesn't need to be set. * * @see @/delivery-options/data/request/requestData:9 */ @@ -29,44 +39,18 @@ const configSendMyParcel = { [CONFIG.PLATFORM]: SENDMYPARCEL, // Includes Friday - [CONFIG.DROP_OFF_DAYS]: [1, 2, 3, 4, 5], + [CONFIG.DROP_OFF_DAYS]: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY], [CONFIG.DROP_OFF_DELAY]: 0, [CONFIG.FRIDAY_CUTOFF_TIME]: '14:30', [CONFIG.ALLOW_SATURDAY_DELIVERY]: true, [CONFIG.CARRIER_SETTINGS]: { - [CARRIERS.BPOST]: { + [BPOST]: { [CONFIG.ALLOW_DELIVERY_OPTIONS]: true, }, }, }; -/** - * Mock delivery options and returns the array of visible choices for the delivery date option. - * - * @param {Object} config - * - * @returns {String[]} - */ -async function getMockedDeliveryDateChoices(config) { - const wrapper = mockDeliveryOptions({ - [CONFIG.KEY]: config, - }); - await waitForEvent(UPDATED_DELIVERY_OPTIONS); - - let wrappers; - const deliveryDateOption = wrapper.findByTestId('deliveryDate__select__label'); - - // When delivery days window is 1 the only option is shown as text instead of a select option. - if (deliveryDateOption.exists()) { - wrappers = [deliveryDateOption]; - } else { - wrappers = wrapper.findAllByTestId('deliveryDate__select__option').wrappers; - } - - return wrappers.map((wrapper) => wrapper.element.getAttribute('data-test-choice')); -} - describe('Delivery moments', () => { afterEach(() => { MockDate.reset(); @@ -74,7 +58,7 @@ describe('Delivery moments', () => { test('can show monday delivery', async() => { expect.assertions(1); - MockDate.set(SATURDAY); + MockDate.set(DATE_SATURDAY); const choices = await getMockedDeliveryDateChoices(configMyParcel); @@ -93,7 +77,7 @@ describe('Delivery moments', () => { it('does not show monday delivery when "allow_monday_delivery" is false', async() => { expect.assertions(1); - MockDate.set(SATURDAY); + MockDate.set(DATE_SATURDAY); const choices = await getMockedDeliveryDateChoices({ ...configMyParcel, @@ -116,12 +100,12 @@ describe('Delivery moments', () => { it('does not show monday delivery when saturday is not a drop-off day', async() => { expect.assertions(1); - MockDate.set(SATURDAY); + MockDate.set(DATE_SATURDAY); const choicesWithMissingDropOffDay = await getMockedDeliveryDateChoices({ ...configMyParcel, - // Saturday is missing - [CONFIG.DROP_OFF_DAYS]: [1, 2, 3, 4, 5], + // No Saturday. + [CONFIG.DROP_OFF_DAYS]: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY], }); // Tuesday to Saturday and the next Tuesday and Wednesday @@ -138,9 +122,32 @@ describe('Delivery moments', () => { ]); }); + it('does not show monday delivery when the saturday cutoff time has passed', async() => { + expect.assertions(1); + MockDate.set(DATE_SATURDAY_AFTER_CUTOFF); + + const choices = await getMockedDeliveryDateChoices({ + ...configMyParcel, + // No Sunday. + [CONFIG.DROP_OFF_DAYS]: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY], + }); + + expect(choices).toStrictEqual([ + // Monday: disallowed because Saturday cutoff time has passed + '2020-03-17T00:00:00.000Z', + '2020-03-18T00:00:00.000Z', + '2020-03-19T00:00:00.000Z', + '2020-03-20T00:00:00.000Z', + '2020-03-21T00:00:00.000Z', + // Sunday: disallowed + '2020-03-23T00:00:00.000Z', + '2020-03-24T00:00:00.000Z', + ]); + }); + test('can show saturday delivery', async() => { expect.assertions(1); - MockDate.set(FRIDAY); + MockDate.set(DATE_FRIDAY); const choicesWithMissingDropOffDay = await getMockedDeliveryDateChoices(configSendMyParcel); @@ -152,26 +159,26 @@ describe('Delivery moments', () => { it('does not show saturday delivery when "allow_saturday_delivery" is false', async() => { expect.assertions(1); - MockDate.set(FRIDAY); + MockDate.set(DATE_FRIDAY); const choices = await getMockedDeliveryDateChoices({ ...configSendMyParcel, [CONFIG.ALLOW_SATURDAY_DELIVERY]: false, }); - // Tuesday because Monday's dropoff day, Sunday, is not a dropoff day. + // Next Monday. expect(choices).toStrictEqual([ - '2020-03-17T00:00:00.000Z', + '2020-03-16T00:00:00.000Z', ]); }); it('does not show saturday delivery when friday is not a drop-off day', async() => { expect.assertions(1); - MockDate.set(FRIDAY); + MockDate.set(DATE_FRIDAY); const choices = await getMockedDeliveryDateChoices({ ...configSendMyParcel, - [CONFIG.DROP_OFF_DAYS]: [1, 2, 3, 4, 0], + [CONFIG.DROP_OFF_DAYS]: [SUNDAY, MONDAY, TUESDAY, WEDNESDAY], }); // Monday because Sunday is a dropoff day. @@ -180,6 +187,18 @@ describe('Delivery moments', () => { ]); }); + it('does not show saturday delivery when the friday cutoff time has passed', async() => { + expect.assertions(1); + MockDate.set(DATE_FRIDAY_AFTER_CUTOFF); + + const choices = await getMockedDeliveryDateChoices(configSendMyParcel); + + // Tuesday because Monday to Friday are dropoff days. + expect(choices).toStrictEqual([ + '2020-03-17T00:00:00.000Z', + ]); + }); + it('hides delivery date when requested', async() => { expect.assertions(3); @@ -189,15 +208,15 @@ describe('Delivery moments', () => { [CONFIG.DELIVERY_DAYS_WINDOW]: 1, [CONFIG.FEATURE_ALLOW_SHOW_DELIVERY_DATE]: true, [CONFIG.CARRIER_SETTINGS]: { - [CARRIERS.POSTNL]: { + [POSTNL]: { [CONFIG.ALLOW_DELIVERY_OPTIONS]: true, [CONFIG.FEATURE_ALLOW_SHOW_DELIVERY_DATE]: true, }, - [CARRIERS.BPOST]: { + [BPOST]: { [CONFIG.ALLOW_DELIVERY_OPTIONS]: true, [CONFIG.FEATURE_ALLOW_SHOW_DELIVERY_DATE]: false, }, - [CARRIERS.DPD]: { + [DPD]: { [CONFIG.ALLOW_DELIVERY_OPTIONS]: true, }, }, @@ -206,19 +225,66 @@ describe('Delivery moments', () => { await waitForEvent(UPDATED_DELIVERY_OPTIONS); - const postnl = wrapper.findChoice('carrier', CARRIERS.POSTNL); + const postnl = wrapper.findChoice('carrier', POSTNL); expect(postnl.find('[data-test-id="deliveryDate__select__label"]').element).toBeVisible(); - const bpost = wrapper.findChoice('carrier', CARRIERS.BPOST); - const bpostInput = wrapper.findChoice('carrier__input', CARRIERS.BPOST); + const bpost = wrapper.findChoice('carrier', BPOST); + const bpostInput = wrapper.findChoice('carrier__input', BPOST); bpostInput.element.click(); await waitForEvent(UPDATED_DELIVERY_OPTIONS); expect(bpost.find('[data-test-id="deliveryDate__select__label"]').element).not.toBeVisible(); - const dpd = wrapper.findChoice('carrier', CARRIERS.DPD); - const dpdInput = wrapper.findChoice('carrier__input', CARRIERS.DPD); + const dpd = wrapper.findChoice('carrier', DPD); + const dpdInput = wrapper.findChoice('carrier__input', DPD); dpdInput.element.click(); await waitForEvent(UPDATED_DELIVERY_OPTIONS); expect(dpd.find('[data-test-id="deliveryDate__select__label"]').element).not.toBeVisible(); }); + + test.each` + platform | carrier | weekday | expected + ${MYPARCEL} | ${POSTNL} | ${MONDAY} | ${false} + ${MYPARCEL} | ${POSTNL} | ${TUESDAY} | ${false} + ${MYPARCEL} | ${POSTNL} | ${WEDNESDAY} | ${false} + ${MYPARCEL} | ${POSTNL} | ${THURSDAY} | ${false} + ${MYPARCEL} | ${POSTNL} | ${FRIDAY} | ${false} + ${MYPARCEL} | ${POSTNL} | ${SATURDAY} | ${true} + ${MYPARCEL} | ${POSTNL} | ${SUNDAY} | ${false} + ${MYPARCEL} | ${RED_JE_PAKKETJE} | ${SATURDAY} | ${false} + ${SENDMYPARCEL} | ${BPOST} | ${MONDAY} | ${false} + ${SENDMYPARCEL} | ${BPOST} | ${TUESDAY} | ${false} + ${SENDMYPARCEL} | ${BPOST} | ${WEDNESDAY} | ${false} + ${SENDMYPARCEL} | ${BPOST} | ${THURSDAY} | ${false} + ${SENDMYPARCEL} | ${BPOST} | ${FRIDAY} | ${true} + ${SENDMYPARCEL} | ${BPOST} | ${SATURDAY} | ${false} + ${SENDMYPARCEL} | ${BPOST} | ${SUNDAY} | ${false} + ${SENDMYPARCEL} | ${DPD} | ${FRIDAY} | ${false} + ${SENDMYPARCEL} | ${POSTNL} | ${FRIDAY} | ${false} + `('handles extra dropoff day for $platform, $carrier on day $weekday correctly', ({ + platform, + carrier, + weekday, + expected, + }) => { + const date = dayjs().weekday(weekday).set('h', 10).set('m', 0).toDate(); + MockDate.set(date); + + const configBus = mockConfigBus({ + [CONFIG.KEY]: { + [CONFIG.PLATFORM]: platform, + [CONFIG.DROP_OFF_DAYS]: [0, 1, 2, 3, 4, 5, 6], + [CONFIG.CARRIER_SETTINGS]: { + [carrier]: { + [CONFIG.ALLOW_DELIVERY_OPTIONS]: true, + [CONFIG.ALLOW_MONDAY_DELIVERY]: true, + [CONFIG.ALLOW_SATURDAY_DELIVERY]: true, + }, + }, + }, + }); + + const extraDropOffDay = getExtraDropOffDay(configBus); + const todayIsExtraDropOffDay = extraDropOffDay && checkIsDropOffDay(extraDropOffDay.dropOffDay, configBus); + expect(todayIsExtraDropOffDay)[expected ? 'toBeTruthy' : 'toBeFalsy'](); + }); }); diff --git a/tests/unit/delivery-options/testLiveApi.spec.js b/tests/unit/delivery-options/testLiveApi.spec.js new file mode 100644 index 00000000..a88a8044 --- /dev/null +++ b/tests/unit/delivery-options/testLiveApi.spec.js @@ -0,0 +1,80 @@ +import * as CONFIG from '@/data/keys/configKeys'; +import { BPOST, POSTNL } from '@/data/keys/carrierKeys'; +import { MYPARCEL, SENDMYPARCEL } from '@/data/keys/platformKeys'; +import dayjs from 'dayjs'; +import { fakeDeliveryOptionsResponse } from '@Mocks/@myparcel/js-sdk/dist/data/fakeDeliveryOptionsResponse'; +import { fetchDeliveryOptions } from '@/delivery-options/data/delivery/fetchDeliveryOptions'; +import { getRequestParameters } from '@/delivery-options/data/request/getRequestParameters'; +import { mockConfigBus } from '@Tests/unit/delivery-options/mockConfigBus'; + +const formatDates = ({ date }) => dayjs(date.date).format('dddd, DD-MM-YYYY'); + +/** + * This test is made to check whether the delivery options generated by fakeDeliveryOptionsResponse match the real + * response from the API. + * + * As long as this test passes, the results of all tests using mocked delivery options can be trusted. + */ +describe('test settings on the live API', () => { + beforeAll(() => { + // Disable mocks, so the test can use the real API instead of mocked responses. + jest.clearAllMocks(); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + const now = dayjs(); + const weekday = now.format('dddd').toLowerCase(); + + test.each` + platform | carrier | allowExtraDelivery | cutoffTime | extraCutoffTime | dropOffDays + ${MYPARCEL} | ${POSTNL} | ${true} | ${'16:00'} | ${'12:00'} | ${[2, 3, 4, 5, 6]} + ${MYPARCEL} | ${POSTNL} | ${false} | ${'16:00'} | ${'12:00'} | ${[0, 1, 2, 3, 4, 5]} + ${SENDMYPARCEL} | ${BPOST} | ${true} | ${'16:00'} | ${'12:00'} | ${[1, 2, 3, 5, 6]} + ${SENDMYPARCEL} | ${BPOST} | ${false} | ${'16:00'} | ${'12:00'} | ${[1, 3, 4, 6]} + ${MYPARCEL} | ${POSTNL} | ${true} | ${'00:01'} | ${'09:00'} | ${[0, 1, 2, 3, 4, 5, 6]} + ${MYPARCEL} | ${POSTNL} | ${false} | ${'00:01'} | ${'09:00'} | ${[1, 2, 3, 4, 5]} + ${SENDMYPARCEL} | ${BPOST} | ${true} | ${'00:01'} | ${'09:00'} | ${[1, 4, 5]} + ${SENDMYPARCEL} | ${BPOST} | ${false} | ${'00:01'} | ${'09:00'} | ${[0, 1, 2, 3, 4, 5, 6]} + `(`test cutoff times for $platform on ${weekday}`, async({ + platform, + carrier, + allowExtraDelivery, + cutoffTime, + extraCutoffTime, + dropOffDays, + }) => { + expect.assertions(1); + const DELIVERY_DAYS_WINDOW = 7; + const mockedConfigBus = mockConfigBus({ + [CONFIG.KEY]: { + [CONFIG.PLATFORM]: platform, + [CONFIG.DELIVERY_DAYS_WINDOW]: DELIVERY_DAYS_WINDOW, + [CONFIG.CUTOFF_TIME]: cutoffTime, + [CONFIG.DROP_OFF_DAYS]: dropOffDays, + [CONFIG.CUTOFF_TIME]: cutoffTime, + [CONFIG.ALLOW_MONDAY_DELIVERY]: allowExtraDelivery, + [CONFIG.ALLOW_SATURDAY_DELIVERY]: allowExtraDelivery, + [CONFIG.FRIDAY_CUTOFF_TIME]: extraCutoffTime, + [CONFIG.SATURDAY_CUTOFF_TIME]: extraCutoffTime, + [CONFIG.CARRIER_SETTINGS]: { + [carrier]: { + [CONFIG.ALLOW_DELIVERY_OPTIONS]: true, + }, + }, + }, + }); + + jest.mock('@/delivery-options/config/configBus', () => ({ configBus: mockedConfigBus })); + + const realResponse = await fetchDeliveryOptions(); + const receivedDeliveryOptions = realResponse.map(formatDates); + + const fakeResponse = fakeDeliveryOptionsResponse(getRequestParameters()); + const calculatedDeliveryOptions = fakeResponse.map(formatDates); + + expect(receivedDeliveryOptions).toEqual(calculatedDeliveryOptions); + }); +}); diff --git a/tests/unit/test/getDeliveryOption.spec.js b/tests/unit/test/getDeliveryOption.spec.js index dcfdc7ea..98123a0c 100644 --- a/tests/unit/test/getDeliveryOption.spec.js +++ b/tests/unit/test/getDeliveryOption.spec.js @@ -8,13 +8,15 @@ const thursday = '2020-03-12'; const friday = '2020-03-13'; const saturday = '2020-03-14'; -const monday = '2020-03-16'; +const monday2 = '2020-03-16'; +const tuesday2 = '2020-03-17'; describe('Mocking delivery options request', () => { it.each` day | result | dropOffDelay | cutoff_time | deliverydays_window | dropoff_days | monday_delivery ${friday} | ${saturday} | ${0} | ${'12:30'} | ${7} | ${'1;2;3;4;5;6'} | ${0} - ${saturday} | ${monday} | ${0} | ${'14:30'} | ${7} | ${'1;2;3;4;5;6'} | ${1} + ${saturday} | ${monday2} | ${0} | ${'14:30'} | ${7} | ${'1;2;3;4;5;6'} | ${1} + ${saturday} | ${tuesday2} | ${0} | ${'00:01'} | ${7} | ${'1;2;3;4;5;6'} | ${0} ${tuesday} | ${thursday} | ${1} | ${'09:30'} | ${7} | ${'1;2;3;4;5;6'} | ${0} `('MyParcel: the next delivery date for $day is $result', ({ day, result, dropOffDelay, ...args }) => { MockDate.set(`${day}T10:00:00`); @@ -26,7 +28,7 @@ describe('Mocking delivery options request', () => { it.each` day | result | dropOffDelay | cutoff_time | deliverydays_window | dropoff_days | saturday_delivery ${friday} | ${saturday} | ${0} | ${'12:30'} | ${7} | ${'1;2;3;4;5;6'} | ${1} - ${saturday} | ${monday} | ${0} | ${'14:30'} | ${7} | ${'0;1;2;3'} | ${0} + ${saturday} | ${monday2} | ${0} | ${'14:30'} | ${7} | ${'0;1;2;3'} | ${0} ${tuesday} | ${thursday} | ${1} | ${'09:30'} | ${7} | ${'1;2;3;4;5;6'} | ${0} `('SendMyParcel: the next delivery date for $day is $result', ({ day, result, dropOffDelay, ...args }) => { MockDate.set(`${day}T10:00:00`);