javascript - 使用 Jest 在 vanilla js 中测试 AJAX

标签 javascript unit-testing xmlhttprequest jestjs

我正在尝试使用 Jest 在普通 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 的调用应该将 this.quote 更改为模拟函数中的新引号。 我从 this quiestion - XHR testing in Jest 得到了这个想法.

  • 我在这里错过了什么?
  • 我至少走在正确的轨道上了吗?
  • 这是测试 AJAX 的正确方法吗?

(这是 FreeCodeCamp 中的“随机报价机”项目。我知道这有点矫枉过正,但我​​真的很想用 MVC 制作一个前端应用程序。) The repository

最佳答案

我自己解决了。

答案在 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 是否被调用并更改报价。希望有一天这对任何人都有用。

关于javascript - 使用 Jest 在 vanilla js 中测试 AJAX,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50657898/

相关文章:

javascript - Node js 扩展继承对象(作为枚举)

php - 测试具有模型作为依赖项的 laravel 存储库

java - 仅在特定代码块中验证模拟调用,忽略其他调用

javascript - 悬停标记时能够滚动 map 吗?

javascript - 我可以在 IE 中打开对象 URL 吗?

javascript - 当内容大于输入字段时(在 Chrome 中),如何将光标/插入符号移动到输入字段中的最后一个字符?

c# - 如何对从 Task.ContinueWith 衍生出来的方法进行单元测试?

http - 如何使XMLHttpRequest跨域withCredentials,HTTP授权(CORS)?

javascript - MediaWiki API,波兰语字符

javascript - 在 XMLHttpRequest 之后打开页面