diff --git a/package.json b/package.json
index 1813a99..7a4df94 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
- "test": "vitest run src/__tests__/BerlinClock.test.tsx",
+ "test": "vitest run src/__tests__/*",
"format": "eslint . --fix && prettier --write .",
"e2e": "cypress run",
"ci": "npm run format && npm run test && npm run e2e"
diff --git a/src/__tests__/DigitalClock.test.tsx b/src/__tests__/DigitalClock.test.tsx
index 0381d1e..20e53f5 100644
--- a/src/__tests__/DigitalClock.test.tsx
+++ b/src/__tests__/DigitalClock.test.tsx
@@ -1,8 +1,81 @@
-import { render } from '@testing-library/react';
+import { render, screen, fireEvent } from '@testing-library/react';
import { DigitalClock } from '../containers/DigitalClock';
+import * as utils from '../utils';
+
+vi.mock('../utils');
+
+const mockedDateToDigital = vi.mocked(utils.dateToDigital);
+const mockedDigitalToDate = vi.mocked(utils.digitalToDate);
describe('DigitalClock', () => {
- it('renders when enabled', () => {
- render();
+ const onTimeChangeMock = vi.fn();
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockedDateToDigital.mockReturnValue('14:30:15');
+ mockedDigitalToDate.mockImplementation((str: string) => {
+ const parts = str.split(':');
+ if (parts.length !== 3) return new Date(NaN);
+ const [h, m, s] = parts.map(Number);
+ if (isNaN(h) || isNaN(m) || isNaN(s)) return new Date(NaN);
+ const d = new Date(2025, 0, 1, 14, 30, 15);
+ d.setHours(h, m, s, 0);
+ return d;
+ });
+ });
+
+ it('renders nothing when disabled', () => {
+ const { container } = render(
+ ,
+ );
+ expect(container.innerHTML).toBe('');
+ });
+
+ it('renders the digital time and input when enabled', () => {
+ render(
+ ,
+ );
+ expect(screen.getByTestId('digital-clock')).toHaveTextContent('14:30:15');
+ expect(screen.getByTestId('time-input')).toBeInTheDocument();
+ });
+
+ it('calls onTimeChange when a valid time is entered', () => {
+ render(
+ ,
+ );
+ const input = screen.getByTestId('time-input');
+ fireEvent.change(input, { target: { value: '12:00:00' } });
+
+ expect(onTimeChangeMock).toHaveBeenCalledTimes(1);
+ const expectedDate = new Date(2025, 0, 1, 12, 0, 0, 0);
+ expect(onTimeChangeMock).toHaveBeenCalledWith(expectedDate);
+
+ expect(input).toHaveValue('12:00:00');
+ });
+
+ it('does not call onTimeChange when an invalid time is entered', () => {
+ render(
+ ,
+ );
+ const input = screen.getByTestId('time-input');
+ fireEvent.change(input, { target: { value: 'notatime' } });
+ expect(onTimeChangeMock).not.toHaveBeenCalled();
+ expect(input).toHaveValue('notatime');
});
});
diff --git a/src/__tests__/TimeConverter.test.tsx b/src/__tests__/TimeConverter.test.tsx
index cf4c3de..db0d02b 100644
--- a/src/__tests__/TimeConverter.test.tsx
+++ b/src/__tests__/TimeConverter.test.tsx
@@ -1,13 +1,56 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { TimeConverter } from '../containers/TimeConverter';
+import { useCurrentTime } from '../hooks/useCurrentTime';
+
+vi.mock('../hooks/useCurrentTime');
+vi.mock('../containers/BerlinClock', () => ({
+ BerlinClock: ({ enabled }: { enabled: boolean }) => (
+
{enabled ? 'enabled' : 'disabled'}
+ ),
+}));
+vi.mock('../containers/DigitalClock', () => ({
+ DigitalClock: ({ enabled, currentTime, onTimeChange }: { enabled: boolean; currentTime: Date; onTimeChange: (d: Date) => void }) => (
+
+ {currentTime.toISOString()}
+
+ {!enabled && disabled}
+
+ ),
+}));
+
+const mockedUseCurrentTime = vi.mocked(useCurrentTime);
describe('TimeConverter', () => {
- it('renders the toggle checkbox', () => {
- render();
- expect(screen.getByRole('checkbox')).toBeInTheDocument();
+ const setCurrentTimeMock = vi.fn();
+ const baseDate = new Date(2025, 0, 1, 14, 30, 15);
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockedUseCurrentTime.mockReturnValue({
+ currentTime: baseDate,
+ setCurrentTime: setCurrentTimeMock,
+ });
});
- it('disables clocks when checkbox is checked', () => {
+
+ it('renders the checkbox, BerlinClock, and DigitalClock', () => {
render();
- // TODO
+ expect(screen.getByTestId('use-system-time')).toBeInTheDocument();
+ expect(screen.getByTestId('berlin-clock')).toHaveTextContent('enabled');
+ expect(screen.getByTestId('digital-clock-wrapper')).toBeInTheDocument();
+ });
+
+ it('disables both clocks when checkbox is checked', () => {
+ render();
+ fireEvent.click(screen.getByTestId('use-system-time'));
+ expect(screen.getByTestId('berlin-clock')).toHaveTextContent('disabled');
+ expect(screen.getByTestId('disabled-indicator')).toBeInTheDocument();
+ });
+
+ it('calls setCurrentTime when DigitalClock triggers onTimeChange', () => {
+ render();
+ fireEvent.click(screen.getByTestId('set-time'));
+ expect(setCurrentTimeMock).toHaveBeenCalledWith(new Date(2025, 0, 1, 12, 0, 0));
});
});
diff --git a/src/containers/DigitalClock.tsx b/src/containers/DigitalClock.tsx
index 4408719..c97c4d0 100644
--- a/src/containers/DigitalClock.tsx
+++ b/src/containers/DigitalClock.tsx
@@ -1,13 +1,36 @@
import { useState } from 'react';
-import { useCurrentTime } from '../hooks/useCurrentTime';
-import { dateToDigital } from '../utils';
+import { dateToDigital, digitalToDate } from '../utils';
interface DigitalClockProps {
enabled: boolean;
+ currentTime: Date;
+ onTimeChange: (time: Date) => void;
}
-export function DigitalClock({ enabled }: DigitalClockProps) {
- const { currentTime } = useCurrentTime();
- const digital = dateToDigital(currentTime);
- return null;
+export function DigitalClock({ enabled, currentTime, onTimeChange }: DigitalClockProps) {
+ const [inputValue, setInputValue] = useState(dateToDigital(currentTime));
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const value = e.target.value;
+ setInputValue(value);
+ const date = digitalToDate(value);
+ if (!isNaN(date.getTime())) {
+ onTimeChange(date);
+ }
+ };
+
+ if (!enabled) return null;
+
+ return (
+
+ {dateToDigital(currentTime)}
+
+
+ );
}
diff --git a/src/containers/TimeConverter.tsx b/src/containers/TimeConverter.tsx
index 9e35a2e..d536573 100644
--- a/src/containers/TimeConverter.tsx
+++ b/src/containers/TimeConverter.tsx
@@ -4,7 +4,30 @@ import { DigitalClock } from './DigitalClock';
import { useCurrentTime } from '../hooks/useCurrentTime';
export function TimeConverter() {
+ const { currentTime, setCurrentTime } = useCurrentTime();
const [useSystemTime, setUseSystemTime] = useState(false);
- // When useSystemTime is true, both BerlinClock and DigitalClock are disabled.
- return null;
+
+ const handleTimeChange = (newTime: Date) => {
+ setCurrentTime(newTime);
+ };
+
+ return (
+
+
+
+
+
+ );
}