diff --git a/CHANGELOG.md b/CHANGELOG.md index d851101a3..d13487ff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to ### Added - 🔧(backend) settings CONVERSION_UPLOAD_ENABLED to control usage of docspec +- 🥚(frontend) add easter egg on doc emoji creation #2155 ### Changed diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxEmoji.spec.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxEmoji.spec.tsx new file mode 100644 index 000000000..5e0024cce --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxEmoji.spec.tsx @@ -0,0 +1,103 @@ +import { render } from '@testing-library/react'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +import { DropdownMenuOption } from '@/components'; +import { AppWrapper } from '@/tests/utils'; + +const mockUpdateDocEmoji = vi.fn(); +let capturedOptions: DropdownMenuOption[] = []; + +vi.mock('@/components', async () => { + const actual = await vi.importActual('@/components'); + return { + ...actual, + DropdownMenu: ({ options }: { options: DropdownMenuOption[] }) => { + capturedOptions = options; + return null; + }, + }; +}); + +vi.mock('next/router', async () => ({ + ...(await vi.importActual('next/router')), + useRouter: () => ({ push: vi.fn() }), +})); + +vi.mock('@/docs/doc-management', async () => { + const actual = await vi.importActual('@/docs/doc-management'); + return { + ...actual, + useDocTitleUpdate: () => ({ updateDocEmoji: mockUpdateDocEmoji }), + useDocUtils: () => ({ isChild: true, isTopRoot: false }), + useCopyDocLink: () => vi.fn(), + useCreateFavoriteDoc: () => ({ mutate: vi.fn() }), + useDeleteFavoriteDoc: () => ({ mutate: vi.fn() }), + useDuplicateDoc: () => ({ mutate: vi.fn() }), + }; +}); + +vi.mock('@/stores', () => ({ + useFocusStore: (selector?: (state: any) => any) => { + const state = { addLastFocus: vi.fn(), restoreFocus: vi.fn() }; + return selector ? selector(state) : state; + }, + useResponsiveStore: () => ({ + isSmallMobile: false, + isMobile: false, + isDesktop: true, + }), +})); + +vi.mock('../hooks/useCopyCurrentEditorToClipboard', () => ({ + useCopyCurrentEditorToClipboard: () => vi.fn(), +})); + +import { DocToolBox } from '../components/DocToolBox'; + +const doc = { + id: 'doc-1', + title: 'My document', + is_favorite: false, + nb_accesses_direct: 1, + abilities: { + versions_list: true, + destroy: true, + partial_update: true, + duplicate: true, + accesses_view: true, + }, +} as any; + +describe('DocToolBox - Add emoji (April Fools easter egg)', () => { + beforeEach(() => { + vi.useFakeTimers(); + mockUpdateDocEmoji.mockClear(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + [ + { emoji: '🐟', date: '2026-04-01' }, + { emoji: '📄', date: '2026-03-30' }, + { emoji: '📄', date: '2026-04-02' }, + ].forEach(({ emoji, date }) => { + test(`uses ${emoji} emoji on ${date}`, () => { + vi.setSystemTime(new Date(date)); + + render(, { wrapper: AppWrapper }); + + const addEmojiOption = capturedOptions.find( + (o) => o.label === 'Add emoji', + ); + void addEmojiOption?.callback?.(); + + expect(mockUpdateDocEmoji).toHaveBeenCalledWith( + 'doc-1', + 'My document', + emoji, + ); + }); + }); +}); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx index baff5461c..ad781879c 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx @@ -169,7 +169,9 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { label: t('Add emoji'), icon: