Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new playwright tests to replace the testcafe "usual suspects" #2438

Merged
merged 12 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/e2e-playwright/app/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const htmlPages = fs.readdirSync(basePageDir).map(fileName => ({
const htmlPageGenerator = ({ id }, index) => {
console.log('htmlPageGenerator', id, index);
return new HTMLWebpackPlugin({
// make card index.html the rest of the pages will have page <lower case ID>.html
filename: `${id !== 'Cards' ? `${id.toLowerCase()}/` : ''}index.html`,
// make Dropin index.html the rest of the pages will have page <lower case ID>.html
filename: `${id !== 'Dropin' ? `${id.toLowerCase()}/` : ''}index.html`,
template: path.join(__dirname, `../src/pages/${id}/${id}.html`),
templateParameters: () => ({ htmlWebpackPlugin: { htmlPages } }),
inject: 'body',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ <h3 class="card-text sf-text">CustomCard #1</h3>
/>
</span>
<label class="pm-form-label pm-form-label-pan">
<span class="pm-form-label__text">Card number:</span>
<span class="pm-form-label__text">Card number</span>
<span class="pm-input-field" data-cse="encryptedCardNumber"></span>
<span class="pm-form-label__error-text">Please enter a valid credit card number</span>
</label>
<label class="pm-form-label pm-form-label--exp-date">
<span class="pm-form-label__text">Expiry date:</span>
<span class="pm-form-label__text">Expiry date</span>
<span class="pm-input-field" data-cse="encryptedExpiryDate"></span>
<span class="pm-form-label__error-text">Date error text</span>
</label>
</label>
<label class="pm-form-label pm-form-label--cvc">
<span class="pm-form-label__text">CVV/CVC:</span>
<span class="pm-form-label__text">Security code</span>
<span class="pm-input-field" data-cse="encryptedSecurityCode"></span>
<span class="pm-form-label__error-text">CVC Error text</span>
</label>
Expand All @@ -60,6 +60,57 @@ <h3 class="card-text sf-text">CustomCard #1</h3>
</div>
</div>

<!-- Custom Card w. separate date fields -->
<div class="merchant-checkout__form">
<div class="merchant-checkout__payment-method">
<div class="merchant-checkout__payment-method__header">
<h3 class="card-text sf-text">CustomCard #2</h3>
</div>
<div class="merchant-checkout__payment-method__details secured-fields-2">
<span class="pm-image">
<img
class="pm-image-1"
width="40"
src="https://checkoutshopper-test.adyen.com/checkoutshopper/images/logos/nocard.svg"
alt=""
/>
</span>
<span class="pm-image-dual">
<img
class="pm-image-dual-1"
width="40"
alt=""
/>
<img
class="pm-image-dual-2"
width="40"
alt=""
/>
</span>
<label class="pm-form-label pm-form-label-pan">
<span class="pm-form-label__text">Card number</span>
<span class="pm-input-field" data-cse="encryptedCardNumber"></span>
<span class="pm-form-label__error-text">Please enter a valid credit card number</span>
</label>
<label class="pm-form-label pm-form-label--exp-month">
<span class="pm-form-label__text">Expiry month</span>
<span class="pm-input-field" data-cse="encryptedExpiryMonth"></span>
<span class="pm-form-label__error-text">Date error text</span>
</label>
<label class="pm-form-label pm-form-label--exp-year">
<span class="pm-form-label__text">Expiry year</span>
<span class="pm-input-field" data-cse="encryptedExpiryYear"></span>
<span class="pm-form-label__error-text">Date error text</span>
</label>
<label class="pm-form-label pm-form-label--cvc">
<span class="pm-form-label__text">Security code</span>
<span class="pm-input-field" data-cse="encryptedSecurityCode"></span>
<span class="pm-form-label__error-text">CVC Error text</span>
</label>
</div>
</div>
</div>

</main>

<script type="text/javascript">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ const initCheckout = async () => {
...window.mainConfiguration
});

window.securedFields = checkout
window.customCard = checkout
.create('securedfields', {
type: 'card',
brands: ['mc', 'visa', 'amex', 'bcmc', 'maestro', 'cartebancaire'],
brands: ['mc', 'visa', 'synchrony_plcc'],
onConfigSuccess,
onBrand,
onFocus: setFocus,
Expand All @@ -33,14 +33,30 @@ const initCheckout = async () => {
})
.mount('.secured-fields');

createPayButton('.secured-fields', window.securedFields, 'securedfields');
createPayButton('.secured-fields', window.customCard, 'customCardRegular');

window.customCardSeparate = checkout
.create('securedfields', {
type: 'card',
brands: ['mc', 'visa', 'synchrony_plcc'],
onConfigSuccess,
onBrand,
onFocus: setFocus,
onBinLookup,
onChange,
...window.cardConfig
})
.mount('.secured-fields-2');

createPayButton('.secured-fields-2', window.customCardSeparate, 'customCardSeparate');

function createPayButton(parent, component, attribute) {
const payBtn = document.createElement('button');

payBtn.textContent = 'Pay';
payBtn.name = 'pay';
payBtn.classList.add('adyen-checkout__button', 'js-components-button--one-click', `js-${attribute}`);
payBtn.name = `pay-${attribute}`;
payBtn.setAttribute('data-testid', `pay-${attribute}`);
payBtn.classList.add('adyen-checkout__button', 'js-components-button--one-click', `js-pay-${attribute}`);

payBtn.addEventListener('click', e => {
e.preventDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,12 @@ export function onBrand(pCallbackObj) {
// Optional cvc fields
if (pCallbackObj.cvcPolicy === 'optional' && !optionalCVC) {
optionalCVC = true;
if (cvcNode) cvcNode.querySelector('.pm-form-label__text').innerText = 'CVV/CVC (optional):';
if (cvcNode) cvcNode.querySelector('.pm-form-label__text').innerText = 'Security code (optional)';
}

if (optionalCVC && pCallbackObj.cvcPolicy !== 'optional') {
optionalCVC = false;
if (cvcNode) cvcNode.querySelector('.pm-form-label__text').innerText = 'CVV/CVC:';
if (cvcNode) cvcNode.querySelector('.pm-form-label__text').innerText = 'Security code';
}

/**
Expand All @@ -135,16 +135,16 @@ export function onBrand(pCallbackObj) {
// Optional date fields
if (pCallbackObj.expiryDatePolicy === 'optional' && !optionalDate) {
optionalDate = true;
if (dateNode) dateNode.querySelector('.pm-form-label__text').innerText = 'Expiry date (optional):';
if (monthNode) monthNode.querySelector('.pm-form-label__text').innerText = 'Expiry month (optional):';
if (yearNode) yearNode.querySelector('.pm-form-label__text').innerText = 'Expiry year (optional):';
if (dateNode) dateNode.querySelector('.pm-form-label__text').innerText = 'Expiry date (optional)';
if (monthNode) monthNode.querySelector('.pm-form-label__text').innerText = 'Expiry month (optional)';
if (yearNode) yearNode.querySelector('.pm-form-label__text').innerText = 'Expiry year (optional)';
}

if (optionalDate && pCallbackObj.expiryDatePolicy !== 'optional') {
optionalDate = false;
if (dateNode) dateNode.querySelector('.pm-form-label__text').innerText = 'Expiry date:';
if (monthNode) monthNode.querySelector('.pm-form-label__text').innerText = 'Expiry month:';
if (yearNode) yearNode.querySelector('.pm-form-label__text').innerText = 'Expiry year:';
if (dateNode) dateNode.querySelector('.pm-form-label__text').innerText = 'Expiry date';
if (monthNode) monthNode.querySelector('.pm-form-label__text').innerText = 'Expiry month';
if (yearNode) yearNode.querySelector('.pm-form-label__text').innerText = 'Expiry year';
}
}

Expand Down Expand Up @@ -248,7 +248,7 @@ export function onChange(state, component) {
}
}

const setErrorClasses = function(pNode, pSetErrors) {
const setErrorClasses = function (pNode, pSetErrors) {
if (pSetErrors) {
if (pNode.className.indexOf('pm-input-field--error') === -1) {
pNode.className += ' pm-input-field--error';
Expand All @@ -263,7 +263,7 @@ const setErrorClasses = function(pNode, pSetErrors) {
}
};

const setFocusClasses = function(pNode, pSetFocus) {
const setFocusClasses = function (pNode, pSetFocus) {
if (pSetFocus) {
if (pNode.className.indexOf('pm-input-field--focus') === -1) {
pNode.className += ' pm-input-field--focus';
Expand Down
22 changes: 22 additions & 0 deletions packages/e2e-playwright/app/src/pages/Dropin/Dropin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>Adyen Web | Drop-in</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>

<body>
<main>
<div class="merchant-checkout__form">
<div id="dropin-container"></div>
</div>
</main>

<script type="text/javascript">
window.htmlPages = <%= JSON.stringify(htmlWebpackPlugin.htmlPages) || '' %>;
</script>
</body>
</html>
27 changes: 27 additions & 0 deletions packages/e2e-playwright/app/src/pages/Dropin/Dropin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import AdyenCheckout from '@adyen/adyen-web';
import '@adyen/adyen-web/dist/es/adyen.css';
import { getPaymentMethods } from '../../services';
import { amount, shopperLocale, countryCode } from '../../services/commonConfig';
import { handleSubmit, handleAdditionalDetails, handleError } from '../../handlers';
import '../../style.scss';

const initCheckout = async () => {
const paymentMethodsResponse = await getPaymentMethods({ amount, shopperLocale });

window.checkout = await AdyenCheckout({
amount,
countryCode,
clientKey: process.env.__CLIENT_KEY__,
paymentMethodsResponse,
locale: shopperLocale,
environment: 'test',
onSubmit: handleSubmit,
onAdditionalDetails: handleAdditionalDetails,
onError: handleError,
...window.mainConfiguration
});

window.dropin = checkout.create('dropin', window.dropinConfig).mount('#dropin-container');
};

initCheckout();
16 changes: 15 additions & 1 deletion packages/e2e-playwright/mocks/binLookup/binLookup.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,18 @@ const optionalDateAndCvcMock = {
requestedId: null
};

export { optionalDateAndCvcMock };
const hiddenDateAndCvcMock = {
brands: [
{
brand: 'mc',
enableLuhnCheck: true,
supported: true,
cvcPolicy: 'hidden',
expiryDatePolicy: 'hidden'
}
],
issuingCountryCode: 'US',
requestedId: null
};

export { optionalDateAndCvcMock, hiddenDateAndCvcMock };
45 changes: 44 additions & 1 deletion packages/e2e-playwright/models/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,51 @@ const CARD_IFRAME_LABEL = LANG['creditCard.encryptedCardNumber.aria.label'];
const EXPIRY_DATE_IFRAME_LABEL = LANG['creditCard.encryptedExpiryDate.aria.label'];
const CVC_IFRAME_LABEL = LANG['creditCard.encryptedSecurityCode.aria.label'];

const INSTALLMENTS_PAYMENTS = LANG['installments.installments'];
const REVOLVING_PAYMENT = LANG['installments.revolving'];

class Card {
readonly page: Page;

readonly rootElement: Locator;
readonly rootElementSelector: string;

readonly cardNumberField: Locator;
readonly cardNumberLabelElement: Locator;
readonly cardNumberErrorElement: Locator;
readonly cardNumberInput: Locator;
readonly brandingIcon: Locator;

readonly expiryDateField: Locator;
readonly expiryDateErrorElement: Locator;
readonly expiryDateLabelText: Locator;
readonly expiryDateInput: Locator;
readonly expiryDateErrorElement: Locator;

readonly cvcField: Locator;
readonly cvcLabelText: Locator;
readonly cvcErrorElement: Locator;
readonly cvcInput: Locator;

readonly installmentsPaymentLabel: Locator;
readonly revolvingPaymentLabel: Locator;
readonly installmentsDropdown: Locator;
readonly selectorList: Locator;

constructor(page: Page, rootElementSelector = '.adyen-checkout__card-input') {
this.page = page;

this.rootElement = page.locator(rootElementSelector);
this.rootElementSelector = rootElementSelector;

/**
* Card Number elements, in Checkout
*/
this.cardNumberField = this.rootElement.locator('.adyen-checkout__field--cardNumber'); // Holder
this.cardNumberLabelElement = this.cardNumberField.locator('.adyen-checkout__label');
this.cardNumberErrorElement = this.cardNumberField.locator('.adyen-checkout__error-text');

this.brandingIcon = this.rootElement.locator('.adyen-checkout__card__cardNumber__brandIcon');

/**
* Card Number elements, in iframe
*/
Expand All @@ -46,7 +65,9 @@ class Card {
* Expiry Date elements, in Checkout
*/
this.expiryDateField = this.rootElement.locator('.adyen-checkout__field--expiryDate'); // Holder
this.expiryDateLabelText = this.expiryDateField.locator('.adyen-checkout__label__text');
this.expiryDateErrorElement = this.expiryDateField.locator('.adyen-checkout__error-text'); // Related error element
// Related error element

/**
* Expiry Date elements, in iframe
Expand All @@ -58,13 +79,22 @@ class Card {
* Security code elements, in Checkout
*/
this.cvcField = this.rootElement.locator('.adyen-checkout__field--securityCode'); // Holder
this.cvcLabelText = this.cvcField.locator('.adyen-checkout__label__text');
this.cvcErrorElement = this.cvcField.locator('.adyen-checkout__error-text'); // Related error element

/**
* Security code elements, in iframe
*/
const cvcIframe = this.rootElement.frameLocator(`[title="${CVC_IFRAME_TITLE}"]`);
this.cvcInput = cvcIframe.locator(`input[aria-label="${CVC_IFRAME_LABEL}"]`);

/**
* Installments related elements
*/
this.installmentsPaymentLabel = this.rootElement.getByText(INSTALLMENTS_PAYMENTS);
this.revolvingPaymentLabel = this.rootElement.getByText(REVOLVING_PAYMENT);
this.installmentsDropdown = this.rootElement.locator('.adyen-checkout__dropdown__button');
this.selectorList = this.rootElement.getByRole('listbox');
}

async isComponentVisible() {
Expand All @@ -81,13 +111,26 @@ class Card {
await this.cardNumberInput.clear();
}

async deleteExpiryDate() {
await this.expiryDateInput.clear();
}

async deleteCvc() {
await this.cvcInput.clear();
}

async typeExpiryDate(expiryDate: string) {
await this.expiryDateInput.type(expiryDate, { delay: USER_TYPE_DELAY });
}

async typeCvc(cvc: string) {
await this.cvcInput.type(cvc, { delay: USER_TYPE_DELAY });
}

async selectListItem(who: string) {
const listItem = this.selectorList.locator(`#listItem-${who}`);
return listItem;
}
}

export { Card };
Loading