Эта библиотека представляет собой макет XMLHttpRequest
, который предоставляет простой интерфейс для имитации взаимодействия с XMLHttpRequest
. Это полная замена XMLHttpRequest
для ваших тестов.
Эта библиотека реализует интерфейс XMLHttpRequest
и обрабатывает запросы и события, как указано в спецификации XMLHTTPRequest, без использования реальных сетевых запросов. Вы можете ответить на ложные запросы тремя способами:
Вы можете моделировать ответы, загружать прогресс, ошибки и другие взаимодействия с помощью методов ложного ответа. Они автоматически обрабатывают обработку более низкого уровня, такую как создание событий и изменение свойства readystate
XMLHttpRequest
.
MockXhr
timeout
и таймауты запросаMockXhr
MockXhrServer
MockXhrServer
MockXhr
MockXhr
MockXhrRequest
newMockXhr()
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
в случае сбоя. Авторы приветствуются! См. это руководство для получения дополнительной информации.
Массачусетский технологический институт