@irsprs/mobwright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/doctor.ts","../../src/cli/colors.ts","../../src/cli/init.ts","../../src/cli/prompt.ts","../../src/cli/templates.ts","../../src/cli/test.ts","../../src/cli/index.ts"],"sourcesContent":["import { exec as execCb } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync } from 'node:fs';\nimport { green, yellow, red, dim, bold } from './colors.js';\n\nconst exec = promisify(execCb);\n\ninterface CheckResult {\n status: 'ok' | 'info' | 'warn' | 'fail';\n label: string;\n detail?: string;\n}\n\ninterface CheckSection {\n title: string;\n results: CheckResult[];\n}\n\n/**\n * Run a shell command and capture the first line of stdout.\n * Returns null if the command fails (not installed, etc.).\n */\nasync function tryExec(cmd: string, args: string[] = []): Promise<string | null> {\n try {\n const { stdout } = await exec([cmd, ...args].join(' '), { timeout: 5000 });\n return stdout.split('\\n')[0]?.trim() ?? '';\n } catch {\n return null;\n }\n}\n\n/**\n * Quick HTTP probe with a short timeout.\n * Used to check if Appium server is reachable.\n */\nasync function httpProbe(url: string, timeoutMs = 1500): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const res = await fetch(url, { signal: controller.signal });\n clearTimeout(timer);\n return res.ok || res.status === 404; // 404 still means the server is up\n } catch {\n return false;\n }\n}\n\n// ---------- System checks ----------\n\nasync function checkSystem(): Promise<CheckSection> {\n const results: CheckResult[] = [];\n\n // Node version\n const nodeVersion = process.versions.node;\n const major = parseInt(nodeVersion.split('.')[0]!, 10);\n results.push({\n status: major >= 18 ? 'ok' : 'fail',\n label: `Node ${nodeVersion}`,\n detail: major >= 18 ? undefined : 'Node 18.18 or higher required',\n });\n\n // Package manager — informational\n const pnpmVersion = await tryExec('pnpm', ['--version']);\n if (pnpmVersion) {\n results.push({ status: 'ok', label: `pnpm ${pnpmVersion}` });\n }\n\n return { title: 'System', results };\n}\n\n// ---------- Android checks ----------\n\nasync function checkAndroid(): Promise<CheckSection> {\n const results: CheckResult[] = [];\n const androidHome = process.env.ANDROID_HOME;\n\n if (!androidHome) {\n results.push({\n status: 'warn',\n label: 'ANDROID_HOME not set',\n detail: 'Required for Android testing. Set to your Android SDK path.',\n });\n return { title: 'Android', results };\n }\n\n results.push({\n status: 'ok',\n label: `ANDROID_HOME=${androidHome}`,\n });\n\n if (!existsSync(androidHome)) {\n results.push({\n status: 'fail',\n label: `Directory does not exist: ${androidHome}`,\n });\n return { title: 'Android', results };\n }\n\n // adb in PATH\n const adb = await tryExec('adb', ['--version']);\n results.push({\n status: adb ? 'ok' : 'warn',\n label: 'adb',\n detail: adb ?? 'Not in PATH. Add $ANDROID_HOME/platform-tools.',\n });\n\n // emulator in PATH\n const emulatorHelp = await tryExec('emulator', ['-help-version']);\n results.push({\n status: emulatorHelp !== null ? 'ok' : 'warn',\n label: 'emulator',\n detail: emulatorHelp !== null ? undefined : 'Not in PATH. Add $ANDROID_HOME/emulator.',\n });\n\n // Booted emulators\n if (adb) {\n const devices = await tryExec('adb', ['devices']);\n const lines = (devices ?? '').split('\\n').slice(1).filter((l) => l.includes('\\tdevice'));\n if (lines.length > 0) {\n results.push({\n status: 'info',\n label: `${lines.length} emulator${lines.length > 1 ? 's' : ''} booted`,\n });\n }\n }\n\n return { title: 'Android', results };\n}\n\n// ---------- iOS checks ----------\n\nasync function checkIOS(): Promise<CheckSection> {\n const results: CheckResult[] = [];\n\n if (process.platform !== 'darwin') {\n results.push({\n status: 'info',\n label: 'iOS checks skipped (not macOS)',\n });\n return { title: 'iOS', results };\n }\n\n // Xcode version\n const xcodeVersion = await tryExec('xcodebuild', ['-version']);\n results.push({\n status: xcodeVersion ? 'ok' : 'warn',\n label: xcodeVersion ?? 'Xcode not found',\n });\n\n // xcrun\n const xcrun = await tryExec('xcrun', ['--version']);\n results.push({\n status: xcrun ? 'ok' : 'warn',\n label: xcrun ? 'xcrun' : 'xcrun not in PATH',\n });\n\n // Booted simulators\n const sims = await tryExec('xcrun', ['simctl', 'list', 'devices', 'booted']);\n if (sims) {\n const lines = sims.split('\\n').filter((l) => l.includes('(Booted)'));\n if (lines.length > 0) {\n results.push({\n status: 'info',\n label: `${lines.length} simulator${lines.length > 1 ? 's' : ''} booted`,\n });\n }\n }\n\n return { title: 'iOS', results };\n}\n\n// ---------- Appium checks ----------\n\nasync function checkAppium(): Promise<CheckSection> {\n const results: CheckResult[] = [];\n\n // Appium CLI\n const appiumVersion = await tryExec('appium', ['--version']);\n if (!appiumVersion) {\n results.push({\n status: 'fail',\n label: 'Appium not installed',\n detail: 'npm install -g appium',\n });\n return { title: 'Appium', results };\n }\n results.push({ status: 'ok', label: `Appium ${appiumVersion}` });\n\n // Drivers\n const driverList = await tryExec('appium', ['driver', 'list', '--installed']);\n if (driverList) {\n const hasUiAutomator2 = driverList.includes('uiautomator2');\n const hasXCUITest = driverList.includes('xcuitest');\n\n results.push({\n status: hasUiAutomator2 ? 'ok' : 'warn',\n label: 'uiautomator2 driver',\n detail: hasUiAutomator2 ? undefined : 'appium driver install uiautomator2',\n });\n\n if (process.platform === 'darwin') {\n results.push({\n status: hasXCUITest ? 'ok' : 'warn',\n label: 'xcuitest driver',\n detail: hasXCUITest ? undefined : 'appium driver install xcuitest',\n });\n }\n }\n\n // Server reachable\n const port = process.env.MOBWRIGHT_APPIUM_PORT ?? '4723';\n const reachable = await httpProbe(`http://localhost:${port}/status`);\n results.push({\n status: reachable ? 'ok' : 'warn',\n label: `Server reachable at localhost:${port}`,\n detail: reachable ? undefined : 'Start with `appium` in another terminal.',\n });\n\n return { title: 'Appium', results };\n}\n\n// ---------- Env vars ----------\n\nfunction checkEnvVars(): CheckSection {\n const results: CheckResult[] = [];\n\n const required = ['MOBWRIGHT_APP_PATH', 'MOBWRIGHT_ANDROID_AVD'];\n for (const key of required) {\n const value = process.env[key];\n results.push({\n status: value ? 'ok' : 'warn',\n label: `${key}${value ? ' set' : ' not set'}`,\n detail: value ? undefined : 'Required for Android testing.',\n });\n }\n\n // AI is optional\n const aiProvider = process.env.MOBWRIGHT_AI_PROVIDER;\n const aiKey = process.env.MOBWRIGHT_AI_API_KEY;\n if (!aiProvider || !aiKey) {\n results.push({\n status: 'warn',\n label: 'MOBWRIGHT_AI_API_KEY not set',\n detail: 'AI features (device.ai) unavailable until set.',\n });\n } else {\n results.push({\n status: 'ok',\n label: `AI provider: ${aiProvider}`,\n });\n }\n\n return { title: 'Environment variables', results };\n}\n\n// ---------- Rendering ----------\n\nfunction symbol(status: CheckResult['status']): string {\n switch (status) {\n case 'ok':\n return green('✔');\n case 'info':\n return green('✓');\n case 'warn':\n return yellow('✗');\n case 'fail':\n return red('✗');\n }\n}\n\nfunction renderSection(section: CheckSection): void {\n console.log('\\n' + bold(section.title));\n for (const r of section.results) {\n const indent = ' ';\n console.log(`${indent}${symbol(r.status)} ${r.label}`);\n if (r.detail) {\n console.log(`${indent} ${dim(r.detail)}`);\n }\n }\n}\n\n// ---------- Main ----------\n\nexport async function runDoctor(): Promise<number> {\n console.log(bold('🔍 Mobwright environment check'));\n\n const sections = await Promise.all([\n checkSystem(),\n checkAndroid(),\n checkIOS(),\n checkAppium(),\n ]);\n sections.push(checkEnvVars());\n\n for (const section of sections) {\n renderSection(section);\n }\n\n // Summary\n const all = sections.flatMap((s) => s.results);\n const fails = all.filter((r) => r.status === 'fail').length;\n const warns = all.filter((r) => r.status === 'warn').length;\n\n console.log('');\n if (fails > 0) {\n console.log(red(bold(`Result: ${fails} error${fails > 1 ? 's' : ''}, ${warns} warning${warns !== 1 ? 's' : ''}.`)));\n console.log(dim('Fix errors above before running tests.'));\n return 1;\n }\n if (warns > 0) {\n console.log(yellow(bold(`Result: ${warns} warning${warns > 1 ? 's' : ''}.`)));\n console.log(dim('Tests should run, but some features may be limited.'));\n return 0;\n }\n console.log(green(bold('Result: All checks passed. ✨')));\n return 0;\n}","/**\n * Minimal ANSI color helpers. No external deps.\n * Auto-disables when not in a TTY (e.g. piped output, CI logs that strip ANSI).\n */\nconst enabled =\n process.stdout.isTTY &&\n !process.env.NO_COLOR &&\n process.env.TERM !== 'dumb';\n\nfunction paint(code: number, text: string): string {\n return enabled ? `\\x1b[${code}m${text}\\x1b[0m` : text;\n}\n\nexport const green = (s: string) => paint(32, s);\nexport const yellow = (s: string) => paint(33, s);\nexport const red = (s: string) => paint(31, s);\nexport const dim = (s: string) => paint(2, s);\nexport const bold = (s: string) => paint(1, s);","import { mkdir, writeFile, readdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { exec as execCb } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { ask, confirm, pickOne, closePrompt } from './prompt.js';\nimport { green, yellow, red, dim, bold } from './colors.js';\nimport {\n PACKAGE_JSON,\n TSCONFIG,\n PLAYWRIGHT_CONFIG,\n ENV_EXAMPLE,\n GITIGNORE,\n SANITY_SPEC,\n PLATFORM_EXAMPLE,\n README,\n type ProjectOptions,\n type Platform,\n type AIChoice,\n} from './templates.js';\n\nconst exec = promisify(execCb);\n\nexport interface InitFlags {\n /** Pre-fill project directory; skip the prompt. */\n dir?: string;\n /** Comma-separated platforms; skip the prompt. */\n platforms?: string;\n /** AI provider; skip the prompt. */\n ai?: string;\n /** Skip all prompts; use defaults for unset flags. */\n yes?: boolean;\n /** Overwrite non-empty target directory. */\n force?: boolean;\n /** Skip the dependency install step. */\n skipInstall?: boolean;\n}\n\nexport async function runInit(flags: InitFlags = {}): Promise<number> {\n console.log(bold('🪄 Mobwright project setup\\n'));\n\n try {\n // 1. Resolve target directory\n const dirInput = flags.dir ?? (flags.yes\n ? './my-mobile-tests'\n : await ask('Project directory', './my-mobile-tests'));\n const targetDir = path.resolve(dirInput);\n\n // 2. Check it's safe to write here\n if (existsSync(targetDir)) {\n const contents = await readdir(targetDir);\n const nonHidden = contents.filter((f) => !f.startsWith('.'));\n if (nonHidden.length > 0 && !flags.force) {\n console.error(red(`✗ Directory ${targetDir} is not empty.`));\n console.error(dim(' Pass --force to overwrite, or pick another directory.'));\n return 1;\n }\n }\n\n // 3. Platforms\n let platforms: Platform[];\n if (flags.platforms) {\n platforms = parsePlatformsFlag(flags.platforms);\n } else if (flags.yes) {\n platforms = ['android', 'ios'];\n } else {\n const choice = await pickOne(\n 'Which platforms?',\n ['Both Android and iOS', 'Android only', 'iOS only'] as const,\n );\n platforms = choice === 'Android only'\n ? ['android']\n : choice === 'iOS only'\n ? ['ios']\n : ['android', 'ios'];\n }\n\n // 4. AI provider\n const aiProvider: AIChoice = flags.ai\n ? parseAIFlag(flags.ai)\n : flags.yes\n ? 'none'\n : await pickOne(\n 'AI provider (optional)?',\n ['none', 'deepseek', 'openai', 'anthropic'] as const,\n );\n\n // 5. Install deps?\n const shouldInstall = flags.skipInstall\n ? false\n : flags.yes\n ? true\n : await confirm('Install dependencies now?', true);\n\n // 6. Project name from directory\n const projectName = path.basename(targetDir).toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\n const opts: ProjectOptions = {\n name: projectName,\n platforms,\n aiProvider,\n };\n\n console.log('');\n console.log(`Creating project at ${dim(targetDir)}...`);\n\n // 7. Write files\n await mkdir(targetDir, { recursive: true });\n await writeFiles(targetDir, opts);\n\n // 8. Install deps (optional)\n if (shouldInstall) {\n console.log(' ' + dim('Installing dependencies (this may take a minute)...'));\n try {\n await exec('npm install', { cwd: targetDir });\n console.log(` ${green('✔')} Dependencies installed`);\n } catch (err) {\n console.log(` ${yellow('✗')} Install failed. Run \\`npm install\\` manually in ${projectName}/.`);\n }\n }\n\n // 9. Done — print next steps\n printNextSteps(projectName, shouldInstall);\n return 0;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ERR_USE_AFTER_CLOSE') {\n // User pressed Ctrl+C mid-prompt\n console.log('\\n' + yellow('Cancelled.'));\n return 130;\n }\n console.error(red(`✗ ${(err as Error).message}`));\n return 1;\n } finally {\n closePrompt();\n }\n}\n\n// ---------- File writing ----------\n\nasync function writeFiles(targetDir: string, opts: ProjectOptions): Promise<void> {\n const files: Array<[string, string]> = [\n ['package.json', PACKAGE_JSON(opts)],\n ['tsconfig.json', TSCONFIG()],\n ['playwright.config.ts', PLAYWRIGHT_CONFIG(opts)],\n ['.env.example', ENV_EXAMPLE(opts)],\n ['.gitignore', GITIGNORE()],\n ['README.md', README(opts)],\n ['tests/shared/sanity.spec.ts', SANITY_SPEC()],\n ];\n\n for (const platform of opts.platforms) {\n files.push([`tests/${platform}/example.spec.ts`, PLATFORM_EXAMPLE(platform)]);\n }\n\n for (const [relPath, content] of files) {\n const fullPath = path.join(targetDir, relPath);\n await mkdir(path.dirname(fullPath), { recursive: true });\n await writeFile(fullPath, content, 'utf8');\n console.log(` ${green('✔')} ${relPath}`);\n }\n}\n\n// ---------- Flag parsing ----------\n\nfunction parsePlatformsFlag(value: string): Platform[] {\n const parts = value.split(',').map((p) => p.trim().toLowerCase());\n const result: Platform[] = [];\n for (const p of parts) {\n if (p === 'android' || p === 'ios') {\n result.push(p);\n } else {\n throw new Error(`Unknown platform: ${p} (use 'android' or 'ios')`);\n }\n }\n if (result.length === 0) {\n throw new Error('At least one platform required');\n }\n return result;\n}\n\nfunction parseAIFlag(value: string): AIChoice {\n const v = value.trim().toLowerCase();\n if (v === 'none' || v === 'anthropic' || v === 'openai' || v === 'deepseek') {\n return v;\n }\n throw new Error(`Unknown AI provider: ${value} (use 'none', 'anthropic', 'openai', 'deepseek')`);\n}\n\n// ---------- Next steps ----------\n\nfunction printNextSteps(projectName: string, installed: boolean): void {\n console.log('');\n console.log(green(bold('✨ Done!')) + ' Next steps:\\n');\n console.log(` ${dim('# enter your new project')}`);\n console.log(` cd ${projectName}\\n`);\n if (!installed) {\n console.log(` ${dim('# install dependencies')}`);\n console.log(` npm install\\n`);\n }\n console.log(` ${dim('# configure your devices')}`);\n console.log(` cp .env.example .env\\n`);\n console.log(` ${dim('# verify your environment')}`);\n console.log(` npx mobwright doctor\\n`);\n console.log(` ${dim('# boot a device + run Appium in another terminal, then:')}`);\n console.log(` npx playwright test`);\n console.log('');\n}","import { createInterface, type Interface } from 'node:readline/promises';\n\n/**\n * Minimal interactive prompts using Node's built-in readline.\n * No external dependencies.\n */\n\nlet rl: Interface | null = null;\n\nfunction getInterface(): Interface {\n if (!rl) {\n rl = createInterface({ input: process.stdin, output: process.stdout });\n }\n return rl;\n}\n\nexport function closePrompt(): void {\n if (rl) {\n rl.close();\n rl = null;\n }\n}\n\n/**\n * Ask for a free-form text answer with an optional default.\n */\nexport async function ask(question: string, defaultValue?: string): Promise<string> {\n const suffix = defaultValue !== undefined ? ` (${defaultValue})` : '';\n const answer = (await getInterface().question(`${question}${suffix}: `)).trim();\n return answer || defaultValue || '';\n}\n\n/**\n * Ask a yes/no question.\n */\nexport async function confirm(question: string, defaultYes = true): Promise<boolean> {\n const hint = defaultYes ? 'Y/n' : 'y/N';\n const answer = (await getInterface().question(`${question} (${hint}): `)).trim().toLowerCase();\n if (!answer) return defaultYes;\n return answer === 'y' || answer === 'yes';\n}\n\n/**\n * Ask the user to pick one item from a list.\n */\nexport async function pickOne<T extends string>(\n question: string,\n options: readonly T[],\n defaultIndex = 0,\n): Promise<T> {\n console.log(question);\n options.forEach((opt, idx) => {\n const marker = idx === defaultIndex ? '›' : ' ';\n console.log(` ${marker} ${idx + 1}. ${opt}`);\n });\n const raw = (await getInterface().question(`Choose (1-${options.length}, default ${defaultIndex + 1}): `)).trim();\n const choice = raw ? parseInt(raw, 10) - 1 : defaultIndex;\n if (Number.isNaN(choice) || choice < 0 || choice >= options.length) {\n return options[defaultIndex] as T;\n }\n return options[choice] as T;\n}","export interface ProjectOptions {\n name: string;\n platforms: Platform[];\n aiProvider: AIChoice;\n}\n\nexport type Platform = 'android' | 'ios';\nexport type AIChoice = 'none' | 'anthropic' | 'openai' | 'deepseek';\n\nexport const PACKAGE_JSON = (opts: ProjectOptions): string =>\n JSON.stringify(\n {\n name: opts.name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n test: 'mobwright test',\n 'test:android': 'mobwright test --project=android',\n 'test:ios': 'mobwright test --project=ios',\n doctor: 'mobwright doctor',\n },\n devDependencies: {\n '@playwright/test': '^1.48.0',\n mobwright: '^0.1.0',\n dotenv: '^16.4.0',\n typescript: '^5.4.0',\n },\n },\n null,\n 2,\n ) + '\\n';\n\nexport const TSCONFIG = (): string =>\n JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n },\n include: ['tests/**/*', 'playwright.config.ts'],\n },\n null,\n 2,\n ) + '\\n';\n\nexport const PLAYWRIGHT_CONFIG = (opts: ProjectOptions): string => {\n const projects = opts.platforms\n .map(\n (p) => ` {\n name: '${p}',\n testMatch: ['**/shared/**', '**/${p}/**'],\n },`,\n )\n .join('\\n');\n\n return `import { defineConfig } from '@playwright/test';\nimport dotenv from 'dotenv';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\ndotenv.config({ path: path.join(__dirname, '.env') });\n\nexport default defineConfig({\n testDir: './tests',\n fullyParallel: false,\n retries: 0,\n workers: 1,\n reporter: 'list',\n timeout: 120_000,\n projects: [\n${projects}\n ],\n});\n`;\n};\n\nexport const ENV_EXAMPLE = (opts: ProjectOptions): string => {\n const lines: string[] = ['# Mobwright local config — copy to .env and fill in.', ''];\n\n if (opts.platforms.includes('android')) {\n lines.push(\n '# Android',\n 'MOBWRIGHT_APP_PATH=/absolute/path/to/your/app.apk',\n 'MOBWRIGHT_ANDROID_AVD=Pixel_6_API_34',\n '# MOBWRIGHT_ANDROID_APP_PACKAGE=com.example',\n '# MOBWRIGHT_ANDROID_APP_ACTIVITY=com.example.MainActivity',\n '',\n );\n }\n\n if (opts.platforms.includes('ios')) {\n lines.push(\n '# iOS',\n 'MOBWRIGHT_IOS_DEVICE=iPhone 15',\n 'MOBWRIGHT_IOS_BUNDLE_ID=com.example.app',\n '# MOBWRIGHT_IOS_APP_PATH=/absolute/path/to/My.app',\n '# MOBWRIGHT_IOS_UDID=',\n '',\n );\n }\n\n if (opts.aiProvider !== 'none') {\n lines.push(\n '# AI provider',\n `MOBWRIGHT_AI_PROVIDER=${opts.aiProvider}`,\n 'MOBWRIGHT_AI_API_KEY=sk-...',\n '',\n );\n } else {\n lines.push(\n '# AI provider (optional)',\n '# MOBWRIGHT_AI_PROVIDER=deepseek',\n '# MOBWRIGHT_AI_API_KEY=sk-...',\n '',\n );\n }\n\n return lines.join('\\n');\n};\n\nexport const GITIGNORE = (): string => `node_modules/\n.env\n.env.local\ntest-results/\nplaywright-report/\n*.log\n.DS_Store\n`;\n\nexport const SANITY_SPEC = (): string => `import { test, expect } from 'mobwright';\n\ntest('session boots cleanly', async ({ device }) => {\n expect(device.browser.sessionId).toBeTruthy();\n console.log(\\`✓ \\${device.project} session\\`);\n});\n\ntest('can take a screenshot', async ({ device }) => {\n const png = await device.screenshot();\n expect(png.length).toBeGreaterThan(1000);\n});\n`;\n\nexport const PLATFORM_EXAMPLE = (platform: Platform): string => `import { test, expect } from 'mobwright';\n\ntest('${platform}: example test', async ({ device }) => {\n // Replace with a real selector from your app\n const greeting = device.locator('~welcome');\n\n // Auto-waits up to 5 seconds for the element to appear\n await expect(greeting).toBeVisible();\n});\n`;\n\nexport const README = (opts: ProjectOptions): string => `# ${opts.name}\n\nMobile e2e tests powered by [mobwright](https://www.npmjs.com/package/mobwright).\n\n## Setup\n\n1. Copy \\`.env.example\\` to \\`.env\\` and fill in your device info:\n \\`\\`\\`bash\n cp .env.example .env\n \\`\\`\\`\n\n2. Verify your environment:\n \\`\\`\\`bash\n npx mobwright doctor\n \\`\\`\\`\n\n3. Boot a device (Android emulator or iOS simulator).\n\n4. Start the Appium server in a separate terminal:\n \\`\\`\\`bash\n appium\n \\`\\`\\`\n\n5. Run the tests:\n \\`\\`\\`bash\n npm test # both platforms\n npm run test:android # Android only${opts.platforms.includes('ios') ? `\n npm run test:ios # iOS only` : ''}\n \\`\\`\\`\n\n## Project structure\n\n\\`\\`\\`\ntests/\n├── shared/ # Tests that run on both platforms\n${opts.platforms.includes('android') ? '├── android/ # Android-only tests\\n' : ''}${opts.platforms.includes('ios') ? '└── ios/ # iOS-only tests\\n' : ''}\\`\\`\\`\n\n## Learn more\n\n- [Mobwright docs](https://github.com/yourname/mobwright)\n- [Playwright test runner](https://playwright.dev/docs/test-intro)\n`;","import { spawn } from 'node:child_process';\nimport { green, red, dim, bold } from './colors.js';\n\nexport interface TestFlags {\n /** Skip pre-flight checks (e.g. Appium reachability). */\n noPreflight?: boolean;\n /** All other args are forwarded verbatim to `playwright test`. */\n rest: string[];\n}\n\n/**\n * Run mobwright tests. Forwards arguments to `playwright test`.\n *\n * Adds:\n * - A branded header\n * - Pre-flight Appium reachability check (skippable via --no-preflight)\n *\n * Returns the exit code from playwright test.\n */\nexport async function runTest(flags: TestFlags): Promise<number> {\n console.log(bold('🎯 Mobwright — running tests') + '\\n');\n\n // Pre-flight: confirm Appium is reachable.\n // We skip this if --no-preflight is passed, since some users may want to\n // start Appium lazily, or run tests against a non-default endpoint.\n if (!flags.noPreflight) {\n const ok = await checkAppium();\n if (!ok) {\n const port = process.env.MOBWRIGHT_APPIUM_PORT ?? '4723';\n console.error(red('✗') + ` Appium server not reachable at http://localhost:${port}.`);\n console.error(dim(' Start it in another terminal: ') + bold('appium'));\n console.error(dim(' Or skip this check: ') + bold('npx mobwright test --no-preflight'));\n console.error('');\n return 1;\n }\n console.log(green('✔') + ' Appium reachable');\n console.log('');\n }\n\n // Forward to playwright test.\n return await forwardToPlaywright(flags.rest);\n}\n\n/**\n * Probe the Appium server's /status endpoint with a short timeout.\n */\nasync function checkAppium(): Promise<boolean> {\n const port = process.env.MOBWRIGHT_APPIUM_PORT ?? '4723';\n const url = `http://localhost:${port}/status`;\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 1500);\n const res = await fetch(url, { signal: controller.signal });\n clearTimeout(timer);\n // /status returns 200 when Appium is healthy\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Spawn `playwright test` with the user's args, inheriting stdio.\n * The child's exit code becomes our exit code.\n */\nfunction forwardToPlaywright(args: string[]): Promise<number> {\n return new Promise((resolve) => {\n // Use npx to resolve playwright from the user's project, not our own dist.\n // This way mobwright doesn't need a direct dep on @playwright/test —\n // it stays a peer dep installed by the user.\n const child = spawn('npx', ['playwright', 'test', ...args], {\n stdio: 'inherit',\n shell: process.platform === 'win32', // Windows needs shell=true for npx\n });\n\n child.on('exit', (code, signal) => {\n // Forward signal-based termination as a non-zero exit\n if (signal) {\n resolve(128);\n return;\n }\n resolve(code ?? 0);\n });\n\n child.on('error', (err) => {\n console.error(red('✗') + ` Failed to spawn playwright: ${err.message}`);\n console.error(dim(' Is @playwright/test installed?'));\n resolve(1);\n });\n });\n}","#!/usr/bin/env node\n\n/**\n * Mobwright CLI entry point.\n *\n * Commands:\n * doctor — environment health check\n * init — scaffold a new project (coming)\n *\n * For now, anything not in the list above prints help.\n */\n\nimport { runDoctor } from './doctor.js';\nimport { runInit, type InitFlags } from './init.js';\nimport { runTest, type TestFlags } from './test.js';\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n /* eslint-disable no-fallthrough -- every case exits via process.exit() */\n switch (command) {\n case 'doctor': {\n const exitCode = await runDoctor();\n process.exit(exitCode);\n }\n case 'init': {\n const flags = parseInitFlags(args.slice(1));\n const exitCode = await runInit(flags);\n process.exit(exitCode);\n }\n case 'test': {\n const flags = parseTestFlags(args.slice(1));\n const exitCode = await runTest(flags);\n process.exit(exitCode);\n }\n case undefined:\n case '-h':\n case '--help':\n case 'help': {\n printHelp();\n process.exit(0);\n }\n case '-v':\n case '--version': {\n console.log('mobwright 0.1.0');\n process.exit(0);\n }\n default: {\n console.error(`Unknown command: ${command}`);\n console.error('');\n printHelp();\n process.exit(2);\n }\n }\n /* eslint-enable no-fallthrough */\n}\n\nfunction parseInitFlags(args: string[]): InitFlags {\n const flags: InitFlags = {};\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n if (arg === '-y' || arg === '--yes') {\n flags.yes = true;\n } else if (arg === '--force') {\n flags.force = true;\n } else if (arg === '--skip-install') {\n flags.skipInstall = true;\n } else if (arg === '--dir') {\n flags.dir = args[++i];\n } else if (arg.startsWith('--dir=')) {\n flags.dir = arg.slice('--dir='.length);\n } else if (arg === '--platforms') {\n flags.platforms = args[++i];\n } else if (arg.startsWith('--platforms=')) {\n flags.platforms = arg.slice('--platforms='.length);\n } else if (arg === '--ai') {\n flags.ai = args[++i];\n } else if (arg.startsWith('--ai=')) {\n flags.ai = arg.slice('--ai='.length);\n } else if (!arg.startsWith('-') && !flags.dir) {\n // First positional arg is treated as the directory\n flags.dir = arg;\n }\n }\n return flags;\n}\n\nfunction parseTestFlags(args: string[]): TestFlags {\n const flags: TestFlags = { rest: [] };\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n if (arg === '--no-preflight') {\n flags.noPreflight = true;\n } else {\n // Everything else gets forwarded to playwright test verbatim.\n flags.rest.push(arg);\n }\n }\n return flags;\n}\n\nfunction printHelp(): void {\n console.log(`mobwright — mobile e2e testing with AI\n\nUsage:\n mobwright <command> [options]\n\nCommands:\n init [dir] Scaffold a new mobwright project\n test Run your test suite\n doctor Check your environment for required tools and config\n help Show this help\n\ninit options:\n --yes, -y Accept all defaults (no prompts)\n --dir <path> Project directory (default: ./my-mobile-tests)\n --platforms <list> Comma-separated: android,ios (default: both)\n --ai <provider> none, deepseek, openai, anthropic (default: none)\n --skip-install Don't run npm install\n --force Overwrite non-empty target directory\n\ntest options:\n --no-preflight Skip Appium reachability check\n All other args are forwarded to \\`playwright test\\`.\n\nExamples:\n mobwright init\n mobwright test --project=android\n mobwright test --grep \"login\" --workers=2\n mobwright doctor\n\nDocs: https://github.com/yourname/mobwright\n`);\n}\n\nmain().catch((err) => {\n console.error('Unexpected error:', err);\n process.exit(1);\n});"],"mappings":"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","names":["execCb","import_promises","import_node_fs","import_node_child_process","import_node_util","exec","execCb","path","import_node_child_process","checkAppium"]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node