Cette bibliothèque est une simulation de XMLHttpRequest
qui fournit une interface simple pour simuler les interactions avec XMLHttpRequest
. Il s'agit d'un remplacement immédiat de XMLHttpRequest
pour vos tests.
Cette bibliothèque implémente l'interface XMLHttpRequest
et gère les requêtes et les événements comme spécifié dans la spécification XMLHTTPRequest sans utiliser de requêtes réseau réelles. Vous pouvez répondre aux demandes fictives de trois manières :
Vous pouvez simuler des réponses, télécharger des progrès, des erreurs et d'autres interactions avec les méthodes de réponse fictive. Ceux-ci gèrent automatiquement le traitement de niveau inférieur tel que l'émission d'événements et la modification de la propriété readystate
de XMLHttpRequest
.
MockXhr
par programmationtimeout
et les délais d'attente des demandesMockXhr
MockXhrServer
MockXhrServer
MockXhr
MockXhr
MockXhrRequest
newMockXhr()
newServer()
XMLHttpRequest
via npm (gestionnaire de packages de nœuds)
$ 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 ( ) ;
}
} ) ;
La classe fictive XMLHttpRequest
est MockXhr
. Il expose la même interface que XMLHttpRequest
et constitue un remplacement instantané pour tester le code qui utilise XMLHttpRequest
.
Il existe deux options pour contrôler le comportement des instances MockXhr
:
XMLHttpRequest
. Utilisez-le si vous avez besoin de plus de contrôle sur les requêtes sans les fonctionnalités fournies par le serveur fictif. La classe MockXhrServer
implémente le serveur fictif. Vous créez un MockXhrServer
avec newServer
. Le MockXhrServer
répond automatiquement aux requêtes MockXhr
et facilite l'écriture des tests.
La structure de base des tests qui utilisent MockXhrServer
est :
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 ( ) ;
}
Il existe deux approches pour que votre code utilise la classe MockXhr
en remplacement de XMLHttpRequest
. Cela permet au MockXhrServer
de répondre aux requêtes :
install()
pour remplacer globalement la classe XMLHttpRequest
par la classe MockXhr
du serveur. À la fin du scénario de test, appelez remove()
pour restaurer l'état d'origine.XMLHttpRequest
, utilisez la classe MockXhr
directement avec l'une des propriétés MockXhrServer
suivantes :xhrFactory
est une fonction qui crée une instance MockXhr
.MockXhr
est la classe des instances créées par xhrFactory
. Ce code démontre l'utilisation de 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 ;
}
Les routes définissent la manière dont le MockXhrServer
répond aux requêtes MockXhr
. Ceux-ci comportent trois parties :
Lorsque vous envoyez une requête MockXhr
, le MockXhrServer
trouve la première route qui correspond à la méthode et à l'URL de la requête. Il répond ensuite avec le gestionnaire de requêtes de la route. Vous pouvez également définir un gestionnaire de requêtes par défaut. Les gestionnaires de requêtes sont définis de manière déclarative ou par programme.
Par défaut, si l'attribut timeout
d'une requête est défini sur une valeur non nulle et que MockXhrServer
ne répond pas à la requête, il finit par expirer.
Il existe deux manières d'ajouter des routes au MockXhrServer
:
routes
du newServer
.MockXhrServer
qui ajoutent des routes. Le MockXhrServer
enregistre toutes les requêtes MockXhr
qu'il reçoit dans un journal des requêtes. Utilisez-le pour valider les requêtes XMLHttpRequest
envoyées par votre code.
Le MockXhrServer
peut générer automatiquement des événements de progression de demande (téléchargement) et de réponse (téléchargement). Ceci est désactivé par défaut. Utilisez le champ progressRate
pour activer cela.
Vous pouvez également générer des événements de progression si vous répondez aux requêtes MockXhr
par programme avec un gestionnaire de requêtes de type Function
.
Les réponses aux requêtes MockXhr
sont asynchrones. Cela reproduit le fonctionnement d’une véritable requête XMLHttpRequest
. Vous devrez donc très probablement utiliser le support de test asynchrone de votre framework de test. Par exemple, la documentation pertinente pour le framework de test Mocha se trouve ici.
Le hook de cycle de vie onSend
est nécessaire pour répondre aux requêtes MockXhr
. Le serveur fictif gère cela automatiquement. L'autre option consiste à utiliser directement les hooks de cycle de vie MockXhr
. Dans les deux cas, le hook de cycle de vie onSend
s'exécute une fois que le contexte d'exécution qui appelle XMLHttpRequest.send()
est terminé ou effacé. En interne, cette bibliothèque utilise une Promise
immédiatement résolue pour obtenir une pile d'appels vide.
MockXhr
par programmation Il existe plusieurs méthodes et propriétés MockXhr
pour répondre aux requêtes. Ces méthodes permettent les interactions suivantes :
Consultez la section Méthodes de réponse simulées pour plus de détails.
timeout
et les délais d'attente des demandes Par défaut, si vous définissez l'attribut timeout
de XMLHttpRequest
dans votre code, les requêtes MockXhr
expirent automatiquement après le délai spécifié. Cela émet l'événement timeout
et annule la demande comme décrit dans la spécification.
S'appuyer sur le passage du temps pour tester la façon dont votre code gère les délais d'attente rend généralement les tests fragiles et difficiles à déboguer. Vous pouvez plutôt déclencher des délais d'attente par programme avec setRequestTimeout()
.
Désactivez les délais d'expiration automatiques des requêtes avec l'une de ces options :
disableTimeout()
sur un MockXhrServer
. Cela affecte toutes les instances MockXhr
qu'il gère.MockXhr.timeoutEnabled = false
. Cette propriété statique sur la classe MockXhr
affecte chacune de ses instances.timeoutEnabled
sur false
sur une instance MockXhr
. Cela affecte uniquement cette instance.MockXhr
Il s'agit d'un modèle d'utilisation alternatif qui n'utilise pas le MockXhrServer
. À la place, vous utilisez directement les hooks de cycle de vie MockXhr
. Cela nécessite plus de code, mais vous avez plus de contrôle sur les requêtes MockXhr
.
Notez que vous pouvez également utiliser les hooks de cycle de vie MockXhr
avec MockXhrServer
si vous avez uniquement besoin d'étendre le serveur fictif.
Exemple:
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
Cette classe est un serveur fictif qui répond aux requêtes MockXhr
en fonction de leur URL et de leur méthode.
MockXhrServer
MockXhrServer(routes)
Arguments :
routes
: Objet avec l'ensemble initial de routes du serveur. (facultatif) Dans la plupart des cas, vous devez utiliser newServer
au lieu de ce constructeur directement.
Les clés de l'objet routes
sont des méthodes HTTP. Les valeurs sont des tableaux avec deux éléments : [url_matcher, request_handler]
.
Voir également Correspondant d'URL de requête et Gestionnaire de requêtes.
Exemple:
const handlerFn = ( request ) => { request . respond ( ) ; } ;
newServer ( {
get : [ '/get' , { status : 200 } ] ,
'my-method' : [ '/my-method' , { status : 201 } ] ,
post : [ '/post' , [ handlerFn , { status : 404 } ] ] ,
} ) ;
install(context = globalThis)
Arguments :
context
: Si vous fournissez une valeur, la méthode install
définit la propriété XMLHttpRequest
dans ce contexte au lieu du contexte global. (facultatif) Installe la simulation MockXhr
du serveur dans le contexte global pour remplacer la classe XMLHttpRequest
. Revenir avec Remove().
remove()
Annule les modifications apportées par install(). Appelez ceci après vos tests.
progressRate
Si vous définissez progressRate
sur un number
supérieur à 0, le serveur génère automatiquement des événements de progression de demande (téléchargement) et de réponse (téléchargement). Chaque événement de progression est incrémenté d’octets progressRate
.
progressRate
s'applique uniquement aux gestionnaires de requêtes de type object
.
disableTimeout()
et enableTimeout()
Ces méthodes désactivent ou activent les effets de l'attribut timeout
de MockXhr
. Voir « L'attribut timeout
et les délais d'attente des demandes ».
Les routes configurent la façon dont le serveur répond aux requêtes MockXhr
. Leurs trois parties sont décrites ci-dessous.
Le concept d'itinéraire est vaguement basé sur le framework Express.
Toute string
avec une méthode de requête HTTP valide est autorisée. Les méthodes valides incluent des méthodes standard telles que GET
, POST
, PUT
et DELETE
, ainsi que d'autres noms de méthodes. Les noms de méthodes standard ne sont pas sensibles à la casse.
Le comparateur d'URL de requête peut être de l'un des types suivants :
string
(par exemple '/my-url'
) correspondant exactement à l'URL de la requête.RegExp
correspondant à l'URL de la requête.Function
qui renvoie true
si l'URL de la requête correspond. La fonction reçoit l'URL en argument. Le gestionnaire de requêtes peut être de l'un des types suivants :
Un object
avec les propriétés de réponse. Les valeurs par défaut sont :
{ status: 200, headers: {}, body: null, statusText: 'OK' }
Une Function
qui appelle directement les méthodes de réponse fictives. La fonction reçoit une instance MockXhrRequest
comme argument.
Une string
avec la valeur 'error'
ou 'timeout'
. Cela déclenche respectivement une erreur ou un délai d'attente.
Un tableau des autres types de gestionnaires de requêtes ci-dessus. La première requête obtient le premier gestionnaire, la seconde obtient le deuxième gestionnaire et ainsi de suite. Le dernier gestionnaire est réutilisé lorsqu'il n'y a plus de gestionnaire dans le tableau.
Pour les gestionnaires de requêtes object
, le serveur ajoute automatiquement l'en-tête de réponse Content-Length
avec la longueur du corps de la réponse.
Tous ces gestionnaires sont équivalents :
const handlerObj = { } ;
const handlerFn = ( request ) => { request . respond ( 200 , { 'Content-Length' : '0' } ) ; } ;
const handlerArray = [ { } ] ;
get(urlMatcher, handler)
Arguments :
urlMatcher
: demande de correspondance d'URL.handler
: gestionnaire de requêtes. Ajoute une route pour la méthode GET
HTTP.
post(urlMatcher, handler)
Arguments :
urlMatcher
: demande de correspondance d'URL.handler
: gestionnaire de requêtes. Ajoute une route pour la méthode HTTP POST
.
put(urlMatcher, handler)
Arguments :
urlMatcher
: demande de correspondance d'URL.handler
: gestionnaire de requêtes. Ajoute une route pour la méthode HTTP PUT
.
delete(urlMatcher, handler)
Arguments :
urlMatcher
: demande de correspondance d'URL.handler
: gestionnaire de requêtes. Ajoute une route pour la méthode HTTP DELETE
.
addHandler(method, urlMatcher, handler)
Arguments :
method
: méthode HTTP sous forme string
.urlMatcher
: demande de correspondance d'URL.handler
: gestionnaire de requêtes. Ajoute une route pour la method
HTTP.
setDefaultHandler(handler)
Arguments :
handler
: gestionnaire de requêtes.Définit un gestionnaire de requêtes par défaut pour les requêtes qui ne correspondent à aucun itinéraire.
setDefault404()
Définit un gestionnaire de requêtes par défaut qui renvoie 404 réponses.
xhrFactory
Fonction qui renvoie une nouvelle instance MockXhr
.
MockXhr
La classe MockXhr
à laquelle le serveur se connecte. xhrFactory
crée des instances de cette classe.
getRequestLog()
Renvoie un tableau de toutes les requêtes reçues par le serveur jusqu'à présent. Chaque appel renvoie un nouveau tableau. Chaque élément du tableau est un objet avec ces propriétés :
method
: string
de méthode HTTP.url
: string
d'URL.body
: corps de la demandeheaders
: demande les en-têtes en tant qu’objet. Les noms d'en-tête sont en minuscules.MockXhr
Cette classe est une simulation de XMLHttpRequest
. Cette section documente ses méthodes et propriétés qui ne figurent pas dans la spécification.
MockXhr.timeoutEnabled
Cette propriété boolean
statique contrôle le délai d'expiration automatique des requêtes de toutes les instances de la classe.
timeoutEnabled
Cette propriété boolean
contrôle le délai d'expiration automatique de cette instance MockXhr
.
getResponseHeadersHash()
Renvoie tous les en-têtes de réponse sous forme d'objet. Les noms d'en-tête sont en minuscules.
MockXhr
Vous pouvez définir des méthodes de rappel pour les hooks de cycle de vie MockXhr
à ces emplacements :
MockXhr
. Le hook s'applique à toutes les instances de MockXhr
et de ses sous-classes.MockXhr
renvoyée par MockXhrServer.MockXhr
ou newMockXhr()
. Le hook s'applique à toutes les instances de cette classe.MockXhr
. Le hook s’applique uniquement à cette instance.Si vous définissez plusieurs hooks pour un événement de cycle de vie, ils sont appelés dans l'ordre ci-dessus.
Vous devriez généralement préférer la troisième option qui permet d’isoler plus facilement vos cas de tests.
onCreate
Méthode de rappel qui reçoit ces arguments :
xhr
: Nouvelle instance MockXhr
. Utilisez ce hook de cycle de vie pour intercepter les instances de MockXhr
lorsqu'elles sont construites.
Appelé lorsqu'une instance de MockXhr
est créée, à la fin de son constructeur. Ce hook de cycle de vie n'est donc disponible qu'en tant que propriété statique.
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
Méthode de rappel qui reçoit ces arguments :
request
: MockXhrRequest
pour la requête.xhr
: L'instance MockXhr
.Utilisez ce hook de cycle de vie pour répondre à une requête avec les méthodes de réponse fictives.
Appelé de manière asynchrone après chaque appel à send()
. Chaque appel à send()
génère un appel à onSend
avec une instance distincte de 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
Chaque appel à send()
crée un MockXhrRequest
qui contient des informations sur XMLHttpRequest
et fournit des méthodes pour répondre par programme.
requestHeaders
HeadersContainer
qui contient une copie des en-têtes de la demande.
method
Une string
avec la méthode HTTP de la requête.
url
Une string
avec l'URL de la requête.
body
Le corps de la demande.
withCredentials
Un boolean
avec la valeur withCredentials
de la requête.
getRequestBodySize()
number
d'octets dans le corps de la requête.
Remarque : ce n'est pas tout à fait exact lorsque le body
est un FormData
codé multipart/form-data
. Les en-têtes, l'encodage et d'autres facteurs qui contribuent à la taille réelle body
d'un XMLHttpRequest
non simulé ne sont pas pris en compte. Vous pouvez utiliser cette méthode pour obtenir une valeur plancher pour la taille réelle body
de la requête. Ceci est utile pour simuler des événements de progression du téléchargement.
Ces méthodes fournissent une interface de programmation pour répondre aux requêtes MockXhr
.
Si un appel à une méthode de réponse n'est pas valide, il renvoie une Error
avec un message contenant "Mock usage error detected"
.
uploadProgress(transmitted)
Arguments :
transmitted
: number
d'octets transmis.Déclenche une demande de progression du téléchargement.
Vous ne pouvez appeler cela que lorsque le body
de la requête n’est pas null
et que le téléchargement n’est pas terminé.
Après avoir appelé cette méthode, vous pouvez utiliser n’importe quelle autre méthode de réponse fictive.
respond(status = 200, headers = {}, body = null, statusText = 'OK')
Arguments :
status
: number
d'état HTTP de la réponse. (facultatif)headers
: object
avec les en-têtes de réponse. (facultatif)body
: corps de réponse. (facultatif)statusText
: texte d'état HTTP de la réponse string
. (facultatif) Méthode de réponse complète qui définit à la fois les en-têtes et le corps de la réponse. Modifie le readyState
de la requête en DONE
.
Déclenche les événements appropriés tels que readystatechange
, progress
et load
.
Il s'agit d'un raccourci pour setResponseHeaders()
suivi de setResponseBody()
.
Après avoir appelé cette méthode, vous ne pouvez plus utiliser d’autres méthodes de réponse fictive. Cette restriction est levée si vous appelez à nouveau open()
.
setResponseHeaders(status = 200, headers = {}, statusText = 'OK')
Arguments :
status
: number
d'état HTTP de la réponse. (facultatif)headers
: object
avec les en-têtes de réponse. (facultatif)statusText
: texte d'état HTTP de la réponse string
. (facultatif) Définit les en-têtes de réponse. Modifie le readyState
de la requête en HEADERS_RECEIVED
.
Déclenche les événements appropriés tels que readystatechange
, progress
et load
.
Après avoir appelé cette méthode, vous pouvez utiliser les méthodes de réponse fictive suivantes :
downloadProgress()
setResponseBody()
setNetworkError()
setRequestTimeout()
. downloadProgress(transmitted, length)
Arguments :
transmitted
: number
d'octets transmis.length
: number
d'octets dans la réponse. Déclenche un événement de progression de la réponse. Modifie le readyState
de la requête en LOADING
s'il s'agit de HEADERS_RECEIVED
.
Vous devez appeler setResponseHeaders()
avant cette méthode.
setResponseBody(body = null)
Arguments :
body
: corps de réponse. (facultatif) Définit le corps de la réponse. Modifie le readyState
de la requête en DONE
.
Déclenche les événements appropriés tels que readystatechange
, progress
et load
.
Appelle setResponseHeaders()
s’il n’est pas déjà appelé. Les en-têtes de réponse ne contiennent alors que Content-Length
avec une valeur égale à la longueur du corps de la réponse.
Après avoir appelé cette méthode, vous ne pouvez plus utiliser d’autres méthodes de réponse fictive. Cette restriction est levée si vous appelez à nouveau open()
.
setNetworkError()
Simule une erreur réseau. Modifie le readyState
de la requête en DONE
.
Déclenche les événements appropriés, y compris l'événement error
.
Après avoir appelé cette méthode, vous ne pouvez plus utiliser d’autres méthodes de réponse fictive. Cette restriction est levée si vous appelez à nouveau open()
.
setRequestTimeout()
Simule un délai d'attente de demande. Modifie le readyState
de la requête en DONE
.
Déclenche les événements appropriés, y compris l'événement timeout
.
Génère une erreur si l'attribut request
est égal à 0 puisque les délais d'attente ne se produisent pas dans ce cas.
Après avoir appelé cette méthode, vous ne pouvez plus utiliser d’autres méthodes de réponse fictive. Cette restriction est levée si vous appelez à nouveau open()
.
newMockXhr()
Renvoie une nouvelle sous-classe MockXhr
.
Si vous utilisez une sous-classe différente de MockXhr
dans chaque scénario de test, il est plus facile de vous assurer qu'elles sont autonomes. Par exemple, si vous définissez la propriété statique timeoutEnabled
sur une sous-classe, cela affecte uniquement cette sous-classe et non les autres sous-classes créées dans d'autres scénarios de test. Étant donné que les sous-classes ne sont pas réutilisées, le code de nettoyage qui annule les modifications apportées à une sous-classe n'est pas requis.
newServer(routes)
Arguments :
routes
: Objet avec l'ensemble initial de routes du serveur. (facultatif) Renvoie un nouveau MockXhrServer
avec sa propre sous-classe MockXhr
unique. Voir newMockXhr()
.
Ajoutez des routes au MockXhrServer
avec l'argument routes
facultatif. Voir le constructeur pour plus de détails.
XMLHttpRequest
Basé sur la version de spécification XMLHTTPRequest « 15 août 2022 ».
open()
, setRequestHeader()
, send()
et abort()
.statusText
, en-têtes et corps.timeout
(peut être désactivé).MockXhr.setNetworkError()
).MockXhr.setRequestTimeout()
).overrideMimeType()
est lancé lorsque cela est nécessaire, mais n'a aucun autre effet.responseType
: ''
, 'text'
et 'json'
sont entièrement pris en charge. Les valeurs responseType
n'ont aucun effet sur le corps de la réponse transmis à setResponseBody()
.responseXml
: le corps de la réponse n'est pas converti en réponse de document. Pour obtenir une réponse de document, transmettez-la directement comme corps de réponse dans setResponseBody()
.responseUrl
: l'URL finale de la requête après les redirections n'est pas automatiquement définie. Cela peut être émulé dans un gestionnaire de requêtes.async
défini sur false
dans open()
).open()
et lancer SyntaxError
en cas d'échec. Les contributeurs sont les bienvenus ! Consultez ce guide pour plus d’informations.
MIT