refactor(frontend): remove addToast bridge — migrate all call sites to notifications API
BREAKING: addToast() removed. Use notify() or notifications facade instead.
- Replace addToast(msg, type, duration?) → notify({ message, type, duration? })
- Introduce notifications.success/info/warning/error/show() semantic facade
- Add dismissAllToasts(), timer management (clearTimeout on remove)
- Unify Toast component: single viewport, a11y (role/aria-live by type)
- Migrate 16 models, 2 stores, 38 components, 23 pages (76 files total)
- 147 test files / 3152 tests pass with updated mocks and assertions
This commit is contained in:
@@ -10,7 +10,7 @@ import { render, screen, fireEvent } from '@testing-library/svelte';
|
||||
|
||||
// ── Hoisted mutable state (before vi.mock calls, hoisted to top) ──
|
||||
|
||||
const { mockStartMaintenance, mockAddToast, mockEnvStore } = vi.hoisted(() => {
|
||||
const { mockStartMaintenance, mockEnvStore } = vi.hoisted(() => {
|
||||
// Mutable env store state — tests can change this before render
|
||||
let _selectedEnvId = 'env-prod';
|
||||
|
||||
@@ -23,7 +23,6 @@ const { mockStartMaintenance, mockAddToast, mockEnvStore } = vi.hoisted(() => {
|
||||
|
||||
return {
|
||||
mockStartMaintenance: vi.fn(),
|
||||
mockAddToast: vi.fn(),
|
||||
mockEnvStore: {
|
||||
obj: mockEnvStoreObj,
|
||||
setSelectedEnvId(id: string) { _selectedEnvId = id; },
|
||||
@@ -38,7 +37,7 @@ vi.mock('$lib/api/maintenance.js', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('$lib/toasts.svelte.js', () => ({
|
||||
addToast: mockAddToast,
|
||||
notifications: { success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn(), show: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock('$lib/stores/environmentContext.svelte.js', () => ({
|
||||
@@ -94,6 +93,7 @@ vi.mock('$lib/i18n/index.svelte.js', () => {
|
||||
|
||||
// ── Imports (after mocks) ─────────────────────────────────────
|
||||
|
||||
import { notifications } from '$lib/toasts.svelte.js';
|
||||
import StartMaintenanceForm from '$lib/components/StartMaintenanceForm.svelte';
|
||||
|
||||
describe('StartMaintenanceForm', () => {
|
||||
@@ -153,9 +153,8 @@ describe('StartMaintenanceForm', () => {
|
||||
expect(mockStartMaintenance).not.toHaveBeenCalled();
|
||||
|
||||
// Error toast should have been shown with the missing environment message
|
||||
expect(mockAddToast).toHaveBeenCalledWith(
|
||||
expect(notifications.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining('No environment selected'),
|
||||
'error',
|
||||
);
|
||||
});
|
||||
// #endregion test_validation_fails_without_environment
|
||||
|
||||
@@ -28,8 +28,8 @@ class MockWebSocket {
|
||||
vi.stubGlobal('WebSocket', MockWebSocket);
|
||||
|
||||
// Mock toasts
|
||||
vi.mock('$lib/toasts.svelte.js', () => ({
|
||||
addToast: vi.fn()
|
||||
vi.mock('$lib/toasts.svelte.js', () => ({
|
||||
notifications: { success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn(), show: vi.fn() },
|
||||
}));
|
||||
|
||||
// Mock i18n
|
||||
@@ -294,21 +294,21 @@ describe('MaintenanceStore', () => {
|
||||
});
|
||||
|
||||
it('endEvent handles non-Error rejection with fallback message', async () => {
|
||||
const { addToast } = await import('$lib/toasts.svelte.js');
|
||||
const { notifications } = await import('$lib/toasts.svelte.js');
|
||||
mockEndMaintenance.mockRejectedValue('string error');
|
||||
try {
|
||||
await store.endEvent('ev-fail');
|
||||
} catch {}
|
||||
expect(addToast).toHaveBeenCalledWith('Failed to end maintenance event', 'error');
|
||||
expect(notifications.error).toHaveBeenCalledWith('Failed to end maintenance event');
|
||||
});
|
||||
|
||||
it('endAllEvents handles non-Error rejection with fallback message', async () => {
|
||||
const { addToast } = await import('$lib/toasts.svelte.js');
|
||||
const { notifications } = await import('$lib/toasts.svelte.js');
|
||||
mockEndAllMaintenance.mockRejectedValue('string error');
|
||||
try {
|
||||
await store.endAllEvents();
|
||||
} catch {}
|
||||
expect(addToast).toHaveBeenCalledWith('Failed to end all events', 'error');
|
||||
expect(notifications.error).toHaveBeenCalledWith('Failed to end all events');
|
||||
});
|
||||
|
||||
it('WebSocket onerror and onclose callbacks fire', async () => {
|
||||
@@ -364,24 +364,26 @@ describe('MaintenanceStore', () => {
|
||||
expect(mockListDashboardBanners).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('endEvent without task_id does not call addToast', async () => {
|
||||
const { addToast } = await import('$lib/toasts.svelte.js');
|
||||
it('endEvent without task_id does not show toast', async () => {
|
||||
const { notifications } = await import('$lib/toasts.svelte.js');
|
||||
mockEndMaintenance.mockResolvedValue({ status: 'pending' }); // no task_id
|
||||
mockListEvents.mockResolvedValue({ active: [], completed: [] });
|
||||
|
||||
await store.endEvent('ev-no-task');
|
||||
|
||||
expect(addToast).not.toHaveBeenCalled();
|
||||
expect(notifications.info).not.toHaveBeenCalled();
|
||||
expect(notifications.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('endAllEvents without task_id does not call addToast', async () => {
|
||||
const { addToast } = await import('$lib/toasts.svelte.js');
|
||||
it('endAllEvents without task_id does not show toast', async () => {
|
||||
const { notifications } = await import('$lib/toasts.svelte.js');
|
||||
mockEndAllMaintenance.mockResolvedValue({ status: 'completed' }); // no task_id
|
||||
mockListEvents.mockResolvedValue({ active: [], completed: [] });
|
||||
|
||||
await store.endAllEvents();
|
||||
|
||||
expect(addToast).not.toHaveBeenCalled();
|
||||
expect(notifications.info).not.toHaveBeenCalled();
|
||||
expect(notifications.error).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
// #endregion MaintenanceStoreTests
|
||||
|
||||
@@ -52,7 +52,7 @@ function resetMockStore() {
|
||||
|
||||
// Mock toasts
|
||||
vi.mock('$lib/toasts.svelte.js', () => ({
|
||||
addToast: vi.fn()
|
||||
notifications: { success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn(), show: vi.fn() },
|
||||
}));
|
||||
|
||||
// Mock i18n — $t is a derived store, needs subscribe method for Svelte $ prefix
|
||||
|
||||
Reference in New Issue
Block a user