Jest 中的 XMLHttpRequest 测试
XMLHttpRequest testing in Jest
我想测试 AJAX 方法(vanilla XHR),但我找不到使用 Jest 框架的方法。我为 Jasmine 找到了 mock-ajax.js
。问题是我找不到安装方法
在 Jest 中是否有更好的单元测试 Ajax 函数的方法?
您可以在 Jest 中测试 XHR,无需额外的包。这是为 XMLHttpRequest 创建模拟对象的辅助函数:
let open, send, onload, onerror;
function createXHRmock() {
open = jest.genMockFn();
// be aware we use *function* because we need to get *this*
// from *new XmlHttpRequest()* call
send = jest.genMockFn().mockImpl(function(){
onload = this.onload.bind(this);
onerror = this.onerror.bind(this);
});
const xhrMockClass = function () {
return {
open,
send
};
};
window.XMLHttpRequest = jest.genMockFn().mockImpl(xhrMockClass);
}
您可以在测试中使用它,如下所示:
it('XHR success', () => {
createXHRmock();
// here you should call GET request
expect(open).toBeCalledWith('GET', 'http://example.com', true);
expect(send).toBeCalled();
// call onload or onerror
onload();
// here you can make your assertions after onload
});
笑话api有点变了。这是我用的。它什么都不做,但足以渲染我的组件。
const xhrMockClass = () => ({
open : jest.fn(),
send : jest.fn(),
setRequestHeader: jest.fn()
})
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass)
并且在测试文件中:
import '../../__mock__/xhr-mock.js'
如前所述,您不需要额外的库:
// mocks.js is where you could put your mocks (example below)
const mocks = require('./mocks.js')
test('XHR test', () => {
let xhrMock = {
open: jest.fn(),
setRequestHeader: jest.fn(),
onreadystatechange: jest.fn(),
send: jest.fn(),
readyState: 4,
responseText: JSON.stringify(mocks),
status: 200
}
window.XMLHttpRequest = jest.fn(() => xhrMock)
sendData().then((response) => {
// You could do you checks here. Some examples:
expect(xhrMock.setRequestHeader).toBeCalledWith('Cache-Control', 'no-cache')
expect(xhrMock.open).toBeCalledWith('POST', 'you_api_url.com/end_point/')
expect(xhrMock.withCredentials).toBe(false)
let formData = new FormData()
formData.append('firstParam', 'firstParamValue')
expect(yoloRequestMock.send).toBeCalledWith(formData)
expect(JSON.stringify(response)).toBe(JSON.stringify(mocks))
})
// when onload is called, resolve and reject has been initialed.
xhrMock.onreadystatechange()
// the following function is the one which sends the request (to be tested)
function sendData() {
return new Promise(function(resolve, reject) {
let formData = new FormData()
formData.append('firstParam', 'firstParamValue')
let xhr = new XMLHttpRequest()
xhr.withCredentials = false
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
if(xhr.status === 200) {
resolve(JSON.parse(xhr.responseText))
} else {
reject(xhr.responseText)
}
}
}
xhr.open('POST', T2S_VISUAL_SEARCH_PARAMS.t2sVisualSeacchApiUrl)
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.send(formData)
})
}
}
文件 mocks.js
包含模拟:
module.exports =
{
response: {
body: { ... }
}
}
这是一个函数,可以创建 XMLHttpRequest 模拟并将其安装到 window
中。
const mockXMLHttpRequest = () => {
const mock = {
open: jest.fn(),
addEventListener: jest.fn(),
setRequestHeader: jest.fn(),
send: jest.fn(),
getResponseHeader: jest.fn(),
upload: {
addEventListener: jest.fn(),
},
};
window.XMLHttpRequest = jest.fn(() => mock);
return mock;
};
然后您可以像这样在测试中使用它:
const mock = mockXMLHttpRequest();
// Get the upload progress callback
// This assumes you attach your listeners in a stable order
expect(mock.upload.addEventListener).toHaveBeenCalledTimes(1);
const [[, progress]] = mock.upload.addEventListener.mock.calls;
// Get the load callback
expect(mock.addEventListener).toHaveBeenCalledTimes(1);
const [[, load]] = mock.addEventListener.mock.calls;
expect(mock.open).toHaveBeenCalled();
expect(mock.send).toHaveBeenCalled();
// Fire a progress event
progress({ loaded: 12, total: 100 });
// ...
mock.status = 201;
mock.getResponseHeader.mockReturnValue('application/json');
mock.response = JSON.stringify({ id: 111 });
// Fire a load event
load();
// ...
我就是这样做的。
test.js
const open = jest.fn();
const onload = jest.fn((x) => {/* <your response data> */});
const onerror = jest.fn();
const send = jest.fn(function(){
this.onload()
})
const xhrMockClass = function () {
return {
open,
send,
onerror,
onload
};
};
global.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
// ...
test('Should make a request', () => {
// do stuff to make request
expect(send).toHaveBeenCalled()
expect(onload).toHaveBeenCalledWith(/* <your response data> */)
expect(open).toHaveBeenCalledWith('GET', 'some/url', true)
})
这是一个使用 Jest 26 的 TypeScript 示例:
function performRequest(callback: any) {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/');
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4 || xhr.status !== 200) return;
callback(xhr.response);
};
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send(null);
}
describe('request', () => {
const xhrMock: Partial<XMLHttpRequest> = {
open: jest.fn(),
send: jest.fn(),
setRequestHeader: jest.fn(),
readyState: 4,
status: 200,
response: 'Hello World!'
};
jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMock as XMLHttpRequest);
const callback = jest.fn();
performRequest(callback);
expect(xhrMock.open).toBeCalledWith('GET', 'https://example.com/');
expect(xhrMock.setRequestHeader).toBeCalledWith('Accept', 'application/json');
(xhrMock.onreadystatechange as EventListener)(new Event(''));
expect(callback.mock.calls).toEqual([['Hello World!']]);
});
我想测试 AJAX 方法(vanilla XHR),但我找不到使用 Jest 框架的方法。我为 Jasmine 找到了 mock-ajax.js
。问题是我找不到安装方法
在 Jest 中是否有更好的单元测试 Ajax 函数的方法?
您可以在 Jest 中测试 XHR,无需额外的包。这是为 XMLHttpRequest 创建模拟对象的辅助函数:
let open, send, onload, onerror;
function createXHRmock() {
open = jest.genMockFn();
// be aware we use *function* because we need to get *this*
// from *new XmlHttpRequest()* call
send = jest.genMockFn().mockImpl(function(){
onload = this.onload.bind(this);
onerror = this.onerror.bind(this);
});
const xhrMockClass = function () {
return {
open,
send
};
};
window.XMLHttpRequest = jest.genMockFn().mockImpl(xhrMockClass);
}
您可以在测试中使用它,如下所示:
it('XHR success', () => {
createXHRmock();
// here you should call GET request
expect(open).toBeCalledWith('GET', 'http://example.com', true);
expect(send).toBeCalled();
// call onload or onerror
onload();
// here you can make your assertions after onload
});
笑话api有点变了。这是我用的。它什么都不做,但足以渲染我的组件。
const xhrMockClass = () => ({
open : jest.fn(),
send : jest.fn(),
setRequestHeader: jest.fn()
})
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass)
并且在测试文件中:
import '../../__mock__/xhr-mock.js'
如前所述,您不需要额外的库:
// mocks.js is where you could put your mocks (example below)
const mocks = require('./mocks.js')
test('XHR test', () => {
let xhrMock = {
open: jest.fn(),
setRequestHeader: jest.fn(),
onreadystatechange: jest.fn(),
send: jest.fn(),
readyState: 4,
responseText: JSON.stringify(mocks),
status: 200
}
window.XMLHttpRequest = jest.fn(() => xhrMock)
sendData().then((response) => {
// You could do you checks here. Some examples:
expect(xhrMock.setRequestHeader).toBeCalledWith('Cache-Control', 'no-cache')
expect(xhrMock.open).toBeCalledWith('POST', 'you_api_url.com/end_point/')
expect(xhrMock.withCredentials).toBe(false)
let formData = new FormData()
formData.append('firstParam', 'firstParamValue')
expect(yoloRequestMock.send).toBeCalledWith(formData)
expect(JSON.stringify(response)).toBe(JSON.stringify(mocks))
})
// when onload is called, resolve and reject has been initialed.
xhrMock.onreadystatechange()
// the following function is the one which sends the request (to be tested)
function sendData() {
return new Promise(function(resolve, reject) {
let formData = new FormData()
formData.append('firstParam', 'firstParamValue')
let xhr = new XMLHttpRequest()
xhr.withCredentials = false
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
if(xhr.status === 200) {
resolve(JSON.parse(xhr.responseText))
} else {
reject(xhr.responseText)
}
}
}
xhr.open('POST', T2S_VISUAL_SEARCH_PARAMS.t2sVisualSeacchApiUrl)
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.send(formData)
})
}
}
文件 mocks.js
包含模拟:
module.exports =
{
response: {
body: { ... }
}
}
这是一个函数,可以创建 XMLHttpRequest 模拟并将其安装到 window
中。
const mockXMLHttpRequest = () => {
const mock = {
open: jest.fn(),
addEventListener: jest.fn(),
setRequestHeader: jest.fn(),
send: jest.fn(),
getResponseHeader: jest.fn(),
upload: {
addEventListener: jest.fn(),
},
};
window.XMLHttpRequest = jest.fn(() => mock);
return mock;
};
然后您可以像这样在测试中使用它:
const mock = mockXMLHttpRequest();
// Get the upload progress callback
// This assumes you attach your listeners in a stable order
expect(mock.upload.addEventListener).toHaveBeenCalledTimes(1);
const [[, progress]] = mock.upload.addEventListener.mock.calls;
// Get the load callback
expect(mock.addEventListener).toHaveBeenCalledTimes(1);
const [[, load]] = mock.addEventListener.mock.calls;
expect(mock.open).toHaveBeenCalled();
expect(mock.send).toHaveBeenCalled();
// Fire a progress event
progress({ loaded: 12, total: 100 });
// ...
mock.status = 201;
mock.getResponseHeader.mockReturnValue('application/json');
mock.response = JSON.stringify({ id: 111 });
// Fire a load event
load();
// ...
我就是这样做的。
test.js
const open = jest.fn();
const onload = jest.fn((x) => {/* <your response data> */});
const onerror = jest.fn();
const send = jest.fn(function(){
this.onload()
})
const xhrMockClass = function () {
return {
open,
send,
onerror,
onload
};
};
global.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
// ...
test('Should make a request', () => {
// do stuff to make request
expect(send).toHaveBeenCalled()
expect(onload).toHaveBeenCalledWith(/* <your response data> */)
expect(open).toHaveBeenCalledWith('GET', 'some/url', true)
})
这是一个使用 Jest 26 的 TypeScript 示例:
function performRequest(callback: any) {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/');
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4 || xhr.status !== 200) return;
callback(xhr.response);
};
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send(null);
}
describe('request', () => {
const xhrMock: Partial<XMLHttpRequest> = {
open: jest.fn(),
send: jest.fn(),
setRequestHeader: jest.fn(),
readyState: 4,
status: 200,
response: 'Hello World!'
};
jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMock as XMLHttpRequest);
const callback = jest.fn();
performRequest(callback);
expect(xhrMock.open).toBeCalledWith('GET', 'https://example.com/');
expect(xhrMock.setRequestHeader).toBeCalledWith('Accept', 'application/json');
(xhrMock.onreadystatechange as EventListener)(new Event(''));
expect(callback.mock.calls).toEqual([['Hello World!']]);
});