From d2d42953e5352febdab0a0507236ac3d36752d00 Mon Sep 17 00:00:00 2001 From: edge Date: Fri, 31 Jul 2026 12:25:50 +0800 Subject: [PATCH] fix: detect iOS TextView as editable --- packages/core/src/perception/dom-trimmer.ts | 3 +- packages/core/src/perception/ios-parser.ts | 3 +- tests/flow/ios-textview-editable.test.ts | 54 +++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/flow/ios-textview-editable.test.ts diff --git a/packages/core/src/perception/dom-trimmer.ts b/packages/core/src/perception/dom-trimmer.ts index 6ec5bd2..1406ed0 100644 --- a/packages/core/src/perception/dom-trimmer.ts +++ b/packages/core/src/perception/dom-trimmer.ts @@ -266,7 +266,8 @@ function walkIOS(node: any, result: TrimmedNode[], parentContext: string = ''): const isFocused = node['@_hasFocus'] === 'true'; const isSelected = node['@_selected'] === 'true'; - const editableTypes = ['TextField', 'SecureTextField', 'TextEditor', 'SearchField']; + // XCUITest exposes UIKit/RN multiline inputs (including KRN composers) as TextView. + const editableTypes = ['TextField', 'TextView', 'SecureTextField', 'TextEditor', 'SearchField']; const editable = editableTypes.some((t) => tag.includes(t)); const clickable = isAccessible || diff --git a/packages/core/src/perception/ios-parser.ts b/packages/core/src/perception/ios-parser.ts index d6ee2fe..8fa2848 100644 --- a/packages/core/src/perception/ios-parser.ts +++ b/packages/core/src/perception/ios-parser.ts @@ -17,7 +17,8 @@ function shortTypeName(xcuiType: string): string { /** Check if an iOS element type is typically editable */ function isEditableType(typeName: string): boolean { - const editableTypes = ['TextField', 'SecureTextField', 'TextEditor', 'SearchField']; + // XCUITest exposes UIKit/RN multiline inputs (including KRN composers) as TextView. + const editableTypes = ['TextField', 'TextView', 'SecureTextField', 'TextEditor', 'SearchField']; return editableTypes.some((t) => typeName.includes(t)); } diff --git a/tests/flow/ios-textview-editable.test.ts b/tests/flow/ios-textview-editable.test.ts new file mode 100644 index 0000000..729020c --- /dev/null +++ b/tests/flow/ios-textview-editable.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, test } from 'vitest'; +import { resolveEditableForTarget } from '@appclaw/core/flow/run-yaml-flow'; +import { trimDOM } from '@appclaw/core/perception/dom-trimmer'; +import { parseIOSPageSource } from '@appclaw/core/perception/ios-parser'; + +const krnComposerSource = ` + + + + +`; + +describe('iOS XCUIElementTypeTextView inputs', () => { + test('page-source parser exposes a TextView as an editable type target', () => { + const elements = parseIOSPageSource(krnComposerSource); + const input = elements.find((element) => element.id === 'kitchen-composer-text-input'); + + expect(input).toMatchObject({ + type: 'TextView', + editable: true, + action: 'type', + }); + expect(resolveEditableForTarget(elements, 'kitchen-composer-text-input').el).toBe(input); + }); + + test('DOM trimmer marks a TextView editable and includes it in editableCount', () => { + const result = trimDOM(krnComposerSource, 'ios'); + + expect(result.editableCount).toBe(1); + expect(result.xml).toContain('