Skip to content

Commit

Permalink
Merge branch 'main' into LYNX-722
Browse files Browse the repository at this point in the history
  • Loading branch information
sirugh authored Feb 7, 2025
2 parents 8e0906a + 59c597e commit ccdd525
Show file tree
Hide file tree
Showing 88 changed files with 838 additions and 196 deletions.
2 changes: 2 additions & 0 deletions blocks/commerce-checkout/commerce-checkout.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
.checkout__payment-methods {
padding-top: var(--spacing-xbig);
border-top: var(--shape-border-width-3) solid var(--color-neutral-400);
padding-bottom: var(--spacing-xbig);
border-bottom: var(--shape-border-width-3) solid var(--color-neutral-400);
}

/* Hide empty blocks */
Expand Down
112 changes: 85 additions & 27 deletions blocks/commerce-checkout/commerce-checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,20 @@ import OrderStatus from '@dropins/storefront-order/containers/OrderStatus.js';
import ShippingStatus from '@dropins/storefront-order/containers/ShippingStatus.js';
import { render as OrderProvider } from '@dropins/storefront-order/render.js';

// Payment Services Dropin
import { PaymentMethodCode } from '@dropins/storefront-payment-services/api.js';
import CreditCard from '@dropins/storefront-payment-services/containers/CreditCard.js';
import { render as PaymentServices } from '@dropins/storefront-payment-services/render.js';
import { getConfigValue } from '../../scripts/configs.js';
import { getUserTokenCookie } from '../../scripts/initializers/index.js';

// Block-level
import createModal from '../modal/modal.js';

