Add tests for stripe (#1529)
* test for stripe * first test for stripe * tests for stripe * remove comment * fix import * fix import * remove todo
This commit is contained in:
parent
d0a6e10cec
commit
d618b8e775
10 changed files with 382 additions and 36 deletions
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"adyen": {
|
||||
"clientData": "eyJ2ZXJzaW9uIjoiMS4wLjAiLCJkZXZpY2VGaW5nZXJwcmludCI6InpabUlDMEVYOHcwMDMwMDAwMDAwMDAwMDAwS1piSVFqNmt6czAwNjA4MjQxOTBjVkI5NGlLekJHS1IybWJMc3JmckFKUEdCY2JHSG0wMDZpdmJTdVlkRzBSMDAwMDBZVnhFcjAwMDAwVk1yM0h5dHhQNmlaQ3FuSTRsc2s6NDAiLCJwZXJzaXN0ZW50Q29va2llIjpbXSwiY29tcG9uZW50cyI6eyJ1c2VyQWdlbnQiOiJkYzJjNDM2MThlOTM0YjY2NmIwOWIxNmEzZDE4NmViZCIsIndlYmRyaXZlciI6MCwibGFuZ3VhZ2UiOiJwbC1QTCIsImNvbG9yRGVwdGgiOjMwLCJkZXZpY2VNZW1vcnkiOjgsInBpeGVsUmF0aW8iOjIsImhhcmR3YXJlQ29uY3VycmVuY3kiOjEyLCJzY3JlZW5XaWR0aCI6MTc5Miwic2NyZWVuSGVpZ2h0IjoxMTIwLCJhdmFpbGFibGVTY3JlZW5XaWR0aCI6MTc5MiwiYXZhaWxhYmxlU2NyZWVuSGVpZ2h0IjoxMDMwLCJ0aW1lem9uZU9mZnNldCI6LTEyMCwidGltZXpvbmUiOiJFdXJvcGUvV2Fyc2F3Iiwic2Vzc2lvblN0b3JhZ2UiOjEsImxvY2FsU3RvcmFnZSI6MSwiaW5kZXhlZERiIjoxLCJhZGRCZWhhdmlvciI6MCwib3BlbkRhdGFiYXNlIjoxLCJwbGF0Zm9ybSI6Ik1hY0ludGVsIiwicGx1Z2lucyI6ImMxMzU2NDM4NzUxNzZkZWU5MTkyZTE5ZDRkOGM3YTkwIiwiY2FudmFzIjoiZDYxNjRlNzA3ZWQ4NDdlNTE4OGE1YjUyMDhmNDI1OGIiLCJ3ZWJnbCI6IjcwM2ZjZWMyM2MxNjhlYjAzNmM0MjA3MzA1ODYzZmNlIiwid2ViZ2xWZW5kb3JBbmRSZW5kZXJlciI6IkludGVsIEluYy5+SW50ZWwoUikgVUhEIEdyYXBoaWNzIDYzMCIsImFkQmxvY2siOjAsImhhc0xpZWRMYW5ndWFnZXMiOjAsImhhc0xpZWRSZXNvbHV0aW9uIjowLCJoYXNMaWVkT3MiOjAsImhhc0xpZWRCcm93c2VyIjowLCJmb250cyI6IjI5MmVhMmNjZWNjZDAyYjAxYzBjNGMxZDQxMzIxNzVlIiwiYXVkaW8iOiIzOTRmNjQwMGY0NDg5NDIwNDIzZGYzMzY1OGU1NGJlNiIsImVudW1lcmF0ZURldmljZXMiOiJmMjA4Yzc3MWExNjBiNjRmNDkzOWFmYmE1OTY2YTRhZiJ9fQ==",
|
||||
"encryptedExpiryMonth": "test_03",
|
||||
"encryptedExpiryYear": "test_2030",
|
||||
|
@ -23,13 +24,19 @@
|
|||
"brand": "visa",
|
||||
"encryptedCardNumber": "test_5201282999005515"
|
||||
},
|
||||
"closeAccount" : {
|
||||
"closeAccount": {
|
||||
"brand": "visa",
|
||||
"encryptedCardNumber" : "test_5454541580311093"
|
||||
"encryptedCardNumber": "test_5454541580311093"
|
||||
},
|
||||
"avs" : {
|
||||
"avs": {
|
||||
"brand": "visa",
|
||||
"encryptedCardNumber" : "test_4400000000000008"
|
||||
"encryptedCardNumber": "test_4400000000000008"
|
||||
}
|
||||
}
|
||||
},
|
||||
"stripe":{
|
||||
"simpleCardNumber": "5555555555554444",
|
||||
"insufficientFundsCard": "4000000000009995",
|
||||
"threeDSecureAuthCard": "4000002760003184"
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ export const urlList = {
|
|||
shippingMethods: "shipping/",
|
||||
siteSettings: "site-settings/",
|
||||
staffMembers: "staff/",
|
||||
stripeApiPaymentMethods: "https://api.stripe.com/v1/payment_methods",
|
||||
translations: "translations/",
|
||||
vouchers: "discounts/vouchers/",
|
||||
warehouses: "warehouses/",
|
||||
|
@ -70,3 +71,6 @@ export const productTypeDetailsUrl = productTypeId =>
|
|||
|
||||
export const giftCardDetailsUrl = giftCardId =>
|
||||
`${urlList.giftCards}${giftCardId}`;
|
||||
|
||||
export const stripeConfirmationUrl = id =>
|
||||
`https://api.stripe.com/v1/payment_intents/${id}/confirm`;
|
||||
|
|
|
@ -42,7 +42,7 @@ filterTests({ definedTags: ["stagedOnly"] }, () => {
|
|||
deleteProductsStartsWith(startsWith);
|
||||
deleteShippingStartsWith(startsWith);
|
||||
cy.fixture("cards").then(cardsResp => {
|
||||
paymentCards = cardsResp;
|
||||
paymentCards = cardsResp.adyen;
|
||||
cardData = {
|
||||
clientData: paymentCards.clientData,
|
||||
encryptedExpiryMonth: paymentCards.encryptedExpiryMonth,
|
||||
|
|
140
cypress/integration/configuration/plugins/stripe.js
Normal file
140
cypress/integration/configuration/plugins/stripe.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
/// <reference types="cypress"/>
|
||||
/// <reference types="../../../support"/>
|
||||
|
||||
import {
|
||||
addShippingMethod,
|
||||
completeCheckout,
|
||||
createCheckout
|
||||
} from "../../../support/api/requests/Checkout";
|
||||
import { getOrder } from "../../../support/api/requests/Order";
|
||||
import { confirmThreeDSecure } from "../../../support/api/requests/stripe";
|
||||
import { addStripePaymentAndGetConfirmationData } from "../../../support/api/utils/ordersUtils";
|
||||
import { createProductWithShipping } from "../../../support/api/utils/products/productsUtils";
|
||||
import { deleteShippingStartsWith } from "../../../support/api/utils/shippingUtils";
|
||||
import filterTests from "../../../support/filterTests";
|
||||
|
||||
filterTests({ definedTags: ["stagedOnly"] }, () => {
|
||||
describe("Stripe payments", () => {
|
||||
const startsWith = "Stripe-";
|
||||
const email = `example@example.com`;
|
||||
|
||||
let address;
|
||||
let defaultChannel;
|
||||
let shippingMethod;
|
||||
let variantsList;
|
||||
let checkout;
|
||||
let paymentCards;
|
||||
let cardData;
|
||||
|
||||
before(() => {
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
deleteShippingStartsWith(startsWith);
|
||||
cy.fixture("cards").then(({ stripe }) => {
|
||||
paymentCards = stripe;
|
||||
cardData = {
|
||||
publicKey: paymentCards.publicApiKey,
|
||||
cvc: 123,
|
||||
expMonth: 10,
|
||||
expYear: 50
|
||||
};
|
||||
});
|
||||
createProductWithShipping({ name: startsWith }).then(values => {
|
||||
address = values.address;
|
||||
defaultChannel = values.defaultChannel;
|
||||
shippingMethod = values.shippingMethod;
|
||||
variantsList = values.variantsList;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
createCheckout({
|
||||
channelSlug: defaultChannel.slug,
|
||||
email,
|
||||
variantsList,
|
||||
address,
|
||||
billingAddress: address,
|
||||
auth: "token"
|
||||
})
|
||||
.then(({ checkout: checkoutResp }) => {
|
||||
checkout = checkoutResp;
|
||||
addShippingMethod(checkout.id, shippingMethod.id);
|
||||
})
|
||||
.then(({ checkout: checkoutResp }) => {
|
||||
checkout = checkoutResp;
|
||||
});
|
||||
});
|
||||
|
||||
it("should purchase products with simple card", () => {
|
||||
const simpleCard = cardData;
|
||||
simpleCard.cardNumber = paymentCards.simpleCardNumber;
|
||||
addStripePaymentAndGetConfirmationData({
|
||||
card: simpleCard,
|
||||
checkoutId: checkout.id,
|
||||
amount: checkout.totalPrice.gross.amount
|
||||
})
|
||||
.then(() => {
|
||||
completeCheckout(checkout.id);
|
||||
})
|
||||
.then(({ order }) => {
|
||||
getOrder(order.id);
|
||||
})
|
||||
.then(order => {
|
||||
expect(order.paymentStatus).to.eq("FULLY_CHARGED");
|
||||
});
|
||||
});
|
||||
|
||||
it("should not purchase products with card with insufficient funds", () => {
|
||||
const simpleCard = cardData;
|
||||
simpleCard.cardNumber = paymentCards.insufficientFundsCard;
|
||||
addStripePaymentAndGetConfirmationData({
|
||||
card: simpleCard,
|
||||
checkoutId: checkout.id,
|
||||
amount: checkout.totalPrice.gross.amount
|
||||
}).then(resp => {
|
||||
expect(resp.body.error.code).to.equal("card_declined");
|
||||
});
|
||||
});
|
||||
|
||||
it("should purchase products with 3D secure card", () => {
|
||||
const threeDSecureCard = cardData;
|
||||
threeDSecureCard.cardNumber = paymentCards.threeDSecureAuthCard;
|
||||
addStripePaymentAndGetConfirmationData({
|
||||
card: threeDSecureCard,
|
||||
checkoutId: checkout.id,
|
||||
amount: checkout.totalPrice.gross.amount
|
||||
})
|
||||
.then(resp => {
|
||||
confirmThreeDSecure(resp.body.next_action.redirect_to_url.url);
|
||||
})
|
||||
.then(() => {
|
||||
completeCheckout(checkout.id);
|
||||
})
|
||||
.then(({ order }) => {
|
||||
getOrder(order.id);
|
||||
})
|
||||
.then(order => {
|
||||
expect(order.paymentStatus).to.eq("FULLY_CHARGED");
|
||||
});
|
||||
});
|
||||
|
||||
it("should not purchase product when 3D secure not pass", () => {
|
||||
const threeDSecureCard = cardData;
|
||||
threeDSecureCard.cardNumber = paymentCards.threeDSecureAuthCard;
|
||||
addStripePaymentAndGetConfirmationData({
|
||||
card: threeDSecureCard,
|
||||
checkoutId: checkout.id,
|
||||
amount: checkout.totalPrice.gross.amount
|
||||
})
|
||||
.then(resp => {
|
||||
confirmThreeDSecure(resp.body.next_action.redirect_to_url.url, false);
|
||||
})
|
||||
.then(() => {
|
||||
completeCheckout(checkout.id);
|
||||
})
|
||||
.then(({ order }) => {
|
||||
expect(order).to.not.be.ok;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -67,6 +67,7 @@ filterTests({ definedTags: ["all"] }, () => {
|
|||
it("Should upload saved image", () => {
|
||||
const name = "CyImages";
|
||||
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
loginDeleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({ name })
|
||||
.then(product => {
|
||||
cy.visit(productDetailsUrl(product.id))
|
||||
|
|
|
@ -26,6 +26,8 @@ module.exports = async (on, config) => {
|
|||
config.env.APP_MOUNT_URI = process.env.APP_MOUNT_URI;
|
||||
config.env.mailHogUrl = process.env.CYPRESS_MAILHOG;
|
||||
config.env.SHOP = await getShopInfo(process.env);
|
||||
config.env.STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
|
||||
config.env.STRIPE_PUBLIC_KEY = process.env.STRIPE_PUBLIC_KEY;
|
||||
|
||||
on("before:browser:launch", (browser = {}, launchOptions) => {
|
||||
launchOptions.args.push("--proxy-bypass-list=<-loopback>");
|
||||
|
|
|
@ -69,6 +69,7 @@ export function addShippingMethod(checkoutId, shippingMethodId) {
|
|||
field
|
||||
}
|
||||
checkout{
|
||||
id
|
||||
shippingMethod{
|
||||
id
|
||||
name
|
||||
|
@ -107,6 +108,7 @@ export function addPayment({ checkoutId, gateway, token, amount }) {
|
|||
gateway: "${gateway}"
|
||||
${tokenLine}
|
||||
${amountLine}
|
||||
returnUrl: "https://qa.storefront.staging.saleor.cloud/checkout/payment-confirm"
|
||||
}){
|
||||
paymentErrors{
|
||||
field
|
||||
|
|
106
cypress/support/api/requests/stripe.js
Normal file
106
cypress/support/api/requests/stripe.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { stripeConfirmationUrl, urlList } from "../../../fixtures/urlList";
|
||||
import { getValueWithDefault } from "./utils/Utils";
|
||||
|
||||
const stripeAuthBearer = `Bearer ${Cypress.env("STRIPE_SECRET_KEY")}`;
|
||||
const stripePublicKey = Cypress.env("STRIPE_PUBLIC_KEY");
|
||||
|
||||
export function getPaymentMethodStripeId({
|
||||
cardNumber,
|
||||
cvc,
|
||||
expMonth,
|
||||
expYear
|
||||
}) {
|
||||
return cy.request({
|
||||
url: urlList.stripeApiPaymentMethods,
|
||||
method: "POST",
|
||||
form: true,
|
||||
body: {
|
||||
type: "card",
|
||||
"card[number]": cardNumber,
|
||||
"card[cvc]": cvc,
|
||||
"card[exp_month]": expMonth,
|
||||
"card[exp_year]": expYear,
|
||||
pasted_fields: "number",
|
||||
key: stripePublicKey
|
||||
},
|
||||
headers: {
|
||||
Authorization: stripeAuthBearer
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function sendConfirmationToStripe(paymentMethodId, confirmationId) {
|
||||
return cy.request({
|
||||
method: "POST",
|
||||
url: stripeConfirmationUrl(confirmationId),
|
||||
form: true,
|
||||
failOnStatusCode: false,
|
||||
headers: {
|
||||
Authorization: stripeAuthBearer
|
||||
},
|
||||
body: {
|
||||
payment_method: paymentMethodId,
|
||||
return_url: Cypress.config().baseUrl,
|
||||
webauthn_uvpa_available: "true",
|
||||
spc_eligible: "false",
|
||||
key: stripePublicKey
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function confirmThreeDSecure(nextActionUrl, withSuccess = true) {
|
||||
let returnUrl;
|
||||
const paRes = getValueWithDefault(withSuccess, "success", "failure");
|
||||
|
||||
return cy
|
||||
.request(nextActionUrl)
|
||||
.then(resp => {
|
||||
const { body } = new DOMParser().parseFromString(resp.body, "text/html");
|
||||
const formUrl = body.querySelector('[id="form"]').getAttribute("action");
|
||||
const source = body
|
||||
.querySelector('[name="source"]')
|
||||
.getAttribute("value");
|
||||
returnUrl = body
|
||||
.querySelector('[name="return_url"]')
|
||||
.getAttribute("value");
|
||||
const amount = body
|
||||
.querySelector('[name="amount"]')
|
||||
.getAttribute("value");
|
||||
const currency = body
|
||||
.querySelector('[name="currency"]')
|
||||
.getAttribute("value");
|
||||
const usage = body.querySelector('[name="usage"]').getAttribute("value");
|
||||
|
||||
const url = `${formUrl}?source=${source}&livemode=false&type=three_d_secure&pass_through=&return_url=${returnUrl}&amount=${amount}¤cy=
|
||||
${currency}&usage=${usage}`;
|
||||
cy.request(url);
|
||||
})
|
||||
.then(() => {
|
||||
cy.request({
|
||||
url: returnUrl,
|
||||
method: "POST",
|
||||
form: true,
|
||||
body: {
|
||||
PaRes: "success",
|
||||
MD: ""
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(resp => {
|
||||
const { body } = new DOMParser().parseFromString(resp.body, "text/html");
|
||||
const formUrl = body.querySelector('[id="form"]').getAttribute("action");
|
||||
const merchant = body
|
||||
.querySelector('[name="merchant"]')
|
||||
.getAttribute("value");
|
||||
cy.request({
|
||||
url: formUrl,
|
||||
method: "POST",
|
||||
form: true,
|
||||
body: {
|
||||
PaRes: paRes,
|
||||
MD: "",
|
||||
Merchant: merchant
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
import * as checkoutRequest from "../requests/Checkout";
|
||||
import * as orderRequest from "../requests/Order";
|
||||
import {
|
||||
getPaymentMethodStripeId,
|
||||
sendConfirmationToStripe
|
||||
} from "../requests/stripe";
|
||||
import { createProductInChannel } from "./products/productsUtils";
|
||||
|
||||
export function createWaitingForCaptureOrder({
|
||||
|
@ -172,6 +176,14 @@ export function addAdyenPayment(checkoutId, amount) {
|
|||
amount
|
||||
});
|
||||
}
|
||||
export function addStripePayment(checkoutId, amount, token) {
|
||||
return checkoutRequest.addPayment({
|
||||
checkoutId,
|
||||
gateway: "saleor.payments.stripe",
|
||||
amount,
|
||||
token
|
||||
});
|
||||
}
|
||||
|
||||
export function createAndCompleteCheckoutWithoutShipping({
|
||||
channelSlug,
|
||||
|
@ -226,3 +238,25 @@ export function createOrderWithNewProduct({
|
|||
})
|
||||
.then(({ order, checkout }) => ({ order, checkout, variantsList }));
|
||||
}
|
||||
|
||||
export function addStripePaymentAndGetConfirmationData({
|
||||
card,
|
||||
checkoutId,
|
||||
amount
|
||||
}) {
|
||||
let paymentMethodId;
|
||||
|
||||
return getPaymentMethodStripeId(card)
|
||||
.then(resp => {
|
||||
paymentMethodId = resp.body.id;
|
||||
addStripePayment(checkoutId, amount, resp.body.id);
|
||||
})
|
||||
.then(() => {
|
||||
checkoutRequest.completeCheckout(checkoutId);
|
||||
})
|
||||
.then(resp => {
|
||||
const confirmationData = JSON.parse(resp.confirmationData);
|
||||
sendConfirmationToStripe(paymentMethodId, confirmationData.id, false);
|
||||
})
|
||||
.then(resp => resp);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
import { deleteAttributesStartsWith } from "../attributes/attributeUtils";
|
||||
import { deleteCollectionsStartsWith } from "../catalog/collectionsUtils";
|
||||
import { getDefaultChannel } from "../channelsUtils";
|
||||
import { createShipping } from "../shippingUtils";
|
||||
|
||||
export function createProductInChannel({
|
||||
name,
|
||||
|
@ -107,15 +108,15 @@ export function deleteProductsStartsWith(startsWith) {
|
|||
);
|
||||
}
|
||||
|
||||
export function loginDeleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({
|
||||
export function deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({
|
||||
name,
|
||||
description = name
|
||||
description = name,
|
||||
warehouseId
|
||||
}) {
|
||||
let defaultChannel;
|
||||
let collection;
|
||||
let attribute;
|
||||
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
deleteProductsStartsWith(name);
|
||||
deleteCollectionsStartsWith(name);
|
||||
return getDefaultChannel()
|
||||
|
@ -136,8 +137,57 @@ export function loginDeleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({
|
|||
channelId: defaultChannel.id,
|
||||
name,
|
||||
collectionId: collection.id,
|
||||
description
|
||||
description,
|
||||
warehouseId
|
||||
});
|
||||
})
|
||||
.then(({ product: productResp }) => productResp);
|
||||
.then(({ product, variantsList }) => ({ product, variantsList }));
|
||||
}
|
||||
|
||||
export function createProductWithShipping({ name }) {
|
||||
let address;
|
||||
let warehouse;
|
||||
let shippingMethod;
|
||||
let defaultChannel;
|
||||
let shippingZone;
|
||||
|
||||
return cy
|
||||
.fixture("addresses")
|
||||
.then(addresses => {
|
||||
address = addresses.usAddress;
|
||||
getDefaultChannel();
|
||||
})
|
||||
.then(channelResp => {
|
||||
defaultChannel = channelResp;
|
||||
createShipping({
|
||||
channelId: defaultChannel.id,
|
||||
name,
|
||||
address,
|
||||
price: 10
|
||||
});
|
||||
})
|
||||
.then(
|
||||
({
|
||||
warehouse: warehouseResp,
|
||||
shippingZone: shippingZoneResp,
|
||||
shippingMethod: shippingMethodResp
|
||||
}) => {
|
||||
warehouse = warehouseResp;
|
||||
shippingMethod = shippingMethodResp;
|
||||
shippingZone = shippingZoneResp;
|
||||
deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({
|
||||
name,
|
||||
warehouseId: warehouse.id
|
||||
});
|
||||
}
|
||||
)
|
||||
.then(({ variantsList, product }) => ({
|
||||
variantsList,
|
||||
product,
|
||||
warehouse,
|
||||
shippingZone,
|
||||
defaultChannel,
|
||||
shippingMethod,
|
||||
address
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue