- PVSM.RU - https://www.pvsm.ru -
Перевод статьи Alister Scott [1]: Five reasons why Playwright is better than Cypress [2]
Очевидно, что я не фанат Cypress, о чем, собственно, 2 года назад написал пост [3]. За это время мое внимание привлек Playwright. Я специально вернулся к Cypress, чтобы сравнить его с Playwright и посмотреть, были ли исправлены претензии по отношению к первому фреймворку. На основании проведенного сравнения, могу смело рассказать о причинах, почему Cypress все еще проигрывает конкуренцию.
Сравниваемые версии:
Cypress: 8.7.0 on Electron 93
Playwright: 1.16.0
Зафиксированный результат — до 4-х раз быстрее! [4]
Берем простой пример из документации Cypress:
describe('My First Test', () => {
it('clicking "type" shows the right headings', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
// Should be on a new URL which includes '/commands/actions'
cy.url().should('include', '/commands/actions')
// Get an input, type into it and verify that the value has been updated
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
Работает 8 секунд на моем M1 Macbook Air
✔ demo-spec.js
00:08
Тот же пример на Playwright:
import { test, expect } from '@playwright/test'
test.describe.parallel('My First Test', () => {
test('clicking "type" shows the right headings', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
// Should be on a new URL which includes '/commands/actions'
await page.waitForURL(/.+/commands/actions$/)
// Get an input, type into it and verify that the value has been updated
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
})
Running 1 test using 1 worker
✓ scenarios/compare.cypress.spec.ts:4:3 › My First Test › clicking "type" shows the right headings (1s)
1 passed (2s)
В 4 раза быстрее!😎
Чтобы запустить тесты параллельно, нужно отправить их в Cypress Dashboard [5] (или Sorry Cypress [6]). Только так возможна работа в несколько потоков на одной машине, хотя разработчики Cypress и не рекомендуют заниматься подобным. В то же время, на Playwright параллельные тесты запускаются без проблем.
“While parallel tests can also technically run on a single machine, we do not recommend it since this machine would require significant resources to run your tests efficiently.”
https://docs.cypress.io/guides/guides/parallelization#Overview [7]
Либо Cypress так раздут, что для параллельных тестов требуется дорогое оборудование, либо команда Cypress хочет, чтобы пользователи платили за их службу параллельного выполнения. А может быть, и то, и другое?
Например, в Playwright я могу запустить эти 8 тестов параллельно:
import { test, expect } from '@playwright/test'
test.describe.parallel('My First Test', () => {
test('clicking "type" shows the right headings 1', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 2', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 3', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 4', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 5', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 6', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 7', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
test('clicking "type" shows the right headings 8', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
})
на моем Macbook Air занимает всего 6 секунд 😎
npx playwright test "./scenarios/compare.cypress.bulk.spec.ts"
Running 8 tests using 4 workers
✓ scenarios/compare.cypress.bulk.spec.ts:4:3 › My First Test › clicking "type" shows the right headings 1 (4s)
......
8 passed (6s)
Чтобы запустить эти тесты параллельно (с использованием сервера) в Cypress, мне нужно было бы структурировать их как отдельные файлы (по одной спецификации на каждый):
И чтобы провести эти тесты, на той же машине потребуется 45 секунд, что в 7,5 раз медленнее.
import { test, expect } from '@playwright/test'
test.describe.parallel('My First Test', () => {
test('clicking "type" shows the right headings', async ({ page }) => {
await page.goto('https://example.cypress.io')
await page.click('a:has-text("type")')
await page.waitForURL(/.+/commands/actions$/)
await page.fill('.action-email', 'fake@email.com')
await expect(page.locator('.action-email')).toHaveValue('fake@email.com')
})
})
Нет цепочек прототипов, никакого сложного для понимания кода, никакой магии. Вы можете видеть, откуда берутся test, expect и page.
Тот же тест в Cypress:
describe('My First Test', () => {
it('clicking "type" shows the right headings', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
// Should be on a new URL which includes '/commands/actions'
cy.url().should('include', '/commands/actions')
// Get an input, type into it and verify that the value has been updated
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
Обратите внимание, как функция вызывает цепочку. Неплохая реализация в данном примере, но происходящее быстро выходит из-под контроля. Нет никаких указаний, что это синхронный код — отсутствует await на вызовы функций. “Магия” происходит в случае с cy и describe, и при этом совершенно отсутствует импорт.
В Cypress много ограничений. Большую часть из них можно исправить плагинами, но некоторые проблемы таковыми остаются ввиду отсутствия “лекарства”.
Нужно нажать клавишу tab? Для этого есть плагин [8]. И, судя по ишью Github [9] он вообще не работает из-за отсутствия поддержки этой самой клавиши. Тема открыта с 2016 года по сей день. Вопрос актуален в течение всего времени с момента, когда я последний раз писал о Cypress.
Нужно загрузить файл? Для этого также есть плагин. [10]
Вам нужно выполнить тесты n раз подряд, чтобы проверить стабильность тестов? Для этого есть плагин. [11]
К счастью, Playwright изначально поддерживает всё вышеописанное и множество других функций без каких-либо плагинов. 😎
Как видите, я все еще не фанат Cypress 😀
Тем более теперь есть инструмент, который стал намного лучше и доступен совершенно бесплатно.
Так что я буду придерживаться вывода двухлетней давности:
Издалека Cypress выглядит как идеальный инструмент для автоматизированного тестирования. Я думаю, что его неправильно позиционируют, как инструмент е2е тестирования, хотя на самом деле фреймворк годится только для проверки компонентов. В нем слишком много ограничений, чтобы заниматься созданием настоящих e2e тестов.
https://alisterbscott.com/2019/07/06/my-oughtts-on-cypress-io [12]/
Автор: Алексей Иванов
Источник [13]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/370287
Ссылки в тексте:
[1] Alister Scott: https://github.com/alisterscott/
[2] Five reasons why Playwright is better than Cypress: https://alisterbscott.com/2021/10/27/five-reasons-why-playwright-is-better-than-cypress/
[3] написал пост: https://alisterbscott.com/2019/07/06/my-thoughts-on-cypress-io/
[4] Зафиксированный результат — до 4-х раз быстрее!: https://blog.checklyhq.com/cypress-vs-selenium-vs-playwright-vs-puppeteer-speed-comparison/
[5] Cypress Dashboard: https://dashboard.cypress.io/
[6] Sorry Cypress: https://github.com/sorry-cypress/sorry-cypress
[7] https://docs.cypress.io/guides/guides/parallelization#Overview: https://docs.cypress.io/guides/guides/parallelization#Overview
[8] Для этого есть плагин: https://www.npmjs.com/package/cypress-plugin-tab
[9] ишью Github: https://github.com/cypress-io/cypress/issues/299
[10] Для этого также есть плагин.: https://www.npmjs.com/package/cypress-file-upload
[11] Для этого есть плагин.: https://github.com/bahmutov/cypress-repeat
[12] https://alisterbscott.com/2019/07/06/my-oughtts-on-cypress-io: https://alisterbscott.com/2019/07/06/my-oughtts-on-cypress-io
[13] Источник: https://habr.com/ru/post/593577/?utm_source=habrahabr&utm_medium=rss&utm_campaign=593577
Нажмите здесь для печати.