Files
portal/app/tests/Frontend/reminders-store.spec.ts
T

179 lines
6.3 KiB
TypeScript
Raw Normal View History

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 });
});
});