From 384b2409a2cddbd10f7149c4298e1e098eb95259 Mon Sep 17 00:00:00 2001 From: Schalli Date: Thu, 2 Jul 2026 10:15:17 +0200 Subject: [PATCH] fix(tests): add noCompactor mock + fix note-widget event simulation - dashboard-grid.test: add noCompactor to react-grid-layout mock - note-widget.test: enable edit mode before typing (onChange is undefined when isEditing=false), replace native dispatchEvent with fireEvent.change Co-Authored-By: Claude Sonnet 4.6 --- .../dashboard/dashboard-grid.test.tsx | 1 + .../dashboard/widgets/note-widget.test.tsx | 64 ++++++------------- 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/apps/web/src/components/dashboard/dashboard-grid.test.tsx b/apps/web/src/components/dashboard/dashboard-grid.test.tsx index cd97b6a..0999436 100644 --- a/apps/web/src/components/dashboard/dashboard-grid.test.tsx +++ b/apps/web/src/components/dashboard/dashboard-grid.test.tsx @@ -41,6 +41,7 @@ vi.mock('react-grid-layout', () => ({ }: { children: React.ReactNode; }) =>
{children}
, + noCompactor: () => null, })); // Mock dashboard-api diff --git a/apps/web/src/components/dashboard/widgets/note-widget.test.tsx b/apps/web/src/components/dashboard/widgets/note-widget.test.tsx index 8d3d332..9888bc1 100644 --- a/apps/web/src/components/dashboard/widgets/note-widget.test.tsx +++ b/apps/web/src/components/dashboard/widgets/note-widget.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen } from '@testing-library/react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; // Mock next-intl @@ -80,32 +80,15 @@ describe('NoteWidget', () => { , ); - const editor = screen.getByTestId('md-editor'); - - // Type into editor + // Enable edit mode so onChange is wired up await act(async () => { - editor.dispatchEvent( - new Event('change', { bubbles: true }), - ); - // Simulate onChange via the mock - const event = new Event('input', { bubbles: true }); - Object.defineProperty(event, 'target', { value: { value: '# Hello' } }); - // Use fireEvent approach + fireEvent.click(screen.getByRole('button')); }); - // Directly trigger onChange via the textarea - await act(async () => { - const textarea = screen.getByTestId('md-editor') as HTMLTextAreaElement; - // Change value triggers onChange in our mock - Object.getOwnPropertyDescriptor( - HTMLTextAreaElement.prototype, - 'value', - )?.set?.call(textarea, '# Hello'); - textarea.dispatchEvent(new Event('input', { bubbles: true })); - textarea.dispatchEvent(new Event('change', { bubbles: true })); - }); + const textarea = screen.getByTestId('md-editor') as HTMLTextAreaElement; // Before debounce fires, fetch should NOT have been called + fireEvent.change(textarea, { target: { value: '# Hello' } }); expect(fetchSpy).not.toHaveBeenCalled(); // Advance past debounce window @@ -126,18 +109,16 @@ describe('NoteWidget', () => { , ); + // Enable edit mode so onChange is wired up + await act(async () => { + fireEvent.click(screen.getByRole('button')); + }); + const textarea = screen.getByTestId('md-editor') as HTMLTextAreaElement; // Simulate rapid typing — three changes in quick succession for (const char of ['H', 'He', 'Hel']) { - await act(async () => { - Object.getOwnPropertyDescriptor( - HTMLTextAreaElement.prototype, - 'value', - )?.set?.call(textarea, char); - textarea.dispatchEvent(new Event('change', { bubbles: true })); - }); - // Small delay between keystrokes (less than debounce) + fireEvent.change(textarea, { target: { value: char } }); await act(async () => { vi.advanceTimersByTime(200); }); @@ -162,17 +143,15 @@ describe('NoteWidget', () => { , ); + // Enable edit mode so onChange is wired up + await act(async () => { + fireEvent.click(screen.getByRole('button')); + }); + const textarea = screen.getByTestId('md-editor') as HTMLTextAreaElement; // First change -> debounce -> save starts - await act(async () => { - Object.getOwnPropertyDescriptor( - HTMLTextAreaElement.prototype, - 'value', - )?.set?.call(textarea, 'first'); - textarea.dispatchEvent(new Event('change', { bubbles: true })); - }); - + fireEvent.change(textarea, { target: { value: 'first' } }); await act(async () => { vi.advanceTimersByTime(1500); }); @@ -181,14 +160,7 @@ describe('NoteWidget', () => { expect(fetchSpy).toHaveBeenCalledTimes(1); // Second change -> debounce -> should abort the first - await act(async () => { - Object.getOwnPropertyDescriptor( - HTMLTextAreaElement.prototype, - 'value', - )?.set?.call(textarea, 'second'); - textarea.dispatchEvent(new Event('change', { bubbles: true })); - }); - + fireEvent.change(textarea, { target: { value: 'second' } }); await act(async () => { vi.advanceTimersByTime(1500); });