Puppeteer — это библиотека для работы с браузером Google Chrome или Chromium с помощью API для автоматизации. В процессе тестирования с использованием Puppeteer часто возникает необходимость в создании кастомных функций для выполнения специфических действий на веб-страницах. Типизация этих функций с помощью TypeScript позволяет обеспечить большую предсказуемость кода, улучшить автодополнение и минимизировать количество ошибок.
Типизация кода, особенно при использовании таких библиотек, как Puppeteer, позволяет избежать множества проблем:
Для работы с Puppeteer в TypeScript необходимо установить соответствующие типы:
npm install --save puppeteer
npm install --save-dev @types/puppeteer
После этого можно использовать типы, предоставляемые библиотекой, для
работы с основными объектами, такими как Page,
ElementHandle, Browser, и другие. Например,
при взаимодействии с веб-страницей можно указать типы для переменных,
которые содержат объекты Page или
ElementHandle:
import puppeteer, { Page, Browser } from &
async function example() {
const browser: Browser = await puppeteer.launch();
const page: Page = await browser.newPage();
await page.goto('https://example.com');
// Действия с элементами страницы
const element = await page.$('h1');
if (element) {
const text = await element.evaluate(el => el.textContent);
console.log(text);
}
await browser.close();
}
В процессе тестирования часто необходимо создавать кастомные функции для выполнения специфических задач, например, взаимодействие с элементами на странице или выполнение сложных сценариев. Чтобы улучшить качество кода, эти функции должны быть правильно типизированы.
async function clickButton(page, selector) {
await page.click(selector);
await page.waitForSelector(selector, { visible: true });
}
async function clickButton(page: Page, selector: string): Promise<void> {
await page.click(selector);
await page.waitForSelector(selector, { visible: true });
}
Типизация позволяет явно указать типы входных параметров функции и
возвращаемое значение. В данном примере page типизирован
как Page, а selector как строка
(string). Возвращаемое значение функции —
Promise<void>, что означает, что функция асинхронная
и не возвращает никакого значения.
Часто в тестах приходится взаимодействовать с элементами DOM. Для этого
Puppeteer предоставляет объект ElementHandle, который
представляет собой ссылку на элемент на странице. Типизация
ElementHandle помогает избежать ошибок при работе с
DOM-элементами.
async function getElementText(page: Page, selector: string): Promise<string | null> {
const element: ElementHandle | null = await page.$(selector);
if (element) {
return element.evaluate(el => el.textContent);
}
return null;
}
Здесь element имеет тип ElementHandle | null,
так как результат поиска может быть либо ссылкой на элемент, либо
null, если элемент не найден.
В Puppeteer можно использовать дополнительные типы для более точной
типизации объектов. Например, для работы с различными опциями, которые
принимает метод page.goto, можно создать интерфейсы для их
параметров.
interface NavigationOptions {
timeout: number;
waitUntil: 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
}
async function navigateToPage(page: Page, url: string, options: NavigationOptions): Promise<void> {
await page.goto(url, { waitUntil: options.waitUntil, timeout: options.timeout });
}
В данном примере создается интерфейс NavigationOptions,
который описывает параметры для метода goto. Это помогает
гарантировать, что все передаваемые параметры будут корректными.
Большинство функций Puppeteer — асинхронные, и правильная типизация
результатов асинхронных операций критична для стабильности и читаемости
кода. Типизация Promise позволяет точно указать, что
возвращается из асинхронных функций, и облегчает работу с результатами.
async function getPageTitle(page: Page): Promise<string> {
const title: string = await page.title();
return title;
}
Здесь тип Promise<string> указывает на то, что
функция возвращает асинхронный результат, который будет строкой.
Типизация таких функций помогает избежать ошибок, например, если
случайно пытаются обработать результат как другой тип данных.
Работа с ошибками в Puppeteer также требует внимательной типизации. Например, если необходимо обрабатывать исключения, выбрасываемые при взаимодействии с элементами на странице, можно использовать типы для обработки ошибок.
async function getElementTextWithErrorHandling(page: Page, selector: string): Promise<string | null> {
try {
const element: ElementHandle | null = await page.$(selector);
if (element) {
return await element.evaluate(el => el.textContent);
}
return null;
} catch (error) {
console.error('Error fetching element text:', error);
return null;
}
}
Здесь используется конструкция try-catch для перехвата
возможных исключений, что важно для стабильности работы тестов. Тип
возвращаемого значения функции по-прежнему остается string |
null, что помогает избежать ошибок при обработке результата.
Для более сложных сценариев можно создавать кастомные классы, которые инкапсулируют логику взаимодействия с Puppeteer. Типизация этих классов позволяет создать более структурированный код и повысить его гибкость.
class PuppeteerHelper {
private page: Page;
constructor(page: Page) {
this.page = page;
}
async clickElement(selector: string): Promise<void> {
await this.page.click(selector);
await this.page.waitForSelector(selector, { visible: true });
}
async getElementText(selector: string): Promise<string | null> {
const element: ElementHandle | null = await this.page.$(selector);
if (element) {
return await element.evaluate(el => el.textContent);
}
return null;
}
}
В этом примере класс PuppeteerHelper инкапсулирует логику
взаимодействия с элементами на странице. Типизация для всех методов
позволяет четко определить, какие параметры ожидаются и что возвращается
из функций.
Page и ElementHandle, значительно улучшает
поддержку и развитие проекта.