Перейти к основному содержанию

Сервис перехвата

wdio-intercept-service - это сторонний пакет, для получения дополнительной информации посетите GitHub | npm

🕸 Перехват и проверка HTTP ajax-вызовов в webdriver.io

Tests Join the chat on Discord

Это плагин для webdriver.io. Если вы еще не знакомы с ним, попробуйте - это действительно круто.

Хотя selenium и webdriver используются для e2e и особенно для UI-тестирования, вам может понадобиться оценить HTTP-запросы, выполняемые вашим клиентским кодом (например, когда у вас нет немедленной обратной связи в интерфейсе, как в метриках или запросах трекинга). С wdio-intercept-service вы можете перехватывать ajax HTTP-вызовы, инициированные какими-либо действиями пользователя (например, нажатием кнопки и т.д.), и делать утверждения о запросе и соответствующих ответах позже.

Есть одно ограничение: вы не можете перехватывать HTTP-вызовы, которые инициируются при загрузке страницы (как в большинстве SPA), поскольку для этого требуется некоторая настройка, которую можно выполнить только после загрузки страницы (из-за ограничений в selenium). Это означает, что вы можете перехватывать только запросы, которые были инициированы внутри теста. Если вас это устраивает, этот плагин может вам подойти, так что читайте дальше.

Требования​

  • webdriver.io v5.x или новее.

Внимание! Если вы все еще используете webdriver.io v4, пожалуйста, используйте ветку v2.x этого плагина!

Установка​

npm install wdio-intercept-service -D

Использование​

Использование с WebDriver CLI​

Достаточно просто добавить wdio-intercept-service в ваш wdio.conf.js:

exports.config = {
// ...
services: ['intercept']
// ...
};

и все готово.

Использование с WebDriver Standalone​

При использовании WebdriverIO Standalone, функции before и beforeTest / beforeScenario должны вызываться вручную.

import { remote } from 'webdriverio';
import WebdriverAjax from 'wdio-intercept-service'

const WDIO_OPTIONS = {
port: 9515,
path: '/',
capabilities: {
browserName: 'chrome'
},
}

let browser;
const interceptServiceLauncher = WebdriverAjax();

beforeAll(async () => {
browser = await remote(WDIO_OPTIONS)
interceptServiceLauncher.before(null, null, browser)
})

beforeEach(async () => {
interceptServiceLauncher.beforeTest()
})

afterAll(async () => {
await client.deleteSession()
});

describe('', async () => {
... // См. пример использования
});

После инициализации, в вашу цепочку команд браузера добавляются соответствующие функции (см. API).

Быстрый старт​

Пример использования:

browser.url('http://foo.bar');
browser.setupInterceptor(); // захват ajax-вызовов
browser.expectRequest('GET', '/api/foo', 200); // ожидаем GET запрос к /api/foo со статусом 200
browser.expectRequest('POST', '/api/foo', 400); // ожидаем POST запрос к /api/foo со статусом 400
browser.expectRequest('GET', /\/api\/foo/, 200); // можно проверять URL с помощью регулярного выражения
browser.click('#button'); // кнопка, которая инициирует ajax-запрос
browser.pause(1000); // возможно, подождать немного, пока запрос завершится
browser.assertRequests(); // проверить запросы

Получение подробной информации о запросах:

browser.url('http://foo.bar')
browser.setupInterceptor();
browser.click('#button')
browser.pause(1000);

var request = browser.getRequest(0);
assert.equal(request.method, 'GET');
assert.equal(request.response.headers['content-length'], '42');

Поддерживаемые браузеры​

Должно работать с более-менее новыми версиями всех браузеров. Пожалуйста, сообщайте о проблемах, если это не работает с вашим браузером.

API​

