- CI: workflows updates (cd, ci), remove playwright.yml - E2E: global-setup, auth/playlists/profile specs - Remove playwright-report and test-results artifacts from tracking - Backend: auth, handlers, services, workers, migrations - Frontend: components, features, vite config - Add e2e-results.json to gitignore - Docs: REMEDIATION_PROGRESS, audit archive - Rust: chat-server, stream-server updates
146 lines
3.5 KiB
TypeScript
146 lines
3.5 KiB
TypeScript
import { renderHook, act, render, screen } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { ToastProvider, useToast } from '../components/feedback/ToastProvider';
|
|
import { ReactNode } from 'react';
|
|
|
|
// Mock toast to avoid react-hot-toast dynamic import issues in Vitest
|
|
vi.mock('@/utils/toast', () => {
|
|
const mockFn = (msg: string) => {
|
|
const el = document.createElement('div');
|
|
el.textContent = msg;
|
|
el.setAttribute('data-testid', 'toast-message');
|
|
document.body.appendChild(el);
|
|
};
|
|
return {
|
|
default: Object.assign(mockFn, {
|
|
success: mockFn,
|
|
error: mockFn,
|
|
warning: mockFn,
|
|
loading: mockFn,
|
|
custom: mockFn,
|
|
dismiss: vi.fn(),
|
|
remove: vi.fn(),
|
|
promise: vi.fn(() => Promise.resolve()),
|
|
}),
|
|
};
|
|
});
|
|
|
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
<ToastProvider>{children}</ToastProvider>
|
|
);
|
|
|
|
describe('ToastContext', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
document.querySelectorAll('[data-testid="toast-message"]').forEach((el) => el.remove());
|
|
});
|
|
|
|
it('should provide toast context', () => {
|
|
const { result } = renderHook(() => useToast(), { wrapper });
|
|
|
|
expect(result.current).toBeDefined();
|
|
expect(result.current).toHaveProperty('addToast');
|
|
expect(typeof result.current.addToast).toBe('function');
|
|
});
|
|
|
|
it('should add toast', () => {
|
|
const TestComponent = () => {
|
|
const { addToast } = useToast();
|
|
return (
|
|
<div>
|
|
<button onClick={() => addToast('Test message', 'info')}>
|
|
Add Toast
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
render(
|
|
<ToastProvider>
|
|
<TestComponent />
|
|
</ToastProvider>,
|
|
);
|
|
|
|
const button = screen.getByText('Add Toast');
|
|
act(() => {
|
|
button.click();
|
|
});
|
|
|
|
// Toast should be added to the DOM
|
|
expect(screen.getByText('Test message')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should add success toast', () => {
|
|
const TestComponent = () => {
|
|
const { addToast } = useToast();
|
|
return (
|
|
<div>
|
|
<button onClick={() => addToast('Success!', 'success')}>
|
|
Add Success
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
render(
|
|
<ToastProvider>
|
|
<TestComponent />
|
|
</ToastProvider>,
|
|
);
|
|
|
|
const button = screen.getByText('Add Success');
|
|
act(() => {
|
|
button.click();
|
|
});
|
|
|
|
expect(screen.getByText('Success!')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should add error toast', () => {
|
|
const TestComponent = () => {
|
|
const { addToast } = useToast();
|
|
return (
|
|
<div>
|
|
<button onClick={() => addToast('Error!', 'error')}>Add Error</button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
render(
|
|
<ToastProvider>
|
|
<TestComponent />
|
|
</ToastProvider>,
|
|
);
|
|
|
|
const button = screen.getByText('Add Error');
|
|
act(() => {
|
|
button.click();
|
|
});
|
|
|
|
expect(screen.getByText('Error!')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should use default type info when type not provided', () => {
|
|
const TestComponent = () => {
|
|
const { addToast } = useToast();
|
|
return (
|
|
<div>
|
|
<button onClick={() => addToast('Info message')}>Add Info</button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
render(
|
|
<ToastProvider>
|
|
<TestComponent />
|
|
</ToastProvider>,
|
|
);
|
|
|
|
const button = screen.getByText('Add Info');
|
|
act(() => {
|
|
button.click();
|
|
});
|
|
|
|
expect(screen.getByText('Info message')).toBeInTheDocument();
|
|
});
|
|
});
|