programing

Jest에서의 XMLHttpRequest 테스트

lastcode 2023. 10. 24. 21:21
반응형

Jest에서의 XMLHttpRequest 테스트

AJAX methods (vanilla XHR)를 테스트하고 싶은데 Jest framework로 할 방법을 못 찾겠어요.발견했습니다.mock-ajax.js재스민을 위해서.문제는 설치 방법을 찾을 수 없다는 것입니다.

Jest에서 Ajax 기능을 유닛 테스트하는 더 좋은 방법이 있을까요?

jest api가 조금 바뀌었습니다.이게 제가 쓰는 거예요.아무 것도 할 수 없지만 내 부품을 렌더링하기에 충분합니다.

const xhrMockClass = () => ({
  open            : jest.fn(),
  send            : jest.fn(),
  setRequestHeader: jest.fn()
})

window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass)

그리고 테스트 파일에서:

import '../../__mock__/xhr-mock.js'

추가 패키지 없이 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
});

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!']]);
});

말씀하신 대로 추가 라이브러리는 필요 없습니다.

 // 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 mock을 생성하여 에 설치하는 기능이 있습니다.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)
})

@thajay의 대답을 한 걸음 더 나아가, 나는 모든 것을 조롱했습니다.XMLHttpRequest속성(XMLHtpRequestEventTargetEventTarget에서 확장됨):

window.XMLHttpRequest = jest.fn(() => ({
  abort: jest.fn(),
  addEventListener: jest.fn(),
  dispatchEvent: jest.fn(),
  error: jest.fn(),
  getResponseHeader: jest.fn(),
  load: jest.fn(),
  loadend: jest.fn(),
  loadstart: jest.fn(),
  onreadystatechange: jest.fn(),
  open: jest.fn(),
  progress: jest.fn(),
  readyState: jest.fn(),
  removeEventListener: jest.fn(),
  response: jest.fn(),
  responseText: jest.fn(),
  responseType: jest.fn(),
  responseURL: jest.fn(),
  responseXML: jest.fn(),
  send: jest.fn(),
  setRequestHeader: jest.fn(),
  status: jest.fn(),
  statusText: jest.fn(),
  timeout: jest.fn(),
  upload: jest.fn(),
  withCredentials: jest.fn(),
}))

그리고 이것을 내 안에 집어넣습니다.jest.setup.js

언급URL : https://stackoverflow.com/questions/28584773/xmlhttprequest-testing-in-jest

반응형