Я пишу сервис для мониторинга информации о акциях разных компаний. У меня есть локальный сервер, который служит «прокси», что делает данные более удобными для обработки. Я пишу фрагмент кода, функция которого заключается в получении данных о компаниях, которые пользователь добавил в свой профиль (на самом деле пользователи пока не имеют возможности создать профиль в моем сервисе, поэтому я просто сохраняю данные в 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
печатания, но Напоминаю, что все работает кроме теста)? Любая помощь приветствуется, спасибо заранее!