Skip to main content
Glama
commandExample.ts5.69 kB
import { DeviceScreen, UIElement } from "./models"; import YAML from "yaml"; const YAML_STRINGIFY_OPTIONS: YAML.SchemaOptions = { toStringDefaults: { lineWidth: 0, defaultKeyType: "PLAIN", defaultStringType: "QUOTE_DOUBLE", }, }; const stringifyYaml = (value: any): string => { return YAML.stringify(value, null, YAML_STRINGIFY_OPTIONS); }; export type CommandExample = { status: "available" | "unavailable"; title: string; content: string; documentation: string; }; type Selector = | { title: string; status: "available"; definition: any; documentation?: string; } | { title: string; status: "unavailable"; message: string; documentation?: string; }; const toPercent = (n: number, total: number) => `${Math.round((100 * n) / total)}%`; const getCoordinatesSelector = ( deviceWidth: number, deviceHeight: number, uiElement: UIElement ): Selector => { const bounds = uiElement.bounds || { x: 0, y: 0, width: 0, height: 0 }; const cx = toPercent(bounds.x + bounds.width / 2, deviceWidth); const cy = toPercent(bounds.y + bounds.height / 2, deviceHeight); return { status: "available", title: "Coordinates", definition: { point: `${cx},${cy}` }, }; }; const getSelectors = ( uiElement: UIElement, deviceScreen: DeviceScreen ): Selector[] => { const selectors: Selector[] = []; if (uiElement.resourceId) { if (typeof uiElement.resourceIdIndex === "number") { selectors.push({ title: "Resource Id", status: "available", definition: { id: uiElement.resourceId, index: uiElement.resourceIdIndex, }, }); } else { selectors.push({ title: "Resource Id", status: "available", definition: { id: uiElement.resourceId, }, }); } } else { const elementsWithSameBounds = deviceScreen.elements.filter((element) => { if (element.resourceId === null || element.resourceId === undefined) return false; return ( element.bounds?.width === uiElement.bounds?.width && element.bounds?.height === uiElement.bounds?.height ); }); if (elementsWithSameBounds.length > 0) { elementsWithSameBounds.forEach((element) => { selectors.push({ title: "Resource Id", status: "available", definition: { id: element.resourceId, }, }); }); } else { selectors.push({ title: "Resource Id", status: "unavailable", message: "This element has no resource id associated with it. Type ‘\u2318 D’ to view platform-specific documentation on how to assign resource ids to ui elements.", documentation: "https://maestro.mobile.dev/platform-support/supported-platforms", }); } } if (uiElement.text) { if (typeof uiElement.textIndex === "number") { selectors.push({ title: "Text", status: "available", definition: { text: uiElement.text, index: uiElement.textIndex, }, }); } else { selectors.push({ title: "Text", status: "available", definition: uiElement.text, }); } } if (uiElement.hintText) { selectors.push({ title: "Hint Text", status: "available", definition: uiElement.hintText, }); } if (uiElement.accessibilityText) { selectors.push({ title: "Accessibility Text", status: "available", definition: uiElement.accessibilityText, }); } return selectors; }; const toTapExample = (selector: Selector): CommandExample => { return { status: selector.status, title: `Tap > ${selector.title}`, content: selector.status === "available" ? stringifyYaml([{ tapOn: selector.definition }]) : selector.message, documentation: selector.documentation || "https://maestro.mobile.dev/api-reference/commands/tapon", }; }; const toAssertExample = (selector: Selector): CommandExample => { return { status: selector.status, title: `Assert > ${selector.title}`, content: selector.status === "available" ? stringifyYaml([{ assertVisible: selector.definition }]) : selector.message, documentation: selector.documentation || "https://maestro.mobile.dev/api-reference/commands/assertvisible", }; }; const toConditionalExample = (selector: Selector): CommandExample => { return { status: selector.status, title: `Conditional > ${selector.title}`, content: selector.status === "available" ? stringifyYaml([ { runFlow: { when: { visible: selector.definition }, file: "Subflow.yaml", }, }, ]) : selector.message, documentation: selector.documentation || "https://maestro.mobile.dev/advanced/conditions", }; }; export const getCommandExamples = ( deviceScreen?: DeviceScreen, uiElement?: UIElement | null ): CommandExample[] => { if (!deviceScreen || !uiElement) { return []; } const selectors = getSelectors(uiElement, deviceScreen); const commands: CommandExample[] = [ ...selectors.map(toTapExample), toTapExample( getCoordinatesSelector(deviceScreen.width, deviceScreen.height, uiElement) ), ...selectors.map(toAssertExample), ...selectors.map(toConditionalExample), ]; return [ ...commands.filter((c) => c.status === "available"), ...commands.filter((c) => c.status === "unavailable"), ]; };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mobile-dev-inc/Maestro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server