mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
4215 lines
142 KiB
JavaScript
4215 lines
142 KiB
JavaScript
// ***********************************************
|
|
// This example commands.js shows you how to
|
|
// create various custom commands and overwrite
|
|
// existing commands.
|
|
//
|
|
// For more comprehensive examples of custom
|
|
// commands please read more here:
|
|
// https://on.cypress.io/custom-commands
|
|
// ***********************************************
|
|
//
|
|
//
|
|
// -- This is a parent command --
|
|
// Cypress.Commands.add('login', (email, password) => { ... })
|
|
//
|
|
//
|
|
// -- This is a child command --
|
|
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
|
//
|
|
//
|
|
// -- This is a dual command --
|
|
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
//
|
|
//
|
|
// -- This will overwrite an existing command --
|
|
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
|
|
|
// commands.js or your custom support file
|
|
import {
|
|
defaultErrorHandler,
|
|
extractIntegerAtEnd,
|
|
getValueByKey,
|
|
} from "../e2e/configs/Payment/Utils";
|
|
import { execConfig, validateConfig } from "../utils/featureFlags";
|
|
import * as RequestBodyUtils from "../utils/RequestBodyUtils";
|
|
import { isoTimeTomorrow, validateEnv } from "../utils/RequestBodyUtils.js";
|
|
import { handleRedirection } from "./redirectionHandler";
|
|
|
|
function logRequestId(xRequestId) {
|
|
if (xRequestId) {
|
|
cy.task("cli_log", "x-request-id -> " + xRequestId);
|
|
} else {
|
|
cy.task("cli_log", "x-request-id is not available in the response headers");
|
|
}
|
|
}
|
|
|
|
function validateErrorMessage(response, resData) {
|
|
if (resData.body.status !== "failed") {
|
|
expect(response.body.error_message, "error_message").to.be.null;
|
|
expect(response.body.error_code, "error_code").to.be.null;
|
|
}
|
|
}
|
|
|
|
//skip MIT using PMId if connector does not support MIT only
|
|
export function shouldSkipMitUsingPMId(connectorId) {
|
|
const skipConnectors = ["fiuu"];
|
|
return skipConnectors.includes(connectorId);
|
|
}
|
|
|
|
Cypress.Commands.add("healthCheck", (globalState) => {
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const url = `${baseUrl}/health`;
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body).to.equal("health is good");
|
|
} else {
|
|
throw new Error(
|
|
`Health Check failed with status: \`${response.status}\` and body: \`${response.body}\``
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"merchantCreateCallTest",
|
|
(merchantCreateBody, globalState) => {
|
|
const randomMerchantId = RequestBodyUtils.generateRandomString();
|
|
RequestBodyUtils.setMerchantId(merchantCreateBody, randomMerchantId);
|
|
globalState.set("merchantId", randomMerchantId);
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/accounts`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
body: merchantCreateBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
// Handle the response as needed
|
|
globalState.set("profileId", response.body.default_profile);
|
|
globalState.set("publishableKey", response.body.publishable_key);
|
|
globalState.set("merchantDetails", response.body.merchant_details);
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("merchantRetrieveCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/accounts/${merchant_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"], "content_headers").to.include(
|
|
"application/json"
|
|
);
|
|
expect(response.body.merchant_id, "merchant_id").to.equal(merchant_id);
|
|
expect(
|
|
response.body.payment_response_hash_key,
|
|
"payment_response_hash_key"
|
|
).to.not.be.null;
|
|
expect(response.body.publishable_key, "publishable_key").to.not.be.null;
|
|
cy.log("HI");
|
|
expect(response.body.default_profile, "default_profile").to.not.be.null;
|
|
expect(response.body.organization_id, "organization_id").to.not.be.null;
|
|
globalState.set("organizationId", response.body.organization_id);
|
|
|
|
if (globalState.get("publishableKey") === undefined) {
|
|
globalState.set("publishableKey", response.body.publishable_key);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("merchantDeleteCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
cy.request({
|
|
method: "DELETE",
|
|
url: `${globalState.get("baseUrl")}/accounts/${merchant_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body.merchant_id).to.equal(merchant_id);
|
|
expect(response.body.deleted).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("ListConnectorsFeatureMatrixCall", (globalState) => {
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const url = `${baseUrl}/feature_matrix`;
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body).to.have.property("connectors").and.not.empty;
|
|
expect(response.body.connectors).to.be.an("array").and.not.empty;
|
|
response.body.connectors.forEach((item) => {
|
|
expect(item).to.have.property("description").and.not.empty;
|
|
expect(item).to.have.property("category").and.not.empty;
|
|
expect(item).to.have.property("integration_status").and.not.empty;
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("merchantListCall", (globalState) => {
|
|
const organization_id = globalState.get("organizationId");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/accounts/list?organization_id=${organization_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
for (const key in response.body) {
|
|
expect(response.body[key]).to.have.property("merchant_id").and.not
|
|
.empty;
|
|
expect(response.body[key]).to.have.property("organization_id").and.not
|
|
.empty;
|
|
expect(response.body[key]).to.have.property("default_profile").and.not
|
|
.empty;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"merchantUpdateCall",
|
|
(merchantUpdateBody, globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
const organization_id = globalState.get("organizationId");
|
|
const publishable_key = globalState.get("publishableKey");
|
|
const merchant_details = globalState.get("merchantDetails");
|
|
|
|
merchantUpdateBody.merchant_id = merchant_id;
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/accounts/${merchant_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
body: merchantUpdateBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body.merchant_id).to.equal(merchant_id);
|
|
expect(response.body.publishable_key).to.equal(publishable_key);
|
|
expect(response.body.organization_id).to.equal(organization_id);
|
|
expect(response.body.merchant_details).to.not.equal(merchant_details);
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createBusinessProfileTest",
|
|
(createBusinessProfile, globalState, profilePrefix = "profile") => {
|
|
const apiKey = globalState.get("apiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const connectorId = globalState.get("connectorId");
|
|
const merchantId = globalState.get("merchantId");
|
|
const profileName = `${profilePrefix}_${RequestBodyUtils.generateRandomString(connectorId)}`;
|
|
const url = `${baseUrl}/account/${merchantId}/business_profile`;
|
|
|
|
createBusinessProfile.profile_name = profileName;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
body: createBusinessProfile,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
globalState.set(`${profilePrefix}Id`, response.body.profile_id);
|
|
if (response.status === 200) {
|
|
expect(response.body.profile_id).to.not.to.be.null;
|
|
} else {
|
|
throw new Error(
|
|
`Business Profile call failed ${response.body.error.message}`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"UpdateBusinessProfileTest",
|
|
(
|
|
updateBusinessProfileBody,
|
|
is_connector_agnostic_mit_enabled,
|
|
collect_billing_details_from_wallet_connector,
|
|
collect_shipping_details_from_wallet_connector,
|
|
always_collect_billing_details_from_wallet_connector,
|
|
always_collect_shipping_details_from_wallet_connector,
|
|
globalState,
|
|
profilePrefix = "profile"
|
|
) => {
|
|
updateBusinessProfileBody.is_connector_agnostic_mit_enabled =
|
|
is_connector_agnostic_mit_enabled;
|
|
updateBusinessProfileBody.collect_shipping_details_from_wallet_connector =
|
|
collect_shipping_details_from_wallet_connector;
|
|
updateBusinessProfileBody.collect_billing_details_from_wallet_connector =
|
|
collect_billing_details_from_wallet_connector;
|
|
updateBusinessProfileBody.always_collect_billing_details_from_wallet_connector =
|
|
always_collect_billing_details_from_wallet_connector;
|
|
updateBusinessProfileBody.always_collect_shipping_details_from_wallet_connector =
|
|
always_collect_shipping_details_from_wallet_connector;
|
|
|
|
const apiKey = globalState.get("apiKey");
|
|
const merchantId = globalState.get("merchantId");
|
|
const profileId = globalState.get(`${profilePrefix}Id`);
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/account/${merchantId}/business_profile/${profileId}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
body: updateBusinessProfileBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
globalState.set(
|
|
"collectBillingDetails",
|
|
response.body.collect_billing_details_from_wallet_connector
|
|
);
|
|
globalState.set(
|
|
"collectShippingDetails",
|
|
response.body.collect_shipping_details_from_wallet_connector
|
|
);
|
|
globalState.set(
|
|
"alwaysCollectBillingDetails",
|
|
response.body.always_collect_billing_details_from_wallet_connector
|
|
);
|
|
globalState.set(
|
|
"alwaysCollectShippingDetails",
|
|
response.body.always_collect_shipping_details_from_wallet_connector
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
// API Key API calls
|
|
Cypress.Commands.add("apiKeyCreateTest", (apiKeyCreateBody, globalState) => {
|
|
// Define the necessary variables and constant
|
|
|
|
const apiKey = globalState.get("adminApiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
// We do not want to keep API Key forever,
|
|
// so we set the expiry to tomorrow as new merchant accounts are created with every run
|
|
const expiry = isoTimeTomorrow();
|
|
const keyIdType = "key_id";
|
|
const keyId = validateEnv(baseUrl, keyIdType);
|
|
const merchantId = globalState.get("merchantId");
|
|
const url = `${baseUrl}/api_keys/${merchantId}`;
|
|
|
|
// Update request body
|
|
apiKeyCreateBody.expiration = expiry;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
body: apiKeyCreateBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body.merchant_id).to.equal(merchantId);
|
|
expect(response.body.description).to.equal(
|
|
apiKeyCreateBody.description
|
|
);
|
|
|
|
// API Key assertions are intentionally excluded to avoid being exposed in the logs
|
|
expect(response.body).to.have.property(keyIdType).and.to.include(keyId)
|
|
.and.to.not.be.empty;
|
|
|
|
globalState.set("apiKeyId", response.body.key_id);
|
|
globalState.set("apiKey", response.body.api_key);
|
|
|
|
cy.task("setGlobalState", globalState.data);
|
|
} else {
|
|
// to be updated
|
|
throw new Error(
|
|
`API Key create call failed with status ${response.status} and message: "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("apiKeyUpdateCall", (apiKeyUpdateBody, globalState) => {
|
|
const merchantId = globalState.get("merchantId");
|
|
const apiKeyId = globalState.get("apiKeyId");
|
|
// We do not want to keep API Key forever,
|
|
// so we set the expiry to tomorrow as new merchant accounts are created with every run
|
|
const expiry = isoTimeTomorrow();
|
|
|
|
// Update request body
|
|
apiKeyUpdateBody.expiration = expiry;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/api_keys/${merchantId}/${apiKeyId}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
body: apiKeyUpdateBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body.name).to.equal("Updated API Key");
|
|
expect(response.body.merchant_id).to.equal(merchantId);
|
|
|
|
// API Key assertions are intentionally excluded to avoid being exposed in the logs
|
|
expect(response.body.key_id).to.equal(apiKeyId);
|
|
} else {
|
|
// to be updated
|
|
throw new Error(
|
|
`API Key create call failed with status ${response.status} and message: "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("apiKeyRetrieveCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
const api_key_id = globalState.get("apiKeyId");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/api_keys/${merchant_id}/${api_key_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body.name).to.equal("Updated API Key");
|
|
expect(response.body.key_id).to.equal(api_key_id);
|
|
expect(response.body.merchant_id).to.equal(merchant_id);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("apiKeyListCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
const base_url = globalState.get("baseUrl");
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${base_url}/api_keys/${merchant_id}/list`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body).to.be.an("array").and.not.empty;
|
|
for (const key in response.body) {
|
|
expect(response.body[key]).to.have.property("name").and.not.empty;
|
|
if (base_url.includes("sandbox") || base_url.includes("integ")) {
|
|
expect(response.body[key]).to.have.property("key_id").include("snd_")
|
|
.and.not.empty;
|
|
} else if (base_url.includes("localhost")) {
|
|
expect(response.body[key]).to.have.property("key_id").include("dev_")
|
|
.and.not.empty;
|
|
}
|
|
expect(response.body[key].merchant_id).to.equal(merchant_id);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("apiKeyDeleteCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
const api_key_id = globalState.get("apiKeyId");
|
|
|
|
cy.request({
|
|
method: "DELETE",
|
|
url: `${globalState.get("baseUrl")}/api_keys/${merchant_id}/${api_key_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body.merchant_id).to.equal(merchant_id);
|
|
expect(response.body.key_id).to.equal(api_key_id);
|
|
expect(response.body.revoked).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"createNamedConnectorCallTest",
|
|
(
|
|
connectorType,
|
|
createConnectorBody,
|
|
paymentMethodsEnabled,
|
|
globalState,
|
|
connectorName,
|
|
connectorLabel,
|
|
profilePrefix = "profile",
|
|
mcaPrefix = "merchantConnector"
|
|
) => {
|
|
const merchantId = globalState.get("merchantId");
|
|
const profileId = globalState.get(`${profilePrefix}Id`);
|
|
|
|
createConnectorBody.profile_id = profileId;
|
|
createConnectorBody.connector_type = connectorType;
|
|
createConnectorBody.connector_name = connectorName;
|
|
createConnectorBody.connector_label = connectorLabel;
|
|
createConnectorBody.payment_methods_enabled = paymentMethodsEnabled;
|
|
// readFile is used to read the contents of the file and it always returns a promise ([Object Object]) due to its asynchronous nature
|
|
// it is best to use then() to handle the response within the same block of code
|
|
cy.readFile(globalState.get("connectorAuthFilePath")).then(
|
|
(jsonContent) => {
|
|
const { authDetails } = getValueByKey(
|
|
JSON.stringify(jsonContent),
|
|
connectorName
|
|
);
|
|
createConnectorBody.connector_account_details =
|
|
authDetails.connector_account_details;
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: createConnectorBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(connectorName).to.equal(response.body.connector_name);
|
|
globalState.set(
|
|
`${mcaPrefix}Id`,
|
|
response.body.merchant_connector_id
|
|
);
|
|
} else {
|
|
cy.task(
|
|
"cli_log",
|
|
"response status -> " + JSON.stringify(response.status)
|
|
);
|
|
|
|
throw new Error(
|
|
`Connector Create Call Failed ${response.body.error.message}`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createConnectorCallTest",
|
|
(
|
|
connectorType,
|
|
createConnectorBody,
|
|
payment_methods_enabled,
|
|
globalState,
|
|
profilePrefix = "profile",
|
|
mcaPrefix = "merchantConnector"
|
|
) => {
|
|
const api_key = globalState.get("apiKey");
|
|
const base_url = globalState.get("baseUrl");
|
|
const connector_id = globalState.get("connectorId");
|
|
const merchant_id = globalState.get("merchantId");
|
|
const profile_id = globalState.get(`${profilePrefix}Id`);
|
|
const url = `${base_url}/account/${merchant_id}/connectors`;
|
|
|
|
createConnectorBody.connector_type = connectorType;
|
|
createConnectorBody.profile_id = profile_id;
|
|
createConnectorBody.connector_name = connector_id;
|
|
createConnectorBody.payment_methods_enabled = payment_methods_enabled;
|
|
|
|
// readFile is used to read the contents of the file and it always returns a promise ([Object Object]) due to its asynchronous nature
|
|
// it is best to use then() to handle the response within the same block of code
|
|
cy.readFile(globalState.get("connectorAuthFilePath")).then(
|
|
(jsonContent) => {
|
|
const { authDetails, stateUpdate } = getValueByKey(
|
|
JSON.stringify(jsonContent),
|
|
connector_id,
|
|
extractIntegerAtEnd(profilePrefix)
|
|
);
|
|
|
|
if (stateUpdate) {
|
|
globalState.set(
|
|
"MULTIPLE_CONNECTORS",
|
|
stateUpdate.MULTIPLE_CONNECTORS
|
|
);
|
|
}
|
|
|
|
createConnectorBody.connector_account_details =
|
|
authDetails.connector_account_details;
|
|
|
|
if (authDetails && authDetails.metadata) {
|
|
createConnectorBody.metadata = {
|
|
...createConnectorBody.metadata, // Preserve existing metadata fields
|
|
...authDetails.metadata, // Merge with authDetails.metadata
|
|
};
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": api_key,
|
|
},
|
|
body: createConnectorBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(globalState.get("connectorId")).to.equal(
|
|
response.body.connector_name
|
|
);
|
|
globalState.set(
|
|
`${mcaPrefix}Id`,
|
|
response.body.merchant_connector_id
|
|
);
|
|
} else {
|
|
cy.task(
|
|
"cli_log",
|
|
"response status -> " + JSON.stringify(response.status)
|
|
);
|
|
|
|
throw new Error(
|
|
`Connector Create Call Failed ${response.body.error.message}`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createPayoutConnectorCallTest",
|
|
(connectorType, createConnectorBody, globalState) => {
|
|
const merchantId = globalState.get("merchantId");
|
|
const connectorName = globalState.get("connectorId");
|
|
createConnectorBody.connector_type = connectorType;
|
|
createConnectorBody.connector_name = connectorName;
|
|
createConnectorBody.connector_type = "payout_processor";
|
|
createConnectorBody.profile_id = globalState.get("profileId");
|
|
|
|
// readFile is used to read the contents of the file and it always returns a promise ([Object Object]) due to its asynchronous nature
|
|
// it is best to use then() to handle the response within the same block of code
|
|
cy.readFile(globalState.get("connectorAuthFilePath")).then(
|
|
(jsonContent) => {
|
|
const { authDetails } = getValueByKey(
|
|
JSON.stringify(jsonContent),
|
|
`${connectorName}_payout`
|
|
);
|
|
|
|
// If the connector does not have payout connector creds in creds file, set payoutsExecution to false
|
|
if (authDetails === null) {
|
|
globalState.set("payoutsExecution", false);
|
|
return false;
|
|
} else {
|
|
globalState.set("payoutsExecution", true);
|
|
}
|
|
|
|
createConnectorBody.connector_account_details =
|
|
authDetails.connector_account_details;
|
|
|
|
if (authDetails && authDetails.metadata) {
|
|
createConnectorBody.metadata = {
|
|
...createConnectorBody.metadata, // Preserve existing metadata fields
|
|
...authDetails.metadata, // Merge with authDetails.metadata
|
|
};
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: createConnectorBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(globalState.get("connectorId")).to.equal(
|
|
response.body.connector_name
|
|
);
|
|
globalState.set(
|
|
"merchantConnectorId",
|
|
response.body.merchant_connector_id
|
|
);
|
|
} else {
|
|
cy.task(
|
|
"cli_log",
|
|
"response status -> " + JSON.stringify(response.status)
|
|
);
|
|
|
|
throw new Error(
|
|
`Connector Create Call Failed ${response.body.error.message}`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("connectorRetrieveCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
const connector_id = globalState.get("connectorId");
|
|
const merchant_connector_id = globalState.get("merchantConnectorId");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/account/${merchant_id}/connectors/${merchant_connector_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
"x-merchant-id": merchant_id,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body.connector_name).to.equal(connector_id);
|
|
expect(response.body.merchant_connector_id).to.equal(
|
|
merchant_connector_id
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("connectorDeleteCall", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
const merchant_connector_id = globalState.get("merchantConnectorId");
|
|
|
|
cy.request({
|
|
method: "DELETE",
|
|
url: `${globalState.get("baseUrl")}/account/${merchant_id}/connectors/${merchant_connector_id}`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body.merchant_id).to.equal(merchant_id);
|
|
expect(response.body.merchant_connector_id).to.equal(
|
|
merchant_connector_id
|
|
);
|
|
expect(response.body.deleted).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"connectorUpdateCall",
|
|
(connectorType, updateConnectorBody, globalState) => {
|
|
const api_key = globalState.get("apiKey");
|
|
const base_url = globalState.get("baseUrl");
|
|
const connector_id = globalState.get("connectorId");
|
|
const merchant_id = globalState.get("merchantId");
|
|
const merchant_connector_id = globalState.get("merchantConnectorId");
|
|
const connectorLabel = `updated_${RequestBodyUtils.generateRandomString(connector_id)}`;
|
|
const url = `${base_url}/account/${merchant_id}/connectors/${merchant_connector_id}`;
|
|
|
|
updateConnectorBody.connector_type = connectorType;
|
|
updateConnectorBody.connector_label = connectorLabel;
|
|
|
|
cy.readFile(globalState.get("connectorAuthFilePath")).then(
|
|
(jsonContent) => {
|
|
const { authDetails } = getValueByKey(
|
|
JSON.stringify(jsonContent),
|
|
connector_id
|
|
);
|
|
if (authDetails && authDetails.metadata) {
|
|
updateConnectorBody.metadata = {
|
|
...updateConnectorBody.metadata, // Preserve existing metadata
|
|
...authDetails.metadata,
|
|
};
|
|
}
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": api_key,
|
|
"x-merchant-id": merchant_id,
|
|
},
|
|
body: updateConnectorBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include(
|
|
"application/json"
|
|
);
|
|
expect(response.body.connector_name).to.equal(connector_id);
|
|
expect(response.body.merchant_connector_id).to.equal(
|
|
merchant_connector_id
|
|
);
|
|
expect(response.body.connector_label).to.equal(connectorLabel);
|
|
});
|
|
});
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
// Generic function to list all connectors
|
|
Cypress.Commands.add("connectorListByMid", (globalState) => {
|
|
const merchant_id = globalState.get("merchantId");
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/account/${merchant_id}/connectors`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
"X-Merchant-Id": merchant_id,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body).to.be.an("array").and.not.empty;
|
|
response.body.forEach((item) => {
|
|
expect(item).to.not.have.property("metadata");
|
|
expect(item).to.not.have.property("additional_merchant_data");
|
|
expect(item).to.not.have.property("connector_wallets_details");
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"createCustomerCallTest",
|
|
(customerCreateBody, globalState) => {
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/customers`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: customerCreateBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
globalState.set("customerId", response.body.customer_id);
|
|
|
|
expect(response.body.customer_id, "customer_id").to.not.be.empty;
|
|
expect(customerCreateBody.email, "email").to.equal(
|
|
response.body.email
|
|
);
|
|
expect(customerCreateBody.name, "name").to.equal(response.body.name);
|
|
expect(customerCreateBody.phone, "phone").to.equal(
|
|
response.body.phone
|
|
);
|
|
expect(customerCreateBody.metadata, "metadata").to.deep.equal(
|
|
response.body.metadata
|
|
);
|
|
expect(customerCreateBody.address, "address").to.deep.equal(
|
|
response.body.address
|
|
);
|
|
expect(
|
|
customerCreateBody.phone_country_code,
|
|
"phone_country_code"
|
|
).to.equal(response.body.phone_country_code);
|
|
} else if (response.status === 400) {
|
|
if (response.body.error.message.includes("already exists")) {
|
|
expect(response.body.error.code).to.equal("IR_12");
|
|
expect(response.body.error.message).to.equal(
|
|
"Customer with the given `customer_id` already exists"
|
|
);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("customerListCall", (globalState) => {
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/customers/list`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
for (const key in response.body) {
|
|
expect(response.body[key]).to.not.be.empty;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("customerRetrieveCall", (globalState) => {
|
|
const customer_id = globalState.get("customerId");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/customers/${customer_id}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body.customer_id).to.equal(customer_id).and.not.be.empty;
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"customerUpdateCall",
|
|
(customerUpdateBody, globalState) => {
|
|
const customer_id = globalState.get("customerId");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/customers/${customer_id}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: customerUpdateBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body.customer_id).to.equal(customer_id);
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("ephemeralGenerateCall", (globalState) => {
|
|
const customer_id = globalState.get("customerId");
|
|
const merchant_id = globalState.get("merchantId");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/ephemeral_keys`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: { customer_id: customer_id },
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body.customer_id).to.equal(customer_id);
|
|
expect(response.body.merchant_id).to.equal(merchant_id);
|
|
expect(response.body.id).to.exist.and.not.be.empty;
|
|
expect(response.body.secret).to.exist.and.not.be.empty;
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("customerDeleteCall", (globalState) => {
|
|
const customer_id = globalState.get("customerId");
|
|
|
|
cy.request({
|
|
method: "DELETE",
|
|
url: `${globalState.get("baseUrl")}/customers/${customer_id}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.body.customer_id).to.equal(customer_id).and.not.be.empty;
|
|
expect(response.body.customer_deleted).to.equal(true);
|
|
expect(response.body.address_deleted).to.equal(true);
|
|
expect(response.body.payment_methods_deleted).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"paymentMethodListTestLessThanEqualToOnePaymentMethod",
|
|
(resData, globalState) => {
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/account/payment_methods?client_secret=${globalState.get("clientSecret")}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
expect(response.body).to.have.property("currency");
|
|
if (resData["payment_methods"].length == 1) {
|
|
function getPaymentMethodType(obj) {
|
|
return obj["payment_methods"][0]["payment_method_types"][0][
|
|
"payment_method_type"
|
|
];
|
|
}
|
|
expect(getPaymentMethodType(resData)).to.equal(
|
|
getPaymentMethodType(response.body)
|
|
);
|
|
} else {
|
|
expect(0).to.equal(response.body["payment_methods"].length);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"paymentMethodListTestWithRequiredFields",
|
|
(data, globalState) => {
|
|
const apiKey = globalState.get("publishableKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const clientSecret = globalState.get("clientSecret");
|
|
const url = `${baseUrl}/account/payment_methods?client_secret=${clientSecret}`;
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: url,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
const responsePaymentMethods = response.body["payment_methods"];
|
|
const responseRequiredFields =
|
|
responsePaymentMethods[0]["payment_method_types"][0][
|
|
"required_fields"
|
|
];
|
|
|
|
const expectedRequiredFields =
|
|
data["payment_methods"][0]["payment_method_types"][0][
|
|
"required_fields"
|
|
];
|
|
|
|
Object.keys(expectedRequiredFields).forEach((key) => {
|
|
const expectedField = expectedRequiredFields[key];
|
|
const responseField = responseRequiredFields[key];
|
|
|
|
expect(responseField).to.exist;
|
|
expect(responseField.required_field).to.equal(
|
|
expectedField.required_field
|
|
);
|
|
expect(responseField.display_name).to.equal(
|
|
expectedField.display_name
|
|
);
|
|
expect(responseField.field_type).to.deep.equal(
|
|
expectedField.field_type
|
|
);
|
|
expect(responseField.value).to.equal(expectedField.value);
|
|
});
|
|
} else {
|
|
throw new Error(
|
|
`List payment methods failed with status code "${response.status}" and error message "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"paymentMethodListTestTwoConnectorsForOnePaymentMethodCredit",
|
|
(resData, globalState) => {
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/account/payment_methods?client_secret=${globalState.get("clientSecret")}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
expect(response.body).to.have.property("currency");
|
|
if (resData["payment_methods"].length > 0) {
|
|
function getPaymentMethodType(obj) {
|
|
return obj["payment_methods"][0]["payment_method_types"][0][
|
|
"card_networks"
|
|
][0]["eligible_connectors"]
|
|
.slice()
|
|
.sort();
|
|
}
|
|
const config_payment_method_type = getPaymentMethodType(resData);
|
|
const response_payment_method_type = getPaymentMethodType(
|
|
response.body
|
|
);
|
|
for (let i = 0; i < response_payment_method_type.length; i++) {
|
|
expect(config_payment_method_type[i]).to.equal(
|
|
response_payment_method_type[i]
|
|
);
|
|
}
|
|
} else {
|
|
expect(0).to.equal(response.body["payment_methods"].length);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"sessionTokenCall",
|
|
(sessionTokenBody, data, globalState) => {
|
|
const { Response: resData } = data || {};
|
|
|
|
sessionTokenBody.payment_id = globalState.get("paymentID");
|
|
sessionTokenBody.client_secret = globalState.get("clientSecret");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/session_tokens`,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
"x-merchant-domain": "hyperswitch - demo - store.netlify.app",
|
|
"x-client-platform": "web",
|
|
},
|
|
body: sessionTokenBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
const expectedTokens = resData.body.session_token;
|
|
const actualTokens = response.body.session_token;
|
|
|
|
// Verifying length of array
|
|
expect(actualTokens.length, "arrayLength").to.equal(
|
|
expectedTokens.length
|
|
);
|
|
|
|
// Verify specific fields in each session_token object
|
|
expectedTokens.forEach((expectedToken, index) => {
|
|
const actualToken = actualTokens[index];
|
|
|
|
// Check specific fields only
|
|
expect(actualToken.wallet_name, "wallet_name").to.equal(
|
|
expectedToken.wallet_name
|
|
);
|
|
expect(actualToken.connector, "connector").to.equal(
|
|
expectedToken.connector
|
|
);
|
|
});
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createPaymentIntentTest",
|
|
(
|
|
createPaymentBody,
|
|
data,
|
|
authentication_type,
|
|
capture_method,
|
|
globalState
|
|
) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
if (
|
|
!createPaymentBody ||
|
|
typeof createPaymentBody !== "object" ||
|
|
!reqData.currency
|
|
) {
|
|
throw new Error(
|
|
"Invalid parameters provided to createPaymentIntentTest command"
|
|
);
|
|
}
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
for (const key in reqData) {
|
|
createPaymentBody[key] = reqData[key];
|
|
}
|
|
createPaymentBody.authentication_type = authentication_type;
|
|
createPaymentBody.capture_method = capture_method;
|
|
createPaymentBody.customer_id = globalState.get("customerId");
|
|
createPaymentBody.profile_id = profile_id;
|
|
|
|
globalState.set("paymentAmount", createPaymentBody.amount);
|
|
globalState.set("setupFutureUsage", createPaymentBody.setup_future_usage);
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: createPaymentBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (resData.status === 200) {
|
|
expect(response.body).to.have.property("client_secret");
|
|
const clientSecret = response.body.client_secret;
|
|
globalState.set("clientSecret", clientSecret);
|
|
globalState.set("paymentID", response.body.payment_id);
|
|
// Store the actual setup_future_usage value from the response
|
|
globalState.set(
|
|
"actualSetupFutureUsage",
|
|
response.body.setup_future_usage
|
|
);
|
|
cy.log(clientSecret);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(
|
|
response.body[key],
|
|
`Expected ${resData.body[key]} but got ${response.body[key]}`
|
|
);
|
|
}
|
|
expect(response.body.payment_id, "payment_id").to.not.be.null;
|
|
expect(response.body.merchant_id, "merchant_id").to.not.be.null;
|
|
expect(createPaymentBody.amount, "amount").to.equal(
|
|
response.body.amount
|
|
);
|
|
expect(createPaymentBody.currency, "currency").to.equal(
|
|
response.body.currency
|
|
);
|
|
expect(createPaymentBody.capture_method, "capture_method").to.equal(
|
|
response.body.capture_method
|
|
);
|
|
expect(
|
|
createPaymentBody.authentication_type,
|
|
"authentication_type"
|
|
).to.equal(response.body.authentication_type);
|
|
expect(createPaymentBody.description, "description").to.equal(
|
|
response.body.description
|
|
);
|
|
expect(createPaymentBody.email, "email").to.equal(
|
|
response.body.email
|
|
);
|
|
expect(createPaymentBody.email, "customer.email").to.equal(
|
|
response.body.customer.email
|
|
);
|
|
expect(createPaymentBody.customer_id, "customer.id").to.equal(
|
|
response.body.customer.id
|
|
);
|
|
expect(createPaymentBody.metadata, "metadata").to.deep.equal(
|
|
response.body.metadata
|
|
);
|
|
expect(
|
|
createPaymentBody.setup_future_usage,
|
|
"setup_future_usage"
|
|
).to.equal(response.body.setup_future_usage);
|
|
// If 'shipping_cost' is not included in the request, the 'amount' in 'createPaymentBody' should match the 'amount_capturable' in the response.
|
|
if (typeof createPaymentBody?.shipping_cost === "undefined") {
|
|
expect(createPaymentBody.amount, "amount_capturable").to.equal(
|
|
response.body.amount_capturable
|
|
);
|
|
} else {
|
|
expect(
|
|
createPaymentBody.amount + createPaymentBody.shipping_cost,
|
|
"amount_capturable"
|
|
).to.equal(response.body.amount_capturable);
|
|
}
|
|
expect(response.body.amount_received, "amount_received").to.be.oneOf([
|
|
0,
|
|
null,
|
|
]);
|
|
expect(response.body.connector, "connector").to.be.null;
|
|
expect(createPaymentBody.capture_method, "capture_method").to.equal(
|
|
response.body.capture_method
|
|
);
|
|
expect(response.body.payment_method, "payment_method").to.be.null;
|
|
expect(response.body.payment_method_data, "payment_method_data").to.be
|
|
.null;
|
|
expect(response.body.merchant_connector_id, "merchant_connector_id")
|
|
.to.be.null;
|
|
expect(response.body.payment_method_id, "payment_method_id").to.be
|
|
.null;
|
|
expect(response.body.payment_method_id, "payment_method_status").to.be
|
|
.null;
|
|
expect(response.body.profile_id, "profile_id").to.not.be.null;
|
|
expect(
|
|
response.body.merchant_order_reference_id,
|
|
"merchant_order_reference_id"
|
|
).to.be.null;
|
|
expect(response.body.connector_mandate_id, "connector_mandate_id").to
|
|
.be.null;
|
|
|
|
validateErrorMessage(response, resData);
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("paymentMethodsCallTest", (globalState) => {
|
|
const clientSecret = globalState.get("clientSecret");
|
|
const paymentIntentID = clientSecret.split("_secret_")[0];
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/account/payment_methods?client_secret=${clientSecret}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body).to.have.property("redirect_url");
|
|
expect(response.body).to.have.property("payment_methods");
|
|
if (
|
|
globalState.get("collectBillingDetails") === true ||
|
|
globalState.get("alwaysCollectBillingDetails") === true
|
|
) {
|
|
expect(
|
|
response.body.collect_billing_details_from_wallets,
|
|
"collectBillingDetailsFromWallets"
|
|
).to.be.true;
|
|
} else
|
|
expect(
|
|
response.body.collect_billing_details_from_wallets,
|
|
"collectBillingDetailsFromWallets"
|
|
).to.be.false;
|
|
|
|
if (
|
|
globalState.get("collectShippingDetails") === true ||
|
|
globalState.get("alwaysCollectShippingDetails") === true
|
|
) {
|
|
expect(
|
|
response.body.collect_shipping_details_from_wallets,
|
|
"collectShippingDetailsFromWallets"
|
|
).to.be.true;
|
|
} else
|
|
expect(
|
|
response.body.collect_shipping_details_from_wallets,
|
|
"collectShippingDetailsFromWallets"
|
|
).to.be.false;
|
|
globalState.set("paymentID", paymentIntentID);
|
|
cy.log(response);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("createPaymentMethodTest", (globalState, data) => {
|
|
const { Request: reqData, Response: resData } = data || {};
|
|
|
|
reqData.customer_id = globalState.get("customerId");
|
|
const merchant_id = globalState.get("merchantId");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payment_methods`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: reqData,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
expect(response.body.client_secret, "client_secret").to.include(
|
|
"_secret_"
|
|
).and.to.not.be.null;
|
|
expect(response.body.payment_method_id, "payment_method_id").to.not.be
|
|
.null;
|
|
expect(response.body.merchant_id, "merchant_id").to.equal(merchant_id);
|
|
expect(reqData.payment_method_type, "payment_method_type").to.equal(
|
|
response.body.payment_method_type
|
|
);
|
|
expect(reqData.payment_method, "payment_method").to.equal(
|
|
response.body.payment_method
|
|
);
|
|
expect(response.body.last_used_at, "last_used_at").to.not.be.null;
|
|
expect(reqData.customer_id, "customer_id").to.equal(
|
|
response.body.customer_id
|
|
);
|
|
globalState.set("paymentMethodId", response.body.payment_method_id);
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("deletePaymentMethodTest", (globalState) => {
|
|
const apiKey = globalState.get("apiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const paymentMethodId = globalState.get("paymentMethodId");
|
|
const url = `${baseUrl}/payment_methods/${paymentMethodId}`;
|
|
|
|
cy.request({
|
|
method: "DELETE",
|
|
url: url,
|
|
headers: {
|
|
Accept: "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
expect(response.body.payment_method_id).to.equal(paymentMethodId);
|
|
expect(response.body.deleted).to.be.true;
|
|
} else if (response.status === 500 && baseUrl.includes("localhost")) {
|
|
// delete payment method api endpoint requires tartarus (hyperswitch card vault) to be set up since it makes a call to the locker service to delete the payment method
|
|
expect(response.body.error.code).to.include("HE_00");
|
|
expect(response.body.error.message).to.include("Something went wrong");
|
|
} else {
|
|
throw new Error(
|
|
`Payment Method Delete Call Failed with error message: ${response.body.error.message}`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("setDefaultPaymentMethodTest", (globalState) => {
|
|
const payment_method_id = globalState.get("paymentMethodId");
|
|
const customer_id = globalState.get("customerId");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/customers/${customer_id}/payment_methods/${payment_method_id}/default`,
|
|
headers: {
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
expect(response.body).to.have.property(
|
|
"default_payment_method_id",
|
|
payment_method_id
|
|
);
|
|
expect(response.body).to.have.property("customer_id", customer_id);
|
|
} else if (response.status === 400) {
|
|
expect(response.body.error.message).to.equal(
|
|
"Payment Method is already set as default"
|
|
);
|
|
} else {
|
|
defaultErrorHandler(response);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"confirmCallTest",
|
|
(confirmBody, data, confirm, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const apiKey = globalState.get("publishableKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const merchantConnectorId = globalState.get(
|
|
`${configInfo.merchantConnectorPrefix}Id`
|
|
);
|
|
const paymentIntentID = globalState.get("paymentID");
|
|
const profileId = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
const url = `${baseUrl}/payments/${paymentIntentID}/confirm`;
|
|
|
|
confirmBody.client_secret = globalState.get("clientSecret");
|
|
confirmBody.confirm = confirm;
|
|
confirmBody.profile_id = profileId;
|
|
|
|
for (const key in reqData) {
|
|
confirmBody[key] = reqData[key];
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
failOnStatusCode: false,
|
|
body: confirmBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("paymentID", paymentIntentID);
|
|
globalState.set("connectorId", response.body.connector);
|
|
expect(response.body.connector, "connector").to.equal(
|
|
globalState.get("connectorId")
|
|
);
|
|
expect(paymentIntentID, "payment_id").to.equal(
|
|
response.body.payment_id
|
|
);
|
|
expect(response.body.payment_method_data, "payment_method_data").to
|
|
.not.be.empty;
|
|
expect(merchantConnectorId, "connector_id").to.equal(
|
|
response.body.merchant_connector_id
|
|
);
|
|
expect(response.body.customer, "customer").to.not.be.empty;
|
|
expect(response.body.billing, "billing_address").to.not.be.empty;
|
|
expect(response.body.profile_id, "profile_id").to.equal(profileId).and
|
|
.to.not.be.null;
|
|
|
|
validateErrorMessage(response, resData);
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
if (
|
|
response.body.setup_future_usage === "off_session" &&
|
|
response.body.status === "succeeded"
|
|
) {
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id"
|
|
).to.not.be.null;
|
|
}
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
if (
|
|
response.body.setup_future_usage === "off_session" &&
|
|
response.body.status === "succeeded"
|
|
) {
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id"
|
|
).to.not.be.null;
|
|
}
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"confirmBankRedirectCallTest",
|
|
(confirmBody, data, confirm, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const connectorId = globalState.get("connectorId");
|
|
const paymentIntentId = globalState.get("paymentID");
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
for (const key in reqData) {
|
|
confirmBody[key] = reqData[key];
|
|
}
|
|
confirmBody.client_secret = globalState.get("clientSecret");
|
|
confirmBody.confirm = confirm;
|
|
confirmBody.profile_id = profile_id;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/${paymentIntentId}/confirm`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: confirmBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.headers["content-type"]).to.include(
|
|
"application/json"
|
|
);
|
|
globalState.set("paymentID", paymentIntentId);
|
|
globalState.set("connectorId", response.body.connector);
|
|
globalState.set("paymentMethodType", confirmBody.payment_method_type);
|
|
|
|
if (response.status === 200) {
|
|
validateErrorMessage(response, resData);
|
|
|
|
switch (response.body.authentication_type) {
|
|
case "three_ds":
|
|
if (
|
|
response.body.capture_method === "automatic" ||
|
|
response.body.capture_method === "manual"
|
|
) {
|
|
if (response.body.status !== "failed") {
|
|
// we get many statuses here, hence this verification
|
|
if (
|
|
connectorId === "adyen" &&
|
|
response.body.payment_method_type === "blik"
|
|
) {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("type")
|
|
.to.equal("wait_screen_information");
|
|
} else {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
}
|
|
} else if (response.body.status === "failed") {
|
|
expect(response.body.error_code).to.equal(
|
|
resData.body.error_code
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
break;
|
|
case "no_three_ds":
|
|
if (
|
|
response.body.capture_method === "automatic" ||
|
|
response.body.capture_method === "manual"
|
|
) {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"confirmBankTransferCallTest",
|
|
(confirmBody, data, confirm, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const paymentIntentID = globalState.get("paymentID");
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
for (const key in reqData) {
|
|
confirmBody[key] = reqData[key];
|
|
}
|
|
confirmBody.client_secret = globalState.get("clientSecret");
|
|
confirmBody.confirm = confirm;
|
|
confirmBody.profile_id = globalState.get(profile_id);
|
|
|
|
globalState.set("paymentMethodType", confirmBody.payment_method_type);
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: confirmBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("paymentID", paymentIntentID);
|
|
|
|
validateErrorMessage(response, resData);
|
|
|
|
if (
|
|
response.body.capture_method === "automatic" ||
|
|
response.body.capture_method === "manual"
|
|
) {
|
|
switch (response.body.payment_method_type) {
|
|
case "pix":
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("qr_code_url");
|
|
if (response.body.next_action.qr_code_url !== null) {
|
|
globalState.set(
|
|
"nextActionUrl", // This is intentionally kept as nextActionUrl to avoid issues during handleRedirection call,
|
|
response.body.next_action.qr_code_url
|
|
);
|
|
globalState.set("nextActionType", "qr_code_url");
|
|
} else {
|
|
globalState.set(
|
|
"nextActionUrl", // This is intentionally kept as nextActionUrl to avoid issues during handleRedirection call,
|
|
response.body.next_action.image_data_url
|
|
);
|
|
globalState.set("nextActionType", "image_data_url");
|
|
}
|
|
break;
|
|
case "ach":
|
|
if (
|
|
response.body.next_action
|
|
?.bank_transfer_steps_and_charges_details != null
|
|
) {
|
|
globalState.set(
|
|
"nextActionType",
|
|
"bank_transfer_steps_and_charges_details"
|
|
);
|
|
}
|
|
|
|
break;
|
|
default:
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
globalState.set("nextActionType", "redirect_to_url");
|
|
break;
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"confirmUpiCall",
|
|
(confirmBody, data, confirm, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const paymentId = globalState.get("paymentID");
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
for (const key in reqData) {
|
|
confirmBody[key] = reqData[key];
|
|
}
|
|
confirmBody.client_secret = globalState.get("clientSecret");
|
|
confirmBody.confirm = confirm;
|
|
confirmBody.profile_id = profile_id;
|
|
|
|
globalState.set("paymentMethodType", confirmBody.payment_method_type);
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/${paymentId}/confirm`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: confirmBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
validateErrorMessage(response, resData);
|
|
|
|
if (
|
|
response.body.capture_method === "automatic" ||
|
|
response.body.capture_method === "manual"
|
|
) {
|
|
if (response.body.payment_method_type === "upi_collect") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
} else if (response.body.payment_method_type === "upi_intent") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("qr_code_fetch_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.qr_code_fetch_url
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createConfirmPaymentTest",
|
|
(
|
|
createConfirmPaymentBody,
|
|
data,
|
|
authentication_type,
|
|
capture_method,
|
|
globalState
|
|
) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const merchant_connector_id = globalState.get(
|
|
`${configInfo.merchantConnectorPrefix}Id`
|
|
);
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
createConfirmPaymentBody.authentication_type = authentication_type;
|
|
createConfirmPaymentBody.capture_method = capture_method;
|
|
createConfirmPaymentBody.customer_id = globalState.get("customerId");
|
|
createConfirmPaymentBody.profile_id = profile_id;
|
|
for (const key in reqData) {
|
|
createConfirmPaymentBody[key] = reqData[key];
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: createConfirmPaymentBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
globalState.set("clientSecret", response.body.client_secret);
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
globalState.set("paymentAmount", createConfirmPaymentBody.amount);
|
|
globalState.set("paymentID", response.body.payment_id);
|
|
// Store the actual setup_future_usage value from the response
|
|
globalState.set(
|
|
"actualSetupFutureUsage",
|
|
response.body.setup_future_usage
|
|
);
|
|
expect(response.body.connector, "connector").to.equal(
|
|
globalState.get("connectorId")
|
|
);
|
|
expect(response.body.payment_id, "payment_id").to.equal(
|
|
globalState.get("paymentID")
|
|
);
|
|
expect(response.body.payment_method_data, "payment_method_data").to
|
|
.not.be.empty;
|
|
expect(response.body.merchant_connector_id, "connector_id").to.equal(
|
|
merchant_connector_id
|
|
);
|
|
expect(response.body.customer, "customer").to.not.be.empty;
|
|
expect(response.body.billing, "billing_address").to.not.be.empty;
|
|
expect(response.body.profile_id, "profile_id").to.not.be.null;
|
|
expect(response.body).to.have.property("status");
|
|
|
|
validateErrorMessage(response, resData);
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type: ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type: ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
// This is consequent saved card payment confirm call test(Using payment token)
|
|
Cypress.Commands.add(
|
|
"saveCardConfirmCallTest",
|
|
(saveCardConfirmBody, data, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const merchant_connector_id = globalState.get(
|
|
`${configInfo.merchantConnectorPrefix}Id`
|
|
);
|
|
const paymentIntentID = globalState.get("paymentID");
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
// Add card_cvc if actual setup_future_usage is "on_session"
|
|
// This covers both explicit on_session and fallback cases
|
|
if (
|
|
globalState.get("actualSetupFutureUsage") === "on_session" &&
|
|
reqData.payment_method_data?.card?.card_cvc
|
|
) {
|
|
saveCardConfirmBody.card_cvc = reqData.payment_method_data.card.card_cvc;
|
|
}
|
|
saveCardConfirmBody.client_secret = globalState.get("clientSecret");
|
|
saveCardConfirmBody.payment_token = globalState.get("paymentToken");
|
|
saveCardConfirmBody.profile_id = profile_id;
|
|
|
|
// Include request data from config but exclude payment_method_data
|
|
if (reqData) {
|
|
const requestDataWithoutPMD = Object.fromEntries(
|
|
Object.entries(reqData).filter(
|
|
([key]) =>
|
|
key !== "payment_method_data" && key !== "customer_acceptance"
|
|
)
|
|
);
|
|
Object.assign(saveCardConfirmBody, requestDataWithoutPMD);
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: saveCardConfirmBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("paymentID", paymentIntentID);
|
|
|
|
globalState.set("paymentID", paymentIntentID);
|
|
globalState.set("connectorId", response.body.connector);
|
|
expect(response.body.connector, "connector").to.equal(
|
|
globalState.get("connectorId")
|
|
);
|
|
expect(paymentIntentID, "payment_id").to.equal(
|
|
response.body.payment_id
|
|
);
|
|
expect(response.body.payment_method_data, "payment_method_data").to
|
|
.not.be.empty;
|
|
expect(merchant_connector_id, "connector_id").to.equal(
|
|
response.body.merchant_connector_id
|
|
);
|
|
expect(response.body.customer, "customer").to.not.be.empty;
|
|
if (reqData.billing !== null) {
|
|
expect(response.body.billing, "billing_address").to.not.be.empty;
|
|
}
|
|
expect(response.body.profile_id, "profile_id").to.not.be.null;
|
|
expect(response.body.payment_token, "payment_token").to.not.be.null;
|
|
|
|
validateErrorMessage(response, resData);
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
|
|
if (
|
|
response.body?.payment_method_id &&
|
|
response.body.payment_method_id !== null
|
|
) {
|
|
expect(
|
|
response.body.payment_method_status,
|
|
"payment_method_status"
|
|
).to.equal("active");
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
expect(response.body.customer_id).to.equal(
|
|
globalState.get("customerId")
|
|
);
|
|
if (
|
|
[
|
|
"partially_captured",
|
|
"requires_capture",
|
|
"succeeded",
|
|
].includes(response.body.status)
|
|
) {
|
|
expect(
|
|
response.body.payment_method_id,
|
|
"payment_method_id should exist for succeeded/requires_capture status"
|
|
).to.exist.and.to.be.a("string");
|
|
|
|
expect(
|
|
response.body.payment_method_id,
|
|
"payment_method_id"
|
|
).to.include("pm_");
|
|
|
|
expect(
|
|
response.body.payment_method_status,
|
|
"payment_method_status"
|
|
).to.equal("active");
|
|
}
|
|
} else {
|
|
// Handle other authentication types as needed
|
|
throw new Error(
|
|
`Invalid authentication type: ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
expect(response.body.customer_id).to.equal(
|
|
globalState.get("customerId")
|
|
);
|
|
} else {
|
|
// Handle other authentication types as needed
|
|
throw new Error(
|
|
`Invalid authentication type: ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else {
|
|
// Handle other capture methods as needed
|
|
throw new Error(
|
|
`Invalid capture method: ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("captureCallTest", (requestBody, data, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const paymentId = globalState.get("paymentID");
|
|
const profileId = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
requestBody.profile_id = profileId;
|
|
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/${paymentId}/capture`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.body.capture_method !== undefined) {
|
|
expect(response.body.payment_id).to.equal(paymentId);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("voidCallTest", (requestBody, data, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Response: resData,
|
|
Request: reqData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const payment_id = globalState.get("paymentID");
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
requestBody.profile_id = profile_id;
|
|
|
|
// Apply connector-specific request data (including cancellation_reason)
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments/${payment_id}/cancel`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"retrievePaymentCallTest",
|
|
(globalState, data, autoretries = false, attempt = 1) => {
|
|
const { Configs: configs = {} } = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const merchant_connector_id = globalState.get(
|
|
`${configInfo.merchantConnectorPrefix}Id`
|
|
);
|
|
const payment_id = globalState.get("paymentID");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/payments/${payment_id}?force_sync=true&expand_attempts=true`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.headers["content-type"]).to.include(
|
|
"application/json"
|
|
);
|
|
expect(response.body.payment_id).to.equal(payment_id);
|
|
expect(response.body.amount).to.equal(
|
|
globalState.get("paymentAmount")
|
|
);
|
|
expect(response.body.profile_id, "profile_id").to.not.be.null;
|
|
expect(response.body.billing, "billing_address").to.not.be.null;
|
|
expect(response.body.customer, "customer").to.not.be.empty;
|
|
|
|
if (
|
|
["succeeded", "processing", "requires_customer_action"].includes(
|
|
response.body.status
|
|
)
|
|
) {
|
|
expect(response.body.connector, "connector").to.equal(
|
|
globalState.get("connectorId")
|
|
);
|
|
expect(response.body.payment_method_data, "payment_method_data").to
|
|
.not.be.empty;
|
|
expect(response.body.payment_method, "payment_method").to.not.be
|
|
.null;
|
|
expect(
|
|
response.body.merchant_connector_id,
|
|
"connector_id"
|
|
).to.equal(merchant_connector_id);
|
|
}
|
|
|
|
if (
|
|
response.body.payment_method_id &&
|
|
typeof response.body.payment_method_id === "string"
|
|
) {
|
|
// Validate the payment_method_id format
|
|
expect(
|
|
response.body.payment_method_id,
|
|
"payment_method_id"
|
|
).to.include("pm_").and.to.not.be.null;
|
|
|
|
// Whenever, CIT Confirmations gets a payment status of `processing`, it does not yield the `payment_method_id` and hence the `paymentMethodId` in the `globalState` gets the value of `null`. And hence while confirming MIT, it yields an `error.message` of `"Json deserialize error: invalid type: null, expected a string at line 1 column 182"` which is basically because of the `null` value in `recurring_details.data` with `recurring_details.type` as `payment_method_id`. However, we get the `payment_method_id` while PSync, so we can assign it to the `globalState` here.
|
|
globalState.set("paymentMethodId", response.body.payment_method_id);
|
|
|
|
const allowedActiveStatuses = [
|
|
"succeeded",
|
|
"requires_capture",
|
|
"partially_captured",
|
|
];
|
|
|
|
// If capture method is manual, 'processing' status also means 'active'
|
|
// for the payment method's usability.
|
|
if (response.body.capture_method === "manual") {
|
|
allowedActiveStatuses.push("processing");
|
|
}
|
|
|
|
const expectedStatus = allowedActiveStatuses.includes(
|
|
response.body.status
|
|
)
|
|
? "active"
|
|
: "inactive";
|
|
|
|
// Validate the status
|
|
expect(
|
|
response.body.payment_method_status,
|
|
"payment_method_status"
|
|
).to.equal(expectedStatus);
|
|
}
|
|
|
|
if (autoretries) {
|
|
expect(response.body).to.have.property("attempts");
|
|
expect(response.body.attempts).to.be.an("array").and.not.empty;
|
|
expect(response.body.attempts.length).to.equal(attempt);
|
|
expect(response.body.attempts[0].attempt_id).to.include(
|
|
`${payment_id}_`
|
|
);
|
|
for (const key in response.body.attempts) {
|
|
if (
|
|
response.body.attempts[key].attempt_id ===
|
|
`${payment_id}_${attempt}` &&
|
|
response.body.status === "succeeded"
|
|
) {
|
|
expect(response.body.attempts[key].status).to.equal("charged");
|
|
} else if (
|
|
response.body.attempts[key].attempt_id ===
|
|
`${payment_id}_${attempt}` &&
|
|
response.body.status === "requires_customer_action"
|
|
) {
|
|
expect(response.body.attempts[key].status).to.equal(
|
|
"authentication_pending"
|
|
);
|
|
} else {
|
|
expect(response.body.attempts[key].status).to.equal("failure");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Retrieve Payment Call Failed with error code "${response.body.error.code}" error message "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("refundCallTest", (requestBody, data, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const payment_id = globalState.get("paymentID");
|
|
|
|
// we only need this to set the delay. We don't need the return value
|
|
execConfig(validateConfig(configs));
|
|
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
requestBody.payment_id = payment_id;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/refunds`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("refundId", response.body.refund_id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
expect(response.body.payment_id).to.equal(payment_id);
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("syncRefundCallTest", (data, globalState) => {
|
|
const { Response: resData } = data || {};
|
|
|
|
const refundId = globalState.get("refundId");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/refunds/${refundId}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"citForMandatesCallTest",
|
|
(
|
|
requestBody,
|
|
data,
|
|
amount,
|
|
confirm,
|
|
capture_method,
|
|
payment_type,
|
|
globalState
|
|
) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
const merchant_connector_id = globalState.get(
|
|
`${configInfo.merchantConnectorPrefix}Id`
|
|
);
|
|
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
requestBody.amount = amount;
|
|
requestBody.capture_method = capture_method;
|
|
requestBody.confirm = confirm;
|
|
requestBody.customer_id = globalState.get("customerId");
|
|
requestBody.payment_type = payment_type;
|
|
requestBody.profile_id = profile_id;
|
|
|
|
globalState.set("paymentAmount", requestBody.amount);
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("paymentID", response.body.payment_id);
|
|
|
|
expect(response.body.payment_method_data, "payment_method_data").to
|
|
.not.be.empty;
|
|
expect(response.body.connector, "connector").to.equal(
|
|
globalState.get("connectorId")
|
|
);
|
|
expect(merchant_connector_id, "connector_id").to.equal(
|
|
response.body.merchant_connector_id
|
|
);
|
|
expect(response.body.customer, "customer").to.not.be.empty;
|
|
expect(response.body.profile_id, "profile_id").to.not.be.null;
|
|
if (
|
|
response.body.status !== "failed" &&
|
|
response.body.setup_future_usage === "off_session"
|
|
) {
|
|
expect(response.body.payment_method_id, "payment_method_id").to.not
|
|
.be.null;
|
|
}
|
|
|
|
if (requestBody.mandate_data === null) {
|
|
expect(response.body).to.have.property("payment_method_id");
|
|
globalState.set("paymentMethodId", response.body.payment_method_id);
|
|
} else {
|
|
expect(response.body).to.have.property("mandate_id");
|
|
globalState.set("mandateId", response.body.mandate_id);
|
|
}
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
expect(response.body).to.have.property("mandate_id");
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
if (
|
|
response.body.setup_future_usage === "off_session" &&
|
|
//Added this check to ensure mandate_id is null so that will get connector_mandate_id
|
|
response.body.mandate_id === null &&
|
|
response.body.status === "succeeded"
|
|
) {
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id"
|
|
).to.not.be.null;
|
|
}
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
globalState.set(
|
|
"nextActionUrl",
|
|
response.body.next_action.redirect_to_url
|
|
);
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.deep.equal(
|
|
response.body[key]
|
|
);
|
|
if (
|
|
response.body.setup_future_usage === "off_session" &&
|
|
response.body.mandate_id === null &&
|
|
response.body.status === "succeeded"
|
|
) {
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id"
|
|
).to.not.be.null;
|
|
}
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"mitForMandatesCallTest",
|
|
(requestBody, data, amount, confirm, capture_method, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const profile_id = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
|
|
const merchant_connector_id = globalState.get(
|
|
`${configInfo.merchantConnectorPrefix}Id`
|
|
);
|
|
|
|
requestBody.amount = amount;
|
|
requestBody.confirm = confirm;
|
|
requestBody.capture_method = capture_method;
|
|
requestBody.customer_id = globalState.get("customerId");
|
|
requestBody.mandate_id = globalState.get("mandateId");
|
|
requestBody.profile_id = profile_id;
|
|
|
|
globalState.set("paymentAmount", requestBody.amount);
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payments`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("paymentID", response.body.payment_id);
|
|
expect(response.body.payment_method_data, "payment_method_data").to
|
|
.not.be.empty;
|
|
expect(response.body.connector, "connector").to.equal(
|
|
globalState.get("connectorId")
|
|
);
|
|
expect(merchant_connector_id, "connector_id").to.equal(
|
|
response.body.merchant_connector_id
|
|
);
|
|
expect(response.body.customer, "customer").to.not.be.empty;
|
|
expect(response.body.profile_id, "profile_id").to.not.be.null;
|
|
expect(response.body.payment_method_id, "payment_method_id").to.not.be
|
|
.null;
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else if (response.status === 400) {
|
|
if (response.body.error.message === "Mandate Validation Failed") {
|
|
expect(response.body.error.code).to.equal("HE_03");
|
|
expect(response.body.error.message).to.equal(
|
|
"Mandate Validation Failed"
|
|
);
|
|
expect(response.body.error.reason).to.equal(
|
|
"request amount is greater than mandate amount"
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"mitUsingPMId",
|
|
(
|
|
requestBody,
|
|
data,
|
|
amount,
|
|
confirm,
|
|
capture_method,
|
|
globalState,
|
|
connector_agnostic_mit
|
|
) => {
|
|
if (shouldSkipMitUsingPMId(globalState.get("connectorId"))) {
|
|
cy.log(
|
|
`Skipping mitUsingPMId for connector: ${globalState.get("connectorId")}`
|
|
);
|
|
return;
|
|
}
|
|
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const profileId = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
const apiKey = globalState.get("apiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const customerId = globalState.get("customerId");
|
|
const paymentMethodId = globalState.get("paymentMethodId");
|
|
const url = `${baseUrl}/payments`;
|
|
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
|
|
requestBody.amount = amount;
|
|
requestBody.capture_method = capture_method;
|
|
requestBody.confirm = confirm;
|
|
requestBody.customer_id = customerId;
|
|
requestBody.profile_id = profileId;
|
|
requestBody.recurring_details.data = paymentMethodId;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
globalState.set("paymentID", response.body.payment_id);
|
|
|
|
if (response.body.status === "failed") {
|
|
expect(
|
|
response.body.connector_transaction_id,
|
|
"connector_transaction_id"
|
|
).to.be.null;
|
|
} else {
|
|
expect(
|
|
response.body.connector_transaction_id,
|
|
"connector_transaction_id"
|
|
).to.not.be.null;
|
|
}
|
|
|
|
if (
|
|
response.body.payment_method_id &&
|
|
typeof response.body.payment_method_id === "string"
|
|
) {
|
|
expect(
|
|
response.body.payment_method_id,
|
|
"payment_method_id"
|
|
).to.include("pm_").and.to.not.be.null;
|
|
|
|
const allowedActiveStatuses = [
|
|
"succeeded",
|
|
"requires_capture",
|
|
"partially_captured",
|
|
];
|
|
|
|
if (allowedActiveStatuses.includes(response.body.status)) {
|
|
expect(response.body.status, "response status").to.be.oneOf(
|
|
allowedActiveStatuses
|
|
);
|
|
|
|
expect(
|
|
response.body.payment_method_status,
|
|
"payment_method_status for active status"
|
|
).to.equal("active");
|
|
|
|
if (connector_agnostic_mit) {
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id for active status"
|
|
).to.be.null;
|
|
} else {
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id for active status"
|
|
).to.exist.and.not.be.null;
|
|
}
|
|
} else {
|
|
expect(response.body.status, "response status").to.not.be.oneOf(
|
|
allowedActiveStatuses
|
|
);
|
|
|
|
expect(
|
|
response.body.payment_method_status,
|
|
"payment_method_status for inactive status"
|
|
).to.equal("inactive");
|
|
|
|
expect(
|
|
response.body.connector_mandate_id,
|
|
"connector_mandate_id for inactive status"
|
|
).to.be.null;
|
|
}
|
|
}
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"mitUsingNTID",
|
|
(requestBody, data, amount, confirm, capture_method, globalState) => {
|
|
const {
|
|
Configs: configs = {},
|
|
Request: reqData,
|
|
Response: resData,
|
|
} = data || {};
|
|
const configInfo = execConfig(validateConfig(configs));
|
|
const profileId = globalState.get(`${configInfo.profilePrefix}Id`);
|
|
|
|
for (const key in reqData) {
|
|
requestBody[key] = reqData[key];
|
|
}
|
|
|
|
requestBody.amount = amount;
|
|
requestBody.confirm = confirm;
|
|
requestBody.capture_method = capture_method;
|
|
requestBody.profile_id = profileId;
|
|
|
|
const apiKey = globalState.get("apiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const url = `${baseUrl}/payments`;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
failOnStatusCode: false,
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.headers["content-type"]).to.include(
|
|
"application/json"
|
|
);
|
|
|
|
globalState.set("paymentID", response.body.payment_id);
|
|
|
|
if (response.body.capture_method === "automatic") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else if (response.body.capture_method === "manual") {
|
|
if (response.body.authentication_type === "three_ds") {
|
|
expect(response.body)
|
|
.to.have.property("next_action")
|
|
.to.have.property("redirect_to_url");
|
|
const nextActionUrl = response.body.next_action.redirect_to_url;
|
|
cy.log(nextActionUrl);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else if (response.body.authentication_type === "no_three_ds") {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key], [key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid authentication type ${response.body.authentication_type}`
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`Invalid capture method ${response.body.capture_method}`
|
|
);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("listMandateCallTest", (globalState) => {
|
|
const customerId = globalState.get("customerId");
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/customers/${customerId}/mandates`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
let i = 0;
|
|
for (i in response.body) {
|
|
if (response.body[i].mandate_id === globalState.get("mandateId")) {
|
|
expect(response.body[i].status).to.equal("active");
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("revokeMandateCallTest", (globalState) => {
|
|
const mandateId = globalState.get("mandateId");
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/mandates/revoke/${mandateId}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.body.status === 200) {
|
|
expect(response.body.status).to.equal("revoked");
|
|
} else if (response.body.status === 400) {
|
|
expect(response.body.reason).to.equal(
|
|
"Mandate has already been revoked"
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"handleRedirection",
|
|
(globalState, expectedRedirection) => {
|
|
const connectorId = globalState.get("connectorId");
|
|
const nextActionUrl = globalState.get("nextActionUrl");
|
|
|
|
const expectedUrl = new URL(expectedRedirection);
|
|
const redirectionUrl = new URL(nextActionUrl);
|
|
|
|
handleRedirection(
|
|
"three_ds",
|
|
{ redirectionUrl, expectedUrl },
|
|
connectorId,
|
|
null
|
|
);
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"handleBankRedirectRedirection",
|
|
(globalState, paymentMethodType, expectedRedirection) => {
|
|
const connectorId = globalState.get("connectorId");
|
|
const nextActionUrl = globalState.get("nextActionUrl");
|
|
|
|
const expectedUrl = new URL(expectedRedirection);
|
|
const redirectionUrl = new URL(nextActionUrl);
|
|
|
|
// explicitly restricting `sofort` payment method by adyen from running as it stops other tests from running
|
|
// trying to handle that specific case results in stripe 3ds tests to fail
|
|
if (!(connectorId == "adyen" && paymentMethodType == "sofort")) {
|
|
handleRedirection(
|
|
"bank_redirect",
|
|
{ redirectionUrl, expectedUrl },
|
|
connectorId,
|
|
paymentMethodType
|
|
);
|
|
}
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"handleBankTransferRedirection",
|
|
(globalState, paymentMethodType, expectedRedirection) => {
|
|
const connectorId = globalState.get("connectorId");
|
|
const nextActionUrl = globalState.get("nextActionUrl");
|
|
const nextActionType = globalState.get("nextActionType");
|
|
|
|
const expectedUrl = new URL(expectedRedirection);
|
|
let redirectionUrl = null;
|
|
try {
|
|
redirectionUrl = new URL(nextActionUrl);
|
|
} catch {
|
|
/* banktransfer may not have redirection url */
|
|
}
|
|
|
|
handleRedirection(
|
|
"bank_transfer",
|
|
{ redirectionUrl, expectedUrl },
|
|
connectorId,
|
|
paymentMethodType,
|
|
{
|
|
nextActionType,
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"handleUpiRedirection",
|
|
(globalState, paymentMethodType, expected_redirection) => {
|
|
const connectorId = globalState.get("connectorId");
|
|
const nextActionUrl = globalState.get("nextActionUrl");
|
|
|
|
const expectedUrl = new URL(expected_redirection);
|
|
const redirectionUrl = new URL(nextActionUrl);
|
|
|
|
handleRedirection(
|
|
"upi",
|
|
{ redirectionUrl, expectedUrl },
|
|
connectorId,
|
|
paymentMethodType
|
|
);
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("listCustomerPMCallTest", (globalState, order = 0) => {
|
|
const apiKey = globalState.get("apiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const customerId = globalState.get("customerId");
|
|
const url = `${baseUrl}/customers/${customerId}/payment_methods`;
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: url,
|
|
headers: {
|
|
"api-key": apiKey,
|
|
"Content-Type": "application/json",
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
// Validate response has payment methods
|
|
if (response.body.customer_payment_methods[order]?.payment_token) {
|
|
const paymentToken =
|
|
response.body.customer_payment_methods[order].payment_token;
|
|
const cardInfo = response.body.customer_payment_methods[order].card;
|
|
const paymentMethodId =
|
|
response.body.customer_payment_methods[order].payment_method_id;
|
|
const lastUsedAt =
|
|
response.body.customer_payment_methods[order].last_used_at;
|
|
|
|
globalState.set("paymentMethodId", paymentMethodId);
|
|
globalState.set("paymentToken", paymentToken);
|
|
|
|
if (cardInfo) {
|
|
expect(cardInfo.expiry_year, "expiry_year").to.not.be.null;
|
|
expect(cardInfo.card_holder_name, "card_holder_name").to.not.be.null;
|
|
}
|
|
|
|
// Validate last_used_at timestamp
|
|
expect(new Date(lastUsedAt).getTime(), "last_used_at").to.be.lessThan(
|
|
Date.now()
|
|
).and.to.not.be.null;
|
|
|
|
// For order > 0, validate payment methods are ordered by last_used_at
|
|
if (order > 0) {
|
|
const prevLastUsedAt =
|
|
response.body.customer_payment_methods[0].last_used_at;
|
|
expect(
|
|
new Date(prevLastUsedAt).getTime(),
|
|
"last_used_at ordering"
|
|
).to.be.greaterThan(new Date(lastUsedAt).getTime());
|
|
}
|
|
} else {
|
|
expect(response.body)
|
|
.to.have.property("customer_payment_methods")
|
|
.to.be.an("array").and.empty;
|
|
}
|
|
|
|
// Validate other payment method properties
|
|
for (const arrayCount in response.body.customer_payment_methods) {
|
|
const paymentMethod =
|
|
response.body.customer_payment_methods[arrayCount];
|
|
|
|
expect(
|
|
globalState.get("customerId"),
|
|
`${arrayCount} customer_id`
|
|
).to.equal(paymentMethod.customer_id);
|
|
|
|
expect(
|
|
paymentMethod.payment_token,
|
|
`${arrayCount} payment_token`
|
|
).to.include("token_").and.not.be.null;
|
|
|
|
expect(
|
|
paymentMethod.payment_method_id,
|
|
`${arrayCount} payment_method_id`
|
|
).to.include("pm_").and.not.be.null;
|
|
|
|
expect(paymentMethod.payment_method, `${arrayCount} payment_method`).to
|
|
.not.be.null;
|
|
|
|
expect(
|
|
paymentMethod.payment_method_type,
|
|
`${arrayCount} payment_method_type`
|
|
).to.not.be.null;
|
|
|
|
expect(paymentMethod.last_used_at, `${arrayCount} last_used_at`).to.not
|
|
.be.null;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("listCustomerPMByClientSecret", (globalState) => {
|
|
const clientSecret = globalState.get("clientSecret");
|
|
const setupFutureUsage = globalState.get("setupFutureUsage");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/customers/payment_methods?client_secret=${clientSecret}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("publishableKey"),
|
|
},
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.body.customer_payment_methods[0]?.payment_token) {
|
|
const paymentToken =
|
|
response.body.customer_payment_methods[0].payment_token;
|
|
const paymentMethodId =
|
|
response.body.customer_payment_methods[0].payment_method_id;
|
|
globalState.set("paymentToken", paymentToken);
|
|
globalState.set("paymentMethodId", paymentMethodId);
|
|
expect(
|
|
response.body.customer_payment_methods[0].payment_method_id,
|
|
"payment_method_id"
|
|
).to.not.be.null;
|
|
|
|
if (setupFutureUsage === "off_session") {
|
|
expect(
|
|
response.body.customer_payment_methods[0].requires_cvv,
|
|
"requires_cvv"
|
|
).to.be.false;
|
|
} else if (setupFutureUsage === "on_session") {
|
|
expect(
|
|
response.body.customer_payment_methods[0].requires_cvv,
|
|
"requires_cvv"
|
|
).to.be.true;
|
|
}
|
|
} else {
|
|
// We only get an empty array if something's wrong. One exception is a 4xx when no customer exist but it is handled in the test
|
|
expect(response.body)
|
|
.to.have.property("customer_payment_methods")
|
|
.to.be.an("array").and.empty;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("listRefundCallTest", (requestBody, globalState) => {
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/refunds/list`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
body: requestBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body.data).to.be.an("array").and.not.empty;
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"createConfirmPayoutTest",
|
|
(createConfirmPayoutBody, data, confirm, auto_fulfill, globalState) => {
|
|
const { Request: reqData, Response: resData } = data || {};
|
|
|
|
for (const key in reqData) {
|
|
createConfirmPayoutBody[key] = reqData[key];
|
|
}
|
|
createConfirmPayoutBody.auto_fulfill = auto_fulfill;
|
|
createConfirmPayoutBody.confirm = confirm;
|
|
createConfirmPayoutBody.customer_id = globalState.get("customerId");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payouts/create`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: createConfirmPayoutBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
if (response.status === 200) {
|
|
globalState.set("payoutAmount", createConfirmPayoutBody.amount);
|
|
globalState.set("payoutID", response.body.payout_id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createConfirmWithTokenPayoutTest",
|
|
(createConfirmPayoutBody, data, confirm, auto_fulfill, globalState) => {
|
|
const { Request: reqData, Response: resData } = data || {};
|
|
|
|
for (const key in reqData) {
|
|
createConfirmPayoutBody[key] = reqData[key];
|
|
}
|
|
createConfirmPayoutBody.customer_id = globalState.get("customerId");
|
|
createConfirmPayoutBody.payout_token = globalState.get("paymentToken");
|
|
createConfirmPayoutBody.auto_fulfill = auto_fulfill;
|
|
createConfirmPayoutBody.confirm = confirm;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payouts/create`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: createConfirmPayoutBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
globalState.set("payoutAmount", createConfirmPayoutBody.amount);
|
|
globalState.set("payoutID", response.body.payout_id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"createConfirmWithPayoutMethodIdTest",
|
|
(createConfirmPayoutBody, data, confirm, auto_fulfill, globalState) => {
|
|
const { Request: reqData, Response: resData } = data || {};
|
|
|
|
for (const key in reqData) {
|
|
createConfirmPayoutBody[key] = reqData[key];
|
|
}
|
|
createConfirmPayoutBody.customer_id = globalState.get("customerId");
|
|
createConfirmPayoutBody.auto_fulfill = auto_fulfill;
|
|
createConfirmPayoutBody.confirm = confirm;
|
|
createConfirmPayoutBody.payout_method_id = globalState.data.paymentMethodId;
|
|
delete createConfirmPayoutBody.payout_token;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payouts/create`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: createConfirmPayoutBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
globalState.set("payoutAmount", createConfirmPayoutBody.amount);
|
|
globalState.set("payoutID", response.body.payout_id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"fulfillPayoutCallTest",
|
|
(payoutFulfillBody, data, globalState) => {
|
|
const { Response: resData } = data || {};
|
|
|
|
payoutFulfillBody.payout_id = globalState.get("payoutID");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/payouts/${globalState.get("payoutID")}/fulfill`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: payoutFulfillBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"updatePayoutCallTest",
|
|
(payoutConfirmBody, data, auto_fulfill, globalState) => {
|
|
const { Response: resData } = data || {};
|
|
|
|
payoutConfirmBody.confirm = true;
|
|
payoutConfirmBody.auto_fulfill = auto_fulfill;
|
|
|
|
cy.request({
|
|
method: "PUT",
|
|
url: `${globalState.get("baseUrl")}/payouts/${globalState.get("payoutID")}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
body: payoutConfirmBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("retrievePayoutCallTest", (globalState) => {
|
|
const payout_id = globalState.get("payoutID");
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/payouts/${payout_id}`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
expect(response.body.payout_id).to.equal(payout_id);
|
|
expect(response.body.amount).to.equal(globalState.get("payoutAmount"));
|
|
});
|
|
});
|
|
});
|
|
|
|
// User API calls
|
|
// Below 3 commands should be called in sequence to login a user
|
|
Cypress.Commands.add("userLogin", (globalState) => {
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const queryParams = `token_only=true`;
|
|
const signinBody = {
|
|
email: globalState.get("email"),
|
|
password: globalState.get("password"),
|
|
};
|
|
const url = `${baseUrl}/user/v2/signin?${queryParams}`;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: signinBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
if (response.body.token_type === "totp") {
|
|
expect(response.body, "totp_token").to.have.property("token").and.to
|
|
.not.be.empty;
|
|
|
|
const totpToken = response.body.token;
|
|
if (!totpToken) {
|
|
throw new Error("No token received from login");
|
|
}
|
|
globalState.set("totpToken", totpToken);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`User login call failed to get totp token with status: "${response.status}" and message: "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
Cypress.Commands.add("terminate2Fa", (globalState) => {
|
|
// Define the necessary variables and constant
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const queryParams = `skip_two_factor_auth=true`;
|
|
const apiKey = globalState.get("totpToken");
|
|
const url = `${baseUrl}/user/2fa/terminate?${queryParams}`;
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: url,
|
|
headers: {
|
|
Authorization: `Bearer ${apiKey}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
if (response.body.token_type === "user_info") {
|
|
expect(response.body, "user_info_token").to.have.property("token").and
|
|
.to.not.be.empty;
|
|
|
|
const userInfoToken = response.body.token;
|
|
if (!userInfoToken) {
|
|
throw new Error("No user info token received");
|
|
}
|
|
globalState.set("userInfoToken", userInfoToken);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`2FA terminate call failed with status: "${response.status}" and message: "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
Cypress.Commands.add("userInfo", (globalState) => {
|
|
// Define the necessary variables and constant
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const userInfoToken = globalState.get("userInfoToken");
|
|
const url = `${baseUrl}/user`;
|
|
|
|
if (!userInfoToken) {
|
|
throw new Error("No user info token available");
|
|
}
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: url,
|
|
headers: {
|
|
Authorization: `Bearer ${userInfoToken}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body, "merchant_id").to.have.property("merchant_id").and
|
|
.to.not.be.empty;
|
|
expect(response.body, "organization_id").to.have.property("org_id").and
|
|
.to.not.be.empty;
|
|
expect(response.body, "profile_id").to.have.property("profile_id").and
|
|
.to.not.be.empty;
|
|
|
|
globalState.set("merchantId", response.body.merchant_id);
|
|
globalState.set("organizationId", response.body.org_id);
|
|
globalState.set("profileId", response.body.profile_id);
|
|
|
|
globalState.set("userInfoToken", userInfoToken);
|
|
} else {
|
|
throw new Error(
|
|
`User login call failed to fetch user info with status: "${response.status}" and message: "${response.body.error.message}"`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Specific to routing tests
|
|
Cypress.Commands.add("ListMcaByMid", (globalState) => {
|
|
const merchantId = globalState.get("merchantId");
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("apiKey"),
|
|
"X-Merchant-Id": merchantId,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
globalState.set("profileId", response.body[0].profile_id);
|
|
globalState.set("stripeMcaId", response.body[0].merchant_connector_id);
|
|
globalState.set("adyenMcaId", response.body[1].merchant_connector_id);
|
|
globalState.set("bluesnapMcaId", response.body[3].merchant_connector_id);
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"addRoutingConfig",
|
|
(routingBody, data, type, routing_data, globalState) => {
|
|
const { Request: reqData, Response: resData } = data || {};
|
|
|
|
for (const key in reqData) {
|
|
routingBody[key] = reqData[key];
|
|
}
|
|
// set profile id from env
|
|
routingBody.profile_id = globalState.get("profileId");
|
|
routingBody.algorithm.type = type;
|
|
routingBody.algorithm.data = routing_data;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/routing`,
|
|
headers: {
|
|
Authorization: `Bearer ${globalState.get("userInfoToken")}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
failOnStatusCode: false,
|
|
body: routingBody,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
expect(response.body).to.have.property("id");
|
|
globalState.set("routingConfigId", response.body.id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("activateRoutingConfig", (data, globalState) => {
|
|
const { Response: resData } = data || {};
|
|
const routing_config_id = globalState.get("routingConfigId");
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/routing/${routing_config_id}/activate`,
|
|
headers: {
|
|
Authorization: `Bearer ${globalState.get("userInfoToken")}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
expect(response.body.id).to.equal(routing_config_id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("retrieveRoutingConfig", (data, globalState) => {
|
|
const { Response: resData } = data || {};
|
|
const routing_config_id = globalState.get("routingConfigId");
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: `${globalState.get("baseUrl")}/routing/${routing_config_id}`,
|
|
headers: {
|
|
Authorization: `Bearer ${globalState.get("userInfoToken")}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
expect(response.headers["content-type"]).to.include("application/json");
|
|
|
|
if (response.status === 200) {
|
|
expect(response.body.id).to.equal(routing_config_id);
|
|
for (const key in resData.body) {
|
|
expect(resData.body[key]).to.equal(response.body[key]);
|
|
}
|
|
} else {
|
|
defaultErrorHandler(response, resData);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add(
|
|
"updateGsmConfig",
|
|
(gsmBody, globalState, step_up_possible) => {
|
|
gsmBody.step_up_possible = step_up_possible;
|
|
cy.request({
|
|
method: "POST",
|
|
url: `${globalState.get("baseUrl")}/gsm/update`,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": globalState.get("adminApiKey"),
|
|
},
|
|
body: gsmBody,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body)
|
|
.to.have.property("message")
|
|
.to.equal("card_declined");
|
|
expect(response.body)
|
|
.to.have.property("connector")
|
|
.to.equal("stripe");
|
|
expect(response.body)
|
|
.to.have.property("step_up_possible")
|
|
.to.equal(step_up_possible);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add("incrementalAuth", (globalState, data) => {
|
|
const { Request: reqData, Response: resData } = data || {};
|
|
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const paymentId = globalState.get("paymentID");
|
|
const apiKey = globalState.get("apiKey");
|
|
const url = `${baseUrl}/payments/${paymentId}/incremental_authorization`;
|
|
|
|
cy.request({
|
|
method: "POST",
|
|
url: url,
|
|
headers: {
|
|
"api-key": apiKey,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: reqData,
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body.amount_capturable, "amount_capturable").to.equal(
|
|
resData.body.amount_capturable
|
|
);
|
|
expect(
|
|
response.body.authorization_count,
|
|
"authorization_count"
|
|
).to.be.a("number").and.not.be.null;
|
|
expect(
|
|
response.body.incremental_authorization_allowed,
|
|
"incremental_authorization_allowed"
|
|
).to.be.true;
|
|
expect(
|
|
response.body.incremental_authorizations,
|
|
"incremental_authorizations"
|
|
).to.be.an("array").and.not.be.empty;
|
|
expect(response.body.payment_id, "payment_id").to.equal(paymentId);
|
|
expect(response.body.status, "status").to.equal(resData.body.status);
|
|
|
|
for (const key in response.body.incremental_authorizations) {
|
|
expect(response.body.incremental_authorizations[key], "amount")
|
|
.to.have.property("amount")
|
|
.to.be.a("number")
|
|
.to.equal(resData.body.amount).and.not.be.null;
|
|
if (
|
|
response.body.incremental_authorizations[key].status === "failure"
|
|
) {
|
|
expect(response.body.incremental_authorizations[key], "error_code")
|
|
.to.have.property("error_code")
|
|
.to.be.equal(
|
|
resData.body.incremental_authorizations[key].error_code
|
|
);
|
|
expect(
|
|
response.body.incremental_authorizations[key],
|
|
"error_message"
|
|
)
|
|
.to.have.property("error_message")
|
|
.to.be.equal(
|
|
resData.body.incremental_authorizations[key].error_message
|
|
);
|
|
expect(response.body.incremental_authorizations[key], "status")
|
|
.to.have.property("status")
|
|
.to.equal("failure");
|
|
} else {
|
|
expect(
|
|
response.body.incremental_authorizations[key],
|
|
"error_code"
|
|
).to.have.property("error_code").to.be.null;
|
|
expect(
|
|
response.body.incremental_authorizations[key],
|
|
"error_message"
|
|
).to.have.property("error_message").to.be.null;
|
|
expect(response.body.incremental_authorizations[key], "status")
|
|
.to.have.property("status")
|
|
.to.equal("success");
|
|
}
|
|
expect(
|
|
response.body.incremental_authorizations[key],
|
|
"previously_authorized_amount"
|
|
)
|
|
.to.have.property("previously_authorized_amount")
|
|
.to.be.a("number")
|
|
.to.equal(
|
|
response.body.incremental_authorizations[key]
|
|
.previously_authorized_amount
|
|
).and.not.be.null;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("setConfigs", (globalState, key, value, requestType) => {
|
|
if (!key || !requestType) {
|
|
throw new Error("Key and requestType are required parameters");
|
|
}
|
|
|
|
const REQUEST_CONFIG = {
|
|
CREATE: { method: "POST", useKey: false },
|
|
UPDATE: { method: "POST", useKey: true },
|
|
FETCH: { method: "GET", useKey: true },
|
|
DELETE: { method: "DELETE", useKey: true },
|
|
};
|
|
|
|
const config = REQUEST_CONFIG[requestType];
|
|
if (!config) {
|
|
throw new Error(`Invalid requestType: ${requestType}`);
|
|
}
|
|
|
|
const apiKey = globalState.get("adminApiKey");
|
|
const baseUrl = globalState.get("baseUrl");
|
|
const url = `${baseUrl}/configs/${config.useKey ? key : ""}`;
|
|
|
|
const getRequestBody = {
|
|
CREATE: () => ({ key, value }),
|
|
UPDATE: () => ({ value }),
|
|
};
|
|
const body = getRequestBody[requestType]?.() || undefined;
|
|
|
|
cy.request({
|
|
method: config.method,
|
|
url,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"api-key": apiKey,
|
|
},
|
|
...(body && { body }),
|
|
failOnStatusCode: false,
|
|
}).then((response) => {
|
|
logRequestId(response.headers["x-request-id"]);
|
|
|
|
cy.wrap(response).then(() => {
|
|
if (response.status === 200) {
|
|
expect(response.body).to.have.property("key").to.equal(key);
|
|
expect(response.body).to.have.property("value").to.equal(value);
|
|
} else {
|
|
Cypress.log({
|
|
name: "setConfigs",
|
|
message: `Failed for key: ${key} → status ${response.status}, message: ${response.body?.error?.message}`,
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("setupConfigs", (globalState, key, value) => {
|
|
cy.setConfigs(globalState, key, value, "DELETE");
|
|
cy.setConfigs(globalState, key, value, "CREATE");
|
|
});
|
|
|
|
// UCS Configuration Commands
|
|
Cypress.Commands.add("setupUCSConfigs", (globalState, connector) => {
|
|
cy.setupConfigs(globalState, "ucs_enabled", "true");
|
|
|
|
const merchantId = globalState.get("merchantId");
|
|
const rolloutConfigs = [
|
|
`ucs_rollout_config_${merchantId}_${connector}_card_Authorize`,
|
|
`ucs_rollout_config_${merchantId}_${connector}_card_SetupMandate`,
|
|
`ucs_rollout_config_${merchantId}_${connector}_card_PSync`,
|
|
];
|
|
|
|
rolloutConfigs.forEach((key) => {
|
|
cy.setConfigs(globalState, key, "1.0", "CREATE");
|
|
});
|
|
});
|
|
|
|
Cypress.Commands.add("cleanupUCSConfigs", (globalState, connector) => {
|
|
const merchantId = globalState.get("merchantId");
|
|
const rolloutConfigs = [
|
|
`ucs_rollout_config_${merchantId}_${connector}_card_Authorize`,
|
|
`ucs_rollout_config_${merchantId}_${connector}_card_SetupMandate`,
|
|
`ucs_rollout_config_${merchantId}_${connector}_card_PSync`,
|
|
];
|
|
|
|
rolloutConfigs.forEach((key) => {
|
|
cy.setConfigs(globalState, key, "1.0", "DELETE");
|
|
});
|
|
|
|
cy.setConfigs(globalState, "ucs_enabled", "true", "DELETE");
|
|
});
|
|
|
|
// DDC Race Condition Test Commands
|
|
Cypress.Commands.add(
|
|
"ddcServerSideRaceConditionTest",
|
|
(confirmData, globalState) => {
|
|
const ddcConfig = confirmData.DDCConfig;
|
|
const paymentId = globalState.get("paymentID");
|
|
const merchantId = globalState.get("merchantId");
|
|
const completeUrl = `${Cypress.env("BASEURL")}/payments/${paymentId}/${merchantId}${ddcConfig.completeUrlPath}`;
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: completeUrl,
|
|
qs: {
|
|
[ddcConfig.collectionReferenceParam]: ddcConfig.firstSubmissionValue,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((firstResponse) => {
|
|
if (
|
|
firstResponse.status === 400 &&
|
|
firstResponse.body?.error?.message?.includes("No eligible connector")
|
|
) {
|
|
throw new Error(
|
|
`Connector configuration issue detected. Response: ${JSON.stringify(firstResponse.body)}`
|
|
);
|
|
}
|
|
|
|
expect(firstResponse.status).to.be.oneOf([200, 302]);
|
|
cy.log(`First request status: ${firstResponse.status}`);
|
|
|
|
cy.request({
|
|
method: "GET",
|
|
url: completeUrl,
|
|
qs: {
|
|
[ddcConfig.collectionReferenceParam]: ddcConfig.secondSubmissionValue,
|
|
},
|
|
failOnStatusCode: false,
|
|
}).then((secondResponse) => {
|
|
cy.log(`Second request status: ${secondResponse.status}`);
|
|
|
|
expect(secondResponse.status).to.eq(ddcConfig.expectedError.status);
|
|
expect(secondResponse.body).to.deep.equal(ddcConfig.expectedError.body);
|
|
|
|
cy.log(
|
|
"✅ Server-side race condition protection verified - second submission properly rejected"
|
|
);
|
|
});
|
|
});
|
|
}
|
|
);
|
|
|
|
Cypress.Commands.add(
|
|
"ddcClientSideRaceConditionTest",
|
|
(confirmData, globalState) => {
|
|
const ddcConfig = confirmData.DDCConfig;
|
|
const paymentId = globalState.get("paymentID");
|
|
const merchantId = globalState.get("merchantId");
|
|
const nextActionUrl = `${Cypress.env("BASEURL")}${ddcConfig.redirectUrlPath}/${paymentId}/${merchantId}/${paymentId}_1`;
|
|
|
|
cy.intercept("GET", nextActionUrl, (req) => {
|
|
req.reply((res) => {
|
|
let modifiedHtml = res.body.toString();
|
|
modifiedHtml = modifiedHtml.replace(
|
|
"</body>",
|
|
ddcConfig.raceConditionScript + "</body>"
|
|
);
|
|
res.send(modifiedHtml);
|
|
});
|
|
}).as("ddcPageWithRaceCondition");
|
|
|
|
cy.intercept("GET", "**/redirect/complete/**").as("ddcSubmission");
|
|
const delayBeforeSubmission = ddcConfig.delayBeforeSubmission || 2000;
|
|
|
|
cy.visit(nextActionUrl);
|
|
cy.wait("@ddcPageWithRaceCondition");
|
|
cy.wait("@ddcSubmission");
|
|
cy.wait(delayBeforeSubmission);
|
|
|
|
cy.get("@ddcSubmission.all").should("have.length", 1);
|
|
|
|
cy.get("@ddcSubmission").then((interception) => {
|
|
const collectionRef =
|
|
interception.request.query[ddcConfig.collectionReferenceParam] || "";
|
|
cy.log(
|
|
`Single submission detected with ${ddcConfig.collectionReferenceParam}: "${collectionRef}"`
|
|
);
|
|
});
|
|
|
|
cy.log(
|
|
"✅ Client-side race condition protection verified - only one submission occurred"
|
|
);
|
|
}
|
|
);
|