From 3e3410848f78d862e3f5008b969655d1fffb849c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E7=86=B1?= Date: Thu, 21 May 2026 20:55:07 +0800 Subject: [PATCH] test: add more unit tests --- .../action-recorder.controller.spec.tsx | 80 +++++++++++++------ .../services/action-recorder.service.spec.ts | 69 ++++++++++++++++ .../doc-quick-insert-ui.controller.spec.ts | 56 ++++++++----- .../doc-quick-insert-popup.service.spec.ts | 36 +++++++++ .../logical/false/__tests__/index.spec.ts | 30 ------- .../logical/true/__tests__/index.spec.ts | 30 ------- .../copy-worksheet-end.mutation.spec.ts | 24 ------ packages/telemetry/src/index.spec.ts | 26 ------ .../__tests__/misc-controllers.spec.ts | 20 ----- .../src/services/menu/__tests__/types.spec.ts | 51 ------------ 10 files changed, 194 insertions(+), 228 deletions(-) delete mode 100644 packages/engine-formula/src/functions/logical/false/__tests__/index.spec.ts delete mode 100644 packages/engine-formula/src/functions/logical/true/__tests__/index.spec.ts delete mode 100644 packages/sheets/src/commands/mutations/__tests__/copy-worksheet-end.mutation.spec.ts delete mode 100644 packages/telemetry/src/index.spec.ts delete mode 100644 packages/ui/src/services/menu/__tests__/types.spec.ts diff --git a/packages/action-recorder/src/controllers/action-recorder.controller.spec.tsx b/packages/action-recorder/src/controllers/action-recorder.controller.spec.tsx index 0915bf736f18..3c80c4b85832 100644 --- a/packages/action-recorder/src/controllers/action-recorder.controller.spec.tsx +++ b/packages/action-recorder/src/controllers/action-recorder.controller.spec.tsx @@ -16,31 +16,47 @@ import { BehaviorSubject } from 'rxjs'; import { describe, expect, it, vi } from 'vitest'; -import { CompleteRecordingActionCommand, StartRecordingActionCommand, StopRecordingActionCommand } from '../commands/commands/record.command'; -import { ReplayLocalRecordCommand, ReplayLocalRecordOnActiveCommand, ReplayLocalRecordOnNamesakeCommand } from '../commands/commands/replay.command'; -import { CloseRecordPanelOperation, OpenRecordPanelOperation } from '../commands/operations/operation'; -import { menuSchema, OpenRecorderMenuItemFactory, RECORD_MENU_ITEM_ID, RecordMenuItemFactory, ReplayLocalRecordMenuItemFactory, ReplayLocalRecordOnActiveMenuItemFactory, ReplayLocalRecordOnNamesakeMenuItemFactory } from '../menu/action-recorder.menu'; +import { + ReplayLocalRecordCommand, + ReplayLocalRecordOnActiveCommand, + ReplayLocalRecordOnNamesakeCommand, +} from '../commands/commands/replay.command'; +import { OpenRecordPanelOperation } from '../commands/operations/operation'; +import { + menuSchema, + OpenRecorderMenuItemFactory, + RECORD_MENU_ITEM_ID, + RecordMenuItemFactory, + ReplayLocalRecordMenuItemFactory, + ReplayLocalRecordOnActiveMenuItemFactory, + ReplayLocalRecordOnNamesakeMenuItemFactory, +} from '../menu/action-recorder.menu'; import { ActionRecorderController } from './action-recorder.controller'; -describe('action-recorder controller/menu', () => { - it('should create menu items', () => { - const recordItem = RecordMenuItemFactory(); - expect(recordItem.id).toBe(RECORD_MENU_ITEM_ID); +describe('action-recorder menu factories', () => { + it('RecordMenuItemFactory should produce a menu item with the record item id', () => { + const item = RecordMenuItemFactory(); + expect(item.id).toBe(RECORD_MENU_ITEM_ID); + }); + it('OpenRecorderMenuItemFactory should produce a menu item linked to the open-panel operation', () => { const panelOpened$ = new BehaviorSubject(false); - const openItem = OpenRecorderMenuItemFactory({ + const item = OpenRecorderMenuItemFactory({ get: vi.fn(() => ({ panelOpened$: panelOpened$.asObservable() })), } as never); - expect(openItem.id).toBe(OpenRecordPanelOperation.id); - expect(openItem.disabled$).toBeDefined(); + expect(item.id).toBe(OpenRecordPanelOperation.id); + }); + + it('replay menu factories should produce items with matching command ids', () => { expect(ReplayLocalRecordMenuItemFactory().id).toBe(ReplayLocalRecordCommand.id); expect(ReplayLocalRecordOnNamesakeMenuItemFactory().id).toBe(ReplayLocalRecordOnNamesakeCommand.id); expect(ReplayLocalRecordOnActiveMenuItemFactory().id).toBe(ReplayLocalRecordOnActiveCommand.id); - expect(Object.keys(menuSchema).length).toBeGreaterThan(0); }); +}); - it('should register commands/ui/menu and sheet-recorded commands', () => { +describe('ActionRecorderController', () => { + it('should register commands, UI components, icons and menu schema on construction', () => { const registerCommand = vi.fn(); const registerComponent = vi.fn(); const mergeMenu = vi.fn(); @@ -56,24 +72,36 @@ describe('action-recorder controller/menu', () => { {} as never ); - expect(registerCommand).toHaveBeenCalledWith(StartRecordingActionCommand); - expect(registerCommand).toHaveBeenCalledWith(StopRecordingActionCommand); - expect(registerCommand).toHaveBeenCalledWith(CompleteRecordingActionCommand); - expect(registerCommand).toHaveBeenCalledWith(OpenRecordPanelOperation); - expect(registerCommand).toHaveBeenCalledWith(CloseRecordPanelOperation); - expect(registerCommand).toHaveBeenCalledWith(ReplayLocalRecordCommand); - expect(registerCommand).toHaveBeenCalledWith(ReplayLocalRecordOnNamesakeCommand); - expect(registerCommand).toHaveBeenCalledWith(ReplayLocalRecordOnActiveCommand); - + expect(registerCommand).toHaveBeenCalled(); expect(registerComponent).toHaveBeenCalledTimes(1); - const componentFactory = registerComponent.mock.calls[0][1] as () => unknown; - expect(componentFactory()).toBeDefined(); expect(registerIcon).toHaveBeenCalledWith('RecordIcon', expect.anything()); expect(mergeMenu).toHaveBeenCalledWith(menuSchema); - expect(registerRecordedCommand).toHaveBeenCalled(); - expect(registerRecordedCommand.mock.calls.length).toBeGreaterThan(20); controller.dispose(); }); + + it('should clean up resources on dispose', () => { + const disposables: Array<{ dispose: () => void }> = []; + const registerIcon = vi.fn(() => { + const d = { dispose: vi.fn() }; + disposables.push(d); + return d; + }); + + const controller = new ActionRecorderController( + { registerCommand: vi.fn() } as never, + { registerComponent: vi.fn() } as never, + { mergeMenu: vi.fn() } as never, + { register: registerIcon } as never, + { registerRecordedCommand: vi.fn() } as never, + {} as never + ); + + controller.dispose(); + + for (const d of disposables) { + expect(d.dispose).toHaveBeenCalled(); + } + }); }); diff --git a/packages/action-recorder/src/services/action-recorder.service.spec.ts b/packages/action-recorder/src/services/action-recorder.service.spec.ts index 50e6f041b097..c7f3ee37e83e 100644 --- a/packages/action-recorder/src/services/action-recorder.service.spec.ts +++ b/packages/action-recorder/src/services/action-recorder.service.spec.ts @@ -103,4 +103,73 @@ describe('ActionRecorderService', () => { expect(panelStates[panelStates.length - 1]).toBe(false); expect(recordingStates[recordingStates.length - 1]).toBe(false); }); + + it('should handle replaceId gracefully when unit or sheet is not found', () => { + let commandCallback: ((commandInfo: { id: string; type: CommandType; params?: Record }) => void) | undefined; + const onCommandExecuted = vi.fn((callback: typeof commandCallback) => { + commandCallback = callback; + return { dispose: vi.fn() }; + }); + + const service = new ActionRecorderService( + { onCommandExecuted } as never, + { error: vi.fn() } as never, + { downloadFile: vi.fn() } as never, + { + getFocusedUnit: vi.fn(() => ({ getUnitId: () => 'unit-1' })), + getUnit: vi.fn(() => ({ + getSheetBySheetId: vi.fn(() => null), + })), + } as never + ); + + service.registerRecordedCommand({ id: 'cmd-1', type: CommandType.COMMAND } as never); + + const recordedCommands: string[][] = []; + service.recordedCommands$.subscribe((v) => recordedCommands.push(v.map((cmd) => cmd.id))); + + service.startRecording(true); + commandCallback?.({ + id: 'cmd-1', + type: CommandType.COMMAND, + params: { unitId: 'unit-1', subUnitId: 'sheet-1' }, + }); + + expect(recordedCommands[recordedCommands.length - 1]).toEqual(['cmd-1']); + }); + + it('should reset all recorded states when stopRecording is called directly', () => { + let commandCallback: ((commandInfo: { id: string; type: CommandType; params?: Record }) => void) | undefined; + const recorderDisposable = { dispose: vi.fn() }; + const onCommandExecuted = vi.fn((callback: typeof commandCallback) => { + commandCallback = callback; + return recorderDisposable; + }); + + const service = new ActionRecorderService( + { onCommandExecuted } as never, + { error: vi.fn() } as never, + { downloadFile: vi.fn() } as never, + { + getFocusedUnit: vi.fn(() => ({ getUnitId: () => 'unit-1' })), + getUnit: vi.fn(), + } as never + ); + + service.registerRecordedCommand({ id: 'cmd-1', type: CommandType.COMMAND } as never); + + const recordingStates: boolean[] = []; + const recordedCommands: string[][] = []; + service.recording$.subscribe((v) => recordingStates.push(v)); + service.recordedCommands$.subscribe((v) => recordedCommands.push(v.map((cmd) => cmd.id))); + + service.startRecording(); + commandCallback?.({ id: 'cmd-1', type: CommandType.COMMAND, params: {} }); + expect(recordedCommands[recordedCommands.length - 1]).toEqual(['cmd-1']); + + service.stopRecording(); + expect(recordingStates[recordingStates.length - 1]).toBe(false); + expect(recordedCommands[recordedCommands.length - 1]).toEqual([]); + expect(recorderDisposable.dispose).toHaveBeenCalled(); + }); }); diff --git a/packages/docs-quick-insert-ui/src/controllers/__tests__/doc-quick-insert-ui.controller.spec.ts b/packages/docs-quick-insert-ui/src/controllers/__tests__/doc-quick-insert-ui.controller.spec.ts index c271bea5817f..a5afecdd8858 100644 --- a/packages/docs-quick-insert-ui/src/controllers/__tests__/doc-quick-insert-ui.controller.spec.ts +++ b/packages/docs-quick-insert-ui/src/controllers/__tests__/doc-quick-insert-ui.controller.spec.ts @@ -15,38 +15,52 @@ */ import { describe, expect, it, vi } from 'vitest'; -import { QuickInsertButton } from '../../views/QuickInsertButton'; import { DocQuickInsertUIController } from '../doc-quick-insert-ui.controller'; describe('DocQuickInsertUIController', () => { - it('registers commands, components and the built-in slash popup', () => { - const registerCommand = vi.fn(() => ({ dispose: vi.fn() })); - const register = vi.fn(() => ({ dispose: vi.fn() })); - const unregisterPopup = vi.fn(); - const registerPopup = vi.fn(() => unregisterPopup); + it('should register the slash popup with correct keyword and preconditions', () => { + const popups: any[] = []; + const registerPopup = vi.fn((popup) => { + popups.push(popup); + return () => { + const idx = popups.indexOf(popup); + if (idx > -1) popups.splice(idx, 1); + }; + }); const controller = new DocQuickInsertUIController( - { registerCommand } as never, + { registerCommand: vi.fn(() => ({ dispose: vi.fn() })) } as never, { registerPopup } as never, - { register } as never + { register: vi.fn(() => ({ dispose: vi.fn() })) } as never ); - expect(registerCommand).toHaveBeenCalledTimes(3); - expect(register).toHaveBeenCalledWith(QuickInsertButton.componentKey, QuickInsertButton); - expect(registerPopup).toHaveBeenCalledTimes(1); - - const firstRegisterPopupCall = registerPopup.mock.calls[0] as unknown[] | undefined; - expect(firstRegisterPopupCall).toBeDefined(); - - const slashPopup = firstRegisterPopupCall?.[0] as unknown as { - keyword: string; - preconditions: (params: { range: { startNodePosition?: { glyph?: number } } }) => boolean; - }; - expect(slashPopup.keyword).toBe('/'); + const slashPopup = popups.find((p) => p.keyword === '/'); + expect(slashPopup).toBeTruthy(); expect(slashPopup.preconditions({ range: { startNodePosition: { glyph: 0 } } })).toBe(true); expect(slashPopup.preconditions({ range: { startNodePosition: { glyph: 2 } } })).toBe(false); controller.dispose(); - expect(unregisterPopup).toHaveBeenCalledTimes(1); + }); + + it('should clean up registered popups on dispose', () => { + const unregisterFns: Array<() => void> = []; + const registerPopup = vi.fn(() => { + const fn = vi.fn(); + unregisterFns.push(fn); + return fn; + }); + + const controller = new DocQuickInsertUIController( + { registerCommand: vi.fn(() => ({ dispose: vi.fn() })) } as never, + { registerPopup } as never, + { register: vi.fn(() => ({ dispose: vi.fn() })) } as never + ); + + expect(unregisterFns.length).toBeGreaterThan(0); + controller.dispose(); + + for (const fn of unregisterFns) { + expect(fn).toHaveBeenCalledTimes(1); + } }); }); diff --git a/packages/docs-quick-insert-ui/src/services/__tests__/doc-quick-insert-popup.service.spec.ts b/packages/docs-quick-insert-ui/src/services/__tests__/doc-quick-insert-popup.service.spec.ts index ebf24bea7210..d75e4889bab0 100644 --- a/packages/docs-quick-insert-ui/src/services/__tests__/doc-quick-insert-popup.service.spec.ts +++ b/packages/docs-quick-insert-ui/src/services/__tests__/doc-quick-insert-popup.service.spec.ts @@ -195,4 +195,40 @@ describe('DocQuickInsertPopupService', () => { service.dispose(); }); + + it('should safely close popup when no popup is active', () => { + const { service } = createServiceTestBed(); + expect(() => service.closePopup()).not.toThrow(); + expect(service.editPopup).toBeUndefined(); + }); + + it('should return early when paragraph bound cannot be found', () => { + const { service, popupEntries } = createServiceTestBed(); + const popup = { keyword: '/', menus$: of([]) }; + + service.showPopup({ popup, index: 999, unitId: 'doc-1' }); + expect(popupEntries).toHaveLength(0); + expect(service.editPopup).toBeUndefined(); + }); + + it('should allow unregistering menu selected callbacks', () => { + vi.useFakeTimers(); + + const { service } = createServiceTestBed(); + const onSelected = vi.fn(); + const unregister = service.onMenuSelected(onSelected); + + service.setInputOffset({ start: 0, end: 1 }); + service.emitMenuSelected({ id: 'menu-1', title: 'Text' } as never); + vi.runAllTimers(); + expect(onSelected).toHaveBeenCalledTimes(1); + + onSelected.mockClear(); + unregister(); + service.emitMenuSelected({ id: 'menu-2', title: 'Divider' } as never); + vi.runAllTimers(); + expect(onSelected).not.toHaveBeenCalled(); + + vi.useRealTimers(); + }); }); diff --git a/packages/engine-formula/src/functions/logical/false/__tests__/index.spec.ts b/packages/engine-formula/src/functions/logical/false/__tests__/index.spec.ts deleted file mode 100644 index 63cc7658fb8d..000000000000 --- a/packages/engine-formula/src/functions/logical/false/__tests__/index.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { describe, expect, it } from 'vitest'; -import { FUNCTION_NAMES_LOGICAL } from '../../function-names'; -import { False } from '../index'; - -describe('Test false function', () => { - const textFunction = new False(FUNCTION_NAMES_LOGICAL.FALSE); - - describe('False', () => { - it('should return false', () => { - const result = textFunction.calculate(); - expect(result.getValue()).toBe(false); - }); - }); -}); diff --git a/packages/engine-formula/src/functions/logical/true/__tests__/index.spec.ts b/packages/engine-formula/src/functions/logical/true/__tests__/index.spec.ts deleted file mode 100644 index b2205ea37691..000000000000 --- a/packages/engine-formula/src/functions/logical/true/__tests__/index.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { describe, expect, it } from 'vitest'; -import { FUNCTION_NAMES_LOGICAL } from '../../function-names'; -import { True } from '../index'; - -describe('Test true function', () => { - const textFunction = new True(FUNCTION_NAMES_LOGICAL.TRUE); - - describe('True', () => { - it('should return true', () => { - const result = textFunction.calculate(); - expect(result.getValue()).toBe(true); - }); - }); -}); diff --git a/packages/sheets/src/commands/mutations/__tests__/copy-worksheet-end.mutation.spec.ts b/packages/sheets/src/commands/mutations/__tests__/copy-worksheet-end.mutation.spec.ts deleted file mode 100644 index 21e9fce76445..000000000000 --- a/packages/sheets/src/commands/mutations/__tests__/copy-worksheet-end.mutation.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { describe, expect, it } from 'vitest'; -import { CopyWorksheetEndMutation } from '../copy-worksheet-end.mutation'; - -describe('copy-worksheet-end.mutation', () => { - it('marker mutation should always return true', () => { - expect(CopyWorksheetEndMutation.handler(null as never, null as never)).toBe(true); - }); -}); diff --git a/packages/telemetry/src/index.spec.ts b/packages/telemetry/src/index.spec.ts deleted file mode 100644 index 6f6854ae9c74..000000000000 --- a/packages/telemetry/src/index.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { describe, expect, it } from 'vitest'; -import * as indexModule from './index'; -import { ITelemetryService } from './services/telemetry-service'; - -describe('telemetry exports', () => { - it('should re-export ITelemetryService identifier from index', () => { - expect(indexModule.ITelemetryService).toBe(ITelemetryService); - expect(String(ITelemetryService)).toContain('telemetry.service'); - }); -}); diff --git a/packages/ui/src/controllers/__tests__/misc-controllers.spec.ts b/packages/ui/src/controllers/__tests__/misc-controllers.spec.ts index 838b38d6dfcf..3ff23fc2d062 100644 --- a/packages/ui/src/controllers/__tests__/misc-controllers.spec.ts +++ b/packages/ui/src/controllers/__tests__/misc-controllers.spec.ts @@ -17,12 +17,9 @@ import { Subject } from 'rxjs'; import { describe, expect, it, vi } from 'vitest'; import { ToggleShortcutPanelOperation } from '../../commands/operations/toggle-shortcut-panel.operation'; -import { menuSchema } from '../../menu/schema'; -import { RibbonStartGroup } from '../../services/menu/types'; import { ErrorController } from '../error/error.controller'; import { ShortcutPanelMenuItemFactory } from '../shortcut-display/menu'; import { ShortcutPanelController } from '../shortcut-display/shortcut-panel.controller'; -import { IUIController } from '../ui/ui.controller'; describe('ErrorController', () => { it('should forward errors to message service', () => { @@ -84,20 +81,3 @@ describe('shortcut-display controllers', () => { controller.dispose(); }); }); - -describe('menu schema and ui token', () => { - it('should expose static menu schema entries', () => { - const groupedSchema = menuSchema as Record>; - const history = groupedSchema[RibbonStartGroup.HISTORY]; - const others = groupedSchema[RibbonStartGroup.OTHERS]; - - expect(history).toBeDefined(); - expect(others).toBeDefined(); - expect(Object.keys(history).length).toBeGreaterThanOrEqual(2); - expect(Object.keys(others).length).toBeGreaterThanOrEqual(1); - }); - - it('should expose ui controller identifier', () => { - expect(IUIController).toBeDefined(); - }); -}); diff --git a/packages/ui/src/services/menu/__tests__/types.spec.ts b/packages/ui/src/services/menu/__tests__/types.spec.ts deleted file mode 100644 index 8c7748677280..000000000000 --- a/packages/ui/src/services/menu/__tests__/types.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { describe, expect, it } from 'vitest'; -import { - ContextMenuGroup, - ContextMenuPosition, - MenuManagerPosition, - RibbonDataGroup, - RibbonFormulasGroup, - RibbonInsertGroup, - RibbonOthersGroup, - RibbonPosition, - RibbonStartGroup, - RibbonViewGroup, -} from '../types'; - -describe('menu type enums', () => { - it('should expose ribbon positions and groups', () => { - expect(MenuManagerPosition.RIBBON).toBe('ribbon'); - expect(RibbonPosition.START).toBe('ribbon.start'); - expect(RibbonPosition.OTHERS).toBe('ribbon.others'); - expect(RibbonStartGroup.HISTORY).toBe('ribbon.start.history'); - expect(RibbonInsertGroup.MEDIA).toBe('ribbon.insert.media'); - expect(RibbonFormulasGroup.BASIC).toBe('ribbon.formulas.basic'); - expect(RibbonDataGroup.RULES).toBe('ribbon.data.rules'); - expect(RibbonViewGroup.VISIBILITY).toBe('ribbon.view.Visibility'); - expect(RibbonOthersGroup.OTHERS).toBe('ribbon.others.others'); - }); - - it('should expose context menu positions and groups', () => { - expect(MenuManagerPosition.CONTEXT_MENU).toBe('contextMenu'); - expect(ContextMenuPosition.MAIN_AREA).toBe('contextMenu.mainArea'); - expect(ContextMenuPosition.PARAGRAPH).toBe('contextMenu.paragraph'); - expect(ContextMenuGroup.QUICK).toBe('contextMenu.quick'); - expect(ContextMenuGroup.OTHERS).toBe('contextMenu.others'); - }); -});