diff --git a/package.json b/package.json index fda3c9e..c613d24 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,14 @@ "lint-fix": "eslint --ext .js,.ts,.vue --ignore-path .gitignore --fix src", "prebuild": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src && node sw_combine.js", "test-local": "npx playwright test -c playwright.config-local.ts --trace on", - "test-all": "npm run build && npx playwright test -c playwright.config-local.ts --trace on", + "test-all": "npm run test:prerequisites && npm run build && npm run test:web && npm run test:mobile", + "test:prerequisites": "node scripts/check-prerequisites.js", + "test:web": "npx playwright test -c playwright.config-local.ts --trace on", + "test:mobile": "npm run build:capacitor && npm run test:android && npm run test:ios", + "test:android": "node scripts/test-android.js", + "test:ios": "node scripts/test-ios.js", + "check:android-device": "adb devices | grep -w 'device' || (echo 'No Android device connected' && exit 1)", + "check:ios-device": "xcrun xctrace list devices 2>&1 | grep -w 'Booted' || (echo 'No iOS simulator running' && exit 1)", "clean:electron": "rimraf dist-electron", "build:pywebview": "vite build --config vite.config.pywebview.mts", "build:electron": "npm run clean:electron && vite build --config vite.config.electron.mts && node scripts/build-electron.js", diff --git a/scripts/check-prerequisites.js b/scripts/check-prerequisites.js new file mode 100644 index 0000000..c7101e7 --- /dev/null +++ b/scripts/check-prerequisites.js @@ -0,0 +1,185 @@ +/** + * @fileoverview Prerequisites checker for mobile development environment + * + * This script verifies that all necessary tools and configurations are in place + * for mobile app development, including both Android and iOS platforms. + * + * Features: + * - Validates development environment setup + * - Checks required command-line tools + * - Verifies Android SDK and device connectivity + * - Confirms iOS development tools and simulator status + * + * Prerequisites checked: + * - Node.js and npm installation + * - Gradle for Android builds + * - Xcode and command line tools for iOS + * - ANDROID_HOME environment variable + * - Android platform files + * - Connected Android devices/emulators + * - iOS platform files + * - Running iOS simulators + * + * Exit codes: + * - 0: All checks passed + * - 1: One or more checks failed + * + * @example + * // Run directly + * node scripts/check-prerequisites.js + * + * // Run via npm script + * npm run test:prerequisites + * + * @author TimeSafari Team + * @license MIT + */ + +const { execSync } = require('child_process'); +const { existsSync } = require('fs'); + +/** + * Checks if a command-line tool is available by attempting to run its --version command + * + * @param {string} command - The command to check (e.g., 'node', 'npm', 'gradle') + * @param {string} errorMessage - The error message to display if the command is not available + * @returns {boolean} - True if the command exists and is executable, false otherwise + * + * @example + * checkCommand('node', 'Node.js is required') + * // Returns true if node is available, false otherwise + */ +function checkCommand(command, errorMessage) { + try { + execSync(command + ' --version', { stdio: 'ignore' }); + return true; + } catch (e) { + console.error(`❌ ${errorMessage}`); + return false; + } +} + +/** + * Verifies Android development environment setup + * + * Checks for: + * 1. ANDROID_HOME environment variable + * 2. Android platform files in project + * 3. Connected Android devices or running emulators + * + * @returns {boolean} - True if Android setup is complete and valid, false otherwise + * + * @example + * if (!checkAndroidSetup()) { + * console.error('Android prerequisites not met'); + * } + */ +function checkAndroidSetup() { + // Check ANDROID_HOME environment variable + // This is required for Android SDK tools access + if (!process.env.ANDROID_HOME) { + console.error('❌ ANDROID_HOME environment variable not set'); + return false; + } + + // Check if Android platform was added to the project + // The 'android' directory should exist if platform was added via 'npx cap add android' + if (!existsSync('android')) { + console.error('❌ Android platform not added. Run: npx cap add android'); + return false; + } + + // Check for connected devices or running emulators + // Uses ADB (Android Debug Bridge) to list connected devices + try { + const devices = execSync('adb devices').toString(); + // Parse ADB output - looking for lines ending with 'device' (not 'offline' or 'unauthorized') + if (!devices.split('\n').slice(1).some(line => line.includes('device'))) { + console.error('❌ No Android devices connected'); + return false; + } + } catch (e) { + console.error('❌ ADB not available'); + return false; + } + + return true; +} + +/** + * Verifies iOS development environment setup + * + * Checks for: + * 1. iOS platform files in project + * 2. Running iOS simulators + * 3. Xcode command line tools availability + * + * @returns {boolean} - True if iOS setup is complete and valid, false otherwise + * + * @example + * if (!checkIosSetup()) { + * console.error('iOS prerequisites not met'); + * } + */ +function checkIosSetup() { + // Check if iOS platform was added to the project + // The 'ios' directory should exist if platform was added via 'npx cap add ios' + if (!existsSync('ios')) { + console.error('❌ iOS platform not added. Run: npx cap add ios'); + return false; + } + + // Check for available and running iOS simulators + // Uses xcrun simctl to list simulator devices + try { + const simulators = execSync('xcrun simctl list devices available').toString(); + if (!simulators.includes('Booted')) { + console.error('❌ No iOS simulator running'); + return false; + } + } catch (e) { + console.error('❌ Xcode command line tools not available'); + return false; + } + + return true; +} + +/** + * Main function to check all prerequisites for mobile development + * + * Verifies: + * 1. Required command line tools (node, npm, gradle, xcodebuild) + * 2. Android development setup + * 3. iOS development setup + * + * Exits with code 1 if any checks fail + * + * @example + * // Run from package.json script: + * // "test:prerequisites": "node scripts/check-prerequisites.js" + */ +function main() { + let success = true; + + // Check required command line tools + // These are essential for building and testing the application + success &= checkCommand('node', 'Node.js is required'); + success &= checkCommand('npm', 'npm is required'); + success &= checkCommand('gradle', 'Gradle is required for Android builds'); + success &= checkCommand('xcodebuild', 'Xcode is required for iOS builds'); + + // Check platform-specific development environments + success &= checkAndroidSetup(); + success &= checkIosSetup(); + + // Exit with error if any checks failed + if (!success) { + process.exit(1); + } + + console.log('✅ All prerequisites met!'); +} + +// Execute the checks +main(); \ No newline at end of file diff --git a/scripts/run-available-mobile-tests.js b/scripts/run-available-mobile-tests.js new file mode 100644 index 0000000..90608a9 --- /dev/null +++ b/scripts/run-available-mobile-tests.js @@ -0,0 +1,132 @@ +/** + * @fileoverview Runs mobile tests based on available platforms and devices + * + * This script intelligently detects available mobile platforms and their + * associated devices/simulators, then runs tests only for the available + * configurations. This allows for flexible testing across different + * development environments without failing when a platform is unavailable. + * + * Platform detection: + * - Android: Checks for SDK and connected devices/emulators + * - iOS: Checks for macOS, Xcode, and running simulators + * + * Features: + * - Smart platform detection + * - Graceful handling of unavailable platforms + * - Clear logging of test execution + * - Comprehensive error reporting + * + * Exit codes: + * - 0: Tests completed successfully on available platforms + * - 1: Tests failed or no platforms available + * + * @example + * // Run directly + * node scripts/run-available-mobile-tests.js + * + * // Run via npm script + * npm run test:mobile:available + * + * @requires child_process + * @requires fs + * + * @author TimeSafari Team + * @license MIT + */ + +const { execSync } = require('child_process'); +const { existsSync } = require('fs'); + +/** + * Executes mobile tests on available platforms + * + * This function performs the following steps: + * 1. Checks Android environment and device availability + * 2. Checks iOS environment and simulator availability (on macOS) + * 3. Runs tests on available platforms + * 4. Reports results and handles errors + * + * Platform-specific checks: + * Android: + * - ANDROID_HOME environment variable + * - Android platform files existence + * - Connected devices via ADB + * + * iOS: + * - macOS operating system + * - iOS platform files existence + * - Running simulators via xcrun + * + * @async + * @throws {Error} If tests fail or no platforms are available + * + * @example + * runAvailableMobileTests().catch(error => { + * console.error('Test execution failed:', error); + * process.exit(1); + * }); + */ +async function runAvailableMobileTests() { + try { + // Check Android availability + // Requires both SDK (ANDROID_HOME) and platform files + const androidAvailable = existsSync('android') && process.env.ANDROID_HOME; + let androidDeviceAvailable = false; + + if (androidAvailable) { + try { + // Check for connected devices using ADB + const devices = execSync('adb devices').toString(); + // Parse ADB output for actually connected devices + // Filters out unauthorized or offline devices + androidDeviceAvailable = devices.split('\n').slice(1).some(line => line.includes('device')); + } catch (e) { + console.log('⚠️ Android SDK available but no devices connected'); + } + } + + // Check iOS availability + // Only possible on macOS with Xcode installed + const iosAvailable = process.platform === 'darwin' && existsSync('ios'); + let iosSimulatorAvailable = false; + + if (iosAvailable) { + try { + // Check for running simulators using xcrun + const simulators = execSync('xcrun simctl list devices available').toString(); + // Look for 'Booted' state in simulator list + iosSimulatorAvailable = simulators.includes('Booted'); + } catch (e) { + console.log('⚠️ iOS platform available but no simulator running'); + } + } + + // Execute tests for available platforms + if (androidDeviceAvailable) { + console.log('🤖 Running Android tests...'); + // Run Android tests via npm script + execSync('npm run test:android', { stdio: 'inherit' }); + } + + if (iosSimulatorAvailable) { + console.log('🍎 Running iOS tests...'); + // Run iOS tests via npm script + execSync('npm run test:ios', { stdio: 'inherit' }); + } + + // Error if no platforms are available for testing + if (!androidDeviceAvailable && !iosSimulatorAvailable) { + console.error('❌ No mobile platforms available for testing'); + process.exit(1); + } + + console.log('✅ Available mobile tests completed successfully'); + } catch (error) { + // Handle any errors during test execution + console.error('❌ Mobile tests failed:', error); + process.exit(1); + } +} + +// Execute the test runner +runAvailableMobileTests(); \ No newline at end of file diff --git a/scripts/test-android.js b/scripts/test-android.js new file mode 100644 index 0000000..30effd4 --- /dev/null +++ b/scripts/test-android.js @@ -0,0 +1,91 @@ +/** + * @fileoverview Android test runner for Capacitor-based mobile app + * + * This script handles the build, installation, and testing of the Android app. + * It ensures the app is properly synced, built, installed on a device/emulator, + * and runs the test suite. + * + * Process flow: + * 1. Sync Capacitor project with latest web build + * 2. Build debug APK + * 3. Install APK on connected device/emulator + * 4. Run instrumented tests + * + * Prerequisites: + * - Android SDK installed and ANDROID_HOME set + * - Gradle installed and in PATH + * - Connected Android device or running emulator + * - Capacitor Android platform added to project + * + * Exit codes: + * - 0: Tests completed successfully + * - 1: Build, installation, or test failure + * + * @example + * // Run directly + * node scripts/test-android.js + * + * // Run via npm script + * npm run test:android + * + * @requires child_process + * @requires path + * + * @author TimeSafari Team + * @license MIT + */ + +const { execSync } = require('child_process'); +const { join } = require('path'); + +/** + * Runs the complete Android test suite including build, installation, and testing + * + * The function performs the following steps: + * 1. Syncs the Capacitor project with latest web build + * 2. Builds and installs debug version of the app + * 3. Runs instrumented Android tests + * + * @async + * @throws {Error} If any step in the build or test process fails + * + * @example + * runAndroidTests().catch(error => { + * console.error('Test execution failed:', error); + * process.exit(1); + * }); + */ +async function runAndroidTests() { + try { + // Sync Capacitor project with latest web build + // This ensures the Android project has the latest web assets + execSync('npx cap sync android', { + stdio: 'inherit', + // Inherit stdio to show real-time output + }); + + // Build and install debug version of the app + // Uses Gradle wrapper to ensure consistent build environment + execSync('cd android && ./gradlew assembleDebug installDebug', { + stdio: 'inherit', + // assembleDebug: Creates debug APK + // installDebug: Installs APK on connected device + }); + + // Run the instrumented Android tests + // These are the tests defined in android/app/src/androidTest + execSync('cd android && ./gradlew connectedAndroidTest', { + stdio: 'inherit', + // connectedAndroidTest: Runs tests on connected device + }); + + console.log('✅ Android tests completed successfully'); + } catch (error) { + // Log the error and exit with failure code + console.error('❌ Android tests failed:', error); + process.exit(1); + } +} + +// Execute the test suite +runAndroidTests(); \ No newline at end of file diff --git a/scripts/test-ios.js b/scripts/test-ios.js new file mode 100644 index 0000000..77e5bd9 --- /dev/null +++ b/scripts/test-ios.js @@ -0,0 +1,93 @@ +/** + * @fileoverview iOS test runner for Capacitor-based mobile app + * + * This script handles the build and testing of the iOS app using Xcode's + * command-line tools. It ensures the app is properly synced with the latest + * web build and runs the test suite on a specified iOS simulator. + * + * Process flow: + * 1. Sync Capacitor project with latest web build + * 2. Build app for iOS simulator + * 3. Run XCTest suite + * + * Prerequisites: + * - macOS operating system + * - Xcode installed with command line tools + * - iOS simulator available + * - Capacitor iOS platform added to project + * - Valid iOS development certificates + * + * Exit codes: + * - 0: Tests completed successfully + * - 1: Build or test failure + * + * @example + * // Run directly + * node scripts/test-ios.js + * + * // Run via npm script + * npm run test:ios + * + * @requires child_process + * @requires path + * + * @author TimeSafari Team + * @license MIT + */ + +const { execSync } = require('child_process'); +const { join } = require('path'); + +/** + * Runs the complete iOS test suite including build and testing + * + * The function performs the following steps: + * 1. Syncs the Capacitor project with latest web build + * 2. Builds and tests the app using xcodebuild + * + * Note: This function requires a running iOS simulator. The test will + * fail if no simulator is available or if it's not in a booted state. + * + * @async + * @throws {Error} If any step in the build or test process fails + * + * @example + * runIosTests().catch(error => { + * console.error('Test execution failed:', error); + * process.exit(1); + * }); + */ +async function runIosTests() { + try { + // Sync Capacitor project with latest web build + // This ensures the iOS project has the latest web assets + execSync('npx cap sync ios', { + stdio: 'inherit', + // Inherit stdio to show real-time output + }); + + // Build and run tests using xcodebuild + execSync( + 'cd ios && xcodebuild test ' + + '-workspace App/App.xcworkspace ' + // Workspace containing the project + '-scheme App ' + // The scheme to build and test + '-destination "platform=iOS Simulator,name=iPhone 14"', // Target simulator + { + stdio: 'inherit', + // test: Builds and runs tests + // -workspace: Specifies the Xcode workspace + // -scheme: Specifies the scheme to test + // -destination: Specifies the target simulator + } + ); + + console.log('✅ iOS tests completed successfully'); + } catch (error) { + // Log the error and exit with failure code + console.error('❌ iOS tests failed:', error); + process.exit(1); + } +} + +// Execute the test suite +runIosTests(); \ No newline at end of file