ElementHandle API

ElementHandle — это объект, представляющий HTML-элемент на странице, который позволяет взаимодействовать с ним напрямую. Он обеспечивает низкоуровневый доступ к элементам DOM, что полезно для операций, которые невозможно выполнить через стандартные селекторы page.locator() или высокоуровневые методы page.click().

Получение ElementHandle

Для получения ElementHandle используется метод page.$(selector), возвращающий первый найденный элемент по CSS-селектору. Если элементов несколько, можно использовать page.$$(selector), возвращающий массив ElementHandle.

const element = await page.$('#username');
const buttons = await page.$$('button');
  • page.$(selector) — возвращает один элемент или null, если элемент не найден.
  • page.$$(selector) — возвращает массив, даже если элементов нет, тогда массив пустой.

Взаимодействие с элементами через ElementHandle

ElementHandle позволяет выполнять следующие действия:

  • Клик и ввод текста:
await element.click();
await element.type('тестовая строка');
  • Получение текста и атрибутов:
const text = await element.textContent();
const value = await element.getAttribute('value');
  • Проверка состояния элемента:
const isVisible = await element.isVisible();
const isEnabled = await element.isEnabled();

Вложенные элементы и скрипты

ElementHandle можно использовать для поиска дочерних элементов относительно конкретного узла DOM:

const parent = await page.$('.form');
const input = await parent.$('input[name="email"]');

Для выполнения произвольного JavaScript внутри контекста элемента используется метод evaluate:

const result = await element.evaluate(el => el.innerHTML);

evaluate позволяет выполнять функции прямо в браузере, передавая DOM-узел в качестве аргумента.

Работа с несколькими элементами

Для работы с набором элементов можно использовать массив ElementHandle:

const items = await page.$$('.item');
for (const item of items) {
    const name = await item.textContent();
    console.log(name);
}

Это удобно для итерирования по спискам и таблицам на странице.

Навигация по DOM

ElementHandle позволяет получать родительские, соседние и дочерние элементы:

  • element.$(selector) — поиск дочернего элемента
  • element.$eval(selector, fn) — выполнить функцию на дочернем элементе
  • element.evaluateHandle(fn) — получить новый ElementHandle из текущего

Пример:

const parent = await page.$('.parent');
const childHandle = await parent.$('.child');

Скриншоты и визуальное тестирование

С помощью ElementHandle можно делать скриншоты конкретного элемента, что полезно для визуальных проверок:

await element.screenshot({ path: 'element.png' });

Также можно использовать метод boundingBox() для получения координат элемента:

const box = await element.boundingBox();
console.log(box.width, box.height, box.x, box.y);

События и взаимодействия

ElementHandle поддерживает эмуляцию различных пользовательских событий:

await element.hover();
await element.focus();
await element.dispatchEvent('input', { data: 'текст' });
  • hover() — наведение мыши
  • focus() — установка фокуса
  • dispatchEvent(type, eventInit) — генерация события с заданными параметрами

Особенности управления жизненным циклом

ElementHandle жёстко привязан к конкретной странице и её состоянию. Если элемент удаляется из DOM, методы ElementHandle перестают работать и вызывают ошибку. Для надёжной работы рекомендуется:

  • Проверять существование элемента через element.evaluate(el => el.isConnected).
  • Получать ElementHandle после обновления DOM, если страница динамическая.

Связь с Locator API

Locator обеспечивает ленивое взаимодействие с элементами и часто предпочтительнее для тестов, так как автоматически ждёт появления элементов. ElementHandle же фиксирует элемент в момент получения и требует явного ожидания:

await page.waitForSelector('#username');
const element = await page.$('#username');

Примеры комплексного использования

  1. Получение текста из таблицы:
const rows = await page.$$('table tr');
for (const row of rows) {
    const cells = await row.$$('td');
    for (const cell of cells) {
        const text = await cell.textContent();
        console.log(text);
    }
}
  1. Скриншот активного элемента формы:
const input = await page.$('input[name="password"]');
await input.focus();
await input.screenshot({ path: 'password_input.png' });
  1. Выполнение кастомного скрипта:
const list = await page.$('.items');
const data = await list.evaluate(el => [...el.children].map(li => li.textContent));
console.log(data);

ElementHandle предоставляет полный контроль над элементами страницы, позволяя работать с DOM напрямую, получать данные, эмулировать события и интегрироваться с визуальным тестированием. Он является необходимым инструментом для низкоуровневого тестирования и работы с динамическими интерфейсами, где стандартные методы могут быть недостаточны.