Skip to main content
Glama
ResultFaker.ts12.7 kB
import { faker } from "@faker-js/faker"; import { ElementBounds, Element, ScreenSize, SystemInsets, Point, ObserveResult, ActiveWindowInfo, TapResult, TapOnElementResult, ExitDialogResult, LaunchAppResult, TerminateAppResult, ClearAppDataResult, InstallAppResult, OpenURLResult, SendTextResult, SendKeyEventResult, PressButtonResult, RotateResult, SwipeResult } from "../../src/models"; /** * Utility class for generating fake model data for testing */ export class ResultFaker { /** * Set a seed for deterministic fake data generation */ static setSeed(seed: number): void { faker.seed(seed); } /** * Generate fake ElementBounds */ static elementBounds(overrides: Partial<ElementBounds> = {}): ElementBounds { return { left: overrides.left ?? faker.number.int({ min: 0, max: 1000 }), top: overrides.top ?? faker.number.int({ min: 0, max: 1600 }), right: overrides.right ?? faker.number.int({ min: overrides.left ?? 0, max: 1080 }), bottom: overrides.bottom ?? faker.number.int({ min: overrides.top ?? 0, max: 1920 }) }; } /** * Generate fake Element */ static element(overrides: Partial<Element> = {}): Element { const bounds = overrides.bounds ?? this.elementBounds(); return { bounds, "text": overrides.text ?? faker.helpers.maybe(() => faker.lorem.words({ min: 1, max: 5 })), "content-desc": overrides["content-desc"] ?? faker.helpers.maybe(() => faker.lorem.sentence()), "resource-id": overrides["resource-id"] ?? faker.helpers.maybe(() => `${faker.word.sample()}:id/${faker.word.sample()}_${faker.word.sample()}`), "class": overrides["class"] ?? faker.helpers.arrayElement(["android.widget.TextView", "android.widget.Button", "android.widget.ImageView"]), "package": overrides["package"] ?? `com.${faker.internet.domainWord()}.${faker.internet.domainWord()}`, "checkable": overrides.checkable ?? faker.datatype.boolean(), "checked": overrides.checked ?? faker.datatype.boolean(), "clickable": overrides.clickable ?? faker.datatype.boolean(0.7), "enabled": overrides.enabled ?? faker.datatype.boolean(0.9), "focusable": overrides.focusable ?? faker.datatype.boolean(0.5), "focused": overrides.focused ?? faker.datatype.boolean(0.2), "scrollable": overrides.scrollable ?? faker.datatype.boolean(0.3), "selected": overrides.selected ?? faker.datatype.boolean(0.3), ...overrides }; } /** * Generate fake ScreenSize */ static screenSize(overrides: Partial<ScreenSize> = {}): ScreenSize { return { width: overrides.width ?? faker.helpers.arrayElement([720, 1080, 1440]), height: overrides.height ?? faker.helpers.arrayElement([1280, 1920, 2560]) }; } /** * Generate fake SystemInsets */ static systemInsets(overrides: Partial<SystemInsets> = {}): SystemInsets { return { top: overrides.top ?? faker.number.int({ min: 24, max: 80 }), right: overrides.right ?? faker.number.int({ min: 0, max: 48 }), bottom: overrides.bottom ?? faker.number.int({ min: 48, max: 144 }), left: overrides.left ?? faker.number.int({ min: 0, max: 48 }) }; } /** * Generate fake Point */ static point(overrides: Partial<Point> = {}): Point { return { x: overrides.x ?? faker.number.int({ min: 0, max: 1080 }), y: overrides.y ?? faker.number.int({ min: 0, max: 1920 }), delay: overrides.delay ?? faker.helpers.maybe(() => faker.number.int({ min: 10, max: 500 })) }; } /** * Generate fake ActiveWindowInfo */ static activeWindowInfo(overrides: Partial<ActiveWindowInfo> = {}): ActiveWindowInfo { const packageName = overrides.appId ?? `com.${faker.internet.domainWord()}.${faker.internet.domainWord()}`; const word = faker.word.sample(); const capitalizedWord = word.charAt(0).toUpperCase() + word.slice(1); return { appId: packageName, activityName: overrides.activityName ?? `${packageName}.activities.${capitalizedWord}Activity`, layoutSeqSum: overrides.layoutSeqSum ?? faker.number.int({ min: 100, max: 10000 }) }; } /** * Generate fake ObserveResult */ static observeResult(overrides: Partial<ObserveResult> = {}): ObserveResult { const screenSize = overrides.screenSize ?? this.screenSize(); const systemInsets = overrides.systemInsets ?? this.systemInsets(); const timestamp = overrides.timestamp ?? Date.now(); // Create some fake elements const elementCount = faker.number.int({ min: 5, max: 20 }); const elements = Array.from({ length: elementCount }, () => this.element()); return { timestamp, screenSize, systemInsets, viewHierarchy: overrides.viewHierarchy ?? { version: "1.0", nodes: elements.map(e => ({ ...e, children: [] })) }, screenshotPath: overrides.screenshotPath ?? faker.helpers.maybe(() => `screenshots/screen_${timestamp}.png`), activeWindow: overrides.activeWindow ?? faker.helpers.maybe(() => this.activeWindowInfo()), elements: overrides.elements ?? { clickable: elements.filter(e => e.clickable), scrollable: elements.filter(e => e.scrollable), text: elements.filter(e => e.text) }, error: overrides.error }; } /** * Generate fake TapResult */ static tapResult(overrides: Partial<TapResult> = {}): TapResult { const x = overrides.x ?? faker.number.int({ min: 0, max: 1080 }); const y = overrides.y ?? faker.number.int({ min: 0, max: 1920 }); return { success: overrides.success ?? true, x, y, observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake TapOnTextResult */ static tapOnTextResult(overrides: Partial<TapOnElementResult> = {}): TapOnElementResult { const text = overrides.text ?? faker.lorem.words({ min: 1, max: 5 }); const x = overrides.x ?? faker.number.int({ min: 0, max: 1080 }); const y = overrides.y ?? faker.number.int({ min: 0, max: 1920 }); return { success: overrides.success ?? true, text, element: overrides.element ?? this.element({ text }), x, y, observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake ExitDialogResult */ static exitDialogResult(overrides: Partial<ExitDialogResult> = {}): ExitDialogResult { const success = overrides.success ?? faker.datatype.boolean(0.9); const elementFound = overrides.elementFound ?? success; return { success, elementFound, element: elementFound ? (overrides.element ?? this.element({ text: faker.helpers.arrayElement(["Close", "Cancel", "X", "Exit", "No thanks"]), clickable: true })) : undefined, x: elementFound ? (overrides.x ?? faker.number.int({ min: 0, max: 1080 })) : undefined, y: elementFound ? (overrides.y ?? faker.number.int({ min: 0, max: 1920 })) : undefined, observation: overrides.observation ?? this.observeResult(), error: overrides.error ?? (!success ? "Failed to exit dialog" : undefined) }; } /** * Generate fake LaunchAppResult */ static launchAppResult(overrides: Partial<LaunchAppResult> = {}): LaunchAppResult { const packageName = overrides.packageName ?? `com.${faker.internet.domainWord()}.${faker.internet.domainWord()}`; return { success: overrides.success ?? true, packageName, activityName: overrides.activityName ?? `${packageName}.MainActivity`, observation: overrides.observation ?? this.observeResult({ activeWindow: this.activeWindowInfo({ appId: packageName }) }), error: overrides.error }; } /** * Generate fake TerminateAppResult */ static terminateAppResult(overrides: Partial<TerminateAppResult> = {}): TerminateAppResult { const packageName = overrides.packageName ?? `com.${faker.internet.domainWord()}.${faker.internet.domainWord()}`; return { success: overrides.success ?? true, packageName, wasInstalled: overrides.wasInstalled ?? true, wasRunning: overrides.wasRunning ?? faker.datatype.boolean(0.7), wasForeground: overrides.wasForeground ?? faker.datatype.boolean(0.5), observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake ClearAppDataResult */ static clearAppDataResult(overrides: Partial<ClearAppDataResult> = {}): ClearAppDataResult { const packageName = overrides.packageName ?? `com.${faker.internet.domainWord()}.${faker.internet.domainWord()}`; return { success: overrides.success ?? true, packageName, observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake InstallAppResult */ static installAppResult(overrides: Partial<InstallAppResult> = {}): InstallAppResult { return { success: overrides.success ?? true, apkPath: overrides.apkPath ?? `/path/to/${faker.system.fileName({ extensionCount: 0 })}.apk`, observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake OpenURLResult */ static openURLResult(overrides: Partial<OpenURLResult> = {}): OpenURLResult { return { success: overrides.success ?? true, url: overrides.url ?? faker.internet.url(), observation: overrides.observation ?? this.observeResult({ activeWindow: this.activeWindowInfo({ appId: "com.android.chrome" }) }), error: overrides.error }; } /** * Generate fake SendTextResult */ static sendTextResult(overrides: Partial<SendTextResult> = {}): SendTextResult { return { success: overrides.success ?? true, text: overrides.text ?? faker.lorem.sentence(), observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake SendKeyEventResult */ static sendKeyEventResult(overrides: Partial<SendKeyEventResult> = {}): SendKeyEventResult { return { success: overrides.success ?? true, keyCode: overrides.keyCode ?? faker.number.int({ min: 0, max: 280 }), observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake PressButtonResult */ static pressButtonResult(overrides: Partial<PressButtonResult> = {}): PressButtonResult { const button = overrides.button ?? faker.helpers.arrayElement(["home", "back", "menu", "power", "volume_up", "volume_down"]); // Map button names to keycodes const keyCodeMap: Record<string, number> = { home: 3, back: 4, menu: 82, power: 26, volume_up: 24, volume_down: 25 }; return { success: overrides.success ?? true, button, keyCode: overrides.keyCode ?? keyCodeMap[button] ?? 0, observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } /** * Generate fake RotateResult */ static rotateResult(overrides: Partial<RotateResult> = {}): RotateResult { const orientation = overrides.orientation ?? faker.helpers.arrayElement(["portrait", "landscape"]); return { success: overrides.success ?? true, orientation, value: overrides.value ?? (orientation === "portrait" ? 0 : 1), observation: overrides.orientation === "portrait" ? this.observeResult({ screenSize: { width: 1080, height: 1920 } }) : this.observeResult({ screenSize: { width: 1920, height: 1080 } }), error: overrides.error }; } /** * Generate fake SwipeResult */ static swipeResult(overrides: Partial<SwipeResult> = {}): SwipeResult { const x1 = overrides.x1 ?? faker.number.int({ min: 0, max: 1080 }); const y1 = overrides.y1 ?? faker.number.int({ min: 0, max: 1920 }); const x2 = overrides.x2 ?? faker.number.int({ min: 0, max: 1080 }); const y2 = overrides.y2 ?? faker.number.int({ min: 0, max: 1920 }); return { success: overrides.success ?? true, x1, y1, x2, y2, duration: overrides.duration ?? faker.number.int({ min: 200, max: 800 }), path: overrides.path, easing: overrides.easing ?? faker.helpers.arrayElement(["linear", "decelerate", "accelerate", "accelerateDecelerate"]), observation: overrides.observation ?? this.observeResult(), error: overrides.error }; } }

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/zillow/auto-mobile'

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