В чем разница между двумя частями кода, написанными на React, которые содержат хук useEffect и некоторые асин c вещи внутри него? - PullRequest
0 голосов
/ 17 февраля 2020

Я пишу сервис для мониторинга информации о акциях разных компаний. У меня есть локальный сервер, который служит «прокси», что делает данные более удобными для обработки. Я пишу фрагмент кода, функция которого заключается в получении данных о компаниях, которые пользователь добавил в свой профиль (на самом деле пользователи пока не имеют возможности создать профиль в моем сервисе, поэтому я просто сохраняю данные в localStorage) с моего сервера. после того, как компонент отображается первый раз. Первая реализация:

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { StockItem } from './StockItem';

export const StocksList = () => {
  const [ stocks, setStocks ] = useState([]);

  useEffect(() => {
    const fetchStocks = async () => {
      const userStocks = localStorage.getItem('userStocks');
      if (!userStocks) {
        return;
      }

      const userStocksList = JSON.parse(userStocks);
      const stockSymbolsParam = userStocksList.join(',');

      const response = await axios.get(
        `http://localhost:8080/api/v1/stocks?stockSymbols=${stockSymbolsParam}`
      );
      const { data: stocksResponse, status } = response;
      if (status !== 200) {
        throw new Error('Invalid request to API');
      }

      const { stocksData } = stocksResponse;
      let initialStocks = [];

      const processStockData = (stockData) => {
        const {
          symbol,
          data: {
            companyName,
            price,
            change,
          },
        } = stockData;

        const stock = {
          company: {
            name: companyName,
            symbol
          },
          price,
          change,
        };

        initialStocks.push(stock);
      };

      stocksData.forEach(item => processStockData(item));
      setStocks(prevState => [ ...prevState, ...initialStocks ]);
    };

    fetchStocks();
  }, []);

  return (
    <section>
      <ul data-testid='stocks-list'>
        {
          stocks.map(stock => {
            return (
              <StockItem key={stock.company.symbol} data={stock} />
            )
          })
        }
      </ul>
    </section>
  )
};

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

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { StockItem } from './StockItem';

export const StocksList = () => {
  const [ stocks, setStocks ] = useState([]);

  const fetchStocks = async (symbols) => {
    const stockSymbolsParam = symbols.join(',');
    const response = await axios.get(
      `http://localhost:8080/api/v1/stocks?stockSymbols=${stockSymbolsParam}`
    );
    const { data: stocksResponse, status } = response;
    if (status !== 200) {
      throw new Error('Invalid request to API');
    }

    const { stocksData } = stocksResponse;
    let resultStocks = [];
    const processStockData = (stockData) => {
      const {
        symbol,
        data: {
          companyName,
          price,
          change,
        },
      } = stockData;

      const stock = {
        company: {
          name: companyName,
          symbol
        },
        price,
        change,
      };

      resultStocks.push(stock);
    };

    stocksData.forEach(item => processStockData(item));
    return resultStocks;
  };

  useEffect(() => {
    const userStocks = localStorage.getItem('userStocks');
    if (!userStocks) {
      return;
    }
    const userStocksList = JSON.parse(userStocks);

    (async () => {
      const result = await fetchStocks(userStocksList);
      setStocks(prevState => [ ...prevState, ...result ]);
    })();
  }, []);

  return (
    <section>
      <ul data-testid='stocks-list'>
        {
          stocks.map(stock => {
            return (
              <StockItem key={stock.company.symbol} data={stock} />
            )
          })
        }
      </ul>
    </section>
  )
};

На самом деле, сервис все еще работает, он получает данные и отображает запасы ТАКОМ ЖЕ, как и раньше, но тест, который тестирует компонент StocksList, не проходит. Тест:

import React from 'react';
import axios from 'axios';
import { render } from '@testing-library/react';
import { StocksList } from './StocksList';
import fakeResponse from './fakeResponse';

jest.mock('axios');

it('should fetch stocks data about companies from localStorage after render', async () => {
    (axios.get as jest.Mock).mockImplementationOnce((url) => {
      const symbols = url.substr(url.indexOf('=') + 1).split(',');
      const response = fakeResponse(symbols);
      return Promise.resolve(response);
    });
    const fakeUserStocks = [ 'WIX', 'EBAY', 'AAPL' ];
    localStorage.setItem('userStocks', JSON.stringify(fakeUserStocks));

    const { getAllByTestId, rerender } = render(<StocksList />);
    localStorage.removeItem('userStocks');

    await expect(axios.get).toHaveBeenCalledTimes(1);

    rerender(<StocksList />);
    const stockItems = getAllByTestId('stock-item');
    fakeUserStocks.forEach((userStock, i) => {
      expect(stockItems[i].innerHTML.indexOf(userStock)).not.toEqual(-1);
    });
  });

Сообщение, с которым тест не пройден:

✕ should fetch stocks data about companies from localStorage after render (30ms)

  ● StocksList testing › should fetch stocks data about companies from localStorage after render

    Unable to find an element by: [data-testid="stock-item"]

    <body>
      <div>
        <section
          class="stocksSection"
        >
          <ul
            class="stocksList"
            data-testid="stocks-list"
          />
        </section>
      </div>
    </body>

      35 |
      36 |     rerender(<StocksList />);
    > 37 |     const stockItems = getAllByTestId('stock-item');
         |                        ^
      38 |     fakeUserStocks.forEach((userStock, i) => {
      39 |       expect(stockItems[i].innerHTML.indexOf(userStock)).not.toEqual(-1);
      40 |     });

И я хочу выяснить, есть ли проблема с моим кодом (например, что-то сложное , связанных с Hooks API et c), с моим тестом или, если ни один из них, с некоторыми другими вещами, которые есть в исходном коде, но удалены, чтобы не загромождать проблему (например, Typescript печатания, но Напоминаю, что все работает кроме теста)? Любая помощь приветствуется, спасибо заранее!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...