mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-21 04:10:47 +02:00
Standalone planner that turns the IOSQAFlow JSON contract into an xcodebuild XCUITest invocation for simulator or physical device, using semantic selectors (identifier/role/label) and no coordinate taps. Pure plan generation; covered by 7 unit tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
export type IOSQATarget =
|
|
| { kind: 'simulator'; udid: string }
|
|
| { kind: 'device'; udid: string };
|
|
|
|
export type ElementRole =
|
|
| 'button'
|
|
| 'cell'
|
|
| 'link'
|
|
| 'navigationBar'
|
|
| 'secureTextField'
|
|
| 'staticText'
|
|
| 'switch'
|
|
| 'textField';
|
|
|
|
export interface ElementSelector {
|
|
/** Stable accessibility identifiers are always attempted before fallback fields. */
|
|
identifier?: string;
|
|
label?: string;
|
|
role?: ElementRole;
|
|
}
|
|
|
|
export type Verification =
|
|
| { kind: 'exists'; selector: ElementSelector; timeoutMs?: number }
|
|
| { kind: 'notExists'; selector: ElementSelector; timeoutMs?: number }
|
|
| { kind: 'labelEquals'; selector: ElementSelector; value: string; timeoutMs?: number };
|
|
|
|
export type FlowStep =
|
|
| { id: string; action: 'launch'; arguments?: string[]; environment?: Record<string, string>; verify?: Verification }
|
|
| { id: string; action: 'tap'; selector: ElementSelector; timeoutMs?: number; verify?: Verification }
|
|
| { id: string; action: 'typeText'; selector: ElementSelector; text: string; clear?: boolean; timeoutMs?: number; verify?: Verification }
|
|
| { id: string; action: 'swipe'; direction: 'up' | 'down' | 'left' | 'right'; selector?: ElementSelector; verify?: Verification }
|
|
| { id: string; action: 'wait'; verification: Verification };
|
|
|
|
export interface IOSQAFlow {
|
|
version: 1;
|
|
name: string;
|
|
bundleIdentifier?: string;
|
|
steps: FlowStep[];
|
|
}
|
|
|
|
export interface XCUITestRunnerConfig {
|
|
projectPath?: string;
|
|
workspacePath?: string;
|
|
scheme: string;
|
|
testIdentifier: string;
|
|
derivedDataPath?: string;
|
|
resultBundlePath?: string;
|
|
}
|
|
|
|
export interface ExecutorCapabilities {
|
|
semanticSelectors: readonly ['identifier', 'role', 'label'];
|
|
actions: readonly ['launch', 'tap', 'typeText', 'swipe', 'wait'];
|
|
targets: readonly ['simulator', 'device'];
|
|
coordinateTaps: false;
|
|
postActionVerification: true;
|
|
}
|
|
|
|
export const XCUITEST_CAPABILITIES: ExecutorCapabilities = {
|
|
semanticSelectors: ['identifier', 'role', 'label'],
|
|
actions: ['launch', 'tap', 'typeText', 'swipe', 'wait'],
|
|
targets: ['simulator', 'device'],
|
|
coordinateTaps: false,
|
|
postActionVerification: true,
|
|
};
|
|
|
|
export type PlanResult =
|
|
| { status: 'ready'; plan: XCUITestExecutionPlan }
|
|
| { status: 'blocked'; reason: string; remediation: string }
|
|
| { status: 'unsupported'; reason: string; stepId?: string };
|
|
|
|
export interface XCUITestExecutionPlan {
|
|
backend: 'xcuitest';
|
|
target: IOSQATarget;
|
|
capabilities: ExecutorCapabilities;
|
|
command: { executable: 'xcodebuild'; args: string[]; env: Record<string, string> };
|
|
flow: IOSQAFlow;
|
|
}
|