Add migration script and work on tests
This commit is contained in:
@@ -0,0 +1,108 @@
|
|||||||
|
import sqlite3
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
SOURCE_DB = 'backend/data/upload.db'
|
||||||
|
DEST_DB = 'backend/data/sleep.db'
|
||||||
|
|
||||||
|
def migrate():
|
||||||
|
try:
|
||||||
|
src_conn = sqlite3.connect(SOURCE_DB)
|
||||||
|
src_cur = src_conn.cursor()
|
||||||
|
|
||||||
|
dest_conn = sqlite3.connect(DEST_DB)
|
||||||
|
dest_cur = dest_conn.cursor()
|
||||||
|
|
||||||
|
print(f"Connecting to {SOURCE_DB} and {DEST_DB}...")
|
||||||
|
|
||||||
|
# 1. Truncate the destination table
|
||||||
|
print("Truncating sleep_session table...")
|
||||||
|
dest_cur.execute("DELETE FROM sleep_session")
|
||||||
|
dest_conn.commit()
|
||||||
|
|
||||||
|
# Fetch all records from the Sleep table
|
||||||
|
print("Fetching records from source...")
|
||||||
|
src_cur.execute('SELECT "Time", "Duration", "Note" FROM "Sleep"')
|
||||||
|
rows = src_cur.fetchall()
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
print("No records found in source Sleep table.")
|
||||||
|
return
|
||||||
|
|
||||||
|
migrated_count = 0
|
||||||
|
error_count = 0
|
||||||
|
now = datetime.now()
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
timestamp_seconds, duration_minutes, note = row
|
||||||
|
|
||||||
|
# Convert Unix timestamp to datetime object
|
||||||
|
try:
|
||||||
|
start_time = datetime.fromtimestamp(timestamp_seconds)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error converting timestamp {timestamp_seconds}: {e}")
|
||||||
|
error_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Calculate end time based on duration (NOW ASSUMED MINUTES)
|
||||||
|
end_time = start_time + timedelta(minutes=duration_minutes)
|
||||||
|
|
||||||
|
# VERIFICATION 1: Check if conversion matches source duration
|
||||||
|
actual_duration_minutes = (end_time - start_time).total_seconds() / 60.0
|
||||||
|
if abs(actual_duration_minutes - duration_minutes) > 0.1:
|
||||||
|
print(f"CRITICAL ERROR: Duration mismatch for timestamp {timestamp_seconds}. Source (min): {duration_minutes}, Calculated (min): {actual_duration_minutes}")
|
||||||
|
error_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
notes = note if note is not None else ""
|
||||||
|
|
||||||
|
# Insert the new record
|
||||||
|
try:
|
||||||
|
dest_cur.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO sleep_session (start_time, end_time, notes, created_at, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
start_time.strftime('%Y-%m-%d %H:%M:%S.%f'),
|
||||||
|
end_time.strftime('%Y-%m-%d %H:%M:%S.%f'),
|
||||||
|
notes,
|
||||||
|
now.strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
now.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
migrated_count += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to insert record for timestamp {timestamp_seconds}: {e}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
dest_conn.commit()
|
||||||
|
print(f"Migration complete.")
|
||||||
|
print(f"Successfully migrated: {migrated_count}")
|
||||||
|
print(f"Errors encountered: {error_count}")
|
||||||
|
|
||||||
|
# 2. FINAL VERIFICATION
|
||||||
|
print("Running final verification...")
|
||||||
|
dest_cur.execute("SELECT start_time, end_time FROM sleep_session")
|
||||||
|
dest_rows = dest_cur.fetchall()
|
||||||
|
|
||||||
|
if len(dest_rows) != migrated_count:
|
||||||
|
print(f"VERIFICATION FAILED: Count mismatch. Source attempted: {migrated_count}, Destination count: {len(dest_rows)}")
|
||||||
|
else:
|
||||||
|
print("VERIFICATION SUCCESS: Count matches.")
|
||||||
|
|
||||||
|
# Sample duration verification in destination
|
||||||
|
print("Verifying sample durations from destination...")
|
||||||
|
for i, (st_str, et_str) in enumerate(dest_rows[:5]):
|
||||||
|
st = datetime.strptime(st_str, '%Y-%m-%d %H:%M:%S.%f')
|
||||||
|
et = datetime.strptime(et_str, '%Y-%m-%d %H:%M:%S.%f')
|
||||||
|
duration_sec = (et - st).total_seconds()
|
||||||
|
print(f" Sample {i+1}: Start={st_str}, End={et_str}, Duration={duration_sec/60.0:.1f}m")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred during migration: {e}")
|
||||||
|
finally:
|
||||||
|
if 'src_conn' in locals(): src_conn.close()
|
||||||
|
if 'dest_conn' in locals(): dest_conn.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
migrate()
|
||||||
Generated
+685
-2577
File diff suppressed because it is too large
Load Diff
+23
-22
@@ -7,35 +7,36 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "vitest run",
|
"test": "DEBUG_PRINT_LIMIT=0 vitest run --reporter=dot --no-color",
|
||||||
"test:all": "vitest run && npx playwright test",
|
"test:all": "vitest run && npx playwright test",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-query": "^5.0.0",
|
"@tanstack/react-query": "^5.100.5",
|
||||||
"lucide-react": "^0.470.0",
|
"lucide-react": "^1.11.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.2.5",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.2.5",
|
||||||
"react-router-dom": "^7.1.0",
|
"react-router-dom": "^7.14.2",
|
||||||
"recharts": "^2.15.0"
|
"recharts": "^3.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.59.1",
|
"@playwright/test": "^1.59.1",
|
||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.2.4",
|
||||||
"@testing-library/jest-dom": "^6.6.0",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.1.0",
|
"@testing-library/react": "^16.3.2",
|
||||||
"@testing-library/user-event": "^14.5.0",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/lodash": "^4.17.24",
|
"@types/lodash": "^4.17.24",
|
||||||
"@types/react": "^18.3.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react": "^19.2.14",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitest/ui": "^2.1.0",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"@vitest/ui": "^4.1.5",
|
||||||
"jsdom": "^29.0.2",
|
"autoprefixer": "^10.5.0",
|
||||||
"postcss": "^8.4.49",
|
"jsdom": "^29.1.0",
|
||||||
"tailwindcss": "^4.0.0",
|
"postcss": "^8.5.12",
|
||||||
"typescript": "^5.7.0",
|
"tailwindcss": "^4.2.4",
|
||||||
"vite": "^6.0.0",
|
"typescript": "^6.0.3",
|
||||||
"vitest": "2.1.9"
|
"vite": "^8.0.10",
|
||||||
|
"vitest": "^4.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
> baby-sleep-tracker-frontend@0.1.0 test
|
||||||
|
> DEBUG_PRINT_LIMIT=0 vitest run --reporter=dot --no-color
|
||||||
|
|
||||||
|
|
||||||
|
RUN v4.1.5 /Users/jhag/projects/babymonitor/frontend
|
||||||
|
|
||||||
|
··································xxx····
|
||||||
|
|
||||||
|
Test Files 1 failed | 6 passed (7)
|
||||||
|
Tests 3 failed | 38 passed (41)
|
||||||
|
Start at 15:55:21
|
||||||
|
Duration 924ms (transform 166ms, setup 0ms, import 600ms, tests 173ms, environment 4.31s)
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { vi, describe, it, expect } from 'vitest';
|
||||||
|
import Timetable from './SleepTimetable';
|
||||||
|
import { useStats } from '../../hooks/useStats';
|
||||||
|
|
||||||
|
vi.mock('../../hooks/useStats', () => ({
|
||||||
|
useStats: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('SleepTimetable', () => {
|
||||||
|
const defaultProps = {
|
||||||
|
from_date: '2025-04-20',
|
||||||
|
to_date: '2025-04-21',
|
||||||
|
day_start: '22:00',
|
||||||
|
day_end: '08:00',
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders loading state', () => {
|
||||||
|
(useStats as any).mockReturnValue({ timetable: null, isLoading: true });
|
||||||
|
render(<Timetable {...defaultProps} />);
|
||||||
|
expect(screen.getByText(/Loading timetable.../i)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders empty state when no data is available', () => {
|
||||||
|
(useStats as any).mockReturnValue({ timetable: { slots: [] }, isLoading: false });
|
||||||
|
render(<Timetable {...defaultProps} />);
|
||||||
|
expect(screen.getByText(/No data available/i)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the grid correctly with hourly rows and biennial labels', () => {
|
||||||
|
(useStats as any).mockReturnValue({
|
||||||
|
timetable: {
|
||||||
|
slots: [
|
||||||
|
{
|
||||||
|
date: '2025-04-20',
|
||||||
|
sleeping: true,
|
||||||
|
slot_start: '01:00',
|
||||||
|
slot_end: '05:00',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
isLoading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<Timetable {...defaultProps} />);
|
||||||
|
|
||||||
|
// Check for day headers
|
||||||
|
expect(screen.getByText(/SUN/i)).toBeInTheDocument(); // 2025-04-20 is Sunday
|
||||||
|
expect(screen.getByText(/MON/i)).toBeInTheDocument(); // 2025-04-21 is Monday
|
||||||
|
|
||||||
|
// Check for time labels (every 2 hours: 00, 02, 04...)
|
||||||
|
expect(screen.getByText('00:00')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('02:00')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('04:00')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('22:00')).toBeInTheDocument();
|
||||||
|
|
||||||
|
// Verify non-labeled hours (every hour that isn't %120 == 0)
|
||||||
|
// We can't easily check for empty text nodes in Vitest/RTL without more precision
|
||||||
|
// but we can check that 01:00 is NOT present as a text label
|
||||||
|
expect(screen.queryByText('01:00')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('colors sleeping intervals correctly', () => {
|
||||||
|
(useStats as any).mockReturnValue({
|
||||||
|
timetable: {
|
||||||
|
slots: [
|
||||||
|
{
|
||||||
|
date: '2025-04-20',
|
||||||
|
sleeping: true,
|
||||||
|
slot_start: '01:00',
|
||||||
|
slot_end: '03:00', // Covers 01:00 and 02:00
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
isLoading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = render(<Timetable {...defaultProps} />);
|
||||||
|
|
||||||
|
// We are looking for the grid cells.
|
||||||
|
// Since they don't have text, we look at their classes/backgrounds.
|
||||||
|
const cells = container.querySelectorAll('.h-8');
|
||||||
|
// Total cells = 24 rows * (1 label col + 2 days) = 72? No, the structure is:
|
||||||
|
// Header row has cells. Time grid rows have (1 label + 2 days) = 3 cells each.
|
||||||
|
// Total elements with .h-8: 1 (header corner) + days.length * 1 (day headers) + 24 * 3 = 75?
|
||||||
|
// Actually, the code has:
|
||||||
|
// Header row: header corner + days.map -> 1 + 2 = 3 cells
|
||||||
|
// Time Rows: (label cell) + days.map -> 24 * 3 = 72 cells
|
||||||
|
// Total = 75.
|
||||||
|
|
||||||
|
// The sleeping cell for 01:00 on 2025-04-20 should be bg-green-500
|
||||||
|
// The cell for 02:00 on 2025-04-20 should be bg-green-500
|
||||||
|
// The cell for 03:00 on 2025-04-20 should be bg-gray-50
|
||||||
|
// Let's just check if ANY cell has bg-green-500 and ALL non-sleeping have bg-gray-50
|
||||||
|
|
||||||
|
const greenCells = container.querySelectorAll('.bg-green-500');
|
||||||
|
expect(greenCells.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
const grayCells = container.querySelectorAll('.bg-gray-50');
|
||||||
|
expect(grayCells.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useStats } from '../../hooks/useStats';
|
import { useStats } from '../../hooks/useStats';
|
||||||
import { timeToMinutes, formatMinutesAfter } from '../../utils/time';
|
import { timeToMinutes } from '../../utils/time';
|
||||||
|
|
||||||
interface TimetableProps {
|
interface TimetableProps {
|
||||||
from_date: string;
|
from_date: string;
|
||||||
@@ -25,7 +25,7 @@ const Timetable: React.FC<TimetableProps> = ({ from_date, to_date, day_start, da
|
|||||||
}, [from_date, to_date]);
|
}, [from_date, to_date]);
|
||||||
|
|
||||||
const timeSteps = useMemo(() => {
|
const timeSteps = useMemo(() => {
|
||||||
return Array.from({ length: 12 }, (_, i) => i * 120);
|
return Array.from({ length: 24 }, (_, i) => i * 60);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (isLoading) return <div className="text-center p-4">Loading timetable...</div>;
|
if (isLoading) return <div className="text-center p-4">Loading timetable...</div>;
|
||||||
@@ -62,9 +62,6 @@ const Timetable: React.FC<TimetableProps> = ({ from_date, to_date, day_start, da
|
|||||||
|
|
||||||
const currentMins = new Date().getHours() * 60 + new Date().getMinutes();
|
const currentMins = new Date().getHours() * 60 + new Date().getMinutes();
|
||||||
|
|
||||||
// Total rows: 1 (header) + 12 (time steps) = 13
|
|
||||||
const totalRows = 13;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white p-4 rounded-xl shadow-sm border border-gray-200 overflow-x-auto">
|
<div className="bg-white p-4 rounded-xl shadow-sm border border-gray-200 overflow-x-auto">
|
||||||
<h3 className="text-lg font-semibold mb-4 text-gray-800">Sleep Timetable</h3>
|
<h3 className="text-lg font-semibold mb-4 text-gray-800">Sleep Timetable</h3>
|
||||||
@@ -87,7 +84,7 @@ const Timetable: React.FC<TimetableProps> = ({ from_date, to_date, day_start, da
|
|||||||
{/* Time Grid Container */}
|
{/* Time Grid Container */}
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div
|
<div
|
||||||
className="grid gap-px"
|
className="grid"
|
||||||
style={{
|
style={{
|
||||||
gridTemplateColumns: `4rem repeat(${days.length}, minmax(40px, 1fr))`
|
gridTemplateColumns: `4rem repeat(${days.length}, minmax(40px, 1fr))`
|
||||||
}}
|
}}
|
||||||
@@ -97,12 +94,12 @@ const Timetable: React.FC<TimetableProps> = ({ from_date, to_date, day_start, da
|
|||||||
<React.Fragment key={step}>
|
<React.Fragment key={step}>
|
||||||
{/* Time Label */}
|
{/* Time Label */}
|
||||||
<div className="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8">
|
<div className="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8">
|
||||||
{formatTimeLabel(step)}
|
{step % 120 === 0 ? formatTimeLabel(step) : ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Grid Cells */}
|
{/* Grid Cells */}
|
||||||
{days.map((day) => {
|
{days.map((day) => {
|
||||||
const sleeping = isSleepingInInterval(day, step, step + 120);
|
const sleeping = isSleepingInInterval(day, step, step + 60);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${day}-${step}`}
|
key={`${day}-${step}`}
|
||||||
@@ -114,6 +111,7 @@ const Timetable: React.FC<TimetableProps> = ({ from_date, to_date, day_start, da
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Red Marker Line */}
|
{/* Red Marker Line */}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="absolute left-[4rem] right-0 h-0.5 bg-red-500 pointer-events-none z-10"
|
className="absolute left-[4rem] right-0 h-0.5 bg-red-500 pointer-events-none z-10"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -0,0 +1,650 @@
|
|||||||
|
|
||||||
|
> baby-sleep-tracker-frontend@0.1.0 test
|
||||||
|
> vitest run --reporter=dot
|
||||||
|
|
||||||
|
|
||||||
|
RUN v2.1.9 /Users/jhag/projects/babymonitor/frontend
|
||||||
|
|
||||||
|
✓ tests/simple.test.ts (1 test) 1ms
|
||||||
|
✓ tests/unit/chartHelpers.test.ts (9 tests) 2ms
|
||||||
|
✓ tests/unit/time.test.ts (16 tests) 3ms
|
||||||
|
✓ tests/unit/StatusBanner.test.tsx (5 tests) 19ms
|
||||||
|
✓ tests/unit/TimeAdjuster.test.tsx (3 tests) 24ms
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx (4 tests | 3 failed) 42ms
|
||||||
|
× SleepTimetable > renders loading state 17ms
|
||||||
|
→ Invalid Chai property: toBeInTheDocument
|
||||||
|
× SleepTimetable > renders empty state when no data is available 1ms
|
||||||
|
→ Invalid Chai property: toBeInTheDocument
|
||||||
|
× SleepTimetable > renders the grid correctly with hourly rows and biennial labels 19ms
|
||||||
|
→ Unable to find an element with the text: SUN. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
[36m<body>[39m
|
||||||
|
[36m<div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"bg-white p-4 rounded-xl shadow-sm border border-gray-200 overflow-x-auto"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<h3[39m
|
||||||
|
[33mclass[39m=[32m"text-lg font-semibold mb-4 text-gray-800"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mSleep Timetable[0m
|
||||||
|
[36m</h3>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"min-w-[600px] flex flex-col gap-px"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"grid"[39m
|
||||||
|
[33mstyle[39m=[32m"grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[0m [0m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mSun[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mMon[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"relative"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"grid"[39m
|
||||||
|
[33mstyle[39m=[32m"grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m00:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m02:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m04:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m06:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m08:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m10:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m12:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m14:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m16:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m18:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m20:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m22:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"absolute left-[4rem] right-0 h-0.5 bg-red-500 pointer-events-none z-10"[39m
|
||||||
|
[33mstyle[39m=[32m"top: 84.02777777777779%; transform: translateY(-50%);"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</body>[39m
|
||||||
|
✓ tests/unit/SleepButton.test.tsx (3 tests) 62ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 3 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL src/components/stats/SleepTimetable.test.tsx > SleepTimetable > renders loading state
|
||||||
|
Error: Invalid Chai property: toBeInTheDocument
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx:21:53
|
||||||
|
19| (useStats as any).mockReturnValue({ timetable: null, isLoading: tr…
|
||||||
|
20| render(<Timetable {...defaultProps} />);
|
||||||
|
21| expect(screen.getByText(/Loading timetable.../i)).toBeInTheDocumen…
|
||||||
|
| ^
|
||||||
|
22| });
|
||||||
|
23|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/3]⎯
|
||||||
|
|
||||||
|
FAIL src/components/stats/SleepTimetable.test.tsx > SleepTimetable > renders empty state when no data is available
|
||||||
|
Error: Invalid Chai property: toBeInTheDocument
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx:27:50
|
||||||
|
25| (useStats as any).mockReturnValue({ timetable: { slots: [] }, isLo…
|
||||||
|
26| render(<Timetable {...defaultProps} />);
|
||||||
|
27| expect(screen.getByText(/No data available/i)).toBeInTheDocument();
|
||||||
|
| ^
|
||||||
|
28| });
|
||||||
|
29|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/3]⎯
|
||||||
|
|
||||||
|
FAIL src/components/stats/SleepTimetable.test.tsx > SleepTimetable > renders the grid correctly with hourly rows and biennial labels
|
||||||
|
TestingLibraryElementError: Unable to find an element with the text: SUN. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
[36m<body>[39m
|
||||||
|
[36m<div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"bg-white p-4 rounded-xl shadow-sm border border-gray-200 overflow-x-auto"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<h3[39m
|
||||||
|
[33mclass[39m=[32m"text-lg font-semibold mb-4 text-gray-800"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mSleep Timetable[0m
|
||||||
|
[36m</h3>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"min-w-[600px] flex flex-col gap-px"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"grid"[39m
|
||||||
|
[33mstyle[39m=[32m"grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[0m [0m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mSun[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mMon[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"relative"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"grid"[39m
|
||||||
|
[33mstyle[39m=[32m"grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m00:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m02:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m04:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-green-500"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m06:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m08:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m10:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m12:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m14:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m16:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m18:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m20:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m22:00[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"h-8 w-full bg-gray-50"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"absolute left-[4rem] right-0 h-0.5 bg-red-500 pointer-events-none z-10"[39m
|
||||||
|
[33mstyle[39m=[32m"top: 84.02777777777779%; transform: translateY(-50%);"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</body>[39m
|
||||||
|
❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:76:38
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:52:17
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx:48:19
|
||||||
|
46|
|
||||||
|
47| // Check for day headers
|
||||||
|
48| expect(screen.getByText('SUN')).toBeInTheDocument(); // 2025-04-20…
|
||||||
|
| ^
|
||||||
|
49| expect(screen.getByText('MON')).toBeInTheDocument(); // 2025-04-21…
|
||||||
|
50|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/3]⎯
|
||||||
|
|
||||||
|
Test Files 1 failed | 6 passed (7)
|
||||||
|
Tests 3 failed | 38 passed (41)
|
||||||
|
Start at 20:10:38
|
||||||
|
Duration 718ms (transform 173ms, setup 0ms, collect 475ms, tests 155ms, environment 2.78s, prepare 242ms)
|
||||||
|
|
||||||
@@ -0,0 +1,650 @@
|
|||||||
|
|
||||||
|
> baby-sleep-tracker-frontend@0.1.0 test
|
||||||
|
> vitest run --reporter=dot
|
||||||
|
|
||||||
|
|
||||||
|
RUN v2.1.9 /Users/jhag/projects/babymonitor/frontend
|
||||||
|
|
||||||
|
✓ tests/simple.test.ts (1 test) 1ms
|
||||||
|
✓ tests/unit/chartHelpers.test.ts (9 tests) 2ms
|
||||||
|
✓ tests/unit/time.test.ts (16 tests) 2ms
|
||||||
|
✓ tests/unit/StatusBanner.test.tsx (5 tests) 20ms
|
||||||
|
✓ tests/unit/TimeAdjuster.test.tsx (3 tests) 24ms
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx (4 tests | 3 failed) 41ms
|
||||||
|
× SleepTimetable > renders loading state 15ms
|
||||||
|
→ Invalid Chai property: toBeInTheDocument
|
||||||
|
× SleepTimetable > renders empty state when no data is available 1ms
|
||||||
|
→ Invalid Chai property: toBeInTheDocument
|
||||||
|
× SleepTimetable > renders the grid correctly with hourly rows and biennial labels 20ms
|
||||||
|
→ Unable to find an element with the text: SUN. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="bg-white p-4 rounded-xl shadow-sm border border-gray-200 overflow-x-auto"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-lg font-semibold mb-4 text-gray-800"
|
||||||
|
>
|
||||||
|
Sleep Timetable
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="min-w-[600px] flex flex-col gap-px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="grid"
|
||||||
|
style="grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-8"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"
|
||||||
|
>
|
||||||
|
Sun
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"
|
||||||
|
>
|
||||||
|
Mon
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="grid"
|
||||||
|
style="grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
00:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
02:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
04:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
06:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
08:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
10:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
12:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
14:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
16:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
18:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
20:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
22:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="absolute left-[4rem] right-0 h-0.5 bg-red-500 pointer-events-none z-10"
|
||||||
|
style="top: 84.16666666666667%; transform: translateY(-50%);"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
✓ tests/unit/SleepButton.test.tsx (3 tests) 62ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 3 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL src/components/stats/SleepTimetable.test.tsx > SleepTimetable > renders loading state
|
||||||
|
Error: Invalid Chai property: toBeInTheDocument
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx:21:53
|
||||||
|
19| (useStats as any).mockReturnValue({ timetable: null, isLoading: tr…
|
||||||
|
20| render(<Timetable {...defaultProps} />);
|
||||||
|
21| expect(screen.getByText(/Loading timetable.../i)).toBeInTheDocumen…
|
||||||
|
| ^
|
||||||
|
22| });
|
||||||
|
23|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/3]⎯
|
||||||
|
|
||||||
|
FAIL src/components/stats/SleepTimetable.test.tsx > SleepTimetable > renders empty state when no data is available
|
||||||
|
Error: Invalid Chai property: toBeInTheDocument
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx:27:50
|
||||||
|
25| (useStats as any).mockReturnValue({ timetable: { slots: [] }, isLo…
|
||||||
|
26| render(<Timetable {...defaultProps} />);
|
||||||
|
27| expect(screen.getByText(/No data available/i)).toBeInTheDocument();
|
||||||
|
| ^
|
||||||
|
28| });
|
||||||
|
29|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/3]⎯
|
||||||
|
|
||||||
|
FAIL src/components/stats/SleepTimetable.test.tsx > SleepTimetable > renders the grid correctly with hourly rows and biennial labels
|
||||||
|
TestingLibraryElementError: Unable to find an element with the text: SUN. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="bg-white p-4 rounded-xl shadow-sm border border-gray-200 overflow-x-auto"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-lg font-semibold mb-4 text-gray-800"
|
||||||
|
>
|
||||||
|
Sleep Timetable
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="min-w-[600px] flex flex-col gap-px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="grid"
|
||||||
|
style="grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-8"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"
|
||||||
|
>
|
||||||
|
Sun
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="text-center text-[10px] font-medium text-gray-500 uppercase flex items-center justify-center h-8"
|
||||||
|
>
|
||||||
|
Mon
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="grid"
|
||||||
|
style="grid-template-columns: 4rem repeat(2, minmax(40px, 1fr));"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
00:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
02:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
04:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-green-500"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
06:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
08:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
10:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
12:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
14:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
16:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
18:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
20:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
>
|
||||||
|
22:00
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="text-[10px] text-gray-400 flex items-center justify-end pr-2 h-8"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="h-8 w-full bg-gray-50"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="absolute left-[4rem] right-0 h-0.5 bg-red-500 pointer-events-none z-10"
|
||||||
|
style="top: 84.16666666666667%; transform: translateY(-50%);"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:76:38
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:52:17
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19
|
||||||
|
❯ src/components/stats/SleepTimetable.test.tsx:48:19
|
||||||
|
46|
|
||||||
|
47| // Check for day headers
|
||||||
|
48| expect(screen.getByText('SUN')).toBeInTheDocument(); // 2025-04-20…
|
||||||
|
| ^
|
||||||
|
49| expect(screen.getByText('MON')).toBeInTheDocument(); // 2025-04-21…
|
||||||
|
50|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/3]⎯
|
||||||
|
|
||||||
|
Test Files 1 failed | 6 passed (7)
|
||||||
|
Tests 3 failed | 38 passed (41)
|
||||||
|
Start at 20:12:08
|
||||||
|
Duration 722ms (transform 112ms, setup 0ms, collect 483ms, tests 153ms, environment 2.74s, prepare 226ms)
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
},
|
},
|
||||||
"types": ["vite/client"]
|
"types": ["vite/client", "vitest/globals"]
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ import path from 'path'
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), tailwindcss()],
|
plugins: [react(), tailwindcss()],
|
||||||
test: {
|
|
||||||
globals: true,
|
|
||||||
environment: 'jsdom',
|
|
||||||
include: ['src/**/*.{test,spec}.{ts,tsx}', 'tests/**/*.{test,spec}.{ts,tsx}'],
|
|
||||||
exclude: ['**/tests/e2e/**', '**/node_modules/**'],
|
|
||||||
},
|
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||||
|
import viteConfig from './vite.config'
|
||||||
|
|
||||||
|
export default mergeConfig(
|
||||||
|
viteConfig,
|
||||||
|
defineConfig({
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
setupFiles: ['./vitest.setup.ts'],
|
||||||
|
include: ['src/**/*.{test,spec}.{ts,tsx}', 'tests/**/*.{test,spec}.{ts,tsx}'],
|
||||||
|
exclude: ['**/tests/e2e/**', '**/node_modules/**'],
|
||||||
|
reporters: ['dot'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import '@testing-library/jest-dom/vitest';
|
||||||
Reference in New Issue
Block a user