Puppeteer предоставляет мощный инструмент для автоматизации браузера Chrome и Chromium, включая взаимодействие с расширениями. Одной из сложных задач в автоматизированном тестировании является работа с popup окон расширений, поскольку они отличаются от стандартных вкладок и требуют специфического подхода для доступа к их DOM и событиям.
Перед взаимодействием с popup необходимо запустить браузер с загруженным
расширением. Для этого используется опция
–disable-extensions-except и –load-extension
при запуске браузера через Puppeteer:
const puppeteer = require(&
(async () => {
const pathToExtension = '/path/to/extension';
const browser = await puppeteer.launch({
headless: false,
args: [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`
]
});
})();
Ключевой момент: Расширения работают только в режиме не-headless, так как Chrome блокирует popup в headless-режиме.
Popup расширения создаётся как отдельный target в браузере. Для доступа
к нему используется метод browser.targets() или обработчик
события targetcreated. Обычно popup открывается после
взаимодействия с иконкой расширения:
const targetsBefore = await browser.targets();
// Здесь происходит клик по иконке расширения
const extensionId = 'abcdefghijklmnop'; // ID расширения
const extensionPopupUrl = `chrome-extension://${extensionId}/popup.html`;
const popupTarget = await new Promise(resolve => {
browser.on('targetcreated', target => {
if (target.url() === extensionPopupUrl) {
resolve(target);
}
});
});
const popupPage = await popupTarget.page();
Важное замечание: URL popup известен только после
анализа манифеста расширения (manifest.json) и его поля
browser_action или action (в зависимости от
манифеста версии 2 или 3).
После получения объекта Page для popup можно использовать
стандартные Puppeteer методы:
page.() < /code > и < code > page.$()</code> — поиск
элементов</li>
<li><code>page.click()</code> — эмуляция
клика</li>
<li><code>page.type()</code> — ввод текста</li>
<li><code>page.waitForSelector()</code> — ожидание
появления
элемента</li>
</ul>
<p>Пример заполнения формы внутри popup:</p>
<pre class="javascript"><code>await
popupPage.waitForSelector('#username');
await popupPage.type('#username',
'testuser');
await popupPage.type('#password',
'securepassword');
await popupPage.click('#loginButton');
await popupPage.waitForSelector('#successMessage', {
visible: true });</code></pre>
<p><strong>Совет:</strong> Popup закрывается
автоматически при потере
фокуса, поэтому все действия нужно выполнять сразу после его
открытия.</p>
<h4 id="ожидание-появления-popup">Ожидание появления
popup</h4>
<p>Для корректной работы с popup важно дождаться его появления.
Один из
подходов — постоянная проверка новых targets:</p>
<pre class="javascript"><code>function
waitForExtensionPopup(browser, url, timeout = 5000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new
Error('Popup не появился')), timeout);
browser.on('targetcreated', target => {
if (target.url() === url) {
clearTimeout(timer);
resolve(target.page());
}
});
});
}</code></pre>
<p>Такой метод обеспечивает надежное получение страницы popup,
даже если
открытие происходит с задержкой.</p>
<h4 id="взаимодействие-с-background-скриптами">Взаимодействие с
background скриптами</h4>
<p>Для тестирования расширений важно не только работать с popup,
но и
проверять его связь с background-скриптами. Puppeteer позволяет
подключаться к background-странице расширения через
<code>targets()</code>:</p>
<pre class="javascript"><code>const backgroundTarget =
browser.targets().find(target =>
target.type() === 'background_page'
&&
target.url().startsWith(`chrome-extension://${extensionId}/) ); const backgroundPage = await backgroundTarget.page();</code></pre> <p>Это открывает возможность:</p> <ul> <li>Отправлять сообщения через <code>chrome.runtime.sendMessage</code></li> <li>Проверять состояние background-скрипта</li> <li>Имитация событий, которые запускают popup</li> </ul> <h4 id="особенности-отладки">Особенности отладки</h4> <ul> <li><strong>Скрипты popup изолированы:</strong> Они выполняются в своем контексте, поэтому <code>window</code> и <code>document</code> не связаны с основным сайтом.</li> <li><strong>Headless режим недоступен:</strong> Все взаимодействия требуют GUI браузера.</li> <li><strong>Закрытие popup:</strong> Любое перемещение фокуса может закрыть popup, поэтому операции должны выполняться последовательно и без переключения вкладок.</li> </ul> <h4 id="рекомендации-по-стабильности-тестов">Рекомендации по стабильности тестов</h4> <ol type="1"> <li>Всегда использовать <code>await page.waitForSelector()</code> перед взаимодействием с элементами.</li> <li>Фиксировать ID элементов в расширении для надежного поиска (<code>#id</code> вместо <code>.class</code>).</li> <li>Минимизировать переключение между страницами и popup, чтобы избежать непреднамеренного закрытия окна.</li> <li>Логировать URL и target при тестировании, чтобы корректно идентифицировать popup и background страницы.</li> </ol> <h4 id="пример-комплексного-сценария">Пример комплексного сценария</h4> <pre class="javascript"><code>const extensionId = 'abcdefghijklmnop'; const extensionPopupUrl =chrome-extension://${extensionId}/popup.html`;
const browser = await puppeteer.launch({ headless: false, args: [
--disable-extensions-except=/path/to/extension,
--load-extension=/path/to/extension ] });
const page = await browser.newPage(); await page.goto('https://example.com');
// Ожидание открытия popup через клик по иконке const popupPage = await waitForExtensionPopup(browser, extensionPopupUrl); await popupPage.waitForSelector('#loginButton'); await popupPage.click('#loginButton');
// Проверка состояния background const backgroundTarget = browser.targets().find(t => t.type() === 'background_page' && t.url().startsWith(chrome-extension://${extensionId}/) );
const backgroundPage = await backgroundTarget.page(); const status =
await backgroundPage.evaluate(() => window.isLoggedIn);
console.log('Статус входа:', status);
Этот подход демонстрирует полный цикл работы: запуск браузера с расширением, открытие popup, взаимодействие с его DOM и проверку состояния background скрипта.
Работа с popup расширений требует внимания к деталям и строгого соблюдения последовательности действий, но использование Puppeteer позволяет автоматизировать сложные сценарии и интеграционные тесты для расширений Chrome.