Реагируйте - как мне выполнить модульное тестирование вызова API в Jest? - PullRequest
0 голосов
/ 03 мая 2020

У меня есть куча вызовов API, которые я хотел бы протестировать. Насколько я знаю, вызовы API модульного тестирования не связаны с выполнением этих вызовов API. Насколько я знаю, вы смоделируете ответы на эти вызовы API, а затем протестируете изменения DOM, однако в настоящее время я пытаюсь это сделать. У меня есть следующий код:

Приложение. js

function App() {

  const [text, setText] = useState("");

  function getApiData() {
        fetch('/api')
        .then(res => res.json())
        .then((result) => {
          console.log(JSON.stringify(result));
          setText(result); 
        })
      }

  return (
    <div className="App">
      {/* <button data-testid="modalButton" onClick={() => modalAlter(true)}>Show modal</button> */}
      <button data-testid="apiCall" onClick={() => getApiData()}>Make API call</button>
      <p data-testid="ptag">{text}</p>
    </div>
  );
}

export default App;

App.test. js

it('expect api call to change ptag', async () => {
  const fakeUserResponse = {'data': 'response'};
  var {getByTestId} = render(<App />)
  var apiFunc = jest.spyOn(global, 'getApiData').mockImplementationOnce(() => {
    return Promise.resolve({
      json: () => Promise.resolve(fakeUserResponse)
    })
  })


  fireEvent.click(getByTestId("apiCall"))
  const text = await getByTestId("ptag")
  expect(text).toHaveTextContent(fakeUserResponse['data'])
})

Я пытаюсь высмеивать результат здесь getApiData (), а затем протестируйте изменение DOM (тег p изменится на результат). Приведенный выше код выдает мне ошибку:

Невозможно следить за свойством getApiData, поскольку оно не является функцией; вместо этого дано неопределенное значение

Как получить доступ к этой функции класса?

РЕДАКТИРОВАТЬ:

Я адаптировал код, но у меня все еще есть проблемы :

Приложение. js

function App() {

  const [text, setText] = useState("");

  async function getApiData() {
        let result = await API.apiCall()
        console.log("in react side " + result)
        setText(result['data'])
      }

  return (
    <div className="App">
      {/* <button data-testid="modalButton" onClick={() => modalAlter(true)}>Show modal</button> */}
      <button data-testid="apiCall" onClick={() => getApiData()}>Make API call</button>
      <p data-testid="ptag">{text}</p>
    </div>
  );
}

export default App;

apiController. js

export const API = {
    apiCall() {
        return fetch('/api')
        .then(res => res.json())
    }
}

Сервер. js

const express = require('express')
const app = express()
const https = require('https')
const port = 5000

app.get('/api', (request, res) => {
    res.json("response")
})

app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))

Приложение .test. js

import React from 'react';
import { render, shallow, fireEvent } from '@testing-library/react';
import App from './App';
import {API} from './apiController'
//import shallow from 'enzyme'

it('api call returns a string', async () => {
  const fakeUserResponse = {'data': 'response'};
  var apiFunc = jest.spyOn(API, 'apiCall').mockImplementationOnce(() => {
    return Promise.resolve({
      json: () => Promise.resolve(fakeUserResponse)
    })
  })
  var {getByTestId, findByTestId} = render(<App />)
  fireEvent.click(getByTestId("apiCall"))
  expect(await findByTestId("ptag")).toHaveTextContent('response');
})

Ошибка, которую я получаю,

expect(element).toHaveTextContent()

   Expected element to have text content:
     response
   Received:

     14 |   var {getByTestId, findByTestId} = render(<App />)
     15 |   fireEvent.click(getByTestId("apiCall"))
   > 16 |   expect(await findByTestId("ptag")).toHaveTextContent('response');
        |                                      ^
     17 | })
     18 | 
     19 | // it('api call returns a string', async () => {

Многоразовый модульный тест (надеюсь):

    it('api call returns a string', async () => {
      const test1 = {'data': 'response'};
       const test2 = {'data': 'wrong'}

      var apiFunc = (response) => jest.spyOn(API, 'apiCall').mockImplementation(() => {
        console.log("the response " + JSON.stringify(response))
        return Promise.resolve(response)
        })

      var {getByTestId, findByTestId} = render(<App />)

      let a = await apiFunc(test1);
      fireEvent.click(getByTestId("apiCall"))
      expect(await findByTestId("ptag")).toHaveTextContent('response');
      let b = await apiFunc(test2);
      fireEvent.click(getByTestId("apiCall"))
      expect(await findByTestId("ptag")).toHaveTextContent('wrong');

    })

1 Ответ

0 голосов
/ 03 мая 2020

Вы не можете получить доступ к getApiData, потому что это закрытая функция внутри другой функции (замыкание) и она не доступна для глобальной области видимости. Это означает, что переменная global не имеет свойства getApiData, и вы получаете undefined given instead.

. Для этого вам нужно как-то экспортировать эту функцию, я бы предложил переместить ее в другой файл, но то же самое должно быть хорошо. Вот простой пример:

export const API = {
  getData() {
    return fetch('/api').then(res => res.json())
  }
}

Где-то в вашем компоненте:

API.getData().then(result => setText(result))

И в тесте:

var apiFunc = jest.spyOn(API, 'getData').mockImplementationOnce(() => {
    return Promise.resolve({
      json: () => Promise.resolve(fakeUserResponse)
    })
  })

Есть и другие способы достижения этого, но может быть, этого будет достаточно.

И я думаю, что будет еще одна проблема. Вы используете const text = await getByTestId("ptag"), но getBy* функции из реагирующей-тестирующей библиотеки не являются асинхронными (они не возвращают обещание, которое вы можете подождать, чтобы выполнить его), поэтому ваш тест не пройден, так как вы не будете ждать ложного показа просьба к фини sh. Вместо этого попробуйте findBy* версию этой функции, которую вы можете await включить, и убедитесь, что обещание выполнено.

...