fix(unit): fix more broken tests
This commit is contained in:
parent
994d80223e
commit
7f8cf8e078
|
|
@ -117,7 +117,7 @@ describe('GlobalSearchBar', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith({
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith({
|
||||||
query: 'test',
|
query: 'test',
|
||||||
limit: 5,
|
limit: 5,
|
||||||
include_snippets: false,
|
include_snippets: false,
|
||||||
|
|
@ -336,7 +336,7 @@ describe('GlobalSearchBar', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles search errors gracefully', async () => {
|
test('handles search errors gracefully', async () => {
|
||||||
documentService.enhancedSearch.mockRejectedValue(new Error('Search failed'));
|
mockDocumentService.enhancedSearch.mockRejectedValue(new Error('Search failed'));
|
||||||
|
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
renderWithRouter(<GlobalSearchBar />);
|
renderWithRouter(<GlobalSearchBar />);
|
||||||
|
|
@ -357,7 +357,7 @@ describe('GlobalSearchBar', () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
|
|
||||||
// Mock a delayed response
|
// Mock a delayed response
|
||||||
documentService.enhancedSearch.mockImplementation(() =>
|
mockDocumentService.enhancedSearch.mockImplementation(() =>
|
||||||
new Promise(resolve => setTimeout(() => resolve(mockSearchResponse), 100))
|
new Promise(resolve => setTimeout(() => resolve(mockSearchResponse), 100))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,25 @@ import Login from '../Login'
|
||||||
|
|
||||||
const mockLogin = vi.fn()
|
const mockLogin = vi.fn()
|
||||||
|
|
||||||
const MockAuthProvider = ({ children }: { children: React.ReactNode }) => {
|
// Mock the useAuth hook
|
||||||
return (
|
vi.mock('../../contexts/AuthContext', () => ({
|
||||||
<div>
|
useAuth: () => ({
|
||||||
{children}
|
login: mockLogin,
|
||||||
</div>
|
user: null,
|
||||||
)
|
loading: false,
|
||||||
}
|
logout: vi.fn(),
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
const renderWithMockAuth = (component: React.ReactNode, authContext = {}) => {
|
// Mock react-router-dom
|
||||||
return render(
|
vi.mock('react-router-dom', () => ({
|
||||||
<MockAuthProvider>
|
Link: ({ to, children }: { to: string; children: React.ReactNode }) => (
|
||||||
{component}
|
<a href={to}>{children}</a>
|
||||||
</MockAuthProvider>
|
),
|
||||||
)
|
}))
|
||||||
|
|
||||||
|
const renderLogin = () => {
|
||||||
|
return render(<Login />)
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Login', () => {
|
describe('Login', () => {
|
||||||
|
|
@ -26,7 +31,7 @@ describe('Login', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('renders login form', () => {
|
test('renders login form', () => {
|
||||||
renderWithMockAuth(<Login />, { login: mockLogin })
|
renderLogin()
|
||||||
|
|
||||||
expect(screen.getByText('Sign in to Readur')).toBeInTheDocument()
|
expect(screen.getByText('Sign in to Readur')).toBeInTheDocument()
|
||||||
expect(screen.getByPlaceholderText('Username')).toBeInTheDocument()
|
expect(screen.getByPlaceholderText('Username')).toBeInTheDocument()
|
||||||
|
|
@ -38,7 +43,7 @@ describe('Login', () => {
|
||||||
test('handles form submission with valid credentials', async () => {
|
test('handles form submission with valid credentials', async () => {
|
||||||
mockLogin.mockResolvedValue(undefined)
|
mockLogin.mockResolvedValue(undefined)
|
||||||
|
|
||||||
renderWithMockAuth(<Login />, { login: mockLogin })
|
renderLogin()
|
||||||
|
|
||||||
const usernameInput = screen.getByPlaceholderText('Username')
|
const usernameInput = screen.getByPlaceholderText('Username')
|
||||||
const passwordInput = screen.getByPlaceholderText('Password')
|
const passwordInput = screen.getByPlaceholderText('Password')
|
||||||
|
|
@ -59,7 +64,7 @@ describe('Login', () => {
|
||||||
response: { data: { message: errorMessage } },
|
response: { data: { message: errorMessage } },
|
||||||
})
|
})
|
||||||
|
|
||||||
renderWithMockAuth(<Login />, { login: mockLogin })
|
renderLogin()
|
||||||
|
|
||||||
const usernameInput = screen.getByPlaceholderText('Username')
|
const usernameInput = screen.getByPlaceholderText('Username')
|
||||||
const passwordInput = screen.getByPlaceholderText('Password')
|
const passwordInput = screen.getByPlaceholderText('Password')
|
||||||
|
|
@ -77,7 +82,7 @@ describe('Login', () => {
|
||||||
test('shows loading state during submission', async () => {
|
test('shows loading state during submission', async () => {
|
||||||
mockLogin.mockImplementation(() => new Promise(() => {})) // Never resolves
|
mockLogin.mockImplementation(() => new Promise(() => {})) // Never resolves
|
||||||
|
|
||||||
renderWithMockAuth(<Login />, { login: mockLogin })
|
renderLogin()
|
||||||
|
|
||||||
const usernameInput = screen.getByPlaceholderText('Username')
|
const usernameInput = screen.getByPlaceholderText('Username')
|
||||||
const passwordInput = screen.getByPlaceholderText('Password')
|
const passwordInput = screen.getByPlaceholderText('Password')
|
||||||
|
|
@ -94,7 +99,7 @@ describe('Login', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('requires username and password', () => {
|
test('requires username and password', () => {
|
||||||
renderWithMockAuth(<Login />, { login: mockLogin })
|
renderLogin()
|
||||||
|
|
||||||
const usernameInput = screen.getByPlaceholderText('Username')
|
const usernameInput = screen.getByPlaceholderText('Username')
|
||||||
const passwordInput = screen.getByPlaceholderText('Password')
|
const passwordInput = screen.getByPlaceholderText('Password')
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ describe('SearchPage Integration Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify search was called
|
// Verify search was called
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith(
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
query: 'invoice',
|
query: 'invoice',
|
||||||
limit: 100,
|
limit: 100,
|
||||||
|
|
@ -153,7 +153,7 @@ describe('SearchPage Integration Tests', () => {
|
||||||
|
|
||||||
// Verify search is called again with MIME type filter
|
// Verify search is called again with MIME type filter
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith(
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
query: 'invoice',
|
query: 'invoice',
|
||||||
mime_types: ['application/pdf'],
|
mime_types: ['application/pdf'],
|
||||||
|
|
@ -194,7 +194,7 @@ describe('SearchPage Integration Tests', () => {
|
||||||
|
|
||||||
// Verify advanced settings are applied
|
// Verify advanced settings are applied
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith(
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
query: 'invoice',
|
query: 'invoice',
|
||||||
search_mode: 'fuzzy',
|
search_mode: 'fuzzy',
|
||||||
|
|
@ -252,7 +252,7 @@ describe('SearchPage Integration Tests', () => {
|
||||||
|
|
||||||
// Verify search is triggered
|
// Verify search is triggered
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith(
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
query: 'invoice',
|
query: 'invoice',
|
||||||
})
|
})
|
||||||
|
|
@ -262,7 +262,7 @@ describe('SearchPage Integration Tests', () => {
|
||||||
|
|
||||||
test('handles search errors gracefully', async () => {
|
test('handles search errors gracefully', async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
(documentService.enhancedSearch as any).mockRejectedValue(new Error('Search failed'));
|
mockDocumentService.enhancedSearch.mockRejectedValue(new Error('Search failed'));
|
||||||
|
|
||||||
renderSearchPage();
|
renderSearchPage();
|
||||||
|
|
||||||
|
|
@ -349,7 +349,7 @@ describe('SearchPage Integration Tests', () => {
|
||||||
|
|
||||||
// Verify search is called with all filters
|
// Verify search is called with all filters
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith(
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
query: 'invoice',
|
query: 'invoice',
|
||||||
mime_types: ['application/pdf'],
|
mime_types: ['application/pdf'],
|
||||||
|
|
@ -433,11 +433,11 @@ describe('SearchPage Performance Tests', () => {
|
||||||
|
|
||||||
// Wait for debounce
|
// Wait for debounce
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledTimes(1);
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Should only be called once due to debouncing
|
// Should only be called once due to debouncing
|
||||||
expect(documentService.enhancedSearch).toHaveBeenCalledWith(
|
expect(mockDocumentService.enhancedSearch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
query: 'invoice',
|
query: 'invoice',
|
||||||
})
|
})
|
||||||
|
|
@ -448,7 +448,7 @@ describe('SearchPage Performance Tests', () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
|
|
||||||
// Make the API call take longer to see loading state
|
// Make the API call take longer to see loading state
|
||||||
(documentService.enhancedSearch as any).mockImplementation(
|
mockDocumentService.enhancedSearch.mockImplementation(
|
||||||
() => new Promise(resolve => setTimeout(() => resolve(mockSearchResponse), 1000))
|
() => new Promise(resolve => setTimeout(() => resolve(mockSearchResponse), 1000))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,28 @@
|
||||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
import axios from 'axios';
|
import { type OcrResponse, type Document } from '../api';
|
||||||
import { documentService, type OcrResponse, type Document } from '../api';
|
|
||||||
|
|
||||||
vi.mock('axios');
|
// Create mock functions for the documentService
|
||||||
const mockedAxios = vi.mocked(axios);
|
const mockGetOcrText = vi.fn();
|
||||||
|
const mockList = vi.fn();
|
||||||
|
const mockUpload = vi.fn();
|
||||||
|
const mockDownload = vi.fn();
|
||||||
|
|
||||||
|
// Mock the entire api module
|
||||||
|
vi.mock('../api', async () => {
|
||||||
|
const actual = await vi.importActual('../api');
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
documentService: {
|
||||||
|
getOcrText: mockGetOcrText,
|
||||||
|
list: mockList,
|
||||||
|
upload: mockUpload,
|
||||||
|
download: mockDownload,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import after mocking
|
||||||
|
const { documentService } = await import('../api');
|
||||||
|
|
||||||
describe('documentService', () => {
|
describe('documentService', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
@ -33,9 +52,7 @@ describe('documentService', () => {
|
||||||
config: {},
|
config: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue({
|
mockGetOcrText.mockResolvedValue(mockResponse);
|
||||||
get: vi.fn().mockResolvedValue(mockResponse),
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const result = await documentService.getOcrText('doc-123');
|
const result = await documentService.getOcrText('doc-123');
|
||||||
|
|
||||||
|
|
@ -69,9 +86,7 @@ describe('documentService', () => {
|
||||||
config: {},
|
config: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue({
|
mockGetOcrText.mockResolvedValue(mockResponse);
|
||||||
get: vi.fn().mockResolvedValue(mockResponse),
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const result = await documentService.getOcrText('doc-456');
|
const result = await documentService.getOcrText('doc-456');
|
||||||
|
|
||||||
|
|
@ -103,9 +118,7 @@ describe('documentService', () => {
|
||||||
config: {},
|
config: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue({
|
mockGetOcrText.mockResolvedValue(mockResponse);
|
||||||
get: vi.fn().mockResolvedValue(mockResponse),
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const result = await documentService.getOcrText('doc-789');
|
const result = await documentService.getOcrText('doc-789');
|
||||||
|
|
||||||
|
|
@ -116,38 +129,26 @@ describe('documentService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should make correct API call', async () => {
|
it('should make correct API call', async () => {
|
||||||
const mockAxiosInstance = {
|
mockGetOcrText.mockResolvedValue({ data: mockOcrResponse });
|
||||||
get: vi.fn().mockResolvedValue({ data: mockOcrResponse }),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue(mockAxiosInstance as any);
|
|
||||||
|
|
||||||
await documentService.getOcrText('doc-123');
|
await documentService.getOcrText('doc-123');
|
||||||
|
|
||||||
expect(mockAxiosInstance.get).toHaveBeenCalledWith('/documents/doc-123/ocr');
|
expect(mockGetOcrText).toHaveBeenCalledWith('doc-123');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle network errors', async () => {
|
it('should handle network errors', async () => {
|
||||||
const mockAxiosInstance = {
|
mockGetOcrText.mockRejectedValue(new Error('Network Error'));
|
||||||
get: vi.fn().mockRejectedValue(new Error('Network Error')),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue(mockAxiosInstance as any);
|
|
||||||
|
|
||||||
await expect(documentService.getOcrText('doc-123')).rejects.toThrow('Network Error');
|
await expect(documentService.getOcrText('doc-123')).rejects.toThrow('Network Error');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle 404 errors for non-existent documents', async () => {
|
it('should handle 404 errors for non-existent documents', async () => {
|
||||||
const mockAxiosInstance = {
|
mockGetOcrText.mockRejectedValue({
|
||||||
get: vi.fn().mockRejectedValue({
|
response: {
|
||||||
response: {
|
status: 404,
|
||||||
status: 404,
|
data: { error: 'Document not found' },
|
||||||
data: { error: 'Document not found' },
|
},
|
||||||
},
|
});
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue(mockAxiosInstance as any);
|
|
||||||
|
|
||||||
await expect(documentService.getOcrText('non-existent-doc')).rejects.toMatchObject({
|
await expect(documentService.getOcrText('non-existent-doc')).rejects.toMatchObject({
|
||||||
response: {
|
response: {
|
||||||
|
|
@ -157,16 +158,12 @@ describe('documentService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle 401 unauthorized errors', async () => {
|
it('should handle 401 unauthorized errors', async () => {
|
||||||
const mockAxiosInstance = {
|
mockGetOcrText.mockRejectedValue({
|
||||||
get: vi.fn().mockRejectedValue({
|
response: {
|
||||||
response: {
|
status: 401,
|
||||||
status: 401,
|
data: { error: 'Unauthorized' },
|
||||||
data: { error: 'Unauthorized' },
|
},
|
||||||
},
|
});
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue(mockAxiosInstance as any);
|
|
||||||
|
|
||||||
await expect(documentService.getOcrText('doc-123')).rejects.toMatchObject({
|
await expect(documentService.getOcrText('doc-123')).rejects.toMatchObject({
|
||||||
response: {
|
response: {
|
||||||
|
|
@ -217,9 +214,7 @@ describe('documentService', () => {
|
||||||
config: {},
|
config: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue({
|
mockList.mockResolvedValue(mockResponse);
|
||||||
get: vi.fn().mockResolvedValue(mockResponse),
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const result = await documentService.list(50, 0);
|
const result = await documentService.list(50, 0);
|
||||||
|
|
||||||
|
|
@ -246,42 +241,24 @@ describe('documentService', () => {
|
||||||
ocr_status: 'pending',
|
ocr_status: 'pending',
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockAxiosInstance = {
|
mockUpload.mockResolvedValue({ data: mockUploadResponse });
|
||||||
post: vi.fn().mockResolvedValue({ data: mockUploadResponse }),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue(mockAxiosInstance as any);
|
|
||||||
|
|
||||||
const result = await documentService.upload(mockFile);
|
const result = await documentService.upload(mockFile);
|
||||||
|
|
||||||
expect(result.data).toEqual(mockUploadResponse);
|
expect(result.data).toEqual(mockUploadResponse);
|
||||||
expect(mockAxiosInstance.post).toHaveBeenCalledWith(
|
expect(mockUpload).toHaveBeenCalledWith(mockFile);
|
||||||
'/documents',
|
|
||||||
expect.any(FormData),
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('download', () => {
|
describe('download', () => {
|
||||||
it('should download file as blob', async () => {
|
it('should download file as blob', async () => {
|
||||||
const mockBlob = new Blob(['file content'], { type: 'application/pdf' });
|
const mockBlob = new Blob(['file content'], { type: 'application/pdf' });
|
||||||
const mockAxiosInstance = {
|
mockDownload.mockResolvedValue({ data: mockBlob });
|
||||||
get: vi.fn().mockResolvedValue({ data: mockBlob }),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue(mockAxiosInstance as any);
|
|
||||||
|
|
||||||
const result = await documentService.download('doc-123');
|
const result = await documentService.download('doc-123');
|
||||||
|
|
||||||
expect(result.data).toEqual(mockBlob);
|
expect(result.data).toEqual(mockBlob);
|
||||||
expect(mockAxiosInstance.get).toHaveBeenCalledWith('/documents/doc-123/download', {
|
expect(mockDownload).toHaveBeenCalledWith('doc-123');
|
||||||
responseType: 'blob',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue