From 279374256b617558b521398161f4d3e7aa24cd03 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Wed, 4 Oct 2023 13:16:16 +0000 Subject: [PATCH] location component unit test cases --- src/components/Location/Flag.tsx | 5 +- src/components/Location/index.test.tsx | 94 ++++++++++++++++++++++++++ src/components/Location/index.tsx | 6 +- 3 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/components/Location/index.test.tsx diff --git a/src/components/Location/Flag.tsx b/src/components/Location/Flag.tsx index b84a516c..31f6c475 100644 --- a/src/components/Location/Flag.tsx +++ b/src/components/Location/Flag.tsx @@ -8,16 +8,15 @@ type Props = { } export function Flag({ country }: Props) { - if (!country?.name || !country?.code) return null // offset between uppercase ascii and regional indicator symbols const OFFSET = 127397 - const emoji = country.code.replace(/./g, (char) => + const emoji = country?.code.replace(/./g, (char) => String.fromCodePoint(char.charCodeAt(0) + OFFSET) ) return ( - + {emoji} ) diff --git a/src/components/Location/index.test.tsx b/src/components/Location/index.test.tsx new file mode 100644 index 00000000..26e7ee4c --- /dev/null +++ b/src/components/Location/index.test.tsx @@ -0,0 +1,94 @@ +import { + describe, + it, + expect, + beforeAll, + afterAll, + vi, + type SpyInstance +} from 'vitest' +import { render, screen } from '@testing-library/react' +import * as nanostores from '@nanostores/react' +import Location from '.' + +const mockData = { + now: { + country: 'USA', + country_code: 'US', + city: 'New York' + }, + next: { + country: 'Canada', + country_code: 'CA', + city: 'Toronto', + date_start: '2023-10-05' + } +} + +describe('Location component', () => { + let useStoreSpy: SpyInstance + + beforeAll(() => { + vi.mock('@nanostores/react') + useStoreSpy = vi.spyOn(nanostores, 'useStore') + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + + it('renders the location items correctly', () => { + useStoreSpy.mockImplementationOnce(() => ({ + data: mockData, + loading: false, + error: null + })) + + render() + + expect(screen.getByLabelText('USA')).toBeInTheDocument() + expect(screen.getByText('New York')).toBeInTheDocument() + expect(screen.getByLabelText('Canada')).toBeInTheDocument() + expect(screen.getByText('Toronto')).toBeInTheDocument() + }) + + it('renders the loading indicator', () => { + useStoreSpy.mockImplementationOnce(() => ({ + data: null, + loading: true, + error: null + })) + + render() + + expect(screen.getByText('...')).toBeInTheDocument() + }) + + it('renders empty when there is no data', () => { + useStoreSpy.mockImplementationOnce(() => ({ + data: null, + loading: false, + error: null + })) + + render() + + expect(screen.queryByLabelText('Location')).toBeEmptyDOMElement() + }) + + it('renders nothing and logs error when error is encountered', () => { + const consoleErrorSpy = vi.spyOn(console, 'error') + useStoreSpy.mockImplementationOnce(() => ({ + data: null, + loading: false, + error: 'Error' + })) + + render() + + expect(screen.queryByLabelText('Location')).not.toBeInTheDocument() + expect(consoleErrorSpy).toHaveBeenCalledWith( + 'Failed to fetch location: Error' + ) + }) +}) diff --git a/src/components/Location/index.tsx b/src/components/Location/index.tsx index 1e4678a0..2b1173f2 100644 --- a/src/components/Location/index.tsx +++ b/src/components/Location/index.tsx @@ -1,6 +1,6 @@ import { useStore } from '@nanostores/react' import { $location } from '@stores/location' -import { formatDistance } from 'date-fns' +import { formatDistanceToNowStrict } from 'date-fns' import { LocationItem } from './LocationItem' import styles from './index.module.css' @@ -30,9 +30,9 @@ export default function Location() { country={data.next.country} countryCode={data.next.country_code} city={data.next.city} - time={formatDistance( + time={formatDistanceToNowStrict( new Date(data.next.date_start), - Date.now() + { addSuffix: true } )} showFlag={data.now.country !== data.next.country} />