From ffc176e847ef9b7b3ca9c753b5446766595cc5dd Mon Sep 17 00:00:00 2001 From: Dennis Kigen Date: Sun, 4 Jul 2021 10:20:58 +0300 Subject: [PATCH] Small improvements - Trim search query - obvious in hindsight. Does away with the need to set isSearching to false if the search query is falsy. - Rename test spec + add inline snapshot comparison that checks for the existence of forecast items. --- src/__tests__/app.test.js | 20 ++++++++++++++++---- src/components/app.js | 26 ++++++++++++-------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/__tests__/app.test.js b/src/__tests__/app.test.js index 56a6e1f..f1746ba 100644 --- a/src/__tests__/app.test.js +++ b/src/__tests__/app.test.js @@ -12,7 +12,6 @@ import App from '../components/app'; describe('', () => { beforeAll(() => jest.useFakeTimers()); - afterAll(() => jest.clearAllTimers()); const history = createMemoryHistory(); @@ -24,7 +23,7 @@ describe('', () => { , ); - test('renders the app', async () => { + test('fetches and renders the current weather and a five day forecast', async () => { renderApp(); await waitForLoadingToFinish(); @@ -36,7 +35,8 @@ describe('', () => { expect( screen.getByPlaceholderText(/search for a location/i), ).toBeInTheDocument(); - await screen.findByText(/eldoret, ke/i); + + expect(screen.getByText(/eldoret, ke/i)).toBeInTheDocument(); expect(screen.getByText(/broken clouds/i)).toBeInTheDocument(); expect(screen.getByText(/feels like 18°/i)).toBeInTheDocument(); expect(screen.getByText(/30m\/s winds/i)).toBeInTheDocument(); @@ -44,7 +44,19 @@ describe('', () => { expect( screen.getByText(/'Netflix and chill' weather. It's pleasant outside/i), ).toBeInTheDocument(); - expect(screen.getAllByRole('list').length).toEqual(5); + expect(screen.getAllByRole('listitem').length).toEqual(5); + const forecast = screen.getAllByRole('listitem').map((listItem) => { + return listItem.textContent; + }); + expect(forecast).toMatchInlineSnapshot(` + Array [ + "Saturday22° / 22°", + "Sunday22° / 22°", + "Monday22° / 22°", + "Tuesday20° / 20°", + "Wednesday21° / 21°", + ] + `); expect(screen.getByText(/Open source by/i)).toBeInTheDocument(); expect(screen.getByText(/Dennis Kigen/i)).toBeInTheDocument(); expect(screen.getByText(/©2020 - now/i)).toBeInTheDocument(); diff --git a/src/components/app.js b/src/components/app.js index 6d0b847..990ae51 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -41,9 +41,8 @@ function viewStateReducer(state, action) { const App = () => { const [location, setLocation] = React.useState('Eldoret'); const [debouncedSearchTerm, setDebouncedSearchTerm] = React.useState(''); - const [isSearching, setIsSearching] = React.useState(false); const [units, setUnits] = React.useState('metric'); - const [state, dispatch] = React.useReducer(viewStateReducer, { + const [viewState, dispatch] = React.useReducer(viewStateReducer, { status: 'started', error: null, forecast: [], @@ -59,12 +58,11 @@ const App = () => { ); const handleLocationChange = (event) => { - if (event.target.value) { + const query = event.target.value.trim(); + if (query) { setIsSearching(true); - } else { - setIsSearching(false); } - debounceSearch(event.target.value); + debounceSearch(query); }; const handleUnitsChange = (newUnits) => { @@ -75,7 +73,7 @@ const App = () => { if (debouncedSearchTerm) { setLocation(debouncedSearchTerm); } - }, [debouncedSearchTerm, isSearching]); + }, [debouncedSearchTerm,]); React.useEffect(() => { async function getWeather() { @@ -129,8 +127,8 @@ const App = () => { - {state.status === 'started' ? : null} - {state.status === 'rejected' ? ( + {viewState.status === 'started' ? : null} + {viewState.status === 'rejected' ? (
{ fillRule="evenodd" /> - {state.error.message} + {viewState.error.message}
) : null} - {(state.weather && Object.keys(state.weather).length) || - (state.forecast && Object.keys(state.forecast).length) ? ( + {(viewState.weather && Object.keys(viewState.weather).length) || + (viewState.forecast && Object.keys(viewState.forecast).length) ? (
{ onLocationChange={handleLocationChange} />