UNPKG

@recras/online-booking-js

Version:

JS library for easy integration of Recras online booking and voucher sales

714 lines (614 loc) 23.8 kB
const mockGetSetting = (name) => ({ slug: name, waarde: '', }); const packageOneProduct = { id: 7, onlineboeking_contactformulier_id: 4, regels: [ { id: 42, max: 8, onlineboeking_aantalbepalingsmethode: "invullen_door_gebruiker", product: { minimum_aantal: 1, vereist_product: [], } }, ], }; const packageMinMaxAmounts = { id: 26, onlineboeking_contactformulier_id: 4, regels: [ { id: 669, max: 8, onlineboeking_aantalbepalingsmethode: "invullen_door_gebruiker", product: { minimum_aantal: 5, vereist_product: [], } }, { id: 1337, max: null, onlineboeking_aantalbepalingsmethode: "invullen_door_gebruiker", product: { minimum_aantal: 1, vereist_product: [], } }, { id: 420, aantal_personen: 10, max: 80, onlineboeking_aantalbepalingsmethode: "invullen_door_gebruiker", product: { minimum_aantal: 1, vereist_product: [], } }, ], }; const packages = [packageOneProduct, packageMinMaxAmounts]; describe('RecrasBooking', () => { describe('constructor', () => { describe('locale', () => { it('has default locale', () => { let options = new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', }); let rb = new RecrasBooking(options); expect(rb.languageHelper.locale).toEqual('nl_NL'); }); it('can set locale', () => { let options = new RecrasOptions({ element: document.createElement('div'), locale: 'en_GB', recras_hostname: 'demo.recras.nl' }); let rb = new RecrasBooking(options); expect(rb.languageHelper.locale).toEqual('en_GB'); }); it('invalid locale falls back to default', () => { let options = new RecrasOptions({ element: document.createElement('div'), locale: 'xx_zz', recras_hostname: 'demo.recras.nl' }); let rb = new RecrasBooking(options); expect(rb.languageHelper.locale).toEqual('nl_NL'); }); }); }); describe('amountsValid', () => { let rb; let inputLessThanMinimum; let inputMoreThanMaximum; beforeEach(() => { let mainEl = document.createElement('div'); rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', })); inputLessThanMinimum = document.createElement('input'); inputLessThanMinimum.value = 1; inputLessThanMinimum.dataset.packageId = '1'; inputMoreThanMaximum = document.createElement('input'); inputMoreThanMaximum.value = 4; inputMoreThanMaximum.dataset.packageId = '2'; let inputBookingSize = document.createElement('input'); inputBookingSize.id = 'bookingsize'; inputBookingSize.value = 1; mainEl.appendChild(inputLessThanMinimum); mainEl.appendChild(inputMoreThanMaximum); mainEl.appendChild(inputBookingSize); }); it('handles minimum amount', function() { const pack = { regels: [ { id: inputLessThanMinimum.dataset.packageId, aantal_personen: 2, onlineboeking_aantalbepalingsmethode: 'invullen_door_gebruiker', }, ], }; expect(rb.amountsValid(pack)).toBe(false); }); it('handles maximum amount', function() { const pack = { regels: [ { id: inputMoreThanMaximum.dataset.packageId, aantal_personen: 1, max: 2, onlineboeking_aantalbepalingsmethode: 'invullen_door_gebruiker', }, ], }; expect(rb.amountsValid(pack)).toBe(false); }); it('handles booking size minimum', function() { const pack = { regels: [ { aantal_personen: 1, onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', product: { minimum_aantal: 2, } }, ], }; expect(rb.amountsValid(pack)).toBe(false); }); it('handles zero products', function() { const pack = { regels: [ { id: inputLessThanMinimum.dataset.packageId, aantal_personen: 0, onlineboeking_aantalbepalingsmethode: 'invullen_door_gebruiker', }, ], }; inputLessThanMinimum.value = ''; expect(rb.amountsValid(pack)).toBe(false); }); it('handles happy path', function() { const pack = { regels: [ { id: inputLessThanMinimum.dataset.packageId, aantal_personen: 0, onlineboeking_aantalbepalingsmethode: 'invullen_door_gebruiker', }, ], }; expect(rb.amountsValid(pack)).toBe(true); }); }); describe('bookingSizeMaximum', () => { beforeEach(() => { this.rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', })); }); it('returns lowest value of booking size maximums', () => { let pack = { regels: [ { onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', max: 25, }, { onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', max: 42, }, ], }; expect(this.rb.bookingSizeMaximum(pack)).toBe(25); }); it('discards lines without maximum', () => { let pack = { regels: [ { onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', }, { onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', max: 42, }, ], }; expect(this.rb.bookingSizeMaximum(pack)).toBe(42); }); it('returns infinity when no line has a maximum', () => { let pack = { regels: [ { onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', }, { onlineboeking_aantalbepalingsmethode: 'boekingsgrootte', }, ], }; expect(this.rb.bookingSizeMaximum(pack)).toBe(99999); }); }); describe('getAvailableDays', () => { beforeEach(() => { this.rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', })); this.rb.postJson = jasmine.createSpy('postJson').and.callFake(() => new Promise(function(resolve) { resolve(); })); this.rb.bookingSize = () => 5; this.rb.productCountsBookingSize = () => [ { aantal: this.rb.bookingSize(), arrangementsregel_id: 42, }, ]; this.rb.productCountsNoBookingSize = () => [ { aantal: 5, arrangementsregel_id: 17, }, { aantal: 5, arrangementsregel_id: 9, }, { aantal: 8, arrangementsregel_id: 83, }, ]; }); it('should add "boekingsgrootte" parameter for packages with fixed programme', () => { this.rb.shouldShowBookingSize = () => true; this.rb.productCountsNoBookingSize = () => []; this.rb.getAvailableDays(1, new Date('2019-05-20 12:00:00Z'), new Date('2019-05-27 12:00:00Z')); expect(this.rb.postJson).toHaveBeenCalledWith('onlineboeking/beschikbaredagen', { arrangement_id: 1, begin: '2019-05-20', eind: '2019-05-27', producten: [], boekingsgrootte: this.rb.bookingSize(), }); }); it('should only include "producten" parameter for packages with choice programme', () => { this.rb.shouldShowBookingSize = () => false; this.rb.getAvailableDays(1, new Date('2019-05-20 12:00:00Z'), new Date('2019-05-27 12:00:00Z')); expect(this.rb.postJson).toHaveBeenCalledWith('onlineboeking/beschikbaredagen', { arrangement_id: 1, begin: '2019-05-20', eind: '2019-05-27', producten: this.rb.productCountsNoBookingSize(), }); }); it('should include both "producten" and "boekingsgrootte" parameters for packages with mixed programme', () => { this.rb.shouldShowBookingSize = () => true; this.rb.getAvailableDays(1, new Date('2019-05-20 12:00:00Z'), new Date('2019-05-27 12:00:00Z')); expect(this.rb.postJson).toHaveBeenCalledWith('onlineboeking/beschikbaredagen', { arrangement_id: 1, begin: '2019-05-20', eind: '2019-05-27', producten: this.rb.productCountsNoBookingSize(), boekingsgrootte: this.rb.bookingSize(), }); }); }); describe('selectSingleTime', () => { beforeEach(() => { let mainEl = document.createElement('div'); this.rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', })); let timesEl = document.createElement('select'); timesEl.id = 'recras-onlinebooking-time'; timesEl.classList.add('recras-onlinebooking-time'); mainEl.appendChild(timesEl); }); it('does not select a timeslot when there are multiple', () => { this.rb.showTimes(['10:00', '11:00']); this.rb.selectSingleTime(); expect(this.rb.findElements('#recras-onlinebooking-time option[value]:checked').length).toEqual(0); }); it('selects the timeslot when there is only one', () => { this.rb.showTimes(['10:00']); this.rb.selectSingleTime(); expect(this.rb.findElements('#recras-onlinebooking-time option[value]:checked').length).toEqual(1); }); }); describe('submitBooking', () => { beforeEach(() => { this.rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', })); this.rb.selectedPackage = { mag_online_geboekt_worden_direct_betalen: false, mag_online_geboekt_worden_achteraf_betalen: true, regels: [], }; this.rb.appliedVouchers = {}; this.rb.contactForm = new RecrasContactForm(new RecrasOptions({ element: document.createElement('div'), form_id: 1, recras_hostname: 'demo.recras.nl', })); }); it('should select only possible payment method by default', () => { this.rb.postJson = jasmine.createSpy('postJson').and.callFake(() => { return new Promise(function(resolve) { resolve(); }); }); this.rb.contactForm.generateJson = jasmine.createSpy('generateJson').and.callFake(() => { return new Promise(function(resolve) { resolve(); }); }); this.rb.bookingSize = () => 5; this.rb.submitBooking();// expect(this.rb.postJson).toHaveBeenCalledWith('onlineboeking/reserveer', jasmine.objectContaining({ betaalmethode: 'factuur', })); }); }); describe('Option "package_id"', () => { let rb; const package1 = { id: 1, }; const package2 = { id: 2, }; const package3 = { id: 3, }; const package4 = { id: 4, }; const getPackagesMock = () => [package1, package2, package3, package4]; it('works with a single package', async () => { rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', package_id: 2, })); spyOn(rb, 'showPackages'); spyOn(rb, 'changePackage'); rb.getPackages = getPackagesMock; await rb.promise; expect(rb.changePackage).toHaveBeenCalledWith(2); expect(rb.showPackages).not.toHaveBeenCalled(); }); it('works with a single-item array', async () => { rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', package_id: [2], })); spyOn(rb, 'showPackages'); spyOn(rb, 'changePackage'); rb.getPackages = getPackagesMock; await rb.promise; expect(rb.changePackage).toHaveBeenCalledWith(2); expect(rb.showPackages).not.toHaveBeenCalled(); }); it('filters the visible packages', async () => { rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', package_id: [2, 3], })); spyOn(rb, 'showPackages'); rb.getPackages = getPackagesMock; await rb.promise; expect(rb.showPackages).toHaveBeenCalledWith([package2, package3]); }); it('works without option', async () => { rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', })); spyOn(rb, 'showPackages'); rb.getPackages = getPackagesMock; await rb.promise; expect(rb.showPackages).toHaveBeenCalledWith([package1, package2, package3, package4]); }); }); describe('requiredAmount', () => { let rb; beforeEach(() => { rb = new RecrasBooking(new RecrasOptions({ element: document.createElement('div'), recras_hostname: 'demo.recras.nl', })); }); it('should calculate "needs 3 per 2, rounded up"', () => expect(rb.requiredAmount(1, { aantal: 3, per_x_aantal: 2, afronding: 'boven', })).toEqual(3) ); it('should calculate "needs 4 per 2, rounded down"', () => expect(rb.requiredAmount(3, { aantal: 4, per_x_aantal: 2, afronding: 'beneden', })).toEqual(4) ); }); describe('checkMinMaxAmounts', () => { let rb; beforeEach(() => { let mainEl = document.createElement('div'); mainEl.id = 'onlinebooking'; document.body.appendChild(mainEl); rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: 26, })); spyOn(rb, 'setMinMaxAmountWarning'); // Mocks rb.getSetting = mockGetSetting; rb.getPackages = () => { rb.packages = packages; return packages; }; }); it('gives error if amount is less than the product minimum', async () => { await rb.promise; let el = document.getElementById('packageline0'); el.value = '1'; el.dispatchEvent(new Event('input')); expect(rb.setMinMaxAmountWarning).toHaveBeenCalledWith('packageline0', 5, 'minimum'); }); it('gives error if amount is more than the maximum', async () => { await rb.promise; let el = document.getElementById('packageline0'); el.value = '15'; el.dispatchEvent(new Event('input')); expect(rb.setMinMaxAmountWarning).toHaveBeenCalledWith('packageline0', 8, 'maximum'); }); it('does not give error if there is no maximum', async () => { await rb.promise; let el = document.getElementById('packageline1'); el.value = '2'; el.dispatchEvent(new Event('input')); expect(rb.setMinMaxAmountWarning).not.toHaveBeenCalled(); }); }); describe('prefillDateIfPossible', () => { let rb; let mainEl = document.createElement('div'); mainEl.id = 'onlinebooking'; document.body.appendChild(mainEl); it('does not set date if date is invalid', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: 7, date: '2050-15-66', })); await rb.promise; expect(rb.prefillDateIfPossible()).toBe(false); }); it('does not set date if date is in the past', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: 7, date: '2019-06-28', })); await rb.promise; expect(rb.prefillDateIfPossible()).toBe(false); }); it('does not set date if no package is selected', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', date: '2050-06-28', })); await rb.promise; expect(rb.prefillDateIfPossible()).toBe(false); }); it('does not set date if multiple packages are selected', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: [1, 2, 3], date: '2050-06-28', })); await rb.promise; expect(rb.prefillDateIfPossible()).toBe(false); }); it('sets date if date is valid and one package is selected', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: [7], date: '2050-06-28', })); await rb.promise; expect(rb.prefillDateIfPossible()).toBe(true); }); }); describe('prefillTimeIfPossible', () => { let rb; let mainEl = document.createElement('div'); mainEl.id = 'onlinebooking'; document.body.appendChild(mainEl); it('does not set time if time is invalid', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: 7, date: '2050-06-28', time: '30:60', })); await rb.promise; expect(rb.prefillTimeIfPossible()).toBe(false); }); it('sets time if time is valid', async () => { rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: [7], date: '2050-06-28', time: '10:00', })); await rb.promise; expect(rb.prefillTimeIfPossible()).toBe(true); }); }); describe('hasAtLeastOneProduct', () => { const pck = { id: 7, onlineboeking_contactformulier_id: 4, regels: [ { id: 42, max: 8, onlineboeking_aantalbepalingsmethode: "invullen_door_gebruiker", product: { minimum_aantal: 1, vereist_product: [], } }, ], }; beforeEach(() => { let mainEl = document.createElement('div'); mainEl.id = 'onlinebooking'; document.body.appendChild(mainEl); rb = new RecrasBooking(new RecrasOptions({ element: mainEl, recras_hostname: 'demo.recras.nl', package_id: 7, })); // Mocks rb.getSetting = mockGetSetting; rb.getPackages = () => { rb.packages = packages; return packages; }; }); it('returns true if booking size is enabled and greater than 0', async () => { await rb.promise; rb.shouldShowBookingSize = () => true; rb.bookingSize = () => 5; expect(rb.hasAtLeastOneProduct({})).toBe(true); }); it('returns true if there is at least one product selected', async () => { await rb.promise; let el = document.getElementById('packageline0'); el.value = '2'; expect(rb.hasAtLeastOneProduct(packageOneProduct)).toBe(true); }); it('returns false if booking size is enabled but 0 and no product is selected', async () => { await rb.promise; rb.shouldShowBookingSize = () => true; rb.bookingSize = () => 0; expect(rb.hasAtLeastOneProduct(packageOneProduct)).toBe(false); }); it('returns false if booking size is disabled and no product is selected', async () => { await rb.promise; rb.shouldShowBookingSize = () => false; expect(rb.hasAtLeastOneProduct(packageOneProduct)).toBe(false); }); }); });