179 lines
6.3 KiB
TypeScript
179 lines
6.3 KiB
TypeScript
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||
|
|
import { createPinia, setActivePinia } from 'pinia';
|
||
|
|
|
||
|
|
vi.mock('../../resources/js/api/reminders', () => ({
|
||
|
|
listReminders: vi.fn(),
|
||
|
|
createReminder: vi.fn(),
|
||
|
|
updateReminder: vi.fn(),
|
||
|
|
completeReminder: vi.fn(),
|
||
|
|
deleteReminder: vi.fn(),
|
||
|
|
}));
|
||
|
|
|
||
|
|
vi.mock('../../resources/js/api/client', () => ({
|
||
|
|
apiClient: {},
|
||
|
|
ensureCsrfCookie: vi.fn(),
|
||
|
|
extractValidationErrors: vi.fn(() => null),
|
||
|
|
extractErrorMessage: vi.fn(() => 'Произошла ошибка.'),
|
||
|
|
extractRateLimitRetry: vi.fn(() => null),
|
||
|
|
}));
|
||
|
|
|
||
|
|
import * as remindersApi from '../../resources/js/api/reminders';
|
||
|
|
import { useRemindersStore } from '../../resources/js/stores/reminders';
|
||
|
|
import type { ApiReminder } from '../../resources/js/api/reminders';
|
||
|
|
|
||
|
|
const mockReminder = (id: number, overrides: Partial<ApiReminder> = {}): ApiReminder => ({
|
||
|
|
id,
|
||
|
|
deal_id: 100 + id,
|
||
|
|
text: `Напоминание #${id}`,
|
||
|
|
remind_at: new Date(2026, 4, 9, 14 + id, 0).toISOString(),
|
||
|
|
completed_at: null,
|
||
|
|
is_sent: false,
|
||
|
|
sent_at: null,
|
||
|
|
created_at: new Date(2026, 4, 9, 12, 0).toISOString(),
|
||
|
|
created_by: 1,
|
||
|
|
assignee_id: null,
|
||
|
|
creator_name: 'Иван Петров',
|
||
|
|
...overrides,
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('useRemindersStore', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
setActivePinia(createPinia());
|
||
|
|
vi.clearAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('initial state', () => {
|
||
|
|
const store = useRemindersStore();
|
||
|
|
expect(store.items).toEqual([]);
|
||
|
|
expect(store.counts).toEqual({ active: 0, today: 0, upcoming: 0, overdue: 0 });
|
||
|
|
});
|
||
|
|
|
||
|
|
it('load() заполняет items + counts', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1), mockReminder(2)],
|
||
|
|
counts: { active: 2, today: 1, upcoming: 1, overdue: 0 },
|
||
|
|
});
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
|
||
|
|
expect(store.items).toHaveLength(2);
|
||
|
|
expect(store.counts.active).toBe(2);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('load() при reject ставит fetchError', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockRejectedValue(new Error('500'));
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
expect(store.fetchError).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('refreshCounts() обновляет только counts', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1)],
|
||
|
|
counts: { active: 5, today: 2, upcoming: 1, overdue: 2 },
|
||
|
|
});
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
store.items = [mockReminder(99)]; // pre-populate
|
||
|
|
await store.refreshCounts();
|
||
|
|
|
||
|
|
expect(store.counts.active).toBe(5);
|
||
|
|
expect(store.items).toHaveLength(1); // не тронуто
|
||
|
|
});
|
||
|
|
|
||
|
|
it('create() добавляет в начало + increment active', async () => {
|
||
|
|
const newR = mockReminder(99);
|
||
|
|
vi.mocked(remindersApi.createReminder).mockResolvedValue(newR);
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
store.counts.active = 3;
|
||
|
|
|
||
|
|
await store.create({ deal_id: 100, remind_at: new Date().toISOString() });
|
||
|
|
expect(store.items[0]!.id).toBe(99);
|
||
|
|
expect(store.counts.active).toBe(4);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('create() при reject возвращает null', async () => {
|
||
|
|
vi.mocked(remindersApi.createReminder).mockRejectedValue(new Error('500'));
|
||
|
|
const store = useRemindersStore();
|
||
|
|
const result = await store.create({ deal_id: 100, remind_at: new Date().toISOString() });
|
||
|
|
expect(result).toBeNull();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('complete() optimistic + decrement active', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1)],
|
||
|
|
counts: { active: 1, today: 1, upcoming: 0, overdue: 0 },
|
||
|
|
});
|
||
|
|
vi.mocked(remindersApi.completeReminder).mockResolvedValue(
|
||
|
|
mockReminder(1, { completed_at: '2026-05-09T15:00:00Z' }),
|
||
|
|
);
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
await store.complete(1);
|
||
|
|
|
||
|
|
expect(store.counts.active).toBe(0);
|
||
|
|
// currentFilter='active' → удалили из items.
|
||
|
|
expect(store.items).toHaveLength(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('complete() при reject — revert', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1)],
|
||
|
|
counts: { active: 1, today: 1, upcoming: 0, overdue: 0 },
|
||
|
|
});
|
||
|
|
vi.mocked(remindersApi.completeReminder).mockRejectedValue(new Error('500'));
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
await store.complete(1);
|
||
|
|
|
||
|
|
expect(store.counts.active).toBe(1);
|
||
|
|
expect(store.items[0]!.completed_at).toBeNull();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('remove() optimistic убирает + decrement', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1), mockReminder(2)],
|
||
|
|
counts: { active: 2, today: 1, upcoming: 1, overdue: 0 },
|
||
|
|
});
|
||
|
|
vi.mocked(remindersApi.deleteReminder).mockResolvedValue();
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
await store.remove(1);
|
||
|
|
|
||
|
|
expect(store.items).toHaveLength(1);
|
||
|
|
expect(store.counts.active).toBe(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('remove() при reject — revert', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1), mockReminder(2)],
|
||
|
|
counts: { active: 2, today: 1, upcoming: 1, overdue: 0 },
|
||
|
|
});
|
||
|
|
vi.mocked(remindersApi.deleteReminder).mockRejectedValue(new Error('500'));
|
||
|
|
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
await store.remove(1);
|
||
|
|
|
||
|
|
expect(store.items).toHaveLength(2);
|
||
|
|
expect(store.counts.active).toBe(2);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('reset() очищает', async () => {
|
||
|
|
vi.mocked(remindersApi.listReminders).mockResolvedValue({
|
||
|
|
items: [mockReminder(1)],
|
||
|
|
counts: { active: 1, today: 1, upcoming: 0, overdue: 0 },
|
||
|
|
});
|
||
|
|
const store = useRemindersStore();
|
||
|
|
await store.load();
|
||
|
|
store.reset();
|
||
|
|
expect(store.items).toEqual([]);
|
||
|
|
expect(store.counts).toEqual({ active: 0, today: 0, upcoming: 0, overdue: 0 });
|
||
|
|
});
|
||
|
|
});
|