In Playwright: navigate to your checkout page, click the pay button to open the Paystack Inline popup, wait for the iframe to load, switch context to the iframe, fill in the test card number (4084084084084081), CVV (408), expiry, and PIN, submit, then assert your success state. Use page.frameLocator() to interact with the Paystack iframe. Run against your Paystack test mode deployment.
// e2e/checkout.spec.ts
import { test, expect } from '@playwright/test';
test('complete payment with Paystack test card', async ({ page }) => {
// Navigate to the checkout page
await page.goto('http://localhost:3000/checkout?product=1');
// Click the pay button to open Paystack popup
await page.click('button[data-testid="pay-button"]');
// Wait for Paystack iframe to appear
const paystackFrame = page.frameLocator('iframe[name="checkout"]');
await paystackFrame.locator('input[placeholder="Card Number"]').waitFor({ timeout: 10000 });
// Fill in test card details
await paystackFrame.locator('input[placeholder="Card Number"]').fill('4084 0840 8408 4081');
await paystackFrame.locator('input[placeholder="MM/YY"]').fill('05/30');
await paystackFrame.locator('input[placeholder="CVV"]').fill('408');
// Click Pay button inside the popup
await paystackFrame.locator('button', { hasText: 'Pay' }).click();
// Enter PIN if prompted
const pinInput = paystackFrame.locator('input[placeholder="Enter PIN"]');
if (await pinInput.isVisible({ timeout: 3000 }).catch(() => false)) {
await pinInput.fill('0000');
await paystackFrame.locator('button', { hasText: 'Confirm' }).click();
}
// Wait for redirect to success page
await page.waitForURL('**/payment/success**', { timeout: 30000 });
await expect(page.locator('h1')).toHaveText('Payment Successful');
});
test('shows error message on declined card', async ({ page }) => {
await page.goto('http://localhost:3000/checkout?product=1');
await page.click('button[data-testid="pay-button"]');
const paystackFrame = page.frameLocator('iframe[name="checkout"]');
await paystackFrame.locator('input[placeholder="Card Number"]').waitFor({ timeout: 10000 });
// Use decline test card
await paystackFrame.locator('input[placeholder="Card Number"]').fill('4084 0800 0000 0409');
await paystackFrame.locator('input[placeholder="MM/YY"]').fill('05/30');
await paystackFrame.locator('input[placeholder="CVV"]').fill('408');
await paystackFrame.locator('button', { hasText: 'Pay' }).click();
// Expect decline message in the popup
await expect(paystackFrame.locator('text=Do Not Honor')).toBeVisible({ timeout: 10000 });
});
This guide is part of the Paystack testing guide.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course