From 8160ac05e0cca988a7168adb06c540a3d84192cb Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Fri, 5 Jun 2026 22:46:45 +0530 Subject: [PATCH] feat(renderer): lib/toast.ts typed wrappers over sonner --- src/renderer/lib/toast.ts | 22 +++++++++++++++++ tests/unit/lib/toast.test.ts | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/renderer/lib/toast.ts create mode 100644 tests/unit/lib/toast.test.ts diff --git a/src/renderer/lib/toast.ts b/src/renderer/lib/toast.ts new file mode 100644 index 0000000..9011e1c --- /dev/null +++ b/src/renderer/lib/toast.ts @@ -0,0 +1,22 @@ +import { toast as sonnerToast } from 'sonner'; + +/** + * Typed wrappers over sonner's toast API. Centralizing the import gives us + * a single surface to evolve (e.g., add brand colors, action buttons, + * analytics) without touching every call site. + */ +export const toast = { + success: (message: string) => sonnerToast.success(message), + error: (message: string) => sonnerToast.error(message), + info: (message: string) => sonnerToast.info(message), + warning: (message: string) => sonnerToast.warning(message), + promise: ( + promise: Promise, + msgs: { + loading: string; + success: string | ((data: T) => string); + error: string | ((err: unknown) => string); + } + ) => sonnerToast.promise(promise, msgs), + dismiss: (id?: string | number) => sonnerToast.dismiss(id), +}; \ No newline at end of file diff --git a/tests/unit/lib/toast.test.ts b/tests/unit/lib/toast.test.ts new file mode 100644 index 0000000..15690d5 --- /dev/null +++ b/tests/unit/lib/toast.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +vi.mock('sonner', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + info: vi.fn(), + warning: vi.fn(), + promise: vi.fn(), + dismiss: vi.fn(), + }, +})); + +import { toast } from '@/lib/toast'; +import { toast as sonnerToast } from 'sonner'; + +describe('toast helpers', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('toast.success forwards to sonner with the message', () => { + toast.success('Saved test.md'); + expect(sonnerToast.success).toHaveBeenCalledWith('Saved test.md'); + }); + + it('toast.error forwards to sonner with the message', () => { + toast.error('Failed to save: ENOENT'); + expect(sonnerToast.error).toHaveBeenCalledWith('Failed to save: ENOENT'); + }); + + it('toast.info forwards to sonner with the message', () => { + toast.info('Update available'); + expect(sonnerToast.info).toHaveBeenCalledWith('Update available'); + }); + + it('toast.warning forwards to sonner with the message', () => { + toast.warning('Disk space low'); + expect(sonnerToast.warning).toHaveBeenCalledWith('Disk space low'); + }); + + it('toast.promise forwards the promise and messages to sonner', async () => { + const promise = Promise.resolve('ok'); + const msgs = { loading: 'Loading…', success: 'Done', error: 'Failed' }; + toast.promise(promise, msgs); + expect(sonnerToast.promise).toHaveBeenCalledWith(promise, msgs); + }); +});