Complete Claude Code plugin with: - 9 skills (/pw:init, generate, review, fix, migrate, coverage, testrail, browserstack, report) - 3 specialized agents (test-architect, test-debugger, migration-planner) - 55 test case templates across 11 categories (auth, CRUD, checkout, search, forms, dashboard, settings, onboarding, notifications, API, accessibility) - TestRail MCP server (TypeScript) — 8 tools for bidirectional sync - BrowserStack MCP server (TypeScript) — 7 tools for cross-browser testing - Smart hooks (auto-validate tests, auto-detect Playwright projects) - 6 curated reference docs (golden rules, locators, assertions, fixtures, pitfalls, flaky tests) - Leverages Claude Code built-ins (/batch, /debug, Explore subagent) - Zero-config for core features; TestRail/BrowserStack via env vars - Both TypeScript and JavaScript support throughout Co-authored-by: Leo <leo@openclaw.ai>
80 lines
3.6 KiB
Markdown
80 lines
3.6 KiB
Markdown
# Cypress → Playwright Mapping
|
|
|
|
## Commands
|
|
|
|
| Cypress | Playwright | Notes |
|
|
|---|---|---|
|
|
| `cy.visit('/page')` | `await page.goto('/page')` | Use `baseURL` in config |
|
|
| `cy.get('.selector')` | `page.locator('.selector')` | Prefer `getByRole()` |
|
|
| `cy.get('[data-cy=x]')` | `page.getByTestId('x')` | |
|
|
| `cy.contains('text')` | `page.getByText('text')` | |
|
|
| `cy.find('.child')` | `parent.locator('.child')` | Chain from parent locator |
|
|
| `cy.first()` | `locator.first()` | |
|
|
| `cy.last()` | `locator.last()` | |
|
|
| `cy.eq(n)` | `locator.nth(n)` | |
|
|
| `cy.parent()` | `locator.locator('..')` | Or restructure with better locators |
|
|
| `cy.children()` | `locator.locator('> *')` | |
|
|
| `cy.siblings()` | Not direct — restructure test | Use parent + filter |
|
|
|
|
## Actions
|
|
|
|
| Cypress | Playwright | Notes |
|
|
|---|---|---|
|
|
| `.click()` | `await locator.click()` | Always `await` |
|
|
| `.dblclick()` | `await locator.dblclick()` | |
|
|
| `.rightclick()` | `await locator.click({ button: 'right' })` | |
|
|
| `.type('text')` | `await locator.fill('text')` | `fill()` clears first |
|
|
| `.type('text', { delay: 50 })` | `await locator.pressSequentially('text', { delay: 50 })` | Simulates typing |
|
|
| `.clear()` | `await locator.clear()` | |
|
|
| `.check()` | `await locator.check()` | |
|
|
| `.uncheck()` | `await locator.uncheck()` | |
|
|
| `.select('value')` | `await locator.selectOption('value')` | |
|
|
| `.scrollTo()` | `await locator.scrollIntoViewIfNeeded()` | |
|
|
| `.trigger('event')` | `await locator.dispatchEvent('event')` | |
|
|
| `.focus()` | `await locator.focus()` | |
|
|
| `.blur()` | `await locator.blur()` | |
|
|
|
|
## Assertions
|
|
|
|
| Cypress | Playwright | Notes |
|
|
|---|---|---|
|
|
| `.should('be.visible')` | `await expect(locator).toBeVisible()` | Web-first, auto-retry |
|
|
| `.should('not.exist')` | `await expect(locator).not.toBeVisible()` | Or `.toHaveCount(0)` |
|
|
| `.should('have.text', 'x')` | `await expect(locator).toHaveText('x')` | |
|
|
| `.should('contain', 'x')` | `await expect(locator).toContainText('x')` | |
|
|
| `.should('have.value', 'x')` | `await expect(locator).toHaveValue('x')` | |
|
|
| `.should('have.attr', 'x', 'y')` | `await expect(locator).toHaveAttribute('x', 'y')` | |
|
|
| `.should('have.class', 'x')` | `await expect(locator).toHaveClass(/x/)` | |
|
|
| `.should('be.disabled')` | `await expect(locator).toBeDisabled()` | |
|
|
| `.should('be.checked')` | `await expect(locator).toBeChecked()` | |
|
|
| `.should('have.length', n)` | `await expect(locator).toHaveCount(n)` | |
|
|
| `cy.url().should('include', '/x')` | `await expect(page).toHaveURL(/\/x/)` | |
|
|
| `cy.title().should('eq', 'x')` | `await expect(page).toHaveTitle('x')` | |
|
|
|
|
## Network
|
|
|
|
| Cypress | Playwright |
|
|
|---|---|
|
|
| `cy.intercept('GET', '/api/*', { body: data })` | `await page.route('**/api/*', route => route.fulfill({ body: JSON.stringify(data) }))` |
|
|
| `cy.intercept('POST', '/api/*').as('save')` | `const savePromise = page.waitForResponse('**/api/*')` |
|
|
| `cy.wait('@save')` | `await savePromise` |
|
|
|
|
## Fixtures & Custom Commands
|
|
|
|
| Cypress | Playwright |
|
|
|---|---|
|
|
| `cy.fixture('data.json')` | `import data from './test-data/data.json'` |
|
|
| `Cypress.Commands.add('login', ...)` | `test.extend({ authenticatedPage: ... })` |
|
|
| `beforeEach(() => { ... })` | `test.beforeEach(async ({ page }) => { ... })` |
|
|
| `before(() => { ... })` | `test.beforeAll(async () => { ... })` |
|
|
|
|
## Config
|
|
|
|
| Cypress | Playwright |
|
|
|---|---|
|
|
| `baseUrl` in `cypress.config.ts` | `use.baseURL` in `playwright.config.ts` |
|
|
| `defaultCommandTimeout` | `expect.timeout` or `use.actionTimeout` |
|
|
| `video: true` | `use.video: 'on'` |
|
|
| `screenshotOnRunFailure` | `use.screenshot: 'only-on-failure'` |
|
|
| `retries: { runMode: 2 }` | `retries: 2` |
|