Mo tests
This commit is contained in:
46
frontend/src/tests/app.test.tsx
Normal file
46
frontend/src/tests/app.test.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import App from '../App';
|
||||
|
||||
let fetchMock: ReturnType<typeof vi.fn>;
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock = vi.fn();
|
||||
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
||||
fetchMock.mockReturnValue(
|
||||
Promise.resolve({ ok: true, json: () => Promise.resolve([]) } as Response)
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const renderApp = (initialRoute = '/') => {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: { queries: { retry: false } },
|
||||
});
|
||||
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<MemoryRouter initialEntries={[initialRoute]}>
|
||||
<App />
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('App routing', () => {
|
||||
|
||||
it('should render the Home page on "/"', async () => {
|
||||
renderApp('/');
|
||||
expect(await screen.findByText('kohngrüti')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should redirect unknown routes to Home', async () => {
|
||||
renderApp('/some/random/path');
|
||||
expect(await screen.findByText('kohngrüti')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
27
frontend/src/tests/button.test.tsx
Normal file
27
frontend/src/tests/button.test.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import Button from '../components/button';
|
||||
|
||||
describe('Button', () => {
|
||||
|
||||
it('should render with the provided label', () => {
|
||||
render(<Button onClick={() => {}} isLoading={false} label="Click Me" />);
|
||||
expect(screen.getByRole('button', { name: 'Click Me' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show "Working..." when isLoading is true', () => {
|
||||
render(<Button onClick={() => {}} isLoading={true} label="Click Me" />);
|
||||
expect(screen.getByRole('button', { name: 'Working...' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call onClick when clicked', async () => {
|
||||
const handleClick = vi.fn();
|
||||
render(<Button onClick={handleClick} isLoading={false} label="Click Me" />);
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
expect(handleClick).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
});
|
||||
1
frontend/src/tests/setup.ts
Normal file
1
frontend/src/tests/setup.ts
Normal file
@@ -0,0 +1 @@
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
107
frontend/src/tests/stickies.test.tsx
Normal file
107
frontend/src/tests/stickies.test.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import Stickies from '../components/stickies';
|
||||
import { createTestWrapper } from './test-wrapper';
|
||||
|
||||
const MOCK_STICKIES = [
|
||||
{ id: 'note_001', text: 'Login flow feels confusing', x: 193, y: 191, author: 'user_5', color: 'yellow' },
|
||||
{ id: 'note_002', text: 'Export takes too long', x: 798, y: 211, author: 'user_2', color: 'green' },
|
||||
];
|
||||
|
||||
const MOCK_CLUSTERS = [
|
||||
{ label: 'Auth Issues', noteIds: ['note_001'] },
|
||||
{ label: 'Export Issues', noteIds: ['note_002'] },
|
||||
];
|
||||
|
||||
let fetchMock: ReturnType<typeof vi.fn>;
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock = vi.fn();
|
||||
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const mockFetchOk = (data: unknown) =>
|
||||
Promise.resolve({ ok: true, json: () => Promise.resolve(data) } as Response);
|
||||
|
||||
const mockFetchFail = () =>
|
||||
Promise.resolve({ ok: false, status: 500, json: () => Promise.resolve({}) } as Response);
|
||||
|
||||
|
||||
describe('Stickies', () => {
|
||||
|
||||
it('should show a loading indicator while fetching notes', () => {
|
||||
// Fetch never resolves — stays in loading state
|
||||
fetchMock.mockReturnValue(new Promise(() => {}));
|
||||
const { Wrapper } = createTestWrapper();
|
||||
|
||||
render(<Stickies />, { wrapper: Wrapper });
|
||||
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render all sticky notes after fetch succeeds', async () => {
|
||||
fetchMock.mockReturnValue(mockFetchOk(MOCK_STICKIES));
|
||||
const { Wrapper } = createTestWrapper();
|
||||
|
||||
render(<Stickies />, { wrapper: Wrapper });
|
||||
|
||||
expect(await screen.findByText('Login flow feels confusing')).toBeInTheDocument();
|
||||
expect(screen.getByText('Export takes too long')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the cluster button', async () => {
|
||||
fetchMock.mockReturnValue(mockFetchOk(MOCK_STICKIES));
|
||||
const { Wrapper } = createTestWrapper();
|
||||
|
||||
render(<Stickies />, { wrapper: Wrapper });
|
||||
|
||||
expect(await screen.findByRole('button', { name: 'Group Stickies By Topic' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show an error message when fetching notes fails', async () => {
|
||||
fetchMock.mockReturnValue(mockFetchFail());
|
||||
const { Wrapper } = createTestWrapper();
|
||||
|
||||
render(<Stickies />, { wrapper: Wrapper });
|
||||
|
||||
expect(await screen.findByText(/Error:/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show cluster labels after clustering succeeds', async () => {
|
||||
// First call = GET notes, second call = POST cluster
|
||||
fetchMock
|
||||
.mockReturnValueOnce(mockFetchOk(MOCK_STICKIES))
|
||||
.mockReturnValueOnce(mockFetchOk(MOCK_CLUSTERS));
|
||||
|
||||
const { Wrapper } = createTestWrapper();
|
||||
render(<Stickies />, { wrapper: Wrapper });
|
||||
|
||||
const btn = await screen.findByRole('button', { name: 'Group Stickies By Topic' });
|
||||
await userEvent.click(btn);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Auth Issues')).toBeInTheDocument();
|
||||
expect(screen.getByText('Export Issues')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should still render sticky note text inside clusters', async () => {
|
||||
fetchMock
|
||||
.mockReturnValueOnce(mockFetchOk(MOCK_STICKIES))
|
||||
.mockReturnValueOnce(mockFetchOk(MOCK_CLUSTERS));
|
||||
|
||||
const { Wrapper } = createTestWrapper();
|
||||
render(<Stickies />, { wrapper: Wrapper });
|
||||
|
||||
const btn = await screen.findByRole('button', { name: 'Group Stickies By Topic' });
|
||||
await userEvent.click(btn);
|
||||
|
||||
expect(await screen.findByText('Login flow feels confusing')).toBeInTheDocument();
|
||||
expect(screen.getByText('Export takes too long')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user