Playwright предоставляет API для автоматизации браузеров, позволяющее легко писать тесты для веб-приложений. Важным аспектом работы с Playwright является асинхронность, поскольку большинство операций с браузером — например, клики, ввод данных или получение текста — требуют времени для выполнения. Поэтому в Playwright активно используются Promises и конструкции async/await для управления асинхронными процессами.
JavaScript имеет несколько способов работы с асинхронным кодом, включая Callbacks, Promises и async/await. В контексте Playwright предпочтительным способом является использование Promises и async/await, так как они обеспечивают более читаемый и поддерживаемый код.
Callbacks — это функции, которые передаются как аргументы в другие функции и вызываются позже, когда операция завершена. Однако с ростом сложности кода возникает проблема «callback hell» — трудности в чтении и поддержке таких цепочек.
Promises предоставляют удобный способ работы с асинхронными операциями, возвращая объект, который будет выполнен (или отклонен) позже. then() и catch() позволяют работать с результатами выполнения Promise.
async/await — синтаксический сахар над Promises,
который позволяет работать с асинхронными операциями в линейном и более
читаемом виде, избавляя от необходимости вручную цеплять колбэки или
методы .then().
Playwright основан на асинхронных методах, что означает, что его API
использует Promises для представления результатов операций. Все ключевые
методы, такие как page.click(), page.fill(),
browser.newPage() возвращают Promise.
Следовательно, нужно использовать async/await для
корректного выполнения этих операций.
Пример асинхронного кода с Playwright:
const { chromium } = require('playwright');
async function runTest() {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log(title);
await browser.close();
}
runTest();
Здесь:
runTest() объявлена как async, что
позволяет использовать await внутри неё.launch(), newPage(), goto(),
title(), возвращают Promises и требуют await
для ожидания их завершения.Одним из распространенных сценариев является необходимость выполнения
нескольких асинхронных операций параллельно. В таких случаях можно
использовать Promise.all() для одновременного выполнения
нескольких задач, что значительно ускоряет тесты.
Пример параллельного выполнения:
const { chromium } = require('playwright');
async function runTest() {
const browser = await chromium.launch();
const page1 = await browser.newPage();
const page2 = await browser.newPage();
const [title1, title2] = await Promise.all([
page1.goto('https://example.com'),
page2.goto('https://example.org')
]);
console.log('Title of example.com:', await page1.title());
console.log('Title of example.org:', await page2.title());
await browser.close();
}
runTest();
Здесь используется Promise.all(), чтобы начать загрузку
страниц одновременно, а затем получить их титулы, не дожидаясь
завершения каждой операции по очереди. Это позволяет ускорить выполнение
тестов, особенно при тестировании многозадачных сценариев.
При работе с асинхронными функциями важно правильно обрабатывать
исключения. Если один из Promises в цепочке не выполнится (например,
из-за проблем с сетью или браузером), то выполнение всего теста будет
остановлено. Для обработки ошибок используйте конструкцию
try/catch, которая позволяет перехватывать и обрабатывать
исключения, а также выводить диагностическую информацию.
Пример обработки ошибок:
const { chromium } = require('playwright');
async function runTest() {
const browser = await chromium.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com');
const title = await page.title();
console.log(title);
} catch (error) {
console.error('Ошибка при работе с Playwright:', error);
} finally {
await browser.close();
}
}
runTest();
В этом примере:
catch, и можно вывести её описание.finally гарантирует, что браузер будет закрыт
независимо от того, произошла ошибка или нет.При взаимодействии с элементами на странице важно не только запустить
действие, но и убедиться, что элемент доступен для взаимодействия. Для
этого Playwright предоставляет методы ожидания, такие как
waitForSelector() и waitForTimeout(), которые
позволяют сделать тесты более надежными.
Пример ожидания элемента:
const { chromium } = require('playwright');
async function runTest() {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.waitForSelector('h1'); // Ждем, пока заголовок появится на странице
const title = await page.innerText('h1');
console.log('Заголовок страницы:', title);
await browser.close();
}
runTest();
Здесь:
waitForSelector() ожидает, пока элемент с тегом
h1 появится на странице.Использование методов ожидания в сочетании с async/await
позволяет легко писать стабильные тесты, минимизируя риски ошибок,
связанных с асинхронной природой работы браузера.
Одним из частых случаев является создание цепочек асинхронных
операций, где каждый шаг зависит от предыдущего. С использованием
async/await такие цепочки становятся читаемыми и
понятными.
Пример цепочки асинхронных операций:
const { chromium } = require('playwright');
async function runTest() {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log('Титул страницы:', title);
await page.click('a[href="/another-page"]');
await page.waitForNavigation();
console.log('Навигация завершена');
await browser.close();
}
runTest();
Здесь:
Использование Promises и async/await в Playwright помогает упростить и улучшить работу с асинхронными операциями. Эти инструменты позволяют писать тесты, которые не только эффективны и быстры, но и легко поддерживаемы. Proper использование асинхронных функций помогает избежать ошибок и делает взаимодействие с браузером предсказуемым и надежным.