Crafting Bulletproof Test Automation: A Prompt-Driven Playbook for Cypress, Playwright, and Selenium

Why Your Test Automation Needs a Prompt Playbook

If you've ever spent hours debugging a flaky test, only to realize a selector changed or a timing issue crept in, you know the struggle. Modern test automation frameworks like Cypress, Playwright, and Selenium are powerful, but they still require careful crafting and maintenance. The difference between a robust test suite and a fragile one often comes down to how you instruct your AI pair programmer. A well-structured prompt can transform a generic test into a resilient, self-healing script that saves you time and headaches.

This isn't about replacing your skills—it's about amplifying them. By using precise prompts, you can generate boilerplate, debug failures, optimize CI integration, and even refactor legacy tests. Here’s a playbook of battle-tested prompts that I use daily, each with a real-world example to get you started immediately.

The Prompts

1. Generate a Page Object Model (POM) for a New Page

Why it works: The POM pattern centralizes selectors and actions, reducing duplication and making tests more maintainable. This prompt gives the AI a clear structure to follow.

Prompt:

Create a Page Object Model class for the login page of a React app. The page has a username input, password input, and a submit button. Include methods for successful login, failed login, and verifying error messages. Use Playwright with TypeScript. Ensure all locators are robust (use role-based where possible). Provide the full class definition and a usage example.

Example output (Playwright + TS):

import { Page, Locator } from '@playwright/test';

export class LoginPage {
  readonly page: Page;
  readonly usernameInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;
  readonly errorMessage: Locator;

  constructor(page: Page) {
    this.page = page;
    this.usernameInput = page.getByRole('textbox', { name: /username/i });
    this.passwordInput = page.getByRole('textbox', { name: /password/i });
    this.submitButton = page.getByRole('button', { name: /submit/i });
    this.errorMessage = page.getByRole('alert');
  }

  async goto() {
    await this.page.goto('/login');
  }

  async login(username: string, password: string) {
    await this.usernameInput.fill(username);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }

  async getErrorMessage() {
    return this.errorMessage.textContent();
  }
}

2. Debug a Flaky Test with Detailed Logging

Why it works: Flaky tests often fail due to timing or dynamic content. This prompt forces the AI to add diagnostic output that helps pinpoint the issue.

Prompt:

I have a Cypress test that fails intermittently. The test clicks a button that loads data asynchronously, then verifies a table row appears. Add extensive logging to the test to capture the state of the DOM before and after the click, including the number of rows, any error messages, and the current URL. Also, suggest a robust wait strategy using cy.intercept() to wait for the API call instead of a fixed wait.

Example improvement:

cy.intercept('GET', '/api/data').as('getData');
cy.get('button').click();
cy.log('Before wait - URL: ' + cy.url());
cy.wait('@getData').then((interception) => {
  cy.log('API response:', JSON.stringify(interception.response.body));
});
cy.get('table tr').should('have.length.at.least', 1);

3. Write a Test for a Complex User Flow with Multiple Steps

Why it works: This prompt guides the AI through a multi-step scenario, ensuring no edge cases are missed.

Prompt:

Write a Selenium test in Java for an e-commerce checkout flow: add product to cart, apply discount code, select shipping method, and complete payment. Use the Page Object pattern. Include assertions for each step and handle potential pop-ups. Also, use WebDriverWait for dynamic elements.

Example snippet:

public void checkoutFlow() {
    HomePage home = new HomePage(driver);
    home.addToCart();
    CartPage cart = new CartPage(driver);
    cart.applyDiscount("SAVE10");
    cart.proceedToCheckout();
    // ...
}

4. Convert a Flaky Test to Use Modern Waits

Why it works: Many flaky tests rely on sleep() or fixed waits. This prompt converts them to explicit waits, which are more reliable and faster.

Prompt:

Refactor this Cypress test to replace all cy.wait(1000) with cy.intercept() or cy.get() with timeout. The test loads a dashboard with multiple API calls. Ensure the test waits for all required data to be displayed.

Example transformation:

// Before
cy.wait(1000);
cy.get('#dashboard').should('be.visible');

// After
cy.intercept('GET', '/api/dashboard').as('dashboardData');
cy.visit('/dashboard');
cy.wait('@dashboardData');
cy.get('#dashboard').should('be.visible');

5. Generate a CI Pipeline Configuration for Test Automation

Why it works: Integrating tests into CI is crucial. This prompt helps you create a configuration file that runs tests automatically on each commit.

Prompt:

Create a GitHub Actions workflow for a Playwright test suite. The workflow should run on push to main and pull requests, install dependencies, run tests with the built-in reporter, and upload test artifacts. Use the official Playwright action. Provide the YAML file.

