WellNuo/__tests__/components/ScreenLoading.test.tsx
Sergei 2b36f801f1 Add comprehensive loading state management system
- Add useLoadingState hook with data/loading/error state management
- Add useSimpleLoading hook for basic boolean loading state
- Add useMultipleLoadingStates hook for tracking multiple items
- Create Skeleton component with shimmer animation for placeholders
- Create specialized skeletons: SkeletonText, SkeletonAvatar, SkeletonCard,
  SkeletonListItem, SkeletonBeneficiaryCard, SkeletonSensorCard
- Create LoadingOverlay components: modal, inline, and card variants
- Create ScreenLoading wrapper with loading/error/content states
- Create RefreshableScreen with built-in pull-to-refresh
- Create EmptyState and LoadingButtonState utility components
- Add comprehensive tests for all components and hooks (61 tests passing)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-01 10:11:14 -08:00

169 lines
4.7 KiB
TypeScript

import React from 'react';
import { Text, View } from 'react-native';
import { render, fireEvent } from '@testing-library/react-native';
import {
ScreenLoading,
RefreshableScreen,
EmptyState,
LoadingButtonState,
} from '@/components/ui/ScreenLoading';
describe('ScreenLoading', () => {
it('renders children when not loading and no error', () => {
const { getByText } = render(
<ScreenLoading isLoading={false} error={null}>
<Text>Content</Text>
</ScreenLoading>
);
expect(getByText('Content')).toBeTruthy();
});
it('renders loading state when isLoading is true', () => {
const { getByText } = render(
<ScreenLoading isLoading={true} error={null}>
<Text>Content</Text>
</ScreenLoading>
);
expect(getByText('Loading...')).toBeTruthy();
});
it('renders custom loading message', () => {
const { getByText } = render(
<ScreenLoading
isLoading={true}
error={null}
loadingMessage="Fetching data..."
>
<Text>Content</Text>
</ScreenLoading>
);
expect(getByText('Fetching data...')).toBeTruthy();
});
it('renders error state when error is provided', () => {
const { getByText } = render(
<ScreenLoading isLoading={false} error="Network error">
<Text>Content</Text>
</ScreenLoading>
);
expect(getByText('Something went wrong')).toBeTruthy();
expect(getByText('Network error')).toBeTruthy();
});
it('renders retry button when onRetry is provided', () => {
const onRetry = jest.fn();
const { getByText } = render(
<ScreenLoading isLoading={false} error="Error" onRetry={onRetry}>
<Text>Content</Text>
</ScreenLoading>
);
expect(getByText('Try Again')).toBeTruthy();
});
it('calls onRetry when retry button is pressed', () => {
const onRetry = jest.fn();
const { getByText } = render(
<ScreenLoading isLoading={false} error="Error" onRetry={onRetry}>
<Text>Content</Text>
</ScreenLoading>
);
fireEvent.press(getByText('Try Again'));
expect(onRetry).toHaveBeenCalledTimes(1);
});
it('does not render retry button when onRetry is not provided', () => {
const { queryByText } = render(
<ScreenLoading isLoading={false} error="Error">
<Text>Content</Text>
</ScreenLoading>
);
expect(queryByText('Try Again')).toBeNull();
});
});
describe('RefreshableScreen', () => {
it('renders children', () => {
const onRefresh = jest.fn();
const { getByText } = render(
<RefreshableScreen isRefreshing={false} onRefresh={onRefresh}>
<Text>Content</Text>
</RefreshableScreen>
);
expect(getByText('Content')).toBeTruthy();
});
});
describe('EmptyState', () => {
it('renders title and description', () => {
const { getByText } = render(
<EmptyState
title="No items"
description="Add some items to get started"
/>
);
expect(getByText('No items')).toBeTruthy();
expect(getByText('Add some items to get started')).toBeTruthy();
});
it('renders action button when provided', () => {
const onAction = jest.fn();
const { getByText } = render(
<EmptyState
title="No items"
actionLabel="Add Item"
onAction={onAction}
/>
);
expect(getByText('Add Item')).toBeTruthy();
});
it('calls onAction when action button is pressed', () => {
const onAction = jest.fn();
const { getByText } = render(
<EmptyState
title="No items"
actionLabel="Add Item"
onAction={onAction}
/>
);
fireEvent.press(getByText('Add Item'));
expect(onAction).toHaveBeenCalledTimes(1);
});
it('does not render action button when onAction is not provided', () => {
const { queryByText } = render(
<EmptyState title="No items" actionLabel="Add Item" />
);
expect(queryByText('Add Item')).toBeNull();
});
});
describe('LoadingButtonState', () => {
it('renders children when not loading', () => {
const { getByText } = render(
<LoadingButtonState isLoading={false}>
<Text>Submit</Text>
</LoadingButtonState>
);
expect(getByText('Submit')).toBeTruthy();
});
it('renders loading state when isLoading is true', () => {
const { getByText } = render(
<LoadingButtonState isLoading={true}>
<Text>Submit</Text>
</LoadingButtonState>
);
expect(getByText('Loading...')).toBeTruthy();
});
it('renders custom loading text', () => {
const { getByText } = render(
<LoadingButtonState isLoading={true} loadingText="Saving...">
<Text>Submit</Text>
</LoadingButtonState>
);
expect(getByText('Saving...')).toBeTruthy();
});
});