How to Automate Coupon Codes Testing (Step-by-Step)
Automating coupon codes testing is essential for e-commerce businesses to ensure a smooth and accurate checkout experience, prevent revenue loss, and maintain customer trust. This step-by-step guide w
# How to Automate Coupon Codes Testing (Step-by-Step)
Automating coupon codes testing is essential for e-commerce businesses to ensure a smooth and accurate checkout experience, prevent revenue loss, and maintain customer trust. This step-by-step guide will walk you through the process, from understanding when automation is beneficial to implementing robust, maintainable tests that can be integrated into your CI/CD pipeline. We'll cover framework selection, locator strategies, handling common challenges like flakiness, data management, and leveraging autonomous exploration to bootstrap your testing efforts.
Coupon codes are a critical component of online sales, driving conversions and customer loyalty. However, their implementation can be complex, introducing numerous potential failure points. Manual testing of coupon codes, while necessary for initial discovery, quickly becomes a bottleneck as the number of promotions, products, and user scenarios grows. Automation allows for more comprehensive coverage, faster feedback loops, and the ability to catch regressions before they impact customers.
When Does Coupon Codes Testing Automation Pay Off?
Before diving into the technicalities, it's crucial to assess whether investing in automation for coupon codes testing is the right move for your team. Automation is not a silver bullet; it requires upfront investment in time, resources, and expertise. However, the return on investment can be substantial.
Factors Favoring Automation
- High Transaction Volume: If your platform processes a significant number of orders daily, even minor coupon code errors can lead to substantial financial losses or customer dissatisfaction.
- Frequent Promotions: Businesses that run frequent sales, flash deals, or offer personalized coupon codes will benefit immensely from automated checks that can quickly validate these promotions.
- Complex Coupon Logic: The more intricate your coupon rules (e.g., tiered discounts, BOGO offers, stackable coupons, free shipping tiers), the higher the likelihood of manual errors and the greater the need for automated validation.
- Multiple Platforms/Browsers: Testing coupon code functionality across various browsers, devices, and operating systems manually is time-consuming and error-prone. Automation ensures consistent testing across all targeted environments.
- Agile Development Cycles: In fast-paced development environments, frequent releases demand rapid and reliable testing. Automation provides the speed and repeatability needed to keep pace.
- Regression Prevention: Coupon code bugs can easily reappear with code changes. Automated regression suites are your best defense against these silent regressions.
- Developer Efficiency: By automating repetitive coupon code validation, developers can focus on building new features rather than getting bogged down in manual testing.
When Manual Testing Might Suffice (Initially)
- Early-Stage Prototypes: For very early prototypes with minimal functionality and a small user base, manual testing might be sufficient to identify major issues.
- Infrequent Promotions: If coupon codes are rarely used or the promotion schedule is very sparse, the ROI for automation might be lower.
- Limited Resources/Expertise: If your team lacks the time or expertise to set up and maintain automated tests, starting with a solid manual strategy is better than poorly implemented automation.
Understanding Coupon Code Test Scenarios
A comprehensive coupon code testing strategy involves covering a wide array of scenarios, from the most common to the obscure edge cases that often slip through the cracks.
Core Functionality Tests
These are the bread-and-butter tests that ensure the basic coupon code functionality works as expected.
- Valid Coupon Applied: Test with a known, active coupon code. Verify that the discount is applied correctly to the order total and that the discount amount is accurate.
- Invalid Coupon: Test with a non-existent or expired coupon code. Verify that an appropriate error message is displayed and no discount is applied.
- Expired Coupon: Test with a coupon code that was once valid but has now expired. The outcome should be similar to an invalid coupon.
- Case Sensitivity: If coupon codes are case-sensitive, test with different casing (e.g.,
SUMMER20vs.summer20). If not, verify that both work. - Whitespace: Test coupon codes with leading/trailing spaces. They should typically be ignored or result in an error, depending on requirements.
Condition-Based Tests
Many coupon codes have specific conditions attached to them.
- Minimum Purchase Amount: Test a valid coupon on an order below the minimum threshold. Verify no discount is applied and an informative message is shown. Then, test with an order meeting or exceeding the threshold.
- Specific Products/Categories: Test a coupon that applies only to certain products or categories.
- Apply it to an eligible product.
- Apply it to an ineligible product.
- Apply it to a cart with a mix of eligible and ineligible products.
- First-Time User Discount: Test with a new user account and a valid coupon. Test with an existing user account and the same coupon.
- Repeat Customer Discount: Similar to the above, but ensuring the logic correctly identifies repeat customers.
- Quantity Restrictions: Test coupons that require a minimum quantity of items in the cart.
- Free Shipping: Test coupons that offer free shipping. Verify shipping costs are removed or reduced.
- Buy One Get One (BOGO): This is more complex. It might involve adding two specific items, applying the coupon, and verifying the discount on the cheaper item.
Multi-Coupon and Interaction Tests
Testing how coupons behave when multiple are present or when other promotions are active.
- Stackable Coupons: If multiple coupons can be combined, test valid combinations. Verify the combined discount is calculated correctly.
- Non-Stackable Coupons: Test applying a second coupon when one is already active. The system should either disallow the second coupon or replace the first with the better discount, as per business rules.
- Coupon + Other Discounts: Test combining coupon codes with other types of discounts (e.g., loyalty points, store credit, sale prices).
Edge Case and Negative Tests
These scenarios often reveal hidden bugs.
- Coupon Applied, Then Cart Modified: Add items, apply a coupon, then remove items. Verify the discount is recalculated correctly.
- Coupon Applied, Then Cart Modified (to invalidate): Apply a coupon that requires a minimum purchase. Then, remove enough items so the cart total falls below the minimum. Verify the coupon is removed or invalidated.
- Coupon Applied, Then Product Changed: Apply a coupon valid for Product A. Then, replace Product A with Product B. Verify coupon behavior.
- Very Long Coupon Codes: Test with extremely long coupon codes to check for buffer overflows or UI truncation issues.
- Coupon Codes with Special Characters: Test codes containing symbols, numbers, and varied alphabets.
- Multiple Applications: Attempt to apply the same coupon code multiple times.
- Applying Coupon Post-Login/Logout: Test applying coupons before and after user authentication.
- Checkout Flow Interruption: Apply a coupon, navigate away from the cart/checkout page, and then return. Verify the coupon is still applied correctly.
User Experience (UX) and UI Tests
Beyond just functionality, how is the coupon experience for the user?
- Clear Error Messages: Are error messages informative and helpful (e.g., "Coupon code 'INVALID10' is not valid" vs. "Error")?
- Discount Visibility: Is the discount clearly displayed in the cart summary?
- Ease of Application: Is the coupon input field easy to find and use?
- Mobile Responsiveness: Does the coupon application work seamlessly on mobile devices?
Choosing Your Automation Framework
The choice of automation framework significantly impacts the ease of writing, maintaining, and running your coupon code tests. Several popular options exist, each with its strengths and weaknesses.
Key Considerations
- Language Support: Choose a language your team is comfortable with.
- E-commerce Platform Compatibility: Ensure the framework integrates well with your web application's technology stack.
- Ease of Setup and Maintenance: How complex is it to get started and keep the framework running?
- Reporting Capabilities: Does it provide clear, actionable reports?
- Community Support and Documentation: A strong community means better resources and quicker solutions to problems.
- Integration with CI/CD: How easily can it be integrated into your existing CI/CD pipeline?
Popular Frameworks and Tools
Here's a comparison of common choices:
| Feature | Selenium WebDriver | Cypress | Playwright | SUSA Test (Autonomous) |
|---|---|---|---|---|
| Primary Use | Browser automation, Cross-browser testing | End-to-end testing, SPA testing | End-to-end testing, Cross-browser, Cross-platform | Autonomous Exploration, E2E Testing, Regression Script Gen. |
| Language | Java, Python, C#, JavaScript, Ruby, etc. | JavaScript/TypeScript | JavaScript/TypeScript, Python, Java, .NET | N/A (UI-driven, no coding required for exploration) |
| Execution Model | WebDriver protocol (external agent) | In-browser execution (runs within the browser) | Node.js API (internal network proxy) | Agent-based exploration |
| Test Stability | Can be prone to flakiness if not managed well | Generally more stable due to architecture | High stability, built-in waits | High (learns app behavior, adapts to changes) |
| DOM Access | Excellent, lots of locator strategies | Excellent, CSS & XPath | Excellent, CSS & XPath, text locators | Automatic DOM interaction |
| CI/CD Integration | Good, requires setup | Excellent, easy integration | Excellent, easy integration | Excellent (CLI for triggering runs) |
| Setup Complexity | Moderate | Low | Low | Very Low (install agent, provide URL/APK) |
| Learning Curve | Moderate to High | Low to Moderate | Moderate | Very Low (for exploration; scripting generation adds learning) |
| Script Generation | Manual scripting | Manual scripting | Manual scripting | Automatic (Appium for Android, Playwright for Web) |
| Visual Testing | Requires integration with other tools | Requires integration with other tools | Requires integration with other tools | Built-in visual diffing capabilities |
| Autonomous Dev | N/A | N/A | N/A | Core feature - explores without scripts |
Recommendation for Coupon Code Testing
- For teams prioritizing ease of setup and fast feedback on modern web apps: Cypress is an excellent choice. Its in-browser execution and automatic waiting mechanisms reduce flakiness.
- For teams needing broader browser/platform support and cross-language flexibility: Playwright is a strong contender. It offers robust features, excellent performance, and good cross-platform capabilities.
- For teams aiming to minimize scripting effort and accelerate test creation: SUSA Test provides a unique advantage. Its autonomous exploration can automatically discover coupon code flows and edge cases, generating initial Appium (Android) or Playwright (Web) scripts. This bootstraps your automation process significantly, especially for complex checkout flows where identifying all interaction points can be challenging. You can then refine these generated scripts or rely on SUSA's ongoing autonomous runs.
Building Your First Coupon Code Test Suite (Step-by-Step)
Let's assume we're building tests for a hypothetical e-commerce website using Playwright (chosen for its robust features and cross-browser capabilities). The principles discussed here apply broadly to other frameworks.
Step 1: Project Setup
First, set up your Playwright project.
# Initialize a new Node.js project
npm init -y
# Install Playwright
npm install --save-dev @playwright/test
# Install browser binaries
npx playwright install
Create a directory for your tests, e.g., tests/coupons.spec.ts.
Step 2: Define Test Data
Hardcoding coupon codes and expected outcomes directly in tests is brittle. Use a separate data structure or configuration file.
data/coupons.ts
export interface CouponData {
code: string;
description: string;
type: 'percentage' | 'fixed' | 'free_shipping';
value: number;
conditions?: {
minPurchase?: number;
appliesTo?: { productSku?: string; category?: string };
newCustomerOnly?: boolean;
};
expectedError?: string; // For invalid/expired codes
}
export const couponTestData: CouponData[] = [
{
code: 'SUMMER20',
description: '20% off sitewide',
type: 'percentage',
value: 20,
},
{
code: 'SAVE10NOW',
description: '$10 off orders over $100',
type: 'fixed',
value: 10,
conditions: {
minPurchase: 100,
},
},
{
code: 'FREESHIP',
description: 'Free shipping on all orders',
type: 'free_shipping',
value: 0, // Value not applicable for free shipping type
},
{
code: 'NEWUSER15',
description: '15% off for new users',
type: 'percentage',
value: 15,
conditions: {
newCustomerOnly: true,
},
},
{
code: 'INVALIDCODE',
description: 'An intentionally invalid code',
expectedError: 'Coupon code "INVALIDCODE" is not valid.',
},
{
code: 'EXPIRED5',
description: 'Expired coupon',
expectedError: 'Coupon code "EXPIRED5" has expired.',
},
// Add more complex scenarios: specific products, categories, BOGO, etc.
];
Step 3: Write the Test Cases
Structure your tests logically. Use describe blocks for grouping and test (or it) for individual test cases.
tests/coupons.spec.ts
import { test, expect, Page } from '@playwright/test';
import { couponTestData, CouponData } from '../data/coupons';
// --- Helper Functions ---
async function applyCoupon(page: Page, couponCode: string): Promise<void> {
await page.getByRole('textbox', { name: /coupon code/i }).fill(couponCode);
await page.getByRole('button', { name: /apply coupon/i }).click();
}
async function getCartTotals(page: Page): Promise<{ subtotal: number; discount: number; total: number }> {
// These locators will need to be specific to your website's DOM structure
const subtotalText = await page.locator('.cart-summary .subtotal').textContent() ?? '0';
const discountText = await page.locator('.cart-summary .discount').textContent() ?? '0';
const totalText = await page.locator('.cart-summary .total').textContent() ?? '0';
// Helper to parse currency strings (e.g., "$100.00", "£50.50")
const parseCurrency = (text: string): number => parseFloat(text.replace(/[^0-9.]/g, ''));
return {
subtotal: parseCurrency(subtotalText),
discount: parseCurrency(discountText),
total: parseCurrency(totalText),
};
}
async function addProductToCart(page: Page, sku: string, quantity: number = 1): Promise<void> {
// This is a placeholder; actual implementation depends on your product pages
await page.goto(`/products/${sku}`); // Example product page URL
await page.fill('input[name="quantity"]', quantity.toString());
await page.getByRole('button', { name: /add to cart/i }).click();
await page.waitForSelector('.minicart-updated-confirmation', { state: 'visible' }); // Wait for confirmation
}
// --- Test Suite ---
test.describe('Coupon Code Functionality', () => {
test.beforeEach(async ({ page }) => {
// Navigate to the cart page and ensure it's clean before each test
await page.goto('/cart');
// Optional: Clear cart items if needed for consistent state
// await page.evaluate(() => localStorage.clear()); // Example if cart is in localStorage
// await page.reload(); // Reload after clearing
await page.waitForLoadState('networkidle'); // Ensure page is fully loaded
});
couponTestData.forEach((coupon) => {
// Skip tests that require specific conditions we haven't set up yet
if (coupon.conditions?.appliesTo || coupon.conditions?.newCustomerOnly) {
test.skip(`Skipping complex condition test: ${coupon.description}`);
return;
}
if (coupon.expectedError) {
test(`Applies invalid/expired coupon: ${coupon.description}`, async ({ page }) => {
await addProductToCart(page, 'SKU123'); // Add a basic product
await applyCoupon(page, coupon.code);
await expect(page.locator('.coupon-error-message')).toContainText(coupon.expectedError); // Adjust locator
const totals = await getCartTotals(page);
expect(totals.discount).toBe(0);
});
} else {
test(`Applies valid coupon: ${coupon.description}`, async ({ page }) => {
await addProductToCart(page, 'SKU123', 2); // Add quantity 2 of a basic product
await applyCoupon(page, coupon.code);
// Wait for discount to be reflected
await page.waitForFunction(
(code) => !document.querySelector(`.coupon-error-message:contains("${code}")`),
coupon.code,
{ timeout: 10000 } // Adjust timeout as needed
);
const totals = await getCartTotals(page);
if (coupon.type === 'percentage') {
const subtotal = await page.locator('.cart-summary .subtotal').textContent() ?? '0';
const expectedDiscount = (parseFloat(subtotal.replace(/[^0-9.]/g, '')) * coupon.value) / 100;
expect(totals.discount).toBeCloseTo(expectedDiscount, 2);
} else if (coupon.type === 'fixed') {
// Check if min purchase condition is met if applicable
if (coupon.conditions?.minPurchase) {
const subtotal = await page.locator('.cart-summary .subtotal').textContent() ?? '0';
expect(parseFloat(subtotal.replace(/[^0-9.]/g, ''))).toBeGreaterThanOrEqual(coupon.conditions.minPurchase);
}
expect(totals.discount).toBe(coupon.value);
} else if (coupon.type === 'free_shipping') {
const shippingCostText = await page.locator('.cart-summary .shipping').textContent() ?? '0';
expect(parseFloat(shippingCostText.replace(/[^0-9.]/g, ''))).toBe(0);
// Also check that the discount field reflects the shipping cost if applicable
// This depends on how your UI displays free shipping
}
// Verify total is correctly calculated
const subtotal = await page.locator('.cart-summary .subtotal').textContent() ?? '0';
const expectedTotal = parseFloat(subtotal.replace(/[^0-9.]/g, '')) - totals.discount;
expect(totals.total).toBeCloseTo(expectedTotal, 2);
});
}
});
test('Handles applying coupon then removing items below minimum purchase', async ({ page }) => {
const coupon = couponTestData.find(c => c.code === 'SAVE10NOW');
if (!coupon || !coupon.conditions?.minPurchase) return;
await addProductToCart(page, 'SKU123', 2); // Ensure subtotal > minPurchase
await applyCoupon(page, coupon.code);
let totals = await getCartTotals(page);
expect(totals.discount).toBe(coupon.value);
// Now remove items to go below minimum purchase
// Placeholder: assumes removing one item reduces subtotal below minPurchase
await page.locator('.remove-item-button').first().click(); // Adjust locator
await page.waitForLoadState('networkidle');
// Re-fetch totals and verify coupon is removed/recalculated
await expect(page.locator('.coupon-error-message')).not.toBeVisible(); // Ensure no error is shown if it just gets removed
totals = await getCartTotals(page);
// The coupon should be removed, discount should be 0
expect(totals.discount).toBe(0);
// Total should revert to subtotal (minus the removed item's price)
const subtotal = await page.locator('.cart-summary .subtotal').textContent() ?? '0';
expect(totals.total).toBe(parseFloat(subtotal.replace(/[^0-9.]/g, '')));
});
// Add more tests for edge cases, stackable coupons etc.
});
Step 4: Refine Locators and Waits
The example uses generic locators (.cart-summary .subtotal). You must replace these with specific, robust locators for your application (e.g., using data-testid attributes, unique IDs, or specific ARIA roles).
Locator Strategies:
-
data-testid: The most recommended approach. Adddata-testid="cart-subtotal"to your HTML elements. Your tests becomepage.getByTestId('cart-subtotal'). - Role: Use
page.getByRole('button', { name: /apply coupon/i }). This leverages accessibility information. - Text:
page.getByText('Apply Coupon'). Can be brittle if text changes. - Label:
page.getByLabel('Coupon Code'). Good for form inputs. - CSS Selectors:
page.locator('#coupon-input'). Use IDs when available and unique. - XPath:
page.locator('//button[contains(text(), "Apply")]'). Use as a last resort; can be complex and brittle.
Handling Waits: Playwright has auto-waiting, which significantly reduces flakiness. However, sometimes explicit waits are needed:
-
page.waitForLoadState('networkidle'): Waits until there are no network connections for a period. -
page.waitForSelector(selector, { state: 'visible' }): Waits for an element to appear and be visible. -
page.waitForFunction(callback, arg): Waits for a JavaScript function to return true.
Step 5: Incorporate Autonomous Exploration
Manually identifying every possible coupon code scenario and writing scripts can be time-consuming. Autonomous testing tools can accelerate this. Platforms like SUSA Test automatically explore your application, including the checkout and cart flows.
How SUSA Test Helps:
- Discovery: SUSA Test navigates your website or Android app, interacting with elements, including coupon input fields. It applies various inputs (including potentially valid/invalid coupon codes if it can infer them or if they are discoverable) and observes the results.
- Flow Tracking: It identifies and tracks key user flows like "Add to Cart -> Checkout -> Apply Coupon".
- Edge Case Identification: By simulating different user personas (impatient, novice, adversarial), it can uncover issues like:
- Applying coupons in unexpected states.
- Interactions between coupons and other checkout elements.
- UI glitches or unresponsive elements during coupon application.
- Accessibility violations (WCAG) related to the coupon form.
- Regression Script Generation: After exploration, SUSA Test can automatically generate starting scripts for frameworks like Appium (for Android) or Playwright (for Web). This gives you a foundational set of tests based on actual user journeys and discovered issues, significantly reducing the manual scripting effort. You can then import these into your existing framework for refinement and integration.
Example Workflow with SUSA Test:
- Provide URL/APK: Point SUSA Test to your web application URL or Android APK.
- Run Autonomous Exploration: Let SUSA Test explore the site, focusing on e-commerce flows. It will automatically interact with the cart and checkout pages, including coupon fields.
- Review Findings: Analyze the SUSA Test report for found issues (crashes, broken links, accessibility violations, UX friction points) related to coupon application.
- Generate Scripts: If desired, use SUSA Test to generate initial Appium/Playwright scripts based on the flows it discovered.
- Integrate: Import these generated scripts into your existing Playwright project or use them as a basis for manual scripting. You can then add more specific assertions and data variations.
This approach allows you to "bootstrap" your automation. SUSA Test finds the paths and potential issues, and your team can then focus on writing more precise validation logic or refining the generated code.
Handling Flakiness in Coupon Code Tests
Flakiness – tests that pass sometimes and fail others without code changes – is the bane of automation. Coupon code tests can be particularly susceptible due to dynamic pricing, network latency, and complex UI updates.
Common Causes and Solutions
- Unreliable Locators:
- Cause: Locators that rely on dynamic content (timestamps, random IDs) or are too generic.
- Solution: Use stable locators like
data-testid, IDs, or ARIA roles. Avoid brittle CSS selectors or XPath. - Improper Waits:
- Cause: Tests proceed before the UI has updated (e.g., discount applied, error message shown).
- Solution: Leverage framework auto-waiting (Playwright, Cypress). Use explicit waits (
waitForSelector,waitForLoadState) judiciously when auto-waiting isn't sufficient. Wait for specific conditions, like the discount amount to update or an error message to appear. - Asynchronous Operations:
- Cause: Actions that trigger background processes (e.g., applying a coupon might trigger an API call).
- Solution: Wait for the UI to reflect the completion of these operations. Use
page.waitForFunctionor wait for specific network responses if necessary. - Test Data Dependencies:
- Cause: Tests rely on a specific state of test data (e.g., a coupon code that might be used by another test).
- Solution: Ensure each test runs in isolation. Use
beforeEachhooks to set up necessary preconditions (e.g., adding specific products to the cart) andafterEachhooks for cleanup. - Environment Instability:
- Cause: Issues with the test environment, network, or third-party services.
- Solution: Ensure your test environments are stable and performant. Implement retry mechanisms for tests that consistently fail due to transient issues.
- Race Conditions:
- Cause: Multiple asynchronous operations happening concurrently, leading to unpredictable outcomes.
- Solution: Carefully sequence actions and use explicit waits to synchronize operations. Analyze test execution logs to identify timing issues.
Implementing Retries
Most test runners and CI/CD systems support test retries. Configure your test runner to retry flaky tests a few times before marking them as failed.
Playwright Retry Configuration (playwright.config.ts):
import { defineConfig } from '@playwright/test';
export default defineConfig({
// ... other configurations
retries: process.env.CI ? 2 : 0, // Retry twice in CI environment
// ...
});
Important Note: Retries should be a last resort for genuinely intermittent issues. They mask underlying problems if overused. Focus on making tests deterministic first.
Test Data Management: Setup and Teardown
Effective test data management is crucial for reliable and repeatable coupon code testing.
Strategies for Data Setup
- Application Database: The most robust method is to manage coupon codes directly in the database used by your test environment.
- Admin Interface: Create coupon codes through your application's admin panel. This ensures the data is created via the same mechanisms as production.
- Seeding Scripts: Write scripts (e.g., SQL scripts, API calls) to populate the database with necessary coupon data before test runs.
- Example API Call (Conceptual):
curl -X POST \
https://your-test-api.com/admin/coupons \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TEST_TOKEN' \
-d '{
"code": "TEST10OFF",
"type": "percentage",
"value": 10,
"starts_at": "2023-01-01T00:00:00Z",
"expires_at": "2024-12-31T23:59:59Z",
"min_purchase_amount": 50
}'
couponTestData example, maintain coupon details in JSON, YAML, or TypeScript files. This is good for simple data but might not cover all server-side logic.Strategies for Teardown
- Database Cleanup: After tests run, remove or deactivate the created coupon codes to prevent interference with subsequent test runs. This can be done via:
-
afterEachHooks: Clean up specific data created by a single test. -
afterAllHooks: Clean up all data created by the test suite. - Scheduled Cleanup Jobs: Run scripts periodically to clear out old or unused test data.
- API Calls: Use API endpoints to disable or delete coupons created during tests.
-
localStorage/sessionStorage: If your cart or coupon state is stored client-side, clear these stores inbeforeEachhooks.
Example: Using beforeEach and afterEach for Isolation
// In your test file or a base test file
test.describe('Coupon Code Functionality', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/cart');
await page.waitForLoadState('networkidle');
// --- Setup ---
// 1. Ensure cart is empty (if necessary)
// await page.evaluate(() => localStorage.clear()); // Example
// 2. Add prerequisite products for tests
await addProductToCart(page, 'SKU123', 1);
await addProductToCart(page, 'SKU456', 1); // Example: Need two products for a BOGO test later
// 3. Apply a base coupon if needed for subsequent tests
// await applyCoupon(page, 'BASECOUPON');
console.log('Test setup complete.');
});
test.afterEach(async ({ page }) => {
// --- Teardown ---
// 1. Remove applied coupons
await page.locator('.remove-coupon-button').click(); // Example locator
await page.waitForLoadState('networkidle');
// 2. Clear cart items if tests involve adding/removing
// await page.evaluate(() => localStorage.clear()); // Example
console.log('Test teardown complete.');
});
// ... Individual tests ...
});
Running Tests in CI/CD
Integrating your coupon code tests into a CI/CD pipeline (e.g., Jenkins, GitHub Actions, GitLab CI) provides continuous feedback on code changes.
CI/CD Pipeline Stages
- Checkout: Get the latest code from your repository.
- Setup Environment:
- Install dependencies (
npm install). - Install browser binaries (
npx playwright install). - Set up test databases or data seeding.
- Run Tests: Execute your test suite using the test runner's command-line interface.
-
npx playwright test tests/coupons.spec.ts --project=chromium(Example for Playwright)
- Reporting: Generate and publish test reports.
- Artifacts: Store test execution logs, screenshots, or videos for failed tests.
Example GitHub Actions Workflow (.github/workflows/e2e-tests.yml)
name: E2E Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
e2e-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Install Playwright browsers
run: npx playwright install --with-deps
# - name: Seed Test Database # Uncomment and adapt if needed
# run: npm run seed:test-db
- name: Run Playwright tests
run: npx playwright test tests/coupons.spec.ts --project=chromium --reporter=dot
env:
CI: true # Set CI environment variable for retries etc.
# Add any other necessary environment variables (API keys, base URLs)
- name: Upload test artifacts on failure
uses: actions/upload-artifact@v3
if: failure()
with:
name: playwright-report
path: test-results/ # Directory where Playwright stores results
retention-days: 7
Considerations for CI
- Headless Execution: Run tests in headless mode (
npx playwright test --headless) for faster execution in CI environments. - Parallelization: Configure your test runner and CI/CD system to run tests in parallel across multiple workers or machines to reduce execution time. Playwright supports parallel execution out of the box.
- Environment Variables: Manage environment-specific configurations (like base URLs for test environments) using environment variables.
- Reporting: Integrate reporting tools that provide clear dashboards and historical trends of test results. Playwright's built-in HTML reporter is excellent for local runs, but consider integrating with services like ReportPortal or Allure for CI.
Reporting and Analysis
Effective reporting transforms raw test results into actionable insights.
Key Metrics to Track
- Pass/Fail Rate: The percentage of tests that passed successfully.
- Execution Time: Total time taken for the test suite to run. Monitor trends for performance regressions.
- Flakiness: Track tests that frequently fail and pass intermittently.
- Failure Trends: Identify which specific coupon scenarios are failing most often.
- Screenshots/Videos: Capture visual evidence of failures, especially for UI-related bugs.
Tools and Techniques
- Playwright HTML Reporter: Generates a detailed HTML report with test steps, console logs, screenshots, and videos for failed tests. Run `npx playwright show-report
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free