Фреймы (frames) представляют собой отдельные контексты внутри веб-страницы, которые позволяют загружать независимые документы HTML. В тестировании часто приходится взаимодействовать с содержимым iframe, поэтому понимание Frame API является ключевым для автоматизации сложных веб-приложений.
Каждая страница в Playwright может содержать один или несколько
фреймов. Основной (главный) фрейм доступен через метод
page.mainFrame(), а дополнительные можно получить из списка
всех фреймов:
const mainFrame = page.mainFrame();
const allFrames = page.frames();
console.log(allFrames.length); // количество фреймов на странице
Дочерние фреймы можно идентифицировать по имени, URL или другим свойствам. Например:
const frame = page.frame({ name: 'iframeName' });
const frameByUrl = page.frame({ url: /example\.com/ });
name — значение атрибута name у
тега <iframe>.url может быть строкой, шаблоном или
регулярным выражением, соответствующим URL фрейма.Фрейм ведет себя почти как страница. Можно использовать те же методы,
что и для page:
await frame.click('button#submit');
await frame.fill('input[name="username"]', 'admin');
const text = await frame.textContent('.message');
Ключевые моменты:
click, fill,
textContent, waitForSelector и другие работают
непосредственно внутри фрейма.Фреймы могут загружаться асинхронно. Для корректной работы рекомендуется явно ожидать их появление:
const frame = await page.waitForSelector('iframe#myFrame').then(f => f.contentFrame());
await frame.waitForSelector('button#submit');
waitForSelector('iframe') позволяет дождаться, пока
iframe появится на странице.contentFrame() возвращает объект Frame, с
которым можно работать.Фреймы могут содержать другие фреймы. Для поиска вложенного фрейма
используется метод frame.childFrames():
const parentFrame = page.frame({ name: 'parentFrame' });
const nestedFrame = parentFrame.childFrames()[0];
await nestedFrame.click('#nestedButton');
childFrames() возвращает массив прямых дочерних
фреймов.childFrames().Для получения данных или выполнения действий можно использовать метод
evaluate:
const result = await frame.evaluate(() => {
return document.querySelector('#data').textContent;
});
Особенности:
evaluate выполняется в контексте
фрейма.const result = await frame.evaluate((selector) => {
return document.querySelector(selector).value;
}, 'input#name');
Фреймы могут изменять свой URL независимо от основной страницы. Методы навигации аналогичны странице:
await frame.goto('https://example.com/form');
await frame.reload();
goto — переход к новому URL внутри фрейма.reload — перезагрузка содержимого фрейма.load.Фреймы генерируют события, на которые можно подписаться через объект
page:
page.on('frameattached', frame => {
console.log('Фрейм присоединён:', frame.url());
});
page.on('framenavigated', frame => {
console.log('Фрейм перешёл на новый URL:', frame.url());
});
page.on('framedetached', frame => {
console.log('Фрейм удалён:', frame.url());
});
frameattached — срабатывает при добавлении нового
фрейма.framenavigated — при смене URL фрейма.framedetached — при удалении фрейма из DOM.Для сложных тестов полезно проверять структуру фреймов:
function printFrames(frame, level = 0) {
console.log(' '.repeat(level * 2) + frame.url());
frame.childFrames().forEach(child => printFrames(child, level + 1));
}
printFrames(page.mainFrame());
waitForSelector и contentFrame.frame({ name }) или
frame({ url }) вместо индексов массива, так как порядок
фреймов может изменяться.childFrames() вместо ручного угадывания.Frame API в Playwright обеспечивает полный контроль над любыми фреймами на странице, позволяя писать стабильные и надежные тесты даже для сложных веб-приложений с множественными iframe.