/** * Tests for gesture command execution via executeCommandById. * * Chainlink #346: F-COMMANDS-9 * - Gestures should use executeCommandById instead of getCommand + executeCommand * - Missing-editor cases should show Notice * - Command-not-found cases should show Notice */ import { describe, it, expect, vi, beforeEach } from 'vitest' // Mock obsidian Notice before importing the module under test const mockNotice = vi.fn() vi.mock('obsidian', () => ({ Notice: mockNotice, })) // Mock gesture settings vi.mock('../gesture-settings', () => ({ loadGestureSettings: vi.fn(() => ({ enabled: true, leftEdge: true, rightEdge: true, topEdge: true, bottomEdge: true, topCommand: 'test-plugin:test-command', bottomCommand: 'test-plugin:another-command', })), })) describe('gesture command execution', () => { beforeEach(() => { vi.clearAllMocks() }) describe('executeGestureCommand', () => { // Import the function dynamically to ensure mocks are set up // The function expects CommandRegistry, but we pass mock objects in tests let executeGestureCommand: (commandId: string, commands: unknown) => void beforeEach(async () => { // Reset module cache to pick up fresh mocks vi.resetModules() const module = await import('../gesture-command-utils') // Cast to allow mock objects in tests executeGestureCommand = module.executeGestureCommand as (commandId: string, commands: unknown) => void }) it('calls executeCommandById with the command ID', async () => { const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('executed'), } executeGestureCommand('test-plugin:test-command', mockCommands) expect(mockCommands.executeCommandByIdWithResult).toHaveBeenCalledWith('test-plugin:test-command') expect(mockNotice).not.toHaveBeenCalled() }) it('shows Notice when command not found', async () => { const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('not-found'), } executeGestureCommand('nonexistent:command', mockCommands) expect(mockNotice).toHaveBeenCalledWith('Command not found: nonexistent:command') }) it('shows Notice when editor-only command has no active editor', async () => { const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('editor-required'), } executeGestureCommand('test-plugin:editor-command', mockCommands) expect(mockNotice).toHaveBeenCalledWith('This command requires an active editor') }) it('shows Notice when a non-editor command is currently unavailable', async () => { const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('unavailable'), } executeGestureCommand('test-plugin:unavailable-command', mockCommands) expect(mockNotice).toHaveBeenCalledWith('This command is not currently available') }) it('does NOT show Notice when command executes successfully', async () => { const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('executed'), } executeGestureCommand('test-plugin:working-command', mockCommands) expect(mockNotice).not.toHaveBeenCalled() }) it('handles editor-only commands that also have regular callback', async () => { // Editor-scoped callbacks take precedence over plain callbacks. const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('editor-required'), } executeGestureCommand('test-plugin:hybrid-command', mockCommands) expect(mockNotice).toHaveBeenCalledWith('This command requires an active editor') }) it('handles checkCallback-only commands', async () => { // Commands with only checkCallback execute fine without editor const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('executed'), } executeGestureCommand('test-plugin:check-command', mockCommands) expect(mockNotice).not.toHaveBeenCalled() }) it('does not add a second Notice when command availability already surfaced the failure', async () => { const mockCommands = { executeCommandByIdWithResult: vi.fn().mockReturnValue('already-notified'), } executeGestureCommand('test-plugin:throwing-check', mockCommands) expect(mockNotice).not.toHaveBeenCalled() }) }) })