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

Add e2e stored card tests #2991

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions packages/e2e-playwright/fixtures/ach.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { test as base, expect } from '@playwright/test';
import Ach from '../models/ach';

type Fixture = {
ach: Ach;
};

const test = base.extend<Fixture>({
ach: async ({ page }, use) => {
await use(new Ach(page));
}
});

export { test, expect };
23 changes: 23 additions & 0 deletions packages/e2e-playwright/models/ach.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Base } from './base';
import { Locator, Page } from '@playwright/test';

class Ach extends Base {
private readonly rootElementSelector = '.adyen-checkout__ach';
private readonly rootElement: Locator;

constructor(page: Page) {
super(page);
this.rootElement = page.locator(this.rootElementSelector);
}

get paymentResult() {
return this.page.locator('.adyen-checkout__status');
}

async payWithStoredCard(lastFour: string): Promise<void> {
const regex = new RegExp(`^continue to.*${lastFour}$`, 'i');
await super.pay({ name: regex });
}
}

export default Ach;
2 changes: 1 addition & 1 deletion packages/e2e-playwright/models/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Address {
}

get streetInput() {
return this.rootElement.locator('.adyen-checkout__input--street');
return this.rootElement.getByRole('textbox', { name: /\b(address|street)\b/i });
}

get streetInputError() {
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-playwright/models/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export abstract class Base {
protected constructor(public readonly page: Page) {}

get paymentResult() {
return this.page.getByTestId('result-message');
return this.page.locator('.adyen-checkout__status');
}

async goto(url: string) {
Expand Down
11 changes: 11 additions & 0 deletions packages/e2e-playwright/models/dropin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ class Dropin extends Base {
this.page.locator('.adyen-checkout__payment-methods-list--otherPayments').getByRole('radio', { name: pmLabel }).check();
}

// Stored payment methods
async selectFirstStoredPaymentMethod(pmType: string, lastFour?: string) {
const pmLabel = this.paymentMethods.find((pm: { type: string }) => pm.type === pmType)?.name;
await this.page
.locator('.adyen-checkout__payment-method')
.filter({ has: this.page.getByRole('img', { name: pmLabel ?? pmType }) }) // filter the payment methods which have the correct logo
.getByRole('radio', { name: lastFour, exact: false })
.first()
.click();
}

async saveDetails() {
await this.saveDetailsButton.click();
}
Expand Down
3 changes: 2 additions & 1 deletion packages/e2e-playwright/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ const config: PlaywrightTestConfig = {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
ignoreHTTPSErrors: true,
screenshot: 'only-on-failure'
screenshot: 'only-on-failure',
video: 'retain-on-failure'
},

/* Configure projects for major browsers */
Expand Down
9 changes: 6 additions & 3 deletions packages/e2e-playwright/tests/e2e/card/avs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ test.describe('Card payments with address lookup', () => {

test.describe('Card payments with partial avs', () => {
test.describe('When fill in a valid the post code', () => {
test('should make a successful card payment', async ({ cardWithAvs }) => {
test('should make a successful card payment', async ({ cardWithAvs, page }) => {
await cardWithAvs.goto(URL_MAP.cardWithPartialAvs);
await cardWithAvs.typeCardNumber(REGULAR_TEST_CARD);
await cardWithAvs.typeExpiryDate(TEST_DATE_VALUE);
await cardWithAvs.typeCvc(TEST_CVC_VALUE);
await cardWithAvs.billingAddress.fillInPostCode(TEST_POSTCODE);
// wait for the form is valid
await page.waitForFunction(() => globalThis.component.isValid === true);
await cardWithAvs.pay();
await cardWithAvs.paymentResult.waitFor({ state: 'visible' });
await expect(cardWithAvs.paymentResult).toContainText(PAYMENT_RESULT.authorised);
Expand All @@ -44,7 +46,7 @@ test.describe('Card payments with partial avs', () => {

test.describe('Card payments with full avs', () => {
test.describe('When fill in the valid address data', () => {
test('should make a successful card payment', async ({ cardWithAvs }) => {
test('should make a successful card payment', async ({ cardWithAvs, page }) => {
await cardWithAvs.goto(URL_MAP.fullAvsWithoutPrefilledDataUrl);
await cardWithAvs.typeCardNumber(REGULAR_TEST_CARD);
await cardWithAvs.typeExpiryDate(TEST_DATE_VALUE);
Expand All @@ -55,8 +57,9 @@ test.describe('Card payments with full avs', () => {
await cardWithAvs.billingAddress.fillInCity('Test city');
await cardWithAvs.billingAddress.selectState({ name: 'Florida' });
await cardWithAvs.billingAddress.fillInPostCode('12345');
// wait for the form is valid
await page.waitForFunction(() => globalThis.component.isValid === true);
await cardWithAvs.pay();
await cardWithAvs.paymentResult.waitFor({ state: 'visible' });
await expect(cardWithAvs.paymentResult).toContainText(PAYMENT_RESULT.authorised);
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { test } from '@playwright/test';
import { mergeTests, expect } from '@playwright/test';
import { test as dropin } from '../../../../fixtures/dropin.fixture';
import { test as ach } from '../../../../fixtures/ach.fixture';
import { URL_MAP } from '../../../../fixtures/URL_MAP';
import { PAYMENT_RESULT } from '../../../utils/constants';

const test = mergeTests(dropin, ach);

test.describe('Stored ach card', () => {
test('should make a successful payment', async () => {
// One click, pay button
test('should make a successful payment', async ({ dropinWithSession, ach }) => {
const lastFourDigits = '3123';
await dropinWithSession.goto(URL_MAP.dropinWithSession);
await dropinWithSession.selectFirstStoredPaymentMethod('ach', lastFourDigits);
await ach.payWithStoredCard(lastFourDigits);
await ach.paymentResult.waitFor({ state: 'visible' });
await expect(ach.paymentResult).toContainText(PAYMENT_RESULT.success);
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
import { test } from '@playwright/test';
import { mergeTests, expect, test as base } from '@playwright/test';
import { test as dropin } from '../../../../fixtures/dropin.fixture';
import { PAYMENT_RESULT, THREEDS2_CHALLENGE_PASSWORD } from '../../../utils/constants';
import { BCMC } from '../../../../models/bcmc';

type Fixture = {
bcmc: BCMC;
};

const test = mergeTests(
dropin,
base.extend<Fixture>({
bcmc: async ({ page }, use) => {
const bcmc = new BCMC(page);
await use(bcmc);
}
})
);

test.describe('Stored Bancontact card', () => {
test('should make a successful payment', async () => {
// One click Pay button
test('should make a successful payment', async ({ dropinWithSession, bcmc }) => {
const url = '/iframe.html?args=countryCode:BE&globals=&id=dropin-default--auto&viewMode=story';
await dropinWithSession.goto(url);
await dropinWithSession.selectFirstStoredPaymentMethod('bcmc', '4449');
await bcmc.pay({ name: /pay €259\.00/i });
await bcmc.threeDs2Challenge.fillInPassword(THREEDS2_CHALLENGE_PASSWORD);
await bcmc.threeDs2Challenge.submit();

await expect(bcmc.paymentResult).toContainText(PAYMENT_RESULT.fail);
});
});
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
import { test } from '@playwright/test';
import { cardInDropin as test, expect } from '../../../../fixtures/dropin.fixture';
import { URL_MAP } from '../../../../fixtures/URL_MAP';
import { PAYMENT_RESULT, TEST_CVC_VALUE, THREEDS2_CHALLENGE_PASSWORD } from '../../../utils/constants';

test.describe('Stored Maestro card - cvc optional', () => {
// When user do not fill in the cvc
test('should make a successful payment without the cvc code', async () => {});
test('should make a successful payment without the cvc code', async ({ dropinWithSession, card }) => {
await dropinWithSession.goto(URL_MAP.dropinWithSession);
await dropinWithSession.selectFirstStoredPaymentMethod('maestro', '0029');

await card.cvcInput.waitFor({ state: 'visible' });
await card.pay({ name: /^Pay/i });
await card.threeDs2Challenge.fillInPassword(THREEDS2_CHALLENGE_PASSWORD);
await card.threeDs2Challenge.submit();

await expect(card.paymentResult).toContainText(PAYMENT_RESULT.success);
});
// When user fills in the cvc
test('should make a successful payment after filling in the correct 3ds challenge password', async () => {});
test('should decline the payment after filling in the wrong 3ds challenge password', async () => {});
test('should make a successful payment after filling in the correct 3ds challenge password', async ({ dropinWithSession, card }) => {
await dropinWithSession.goto(URL_MAP.dropinWithSession);
await dropinWithSession.selectFirstStoredPaymentMethod('maestro', '0029');

await card.cvcInput.waitFor({ state: 'visible' });
await card.fillCvc(TEST_CVC_VALUE);
await card.pay({ name: /^Pay/i });
await card.threeDs2Challenge.fillInPassword(THREEDS2_CHALLENGE_PASSWORD);
await card.threeDs2Challenge.submit();

await expect(card.paymentResult).toContainText(PAYMENT_RESULT.success);
});

test('should decline the payment after filling in the wrong 3ds challenge password', async ({ dropinWithSession, card }) => {
await dropinWithSession.goto(URL_MAP.dropinWithSession);
await dropinWithSession.selectFirstStoredPaymentMethod('maestro', '0029');

await card.cvcInput.waitFor({ state: 'visible' });
await card.fillCvc(TEST_CVC_VALUE);
await card.pay({ name: /^Pay/i });
await card.threeDs2Challenge.fillInPassword('dummy');
await card.threeDs2Challenge.submit();

await expect(card.paymentResult).toContainText(PAYMENT_RESULT.fail);
});
});
1 change: 1 addition & 0 deletions packages/lib/storybook/helpers/checkout-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function displayResultMessage(isAuthorized: boolean, resultCode: string): void {

const resultText = document.createElement('div');
resultText.setAttribute('data-testid', 'result-message');
resultText.classList.add('adyen-checkout__status');
resultText.style.textAlign = 'center';
resultText.textContent = resultCode;

Expand Down
Loading