fix(frontend): prevent RangeError in TimeAdjuster and add validation to SleepButton
Build Frontend / build (push) Failing after 3m15s

This commit is contained in:
2026-06-02 21:20:38 +02:00
parent 13bc53ea59
commit c371a3d8e8
5 changed files with 53 additions and 0 deletions
@@ -10,6 +10,10 @@ const SleepButton: React.FC<SleepButtonProps> = ({ time }) => {
const isSleeping = !!activeSession;
const handleClick = async () => {
if (!time) {
alert('Please select a valid time.');
return;
}
try {
if (isSleeping && activeSession?.id) {
await endSession({ sessionId: activeSession.id, endTime: time });
+3
View File
@@ -90,6 +90,9 @@ export function formatDateTime(date: Date | string): string {
*/
export function toUTCFromLocalInput(inputValue: string): string {
const d = new Date(inputValue);
if (isNaN(d.getTime())) {
return "";
}
return d.toISOString();
}
+16
View File
@@ -70,4 +70,20 @@ describe('SleepButton', () => {
await waitFor(() => expect(endSessionMock).toHaveBeenCalled());
});
it('shows alert when time is invalid', async () => {
const alertSpy = vi.spyOn(window, 'alert').mockImplementation(() => {});
(useSleepSession as any).mockReturnValue({
activeSession: null,
isCreating: false,
isEnding: false,
});
renderWithProviders(<SleepButton time="" />);
const button = screen.getByRole('button', { name: /Start Sleep/i });
fireEvent.click(button);
expect(alertSpy).toHaveBeenCalledWith('Please select a valid time.');
alertSpy.mockRestore();
});
});
+14
View File
@@ -29,4 +29,18 @@ describe('TimeAdjuster', () => {
fireEvent.click(resetButton);
expect(handleChange).toHaveBeenCalled();
});
it('handles invalid date input gracefully (returns empty string)', async () => {
// Since we changed the implementation, it should no longer throw.
// We can't easily test the useEffect error anymore because it doesn't throw,
// but we can check if onTimeChange is called with "" for invalid input.
const handleChange = vi.fn();
const { container } = render(<TimeAdjuster onTimeChange={handleChange} />);
const input = container.querySelector('input');
fireEvent.change(input!, { target: { value: '2026-06-0' } });
// We might need to wait for the effect
await new Promise((r) => setTimeout(r, 0));
expect(handleChange).toHaveBeenCalledWith("");
});
});
+16
View File
@@ -12,6 +12,7 @@ import {
adjustForTimezone,
getLocalOffsetFromReference,
formatDateTime,
toUTCFromLocalInput,
} from '../../src/utils/time';
describe('formatMinutesAfter', () => {
@@ -152,3 +153,18 @@ describe('getLocalOffsetFromReference', () => {
expect(offset).toBe(localMins - refMins);
});
});
describe('toUTCFromLocalInput', () => {
it('converts valid datetime-local string to ISO UTC string', () => {
const input = '2024-01-15T10:00';
// This is tricky because it depends on local timezone.
// But we just want to see if it works for a valid input.
const result = toUTCFromLocalInput(input);
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/);
});
it('returns empty string on invalid datetime-local string', () => {
expect(toUTCFromLocalInput('2026-06-0')).toBe('');
});
});