Playwright vs. Cypress - porównanie frameworków do testowania E2E
Szczegółowe porównanie dwóch popularnych frameworków do testowania E2E: Playwright i Cypress. Które z funkcji są porównywalne i który z nich oferuje więcej?
Zaktualizowano: 3 listopada 2024Ostatnio przeniosłem moją stronę na nowy stos technologiczny. Porzuciłem moją starą stronę opartą na Gatsbym i stworzyłem nowy projekt wykorzystując Next.js. Był to spory wysiłek sam w sobie. Zastanawiałem się, czy jest to dobry moment, aby przepisać testy. Testy E2E są abstrakcyjne, więc po migracji musiałbym je dostosować w małym stopniu (albo wcale). Jednakże, zamiast zmieniać rzeczy stopniowo - jak normalny człowiek - zmieniłem wszystko jednocześnie, włączając testy. Zajęło mi to sporo czasu, ale skończyłem mając dwa zestawy testów E2E - w Cypress'ie i Playwright'cie. Postanowiłem, że wykorzystam tę okazję i porównam te dwa frameworki.
Playwright
Playwright to współczesna biblioteka do testowania rozwijana przez Microsoft i wydana w 2020 roku. Zespół. który początkowo pracował nad innym narzędziem do automatyzacji, Puppeteer'em, stworzył Playwright'a. "Chwila, moment, czy Puppeteer nie jest od Google?". Jest, ale ten zespół przeniósł się z Google do Microsoftu. Także jest to kolejne narzędzie od Microsoftu do twojego stosu technologicznego, gdybyś jeszcze nie miał ich wystarczająco wiele.
Playwright składa się z dwóch części:
- Playwright Library, która udostępnia zunifikowane API do uruchamiania i interakcji z przeglądarkami.
- Playwright Test, który dostarcza to API wraz z test runnerem, którym możesz w pełni zarządzać.
Pomimo, że Playwright istnieje na rynku krócej niż Cypress, to zgromadził już ponad 66k gwiazdek na GitHub'ie (w porównaniu do 47 tysięcy Cypress'a). Myślę, że istnieje dobry powód stojący za tą popularnością. Playwright oferuję pełny parytet funkcji z Cypress'em, a nawet więcej.
Cypress
Cypress, framework do testowania E2E aplikacji internetowych, został pierwszy raz wydany we wrześniu 2017 roku. Od czasu wydania zdobył znaczącą popularność wśród społeczności deweloperów, gromadząc ponad 40 000 gwiazdek na GitHub'ie. Framework ten jest rozwijany i utrzymywany przez doświadczonych deweloperów i inżynierów, włączając Gleba Bahamutova. Wielokrotnie wpadałem na jego posty dotyczące testowania - dobre rzeczy. Cypress jest nadal głównym wyborem dla wielu deweloperów szukających frameworka E2E.
Playwright vs. Cypress
Przejdźmy do mięsa tego posta - porównania. Stworzyłem tabelę wyróżniającą wiele funkcjonalności, których możesz się spodziewać po współczesnym narzędziu do testowania E2E. Tabela może być przydatna per se, ale przyjrzę się każdej funkcjonalności z osobna i dodam kontekst. Zacznę od "więcej", gdzie Playwright oferuje ekstra funkcjonalności, a później przejdę do parytetu funkcji.
Funkcjonalność | Playwright | Cypress |
---|---|---|
Język programowania | JS/TS | JS/TS |
Inne języki | Wspierane | Nie wspierane |
Paralelizacja | Darmowa | Płatna |
Przeglądarki | Wsparcie dla wielu | Wsparcie dla wielu |
Inne test runnery | Wspierane | Nie wspierane |
Wiele kart | Wspierane | Nie wspierane |
Generacja kodu | Wspierane | Nie wspierane |
Design | Headless | GUI |
Wydajność | Szybsza | Wolniejsza |
<iframe> | Wspierane | Wspierane |
Interakcje z dialogami | Wspierane | Wspierane |
Plugin do VSC | Oficjalny | Społeczności |
Składnia | Przypominająca ES6 | Przypominająca jQuery |
Interakcje z elementami | Wspierane | Wspierane |
Auto-wait | Wspierane | Wspierane |
Shadow DOM | Wspierane | Wspierane |
Testowanie API | Wspierane | Wspierane |
Dokumentacja | Dobra | Dobra |
Języki programowania
Playwright wspiera TypeScripta "prosto z pudełka". Możesz go zainstalować i od razu pisać testy zabezpieczone typami. JavaScript też jest oczywiście wspierany. Jeżeli używasz Cypress'a, to w domyśle piszesz testy używając języka JavaScript. Jednakże możesz używać Cypress'a wraz z TypeScriptem, gdy dostarczysz odpowiednią konfigurację.
Inne języki
Poza JavaScriptem, Playwright wspiera inne języki programowania, takie jak Python, C# lub Java. Dla mnie nie ma to większego znaczenia, bo i tak tworzę tę stronę w ekosystemie JavaScript. Ale wyobrażam sobie, że wykorzystywanie jednego frameworka do testowania przez cały zespół - front-end i back-end - może być plusem. Będąc przy temacie - poważnie rozważałem, czy powinienem zakwalifikować wsparcie dla Javy jako plus (JavaScript deweloper srający na Javę - o ironio). Cypress nie wspiera (i prawdopodobnie tak pozostanie) innych języków programowania.
Paralelizacja
W domyśle, Playwright uruchamia pliki testowe równolegle. Odpala kilka procesów, które działają jednocześnie. Testy w pojedynczym pliku są uruchamiane po kolei, ale możesz nawet zrównoleglić testy w jednym pliku. Paralelizacja jest płatną funkcjonalnością w usłudze Cypress Cloud.
Przeglądarki
Paralelizacja pomaga w testach wielu przeglądarek. Playwright wprowadza koncept "projektów", gdze każdy z nich może służyć jako odrębna przeglądarka, włączając Safari.
Definiowanie projektów w PlaywrightTS
1projects: [2 {3 name: 'chromium',4 use: { ...devices['Desktop Chrome'] }5 },6 {7 name: 'firefox',8 use: { ...devices['Desktop Firefox'] }9 },10 {11 name: 'webkit',12 use: { ...devices['Desktop Safari'] }13 },14 {15 name: 'Mobile Chrome',16 use: { ...devices['Pixel 5'] }17 },18 {19 name: 'Mobile Safari',20 use: { ...devices['iPhone 12'] }21 }22]
Współczesny Internet Explorer może wprowadzać egzotyczne problemy, więc istotne jest, aby go wspierać. Playwright umożliwia bardzo łatwą, globalną konfigurację różnych projektów. Z drugiej strony, Cypress sprawia trochę kłopotów. Poniżej jest fragment mojej akcji GitHub, która uruchamia wiele przeglądarek.
GitHub action uruchamiająca wiele przeglądarek w CypressYAML
1e2e-test-chrome:2 runs-on: ubuntu-latest3 strategy:4 matrix:5 node: [16]6 needs: build7 steps:8 - name: Checkout commit9 uses: actions/checkout@v310 - name: Use Node ${{ matrix.node }}11 uses: actions/setup-node@v312 with:13 node-version: ${{ matrix.node }}14 cache: npm15 - name: Install dependencies16 run: npm ci --legacy-peer-deps17 - name: Restore Cypress binary18 uses: actions/cache@v319 id: cache-cypress20 with:21 path: ~/.cache/Cypress22 key: cypress-binary-${{ hashFiles('**/package-lock.json') }}23 restore-keys: |24 cypress-binary-25 - name: Download build artifacts26 uses: actions/download-artifact@v327 with:28 name: build-output29 - name: Run Cypress30 uses: cypress-io/github-action@v431 with:32 start: npm run serve33 wait-on: 'http://localhost:8000'34 browser: chrome35 install: false36 e2e-tests-firefox:37 runs-on: ubuntu-latest38 strategy:39 matrix:40 node: [16]41 needs: build42 steps:43 - name: Checkout commit44 uses: actions/checkout@v345 - name: Use Node ${{ matrix.node }}46 uses: actions/setup-node@v347 with:48 node-version: ${{ matrix.node }}49 cache: npm50 - name: Install dependencies51 run: npm ci --legacy-peer-deps52 - name: Restore Cypress binary53 uses: actions/cache@v354 id: cache-cypress55 with:56 path: ~/.cache/Cypress57 key: cypress-binary-${{ hashFiles('**/package-lock.json') }}58 restore-keys: |59 cypress-binary-60 - name: Download build artifacts61 uses: actions/download-artifact@v362 with:63 name: build-output64 - name: Run Cypress65 uses: cypress-io/github-action@v466 with:67 start: npm run serve68 wait-on: 'http://localhost:8000'69 browser: firefox70 headed: true71 install: false
Nie ma tu Safari, ponieważ Cypress przez długi czas nie wspierał Safari. Dopiero niedawno otrzymał eksperymentalne wsparcie dla Webkit'a (silnik Safari).
Inne test runnery
Playwright Test to dedykowany test runner dla tego frameworka. Jednakże, dodając kilka lini kodu, możesz podpiąć Playwright'a do innych, istniejących runnerów, takich jak Jest, Mocha czy AVA. Cypress nie wspiera zewnętrznych test runnerów.
Wiele kart
Playwright wykorzystuje BrowserContext
, który umożliwia operowanie wieloma, niezależnymi sesjami przeglądarek. Możesz w łatwy sposób pisać testy, które wchodzą w interakcję z wieloma kartami. Cypress uruchamiany jest wewnątrz przeglądarki, dlatego nie wspiera wielu kart.
Generacja kodu
Nie nazwałbym tego najistotniejszą funkcjonalnością, ale jest fajna. Playwright pozwala generować kod. Rozpoczynasz nagrywanie, klikasz w swojej aplikacji i, dla przykładu, Playwright generuje dla ciebie odpowiednie lokatory (jest to sposób na odnalezienie elementu na stronie, podobny do JavaScriptowych selektorów). Raczej nie wygeneruje ci produkcyjnego kodu, ale jest to dobry punkt startowy. Cypress nie oferuje analogicznej funkcjonalności.
Wydajność
Z drugiej strony, wydajność jest istotna dla większości ludzi. Playwright bezpośrednio wchodzi w interakcję z przeglądarką wykorzystując protokół Chrome dev tools, co przekłada się na lepszą wydajność. Wykorzystałem mój zestaw bliźniaczych testów i przetestowałem wydajność. Testowałem wykorzystując UI i przeglądarkę Chromium w obu frameworkach. Aby uniknąć odstających wyników, każdy z testów uruchomiłem wielokrotnie i wziąłem średni czas. Dla Cypress'a, jest to całkowity czas, a dla Playwright'a wziąłem czas najdłuższego testu, ponieważ są one uruchamiane równolegle.
Testy | Playwright | Cypress |
---|---|---|
Internacjonalizacja | ~1.425s | ~4.5s |
Dostępność | ~2.1s | ~5.5s |
Subskrypcja | ~870ms | ~4.25s |
Nawigacja | ~1.2s | ~4s |
Oczywiście zależy to od wielu czynników, ale możemy przyjąć, że Playwright jest z grubsza 3-4 razy szybszy niż Cypress.
Wsparcie dla iframe
Strona w Playwright wystawia aktualny frame tree poprzez odpowiednie metody. Masz dostęp do elementów iframe prosto po wyjęciu z cyfrowego pudełka. Cypress także wspiera elementy iframe, ale wymaga dodatkowego pluginu.
Okna dialogowe
Podobna historia dotyczy natywnych, przeglądarkowych okien dialogowych. Playwright automatycznie je pomija, ale możesz zarejestrować handler i je łatwo zaakceptować. Cypress także może je obsłużyć wykorzystując eventy, ale kod wtedy zależy od rodzaju okna dialogowego.
Plugin do VSC
Oba frameowrki oferują wspierające pluginy do edytora Visual Studio Code. Microsoft rozwija oficjalny plugin do Playwright'a. Używając Cypress'a, musisz się zadowolić pluginami od społeczności.
Składnia
Preferencje składniowe są subiektywne, więc ciężko wskazać tutaj zwycięzcę. Playwright oferuje składnię podobną do współczesnego, asynchronicznego JavaScriptu ES6, z wieloma słowami kluczowymi async
i await
. Testy Cypress'a przypominają składnią jQuery, z łańcuchami metod. Poniżej prezentuję test E2E napisany dla obu frameworków.
Test subskrypcji w PlaywrightTS
1import { test, expect } from './fixtures'23test.describe('Subscription tests', () => {4 test('checks the successful flow', async ({ page, settingsPage }) => {5 const { section } = await settingsPage.getDictionary('en')6 const formURL = await settingsPage.getFormURL('en')78 await page.route(formURL, (route) =>9 route.fulfill({10 status: 200,11 contentType: 'application/json',12 body: JSON.stringify({ status: 'success' })13 })14 )15 await page.goto(settingsPage.link.home)1617 const input = page.getByLabel(section.newsletter.email)18 const button = page.getByRole('button', { name: section.newsletter.button })1920 await expect(input).toHaveAttribute('required')21 await expect(input).toHaveAttribute('type', 'email')22 await expect(input).toHaveAttribute('autocomplete', 'off')2324 await input.fill(settingsPage.example.email)25 await button.scrollIntoViewIfNeeded()26 await button.click()2728 await expect(29 page.getByText(section.newsletter.success.heading)30 ).toBeVisible()31 })3233 // More test cases34})
Test subskrypcji w CypressJS
1/// <reference types="Cypress" />2import { icon } from '../fixtures/theme.json'3import { form, user } from '../fixtures/subscription.json'45describe('Subscription tests', () => {6 beforeEach(() => {7 cy.visit('/blog/hello-world/')8 cy.findByTestId(icon).should('exist')9 cy.findByPlaceholderText(form.email)10 .as('email')11 .should('have.prop', 'type', 'email')12 .and('have.prop', 'required')13 cy.findByRole('button', { name: form.button }).as('button')14 })1516 it('Tests success flow', () => {17 cy.intercept(form.url, (req) => {18 expect(req.body).to.include('email_address')19 expect(req.body).to.include(user.email)20 req.reply({21 statusCode: 200,22 body: {23 status: 'success'24 }25 })26 })27 cy.get('@email').type(user.email, { delay: 50 })28 cy.get('@button').click()29 cy.findByText(form.success, { exact: false }).should('be.visible')30 })3132 // More test cases33})
Design
W tej sekcji, odnoszę się do ogólnego projektu frameworka. Playwright zaprojektowany jest "bez głowy" - graficzny interfejs użytkownika to tylko dodatek. Nie musisz nic konfigurować, żeby uruchomić Playwright'a na serwerze CI. Istnieje flaga, aby uruchomić go w trybie GUI.
🔴 🟡 🟢
npx playwright test --ui
Cypress jest zaprojektowany w myśl przeciwnej filozofii. Graficzny interfejs jest w centrum doświadczenia. Możesz dostosować konfigurację, aby uruchomić Cypress'a na serwerze CI.
Interakcja z elementami
Zarówno Playwright jak i Cypress oferują dobre API do interakcji z elementami DOM. Playwright wprowadza lokatory. Jest to sposób, aby w dowolnym momencie znaleźć elementy na stronie. Każdy kto kiedykolwiek używał Testing Library, będzie się tu czuł jak w domu.
Interakcja z elementami w PlaywrightTS
1await page.getByRole('button', { name: 'Submit' }).click()
W Cypress'ie, do łapania za elementy służy funkcja get. Istnieje też sposób, aby dodawać znaczące nazwy do elementów wykorzystując aliasy.
Interakcja z elementami w CypressJS
1cy.get('button[type=submit]').as('submitBtn')23cy.get('@submitBtn').click()
Auto-wait
Odnosząc się do poprzedniej sekcji, oba frameworki automatycznie zaczekają na te elementy (w przeciwieństwie do Selenium). Funkcja ta pomaga w testowaniu współczesnych, dynamicznych interfejsów użytkownika, gdzie komponenty są często dołączane i odłączane od DOM-u. Dzięki temu, testy mają tendencję do bycia mniej "flaky".
Shadow DOM
Będąc przy komponentach, lokatory Playwright'a domyślnie będą działały z elementami w shadow DOM. Jest to konieczne, jeżeli twoja aplikacja wykorzystuje te natywne, niestandardowe komponenty. Cypress także może wchodzić w interakcję z tymi elementami "cieniowego" DOM-u. Jednakże, w tym celu, musisz wywoływać dodatkową metodę.
Testowanie API
Poza testowaniem interfejsów użytkownika, oba frameworki umożliwiają testowanie interfejsów API. Playwright może uzyskać dostęp do twojego REST API. Jest to pomocne, jeżeli chcesz przetestować serwer API albo przygotować odpowiedź serwera przez odwiedzeniem aplikacji. Cypress także dostarcza dobre doświadczenie jeżeli chodzi o testowanie API.
Dokumentacja
Oba frameworki posiadają dogłębną i szeroką dokumentację techniczną. Podczas pracy z nimi, rzadko czułem potrzebę zaglądania do innych źródeł. Ciężko wskazać konkretny powód, ale preferuję dokumentację Cypress'a. Może to przez estetykę? I nie zrozum mnie źle - Playwright ma dobrą dokumentację. Szybko zacząłem i przepisałem moje testy z jej wykorzystaniem. Ale ma ona twardą konkurencję - dokumentacja Cypress'a jest po prostu bardzo dobra.
Podsumowanie
Nie będzie tu żadnych zwrotów akcji, bo już na początku napisałem, że przepisałem moje testy do Playwright'a. Dlatego znasz już mój wybór. Mam nadzieję, że po przeczytaniu tego posta znasz także powody stojące za tą decyzją. Playwright oferuje pełny parytet funkcjonalności względem Cypress'a i dodatkowe funkcjonalności, jak paralelizacja czy wsparcie dla wielu kart, które są dla mnie przydatne. Jednakże, po napisaniu tego wszystkiego, nadal uważam, że Cypress to bardzo dobry wybór. Jego popularność to nie przypadek. A co z tobą - który z frameworków wybierasz?