Эта библиотека представляет собой макет XMLHttpRequest , который предоставляет простой интерфейс для имитации взаимодействия с XMLHttpRequest . Это полная замена XMLHttpRequest для ваших тестов.
Эта библиотека реализует интерфейс XMLHttpRequest и обрабатывает запросы и события, как указано в спецификации XMLHTTPRequest, без использования реальных сетевых запросов. Вы можете ответить на ложные запросы тремя способами:
Вы можете моделировать ответы, загружать прогресс, ошибки и другие взаимодействия с помощью методов ложного ответа. Они автоматически обрабатывают обработку более низкого уровня, такую как создание событий и изменение свойства readystate XMLHttpRequest .
MockXhrtimeout и таймауты запросаMockXhrMockXhrServerMockXhrServerMockXhrMockXhrMockXhrRequestnewMockXhr()newServer()XMLHttpRequestчерез npm (менеджер пакетов узла)
$ npm install mock-xmlhttprequest
import { newServer } from 'mock-xmlhttprequest' ;
import { functionToTest } from '../src/SomethingToTest' ;
// Adapt based on your testing framework. This example uses Mocha and Chai's syntax.
it ( 'should produce a success response' , async ( ) => {
const server = newServer ( {
get : [ '/my/url' , {
// status: 200 is the default
headers : { 'Content-Type' : 'application/json' } ,
body : '{ "message": "Success!" }' ,
} ] ,
} ) ;
try {
// Installs the server's XMLHttpRequest mock in the "global" context.
// After this, "new XMLHttpRequest()" creates a mock request to which the server replies.
server . install ( /* optional context; defaults to globalThis */ ) ;
// Do something that send()s an XMLHttpRequest to '/my/url' and returns a Promise
// that resolves to the parsed JSON response
const result = await functionToTest ( ) ;
assert . equal ( result . message , 'Success!' ) ;
} finally {
// Restore the original XMLHttpRequest
server . remove ( ) ;
}
} ) ; Макетный класс XMLHttpRequest — MockXhr . Он предоставляет тот же интерфейс, что и XMLHttpRequest , и представляет собой замену тестового кода, использующего XMLHttpRequest .
Есть два варианта управления поведением экземпляров MockXhr :
XMLHttpRequest . Используйте это, если вам нужен больший контроль над запросами без функций, предоставляемых макетным сервером. Класс MockXhrServer реализует макет сервера. Вы создаете MockXhrServer с помощью newServer . MockXhrServer автоматически отвечает на запросы MockXhr и упрощает написание тестов.
Базовая структура тестов, использующих MockXhrServer :
import { newServer } from 'mock-xmlhttprequest' ;
const server = newServer ( /* routes */ ) ;
try {
server . install ( /* optional context; defaults to globalThis */ ) ;
// Test your code that creates XMLHttpRequests
} finally {
// Reverts server.install() at the end of the test.
// Only do this after the test case has finished creating XMLHttpRequests.
server . remove ( ) ;
} Существует два подхода к тому, чтобы ваш код использовал класс MockXhr в качестве замены XMLHttpRequest . Это позволяет MockXhrServer отвечать на запросы:
install() , чтобы глобально заменить класс XMLHttpRequest серверным классом MockXhr . В конце тестового примера вызовите метод remove() чтобы восстановить исходное состояние.XMLHttpRequest , используйте класс MockXhr напрямую с одним из следующих свойств MockXhrServer :xhrFactory — это функция, создающая экземпляр MockXhr .MockXhr — это класс экземпляров, созданных xhrFactory . Этот код демонстрирует использование xhrFactory :
import { newServer } from 'mock-xmlhttprequest' ;
const server = newServer ( /* routes */ ) ;
const savedFactory = MyClass . xhrFactory ;
try {
MyClass . xhrFactory = server . xhrFactory ;
// Test code that creates XMLHttpRequests through MyClass.xhrFactory()
} finally {
// Only do this after the test case has finished creating XMLHttpRequests.
MyClass . xhrFactory = savedFactory ;
} Маршруты определяют, как MockXhrServer отвечает на запросы MockXhr . Они состоят из трех частей:
Когда вы отправляете запрос MockXhr , MockXhrServer находит первый маршрут, соответствующий методу и URL-адресу запроса. Затем он отвечает обработчиком запроса маршрута. Вы также можете установить обработчик запросов по умолчанию. Обработчики запросов определяются декларативно или программно.
По умолчанию, если для атрибута timeout запроса установлено ненулевое значение и MockXhrServer не отвечает на запрос, в конечном итоге время ожидания истекает.
Есть два способа добавить маршруты в MockXhrServer :
routes newServer .MockXhrServer , добавляющие маршруты. MockXhrServer записывает все полученные запросы MockXhr в журнал запросов. Используйте это для проверки запросов XMLHttpRequest , которые отправляет ваш код.
MockXhrServer может автоматически генерировать события выполнения запроса (загрузки) и ответа (загрузки). По умолчанию это отключено. Используйте поле progressRate чтобы включить это.
Вы также можете генерировать события прогресса, если отвечаете на запросы MockXhr программно с помощью обработчика запросов типа Function .
Ответы на запросы MockXhr асинхронны. Это воспроизводит то, как работает реальный запрос XMLHttpRequest . Поэтому вам, скорее всего, потребуется использовать поддержку асинхронного тестирования вашей тестовой среды. Например, соответствующая документация по тестовой среде Mocha находится здесь.
Перехватчик жизненного цикла onSend необходим для ответа на запросы MockXhr . Мок-сервер обрабатывает это автоматически. Другой вариант — напрямую использовать перехватчики жизненного цикла MockXhr . В обоих случаях перехватчик жизненного цикла onSend выполняется после того, как контекст выполнения, вызывающий XMLHttpRequest.send() , выполнен или очищен. Внутри эта библиотека использует немедленно разрешенное Promise для получения пустого стека вызовов.
MockXhr Существует несколько методов и свойств MockXhr для ответа на запросы. Эти методы допускают следующие взаимодействия:
Подробности см. в разделе «Методы ложного ответа».
timeout и таймауты запроса По умолчанию, если вы установите атрибут timeout XMLHttpRequest в своем коде, запросы MockXhr автоматически истечет по истечении указанного времени после указанной задержки. При этом генерируется событие timeout и отменяется запрос, как описано в спецификации.
Полагаясь на течение времени при проверке того, как ваш код обрабатывает таймауты, обычно тесты становятся хрупкими и их трудно отлаживать. Вместо этого вы можете программно запускать тайм-ауты с помощью setRequestTimeout() .
Отключите автоматические таймауты запросов с помощью одной из этих опций:
disableTimeout() на MockXhrServer . Это влияет на все экземпляры MockXhr , которые он обрабатывает.MockXhr.timeoutEnabled = false . Это статическое свойство класса MockXhr влияет на каждый его экземпляр.timeoutEnabled значение false на экземпляре MockXhr . Это влияет только на этот экземпляр.MockXhr Это альтернативный шаблон использования, который не использует MockXhrServer . Вместо этого вы напрямую используете хуки жизненного цикла MockXhr . Это требует больше кода, но у вас больше контроля над запросами MockXhr .
Обратите внимание, что вы также можете использовать перехватчики жизненного цикла MockXhr вместе с MockXhrServer если вам нужно только расширить макет сервера.
Пример:
import { newMockXhr } from 'mock-xmlhttprequest' ;
import { functionToTest } from '../src/SomethingToTest' ;
// Adapt based on your testing framework. This example uses Mocha and Chai's syntax.
it ( 'should produce a success response' , async ( ) => {
// Get a "local" MockXhr subclass
const MockXhr = newMockXhr ( ) ;
// Mock JSON response
MockXhr . onSend = ( request ) => {
const responseHeaders = { 'Content-Type' : 'application/json' } ;
const response = '{ "message": "Success!" }' ;
request . respond ( 200 , responseHeaders , response ) ;
} ;
try {
// Install in the global context so "new XMLHttpRequest()" creates MockXhr instances
global . XMLHttpRequest = MockXhr ;
// Do something that send()s an XMLHttpRequest to '/my/url' and returns a Promise
// that resolves to the parsed JSON response
const result = await functionToTest ( ) ;
assert . equal ( result . message , 'Success!' ) ;
} finally {
// Restore the original XMLHttpRequest
delete global . XMLHttpRequest ;
}
} ) ; MockXhrServer Этот класс представляет собой макетный сервер, который отвечает на запросы MockXhr на основе их URL-адреса и метода.
MockXhrServer MockXhrServer(routes)Аргументы:
routes : Объект с начальным набором маршрутов сервера. (необязательный) В большинстве случаев вам следует использовать newServer вместо этого конструктора напрямую.
Ключами объекта routes являются методы HTTP. Значения представляют собой массивы с двумя элементами: [url_matcher, request_handler] .
См. также Сопоставление URL-адресов запросов и Обработчик запросов.
Пример:
const handlerFn = ( request ) => { request . respond ( ) ; } ;
newServer ( {
get : [ '/get' , { status : 200 } ] ,
'my-method' : [ '/my-method' , { status : 201 } ] ,
post : [ '/post' , [ handlerFn , { status : 404 } ] ] ,
} ) ; install(context = globalThis)Аргументы:
context : если вы указываете значение, метод install устанавливает свойство XMLHttpRequest в этом контексте, а не в глобальном контексте. (необязательный) Устанавливает макет сервера MockXhr в глобальном контексте для замены класса XMLHttpRequest . Вернитесь с помощью функции удаления().
remove()Отменяет изменения, внесенные функцией install(). Позвоните сюда после тестов.
progressRate Если вы установите для progressRate number больше 0, сервер автоматически генерирует события выполнения запроса (загрузки) и ответа (загрузки). Каждое событие прогресса увеличивается на байты progressRate .
progressRate применяется только к обработчикам запросов типа object .
disableTimeout() и enableTimeout() Эти методы отключают или включают эффекты атрибута timeout MockXhr . См. «Атрибут timeout и тайм-ауты запроса».
Маршруты настраивают, как сервер отвечает на запросы MockXhr . Их три части описаны ниже.
Концепция маршрута во многом основана на платформе Express.
Разрешена любая string с допустимым методом HTTP-запроса. Допустимые методы включают стандартные методы, такие как GET , POST , PUT и DELETE , а также имена других методов. Имена стандартных методов нечувствительны к регистру.
Сопоставитель URL-адресов запроса может быть одним из следующих типов:
string (например '/my-url' ), точно соответствующая URL-адресу запроса.RegExp соответствующий URL-адресу запроса.Function , которая возвращает true если URL-адрес запроса совпадает. Функция получает URL-адрес в качестве аргумента. Обработчик запроса может быть одного из следующих типов:
object со свойствами ответа. Значения по умолчанию:
{ status: 200, headers: {}, body: null, statusText: 'OK' }
Function , которая напрямую вызывает методы ложного ответа. Функция получает в качестве аргумента экземпляр MockXhrRequest .
string со значением 'error' или 'timeout' . Это вызывает либо ошибку, либо тайм-аут соответственно.
Массив других типов обработчиков запросов, указанных выше. Первый запрос получает первый обработчик, второй — второй и так далее. Последний обработчик используется повторно, если в массиве больше нет обработчиков.
Для обработчиков запросов object сервер автоматически добавляет заголовок ответа Content-Length с длиной тела ответа.
Все эти обработчики эквивалентны:
const handlerObj = { } ;
const handlerFn = ( request ) => { request . respond ( 200 , { 'Content-Length' : '0' } ) ; } ;
const handlerArray = [ { } ] ; get(urlMatcher, handler)Аргументы:
urlMatcher : запросить сопоставление URL-адресов.handler : обработчик запроса. Добавляет маршрут для HTTP-метода GET .
post(urlMatcher, handler)Аргументы:
urlMatcher : запросить сопоставление URL-адресов.handler : обработчик запроса. Добавляет маршрут для метода POST HTTP.
put(urlMatcher, handler)Аргументы:
urlMatcher : запросить сопоставление URL-адресов.handler : обработчик запроса. Добавляет маршрут для HTTP-метода PUT .
delete(urlMatcher, handler)Аргументы:
urlMatcher : запросить сопоставление URL-адресов.handler : обработчик запроса. Добавляет маршрут для HTTP-метода DELETE .
addHandler(method, urlMatcher, handler)Аргументы:
method : метод HTTP в виде string .urlMatcher : запросить сопоставление URL-адресов.handler : обработчик запроса. Добавляет маршрут для method HTTP.
setDefaultHandler(handler)Аргументы:
handler : обработчик запроса.Устанавливает обработчик запросов по умолчанию для запросов, которые не соответствуют ни одному маршруту.
setDefault404()Устанавливает обработчик запросов по умолчанию, который возвращает ответы 404.
xhrFactory Функция, возвращающая новый экземпляр MockXhr .
MockXhr Класс MockXhr , к которому подключается сервер. xhrFactory создает экземпляры этого класса.
getRequestLog()Возвращает массив всех запросов, полученных сервером на данный момент. Каждый вызов возвращает новый массив. Каждый элемент массива представляет собой объект со следующими свойствами:
method : string метода HTTP.url : string URL.body : тело запросаheaders : заголовки запроса как объект. Имена заголовков пишутся строчными буквами.MockXhr Этот класс является макетом XMLHttpRequest . В этом разделе описаны его методы и свойства, которых нет в спецификации.
MockXhr.timeoutEnabled Это статическое boolean свойство управляет автоматическим тайм-аутом запросов от всех экземпляров класса.
timeoutEnabled Это boolean свойство управляет автоматическим тайм-аутом этого экземпляра MockXhr .
getResponseHeadersHash()Возвращает все заголовки ответов в виде объекта. Имена заголовков пишутся строчными буквами.
MockXhr Вы можете определить методы обратного вызова для перехватчиков жизненного цикла MockXhr в следующих местах:
MockXhr . Этот хук применяется ко всем экземплярам MockXhr и его подклассам.MockXhr , возвращаемое MockXhrServer.MockXhr или newMockXhr() . Хук применяется ко всем экземплярам этого класса.MockXhr . Хук применяется только к этому экземпляру.Если вы определяете несколько перехватчиков для события жизненного цикла, они вызываются в указанном выше порядке.
Обычно вам следует предпочесть третий вариант, который упрощает изоляцию тестовых случаев.
onCreateМетод обратного вызова, который получает эти аргументы:
xhr : новый экземпляр MockXhr . Используйте этот крючок жизненного цикла для перехвата экземпляров MockXhr при их создании.
Вызывается при создании экземпляра MockXhr в конце его конструктора. Поэтому этот крючок жизненного цикла доступен только как статическое свойство.
import { MockXhr , newMockXhr } from 'mock-xmlhttprequest' ;
// Called for all instances of MockXhr and all its subclasses
MockXhr . onCreate = ( xhr ) => { /*...*/ } ;
// Called for all instances of this MockXhr subclass
const MockXhrSubclass = newMockXhr ( ) ;
MockXhrSubclass . onCreate = ( xhr ) => { /*...*/ } ; onSendМетод обратного вызова, который получает эти аргументы:
request : MockXhrRequest для запроса.xhr : Экземпляр MockXhr .Используйте этот крючок жизненного цикла, чтобы ответить на запрос с помощью методов ложного ответа.
Вызывается асинхронно после каждого вызова send() . Каждый вызов send() генерирует вызов onSend с отдельным экземпляром MockXhrRequest .
import { MockXhr , newMockXhr } from 'mock-xmlhttprequest' ;
// Called for all instances of MockXhr and all its subclasses
MockXhr . onSend = ( request ) => { /*...*/ } ;
// Called for all instances of this MockXhr subclass
const MockXhrSubclass = newMockXhr ( ) ;
MockXhrSubclass . onSend = ( request ) => { /*...*/ } ;
// Called for this instance only
const xhr = new MockXhrSubclass ( ) ;
xhr . onSend = ( request ) => { /*...*/ } ;MockXhrRequest Каждый вызов send() создает MockXhrRequest , который содержит информацию о XMLHttpRequest и предоставляет методы для программного ответа.
requestHeaders HeadersContainer , содержащий копию заголовков запроса.
method string с HTTP-методом запроса.
url string с URL-адресом запроса.
bodyТело запроса.
withCredentials boolean со значением запроса withCredentials .
getRequestBodySize() number байтов в теле запроса.
Примечание. Это не совсем точно, если body представляет собой FormData закодированную в multipart/form-data . Заголовки, кодировка и другие факторы, влияющие на истинный размер body XMLHttpRequest без имитации, не учитываются. Вы можете использовать этот метод, чтобы получить минимальное значение истинного размера body запроса. Это полезно для моделирования событий процесса загрузки.
Эти методы предоставляют программный интерфейс для ответа на запросы MockXhr .
Если вызов метода ответа недействителен, он выдает Error с сообщением, содержащим "Mock usage error detected" .
uploadProgress(transmitted)Аргументы:
transmitted : number переданных байтов.Запускает ход загрузки запроса.
Вы можете вызвать это только в том случае, если body запроса не null и загрузка не завершена.
После вызова этого метода вы можете использовать любой другой метод ложного ответа.
respond(status = 200, headers = {}, body = null, statusText = 'OK')Аргументы:
status : number статуса HTTP ответа. (необязательный)headers : object с заголовками ответов. (необязательный)body : Тело ответа. (необязательный)statusText : текст HTTP-статуса string ответа. (необязательный) Полный метод ответа, который устанавливает как заголовки, так и тело ответа. Изменяет readyState запроса на DONE .
Вызывает соответствующие события, такие как readystatechange , progress и load .
Это сокращение для setResponseHeaders() за которым следует setResponseBody() .
После вызова этого метода вы не сможете использовать другие методы ложного ответа. Это ограничение снимается, если вы снова вызываете open() .
setResponseHeaders(status = 200, headers = {}, statusText = 'OK')Аргументы:
status : number статуса HTTP ответа. (необязательный)headers : object с заголовками ответов. (необязательный)statusText : текст статуса HTTP- string . (необязательный) Устанавливает заголовки ответа. Изменяет readyState запроса на HEADERS_RECEIVED .
Вызывает соответствующие события, такие как readystatechange , progress и load .
После вызова этого метода вы можете использовать следующие методы ложного ответа:
downloadProgress()setResponseBody()setNetworkError()setRequestTimeout() . downloadProgress(transmitted, length)Аргументы:
transmitted : number переданных байтов.length : number байтов в ответе. Вызывает событие хода ответа. Изменяет readyState запроса на LOADING , если он HEADERS_RECEIVED .
Перед этим методом вы должны вызвать setResponseHeaders() .
setResponseBody(body = null)Аргументы:
body : Тело ответа. (необязательный) Устанавливает тело ответа. Изменяет readyState запроса на DONE .
Вызывает соответствующие события, такие как readystatechange , progress и load .
Вызывает setResponseHeaders() если он еще не был вызван. Заголовки ответа тогда содержат только Content-Length со значением, равным длине тела ответа.
После вызова этого метода вы не сможете использовать другие методы ложного ответа. Это ограничение снимается, если вы снова вызываете open() .
setNetworkError() Имитирует сетевую ошибку. Изменяет readyState запроса на DONE .
Вызывает соответствующие события, включая событие error .
После вызова этого метода вы не сможете использовать другие методы ложного ответа. Это ограничение снимается, если вы снова вызываете open() .
setRequestTimeout() Имитирует тайм-аут запроса. Изменяет readyState запроса на DONE .
Вызывает соответствующие события, включая событие timeout .
Выдает ошибку, если атрибут request равен 0, поскольку в этом случае тайм-ауты не возникают.
После вызова этого метода вы не сможете использовать другие методы ложного ответа. Это ограничение снимается, если вы снова вызываете open() .
newMockXhr() Возвращает новый подкласс MockXhr .
Если вы используете разные подклассы MockXhr в каждом тестовом примере, легче обеспечить их автономность. Например, если вы установите статическое свойство timeoutEnabled для подкласса, оно повлияет только на этот подкласс, а не на другие подклассы, созданные в других тестовых примерах. Поскольку подклассы не используются повторно, код очистки, который возвращает изменения, внесенные в подкласс, не требуется.
newServer(routes)Аргументы:
routes : Объект с начальным набором маршрутов сервера. (необязательный) Возвращает новый MockXhrServer со своим уникальным подклассом MockXhr . См newMockXhr() .
Добавьте маршруты в MockXhrServer с необязательным аргументом routes . Подробности смотрите в конструкторе.
XMLHttpRequestНа основе версии спецификации XMLHTTPRequest от 15 августа 2022 г.
open() , setRequestHeader() , send() и abort() .statusText , заголовки и тело.timeout (можно отключить).MockXhr.setNetworkError() ).MockXhr.setRequestTimeout() ).overrideMimeType() вызывается, когда это необходимо, но не имеет другого эффекта.responseType : '' , 'text' и 'json' полностью поддерживаются. Значения responseType не влияют на тело ответа, передаваемое в setResponseBody() .responseXml : тело ответа не преобразуется в ответ документа. Чтобы получить ответ документа, передайте его непосредственно в качестве тела ответа в setResponseBody() .responseUrl : конечный URL-адрес запроса после перенаправления не устанавливается автоматически. Это можно эмулировать в обработчике запроса.async установлено значение false в open() ).open() и выдача SyntaxError в случае сбоя. Авторы приветствуются! См. это руководство для получения дополнительной информации.
Массачусетский технологический институт