// Scripts
import { getUserTokenCookie } from '../../scripts/initializers/index.js';
import {
estimateShippingCost, getCartAddress,
estimateShippingCost,
getCartAddress,
isCartEmpty,
isCheckoutEmpty,
scrollToElement,
Expand Down Expand Up @@ -114,7 +121,7 @@ export default async function decorate(block) {
setMetaTags('Checkout');
document.title = 'Checkout';

events.on('checkout/order', () => {
events.on('order/placed', () => {
setMetaTags('Order Confirmation');
document.title = 'Order Confirmation';
});
Expand Down Expand Up @@ -196,13 +203,17 @@ export default async function decorate(block) {
let loader;
let modal;
let emptyCart;
let shippingFormRef = { current: null };
let billingFormRef = { current: null };
const shippingFormRef = { current: null };
const billingFormRef = { current: null };
const creditCardFormRef = { current: null };
let shippingForm;
let billingForm;
let shippingAddresses;
let billingAddresses;

// Adobe Commerce GraphQL endpoint
const commerceCoreEndpoint = await getConfigValue('commerce-core-endpoint');

// Render the initial containers
const [
_mergedCartBanner,
Expand All @@ -221,9 +232,14 @@ export default async function decorate(block) {
] = await Promise.all([
CheckoutProvider.render(MergedCartBanner)($mergedCartBanner),

UI.render(Header, { title: 'Checkout', size: 'large', divider: true })($heading),
UI.render(Header, {
title: 'Checkout',
size: 'large',
divider: true,
})($heading),

CheckoutProvider.render(ServerError, {
autoScroll: true,
onRetry: () => {
$content.classList.remove('checkout__content--error');
},
Expand Down Expand Up @@ -290,12 +306,40 @@ export default async function decorate(block) {

CheckoutProvider.render(ShippingMethods, {
hideOnVirtualCart: true,
onCheckoutDataUpdate: () => {
cartApi.refreshCart().catch(console.error);
},
})($delivery),

CheckoutProvider.render(PaymentMethods)($paymentMethods),
CheckoutProvider.render(PaymentMethods, {
slots: {
Methods: {
[PaymentMethodCode.CREDIT_CARD]: {
render: (ctx) => {
const $content = document.createElement('div');

PaymentServices.render(CreditCard, {
apiUrl: commerceCoreEndpoint,
getCustomerToken: getUserTokenCookie,
getCartId: () => ctx.cartId,
creditCardFormRef,
})($content);

ctx.replaceHTML($content);
},
},
[PaymentMethodCode.SMART_BUTTONS]: {
enabled: false,
},
[PaymentMethodCode.APPLE_PAY]: {
enabled: false,
},
[PaymentMethodCode.GOOGLE_PAY]: {
enabled: false,
},
[PaymentMethodCode.VAULT]: {
enabled: false,
},
},
},
})($paymentMethods),

AccountProvider.render(AddressForm, {
isOpen: true,
Expand Down Expand Up @@ -393,10 +437,30 @@ export default async function decorate(block) {

return success;
},
handlePlaceOrder: async ({ cartId }) => {
handlePlaceOrder: async ({ cartId, code }) => {
await displayOverlaySpinner();

await orderApi.placeOrder(cartId).finally(removeOverlaySpinner);
try {
// Payment Services credit card
if (code === PaymentMethodCode.CREDIT_CARD) {
if (!creditCardFormRef.current) {
console.error('Credit card form not rendered.');
return;
}
if (!creditCardFormRef.current.validate()) {
// Credit card form invalid; abort order placement
return;
}
// Submit Payment Services credit card form
await creditCardFormRef.current.submit();
}
// Place order
await orderApi.placeOrder(cartId);
} catch (error) {
console.error(error);
throw error;
} finally {
await removeOverlaySpinner();
}
},
})($placeOrder),
]);
Expand Down Expand Up @@ -569,12 +633,12 @@ export default async function decorate(block) {
} else if (!shippingAddresses) {
shippingForm?.remove();
shippingForm = null;
shippingFormRef = { current: null };
shippingFormRef.current = null;

const cartShippingAddress = getCartAddress(data, 'shipping');

const shippingAddressId = cartShippingAddress
? (cartShippingAddress?.id ?? 0)
? cartShippingAddress?.id ?? 0
: undefined;

const shippingAddressCache = sessionStorage.getItem(
Expand All @@ -586,15 +650,6 @@ export default async function decorate(block) {
sessionStorage.removeItem(SHIPPING_ADDRESS_DATA_KEY);
}

// when shipping address form is empty
if (!cartShippingAddress) {
checkoutApi.estimateShippingMethods();
events.emit('checkout/estimate-shipping-address', {
address: {},
isValid: false,
});
}

const storeConfig = checkoutApi.getStoreConfigCache();

const inputsDefaultValueSet = cartShippingAddress && cartShippingAddress.id === undefined
Expand Down Expand Up @@ -634,12 +689,12 @@ export default async function decorate(block) {
if (!billingAddresses) {
billingForm?.remove();
billingForm = null;
billingFormRef = { current: null };
billingFormRef.current = null;

const cartBillingAddress = getCartAddress(data, 'billing');

const billingAddressId = cartBillingAddress
? (cartBillingAddress?.id ?? 0)
? cartBillingAddress?.id ?? 0
: undefined;

const billingAddressCache = sessionStorage.getItem(
Expand Down Expand Up @@ -737,7 +792,10 @@ export default async function decorate(block) {

block.replaceChildren(orderConfirmationFragment);

const handleSignUpClick = async ({ inputsDefaultValueSet, addressesData }) => {
const handleSignUpClick = async ({
inputsDefaultValueSet,
addressesData,
}) => {
const signUpForm = document.createElement('div');
AuthProvider.render(SignUp, {
routeSignIn: () => '/customer/login',
Expand Down
79 changes: 64 additions & 15 deletions cypress/src/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as fields from '../fields/index';
import * as fields from "../fields/index";

export const setGuestEmail = (customerEmail) => {
cy.get(fields.shippingFormGuestEmail).clear().type(customerEmail);
Expand All @@ -21,34 +21,59 @@ export const setGuestShippingAddress = (customerAddress, isSelectableState) => {

export const setGuestBillingAddress = (customerAddress, isSelectableState) => {
cy.wait(1000);
cy.get(fields.billingFormFirstName).should("not.be.disabled").clear().type(customerAddress.firstName, { force: true });
cy.get(fields.billingFormFirstName)
.should("not.be.disabled")
.clear()
.type(customerAddress.firstName, { force: true });
cy.wait(1000);
cy.get(fields.billingFormLastName).should("not.be.disabled").clear().type(customerAddress.lastName, { force: true });
cy.get(fields.billingFormLastName)
.should("not.be.disabled")
.clear()
.type(customerAddress.lastName, { force: true });
cy.wait(1000);
cy.get(fields.billingFormStreet).should("not.be.disabled").clear().type(customerAddress.street, { force: true });
cy.get(fields.billingFormStreet)
.should("not.be.disabled")
.clear()
.type(customerAddress.street, { force: true });
cy.wait(1000);
cy.get(fields.billingFormStreet1).should("not.be.disabled").clear().type(customerAddress.street1, { force: true });
cy.get(fields.billingFormStreet1)
.should("not.be.disabled")
.clear()
.type(customerAddress.street1, { force: true });
if (isSelectableState) {
cy.wait(1000);
cy.get(fields.billingFormState).should("not.be.disabled").select(customerAddress.region, { force: true });
cy.get(fields.billingFormState)
.should("not.be.disabled")
.select(customerAddress.region, { force: true });
} else {
cy.wait(1000);
cy.get(fields.billingFormInputState).should("not.be.disabled").type(customerAddress.region, { force: true });
cy.get(fields.billingFormInputState)
.should("not.be.disabled")
.type(customerAddress.region, { force: true });
}
cy.wait(1000);
cy.get(fields.billingFormCity).should("not.be.disabled").clear().type(customerAddress.city, { force: true });
cy.get(fields.billingFormCity)
.should("not.be.disabled")
.clear()
.type(customerAddress.city, { force: true });
cy.wait(1000);
cy.get(fields.billingFormPostCode).should("not.be.disabled").clear().type(customerAddress.postCode, { force: true });
cy.get(fields.billingFormPostCode)
.should("not.be.disabled")
.clear()
.type(customerAddress.postCode, { force: true });
cy.wait(1000);
cy.get(fields.billingFormTelephone).should("not.be.disabled").clear().type(customerAddress.telephone, { force: true });
cy.get(fields.billingFormTelephone)
.should("not.be.disabled")
.clear()
.type(customerAddress.telephone, { force: true });
};

export const uncheckBillToShippingAddress = () => {
cy.get(fields.billToShippingAddress).uncheck({ force: true });
};

export const placeOrder = () => {
cy.get(fields.placeOrderButton).should('be.visible')
cy.get(fields.placeOrderButton).should("be.visible");
cy.get(fields.placeOrderButton).click();
};

Expand All @@ -59,12 +84,15 @@ export const createAccount = () => {
export const signUpUser = (sign_up, isValid = true) => {
const random = Cypress._.random(0, 10000000);
const username = `${random}${sign_up.email}`;
cy.contains("Create account").should('be.visible');
cy.contains("Create account").should("be.visible");
if (sign_up.company) {
cy.get(fields.authFormUserCompany).clear().type(sign_up.company);
}
if (sign_up.email) {
cy.get(fields.authFormUserEmail).eq(1).clear({force: true}).type(username);
cy.get(fields.authFormUserEmail)
.eq(1)
.clear({ force: true })
.type(username);
}
cy.get(fields.authFormUserFirstName).clear().type(sign_up.firstName);
cy.get(fields.authFormUserLastName).clear().type(sign_up.lastName);
Expand All @@ -73,8 +101,29 @@ export const signUpUser = (sign_up, isValid = true) => {
if (isValid) {
cy.get(fields.authFormUserPassword).eq(1).clear().type(sign_up.password);
} else {
cy.get(fields.authFormUserPassword).eq(1).clear().type(sign_up.shortPassword);
cy.get(fields.authFormUserPassword)
.eq(1)
.clear()
.type(sign_up.shortPassword);
}
cy.get('.dropin-picker__select').select('Male');
cy.get(".dropin-picker__select").select("Male");
createAccount();
};

export const setPaymentMethod = (paymentMethod) => {
cy.get(fields.paymentMethods).contains(paymentMethod.name).click();
if (paymentMethod.name === 'Credit Card') {
const {cc_number, cc_exp, cc_cid} = paymentMethod.params;
cy.wait(2000);
cy.getIFrameField(
fields.creditCardNumberIFrame,
fields.creditCardNumber
).type(cc_number);
cy.getIFrameField(fields.creditCardExpIFrame, fields.creditCardExp).type(
cc_exp
);
cy.getIFrameField(fields.creditCardCvvIFrame, fields.creditCardCvv).type(
cc_cid
);
}
};
4 changes: 2 additions & 2 deletions cypress/src/assertions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const assertSelectedPaymentMethod = (
.and('have.value', selected_payment_method);
};

export const assertOrderConfirmationCommonDetails = (customerDetails) => {
export const assertOrderConfirmationCommonDetails = (customerDetails, paymentMethod) => {
cy.get('.order-confirmation')
.should(
'contain',
Expand All @@ -119,7 +119,7 @@ export const assertOrderConfirmationCommonDetails = (customerDetails) => {
.and('contain', 'Contact details')
.and('contain', customerDetails.email)
.and('contain', 'Payment method')
.and('contain', customerDetails.paymentMethod)
.and('contain', paymentMethod.name)
.and('contain', 'Order summary');
cy.contains('p', /ORDER #\d+/).should('be.visible');
cy.get('.order-confirmation__order-cost-summary').should('exist');
Expand Down
13 changes: 13 additions & 0 deletions cypress/src/fields/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ export const billToShippingAddress =
// Shipping Methods
export const shippingMethods = 'div[class*="checkout-shipping-methods"]';

// Payment Methods
export const paymentMethods = '.checkout-payment-methods__method';

export const creditCardNumberIFrame =
'.payment-services-credit-card-form__card-number iframe';
export const creditCardNumber = 'input[name="credit-card-number"]';
export const creditCardExpIFrame =
'.payment-services-credit-card-form__expiration-date iframe';
export const creditCardExp = 'input[name="expiration"]';
export const creditCardCvvIFrame =
'.payment-services-credit-card-form__security-code iframe';
export const creditCardCvv = 'input[name="cvv"]';

// Place Order
export const placeOrderButton = 'button[class*="checkout-place-order__button"]';

Expand Down
Loading

0 comments on commit ccdd525

Please sign in to comment.