From 2d3b7b420a86367305b5003340b5fd29801392a5 Mon Sep 17 00:00:00 2001 From: aleksandarm Date: Fri, 11 Oct 2024 14:00:27 +0200 Subject: [PATCH] fix: lint --- .../js/__tests__/applePayExpress.test.js | 613 ++++++++++++++++++ .../adyen_checkout/checkoutConfiguration.js | 10 +- .../adyen_checkout/renderGiftcardComponent.js | 5 +- .../default/js/applePayExpressCommon.js | 11 +- 4 files changed, 624 insertions(+), 15 deletions(-) create mode 100644 src/cartridges/app_adyen_SFRA/cartridge/client/default/js/__tests__/applePayExpress.test.js diff --git a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/__tests__/applePayExpress.test.js b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/__tests__/applePayExpress.test.js new file mode 100644 index 000000000..f3f02e67b --- /dev/null +++ b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/__tests__/applePayExpress.test.js @@ -0,0 +1,613 @@ +/** + * @jest-environment jsdom + */ +const applePayExpressModule = require('../applePayExpressCommon'); +const formatCustomerObject = applePayExpressModule.formatCustomerObject; +const handleAuthorised = applePayExpressModule.handleAuthorised; +const handleError = applePayExpressModule.handleError; +const callPaymentFromComponent = applePayExpressModule.callPaymentFromComponent; +const selectShippingMethod = applePayExpressModule.selectShippingMethod; +const getShippingMethod = applePayExpressModule.getShippingMethod; +const initializeCheckout = applePayExpressModule.initializeCheckout; +const createApplePayButton = applePayExpressModule.createApplePayButton; + +const APPLE_PAY = 'applepay'; +const mockCreate = jest.fn(); + +let getPaymentMethods = applePayExpressModule.getPaymentMethods; +let spy; + +global.checkout = { create: mockCreate }; +global.fetch = jest.fn(); + +jest.mock('../applePayExpressCommon', () => ({ + handleAuthorised: jest.fn(), + handleError: jest.fn(), + getPaymentMethods: jest.fn(), +})); + +beforeAll(() => { + spy = jest.spyOn(document, 'querySelector'); +}); + +describe('formatCustomerObject', () => { + it('should correctly format customer and billing data', () => { + const customerData = { + addressLines: ['123 Main St', 'Apt 4B'], + locality: 'Springfield', + country: 'United States', + countryCode: 'US', + givenName: 'John', + familyName: 'Doe', + emailAddress: 'john.doe@example.com', + postalCode: '12345', + administrativeArea: 'IL', + phoneNumber: '555-555-5555', + }; + + const billingData = { + addressLines: ['456 Oak St'], + locality: 'Shelbyville', + country: 'United States', + countryCode: 'US', + givenName: 'John', + familyName: 'Doe', + postalCode: '67890', + administrativeArea: 'IN', + }; + + const expectedOutput = { + addressBook: { + addresses: {}, + preferredAddress: { + address1: '123 Main St', + address2: 'Apt 4B', + city: 'Springfield', + countryCode: { + displayValue: 'United States', + value: 'US', + }, + firstName: 'John', + lastName: 'Doe', + ID: 'john.doe@example.com', + postalCode: '12345', + stateCode: 'IL', + }, + }, + billingAddressDetails: { + address1: '456 Oak St', + address2: null, + city: 'Shelbyville', + countryCode: { + displayValue: 'United States', + value: 'US', + }, + firstName: 'John', + lastName: 'Doe', + postalCode: '67890', + stateCode: 'IN', + }, + customer: {}, + profile: { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + phone: '555-555-5555', + }, + }; + + const result = formatCustomerObject(customerData, billingData); + expect(result).toEqual(expectedOutput); + }); + + it('should handle missing address lines in billing data', () => { + const customerData = { + addressLines: ['123 Main St', 'Apt 4B'], + locality: 'Springfield', + country: 'United States', + countryCode: 'US', + givenName: 'Jane', + familyName: 'Doe', + emailAddress: 'jane.doe@example.com', + postalCode: '12345', + administrativeArea: 'IL', + phoneNumber: '555-123-4567', + }; + + const billingData = { + addressLines: ['789 Elm St'], + locality: 'Capital City', + country: 'United States', + countryCode: 'US', + givenName: 'Jane', + familyName: 'Doe', + postalCode: '98765', + administrativeArea: 'CA', + }; + + const expectedOutput = { + addressBook: { + addresses: {}, + preferredAddress: { + address1: '123 Main St', + address2: 'Apt 4B', + city: 'Springfield', + countryCode: { + displayValue: 'United States', + value: 'US', + }, + firstName: 'Jane', + lastName: 'Doe', + ID: 'jane.doe@example.com', + postalCode: '12345', + stateCode: 'IL', + }, + }, + billingAddressDetails: { + address1: '789 Elm St', + address2: null, + city: 'Capital City', + countryCode: { + displayValue: 'United States', + value: 'US', + }, + firstName: 'Jane', + lastName: 'Doe', + postalCode: '98765', + stateCode: 'CA', + }, + customer: {}, + profile: { + firstName: 'Jane', + lastName: 'Doe', + email: 'jane.doe@example.com', + phone: '555-123-4567', + }, + }; + + const result = formatCustomerObject(customerData, billingData); + expect(result).toEqual(expectedOutput); + }); + + it('should handle customer data with a single address line', () => { + const customerData = { + addressLines: ['123 Main St'], + locality: 'Springfield', + country: 'United States', + countryCode: 'US', + givenName: 'Alice', + familyName: 'Johnson', + emailAddress: 'alice.johnson@example.com', + postalCode: '54321', + administrativeArea: 'TX', + phoneNumber: '555-678-9101', + }; + + const billingData = { + addressLines: ['987 Maple St'], + locality: 'Metropolis', + country: 'United States', + countryCode: 'US', + givenName: 'Alice', + familyName: 'Johnson', + postalCode: '76543', + administrativeArea: 'FL', + }; + + const expectedOutput = { + addressBook: { + addresses: {}, + preferredAddress: { + address1: '123 Main St', + address2: null, + city: 'Springfield', + countryCode: { + displayValue: 'United States', + value: 'US', + }, + firstName: 'Alice', + lastName: 'Johnson', + ID: 'alice.johnson@example.com', + postalCode: '54321', + stateCode: 'TX', + }, + }, + billingAddressDetails: { + address1: '987 Maple St', + address2: null, + city: 'Metropolis', + countryCode: { + displayValue: 'United States', + value: 'US', + }, + firstName: 'Alice', + lastName: 'Johnson', + postalCode: '76543', + stateCode: 'FL', + }, + customer: {}, + profile: { + firstName: 'Alice', + lastName: 'Johnson', + email: 'alice.johnson@example.com', + phone: '555-678-9101', + }, + }; + + const result = formatCustomerObject(customerData, billingData); + expect(result).toEqual(expectedOutput); + }); +}); + +describe('handleAuthorised', () => { + let mockResolveApplePay; + let mockQuerySelector; + let mockResultInput; + let mockFormSubmit; + + beforeEach(() => { + mockResolveApplePay = jest.fn(); + mockResultInput = { + value: '', + }; + mockFormSubmit = jest.fn(); + mockQuerySelector = jest.spyOn(document, 'querySelector').mockImplementation((selector) => { + if (selector === '#result') { + return mockResultInput; + } + if (selector === '#showConfirmationForm') { + return { + submit: mockFormSubmit, + }; + } + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should handle authorized response and update the result input field', () => { + const response = { + fullResponse: { + pspReference: 'ABC123', + resultCode: 'Authorised', + paymentMethod: 'applepay', + donationToken: 'DONATION123', + amount: { + value: 1000, + currency: 'USD', + }, + }, + }; + + handleAuthorised(response, mockResolveApplePay); + expect(mockResolveApplePay).toHaveBeenCalled(); + expect(mockResultInput.value).toBe( + JSON.stringify({ + pspReference: 'ABC123', + resultCode: 'Authorised', + paymentMethod: 'applepay', + donationToken: 'DONATION123', + amount: { + value: 1000, + currency: 'USD', + }, + }) + ); + expect(mockFormSubmit).toHaveBeenCalled(); + }); + + it('should handle case where paymentMethod is missing but available in additionalData', () => { + const response = { + fullResponse: { + pspReference: 'XYZ789', + resultCode: 'Authorised', + additionalData: { + paymentMethod: 'creditcard', + }, + donationToken: 'DONATION456', + amount: { + value: 500, + currency: 'EUR', + }, + }, + }; + + handleAuthorised(response, mockResolveApplePay); + expect(mockResolveApplePay).toHaveBeenCalled(); + expect(mockResultInput.value).toBe( + JSON.stringify({ + pspReference: 'XYZ789', + resultCode: 'Authorised', + paymentMethod: 'creditcard', + donationToken: 'DONATION456', + amount: { + value: 500, + currency: 'EUR', + }, + }) + ); + expect(mockFormSubmit).toHaveBeenCalled(); + }); + + it('should handle case where some optional fields are missing', () => { + const response = { + fullResponse: { + pspReference: 'LMN456', + resultCode: 'Authorised', + amount: { + value: 750, + currency: 'GBP', + }, + }, + }; + handleAuthorised(response, mockResolveApplePay); + expect(mockResolveApplePay).toHaveBeenCalled(); + expect(mockResultInput.value).toBe( + JSON.stringify({ + pspReference: 'LMN456', + resultCode: 'Authorised', + paymentMethod: undefined, + donationToken: undefined, + amount: { + value: 750, + currency: 'GBP', + }, + }) + ); + expect(mockFormSubmit).toHaveBeenCalled(); + }); +}); + +describe('handleError', () => { + let mockRejectApplePay; + let mockQuerySelector; + let mockResultInput; + let mockFormSubmit; + + beforeEach(() => { + mockRejectApplePay = jest.fn(); + mockResultInput = { + value: '', + }; + mockFormSubmit = jest.fn(); + mockQuerySelector = jest.spyOn(document, 'querySelector').mockImplementation((selector) => { + if (selector === '#result') { + return mockResultInput; + } + if (selector === '#showConfirmationForm') { + return { + submit: mockFormSubmit, + }; + } + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should handle the error correctly and update the result input field', () => { + handleError(mockRejectApplePay); + expect(mockRejectApplePay).toHaveBeenCalled(); + expect(mockResultInput.value).toBe( + JSON.stringify({ + error: true, + }) + ); + expect(mockFormSubmit).toHaveBeenCalled(); + }); +}); + +describe('callPaymentFromComponent', () => { + const mockResolveApplePay = jest.fn(); + const mockRejectApplePay = jest.fn(); + const mockData = { some: 'data' }; + let mockElementDiv; + let mockElementForm + + beforeEach(() => { + jest.clearAllMocks(); + window.paymentFromComponentURL = '/test-url'; + window.showConfirmationAction = '/confirmation-action'; + mockElementForm = document.createElement('form'); + mockElementForm.setAttribute("id", "showConfirmationForm"); + mockElementDiv = document.createElement('div'); + mockElementDiv.setAttribute("id", "additionalDetailsHidden"); + spy.mockReturnValue(mockElementForm); + spy.mockReturnValue(mockElementDiv); + }); + + it('should call rejectApplePay on ajax fail', async () => { + global.$.ajax = jest.fn().mockImplementation(({ success }) => ({ + fail: (callback) => { + callback(); + }, + })); + await callPaymentFromComponent(mockData, mockResolveApplePay, mockRejectApplePay); + expect(mockRejectApplePay).toHaveBeenCalled(); + }); +}); + + +describe('selectShippingMethod', () => { + const mockShipmentUUID = 'test-shipment-uuid'; + const mockID = 'test-method-id'; + const mockBasketId = 'test-basket-id'; + const mockResponse = { status: 200, json: jest.fn().mockResolvedValue({}) }; + + beforeEach(() => { + jest.clearAllMocks(); + window.selectShippingMethodUrl = '/test-select-shipping-url'; + }); + + it('should send correct request to fetch with valid parameters', async () => { + fetch.mockResolvedValue(mockResponse); + const result = await selectShippingMethod( + { shipmentUUID: mockShipmentUUID, ID: mockID }, + mockBasketId + ); + expect(fetch).toHaveBeenCalledWith(window.selectShippingMethodUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + paymentMethodType: APPLE_PAY, + shipmentUUID: mockShipmentUUID, + methodID: mockID, + basketId: mockBasketId, + }), + }); + expect(result).toEqual(mockResponse); + }); + + it('should handle fetch rejection', async () => { + fetch.mockRejectedValue(new Error('Fetch failed')); + try { + await selectShippingMethod( + { shipmentUUID: mockShipmentUUID, ID: mockID }, + mockBasketId + ); + } catch (error) { + expect(error.message).toBe('Fetch failed'); + } + }); +}); + + +describe('getShippingMethod', () => { + const mockBasketId = 'test-basket-id'; + const mockResponse = { status: 200, json: jest.fn().mockResolvedValue({}) }; + + beforeEach(() => { + jest.clearAllMocks(); + window.shippingMethodsUrl = '/test-shipping-methods-url'; + }); + + it('should send correct request to fetch with shippingContact', async () => { + const shippingContact = { + locality: 'Test City', + country: 'Test Country', + countryCode: 'TC', + administrativeArea: 'Test State', + postalCode: '12345', + }; + fetch.mockResolvedValue(mockResponse); + const result = await getShippingMethod(shippingContact, mockBasketId); + expect(fetch).toHaveBeenCalledWith(window.shippingMethodsUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + paymentMethodType: APPLE_PAY, + basketId: mockBasketId, + address: { + city: shippingContact.locality, + country: shippingContact.country, + countryCode: shippingContact.countryCode, + stateCode: shippingContact.administrativeArea, + postalCode: shippingContact.postalCode, + }, + }), + }); + expect(result).toEqual(mockResponse); + }); + + it('should send correct request to fetch without shippingContact', async () => { + fetch.mockResolvedValue(mockResponse); + const result = await getShippingMethod(null, mockBasketId); + expect(fetch).toHaveBeenCalledWith(window.shippingMethodsUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + paymentMethodType: APPLE_PAY, + basketId: mockBasketId, + }), + }); + expect(result).toEqual(mockResponse); + }); + + it('should handle fetch rejection', async () => { + fetch.mockRejectedValue(new Error('Fetch failed')); + try { + await getShippingMethod(null, mockBasketId); + } catch (error) { + expect(error.message).toBe('Fetch failed'); + } + }); +}); + +describe('initializeCheckout', () => { + let mockPaymentMethodsResponse; + let AdyenCheckout; + + beforeEach(() => { + jest.clearAllMocks(); + window.environment = 'test-env'; + window.clientKey = 'test-client-key'; + window.locale = 'en-US'; + mockPaymentMethodsResponse = { + json: jest.fn().mockResolvedValue({ + applicationInfo: { + some: 'info', + }, + }), + }; + global.fetch = jest.fn().mockResolvedValueOnce({ + ok: true, + json: jest.fn().mockResolvedValue({ + applicationInfo: { + some: 'info', + }, + }), + }) + getPaymentMethods = jest.fn().mockImplementation({ + json: jest.fn().mockResolvedValue({ + applicationInfo: { + some: 'info', + }, + }), + }) + AdyenCheckout = jest.fn().mockResolvedValueOnce({}) + }); + + it('should handle errors when getPaymentMethods fails', async () => { + try { + await initializeCheckout(); + } catch (error) { + expect(error.message).toBe('Fetch failed'); + } + }); +}); + +describe('createApplePayButton', () => { + const applePayButtonConfig = { configKey: 'configValue' }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should call checkout.create with APPLE_PAY and applePayButtonConfig', async () => { + const mockButtonInstance = { + mount: {} + } + mockCreate.mockImplementationOnce(() => (mockButtonInstance)); + const result = await createApplePayButton(applePayButtonConfig); + expect(result).toMatchObject(mockButtonInstance); + }); + + it('should handle errors thrown by checkout.create', async () => { + const mockError = new Error('Failed to create Apple Pay button'); + mockCreate.mockRejectedValue(mockError); + try { + await createApplePayButton(applePayButtonConfig); + } catch (error) { + expect(error).toBe(mockError); + } + }); +}); \ No newline at end of file diff --git a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/checkoutConfiguration.js b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/checkoutConfiguration.js index 0f428d395..d2c968fcf 100644 --- a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/checkoutConfiguration.js +++ b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/checkoutConfiguration.js @@ -192,9 +192,8 @@ function getGiftCardConfig() { async: false, success: (data) => { giftcardBalance = data.balance; - document.querySelector( - 'button[value="submit-payment"]', - ).disabled = false; + document.querySelector('button[value="submit-payment"]').disabled = + false; if (data.resultCode === constants.SUCCESS) { const { giftCardsInfoMessageContainer, @@ -220,9 +219,8 @@ function getGiftCardConfig() { initialPartialObject.totalDiscountedAmount; }); - document.querySelector( - 'button[value="submit-payment"]', - ).disabled = true; + document.querySelector('button[value="submit-payment"]').disabled = + true; giftCardsInfoMessageContainer.innerHTML = ''; giftCardsInfoMessageContainer.classList.remove( 'gift-cards-info-message-container', diff --git a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/renderGiftcardComponent.js b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/renderGiftcardComponent.js index dc16d6139..e2f73a19b 100644 --- a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/renderGiftcardComponent.js +++ b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/adyen_checkout/renderGiftcardComponent.js @@ -98,9 +98,8 @@ function removeGiftCards() { giftCardsInfoMessageContainer.classList.remove( 'gift-cards-info-message-container', ); - document.querySelector( - 'button[value="submit-payment"]', - ).disabled = false; + document.querySelector('button[value="submit-payment"]').disabled = + false; if (res.resultCode === constants.RECEIVED) { document diff --git a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/applePayExpressCommon.js b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/applePayExpressCommon.js index 2bfc67b59..729e432c1 100644 --- a/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/applePayExpressCommon.js +++ b/src/cartridges/app_adyen_SFRA/cartridge/client/default/js/applePayExpressCommon.js @@ -188,12 +188,6 @@ async function init() { amount: JSON.parse(window.basketAmount), requiredShippingContactFields: ['postalAddress', 'email', 'phone'], requiredBillingContactFields: ['postalAddress', 'phone'], - // shippingMethods: shippingMethodsData.shippingMethods.map((sm) => ({ - // label: sm.displayName, - // detail: sm.description, - // identifier: sm.ID, - // amount: `${sm.shippingCost.value}`, - // })), onAuthorized: async (resolve, reject, event) => { try { const customerData = event.payment.shippingContact; @@ -362,4 +356,9 @@ module.exports = { callPaymentFromComponent, formatCustomerObject, init, + selectShippingMethod, + getShippingMethod, + getPaymentMethods, + initializeCheckout, + createApplePayButton, };