222 lines
5.8 KiB
TypeScript
222 lines
5.8 KiB
TypeScript
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import SettingsPage from '../SettingsPage.tsx';
|
|
|
|
const {
|
|
listMock,
|
|
createMock,
|
|
removeMock,
|
|
usersListMock,
|
|
buhsMock,
|
|
pendingMock,
|
|
requestMock,
|
|
approveMock,
|
|
refreshUserMock,
|
|
authState,
|
|
} = vi.hoisted(() => ({
|
|
listMock: vi.fn(),
|
|
createMock: vi.fn(),
|
|
removeMock: vi.fn(),
|
|
usersListMock: vi.fn(),
|
|
buhsMock: vi.fn(),
|
|
pendingMock: vi.fn(),
|
|
requestMock: vi.fn(),
|
|
approveMock: vi.fn(),
|
|
refreshUserMock: vi.fn(),
|
|
authState: {
|
|
user: {
|
|
id: 5,
|
|
user_login: 'gm.user',
|
|
user_name: 'gm.user',
|
|
status: 'gm' as string,
|
|
managed_by: null as number | null,
|
|
managed_by_name: null as string | null,
|
|
managed_by_pending: null as number | null,
|
|
managed_by_pending_name: null as string | null,
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
},
|
|
}));
|
|
|
|
vi.mock('../../services/apiClient.ts', () => ({
|
|
api: {
|
|
citySites: {
|
|
list: listMock,
|
|
create: createMock,
|
|
remove: removeMock,
|
|
},
|
|
users: {
|
|
list: usersListMock,
|
|
listBuhs: buhsMock,
|
|
listPendingManaged: pendingMock,
|
|
requestManagedBy: requestMock,
|
|
cancelManagedByRequest: vi.fn(),
|
|
approveManagedBy: approveMock,
|
|
rejectManagedBy: vi.fn(),
|
|
},
|
|
},
|
|
errorMessage: (err: unknown) => (err instanceof Error ? err.message : 'Terjadi kesalahan'),
|
|
}));
|
|
|
|
vi.mock('../../context/AuthContext.tsx', () => ({
|
|
useAuth: () => ({
|
|
user: authState.user,
|
|
refreshUser: refreshUserMock,
|
|
}),
|
|
}));
|
|
|
|
vi.mock('../../context/FarmContext.tsx', () => ({
|
|
useFarm: () => ({
|
|
reload: vi.fn().mockResolvedValue(undefined),
|
|
}),
|
|
}));
|
|
|
|
describe('SettingsPage city site registry', () => {
|
|
beforeEach(() => {
|
|
listMock.mockReset();
|
|
createMock.mockReset();
|
|
removeMock.mockReset();
|
|
usersListMock.mockReset();
|
|
buhsMock.mockReset();
|
|
pendingMock.mockReset();
|
|
requestMock.mockReset();
|
|
approveMock.mockReset();
|
|
refreshUserMock.mockReset();
|
|
authState.user = {
|
|
id: 5,
|
|
user_login: 'gm.user',
|
|
user_name: 'gm.user',
|
|
status: 'gm',
|
|
managed_by: null,
|
|
managed_by_name: null,
|
|
managed_by_pending: null,
|
|
managed_by_pending_name: null,
|
|
created_at: '',
|
|
updated_at: '',
|
|
};
|
|
refreshUserMock.mockResolvedValue(authState.user);
|
|
listMock.mockResolvedValue([
|
|
{
|
|
id: 1,
|
|
code: 'sukawarna',
|
|
name: 'Sukawarna',
|
|
api_base_url: 'https://sukawarna.example/api/v1',
|
|
has_api_key: true,
|
|
registered_by: 5,
|
|
registered_by_name: 'gm.user',
|
|
is_active: true,
|
|
last_synced_at: null,
|
|
last_sync_status: '',
|
|
last_sync_message: '',
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
]);
|
|
createMock.mockResolvedValue({
|
|
id: 2,
|
|
code: 'cikupa',
|
|
name: 'Cikupa',
|
|
api_base_url: 'https://cikupa.example/api/v1',
|
|
has_api_key: false,
|
|
registered_by: 5,
|
|
registered_by_name: 'gm.user',
|
|
is_active: true,
|
|
last_synced_at: null,
|
|
last_sync_status: '',
|
|
last_sync_message: '',
|
|
created_at: '',
|
|
updated_at: '',
|
|
});
|
|
buhsMock.mockResolvedValue([
|
|
{ id: 2, user_login: 'buh', user_name: 'buh', status: 'buh', created_at: '', updated_at: '' },
|
|
]);
|
|
usersListMock.mockResolvedValue([
|
|
{
|
|
id: 5,
|
|
user_login: 'gm',
|
|
user_name: 'gm',
|
|
status: 'gm',
|
|
managed_by: 2,
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
]);
|
|
pendingMock.mockResolvedValue([]);
|
|
});
|
|
|
|
it('lists registered city sites for GM', async () => {
|
|
render(<SettingsPage />);
|
|
|
|
expect(await screen.findByText('Sukawarna')).toBeInTheDocument();
|
|
expect(screen.getByText('BUH pengelola')).toBeInTheDocument();
|
|
});
|
|
|
|
it('submits a new city site to the view list', async () => {
|
|
render(<SettingsPage />);
|
|
await screen.findByText('Sukawarna');
|
|
|
|
fireEvent.change(screen.getByPlaceholderText('Contoh: Sukawarna'), {
|
|
target: { value: 'Cikupa' },
|
|
});
|
|
fireEvent.change(screen.getByPlaceholderText('https://site.example/api/v1'), {
|
|
target: { value: 'https://cikupa.example/api/v1' },
|
|
});
|
|
fireEvent.click(screen.getByRole('button', { name: 'Tambah ke daftar' }));
|
|
|
|
await waitFor(() => expect(createMock).toHaveBeenCalledTimes(1));
|
|
expect(createMock).toHaveBeenCalledWith({
|
|
code: 'cikupa',
|
|
name: 'Cikupa',
|
|
api_base_url: 'https://cikupa.example/api/v1',
|
|
is_active: true,
|
|
});
|
|
});
|
|
|
|
it('lets GM request a BUH', async () => {
|
|
requestMock.mockResolvedValue({
|
|
...authState.user,
|
|
managed_by_pending: 2,
|
|
managed_by_pending_name: 'buh',
|
|
});
|
|
render(<SettingsPage />);
|
|
await screen.findByText('BUH pengelola');
|
|
|
|
fireEvent.change(screen.getByLabelText(/Pilih BUH/i), { target: { value: '2' } });
|
|
fireEvent.click(screen.getByRole('button', { name: 'Kirim permintaan' }));
|
|
|
|
await waitFor(() => expect(requestMock).toHaveBeenCalledWith(2));
|
|
});
|
|
|
|
it('shows pending GM confirmation for BUH', async () => {
|
|
authState.user = {
|
|
id: 2,
|
|
user_login: 'buh',
|
|
user_name: 'buh',
|
|
status: 'buh',
|
|
managed_by: null,
|
|
managed_by_name: null,
|
|
managed_by_pending: null,
|
|
managed_by_pending_name: null,
|
|
created_at: '',
|
|
updated_at: '',
|
|
};
|
|
pendingMock.mockResolvedValue([
|
|
{
|
|
id: 5,
|
|
user_login: 'gm.user',
|
|
user_name: 'gm.user',
|
|
status: 'gm',
|
|
created_at: '',
|
|
updated_at: '',
|
|
},
|
|
]);
|
|
|
|
render(<SettingsPage />);
|
|
|
|
expect(await screen.findByText('Permintaan GM')).toBeInTheDocument();
|
|
expect(screen.getByText('gm.user')).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'Konfirmasi' })).toBeInTheDocument();
|
|
});
|
|
});
|