Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cypress or Playwright?

Cypress or Playwright?

Rainer Hahnekamp

April 26, 2024
Tweet

More Decks by Rainer Hahnekamp

Other Decks in Technology

Transcript

  1. RainerHahnekamp About Me... Professional NgRx https://www.youtube.com/ @RainerHahnekamp https://www.ng-news.com https://github.com/softarc-consulting/sheriff •

    Rainer Hahnekamp ANGULARarchitects.io • Developer / Trainer / Speaker Modern Spring for Angular @RainerHahnekamp
  2. RainerHahnekamp Goal • Discuss both Frameworks from different Perspectives •

    Provide enough information for a founded decision • Present my own opinion
  3. RainerHahnekamp Agenda 1. Technological Approach 2. Developer Experience 3. CI

    4. Coding 5. Architecture & Extensibility 6. Misc. Features 7. Summary
  4. RainerHahnekamp Browser Support • Browsers ◦ Chromium Family ◦ Firefox

    ◦ Webkit • Languages ◦ JavaScript/TypeScript ◦ .NET ◦ Java ◦ Python Playwright • Browsers ◦ Chromium Family ◦ Firefox ◦ Webkit • Languages ◦ JavaScript/TypeScript
  5. RainerHahnekamp CI • Traceview • Parallelization • Sharding Playwright •

    Video Recording per Test • Screenshot for failed Test • Commercial Cypress Cloud
  6. RainerHahnekamp Coding: Selectors, Actions & Assertions • Testing framework built-in

    ◦ Different Selector Engines ◦ Special Web Assertions • Locators as Abstraction to DOM • Async/Await Playwright • Relies on External Libraries ◦ Selection via jQuery ◦ Assertion via Mocha & Chai ◦ Explicit Assertions • Retryability • "Declarative Asynchrony"
  7. RainerHahnekamp Architecture & Extensibility • Recommends Page Objects • Fixtures

    as DI Playwright • Page Objects possible • Recommendation to extend cy ◦ Mind the Query!
  8. RainerHahnekamp Playwright Page Object import { Page } from '@playwright/test';

    export class SidemenuPage { constructor(private page: Page) {} async select(menu: 'customers' | 'holidays') { await this.page.getByTestId(`btn-${menu}`).click(); } }
  9. RainerHahnekamp Playwright Fixture import { SidemenuPage } from '../page-objects/sidemenu-page'; export

    interface SidemenuFixtures { sidemenuPage: SidemenuPage; } export const sidemenuFixtures = { sidemenuPage: async ({ page }, use) => { const sidemenuPage = new SidemenuPage(page); await use(sidemenuPage); }, };
  10. RainerHahnekamp Playwright Usage in Test const test = base.extend<SidemenuFixtures>(sidemenuFixtures); test('rename

    Latitia to Laetitia', async ({ page, sidemenuPage }) => { await page.goto(''); await sidemenuPage.select('customers'); // ... });
  11. RainerHahnekamp Cypress Commands declare namespace Cypress { interface Chainable<Subject> {

    openMenu(item: 'Customers' | 'Holidays'): void; } } Cypress.Commands.add('openMenu', (item: 'Customers' | 'Holidays') => { cy.findByRole('link', { name: item }).click(); });
  12. RainerHahnekamp Cypress Commands declare namespace Cypress { interface Chainable<Subject> {

    openMenu(item: 'Customers' | 'Holidays'): void; } } Cypress.Commands.add('openMenu', (item: 'Customers' | 'Holidays') => { cy.findByRole('link', { name: item }).click(); });
  13. RainerHahnekamp Cypress Queries declare namespace Cypress { interface Chainable<Subject> {

    openMenu(item: 'Customers' | 'Holidays'): void; testid(selector: string): Chainable<JQuery<HTMLElement>>; } } Cypress.Commands.add('openMenu', (item: 'Customers' | 'Holidays') => { cy.findByRole('link', { name: item }).click(); }); Cypress.Commands.addQuery('testid', (selector: string) => { const getFn = cy.now('get', `[data-testid=${selector}]`) as () => Promise<Chainable<JQuery>>; return () => getFn(); });
  14. RainerHahnekamp Miscellaneous Features • Network: Stubbing, Verifying, Requesting • Visual

    Regression • A11y: User-Facing Selectors, Axe Plugin • Recorder: Chrome Extensions • Session Storage
  15. RainerHahnekamp Browser Support ✅ Performance ✅ More Control over the

    Browser ✅ Tracing ✅ Backed by Microsoft Playwright ✅ Developer Experience ✅ Mature ✅ Component Testing