Example:

name: Playwright Tests
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

6. Write a Test That Handles Shadow DOM and Iframes

Why it works: Modern web apps often use shadow DOM and iframes, which can be tricky to select. This prompt ensures the AI uses the correct approach.

Prompt:

Using Playwright, write a test that interacts with an element inside a shadow root and an iframe. The shadow root contains a button, and the iframe has a search input. Provide the code with proper piercing selectors and frame handling.

Example:

const shadowHost = page.locator('my-custom-component');
const shadowButton = shadowHost.shadowRoot.locator('button');
const frame = page.frameLocator('#my-iframe');
await frame.locator('input[type="search"]').fill('test');

7. Refactor a Test Suite to Use Data-Driven Testing

Why it works: Data-driven tests reduce redundancy and improve coverage. This prompt helps you parametrize your tests.

Prompt:

Refactor this Selenium test for login to be data-driven using JUnit 5 @ParameterizedTest and @CsvSource. Include at least 5 test cases: valid credentials, invalid username, invalid password, empty fields, and locked account. The test should read from the CSV source.

Example:

@ParameterizedTest
@CsvSource({
    "validUser, validPass, success",
    "invalidUser, validPass, error",
    "validUser, invalidPass, error",
    "'', '', error",
    "lockedUser, validPass, locked"
})
void testLogin(String user, String pass, String expected) {
    // implementation
}

8. Generate a Test for Visual Regression Testing

Why it works: Visual regression tests catch unintended UI changes. This prompt sets up a snapshot test.

Prompt:

Write a Cypress test that uses cy.screenshot() to capture a component and compare it to a baseline image. Use the cypress-image-snapshot plugin. Include a test for a responsive design (mobile and desktop).

Example:

cy.visit('/component');
cy.matchImageSnapshot('component-desktop');
cy.viewport('iphone-6');
cy.matchImageSnapshot('component-mobile');

9. Create a Test That Uses API Mocking to Simulate Errors

Why it works: Testing error handling is essential. This prompt mocks API responses to simulate server errors.

Prompt:

Using Playwright, write a test that mocks a GET request to return a 500 error and verifies the UI shows a friendly error message. Also, mock a network failure to test offline behavior.

Example:

await page.route('**/api/data', route => route.fulfill({
  status: 500,
  contentType: 'application/json',
  body: JSON.stringify({ message: 'Server Error' })
}));
await page.goto('/');
await expect(page.locator('.error-message')).toHaveText('Something went wrong. Please try again.');

10. Write a Test for Cross-Browser Compatibility

Why it works: Ensuring your app works across browsers is critical. This prompt generates a test that runs on multiple browsers.

Prompt:

Create a Playwright test that runs on Chromium, Firefox, and WebKit. Use the project configuration in playwright.config.ts to define browser projects. Include a test that checks a specific element's visibility and text.

Example config:

projects: [
  { name: 'chromium', use: { browserName: 'chromium' } },
  { name: 'firefox', use: { browserName: 'firefox' } },
  { name: 'webkit', use: { browserName: 'webkit' } }
]

11. Optimize Test Performance by Running in Parallel

Why it works: Parallel execution speeds up the suite. This prompt helps you configure parallel workers.

Prompt:

Configure a Cypress test suite to run in parallel using the Cypress Dashboard and `cypress run --parallel`. Explain how to split tests across machines. Also, show how to use the `--record` flag.

Example:

cypress run --record --key <key> --parallel --ci-build-id <unique-id>

12. Generate a Test for Accessibility (a11y) Checks

Why it works: Accessibility is not just good practice—it's often a legal requirement. This prompt integrates automated a11y testing.

Prompt:

Using Cypress and cypress-axe, write a test that checks the page for WCAG 2.1 AA compliance. Include a test that runs axe on the main navigation and footer. Handle the case where there are known violations by disabling specific rules.

Example:

cy.visit('/home');
cy.injectAxe();
cy.checkA11y('#main-nav', {
  runOnly: {
    type: 'tag',
    values: ['wcag21aa']
  }
});

Wrapping Up

These prompts are not just copy-paste snippets; they're starting points. The key is to be specific about your framework, language, and the exact behavior you want. As you use them, you'll develop a feel for what works and what doesn't, and you'll start crafting your own. The result? A test suite that's easier to maintain, more reliable, and faster to run.

Now, go ahead and try one of these prompts in your next test automation task. You'll be amazed at the time you save and the quality you gain. And remember: the best prompt is one that keeps the human in the loop—always review and adapt the AI's output to fit your project's unique needs.

← All posts

Comments