Not sure what happened here...
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const BASE_URL = 'http://localhost:5173';
|
||||
|
||||
test.describe('Component Playground', () => {
|
||||
test('playground route loads and shows component selector', async ({ page }) => {
|
||||
// Listen for console errors
|
||||
const errors: string[] = [];
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error') errors.push(msg.text());
|
||||
});
|
||||
|
||||
await page.goto(`${BASE_URL}/playground`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Take screenshot immediately after load to see what is actually there
|
||||
await page.screenshot({ path: 'playground_debug_load.png' });
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.log('Console errors detected:', errors);
|
||||
}
|
||||
|
||||
// Check heading using a more flexible approach
|
||||
const heading = page.getByRole('heading', { name: /Component Playground/i });
|
||||
await expect(heading).toBeVisible();
|
||||
|
||||
// Check if dropdown exists and is visible
|
||||
const select = page.locator('select#component-select');
|
||||
await expect(select).toBeVisible();
|
||||
|
||||
// Check if it has options (besides the placeholder)
|
||||
const optionCount = await select.locator('option').count();
|
||||
expect(optionCount).toBeGreaterThan(1);
|
||||
|
||||
// Take screenshot for visual confirmation
|
||||
await page.screenshot({ path: 'playground_loaded.png' });
|
||||
});
|
||||
|
||||
test('selecting a component renders it', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL}/playground`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const select = page.locator('select#component-select');
|
||||
|
||||
// Select 'StatusBanner' (assuming it is the first one in registry after placeholder)
|
||||
await select.selectOption({ label: 'StatusBanner' });
|
||||
|
||||
// Check if the main area is no longer showing "No component selected"
|
||||
const emptyState = page.locator('text=No component selected');
|
||||
await expect(emptyState).not.toBeVisible();
|
||||
|
||||
// Verify footer shows correct component name
|
||||
const footer = page.locator('footer');
|
||||
await expect(footer).toContainText('StatusBanner');
|
||||
|
||||
// Take screenshot of rendered component
|
||||
await page.screenshot({ path: 'playground_component_rendered.png' });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const BASE_URL = 'http://localhost:5173';
|
||||
|
||||
test.describe('Exhaustive Component Playground Tests', () => {
|
||||
test('every component in playground should render without console errors', async ({ page }) => {
|
||||
const errors: string[] = [];
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error') errors.push(msg.text());
|
||||
});
|
||||
|
||||
await page.goto(`${BASE_URL}/playground`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const select = page.locator('select#component-select');
|
||||
await expect(select).toBeVisible();
|
||||
|
||||
const optionCount = await select.locator('option').count();
|
||||
// The first option is '-- Select a Component --', so we iterate from index 1
|
||||
for (let i = 1; i < optionCount; i++) {
|
||||
const optionName = await select.locator('option').nth(i).textContent();
|
||||
if (!optionName) continue;
|
||||
|
||||
console.log(`Testing component: ${optionName}`);
|
||||
|
||||
// Select the component
|
||||
await select.selectOption({ index: i });
|
||||
|
||||
// Wait for potential re-renders and data fetching (even if mocked)
|
||||
await page.waitForTimeout(500);
|
||||
// Allow some time for useEffects and async mock injections to settle
|
||||
await page.waitForLoadState('networkidle').catch(() => {});
|
||||
|
||||
// Log the current HTML to debug why footer is missing
|
||||
const html = await page.content();
|
||||
console.log(`Current HTML length: ${html.length}`);
|
||||
if (!html.includes('id="playground-footer"')) {
|
||||
console.log('CRITICAL: id="playground-footer" not found in HTML');
|
||||
}
|
||||
|
||||
// Check if any errors were logged during the selection and render
|
||||
if (errors.length > 0) {
|
||||
// We check if the errors are actually related to the current component selection
|
||||
// For simplicity in this exhaustive test, any console error is a failure.
|
||||
throw new Error(`Console errors detected while rendering ${optionName}: ${errors.join(', ')}`);
|
||||
}
|
||||
|
||||
// Verify footer updated correctly
|
||||
const footer = page.locator('#playground-footer');
|
||||
await expect(footer).toBeVisible();
|
||||
await expect(footer).toContainText(optionName);
|
||||
}
|
||||
|
||||
expect(errors.length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { vi, describe, it, expect } from 'vitest';
|
||||
import Timetable from '../../../../src/components/stats/SleepTimetable';
|
||||
import { useStats } from '../../../../src/hooks/useStats';
|
||||
|
||||
vi.mock('../../../../src/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 1 hour: 00, 01, 02...)
|
||||
expect(screen.getByText('00:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('01:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('02:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('03:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('04:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('22:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('23:00')).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');
|
||||
|
||||
const greenCells = container.querySelectorAll('.bg-green-500');
|
||||
expect(greenCells.length).toBeGreaterThan(0);
|
||||
|
||||
const grayCells = container.querySelectorAll('.bg-gray-50');
|
||||
expect(grayCells.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user