該函式庫是XMLHttpRequest
的模擬,它提供了一個簡單的介面來模擬與XMLHttpRequest
互動。它是用於測試的XMLHttpRequest
的直接替代品。
該庫實作了XMLHttpRequest
接口,並按照 XMLHTTPRequest 規範中指定的方式處理請求和事件,而無需使用實際的網路請求。您可以透過三種方式回應模擬請求:
您可以使用模擬回應方法來模擬回應、上傳進度、錯誤和其他互動。它們會自動處理較低層級的處理,例如發出事件和更改XMLHttpRequest
的readystate
屬性。
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
類別實作模擬伺服器。您使用newServer
建立一個MockXhrServer
。 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
:
newServer
的routes
參數。MockXhrServer
方法。 MockXhrServer
在請求日誌中記錄它收到的所有MockXhr
請求。使用它來驗證您的程式碼發送的XMLHttpRequest
請求。
MockXhrServer
可以自動產生請求(上傳)和回應(下載)進度事件。預設情況下停用此功能。使用progressRate
欄位來啟用此功能。
如果您使用Function
類型的請求處理程序以程式設計方式回應MockXhr
請求,您也可以產生進度事件。
對MockXhr
請求的回應是異步的。這再現了真實的XMLHttpRequest
請求的工作方式。因此,您很可能需要使用測試框架的非同步測試支援。例如Mocha測試框架的相關文件在這裡。
onSend
生命週期鉤子是回應MockXhr
請求所必需的。模擬伺服器會自動處理這個問題。另一個選擇是直接使用MockXhr
生命週期掛鉤。在這兩種情況下, onSend
生命週期掛鉤都會在呼叫XMLHttpRequest.send()
執行上下文完成或清除後執行。在內部,該函式庫使用立即解析的Promise
來取得空的呼叫堆疊。
MockXhr
請求有幾種MockXhr
方法和屬性可以回應請求。這些方法允許以下互動:
有關詳細信息,請參閱模擬響應方法部分。
timeout
屬性和請求超時預設情況下,如果您在程式碼中設定XMLHttpRequest
的timeout
屬性, MockXhr
請求會在指定的延遲後自動逾時。這會發出timeout
事件並取消請求,如規範中所述。
依靠時間的推移來測試程式碼如何處理超時通常會使測試變得脆弱且難以調試。您可以使用setRequestTimeout()
以程式方式觸發逾時。
使用以下選項之一停用自動請求逾時:
MockXhrServer
上呼叫disableTimeout()
。這會影響它處理的所有MockXhr
實例。MockXhr.timeoutEnabled = false
。 MockXhr
類別的這個靜態屬性會影響它的每個實例。MockXhr
實例上將timeoutEnabled
設定為false
。這僅影響該實例。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
類此類是一個模擬伺服器,它根據 URL 和方法回應MockXhr
請求。
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() 恢復。
remove()
恢復由 install() 所做的變更。測試後呼叫此方法。
progressRate
如果將progressRate
設定為大於0的number
,伺服器會自動產生請求(上傳)和回應(下載)進度事件。每個進度事件都以progressRate
位元組遞增。
progressRate
僅適用於object
類型的請求處理程序。
disableTimeout()
和enableTimeout()
這些方法會停用或啟用MockXhr
的timeout
屬性的效果。請參閱“ timeout
屬性和請求逾時”。
路由配置伺服器如何回應MockXhr
請求。以下分別介紹它們的三個部分。
路線概念鬆散地基於 Express 框架。
允許任何具有有效 HTTP 請求方法的string
。有效方法包括標準方法,例如GET
、 POST
、 PUT
和DELETE
,以及其他方法名稱。標準方法名稱不區分大小寫。
請求 URL 匹配器可以是以下類型之一:
string
(例如'/my-url'
)。RegExp
。true
的Function
。此函數接收 URL 作為參數。 請求處理程序可以是以下類型之一:
具有響應屬性的object
。預設值為:
{ status: 200, headers: {}, body: null, statusText: 'OK' }
直接呼叫模擬響應方法的Function
。此函數接收MockXhrRequest
實例作為參數。
值為'error'
或'timeout'
的string
。這將分別觸發錯誤或超時。
上述其他請求處理程序類型的陣列。第一個請求取得第一個處理程序,第二個請求取得第二個處理程序,依此類推。當陣列中沒有其他處理程序時,將重複使用最後一個處理程序。
對於object
請求處理程序,伺服器會自動新增Content-Length
回應標頭和回應正文的長度。
所有這些處理程序都是等效的:
const handlerObj = { } ;
const handlerFn = ( request ) => { request . respond ( 200 , { 'Content-Length' : '0' } ) ; } ;
const handlerArray = [ { } ] ;
get(urlMatcher, handler)
論點:
urlMatcher
:請求 URL 匹配器。handler
:請求處理程序。新增GET
HTTP 方法的路由。
post(urlMatcher, handler)
論點:
urlMatcher
:請求 URL 匹配器。handler
:請求處理程序。新增POST
HTTP 方法的路由。
put(urlMatcher, handler)
論點:
urlMatcher
:請求 URL 匹配器。handler
:請求處理程序。新增PUT
HTTP 方法的路由。
delete(urlMatcher, handler)
論點:
urlMatcher
:請求 URL 匹配器。handler
:請求處理程序。新增DELETE
HTTP 方法的路由。
addHandler(method, urlMatcher, handler)
論點:
method
:作為string
HTTP 方法。urlMatcher
:請求 URL 匹配器。handler
:請求處理程序。新增method
HTTP 方法的路由。
setDefaultHandler(handler)
論點:
handler
:請求處理程序。為不符合任何路由的請求設定預設請求處理程序。
setDefault404()
設定返回 404 回應的預設請求處理程序。
xhrFactory
傳回新MockXhr
實例的函數。
MockXhr
伺服器掛鉤的MockXhr
類別。 xhrFactory
建立此類別的實例。
getRequestLog()
傳回迄今為止伺服器收到的所有請求的陣列。每次呼叫都會傳回一個新數組。每個數組元素都是一個具有以下屬性的物件:
method
:HTTP 方法string
。url
:URL string
。body
:請求正文headers
:請求標頭作為物件。標頭名稱為小寫。MockXhr
類此類別是XMLHttpRequest
的模擬。本節記錄了規範中未包含的方法和屬性。
MockXhr.timeoutEnabled
此靜態boolean
屬性控制來自類別的所有實例的請求的自動逾時。
timeoutEnabled
此boolean
屬性控制此MockXhr
實例的自動逾時。
getResponseHeadersHash()
將所有響應標頭作為物件傳回。標頭名稱為小寫。
MockXhr
生命週期掛鉤您可以在以下位置為MockXhr
生命週期掛鉤定義回呼方法:
MockXhr
類別的靜態屬性。此鉤子適用於MockXhr
及其子類別的所有實例。MockXhrServer.MockXhr
或newMockXhr()
傳回的MockXhr
子類別的靜態屬性。該鉤子適用於該類別的所有實例。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
包含請求的 HTTP 方法的string
。
url
包含請求 URL 的string
。
body
請求的正文。
withCredentials
具有請求的withCredentials
值的boolean
。
getRequestBodySize()
請求正文中的位元組number
。
注意:當body
是multipart/form-data
編碼的FormData
時,這並不完全準確。不考慮標頭、編碼和其他影響非模擬XMLHttpRequest
真實body
大小的因素。您可以使用此方法取得請求的真實body
大小的下限值。這對於模擬上傳進度事件很有用。
這些方法提供了一個程式介面來回應MockXhr
請求。
如果對回應方法的呼叫無效,則會拋出Error
並"Mock usage error detected"
的訊息。
uploadProgress(transmitted)
論點:
transmitted
:傳輸的位元組number
。觸發請求上傳進度。
僅當請求body
不為null
且上傳未完成時才能呼叫此方法。
呼叫此方法後,您可以使用任何其他模擬響應方法。
respond(status = 200, headers = {}, body = null, statusText = 'OK')
論點:
status
:回應HTTP狀態number
。 (選修的)headers
:有回應頭的object
。 (選修的)body
:響應主體。 (選修的)statusText
: string
回應 HTTP 狀態文字。 (選修的)設定回應標頭和正文的完整回應方法。將請求的readyState
更改為DONE
。
觸發適當的事件,例如readystatechange
、 progress
和load
。
這是setResponseHeaders()
後面跟著setResponseBody()
的簡寫。
呼叫此方法後,您將無法使用其他模擬回應方法。如果您再次呼叫open()
則此限制將被解除。
setResponseHeaders(status = 200, headers = {}, statusText = 'OK')
論點:
status
:回應HTTP狀態number
。 (選修的)headers
:有回應頭的object
。 (選修的)statusText
: string
回應 HTTP 狀態文字。 (選修的)設定響應標頭。將請求的readyState
更改為HEADERS_RECEIVED
。
觸發適當的事件,例如readystatechange
、 progress
和load
。
呼叫該方法後,您可以使用以下模擬響應方法:
downloadProgress()
setResponseBody()
setNetworkError()
setRequestTimeout()
。 downloadProgress(transmitted, length)
論點:
transmitted
:傳輸的位元組number
。length
:回應中的位元組number
。觸發響應進度事件。如果請求的readyState
為HEADERS_RECEIVED
,則將其變更為LOADING
。
您必須在此方法之前呼叫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()
。
使用可選的routes
參數將路由新增至MockXhrServer
。有關詳細信息,請參閱構造函數。
XMLHttpRequest
特性基於 XMLHTTPRequest 規範版本「2022 年 8 月 15 日」。
open()
、 setRequestHeader()
、 send()
和abort()
。statusText
、標頭和正文。timeout
屬性(可以停用)。MockXhr.setNetworkError()
)。MockXhr.setRequestTimeout()
)。overrideMimeType()
在需要時拋出,但沒有其他效果。responseType
:完全支援''
、 'text'
和'json'
。 responseType
值對傳遞給setResponseBody()
的回應正文沒有影響。responseXml
:回應正文不會轉換為文件回應。若要取得文件回應,請將其直接作為setResponseBody()
中的回應正文傳遞。responseUrl
:重定向後的最終請求 URL 不會自動設定。這可以在請求處理程序中模擬。async
在open()
中設定為false
)。open()
中解析請求 URL 並在失敗時拋出SyntaxError
。 歡迎貢獻者!請參閱本指南以了解更多資訊。
麻省理工學院