Ознакомьтесь с файлом объявлений TypeScript для полного синтаксиса пользовательских команд, добавляемых к объекту браузера WebdriverIO. В общем, любой метод, который принимает объект "options" в качестве параметра, может быть вызван без этого параметра для получения поведения по умолчанию. Эти "необязательные объекты options" обозначены ?: = {}, и для каждого метода описаны значения по умолчанию.

Описание опций​

Эта библиотека предлагает небольшую настройку при выполнении команд. Параметры конфигурации, используемые несколькими методами, описаны здесь (см. определение каждого метода для определения конкретной поддержки).

  • orderBy ('START' | 'END'): Эта опция управляет порядком запросов, перехваченных перехватчиком, при возврате в ваш тест. Для обратной совместимости с существующими версиями этой библиотеки, порядок по умолчанию - 'END', что соответствует времени завершения запроса. Если вы установите опцию orderBy в 'START', то запросы будут упорядочены в соответствии со временем их начала.
  • includePending (boolean): Эта опция управляет тем, будут ли возвращаться еще не завершенные запросы. Для обратной совместимости с существующими версиями этой библиотеки, значение по умолчанию - false, и будут возвращаться только завершенные запросы.

browser.setupInterceptor()​

Перехватывает ajax-вызовы в браузере. Вы всегда должны вызывать функцию настройки, чтобы иметь возможность оценивать запросы позже.

browser.disableInterceptor()​

Предотвращает дальнейший захват ajax-вызовов в браузере. Вся информация о перехваченных запросах удаляется. Большинству пользователей не понадобится отключать перехватчик, но если тест особенно длительный или превышает емкость хранилища сессии, отключение перехватчика может быть полезным.

browser.excludeUrls(urlRegexes: (string | RegExp)[])​

Исключает запросы с определенных URL из записи. Принимает массив строк или регулярных выражений. Перед записью в хранилище тестирует URL запроса на соответствие каждой строке или регулярному выражению. Если соответствие найдено, запрос не записывается в хранилище. Как и disableInterceptor, это может быть полезно при возникновении проблем с превышением емкости хранилища сессии.

browser.expectRequest(method: string, url: string, statusCode: number)​

Создает ожидания относительно ajax-запросов, которые будут инициированы во время теста. Может (и должен) быть объединен в цепочку. Порядок ожиданий должен соответствовать порядку выполнения запросов.

  • method (String): http-метод, который ожидается. Может быть любым значением, которое xhr.open() принимает в качестве первого аргумента.
  • url (String|RegExp): точный URL, который вызывается в запросе в виде строки или RegExp для сопоставления
  • statusCode (Number): ожидаемый код состояния ответа

browser.getExpectations()​

Вспомогательный метод. Возвращает все ожидания, которые вы создали до этого момента

browser.resetExpectations()​

Вспомогательный метод. Сбрасывает все ожидания, которые вы создали до этого момента

browser.assertRequests({ orderBy?: 'START' | 'END' }?: = {})​

Вызывайте этот метод, когда все ожидаемые ajax-запросы завершены. Он сравнивает ожидания с фактически выполненными запросами и проверяет следующее:

  • Количество выполненных запросов
  • Порядок запросов
  • Метод, URL и статус-код должны соответствовать для каждого выполненного запроса
  • Объект опций по умолчанию - { orderBy: 'END' }, т.е. когда запросы были завершены, чтобы соответствовать поведению версии v4.1.10 и ранее. Когда опция orderBy установлена в 'START', запросы будут упорядочены по времени их инициации страницей.

browser.assertExpectedRequestsOnly({ inOrder?: boolean, orderBy?: 'START' | 'END' }?: = {})​

Аналогично browser.assertRequests, но проверяет только те запросы, которые вы указали в ваших директивах expectRequest, без необходимости описывать все сетевые запросы, которые могут происходить вокруг этого. Если опция inOrder равна true (по умолчанию), ожидается, что запросы будут найдены в том же порядке, в котором они были настроены с помощью expectRequest.

