返回 oh-my-ppt
useSessionPageActions.test.ts
根目录 / tests / unit / session / useSessionPageActions.test.ts
1 /**
2 * @vitest-environment happy-dom
3 */
4 import React, { act } from 'react'
5 import { beforeEach, describe, expect, it, vi } from 'vitest'
6 import { createRoot, type Root } from 'react-dom/client'
7 import { useSessionPageActions } from '../../../src/renderer/src/components/session-detail/hooks/useSessionPageActions'
8 import { useSessionDetailUiStore } from '../../../src/renderer/src/store/sessionDetailStore'
9 import { useSessionStore } from '../../../src/renderer/src/store/sessionStore'
10 import type { SessionPreviewPage } from '../../../src/renderer/src/components/session-detail/shared/types'
11
12 vi.mock('sonner', () => {
13 const fn = (() => '') as unknown as {
14 success: () => string
15 error: () => string
16 info: () => string
17 warning: () => string
18 loading: () => string
19 promise: () => void
20 dismiss: () => void
21 }
22 fn.success = fn
23 fn.error = fn
24 fn.info = fn
25 fn.warning = fn
26 fn.loading = fn
27 fn.promise = () => {}
28 fn.dismiss = () => {}
29 return { toast: fn }
30 })
31
32 const ipcMocks = vi.hoisted(() => ({
33 exportPptx: vi.fn(),
34 onExportProgress: vi.fn()
35 }))
36
37 vi.mock('@renderer/lib/ipc', () => ({
38 ipc: {
39 exportPptx: ipcMocks.exportPptx,
40 onExportProgress: ipcMocks.onExportProgress
41 }
42 }))
43
44 vi.mock('@renderer/i18n', () => ({
45 useT: () => (key: string) => key
46 }))
47
48 type PageActions = ReturnType<typeof useSessionPageActions>
49
50 let latest: PageActions | null = null
51
52 function Harness({ sessionId }: { sessionId: string }): null {
53 latest = useSessionPageActions(sessionId)
54 return null
55 }
56
57 async function renderHarness(sessionId = 'session-1'): Promise<{
58 root: Root
59 container: HTMLDivElement
60 }> {
61 const container = document.createElement('div')
62 document.body.appendChild(container)
63 const root = createRoot(container)
64 await act(async () => {
65 root.render(React.createElement(Harness, { sessionId }))
66 })
67 return { root, container }
68 }
69
70 async function cleanup(root: Root, container: HTMLDivElement): Promise<void> {
71 await act(async () => {
72 root.unmount()
73 })
74 container.remove()
75 }
76
77 describe('useSessionPageActions', () => {
78 beforeEach(() => {
79 latest = null
80 ipcMocks.exportPptx.mockReset()
81 ipcMocks.exportPptx.mockResolvedValue({
82 success: true,
83 cancelled: false,
84 path: '/tmp/page.pptx',
85 pageCount: 1,
86 warnings: []
87 })
88 ipcMocks.onExportProgress.mockReset()
89 ipcMocks.onExportProgress.mockReturnValue(() => undefined)
90 useSessionDetailUiStore.getState().resetForSessionChange()
91 useSessionStore.setState({
92 currentSession: {
93 slideSizeId: 'wide-16-9',
94 slideWidth: 1600,
95 slideHeight: 900
96 } as never
97 })
98 })
99
100 it('exports the requested page as PPTX', async () => {
101 const page = { id: 'page-2', title: 'Page 2' } as SessionPreviewPage
102 const { root, container } = await renderHarness()
103
104 try {
105 await act(async () => {
106 latest?.exportPagePptx(page, { imageOnly: true })
107 })
108
109 expect(ipcMocks.exportPptx).toHaveBeenCalledWith('session-1', {
110 pageId: 'page-2',
111 imageOnly: true
112 })
113 } finally {
114 await cleanup(root, container)
115 }
116 })
117 })
118
118 lines TYPESCRIPT