Skip to content

Commit a7be5bc

Browse files
committed
Implementation tests
1 parent 81a5a45 commit a7be5bc

1 file changed

Lines changed: 314 additions & 0 deletions

File tree

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import { act } from '@testing-library/react';
3+
import { useProjectStore } from '../project';
4+
import { api } from '../../api';
5+
6+
// Mock the API client
7+
vi.mock('../../api', () => ({
8+
api: {
9+
projects: {
10+
getProjects: vi.fn(),
11+
getProject: vi.fn(),
12+
createProject: vi.fn(),
13+
deleteProject: vi.fn(),
14+
getUploadUrl: vi.fn(),
15+
getProjectStatus: vi.fn(),
16+
},
17+
},
18+
}));
19+
20+
// Mock fetch for file upload
21+
global.fetch = vi.fn();
22+
23+
describe('Project Store', () => {
24+
beforeEach(() => {
25+
// Reset store state
26+
useProjectStore.setState({
27+
projects: [],
28+
currentProject: null,
29+
uploadStatus: null,
30+
isLoading: false,
31+
isCreating: false,
32+
isDeleting: false,
33+
isUploading: false,
34+
error: null,
35+
page: 1,
36+
limit: 10,
37+
total: 0,
38+
hasMore: false,
39+
});
40+
41+
// Clear all mocks
42+
vi.clearAllMocks();
43+
});
44+
45+
describe('fetchProjects', () => {
46+
it('should fetch projects successfully', async () => {
47+
const mockProjects = [
48+
{ id: '1', name: 'Project 1', description: 'Test project 1', status: 'ready', user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() },
49+
{ id: '2', name: 'Project 2', description: 'Test project 2', status: 'processing', user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() },
50+
];
51+
52+
vi.mocked(api.projects.getProjects).mockResolvedValue({
53+
success: true,
54+
data: {
55+
items: mockProjects,
56+
total: 2,
57+
page: 1,
58+
limit: 10,
59+
hasMore: false,
60+
},
61+
});
62+
63+
const { fetchProjects } = useProjectStore.getState();
64+
65+
await act(async () => {
66+
await fetchProjects();
67+
});
68+
69+
const state = useProjectStore.getState();
70+
expect(state.projects).toEqual(mockProjects);
71+
expect(state.total).toBe(2);
72+
expect(state.hasMore).toBe(false);
73+
expect(state.isLoading).toBe(false);
74+
expect(state.error).toBeNull();
75+
});
76+
77+
it('should handle fetch error', async () => {
78+
vi.mocked(api.projects.getProjects).mockResolvedValue({
79+
success: false,
80+
error: 'Failed to fetch projects',
81+
});
82+
83+
const { fetchProjects } = useProjectStore.getState();
84+
85+
await act(async () => {
86+
await fetchProjects();
87+
});
88+
89+
const state = useProjectStore.getState();
90+
expect(state.projects).toEqual([]);
91+
expect(state.error).toBe('Failed to fetch projects');
92+
expect(state.isLoading).toBe(false);
93+
});
94+
});
95+
96+
describe('createProject', () => {
97+
it('should create project successfully', async () => {
98+
const newProject = {
99+
id: '3',
100+
name: 'New Project',
101+
description: 'A new test project',
102+
status: 'uploading' as const,
103+
user_id: 'user1',
104+
created_at: new Date().toISOString(),
105+
updated_at: new Date().toISOString(),
106+
};
107+
108+
vi.mocked(api.projects.createProject).mockResolvedValue({
109+
success: true,
110+
data: {
111+
project: newProject,
112+
upload_url: 'https://minio.example.com/upload',
113+
},
114+
});
115+
116+
const { createProject } = useProjectStore.getState();
117+
118+
const result = await act(async () => {
119+
return await createProject({ name: 'New Project', description: 'A new test project' });
120+
});
121+
122+
expect(result).toEqual(newProject);
123+
124+
const state = useProjectStore.getState();
125+
expect(state.projects).toContainEqual(newProject);
126+
expect(state.currentProject).toEqual(newProject);
127+
expect(state.isCreating).toBe(false);
128+
expect(state.error).toBeNull();
129+
});
130+
131+
it('should handle create error', async () => {
132+
vi.mocked(api.projects.createProject).mockResolvedValue({
133+
success: false,
134+
error: 'Failed to create project',
135+
});
136+
137+
const { createProject } = useProjectStore.getState();
138+
139+
const result = await act(async () => {
140+
return await createProject({ name: 'New Project', description: 'Test' });
141+
});
142+
143+
expect(result).toBeNull();
144+
145+
const state = useProjectStore.getState();
146+
expect(state.error).toBe('Failed to create project');
147+
expect(state.isCreating).toBe(false);
148+
});
149+
});
150+
151+
describe('deleteProject', () => {
152+
it('should delete project successfully', async () => {
153+
// Set initial projects
154+
useProjectStore.setState({
155+
projects: [
156+
{ id: '1', name: 'Project 1', description: 'Test', status: 'ready', user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() },
157+
{ id: '2', name: 'Project 2', description: 'Test', status: 'ready', user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() },
158+
],
159+
});
160+
161+
vi.mocked(api.projects.deleteProject).mockResolvedValue({
162+
success: true,
163+
data: { message: 'Project deleted' },
164+
});
165+
166+
const { deleteProject } = useProjectStore.getState();
167+
168+
const result = await act(async () => {
169+
return await deleteProject('1');
170+
});
171+
172+
expect(result).toBe(true);
173+
174+
const state = useProjectStore.getState();
175+
expect(state.projects).toHaveLength(1);
176+
expect(state.projects[0].id).toBe('2');
177+
expect(state.isDeleting).toBe(false);
178+
});
179+
});
180+
181+
describe('uploadFile', () => {
182+
it('should upload file successfully', async () => {
183+
const mockFile = new File(['test content'], 'test.csv', { type: 'text/csv' });
184+
185+
vi.mocked(api.projects.getUploadUrl).mockResolvedValue({
186+
success: true,
187+
data: {
188+
upload_url: 'https://minio.example.com/upload',
189+
upload_fields: {
190+
key: 'test-key',
191+
policy: 'test-policy',
192+
},
193+
},
194+
});
195+
196+
vi.mocked(api.projects.getProjectStatus).mockResolvedValue({
197+
success: true,
198+
data: {
199+
status: 'processing',
200+
message: 'Processing file',
201+
progress: 50,
202+
},
203+
});
204+
205+
vi.mocked(global.fetch).mockResolvedValue({
206+
ok: true,
207+
} as Response);
208+
209+
const { uploadFile } = useProjectStore.getState();
210+
211+
const result = await act(async () => {
212+
return await uploadFile('project1', mockFile);
213+
});
214+
215+
expect(result).toBe(true);
216+
expect(vi.mocked(global.fetch)).toHaveBeenCalledWith(
217+
'https://minio.example.com/upload',
218+
expect.objectContaining({
219+
method: 'POST',
220+
body: expect.any(FormData),
221+
})
222+
);
223+
224+
const state = useProjectStore.getState();
225+
expect(state.isUploading).toBe(false);
226+
expect(state.uploadStatus).toEqual({
227+
status: 'processing',
228+
message: 'Processing file',
229+
progress: 50,
230+
});
231+
});
232+
233+
it('should handle upload error', async () => {
234+
const mockFile = new File(['test content'], 'test.csv', { type: 'text/csv' });
235+
236+
vi.mocked(api.projects.getUploadUrl).mockResolvedValue({
237+
success: false,
238+
error: 'Failed to get upload URL',
239+
});
240+
241+
const { uploadFile } = useProjectStore.getState();
242+
243+
const result = await act(async () => {
244+
return await uploadFile('project1', mockFile);
245+
});
246+
247+
expect(result).toBe(false);
248+
249+
const state = useProjectStore.getState();
250+
expect(state.error).toBe('Failed to get upload URL');
251+
expect(state.isUploading).toBe(false);
252+
});
253+
});
254+
255+
describe('convenience hooks', () => {
256+
it('useProjects should return projects data', () => {
257+
const mockProjects = [
258+
{ id: '1', name: 'Project 1', description: 'Test', status: 'ready' as const, user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() },
259+
];
260+
261+
useProjectStore.setState({
262+
projects: mockProjects,
263+
isLoading: false,
264+
error: null,
265+
hasMore: false,
266+
total: 1,
267+
});
268+
269+
const state = useProjectStore.getState();
270+
expect(state.projects).toEqual(mockProjects);
271+
expect(state.isLoading).toBe(false);
272+
});
273+
274+
it('setCurrentProject should update current project', () => {
275+
const project = {
276+
id: '1',
277+
name: 'Project 1',
278+
description: 'Test',
279+
status: 'ready' as const,
280+
user_id: 'user1',
281+
created_at: new Date().toISOString(),
282+
updated_at: new Date().toISOString(),
283+
};
284+
285+
const { setCurrentProject } = useProjectStore.getState();
286+
287+
act(() => {
288+
setCurrentProject(project);
289+
});
290+
291+
const state = useProjectStore.getState();
292+
expect(state.currentProject).toEqual(project);
293+
});
294+
295+
it('reset should clear all state', () => {
296+
useProjectStore.setState({
297+
projects: [{ id: '1', name: 'Test', description: 'Test', status: 'ready', user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() }],
298+
currentProject: { id: '1', name: 'Test', description: 'Test', status: 'ready', user_id: 'user1', created_at: new Date().toISOString(), updated_at: new Date().toISOString() },
299+
error: 'Some error',
300+
});
301+
302+
const { reset } = useProjectStore.getState();
303+
304+
act(() => {
305+
reset();
306+
});
307+
308+
const state = useProjectStore.getState();
309+
expect(state.projects).toEqual([]);
310+
expect(state.currentProject).toBeNull();
311+
expect(state.error).toBeNull();
312+
});
313+
});
314+
});

0 commit comments

Comments
 (0)