ci(cypressV2): update cypress v2 framework to accommodate hyperswitch v2 changes (#6493)

This commit is contained in:
Pa1NarK
2024-11-08 17:42:30 +05:30
committed by GitHub
parent d9ce42fd0c
commit 28e3c36693
9 changed files with 412 additions and 196 deletions

View File

@ -94,15 +94,3 @@ export function defaultErrorHandler(response, response_data) {
expect(response.body.error).to.include(response_data.body.error);
}
}
export function isoTimeTomorrow() {
const now = new Date();
// Create a new date object for tomorrow
const tomorrow = new Date(now);
tomorrow.setDate(now.getDate() + 1);
// Convert to ISO string format
const isoStringTomorrow = tomorrow.toISOString();
return isoStringTomorrow;
}

View File

@ -15,12 +15,23 @@ function normalise(input) {
paybox: "Paybox",
paypal: "Paypal",
wellsfargo: "Wellsfargo",
fiuu: "Fiuu",
// Add more known exceptions here
};
if (typeof input !== "string") {
const spec_name = Cypress.spec.name.split("-")[1].split(".")[0];
return `${spec_name}`;
const specName = Cypress.spec.name;
if (specName.includes("-")) {
const parts = specName.split("-");
if (parts.length > 1 && parts[1].includes(".")) {
return parts[1].split(".")[0];
}
}
// Fallback
return `${specName}`;
}
const lowerCaseInput = input.toLowerCase();

View File

@ -0,0 +1,132 @@
/*
No 3DS Auto capture with Confirm True
No 3DS Auto capture with Confirm False
No 3DS Manual capture with Confirm True
No 3DS Manual capture with Confirm False
No 3DS Manual multiple capture with Confirm True
No 3DS Manual multiple capture with Confirm False
*/
import * as fixtures from "../../../fixtures/imports";
import State from "../../../utils/State";
import getConnectorDetails from "../../configs/Payment/Utils";
let globalState;
// Below is an example of a test that is skipped just because it is not implemented yet
describe("[Payment] [No 3DS] [Payment Method: Card]", () => {
context("[Payment] [No 3DS] [Capture: Automatic] [Confirm: True]", () => {
let should_continue = true;
before("seed global state", () => {
cy.task("getGlobalState").then((state) => {
globalState = new State(state);
});
});
beforeEach(function () {
if (!should_continue) {
this.skip();
}
});
after("flush global state", () => {
cy.task("setGlobalState", globalState.data);
});
it.skip("Create payment intent", () => {
let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][
"PaymentIntent"
];
let req_data = data["Request"];
let res_data = data["Response"];
cy.paymentIntentCreateCall(
fixtures.createPaymentBody,
req_data,
res_data,
"no_three_ds",
"automatic",
globalState
);
});
it.skip("List payment methods", () => {
cy.paymentMethodsListCall(globalState);
});
it.skip("Confirm payment intent", () => {
let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][
"No3DSAutoCapture"
];
let req_data = data["Request"];
let res_data = data["Response"];
cy.paymentIntentConfirmCall(
fixtures.confirmBody,
req_data,
res_data,
true,
globalState
);
});
it.skip("Retrieve payment intent", () => {
cy.paymentIntentRetrieveCall(globalState);
});
});
context("[Payment] [No 3DS] [Capture: Automatic] [Confirm: False]", () => {
let should_continue = true;
before("seed global state", () => {
cy.task("getGlobalState").then((state) => {
globalState = new State(state);
});
});
beforeEach(function () {
if (!should_continue) {
this.skip();
}
});
after("flush global state", () => {
cy.task("setGlobalState", globalState.data);
});
it.skip("Create Payment Intent", () => {
let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][
"PaymentIntent"
];
let req_data = data["Request"];
let res_data = data["Response"];
cy.paymentIntentCreateCall(
fixtures.createPaymentBody,
req_data,
res_data,
"no_three_ds",
"automatic",
globalState
);
});
it.skip("Payment Methods", () => {
cy.paymentMethodsCallTest(globalState);
});
it.skip("Confirm No 3DS", () => {
let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][
"No3DSAutoCapture"
];
let req_data = data["Request"];
let res_data = data["Response"];
cy.paymentIntentConfirmCall(
fixtures.confirmBody,
req_data,
res_data,
true,
globalState
);
});
it.skip("Retrieve payment intent", () => {
cy.paymentIntentRetrieveCall(globalState);
});
});
});

View File

@ -0,0 +1,8 @@
/*
3DS Auto capture with Confirm True
3DS Auto capture with Confirm False
3DS Manual capture with Confirm True
3DS Manual capture with Confirm False
3DS Manual multiple capture with Confirm True
3DS Manual multiple capture with Confirm False
*/

View File

@ -1,6 +1,6 @@
{
"org_create": {
"organization_name": "Hyperswitch Organization"
"organization_name": "Hyperswitch"
},
"org_update": {
"organization_name": "Hyperswitch",

View File

@ -26,10 +26,9 @@
// cy.task can only be used in support files (spec files or commands file)
import {
getValueByKey,
isoTimeTomorrow,
} from "../e2e/configs/Payment/Utils.js";
import { nanoid } from "nanoid";
import { getValueByKey } from "../e2e/configs/Payment/Utils.js";
import { isoTimeTomorrow, validateEnv } from "../utils/RequestBodyUtils.js";
function logRequestId(xRequestId) {
if (xRequestId) {
@ -48,6 +47,9 @@ Cypress.Commands.add(
const base_url = globalState.get("baseUrl");
const url = `${base_url}/v2/organization`;
// Update request body
organizationCreateBody.organization_name += " " + nanoid();
cy.request({
method: "POST",
url: url,
@ -71,7 +73,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Organization create call failed with status ${response.status} and message ${response.body.message}`
`Organization create call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -111,7 +113,7 @@ Cypress.Commands.add("organizationRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Organization retrieve call failed with status ${response.status} and message ${response.body.message}`
`Organization retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -125,6 +127,9 @@ Cypress.Commands.add(
const organization_id = globalState.get("organizationId");
const url = `${base_url}/v2/organization/${organization_id}`;
// Update request body
organizationUpdateBody.organization_name += " " + nanoid();
cy.request({
method: "PUT",
url: url,
@ -152,7 +157,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Organization update call failed with status ${response.status} and message ${response.body.message}`
`Organization update call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -166,6 +171,8 @@ Cypress.Commands.add(
// Define the necessary variables and constants
const api_key = globalState.get("adminApiKey");
const base_url = globalState.get("baseUrl");
const key_id_type = "publishable_key";
const key_id = validateEnv(base_url, key_id_type);
const organization_id = globalState.get("organizationId");
const url = `${base_url}/v2/merchant_accounts`;
@ -192,14 +199,9 @@ Cypress.Commands.add(
.and.to.include(`${merchant_name}_`)
.and.to.be.a("string").and.not.be.empty;
if (base_url.includes("sandbox") || base_url.includes("integ"))
expect(response.body)
.to.have.property("publishable_key")
.and.to.include("pk_snd").and.to.not.be.empty;
else if (base_url.includes("localhost"))
expect(response.body)
.to.have.property("publishable_key")
.and.to.include("pk_dev").and.to.not.be.empty;
expect(response.body)
.to.have.property(key_id_type)
.and.to.include(key_id).and.to.not.be.empty;
globalState.set("merchantId", response.body.id);
globalState.set("publishableKey", response.body.publishable_key);
@ -208,7 +210,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Merchant create call failed with status ${response.status} and message ${response.body.message}`
`Merchant create call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -218,6 +220,8 @@ Cypress.Commands.add("merchantAccountRetrieveCall", (globalState) => {
// Define the necessary variables and constants
const api_key = globalState.get("adminApiKey");
const base_url = globalState.get("baseUrl");
const key_id_type = "publishable_key";
const key_id = validateEnv(base_url, key_id_type);
const merchant_id = globalState.get("merchantId");
const url = `${base_url}/v2/merchant_accounts/${merchant_id}`;
@ -236,14 +240,8 @@ Cypress.Commands.add("merchantAccountRetrieveCall", (globalState) => {
expect(response.body).to.have.property("id").and.to.be.a("string").and.not
.be.empty;
if (base_url.includes("sandbox") || base_url.includes("integ"))
expect(response.body)
.to.have.property("publishable_key")
.and.to.include("pk_snd").and.to.not.be.empty;
else
expect(response.body)
.to.have.property("publishable_key")
.and.to.include("pk_dev").and.to.not.be.empty;
expect(response.body).to.have.property(key_id_type).and.to.include(key_id)
.and.to.not.be.empty;
if (merchant_id === undefined || merchant_id === null) {
globalState.set("merchantId", response.body.id);
@ -253,7 +251,7 @@ Cypress.Commands.add("merchantAccountRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Merchant account retrieve call failed with status ${response.status} and message ${response.body.message}`
`Merchant account retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -264,6 +262,8 @@ Cypress.Commands.add(
// Define the necessary variables and constants
const api_key = globalState.get("adminApiKey");
const base_url = globalState.get("baseUrl");
const key_id_type = "publishable_key";
const key_id = validateEnv(base_url, key_id_type);
const merchant_id = globalState.get("merchantId");
const url = `${base_url}/v2/merchant_accounts/${merchant_id}`;
@ -284,14 +284,10 @@ Cypress.Commands.add(
if (response.status === 200) {
expect(response.body.id).to.equal(merchant_id);
if (base_url.includes("sandbox") || base_url.includes("integ"))
expect(response.body)
.to.have.property("publishable_key")
.and.to.include("pk_snd").and.to.not.be.empty;
else
expect(response.body)
.to.have.property("publishable_key")
.and.to.include("pk_dev").and.to.not.be.empty;
expect(response.body)
.to.have.property(key_id_type)
.and.to.include(key_id).and.to.not.be.empty;
expect(response.body.merchant_name).to.equal(merchant_name);
if (merchant_id === undefined || merchant_id === null) {
@ -302,7 +298,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Merchant account update call failed with status ${response.status} and message ${response.body.message}`
`Merchant account update call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -349,7 +345,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Business profile create call failed with status ${response.status} and message ${response.body.message}`
`Business profile create call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -390,7 +386,7 @@ Cypress.Commands.add("businessProfileRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Business profile retrieve call failed with status ${response.status} and message ${response.body.message}`
`Business profile retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -436,7 +432,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Business profile update call failed with status ${response.status} and message ${response.body.message}`
`Business profile update call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -494,8 +490,8 @@ Cypress.Commands.add(
authDetails.connector_account_details;
if (authDetails && authDetails.metadata) {
createConnectorBody.metadata = {
...createConnectorBody.metadata, // Preserve existing metadata fields
mcaCreateBody.metadata = {
...mcaCreateBody.metadata, // Preserve existing metadata fields
...authDetails.metadata, // Merge with authDetails.metadata
};
}
@ -525,7 +521,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Merchant connector account create call failed with status ${response.status} and message ${response.body.message}`
`Merchant connector account create call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -573,7 +569,7 @@ Cypress.Commands.add("mcaRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Merchant connector account retrieve call failed with status ${response.status} and message ${response.body.message}`
`Merchant connector account retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -638,7 +634,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Merchant connector account update call failed with status ${response.status} and message ${response.body.message}`
`Merchant connector account update call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -654,6 +650,8 @@ Cypress.Commands.add("apiKeyCreateCall", (apiKeyCreateBody, globalState) => {
// 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 key_id_type = "key_id";
const key_id = validateEnv(base_url, key_id_type);
const merchant_id = globalState.get("merchantId");
const url = `${base_url}/v2/api_keys`;
@ -682,13 +680,8 @@ Cypress.Commands.add("apiKeyCreateCall", (apiKeyCreateBody, globalState) => {
expect(response.body.description).to.equal(apiKeyCreateBody.description);
// API Key assertions are intentionally excluded to avoid being exposed in the logs
if (base_url.includes("sandbox") || base_url.includes("integ")) {
expect(response.body).to.have.property("key_id").and.to.include("snd_")
.and.to.not.be.empty;
} else if (base_url.includes("localhost")) {
expect(response.body).to.have.property("key_id").and.to.include("dev_")
.and.to.not.be.empty;
}
expect(response.body).to.have.property(key_id_type).and.to.include(key_id)
.and.to.not.be.empty;
globalState.set("apiKeyId", response.body.key_id);
globalState.set("apiKey", response.body.api_key);
@ -697,7 +690,7 @@ Cypress.Commands.add("apiKeyCreateCall", (apiKeyCreateBody, globalState) => {
} else {
// to be updated
throw new Error(
`API Key create call failed with status ${response.status} and message ${response.body.message}`
`API Key create call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -706,6 +699,8 @@ Cypress.Commands.add("apiKeyRetrieveCall", (globalState) => {
// Define the necessary variables and constant
const api_key = globalState.get("adminApiKey");
const base_url = globalState.get("baseUrl");
const key_id_type = "key_id";
const key_id = validateEnv(base_url, key_id_type);
const merchant_id = globalState.get("merchantId");
const api_key_id = globalState.get("apiKeyId");
const url = `${base_url}/v2/api_keys/${api_key_id}`;
@ -728,15 +723,9 @@ Cypress.Commands.add("apiKeyRetrieveCall", (globalState) => {
if (response.status === 200) {
expect(response.body.merchant_id).to.equal(merchant_id);
// API Key assertions are intentionally excluded to avoid being exposed in the logs
if (base_url.includes("sandbox") || base_url.includes("integ")) {
expect(response.body).to.have.property("key_id").and.to.include("snd_")
.and.to.not.be.empty;
} else if (base_url.includes("localhost")) {
expect(response.body).to.have.property("key_id").and.to.include("dev_")
.and.to.not.be.empty;
}
expect(response.body).to.have.property(key_id_type).and.to.include(key_id)
.and.to.not.be.empty;
if (api_key === undefined || api_key === null) {
globalState.set("apiKey", response.body.api_key);
@ -745,7 +734,7 @@ Cypress.Commands.add("apiKeyRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`API Key retrieve call failed with status ${response.status} and message ${response.body.message}`
`API Key retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -758,6 +747,8 @@ Cypress.Commands.add("apiKeyUpdateCall", (apiKeyUpdateBody, globalState) => {
// 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 key_id_type = "key_id";
const key_id = validateEnv(base_url, key_id_type);
const merchant_id = globalState.get("merchantId");
const url = `${base_url}/v2/api_keys/${api_key_id}`;
@ -786,13 +777,8 @@ Cypress.Commands.add("apiKeyUpdateCall", (apiKeyUpdateBody, globalState) => {
expect(response.body.description).to.equal(apiKeyUpdateBody.description);
// API Key assertions are intentionally excluded to avoid being exposed in the logs
if (base_url.includes("sandbox") || base_url.includes("integ")) {
expect(response.body).to.have.property("key_id").and.to.include("snd_")
.and.to.not.be.empty;
} else if (base_url.includes("localhost")) {
expect(response.body).to.have.property("key_id").and.to.include("dev_")
.and.to.not.be.empty;
}
expect(response.body).to.have.property(key_id_type).and.to.include(key_id)
.and.to.not.be.empty;
if (api_key === undefined || api_key === null) {
globalState.set("apiKey", response.body.api_key);
@ -801,7 +787,7 @@ Cypress.Commands.add("apiKeyUpdateCall", (apiKeyUpdateBody, globalState) => {
} else {
// to be updated
throw new Error(
`API Key update call failed with status ${response.status} and message ${response.body.message}`
`API Key update call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -847,7 +833,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Routing algorithm setup call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm setup call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -886,7 +872,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Routing algorithm activation call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm activation call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -925,7 +911,7 @@ Cypress.Commands.add("routingActivationRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Routing algorithm activation retrieve call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm activation retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -960,7 +946,7 @@ Cypress.Commands.add("routingDeactivateCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Routing algorithm deactivation call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm deactivation call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -997,7 +983,7 @@ Cypress.Commands.add("routingRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Routing algorithm activation retrieve call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm activation retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1016,7 +1002,7 @@ Cypress.Commands.add(
routingDefaultFallbackBody = payload;
cy.request({
method: "POST",
method: "PATCH",
url: url,
headers: {
Authorization: `Bearer ${api_key}`,
@ -1032,7 +1018,7 @@ Cypress.Commands.add(
} else {
// to be updated
throw new Error(
`Routing algorithm activation retrieve call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm activation retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1061,7 +1047,7 @@ Cypress.Commands.add("routingFallbackRetrieveCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Routing algorithm activation retrieve call failed with status ${response.status} and message ${response.body.message}`
`Routing algorithm activation retrieve call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1100,7 +1086,7 @@ Cypress.Commands.add("userLogin", (globalState) => {
} else {
// to be updated
throw new Error(
`User login call failed to get totp token with status ${response.status} and message ${response.body.message}`
`User login call failed to get totp token with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1133,7 +1119,7 @@ Cypress.Commands.add("terminate2Fa", (globalState) => {
} else {
// to be updated
throw new Error(
`2FA terminate call failed with status ${response.status} and message ${response.body.message}`
`2FA terminate call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1166,7 +1152,7 @@ Cypress.Commands.add("userInfo", (globalState) => {
} else {
// to be updated
throw new Error(
`User login call failed to fetch user info with status ${response.status} and message ${response.body.message}`
`User login call failed to fetch user info with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1177,6 +1163,8 @@ Cypress.Commands.add("merchantAccountsListCall", (globalState) => {
// Define the necessary variables and constants
const api_key = globalState.get("adminApiKey");
const base_url = globalState.get("baseUrl");
const key_id_type = "publishable_key";
const key_id = validateEnv(base_url, key_id_type);
const organization_id = globalState.get("organizationId");
const url = `${base_url}/v2/organization/${organization_id}/merchant_accounts`;
@ -1198,21 +1186,15 @@ Cypress.Commands.add("merchantAccountsListCall", (globalState) => {
expect(response.body[key])
.to.have.property("organization_id")
.and.to.equal(organization_id);
if (base_url.includes("integ") || base_url.includes("sandbox")) {
expect(response.body[key])
.to.have.property("publishable_key")
.and.include("pk_snd_").and.to.not.be.empty;
} else if (base_url.includes("localhost")) {
expect(response.body[key])
.to.have.property("publishable_key")
.and.include("pk_dev_").and.to.not.be.empty;
}
expect(response.body[key])
.to.have.property(key_id_type)
.and.include(key_id).and.to.not.be.empty;
expect(response.body[key]).to.have.property("id").and.to.not.be.empty;
}
} else {
// to be updated
throw new Error(
`Merchant accounts list call failed with status ${response.status} and message ${response.body.message}`
`Merchant accounts list call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1253,7 +1235,7 @@ Cypress.Commands.add("businessProfilesListCall", (globalState) => {
} else {
// to be updated
throw new Error(
`Business profiles list call failed with status ${response.status} and message ${response.body.message}`
`Business profiles list call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1314,7 +1296,7 @@ Cypress.Commands.add("mcaListCall", (globalState, service_type) => {
} else {
// to be updated
throw new Error(
`Merchant connector account list call failed with status ${response.status} and message ${response.body.message}`
`Merchant connector account list call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
@ -1323,6 +1305,8 @@ Cypress.Commands.add("apiKeysListCall", (globalState) => {
// Define the necessary variables and constants
const api_key = globalState.get("adminApiKey");
const base_url = globalState.get("baseUrl");
const key_id_type = "key_id";
const key_id = validateEnv(base_url, key_id_type);
const merchant_id = globalState.get("merchantId");
const url = `${base_url}/v2/api_keys/list`;
@ -1347,8 +1331,8 @@ Cypress.Commands.add("apiKeysListCall", (globalState) => {
expect(response.body).to.be.an("array").and.to.not.be.empty;
for (const key in response.body) {
expect(response.body[key])
.to.have.property("key_id")
.and.to.include("dev_").and.to.not.be.empty;
.to.have.property(key_id_type)
.and.to.include(key_id).and.to.not.be.empty;
expect(response.body[key])
.to.have.property("merchant_id")
.and.to.equal(merchant_id).and.to.not.be.empty;
@ -1356,13 +1340,74 @@ Cypress.Commands.add("apiKeysListCall", (globalState) => {
} else {
// to be updated
throw new Error(
`API Keys list call failed with status ${response.status} and message ${response.body.message}`
`API Keys list call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
});
// templates
// Payment API calls
// Update the below commands while following the conventions
// Below is an example of how the payment intent create call should look like (update the below command as per the need)
Cypress.Commands.add(
"paymentIntentCreateCall",
(
globalState,
paymentRequestBody,
paymentResponseBody
/* Add more variables based on the need*/
) => {
// Define the necessary variables and constants at the top
// Also construct the URL here
const api_key = globalState.get("apiKey");
const base_url = globalState.get("baseUrl");
const profile_id = globalState.get("profileId");
const url = `${base_url}/v2/payments/create-intent`;
// Update request body if needed
paymentRequestBody = {};
// Pass Custom Headers
const customHeaders = {
"x-profile-id": profile_id,
};
cy.request({
method: "POST",
url: url,
headers: {
"api-key": api_key,
"Content-Type": "application/json",
...customHeaders,
},
body: paymentRequestBody,
failOnStatusCode: false,
}).then((response) => {
// Logging x-request-id is mandatory
logRequestId(response.headers["x-request-id"]);
if (response.status === 200) {
// Update the assertions based on the need
expect(response.body).to.deep.equal(paymentResponseBody);
} else if (response.status === 400) {
// Add 4xx validations here
expect(response.body).to.deep.equal(paymentResponseBody);
} else if (response.status === 500) {
// Add 5xx validations here
expect(response.body).to.deep.equal(paymentResponseBody);
} else {
// If status code is other than the ones mentioned above, default should be thrown
throw new Error(
`Payment intent create call failed with status ${response.status} and message: "${response.body.error.message}"`
);
}
});
}
);
Cypress.Commands.add("paymentIntentConfirmCall", (globalState) => {});
Cypress.Commands.add("paymentIntentRetrieveCall", (globalState) => {});
// templates for future use
Cypress.Commands.add("", () => {
cy.request({}).then((response) => {});
});

View File

@ -0,0 +1,48 @@
const keyPrefixes = {
localhost: {
publishable_key: "pk_dev_",
key_id: "dev_",
},
integ: {
publishable_key: "pk_snd_",
key_id: "snd_",
},
sandbox: {
publishable_key: "pk_snd_",
key_id: "snd_",
},
};
export function isoTimeTomorrow() {
const now = new Date();
// Create a new date object for tomorrow
const tomorrow = new Date(now);
tomorrow.setDate(now.getDate() + 1);
// Convert to ISO string format
const isoStringTomorrow = tomorrow.toISOString();
return isoStringTomorrow;
}
export function validateEnv(baseUrl, keyIdType) {
if (!baseUrl) {
throw new Error("Please provide a baseUrl");
}
const environment = Object.keys(keyPrefixes).find((env) =>
baseUrl.includes(env)
);
if (!environment) {
throw new Error("Unsupported baseUrl");
}
const prefix = keyPrefixes[environment][keyIdType];
if (!prefix) {
throw new Error(`Unsupported keyIdType: ${keyIdType}`);
}
return prefix;
}

View File

@ -10,9 +10,10 @@
"license": "ISC",
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"cypress": "^13.14.2",
"cypress": "^13.15.2",
"cypress-mochawesome-reporter": "^3.8.2",
"jsqr": "^1.4.0",
"nanoid": "^5.0.8",
"prettier": "^3.3.2"
}
},
@ -28,9 +29,9 @@
}
},
"node_modules/@cypress/request": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz",
"integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.6.tgz",
"integrity": "sha512-fi0eVdCOtKu5Ed6+E8mYxUF6ZTFJDZvHogCBelM0xVXmrDEkyM22gRArQzq1YcHPm1V47Vf/iAD+WgVdUlJCGg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@ -49,7 +50,7 @@
"performance-now": "^2.1.0",
"qs": "6.13.0",
"safe-buffer": "^5.1.2",
"tough-cookie": "^4.1.3",
"tough-cookie": "^5.0.0",
"tunnel-agent": "^0.6.0",
"uuid": "^8.3.2"
},
@ -567,9 +568,9 @@
}
},
"node_modules/ci-info": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz",
"integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==",
"dev": true,
"funding": [
{
@ -741,14 +742,14 @@
}
},
"node_modules/cypress": {
"version": "13.14.2",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz",
"integrity": "sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==",
"version": "13.15.2",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.2.tgz",
"integrity": "sha512-ARbnUorjcCM3XiPwgHKuqsyr5W9Qn+pIIBPaoilnoBkLdSC2oLQjV1BUpnmc7KR+b7Avah3Ly2RMFnfxr96E/A==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@cypress/request": "^3.0.1",
"@cypress/request": "^3.0.6",
"@cypress/xvfb": "^1.2.4",
"@types/sinonjs__fake-timers": "8.1.1",
"@types/sizzle": "^2.3.2",
@ -759,6 +760,7 @@
"cachedir": "^2.3.0",
"chalk": "^4.1.0",
"check-more-types": "^2.24.0",
"ci-info": "^4.0.0",
"cli-cursor": "^3.1.0",
"cli-table3": "~0.6.1",
"commander": "^6.2.1",
@ -773,7 +775,6 @@
"figures": "^3.2.0",
"fs-extra": "^9.1.0",
"getos": "^3.2.1",
"is-ci": "^3.0.1",
"is-installed-globally": "~0.4.0",
"lazy-ass": "^1.6.0",
"listr2": "^3.8.3",
@ -788,6 +789,7 @@
"semver": "^7.5.3",
"supports-color": "^8.1.1",
"tmp": "~0.2.3",
"tree-kill": "1.2.2",
"untildify": "^4.0.0",
"yauzl": "^2.10.0"
},
@ -1203,9 +1205,9 @@
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1583,19 +1585,6 @@
"node": ">=8"
}
},
"node_modules/is-ci": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
"integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ci-info": "^3.2.0"
},
"bin": {
"is-ci": "bin.js"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -2457,6 +2446,25 @@
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz",
"integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.js"
},
"engines": {
"node": "^18 || >=20"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -2733,13 +2741,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
"dev": true,
"license": "MIT"
},
"node_modules/pump": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
@ -2751,16 +2752,6 @@
"once": "^1.3.1"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
@ -2777,13 +2768,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true,
"license": "MIT"
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -2843,13 +2827,6 @@
"dev": true,
"license": "ISC"
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true,
"license": "MIT"
},
"node_modules/restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@ -3150,6 +3127,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/tldts": {
"version": "6.1.59",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.59.tgz",
"integrity": "sha512-472ilPxsRuqBBpn+KuRBHJvZhk6tTo4yTVsmODrLBNLwRYJPkDfMEHivgNwp5iEl+cbrZzzRtLKRxZs7+QKkRg==",
"dev": true,
"license": "MIT",
"dependencies": {
"tldts-core": "^6.1.59"
},
"bin": {
"tldts": "bin/cli.js"
}
},
"node_modules/tldts-core": {
"version": "6.1.59",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.59.tgz",
"integrity": "sha512-EiYgNf275AQyVORl8HQYYe7rTVnmLb4hkWK7wAk/12Ksy5EiHpmUmTICa4GojookBPC8qkLMBKKwCmzNA47ZPQ==",
"dev": true,
"license": "MIT"
},
"node_modules/tmp": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
@ -3175,29 +3172,26 @@
}
},
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
"integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
"tldts": "^6.1.32"
},
"engines": {
"node": ">=6"
"node": ">=16"
}
},
"node_modules/tough-cookie/node_modules/universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
"bin": {
"tree-kill": "cli.js"
}
},
"node_modules/tslib": {
@ -3267,17 +3261,6 @@
"node": ">=8"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",

View File

@ -15,9 +15,10 @@
"license": "ISC",
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"cypress": "^13.14.2",
"cypress": "^13.15.2",
"cypress-mochawesome-reporter": "^3.8.2",
"jsqr": "^1.4.0",
"prettier": "^3.3.2"
"prettier": "^3.3.2",
"nanoid": "^5.0.8"
}
}