Переключение между окнами и табами

В процессе автоматизированного тестирования веб-приложений часто возникает необходимость работать с несколькими окнами или вкладками браузера. Protractor предоставляет средства для управления этими объектами через WebDriver API, позволяя переключаться между окнами, выполнять действия в нужном контексте и возвращаться к исходному состоянию.

Работа с окнами и вкладками

В Protractor каждое окно или вкладка идентифицируется с помощью window handle — уникального идентификатора, возвращаемого методом getAllWindowHandles(). Основные операции включают:

  1. Получение всех открытых окон или вкладок:
browser.getAllWindowHandles().then(function(handles) {
    console.log(handles);
});

handles — массив строк, каждая из которых соответствует одному окну или вкладке. Порядок элементов соответствует порядку открытия окон, но на практике лучше явно проверять нужный handle.

  1. Переключение на нужное окно:
browser.switchTo().window(handles[1]);

После выполнения этого кода все последующие команды будут выполняться в контексте выбранного окна.

  1. Закрытие текущего окна:
browser.close();

После закрытия окна необходимо явно переключиться на другое окно, иначе дальнейшие команды приведут к ошибке.

Пример работы с двумя вкладками

// Открытие страницы и инициирование новой вкладки
browser.get('https://example.com');
element(by.id('openNewTab')).click();

// Получение всех окон
browser.getAllWindowHandles().then(function(handles) {
    let originalWindow = handles[0];
    let newWindow = handles[1];

    // Переключение на новую вкладку
    browser.switchTo().window(newWindow);
    browser.getTitle().then(title => console.log('Title новой вкладки:', title));

    // Выполнение действий на новой вкладке
    element(by.css('.some-button')).click();

    // Возврат к исходной вкладке
    browser.switchTo().window(originalWindow);
});

В этом примере демонстрируется стандартный сценарий: сохранение идентификаторов окон, переключение на целевую вкладку, выполнение действий и возврат к исходной вкладке.

Асинхронность и управление ожиданиями

Protractor основан на промисах, поэтому при работе с окнами необходимо учитывать асинхронность. Часто требуется использовать ожидания, чтобы убедиться, что новая вкладка полностью загружена:

let EC = protractor.ExpectedConditions;

browser.getAllWindowHandles().then(function(handles) {
    let newWindow = handles[1];
    browser.switchTo().window(newWindow);

    let elementToWaitFor = element(by.css('.loaded-element'));
    browser.wait(EC.presenceOf(elementToWaitFor), 5000);
});

Использование ExpectedConditions гарантирует, что действия будут выполняться только после полной готовности элементов на странице.

Управление множественными окнами

Для сложных сценариев с большим количеством окон рекомендуется создавать утилиты:

function switchToWindowByTitle(title) {
    return browser.getAllWindowHandles().then(function(handles) {
        let found = false;
        let promises = handles.map(function(handle) {
            return browser.switchTo().window(handle).getTitle().then(function(t) {
                if (t === title) {
                    found = true;
                }
            });
        });
        return Promise.all(promises).then(() => {
            if (!found) throw new Error('Окно с таким заголовком не найдено');
        });
    });
}

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

Особенности и ограничения

  • browser.switchTo().window(handle) работает только с открытыми окнами браузера. Закрытые окна нужно исключать из массива handles.
  • При использовании браузеров с политикой блокировки всплывающих окон необходимо учитывать, что автоматическое открытие вкладок может быть запрещено.
  • Некоторые действия, такие как browser.navigate().back(), влияют только на текущее окно, поэтому перед выполнением навигации важно убедиться, что переключение выполнено корректно.

Практические рекомендации

  • Всегда сохранять оригинальный handle, чтобы можно было вернуться к исходной вкладке.
  • Использовать явные ожидания (ExpectedConditions) при переходе на новые окна.
  • Для динамически создаваемых вкладок проверять их заголовок или URL перед выполнением действий.
  • Закрывать лишние окна по завершении работы, чтобы не нагружать браузер и избежать ошибок контекста.

Дополнительные возможности

  • Комбинирование с browser.switchTo().frame() позволяет работать с фреймами внутри отдельных вкладок.
  • Возможность интеграции с browser.getCurrentUrl() и browser.getTitle() для проверки правильного контекста перед взаимодействием с элементами.
  • Использование утилит для массового закрытия окон:
browser.getAllWindowHandles().then(handles => {
    handles.forEach(handle => {
        browser.switchTo().window(handle);
        browser.close();
    });
});

Этот подход полезен для очистки после завершения теста или восстановления исходного состояния браузера.

Переключение между окнами и вкладками является ключевым навыком при тестировании современных веб-приложений, особенно тех, которые активно используют модальные окна, всплывающие вкладки или внешние сервисы. Тщательное управление window handles и явные ожидания обеспечивают стабильность тестов и предотвращают ошибки взаимодействия с элементами.