Сервис перехвата
wdio-intercept-service - это сторонний пакет, для получения дополнительной информации посетите GitHub | npm
🕸 Перехват и проверка HTTP ajax-вызовов в webdriver.io
Это плагин для 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
: запрошенный URLrequest.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