UNPKG

tui-tester

Version:

End-to-end testing framework for terminal user interfaces

1 lines 14.8 kB
{"version":3,"sources":["../../src/helpers/interactions.ts"],"names":[],"mappings":"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","file":"interactions.cjs","sourcesContent":["/**\n * High-Level Interaction Helpers\n * Utilities for common terminal UI interactions\n */\n\nimport type { Point, WaitOptions, TerminalTester } from '../core/types.js';\n\n/**\n * Navigate menu using arrow keys\n */\nexport async function navigateMenu(\n tester: TerminalTester,\n direction: 'up' | 'down' | 'left' | 'right',\n count: number = 1\n): Promise<void> {\n for (let i = 0; i < count; i++) {\n await tester.sendKey(direction);\n await tester.sleep(100);\n }\n}\n\n/**\n * Select menu item by text\n */\nexport async function selectMenuItem(\n tester: TerminalTester,\n itemText: string,\n maxAttempts: number = 10\n): Promise<void> {\n // Try to find the item\n for (let i = 0; i < maxAttempts; i++) {\n const screen = await tester.getScreenText();\n \n if (screen.includes(`> ${itemText}`) || screen.includes(`● ${itemText}`)) {\n // Item is selected, press enter\n await tester.sendKey('enter');\n return;\n }\n \n // Try navigating down\n await tester.sendKey('down');\n await tester.sleep(100);\n }\n \n throw new Error(`Menu item \"${itemText}\" not found after ${maxAttempts} attempts`);\n}\n\n/**\n * Fill form field\n */\nexport async function fillField(\n tester: TerminalTester,\n fieldName: string,\n value: string\n): Promise<void> {\n // Wait for field to be visible\n await tester.waitForText(fieldName);\n \n // Clear existing value (Ctrl+A, Delete)\n await tester.sendKey('a', { ctrl: true });\n await tester.sendKey('delete');\n \n // Type new value\n await tester.typeText(value);\n \n // Move to next field\n await tester.sendKey('tab');\n}\n\n/**\n * Submit form\n * Optionally fill form fields before submitting\n */\nexport async function submitForm(\n tester: TerminalTester,\n formData?: Record<string, string>\n): Promise<void> {\n // If form data is provided, fill each field\n if (formData) {\n for (const [field, value] of Object.entries(formData)) {\n // Wait for field to be visible\n await tester.waitForText(field, { timeout: 5000 });\n \n // Type the value\n await tester.typeText(value);\n \n // Press Enter to move to next field\n await tester.sendKey('enter');\n await tester.sleep(200);\n }\n } else {\n // Just submit the form\n await tester.sendKey('enter');\n }\n}\n\n/**\n * Cancel dialog or form\n */\nexport async function cancel(tester: TerminalTester): Promise<void> {\n await tester.sendKey('escape');\n}\n\n/**\n * Confirm dialog\n */\nexport async function confirmDialog(\n tester: TerminalTester,\n accept: boolean = true\n): Promise<void> {\n if (accept) {\n await tester.sendKey('y');\n } else {\n await tester.sendKey('n');\n }\n}\n\n/**\n * Scroll content\n */\nexport async function scroll(\n tester: TerminalTester,\n direction: 'up' | 'down' | 'pageup' | 'pagedown' | 'home' | 'end',\n count: number = 1\n): Promise<void> {\n const key = direction === 'up' || direction === 'down' ? direction : direction.toLowerCase();\n \n for (let i = 0; i < count; i++) {\n await tester.sendKey(key);\n await tester.sleep(50);\n }\n}\n\n/**\n * Click on text\n */\nexport async function clickOnText(\n tester: TerminalTester,\n text: string\n): Promise<void> {\n const screen = await tester.getScreenText();\n const lines = screen.split('\\n');\n \n // Find text position\n for (let y = 0; y < lines.length; y++) {\n const x = lines[y].indexOf(text);\n if (x !== -1) {\n // Click on the text\n await tester.sendMouse({\n type: 'click',\n position: { x, y },\n button: 'left'\n });\n return;\n }\n }\n \n throw new Error(`Text \"${text}\" not found on screen`);\n}\n\n/**\n * Click at position\n */\nexport async function clickAt(\n tester: TerminalTester,\n position: Point,\n button: 'left' | 'middle' | 'right' = 'left'\n): Promise<void> {\n await tester.sendMouse({\n type: 'click',\n position,\n button\n });\n}\n\n/**\n * Drag from one position to another\n */\nexport async function drag(\n tester: TerminalTester,\n from: Point,\n to: Point\n): Promise<void> {\n // Mouse down at start position\n await tester.sendMouse({\n type: 'down',\n position: from,\n button: 'left'\n });\n \n await tester.sleep(100);\n \n // Move to end position\n await tester.sendMouse({\n type: 'drag',\n position: to,\n button: 'left'\n });\n \n await tester.sleep(100);\n \n // Mouse up at end position\n await tester.sendMouse({\n type: 'up',\n position: to,\n button: 'left'\n });\n}\n\n/**\n * Select text by dragging\n */\nexport async function selectText(\n tester: TerminalTester,\n startText: string,\n endText: string\n): Promise<void> {\n const screen = await tester.getScreenText();\n const lines = screen.split('\\n');\n \n let startPos: Point | null = null;\n let endPos: Point | null = null;\n \n // Find start and end positions\n for (let y = 0; y < lines.length; y++) {\n const startX = lines[y].indexOf(startText);\n if (startX !== -1 && !startPos) {\n startPos = { x: startX, y };\n }\n \n const endX = lines[y].indexOf(endText);\n if (endX !== -1) {\n endPos = { x: endX + endText.length - 1, y };\n }\n }\n \n if (!startPos || !endPos) {\n throw new Error('Could not find text positions for selection');\n }\n \n await drag(tester, startPos, endPos);\n}\n\n/**\n * Copy selected text\n */\nexport async function copySelection(tester: TerminalTester): Promise<void> {\n await tester.sendKey('c', { ctrl: true });\n}\n\n/**\n * Paste from clipboard\n */\nexport async function pasteFromClipboard(tester: TerminalTester): Promise<void> {\n await tester.sendKey('v', { ctrl: true });\n}\n\n/**\n * Execute command in shell\n */\nexport async function executeCommand(\n tester: TerminalTester,\n command: string\n): Promise<void> {\n await tester.sendText(command);\n await tester.sendKey('enter');\n}\n\n/**\n * Wait for prompt\n */\nexport async function waitForPrompt(\n tester: TerminalTester,\n prompt: string = '$',\n options?: WaitOptions\n): Promise<void> {\n await tester.waitForText(prompt, options);\n}\n\n/**\n * Login to application\n */\nexport async function login(\n tester: TerminalTester,\n username: string,\n password: string\n): Promise<void> {\n // Wait for username prompt\n await tester.waitForText('Username:');\n await tester.typeText(username);\n await tester.sendKey('enter');\n \n // Wait for password prompt\n await tester.waitForText('Password:');\n await tester.typeText(password);\n await tester.sendKey('enter');\n}\n\n/**\n * Navigate through tabs\n */\nexport async function switchTab(\n tester: TerminalTester,\n tabIndex: number\n): Promise<void> {\n // Use Alt+number to switch tabs (common pattern)\n await tester.sendKey(tabIndex.toString(), { alt: true });\n}\n\n/**\n * Open command palette or menu\n */\nexport async function openCommandPalette(tester: TerminalTester): Promise<void> {\n await tester.sendKey('p', { ctrl: true, shift: true });\n}\n\n/**\n * Search for text\n */\nexport async function search(\n tester: TerminalTester,\n searchText: string\n): Promise<boolean> {\n // Get current screen content\n const screen = await tester.getScreenText();\n \n // Check if text exists\n return screen.includes(searchText);\n}\n\n/**\n * Exit application\n */\nexport async function exitApplication(\n tester: TerminalTester,\n force: boolean = false\n): Promise<void> {\n if (force) {\n await tester.sendKey('c', { ctrl: true });\n } else {\n await tester.sendKey('q');\n }\n}\n\n/**\n * Wait for loading to complete\n */\nexport async function waitForLoading(\n tester: TerminalTester,\n options?: WaitOptions\n): Promise<void> {\n // Wait for common loading indicators to disappear\n const indicators = ['Loading...', 'Please wait...', '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n \n await tester.waitForPattern(\n new RegExp(`^(?!.*(${indicators.join('|')})).*$`, 's'),\n options\n );\n}\n\n/**\n * Take screenshot with annotation\n */\nexport async function takeAnnotatedSnapshot(\n tester: TerminalTester,\n name: string,\n annotations?: { text: string; position: Point }[]\n): Promise<void> {\n const snapshot = await tester.takeSnapshot(name);\n \n // Add annotations to metadata\n if (annotations && snapshot.metadata) {\n snapshot.metadata.annotations = annotations;\n }\n \n await tester.saveSnapshot(snapshot);\n}"]}