我正在尝试使用Jest在vanilla JavaScript中测试XMLHttpRequesting函数。它是一个模型函数的单元测试。该函数正在向mashape.com randsom-famous-quote API发出XMLHttpRequest。
这是我的模特:
const QuoteModel = function(quote) {
this.quote = quote;
this.savedQuotes = [];
this.quoteChanged = new Observer();
this.quoteSaved = new Observer();
this.quoteDeleted = new Observer();
};
QuoteModel.prototype.changeQuote = function(quote) {
this.quote = quote;
this.quoteChanged.notify(this.quote);
};
QuoteModel.prototype.fetchQuote = function(url, apiKey = null) {
const xhr = new XMLHttpRequest();
let data;
// QuoteModel
const self = this;
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
data = JSON.parse(this.response)[0];
self.changeQuote(data);
} else {
data = 'Bad response';
}
};
xhr.onerror = function() {
data = 'Error fetching quote';
};
xhr.open('GET', url, true);
if (apiKey != null) xhr.setRequestHeader('X-Mashape-Key', apiKey);
xhr.send();
};
QuoteModel.prototype.getQuote = function() {
return this.quote;
};
QuoteModel.prototype.tweet = function() {
// Opens a tweet window..
};
QuoteModel.prototype.loadSavedQuotes = function() {
// Load quotes from localStorage..
};
QuoteModel.prototype.saveQuote = function(quote) {
// Saves quotes to localStorage..
};
所以fetchQuote函数正在发出一个AJAX请求,并且调用了带有收到引号的changQuote。
在我对模型的单元测试中,我得到了这个:
import QuoteModel from '../js/QuoteModel';
import config from '../config.js';
const model = new QuoteModel({
quote: 'I will never be quoted!',
author: 'Michael Krøyserth-Simsø'
});
// https://stackoverflow.com/questions/28584773/xhr-testing-in-jest
const xhrMockClass = () => ({
open: jest.fn(),
send: jest.fn(),
setRequestHeader: jest.fn(),
status: 200,
response: JSON.stringify([{
quote: 'A fetched quote is as good as any quote.',
author: 'Pelle the Cat'
}])
});
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
// fetchQuote - ajax call to get quote is successfull
test('should make XMLHttpRequest to get new quote', () => {
model.fetchQuote('https://andruxnet-random-famous-quotes.p.mashape.com/?cat=famous&count=10', config.API_KEY);
expect(model.quote).toEqual({
quote: 'A fetched quote is as good as any quote.',
author: 'Pelle the Cat'
});
});
当我运行测试时,我得到了这个:
FAIL test/QuoteModel.test.js
✕ should make XMLHttpRequest to get new quote (16ms)
✓ should have quote set (1ms)
✓ should change quote on request
● should make XMLHttpRequest to get new quote
expect(received).toEqual(expected)
Expected value to equal:
{"author": "Pelle the Cat", "quote": "A fetched quote is as good as any quote."}
Received:
{"author": "Michael Krøyserth-Simsø", "quote": "I will never be quoted!"}
Difference:
- Expected
+ Received
Object {
- "author": "Pelle the Cat",
- "quote": "A fetched quote is as good as any quote.",
+ "author": "Michael Krøyserth-Simsø",
+ "quote": "I will never be quoted!",
}
23 | test('should make XMLHttpRequest to get new quote', () => {
24 | model.fetchQuote('https://andruxnet-random-famous-quotes.p.mashape.com/?cat=famous&count=10', config.API_KEY);
> 25 | expect(model.quote).toEqual({
| ^
26 | quote: 'A fetched quote is as good as any quote.',
27 | author: 'Pelle the Cat'
28 | });
at Object.<anonymous> (test/QuoteModel.test.js:25:25)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 2 passed, 3 total
Snapshots: 0 total
Time: 1.985s
Ran all test suites matching /test\/QuoteModel.test.js/i.
npm ERR! Test failed. See above for more details.
在我看来,对model.fetchQuote的调用应该使用mock函数中的新引号更改this.quote。 我从this quiestion - XHR testing in Jest 得到了这个想法。
(这是FreeCodeCamp中的“随机报价机”项目。我知道这太过分了,但我真的很想用MVC制作一个前端应用程序。) The repository
答案 0 :(得分:1)
有些人可能认为这对做出反应很有帮助
import { act, renderHook } from "@testing-library/react-hooks"
import { xxx } from "../xxx"
describe("xxxx", () => {
it("should xxx", async () => {
let onload
const xhrMock = {
open: jest.fn(),
setRequestHeader: jest.fn(),
onreadystatechange: jest.fn(),
// dont change to arrow function ... does not work
send: jest.fn(function() {
onload = this.onload
}),
readyState: 4,
responseText: "text",
status: 200
}
window.XMLHttpRequest = jest.fn(() => {
return xhrMock
})
const { result } = renderHook(() => xxx())
act(() => {
onload()
})
答案 1 :(得分:0)
我自己解决了。
答案在XHR testing in Jest。只有答案不被接受为解决方案。
let open, send, status, onload, setRequestHeader, response;
function createXHRmock() {
open = jest.fn();
status = 200;
setRequestHeader = jest.fn();
response = JSON.stringify([{
quote: 'A fetched quote is as good as any quote.',
author: 'Pelle the Cat'
}]);
// be aware we use *function* because we need to get *this*
// from *new XmlHttpRequest()* call
send = jest.fn().mockImplementation(function(){
onload = this.onload.bind(this);
onerror = this.onerror.bind(this);
setRequestHeader = this.setRequestHeader.bind(this);
});
const xhrMockClass = function () {
return {
open,
send,
status,
setRequestHeader,
response
};
};
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
}
必须将其更改为jest.fn().mockImplementation
并添加status, setRequestHeader, response
才能让它以我想要的方式运行。
现在我可以测试是否调用model.changeQuote
并更改引用。希望有一天这对任何人都有用。