Можно создать несколько портфелей и добавлять в них акции. Искать их можно по названию или символу. При добавлении в портфель можно указать количество "покупаемых" акций по текущей рыночной цене. Каждые 30 секунд акции обновляют свою стоимость и процент роста.
При ошибке сети/api информация корректно выводится пользователю, а не валидные акции подсвечиваются красным.
Статусы загрузки и обновления корректно отображаются в UI.
Для написания редюсеров был использован пакет redux-toolkit. Функции редюсеров внутри методов createSlice
и createReducer
обернуты в immer и позволяют использовать код с мутациями состояния. В моем случае это было оптимально, так как у меня много вложенных объектов в структуре хранилища и это делает код более читаемым.
Для сохранения состояния был использован пакет redux-persist, потому что удобно. Кроме миграций хранилища, которые крайне сложно сделать "type safe", но это проблемы самой концепции миграций, вот обсуждение и возможное решение на SO.
Для mock-а axios
был использован готовый адаптер.
Для внешнего вида был использован Material-UI, потому что красиво.
-
Сумма портфеля выводится в рублях, и у пользователя нет возможности поменять валюту. Технических прeпятствий для реализации этой фитчи нет, просто в техническом задании её не было. Сумма считается корректно на основе курсов валют подгружаемых по api.
-
Процент изменения портфолио считается на основе новых значений поля
change percent
у обновленных акций, а не путем сравнения предыдущей сумы и текущей. Был выбор: самостоятельно высчитывать процент каждые 30 секунд на основе дневного отчета от api AlphaVantage или использовать методGlobalQuote
для получения готового процента. Оба варианта приемлемы, но второй менее затратный по времени. -
Т.к. api бесплатный, максимальное число запросов в день по api ключу - 500, а в минуту - 5. Из-за этого при превышении лимита показывается предупреждение с сообщением об ошибке.
По сути, здесь я опишу неудачные решения на стадии проектирования.
-
Стоило использовать одну из библиотек по работе с валютами. Я понял это слишком поздно, поэтому внедрение такой библиотеки было бы слишком затратно по времени. Все операции я выполнял, "передвигая" знак запятой так, чтобы не осталось дробной части, выполнял действие/округления и возвращал его обратно.
-
Стоило использовать Redux-Saga, а не Thunk как midleware для редукторов, так-как первый намного проще в тестировании.
Проект размещен на heroku, однако при долгом неиспользовании приложение "засыпает" для экономии ресурсов, поэтому первая загрузка может быть крайне долгой, пока оно просыпается.
Не все компоненты и хуки протестированы, т.к. enzyme
и act
крайне странно обращается с функциональными компонентами. В официальной документации рекомендуют оборачивать выражения, которые потенциально изменяют state, в функцию act
, однако в чистом виде это не работает.
При обертывании изменения в act
не происходит ререндера, а следовательно не срабатывает хук useEffect
. Приходится вызывать каждый ререндер вручную с помощью wrapper.setProps({})
(wrapper.update()
не форсит ререндер компонента).
Если в компоненте используется async логика, судя по всему необходимо использовать await act
и делать весь тест async. Данный подход почему-то не задокументирован, однако упоминается например в заметках одного из контрибьютеров react-а, threepointone.
-Видишь async act в документации?
-Нет.
-И я нет. А он есть.
Пример элементов в AddStockItemForm.spec.tsx
:
const container = mount(<AddStockItemForm/>);
const autocomplete = container.find(StockItemSearchField);
let buttonSubmit = container.find(Collapse).find(Button);
Вот синхронный пример такого взаимодействия:
act(() => {
buttonSubmit.simulate('click');
// expects
})
container.setProps({}); //без этого не работает
И асинхронного:
//если убрать await и async, не работает
await act(async () => {
autocomplete.prop('onChange')({}, mockSearchMatch);
})
container.setProps({});
На решение этой проблемы ушло непозволительно много времени, поэтому не сто процентный code coverage, однако все ненаписанные тесты, делались бы аналогично написанным. Если я ошибаюсь насчет act
, пожалуйста поправьте, мог замылиться глаз. Так же, глаз косится на axios-mock-adapter
или его некорректное использование.
Redux редюсеры протестированы в полной мере, с ними проблем нет.