browser.getRequest(index: number, { includePending?: boolean, orderBy?: 'START' | 'END' }?: = {})​

Для более сложных утверждений о конкретном запросе вы можете получить подробную информацию для определенного запроса. Вы должны указать 0-based индекс запроса, к которому хотите получить доступ, в порядке, в котором запросы были завершены (по умолчанию) или инициированы (передав опцию orderBy: 'START').

  • index (number): номер запроса, к которому вы хотите получить доступ
  • options (object): Параметры конфигурации
  • options.includePending (boolean): Должны ли возвращаться еще не завершенные запросы. По умолчанию это false, чтобы соответствовать поведению библиотеки в версии v4.1.10 и ранее.
  • options.orderBy ('START' | 'END'): Как следует упорядочивать запросы. По умолчанию это 'END', чтобы соответствовать поведению библиотеки в версии v4.1.10 и ранее. Если 'START', запросы будут упорядочены по времени инициации, а не по времени завершения запроса. (Поскольку ожидающий запрос еще не завершен, при упорядочивании по 'END' все ожидающие запросы будут идти после всех завершенных запросов.)

Возвращает объект request:

  • request.url: запрошенный URL
  • request.method: используемый HTTP-метод
  • request.body: данные payload/body, использованные в запросе
  • request.headers: http-заголовки запроса в виде JS-объекта
  • request.pending: логический флаг, указывающий, завершен ли этот запрос (т.е. имеет свойство response) или находится в процессе выполнения.
  • request.response: JS-объект, который присутствует только если запрос завершен (т.е. request.pending === false), содержащий данные об ответе.
  • request.response?.headers: http-заголовки ответа в виде JS-объекта
  • request.response?.body: тело ответа (будет преобразовано в JSON, если возможно)
  • request.response?.statusCode: код состояния ответа

Примечание о request.body: wdio-intercept-service попытается разобрать тело запроса следующим образом:

  • string: Просто возвращает строку ('value')
  • JSON: Разбирает JSON-объект с использованием JSON.parse() (({ key: value }))
  • FormData: Выводит FormData в формате { key: [value1, value2, ...] }
  • ArrayBuffer: Попытается преобразовать буфер в строку (экспериментально)
  • Что-либо еще: Будет использовать жесткий JSON.stringify() на ваших данных. Удачи!

Для API fetch мы поддерживаем только строковые и JSON-данные!

browser.getRequests({ includePending?: boolean, orderBy?: 'START' | 'END' }?: = {})​

Получить все перехваченные запросы в виде массива, поддерживая те же необязательные опции, что и getRequest.

Возвращает массив объектов request.

browser.hasPendingRequests()​

Утилитарный метод, который проверяет, ожидают ли еще какие-либо HTTP-запросы. Может использоваться тестами для обеспечения завершения всех запросов в разумные сроки или для проверки того, что вызов getRequests() или assertRequests() будет включать все желаемые HTTP-запросы.

Возвращает boolean

Поддержка TypeScript​

Этот плагин предоставляет свои собственные TS-типы. Просто укажите в вашем tsconfig на расширения типов, как упомянуто здесь:

"compilerOptions": {
// ..
"types": ["node", "webdriverio", "wdio-intercept-service"]
},

Запуск тестов​

Для локального запуска тестов требуются последние версии Chrome и Firefox. Возможно, вам потребуется обновить зависимости chromedriver и geckodriver, чтобы они соответствовали версии, установленной в вашей системе.

npm test

Внесение вклада​

Я рад любому вкладу. Просто откройте issue или напрямую отправьте PR.
Обратите внимание, что эта библиотека перехватчика написана для работы с устаревшими браузерами, такими как Internet Explorer. Таким образом, любой код, используемый в lib/interceptor.js, должен быть по крайней мере обрабатываемым средой выполнения JavaScript Internet Explorer.

Лицензия​

MIT

Welcome! How can I help?

WebdriverIO AI Copilot