Sifa professional network frontend (Next.js, React, TailwindCSS)
sifa.id/
1import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2import { updateProfileSelf, createRecord, updateRecord, deleteRecord } from '@/lib/profile-api';
3
4const mockFetch = vi.fn();
5
6beforeEach(() => {
7 vi.stubGlobal('fetch', mockFetch);
8});
9
10afterEach(() => {
11 vi.unstubAllGlobals();
12});
13
14describe('profile-api', () => {
15 it('updateProfileSelf sends PUT with data', async () => {
16 mockFetch.mockResolvedValue({ ok: true });
17 const result = await updateProfileSelf({ headline: 'Developer' });
18 expect(result.success).toBe(true);
19 expect(mockFetch).toHaveBeenCalledWith(
20 expect.stringContaining('/api/profile/self'),
21 expect.objectContaining({ method: 'PUT' }),
22 );
23 });
24
25 it('createRecord sends POST and returns rkey', async () => {
26 mockFetch.mockResolvedValue({
27 ok: true,
28 json: () => Promise.resolve({ rkey: 'tid123' }),
29 });
30 const result = await createRecord('id.sifa.profile.position', { title: 'Eng' });
31 expect(result.success).toBe(true);
32 expect(result.rkey).toBe('tid123');
33 expect(mockFetch).toHaveBeenCalledWith(
34 expect.stringContaining('/api/profile/records/id.sifa.profile.position'),
35 expect.objectContaining({ method: 'POST' }),
36 );
37 });
38
39 it('updateRecord sends PUT with rkey', async () => {
40 mockFetch.mockResolvedValue({ ok: true });
41 const result = await updateRecord('id.sifa.profile.position', 'abc123', {
42 title: 'Senior Eng',
43 });
44 expect(result.success).toBe(true);
45 expect(mockFetch).toHaveBeenCalledWith(
46 expect.stringContaining('/api/profile/records/id.sifa.profile.position/abc123'),
47 expect.objectContaining({ method: 'PUT' }),
48 );
49 });
50
51 it('deleteRecord sends DELETE', async () => {
52 mockFetch.mockResolvedValue({ ok: true });
53 const result = await deleteRecord('id.sifa.profile.position', 'abc123');
54 expect(result.success).toBe(true);
55 expect(mockFetch).toHaveBeenCalledWith(
56 expect.stringContaining('/api/profile/records/id.sifa.profile.position/abc123'),
57 expect.objectContaining({ method: 'DELETE' }),
58 );
59 });
60
61 it('returns error on failed request', async () => {
62 mockFetch.mockResolvedValue({
63 ok: false,
64 status: 401,
65 json: () => Promise.resolve({ message: 'Unauthorized' }),
66 });
67 const result = await updateProfileSelf({ headline: 'Test' });
68 expect(result.success).toBe(false);
69 expect(result.error).toBe('Unauthorized');
70 });
71
72 it('handles network errors', async () => {
73 mockFetch.mockRejectedValue(new Error('Network failure'));
74 const result = await updateProfileSelf({ headline: 'Test' });
75 expect(result.success).toBe(false);
76 expect(result.error).toBe('Network error');
77 });
78});