Skip to content

Commit

Permalink
Feature/sfi 991 handle execute analytics (#1201)
Browse files Browse the repository at this point in the history
* fix: lint errors

* feat: make responses same for all calls

* feat: tests for creating attempt id

* chore: bump playwright version

* chore: additional logs

* chore: info log

* chore: revert changes

* chore: add one more line for e2e tests to pass
  • Loading branch information
amihajlovski authored Oct 31, 2024
1 parent 3535f27 commit bbbbe33
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,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,
Expand All @@ -217,9 +216,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',
Expand Down Expand Up @@ -274,7 +272,8 @@ function getGiftCardConfig() {
}

function handleOnChange(state) {
const { type } = state.data.paymentMethod;
const { paymentMethod } = state.data;
const { type } = paymentMethod;
store.isValid = state.isValid;
if (!store.componentsObj[type]) {
store.componentsObj[type] = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const { createCheckoutAttemptId } = require('../analyticsService');

const AdyenHelper = {
getApplicationInfo: jest.fn(),
};

const execute = jest.fn();
const constants = {
SERVICE: {
ADYEN_ANALYTICS: 'ADYEN_ANALYTICS',
},
};

const AdyenLogs = {
error_log: jest.fn(),
};

global.AdyenHelper = AdyenHelper;
global.execute = execute;
global.constants = constants;
global.AdyenLogs = AdyenLogs;

describe('createCheckoutAttemptId', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should return checkoutAttemptId when the execute function is successful', () => {
const mockCheckoutAttemptId = 'test-checkout-attempt-id';
const mockApplicationInfo = { name: 'testApp' };

AdyenHelper.getApplicationInfo.mockReturnValue(mockApplicationInfo);
execute.mockReturnValue({ checkoutAttemptId: mockCheckoutAttemptId });

const result = createCheckoutAttemptId();

setTimeout(() => {
expect(AdyenHelper.getApplicationInfo).toHaveBeenCalled();
expect(execute).toHaveBeenCalledWith(constants.SERVICE.ADYEN_ANALYTICS, {
applicationInfo: mockApplicationInfo,
channel: 'Web',
platform: 'Web',
});
expect(result).toEqual({ data: mockCheckoutAttemptId });
}, 0)
});

it('should return an error object and log error when execute throws an error', () => {
const mockError = new Error('Execution failed');
AdyenHelper.getApplicationInfo.mockReturnValue({});
execute.mockImplementation(() => {
throw mockError;
});

const result = createCheckoutAttemptId();

setTimeout(() => {
expect(AdyenHelper.getApplicationInfo).toHaveBeenCalled();
expect(AdyenLogs.error_log).toHaveBeenCalledWith(
'createCheckoutAttemptId for /analytics call failed:',
mockError
);
expect(result).toEqual({ error: true });
}, 0)
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ function createAnalyticsEvent(
customObj.custom.eventType = eventType;
customObj.custom.eventStatus = eventStatus;
customObj.custom.eventCode = eventCode;
customObj.custom.processingStatus =
constants.processingStatus.NOT_PROCESSED;
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,52 @@
const UUIDUtils = require('dw/util/UUIDUtils');

const AdyenHelper = require('*/cartridge/adyen/utils/adyenHelper');
const AdyenConfigs = require('*/cartridge/adyen/utils/adyenConfigs');
const constants = require('*/cartridge/adyen/config/constants');
const AdyenLogs = require('*/cartridge/adyen/logs/adyenCustomLogs');

function execute(serviceType, requestObject, checkoutAttemptID = '') {
const service = AdyenHelper.getService(serviceType);
if (service === null) {
throw new Error(`Could not create ${serviceType} service object`);
}

const clientKey = AdyenConfigs.getAdyenClientKey();
let serviceUrl = service.getURL();
serviceUrl += `/${checkoutAttemptID}?clientKey=${clientKey}`;
service.setURL(serviceUrl);

const apiKey = AdyenConfigs.getAdyenApiKey();
const uuid = UUIDUtils.createUUID();
service.addHeader('Content-type', 'application/json');
service.addHeader('charset', 'UTF-8');
service.addHeader('X-API-KEY', apiKey);
service.addHeader('Idempotency-Key', uuid);

const callResult = service.call(JSON.stringify(requestObject));
if (!callResult.isOk()) {
throw new Error(
`${serviceType} service call error code${callResult
.getError()
.toString()} Error => ResponseStatus: ${callResult.getStatus()} | ResponseErrorText: ${callResult.getErrorMessage()} | ResponseText: ${callResult.getMsg()}`,
);
}

const parsedResponse = JSON.parse(callResult.object?.getText());
return parsedResponse || callResult.status;
}

function createCheckoutAttemptId() {
try {
const analyticsResponse = {};
const requestObject = {
applicationInfo: AdyenHelper.getApplicationInfo(),
channel: 'Web',
platform: 'Web',
};

const response = AdyenHelper.executeCall(
constants.SERVICE.ADYEN_ANALYTICS,
requestObject,
);

analyticsResponse.attemptId = response.checkoutAttemptId;
const response = execute(constants.SERVICE.ADYEN_ANALYTICS, requestObject);

return analyticsResponse;
return { data: response.checkoutAttemptId };
} catch (error) {
AdyenLogs.error_log(
'createCheckoutAttemptId for /analytics call failed:',
Expand All @@ -32,19 +60,18 @@ function submitData(requestObject, attemptIdParam = null) {
try {
let attemptId = attemptIdParam;

// If attemptId is not provided as a parameter, generate it
if (!attemptId) {
const initialAnalyticsCall = createCheckoutAttemptId();
attemptId = initialAnalyticsCall.attemptId;
attemptId = initialAnalyticsCall.data;
}

const response = AdyenHelper.executeCall(
const response = execute(
constants.SERVICE.ADYEN_ANALYTICS,
requestObject,
attemptId,
);

return response;
return { data: response };
} catch (error) {
AdyenLogs.error_log('submitData for /analytics call failed:', error);
return { error: true };
Expand All @@ -54,4 +81,5 @@ function submitData(requestObject, attemptIdParam = null) {
module.exports = {
createCheckoutAttemptId,
submitData,
execute,
};
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,13 @@ function processData() {
);

const payload = createRequestObjectForAllReferenceIds(groupedObjects);
const submissionSuccess = AnalyticsService.submitData(payload);
if (submissionSuccess) {
const submission = AnalyticsService.submitData(payload);
if (submission.data) {
customObjectsToDelete.forEach((customObject) => {
deleteCustomObject(customObject);
});
} else {
AdyenLogs.error_log('Failed to submit full payload for grouped objects.');
// This will be triggered upon completion of SFI-991
customObjectsToDelete.forEach((customObject) => {
updateProcessingStatus(
customObject,
Expand Down
22 changes: 10 additions & 12 deletions src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ let adyenHelperObj = {
}
},

executeCall(serviceType, requestObject, checkoutAttemptID = '') {
executeCall(serviceType, requestObject = '') {
const service = this.getService(serviceType);
if (service === null) {
throw new Error(`Could not create ${serviceType} service object`);
Expand All @@ -938,13 +938,6 @@ let adyenHelperObj = {
service.setURL(serviceUrl);
}

if (serviceType === constants.SERVICE.ADYEN_ANALYTICS) {
const clientKey = AdyenConfigs.getAdyenClientKey();
let serviceUrl = service.getURL();
serviceUrl += `/${checkoutAttemptID}?clientKey=${clientKey}`;
service.setURL(serviceUrl);
}

const maxRetries = constants.MAX_API_RETRIES;
const apiKey = AdyenConfigs.getAdyenApiKey();
const uuid = UUIDUtils.createUUID();
Expand Down Expand Up @@ -975,10 +968,15 @@ let adyenHelperObj = {
if (!resultObject || !resultObject.getText()) {
throw new Error(`No correct response from ${serviceType} service call`);
}
// Once analytics executeCall is separated in SFI-991, this if condition can be removed
if (serviceType !== constants.SERVICE.ADYEN_ANALYTICS) {
analyticsEvent.createAnalyticsEvent(session.sessionID, serviceType, analyticsConstants.eventType.END, analyticsConstants.eventStatus.EXPECTED, analyticsConstants.eventCode.INFO);
}

analyticsEvent.createAnalyticsEvent(
session.sessionID,
serviceType,
analyticsConstants.eventType.END,
analyticsConstants.eventStatus.EXPECTED,
analyticsConstants.eventCode.INFO
);

return JSON.parse(resultObject.getText());
},
};
Expand Down
2 changes: 1 addition & 1 deletion tests/playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"yazl": "^2.5.1"
},
"devDependencies": {
"@playwright/test": "^1.42.1"
"@playwright/test": "^1.47.2"
},
"scripts": {
"test": "npx playwright test",
Expand Down

0 comments on commit bbbbe33

Please sign in to comment.