From 62df07f6b69ab1163074e5d48d10b7fce8b47b52 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 16:23:59 +0530 Subject: [PATCH 01/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 82 +-- common/config/devices.txt | 23 + common/config/repos.txt | 6 + {mac => common/mac}/common-utils.sh | 33 +- common/mac/device-machine-allocation.sh | 122 ++++ {mac => common/mac}/env-prequisite-checks.sh | 0 common/mac/env-setup-run.sh | 287 +++++++++ {mac => common/mac}/logging-utils.sh | 0 common/mac/run.sh | 91 +++ {mac => common/mac}/user-interaction.sh | 49 ++ common/win/common-utils.ps1 | 520 ++++++++++++++++ common/win/device-machine-allocation.ps1 | 90 +++ common/win/env-prequisite-checks.ps1 | 154 +++++ common/win/env-setup-run.ps1 | 274 +++++++++ common/win/logging-utils.ps1 | 55 ++ common/win/run.ps1 | 116 ++++ {win => common/win}/user-interaction.ps1 | 134 ++--- common/win/windows-gui.ps1 | 169 ++++++ mac/device-machine-allocation.sh | 171 ------ mac/env-setup-run.sh | 548 ----------------- mac/run.sh | 78 +-- win/common-utils.ps1 | 358 ----------- win/device-machine-allocation.ps1 | 285 --------- win/env-prequisite-checks.ps1 | 148 ----- win/env-setup-run.ps1 | 589 ------------------- win/logging-utils.ps1 | 56 -- win/run.ps1 | 112 +--- 27 files changed, 2091 insertions(+), 2459 deletions(-) create mode 100644 common/config/devices.txt create mode 100644 common/config/repos.txt rename {mac => common/mac}/common-utils.sh (91%) create mode 100644 common/mac/device-machine-allocation.sh rename {mac => common/mac}/env-prequisite-checks.sh (100%) create mode 100644 common/mac/env-setup-run.sh rename {mac => common/mac}/logging-utils.sh (100%) create mode 100755 common/mac/run.sh rename {mac => common/mac}/user-interaction.sh (70%) create mode 100644 common/win/common-utils.ps1 create mode 100644 common/win/device-machine-allocation.ps1 create mode 100644 common/win/env-prequisite-checks.ps1 create mode 100644 common/win/env-setup-run.ps1 create mode 100644 common/win/logging-utils.ps1 create mode 100644 common/win/run.ps1 rename {win => common/win}/user-interaction.ps1 (78%) create mode 100644 common/win/windows-gui.ps1 delete mode 100644 mac/device-machine-allocation.sh delete mode 100644 mac/env-setup-run.sh delete mode 100644 win/common-utils.ps1 delete mode 100644 win/device-machine-allocation.ps1 delete mode 100644 win/env-prequisite-checks.ps1 delete mode 100644 win/env-setup-run.ps1 delete mode 100644 win/logging-utils.ps1 diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index 504607c..84e3635 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -34,26 +34,27 @@ jobs: run: | echo "Validating mac/run.sh syntax..." bash -n mac/run.sh + bash -n common/mac/run.sh echo "✅ mac/run.sh syntax is valid" - name: Validate supporting scripts syntax run: | echo "Validating supporting scripts..." - bash -n mac/common-utils.sh - bash -n mac/logging-utils.sh - bash -n mac/env-setup-run.sh - bash -n mac/user-interaction.sh - bash -n mac/env-prequisite-checks.sh + bash -n common/mac/common-utils.sh + bash -n common/mac/logging-utils.sh + bash -n common/mac/env-setup-run.sh + bash -n common/mac/user-interaction.sh + bash -n common/mac/env-prequisite-checks.sh echo "✅ All supporting scripts are valid" - name: Check if scripts are executable run: | chmod +x mac/run.sh - chmod +x mac/common-utils.sh - chmod +x mac/logging-utils.sh - chmod +x mac/env-setup-run.sh - chmod +x mac/user-interaction.sh - chmod +x mac/env-prequisite-checks.sh + chmod +x common/mac/common-utils.sh + chmod +x common/mac/logging-utils.sh + chmod +x common/mac/env-setup-run.sh + chmod +x common/mac/user-interaction.sh + chmod +x common/mac/env-prequisite-checks.sh echo "✅ All scripts are executable" - name: Run ShellCheck on mac scripts @@ -61,11 +62,12 @@ jobs: brew install shellcheck echo "Running ShellCheck on mac scripts..." shellcheck -x mac/run.sh || true - shellcheck -x mac/common-utils.sh || true - shellcheck -x mac/logging-utils.sh || true - shellcheck -x mac/env-setup-run.sh || true - shellcheck -x mac/user-interaction.sh || true - shellcheck -x mac/env-prequisite-checks.sh || true + shellcheck -x common/mac/run.sh || true + shellcheck -x common/mac/common-utils.sh || true + shellcheck -x common/mac/logging-utils.sh || true + shellcheck -x common/mac/env-setup-run.sh || true + shellcheck -x common/mac/user-interaction.sh || true + shellcheck -x common/mac/env-prequisite-checks.sh || true echo "✅ ShellCheck analysis complete" - name: Verify required dependencies @@ -81,7 +83,7 @@ jobs: run: | set -e echo "Testing script sourcing..." - bash -c "source mac/common-utils.sh && echo '✅ common-utils.sh sourced successfully'" + bash -c "source common/mac/common-utils.sh && echo '✅ common-utils.sh sourced successfully'" echo "✅ Script sourcing successful" - name: Integration Test - Silent Mode Execution @@ -205,18 +207,20 @@ jobs: Write-Host "Validating win/run.ps1 syntax..." $ScriptPath = "win/run.ps1" $null = [System.Management.Automation.PSParser]::Tokenize((Get-Content -Raw $ScriptPath), [ref]$null) + $CommonScriptPath = "common/win/run.ps1" + $null = [System.Management.Automation.PSParser]::Tokenize((Get-Content -Raw $CommonScriptPath), [ref]$null) Write-Host "✅ win/run.ps1 syntax is valid" - name: Validate supporting PowerShell scripts syntax run: | Write-Host "Validating supporting PowerShell scripts..." $Scripts = @( - "win/common-utils.ps1", - "win/logging-utils.ps1", - "win/env-prequisite-checks.ps1", - "win/user-interaction.ps1", - "win/env-setup-run.ps1", - "win/device-machine-allocation.ps1" + "common/win/common-utils.ps1", + "common/win/logging-utils.ps1", + "common/win/env-prequisite-checks.ps1", + "common/win/user-interaction.ps1", + "common/win/env-setup-run.ps1", + "common/win/device-machine-allocation.ps1" ) foreach ($Script in $Scripts) { $null = [System.Management.Automation.PSParser]::Tokenize((Get-Content -Raw $Script), [ref]$null) @@ -400,26 +404,27 @@ jobs: run: | echo "Validating mac/run.sh syntax..." bash -n mac/run.sh + bash -n common/mac/run.sh echo "✅ mac/run.sh syntax is valid" - name: Validate supporting scripts syntax run: | echo "Validating supporting scripts..." - bash -n mac/common-utils.sh - bash -n mac/logging-utils.sh - bash -n mac/env-setup-run.sh - bash -n mac/user-interaction.sh - bash -n mac/env-prequisite-checks.sh + bash -n common/mac/common-utils.sh + bash -n common/mac/logging-utils.sh + bash -n common/mac/env-setup-run.sh + bash -n common/mac/user-interaction.sh + bash -n common/mac/env-prequisite-checks.sh echo "✅ All supporting scripts are valid" - name: Check if scripts are executable run: | chmod +x mac/run.sh - chmod +x mac/common-utils.sh - chmod +x mac/logging-utils.sh - chmod +x mac/env-setup-run.sh - chmod +x mac/user-interaction.sh - chmod +x mac/env-prequisite-checks.sh + chmod +x common/mac/common-utils.sh + chmod +x common/mac/logging-utils.sh + chmod +x common/mac/env-setup-run.sh + chmod +x common/mac/user-interaction.sh + chmod +x common/mac/env-prequisite-checks.sh echo "✅ All scripts are executable" - name: Install ShellCheck @@ -433,11 +438,12 @@ jobs: run: | echo "Running ShellCheck on mac scripts..." shellcheck -x mac/run.sh || true - shellcheck -x mac/common-utils.sh || true - shellcheck -x mac/logging-utils.sh || true - shellcheck -x mac/env-setup-run.sh || true - shellcheck -x mac/user-interaction.sh || true - shellcheck -x mac/env-prequisite-checks.sh || true + shellcheck -x common/mac/run.sh || true + shellcheck -x common/mac/common-utils.sh || true + shellcheck -x common/mac/logging-utils.sh || true + shellcheck -x common/mac/env-setup-run.sh || true + shellcheck -x common/mac/user-interaction.sh || true + shellcheck -x common/mac/env-prequisite-checks.sh || true echo "✅ ShellCheck analysis complete" - name: Verify required dependencies @@ -453,7 +459,7 @@ jobs: run: | set -e echo "Testing script sourcing..." - bash -c "source mac/common-utils.sh && echo '✅ common-utils.sh sourced successfully'" + bash -c "source common/mac/common-utils.sh && echo '✅ common-utils.sh sourced successfully'" echo "✅ Script sourcing successful" - name: Integration Test - Silent Mode Execution diff --git a/common/config/devices.txt b/common/config/devices.txt new file mode 100644 index 0000000..fb21c7c --- /dev/null +++ b/common/config/devices.txt @@ -0,0 +1,23 @@ +# Format: TYPE|PLATFORM|DEVICE_OR_BROWSER +# Web +WEB|Windows|Chrome +WEB|Windows|Firefox +WEB|Windows|Edge +MOBILE|ios|iPhone 1[234567]* +MOBILE|android|Samsung Galaxy S* +WEB|OS X|Chrome +WEB|OS X|Safari +WEB|OS X|Firefox +MOBILE|ios|iPad Air* +MOBILE|android|Samsung Galaxy Tab* +MOBILE|android|Samsung Galaxy M* +MOBILE|android|Google Pixel [56789]* +MOBILE|android|Vivo Y* +MOBILE|android|Oppo* +MOBILE|ios|iPad Pro* +MOBILE|android|Samsung Galaxy A* +MOBILE|android|Google Pixel 10* +MOBILE|android|OnePlus * +MOBILE|android|Vivo V* +MOBILE|android|Xiaomi * +MOBILE|android|Huawei * diff --git a/common/config/repos.txt b/common/config/repos.txt new file mode 100644 index 0000000..a040489 --- /dev/null +++ b/common/config/repos.txt @@ -0,0 +1,6 @@ +web_java|now-testng-browserstack +app_java|now-testng-appium-app-browserstack +web_python|now-pytest-browserstack +app_python|now-pytest-appium-app-browserstack +web_nodejs|now-webdriverio-browserstack +app_nodejs|now-webdriverio-appium-app-browserstack diff --git a/mac/common-utils.sh b/common/mac/common-utils.sh similarity index 91% rename from mac/common-utils.sh rename to common/mac/common-utils.sh index e41f4f8..313deaa 100644 --- a/mac/common-utils.sh +++ b/common/mac/common-utils.sh @@ -1,11 +1,14 @@ #!/bin/bash +# shellcheck source=/dev/null # shellcheck source=/dev/null source "$(dirname "$0")/device-machine-allocation.sh" # # ===== Global Variables ===== WORKSPACE_DIR="$HOME/.browserstack" PROJECT_FOLDER="NOW" +GUI_SCRIPT="$(dirname "${BASH_SOURCE[0]}")/windows-gui.ps1" + # URL handling DEFAULT_TEST_URL="https://bstackdemo.com" @@ -81,6 +84,11 @@ setup_workspace() { # ===== App Upload Management ===== handle_app_upload() { local app_platform="" + if [[ -n "$CLI_APP_PATH" ]]; then + upload_custom_app "$CLI_APP_PATH" + return + fi + if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then upload_sample_app app_platform="android" @@ -96,6 +104,8 @@ handle_app_upload() { buttons {"Use Sample App", "Upload my App (.apk/.ipa)", "Cancel"} ¬ default button "Upload my App (.apk/.ipa)" ' 2>/dev/null) + elif [[ "$NOW_OS" == "windows" ]]; then + choice=$(powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "ClickChoice" -Title "BrowserStack App Upload" -Prompt "How would you like to select your app?" -Choices "Use Sample App,Upload my App (.apk/.ipa),Cancel" -DefaultChoice "Upload my App (.apk/.ipa)" | tr -d '\r') else echo "How would you like to select your app?" select opt in "Use Sample App" "Upload my App (.apk/.ipa)" "Cancel"; do @@ -144,14 +154,17 @@ upload_sample_app() { upload_custom_app() { local app_platform="" - local file_path + local file_path="$1" - # Convert to POSIX path + if [ -z "$file_path" ]; then + # Convert to POSIX path # Convert to POSIX path if [[ "$NOW_OS" == "macos" ]]; then file_path=$(osascript -e \ 'POSIX path of (choose file with prompt "Select your .apk or .ipa file:" of type {"apk", "ipa"})' \ 2>/dev/null) + elif [[ "$NOW_OS" == "windows" ]]; then + file_path=$(powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "OpenFileDialog" -Title "Select your .apk or .ipa file" -Filter "App Files (*.apk;*.ipa)|*.apk;*.ipa|All files (*.*)|*.*" | tr -d '\r') else echo "Please enter the full path to your .apk or .ipa file:" read -r file_path @@ -159,6 +172,7 @@ upload_custom_app() { file_path="${file_path%\"}" file_path="${file_path#\"}" fi + fi # Trim whitespace file_path="${file_path%"${file_path##*[![:space:]]}"}" @@ -217,7 +231,7 @@ generate_mobile_platforms() { local platformsListContentFormat=$2 local app_platform="$APP_PLATFORM" local platformsList="" - platformsList=$(pick_terminal_devices "$app_platform" "$max_total_parallels", "$platformsListContentFormat") + platformsList=$(pick_terminal_devices "$app_platform" "$max_total_parallels" "$platformsListContentFormat") echo "$platformsList" } @@ -277,7 +291,7 @@ fetch_plan_details() { TEAM_PARALLELS_MAX_ALLOWED_MOBILE=5 export TEAM_PARALLELS_MAX_ALLOWED_MOBILE=5 fi - log_info "Resetting Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)" + log_info "Silent mode: Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)" fi } @@ -340,6 +354,15 @@ resolve_ip() { echo "$ip" } +report_bstack_local_status() { + local local_flag=$1 + if [ "$local_flag" == "true" ]; then + log_info "BrowserStack Local: ENABLED" + else + log_info "BrowserStack Local: DISABLED" + fi +} + identify_run_status_java() { local log_file=$1 @@ -391,7 +414,7 @@ identify_run_status_nodejs() { log_success "Success: $passed test(s) passed" return 0 else - log_error "❌ Error: No tests passed" + log_error "Error: No tests passed" return 1 fi } diff --git a/common/mac/device-machine-allocation.sh b/common/mac/device-machine-allocation.sh new file mode 100644 index 0000000..afc353f --- /dev/null +++ b/common/mac/device-machine-allocation.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +CONFIG_FILE="$(dirname "$0")/../config/devices.txt" + +get_devices() { + local type=$1 + local devices=() + while IFS= read -r line; do + # Skip comments and empty lines + [[ "$line" =~ ^#.*$ ]] && continue + [[ -z "$line" ]] && continue + + if [[ "$type" == "MOBILE" ]]; then + if [[ "$line" == MOBILE* ]]; then + devices+=("${line#MOBILE|}") + fi + else + if [[ "$line" == WEB* ]]; then + devices+=("${line#WEB|}") + elif [[ "$line" == MOBILE* ]]; then + # Web also includes mobile devices in the original script logic + devices+=("${line#MOBILE|}") + fi + fi + done < "$CONFIG_FILE" + echo "${devices[@]}" +} + +pick_terminal_devices() { + local platformName="$1" + local count=$2 + count="${count%,}" + local platformsListContentFormat="$3" + + if [[ -z "$platformName" || -z "$count" ]]; then + return 1 + fi + + # Read devices into array + local matching_devices=() + local raw_devices + + if [[ "$platformName" == "android" || "$platformName" == "ios" ]]; then + # Filter specifically for the requested platform from the MOBILE list + while IFS= read -r line; do + [[ "$line" =~ ^#.*$ ]] && continue + [[ -z "$line" ]] && continue + if [[ "$line" == MOBILE* ]]; then + entry="${line#MOBILE|}" + prefix="${entry%%|*}" + if [[ "$prefix" == "$platformName" ]]; then + matching_devices+=("$entry") + fi + fi + done < "$CONFIG_FILE" + else + # For Web, use everything (WEB + MOBILE) as per original logic + while IFS= read -r line; do + [[ "$line" =~ ^#.*$ ]] && continue + [[ -z "$line" ]] && continue + if [[ "$line" == WEB* ]]; then + matching_devices+=("${line#WEB|}") + elif [[ "$line" == MOBILE* ]]; then + matching_devices+=("${line#MOBILE|}") + fi + done < "$CONFIG_FILE" + fi + + if [ ${#matching_devices[@]} -eq 0 ]; then + return 0 + fi + + local yaml="" + local json="[" + + for ((i = 1; i <= count; i++)); do + index=$(( (i - 1) % ${#matching_devices[@]} )) + entry="${matching_devices[$index]}" + suffixEntry="${entry#*|}" + prefixEntry="${entry%%|*}" + + mod=$(( i % 4 )) + local hardcodedBVersion=140 + local bVersionLiteral="" + + if [ $((i % 4)) -ne 0 ]; then + bVersionLiteral="-$mod" + fi + bVersion="latest$bVersionLiteral" + + if [[ "$platformsListContentFormat" == "yaml" ]]; then + if [[ "$prefixEntry" == "android" || "$prefixEntry" == "ios" ]]; then + yaml+=" - platformName: $prefixEntry + deviceName: $suffixEntry +" + else + yaml+=" - osVersion: $prefixEntry + browserName: $suffixEntry + browserVersion: $(( hardcodedBVersion-i )) +" + fi + if [[ $i -lt $count ]]; then + yaml+=$'\n' + fi + + elif [[ "$platformsListContentFormat" == "json" ]]; then + if [[ "$prefixEntry" == "android" || "$prefixEntry" == "ios" ]]; then + json+=$'{"platformName": "'"$prefixEntry"'","bstack:options":{"deviceName": "'"$suffixEntry"'"}},' + else + json+=$'{"bstack:options":{ "os": "'"$prefixEntry"'"},"browserName": "'"$suffixEntry"'","browserVersion": "'"$bVersion"'"},' + fi + fi + done + + json="${json%,}]" + + if [[ "$platformsListContentFormat" == "yaml" ]]; then + echo "$yaml" + else + echo "$json" + fi +} diff --git a/mac/env-prequisite-checks.sh b/common/mac/env-prequisite-checks.sh similarity index 100% rename from mac/env-prequisite-checks.sh rename to common/mac/env-prequisite-checks.sh diff --git a/common/mac/env-setup-run.sh b/common/mac/env-setup-run.sh new file mode 100644 index 0000000..7207630 --- /dev/null +++ b/common/mac/env-setup-run.sh @@ -0,0 +1,287 @@ +#!/usr/bin/env bash +# shellcheck shell=bash + +REPO_CONFIG="$(dirname "$0")/../config/repos.txt" + +get_repo_name() { + local key="$1" + local repo="" + while IFS= read -r line; do + if [[ "$line" == "$key|"* ]]; then + repo="${line#*|}" + echo "$repo" + return + fi + done < "$REPO_CONFIG" +} + +setup_environment() { + local setup_type=$1 + local tech_stack=$2 + local max_parallels + + log_section "📦 Project Setup" + + if [ "$setup_type" = "web" ]; then + max_parallels=$TEAM_PARALLELS_MAX_ALLOWED_WEB + else + max_parallels=$TEAM_PARALLELS_MAX_ALLOWED_MOBILE + fi + + log_msg_to "Starting ${setup_type} setup for $tech_stack" "$NOW_RUN_LOG_FILE" + + local total_parallels=$max_parallels + [ -z "$total_parallels" ] && total_parallels=1 + + local repo_key="${setup_type}_${tech_stack}" + local repo_name=$(get_repo_name "$repo_key") + + if [ -z "$repo_name" ]; then + log_error "Unknown combination: $repo_key" + return 1 + fi + + local target_dir="$WORKSPACE_DIR/$PROJECT_FOLDER/$repo_name" + clone_repository "$repo_name" "$target_dir" + + # Dispatch to specific setup function + "setup_${setup_type}_${tech_stack}" "$target_dir" "$total_parallels" + + local ret=$? + + log_section "✅ Results" + log_info "${setup_type} setup completed with exit code: $ret" + local status=1 + #if [ $ret -eq 0 ]; then + "identify_run_status_${tech_stack}" "$NOW_RUN_LOG_FILE" + status=$? + #fi + + if [ $status -eq 0 ]; then + log_success "${setup_type} setup succeeded." + else + log_error "${setup_type} setup failed." + exit 1 + fi +} + +setup_web_java() { + local cwd=$1 + local parallels=$2 + cd "$cwd" || return 1 + + if is_domain_private; then local_flag=true; else local_flag=false; fi + report_bstack_local_status "$local_flag" + + export BROWSERSTACK_CONFIG_FILE="./browserstack.yml" + platform_yaml=$(generate_web_platforms "$parallels" "yaml") + cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 + + print_env_vars + + + log_info "Running tests..." + mvn test -P sample-test >> "$NOW_RUN_LOG_FILE" 2>&1 & + cmd_pid=$! + show_spinner "$cmd_pid" + wait "$cmd_pid" + return $? +} + +setup_app_java() { + local root_dir=$1 + local parallels=$2 + + if [[ "$APP_PLATFORM" == "all" || "$APP_PLATFORM" == "android" ]]; then + cd "$root_dir/android/testng-examples" || return 1 + else + cd "$root_dir/ios/testng-examples" || return 1 + fi + + export BROWSERSTACK_CONFIG_FILE="./browserstack.yml" + platform_yaml=$(generate_mobile_platforms "$parallels" "yaml") + cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 + + log_info "Running tests..." + mvn test -P sample-test >> "$NOW_RUN_LOG_FILE" 2>&1 & + cmd_pid=$! + show_spinner "$cmd_pid" + wait "$cmd_pid" + return $? +} + +setup_web_python() { + local cwd=$1 + local parallels=$2 + cd "$cwd" || return 1 + + detect_setup_python_env + pip3 install --only-binary grpcio -r requirements.txt >> "$NOW_RUN_LOG_FILE" 2>&1 + + export BROWSERSTACK_CONFIG_FILE="./browserstack.yml" + platform_yaml=$(generate_web_platforms "$parallels" "yaml") + cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 & + cmd_pid=$! + show_spinner "$cmd_pid" + wait "$cmd_pid" + return $? +} + +setup_app_python() { + local cwd=$1 + local parallels=$2 + cd "$cwd" || return 1 + + detect_setup_python_env + pip install --only-binary grpcio -r requirements.txt >> "$NOW_RUN_LOG_FILE" 2>&1 + + local run_dir="android" + if [ "$APP_PLATFORM" = "ios" ]; then run_dir="ios"; fi + + export BROWSERSTACK_CONFIG_FILE="./$run_dir/browserstack.yml" + platform_yaml=$(generate_mobile_platforms "$parallels" "yaml") + cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 + ) & + cmd_pid=$! + show_spinner "$cmd_pid" + wait "$cmd_pid" + return $? +} + +setup_web_nodejs() { + local cwd=$1 + local parallels=$2 + cd "$cwd" || return 1 + + npm install >> "$NOW_RUN_LOG_FILE" 2>&1 + + caps_json=$(generate_web_platforms "$parallels" "json") + export BSTACK_CAPS_JSON=$caps_json + export BSTACK_PARALLELS=$parallels + if is_domain_private; then local_flag=true; else local_flag=false; fi + export BROWSERSTACK_LOCAL=$local_flag + export BROWSERSTACK_BUILD_NAME="now-$NOW_OS-web-nodejs-wdio" + export BROWSERSTACK_PROJECT_NAME="now-$NOW_OS-web" + + print_env_vars + + log_info "Running tests..." + npm run test >> "$NOW_RUN_LOG_FILE" 2>&1 & + cmd_pid=$! + show_spinner "$cmd_pid" + wait "$cmd_pid" + return $? +} + +setup_app_nodejs() { + local root_dir=$1 + local parallels=$2 + # App nodejs clones into root, but tests are in root/test? + # Original script: clone_repository $REPO "$TARGET_DIR" "$TEST_FOLDER" where TEST_FOLDER="/test" + # clone_repository does cd "$install_folder/$test_folder" + # So we should cd to test folder. + cd "$root_dir/test" || return 1 + + npm install >> "$NOW_RUN_LOG_FILE" 2>&1 + + caps_json=$(generate_mobile_platforms "$parallels" "json") + export BSTACK_CAPS_JSON=$caps_json + export BSTACK_PARALLELS=$parallels + export BROWSERSTACK_LOCAL=true + export BROWSERSTACK_APP=$BROWSERSTACK_APP + export BROWSERSTACK_BUILD_NAME="now-$NOW_OS-app-nodejs-wdio" + export BROWSERSTACK_PROJECT_NAME="now-$NOW_OS-app" + + print_env_vars + + log_info "Running tests..." + npm run test >> "$NOW_RUN_LOG_FILE" 2>&1 & + cmd_pid=$! + show_spinner "$cmd_pid" + wait "$cmd_pid" + return $? +} + +clone_repository() { + local repo_git=$1 + local install_folder=$2 + rm -rf "$install_folder" + log_info "Cloning $repo_git..." + git clone "https://github.com/BrowserStackCE/$repo_git.git" "$install_folder" >> "$NOW_RUN_LOG_FILE" 2>&1 +} + +detect_setup_python_env() { + log_info "Setting up Python environment..." + python3 -m venv .venv + if [ -f ".venv/bin/activate" ]; then + source .venv/bin/activate + else + source .venv/Scripts/activate + fi +} + +print_env_vars() { + log_section "Validate Environment Variables and Platforms" + log_info "BrowserStack Username: $BROWSERSTACK_USERNAME" + log_info "BrowserStack Project Name: $BROWSERSTACK_PROJECT_NAME" + log_info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" + if [ $TEST_TYPE == "app" ]; then + log_info "Native App Endpoint: $BROWSERSTACK_APP" + fi + log_info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" + log_info "Parallels per platform: $BSTACK_PARALLELS" + log_info "Platforms: \n$BSTACK_PLATFORMS" +} diff --git a/mac/logging-utils.sh b/common/mac/logging-utils.sh similarity index 100% rename from mac/logging-utils.sh rename to common/mac/logging-utils.sh diff --git a/common/mac/run.sh b/common/mac/run.sh new file mode 100755 index 0000000..951f75d --- /dev/null +++ b/common/mac/run.sh @@ -0,0 +1,91 @@ +#!/bin/bash +set -o pipefail + +# Import utilities +# shellcheck source=/dev/null +source "$(dirname "$0")/common-utils.sh" +# shellcheck source=/dev/null +source "$(dirname "$0")/logging-utils.sh" + +# shellcheck source=/dev/null +source "$(dirname "$0")/env-setup-run.sh" + +# shellcheck source=/dev/null +source "$(dirname "$0")/user-interaction.sh" +# shellcheck source=/dev/null +source "$(dirname "$0")/env-prequisite-checks.sh" + +# ===== Web wrapper with retry logic (writes runtime logs to $NOW_RUN_LOG_FILE) ===== +# Wrapper functions using the common setup_environment function +run_setup() { + local test_type=$1 + local tech_stack=$2 + setup_environment "$test_type" "$tech_stack" +} + + +# ===== Main flow (baseline steps then run) ===== + +detect_os + + +RUN_MODE=$1 # --interactive or --silent / --debug +TT=$2 # Testing Type from env (for silent mode) +TSTACK=$3 # Tech Stack from env (for silent mode) +CLI_TEST_URL=$4 +CLI_APP_PATH=$5 +CLI_APP_PLATFORM=$6 + +export CLI_TEST_URL +export CLI_APP_PATH +export CLI_APP_PLATFORM + +log_section "🧭 Setup Summary – BrowserStack NOW" +log_info "Timestamp: $(date '+%Y-%m-%d %H:%M:%S')" + + +log_file="" +if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then + TEST_TYPE=$TT + TECH_STACK=$TSTACK + log_file="$LOG_DIR/${TEST_TYPE:unknown}_${TECH_STACK:unknown}_run_result.log" + log_info "Run Mode: ${RUN_MODE:-default}" +else + get_test_type "$RUN_MODE" + get_tech_stack "$RUN_MODE" + log_file="$LOG_DIR/${TEST_TYPE:unknown}_${TECH_STACK:unknown}_run_result.log" + perform_next_steps_based_on_test_type "$TEST_TYPE" +fi + +log_info "Log file path: $log_file" +export NOW_RUN_LOG_FILE="$log_file" +setup_workspace +get_browserstack_credentials "$RUN_MODE" + +log_section "⚙️ Platform & Tech Stack" +log_info "Platform: ${TEST_TYPE:-N/A}" +log_info "Tech Stack: ${TECH_STACK:-N/A}" + +validate_tech_stack_installed "$TECH_STACK" +fetch_plan_details "$TEST_TYPE" + +if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then + if [[ $TEST_TYPE == "app" ]]; then + get_upload_app + log_success "Sample App uploaded successfully" + fi +fi + +log_msg_to "Plan summary: WEB_PLAN_FETCHED=$WEB_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_WEB), MOBILE_PLAN_FETCHED=$MOBILE_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" +log_msg_to "Checking proxy in environment" +set_proxy_in_env + +log_section "🧹 Getting Ready" +log_info "Detected Operating system: $NOW_OS" +log_info "Clearing old logs fron NOW Home Directory inside .browserstack" + +clear_old_logs + +log_info "Starting $TEST_TYPE setup for $TECH_STACK" +setup_environment "$TEST_TYPE" "$TECH_STACK" + diff --git a/mac/user-interaction.sh b/common/mac/user-interaction.sh similarity index 70% rename from mac/user-interaction.sh rename to common/mac/user-interaction.sh index d671e50..54fac80 100644 --- a/mac/user-interaction.sh +++ b/common/mac/user-interaction.sh @@ -1,5 +1,35 @@ #!/bin/bash +GUI_SCRIPT="$(dirname "$0")/../win/windows-gui.ps1" + +windows_input_box() { + local title="$1" + local prompt="$2" + local default="$3" + powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "InputBox" -Title "$title" -Prompt "$prompt" -DefaultText "$default" | tr -d '\r' +} + +windows_password_box() { + local title="$1" + local prompt="$2" + powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "PasswordBox" -Title "$title" -Prompt "$prompt" | tr -d '\r' +} + +windows_click_choice() { + local title="$1" + local prompt="$2" + local default="$3" + shift 3 + local choices_str=$(IFS=,; echo "$*") + powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "ClickChoice" -Title "$title" -Prompt "$prompt" -DefaultChoice "$default" -Choices "$choices_str" | tr -d '\r' +} + +windows_open_file_dialog() { + local title="$1" + local filter="$2" + powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "OpenFileDialog" -Title "$title" -Filter "$filter" | tr -d '\r' +} + # ===== Credential Management ===== get_browserstack_credentials() { local run_mode=$1 @@ -13,6 +43,8 @@ get_browserstack_credentials() { if [[ "$NOW_OS" == "macos" ]]; then username=$(osascript -e 'Tell application "System Events" to display dialog "Please enter your BrowserStack Username.\n\nNote: Locate it in your BrowserStack account profile page.\nhttps://www.browserstack.com/accounts/profile/details" default answer "" with title "BrowserStack Setup" buttons {"OK"} default button "OK"' \ -e 'text returned of result') + elif [[ "$NOW_OS" == "windows" ]]; then + username=$(windows_input_box "BrowserStack Setup" "Enter your BrowserStack Username:\n\nLocate it on https://www.browserstack.com/accounts/profile/details" "") else echo "Please enter your BrowserStack Username." echo "Note: Locate it in your BrowserStack account profile page: https://www.browserstack.com/accounts/profile/details" @@ -27,6 +59,8 @@ get_browserstack_credentials() { if [[ "$NOW_OS" == "macos" ]]; then access_key=$(osascript -e 'Tell application "System Events" to display dialog "Please enter your BrowserStack Access Key.\n\nNote: Locate it in your BrowserStack account page.\nhttps://www.browserstack.com/accounts/profile/details" default answer "" with hidden answer with title "BrowserStack Setup" buttons {"OK"} default button "OK"' \ -e 'text returned of result') + elif [[ "$NOW_OS" == "windows" ]]; then + access_key=$(windows_password_box "BrowserStack Setup" "Enter your BrowserStack Access Key:\n\nLocate it on https://www.browserstack.com/accounts/profile/details") else echo "Please enter your BrowserStack Access Key." echo "Note: Locate it in your BrowserStack account page: https://www.browserstack.com/accounts/profile/details" @@ -57,6 +91,10 @@ get_tech_stack() { if [[ "$NOW_OS" == "macos" ]]; then tech_stack=$(osascript -e 'Tell application "System Events" to display dialog "Select installed tech stack:" buttons {"java", "python", "nodejs"} default button "java" with title "Testing Framework Technology Stack"' \ -e 'button returned of result') + elif [[ "$NOW_OS" == "windows" ]]; then + tech_stack=$(windows_click_choice "Tech Stack" "Select your installed language / framework:" "Java" "Java" "Python" "NodeJS") + # Convert to lowercase to match expected values + tech_stack=$(echo "$tech_stack" | tr '[:upper:]' '[:lower:]') else echo "Select installed tech stack:" select opt in "java" "python" "nodejs"; do @@ -79,15 +117,23 @@ get_tech_stack() { get_test_url() { local test_url=$DEFAULT_TEST_URL + if [ -n "$CLI_TEST_URL" ]; then + test_url="$CLI_TEST_URL" + log_msg_to "🌐 Using custom test URL from CLI: $test_url" + else if [[ "$NOW_OS" == "macos" ]]; then test_url=$(osascript -e 'Tell application "System Events" to display dialog "Enter the URL you want to test with BrowserStack:\n(Leave blank for default: '"$DEFAULT_TEST_URL"')" default answer "" with title "Test URL Setup" buttons {"OK"} default button "OK"' \ -e 'text returned of result') + elif [[ "$NOW_OS" == "windows" ]]; then + test_url=$(windows_input_box "Test URL Setup" "Enter the URL you want to test with BrowserStack:\n(Leave blank for default: $DEFAULT_TEST_URL)" "") else echo "Enter the URL you want to test with BrowserStack:" echo "(Leave blank for default: $DEFAULT_TEST_URL)" read -r test_url fi + fi + if [ -n "$test_url" ]; then log_msg_to "🌐 Using custom test URL: $test_url" log_info "🌐 Using custom test URL: $test_url" @@ -111,6 +157,9 @@ get_test_type() { if [[ "$NOW_OS" == "macos" ]]; then test_type=$(osascript -e 'Tell application "System Events" to display dialog "Select testing type:" buttons {"web", "app"} default button "web" with title "Testing Type"' \ -e 'button returned of result') + elif [[ "$NOW_OS" == "windows" ]]; then + test_type=$(windows_click_choice "Testing Type" "What do you want to run?" "Web" "Web" "App") + test_type=$(echo "$test_type" | tr '[:upper:]' '[:lower:]') else echo "Select testing type:" select opt in "web" "app"; do diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 new file mode 100644 index 0000000..7a678c2 --- /dev/null +++ b/common/win/common-utils.ps1 @@ -0,0 +1,520 @@ +# Common Utilities for PowerShell + +# ===== Global Variables ===== +$script:WORKSPACE_DIR = Join-Path $env:USERPROFILE ".browserstack" +$script:PROJECT_FOLDER = "NOW" + +$script:GLOBAL_DIR = Join-Path $WORKSPACE_DIR $PROJECT_FOLDER +$script:LOG_DIR = Join-Path $GLOBAL_DIR "logs" +$script:GLOBAL_LOG = "" + +# Script state +$script:BROWSERSTACK_USERNAME = "" +$script:BROWSERSTACK_ACCESS_KEY = "" +$script:TEST_TYPE = "" # Web / App +$script:TECH_STACK = "" # Java / Python / JS +[double]$script:PARALLEL_PERCENTAGE = 1.00 + +$script:WEB_PLAN_FETCHED = $false +$script:MOBILE_PLAN_FETCHED = $false +[int]$script:TEAM_PARALLELS_MAX_ALLOWED_WEB = 0 +[int]$script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = 0 + +# URL handling +$script:DEFAULT_TEST_URL = "https://bstackdemo.com" +$script:CX_TEST_URL = $DEFAULT_TEST_URL + +# App handling +$script:BROWSERSTACK_APP = "" +$script:APP_PLATFORM = "" # ios | android | all + +# Chosen Python command tokens +$script:PY_CMD = @() + +# ===== Workspace Management ===== +function Ensure-Workspace { + if (!(Test-Path $script:GLOBAL_DIR)) { + New-Item -ItemType Directory -Path $script:GLOBAL_DIR | Out-Null + Log-Line "✅ Created Onboarding workspace: $script:GLOBAL_DIR" $global:NOW_RUN_LOG_FILE + } else { + Log-Line "✅ Onboarding workspace found at: $script:GLOBAL_DIR" $global:NOW_RUN_LOG_FILE + } +} + +function Setup-Workspace { + Log-Section "⚙️ Environment & Credentials" + Ensure-Workspace +} + +function Clear-OldLogs { + if (!(Test-Path $script:LOG_DIR)) { + New-Item -ItemType Directory -Path $script:LOG_DIR | Out-Null + } + + $legacyLogs = @("global.log","web_run_result.log","mobile_run_result.log") + foreach ($legacy in $legacyLogs) { + $legacyPath = Join-Path $script:LOG_DIR $legacy + if (Test-Path $legacyPath) { + Remove-Item -Path $legacyPath -Force -ErrorAction SilentlyContinue + } + } + + Log-Line "✅ Logs directory cleaned. Legacy files removed." $global:NOW_RUN_LOG_FILE +} + +# ===== Git Clone ===== +function Invoke-GitClone { + param( + [Parameter(Mandatory)] [string]$Url, + [Parameter(Mandatory)] [string]$Target, + [string]$Branch, + [string]$LogFile + ) + $argsList = @("clone") + if ($Branch) { $argsList += @("-b", $Branch) } + $argsList += @($Url, $Target) + + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = "git" + $psi.Arguments = ($argsList | ForEach-Object { + if ($_ -match '\s') { '"{0}"' -f $_ } else { $_ } + }) -join ' ' + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + $psi.WorkingDirectory = (Get-Location).Path + + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $psi + [void]$p.Start() + $stdout = $p.StandardOutput.ReadToEnd() + $stderr = $p.StandardError.ReadToEnd() + $p.WaitForExit() + + if ($LogFile) { + if ($stdout) { Add-Content -Path $LogFile -Value $stdout } + if ($stderr) { Add-Content -Path $LogFile -Value $stderr } + } + + if ($p.ExitCode -ne 0) { + throw "git clone failed (exit $($p.ExitCode)): $stderr" + } +} + +function Invoke-External { + param( + [Parameter(Mandatory)][string]$Exe, + [Parameter()][string[]]$Arguments = @(), + [string]$LogFile, + [string]$WorkingDirectory + ) + $psi = New-Object System.Diagnostics.ProcessStartInfo + $exeToRun = $Exe + $argLine = ($Arguments | ForEach-Object { if ($_ -match '\s') { '"{0}"' -f $_ } else { $_ } }) -join ' ' + + $ext = [System.IO.Path]::GetExtension($Exe) + if ($ext -and ($ext.ToLowerInvariant() -in @('.cmd','.bat'))) { + if (-not (Test-Path $Exe)) { throw "Command not found: $Exe" } + $psi.FileName = "cmd.exe" + $psi.Arguments = "/c `"$Exe`" $argLine" + } else { + $psi.FileName = $exeToRun + $psi.Arguments = $argLine + } + + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + $psi.UseShellExecute = $false + $psi.CreateNoWindow = $true + if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) { + $psi.WorkingDirectory = (Get-Location).Path + } else { + $psi.WorkingDirectory = $WorkingDirectory + } + + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $psi + + if ($LogFile) { + $logDir = Split-Path -Parent $LogFile + if ($logDir -and !(Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir | Out-Null } + + # Synchronous read is safer for simple logging to avoid deadlock if buffer fills, + # but async is better for real-time. We'll use async events. + + $outputHandler = { + if (-not [string]::IsNullOrEmpty($EventArgs.Data)) { + Add-Content -Path $Event.MessageData -Value $EventArgs.Data -Encoding UTF8 + } + } + + $stdoutEvent = Register-ObjectEvent -InputObject $p -EventName OutputDataReceived -Action $outputHandler -MessageData $LogFile + $stderrEvent = Register-ObjectEvent -InputObject $p -EventName ErrorDataReceived -Action $outputHandler -MessageData $LogFile + + [void]$p.Start() + $p.BeginOutputReadLine() + $p.BeginErrorReadLine() + $p.WaitForExit() + + Unregister-Event -SourceIdentifier $stdoutEvent.Name + Unregister-Event -SourceIdentifier $stderrEvent.Name + Remove-Job -Id $stdoutEvent.Id -Force + Remove-Job -Id $stderrEvent.Id -Force + } else { + [void]$p.Start() + $p.WaitForExit() + } + + return $p.ExitCode +} + +function Get-MavenCommand { + param([Parameter(Mandatory)][string]$RepoDir) + $mvnCmd = Get-Command mvn -ErrorAction SilentlyContinue + if ($mvnCmd) { return $mvnCmd.Source } + $wrapper = Join-Path $RepoDir "mvnw.cmd" + if (Test-Path $wrapper) { return $wrapper } + throw "Maven not found in PATH and 'mvnw.cmd' not present under $RepoDir. Install Maven or ensure the wrapper exists." +} + +function Get-VenvPython { + param([Parameter(Mandatory)][string]$VenvDir) + $py = Join-Path $VenvDir "Scripts\python.exe" + if (Test-Path $py) { return $py } + throw "Python interpreter not found in venv: $VenvDir" +} + +function Set-PythonCmd { + $candidates = @( + @("python3"), + @("python"), + @("py","-3"), + @("py") + ) + foreach ($cand in $candidates) { + try { + $exe = $cand[0] + $argsList = @() + if ($cand.Length -gt 1) { $argsList = $cand[1..($cand.Length-1)] } + $code = Invoke-External -Exe $exe -Arguments ($argsList + @("--version")) -LogFile $null + if ($code -eq 0) { + $script:PY_CMD = $cand + return + } + } catch {} + } + throw "Python not found via python3/python/py. Please install Python 3 and ensure it's on PATH." +} + +function Invoke-Py { + param( + [Parameter(Mandatory)][string[]]$Arguments, + [string]$LogFile, + [string]$WorkingDirectory + ) + if (-not $script:PY_CMD -or $script:PY_CMD.Count -eq 0) { Set-PythonCmd } + $exe = $script:PY_CMD[0] + $baseArgs = @() + if ($script:PY_CMD.Count -gt 1) { $baseArgs = $script:PY_CMD[1..($script:PY_CMD.Count-1)] } + return (Invoke-External -Exe $exe -Arguments ($baseArgs + $Arguments) -LogFile $LogFile -WorkingDirectory $WorkingDirectory) +} + +function Show-Spinner { + param([Parameter(Mandatory)][System.Diagnostics.Process]$Process) + $spin = @('|','/','-','\') + $i = 0 + $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") + while (!$Process.HasExited) { + Write-Host "`r[$ts] ⏳ Processing... $($spin[$i])" -NoNewline -ForegroundColor Cyan + $i = ($i + 1) % 4 + Start-Sleep -Milliseconds 100 + } + Write-Host "" + Log-Info "Run Test command completed." + Start-Sleep -Seconds 2 +} + +function Test-PrivateIP { + param([string]$IP) + if ([string]::IsNullOrWhiteSpace($IP)) { return $false } + $parts = $IP.Split('.') + if ($parts.Count -ne 4) { return $false } + $first = [int]$parts[0] + $second = [int]$parts[1] + if ($first -eq 10) { return $true } + if ($first -eq 192 -and $second -eq 168) { return $true } + if ($first -eq 172 -and $second -ge 16 -and $second -le 31) { return $true } + return $false +} + +function Test-DomainPrivate { + $domain = $script:CX_TEST_URL -replace '^https?://', '' -replace '/.*$', '' + Log-Line "Website domain: $domain" $global:NOW_RUN_LOG_FILE + $env:NOW_WEB_DOMAIN = $script:CX_TEST_URL + + $IP_ADDRESS = "" + try { + $dnsResult = Resolve-DnsName -Name $domain -Type A -ErrorAction Stop | Where-Object { $_.Type -eq 'A' } | Select-Object -First 1 + if ($dnsResult) { + $IP_ADDRESS = $dnsResult.IPAddress + } + } catch { + try { + $nslookupOutput = nslookup $domain 2>&1 | Out-String + if ($nslookupOutput -match '(?:Address|Addresses):\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') { + $IP_ADDRESS = $matches[1] + } + } catch { + Log-Line "⚠️ Failed to resolve domain: $domain (assuming public domain)" $global:NOW_RUN_LOG_FILE + $IP_ADDRESS = "" + } + } + + if ([string]::IsNullOrWhiteSpace($IP_ADDRESS)) { + Log-Line "⚠️ DNS resolution failed for: $domain (treating as public domain, BrowserStack Local will be DISABLED)" $global:NOW_RUN_LOG_FILE + } else { + Log-Line "✅ Resolved IP: $IP_ADDRESS" $global:NOW_RUN_LOG_FILE + } + + return (Test-PrivateIP -IP $IP_ADDRESS) +} + +function Report-BStack-Local-Status { + param([bool]$LocalFlag) + if ($LocalFlag) { + Log-Info "BrowserStack Local: ENABLED" + } else { + Log-Info "BrowserStack Local: DISABLED" + } +} + +function Get-BasicAuthHeader { + param([string]$User, [string]$Key) + $pair = "{0}:{1}" -f $User,$Key + $bytes = [System.Text.Encoding]::UTF8.GetBytes($pair) + "Basic {0}" -f [System.Convert]::ToBase64String($bytes) +} + +function Fetch-Plan-Details { + param([string]$TestType) + + if ([string]::IsNullOrWhiteSpace($TestType)) { + throw "Test type is required to fetch plan details." + } + + $normalized = $TestType.ToLowerInvariant() + Log-Section "☁️ Account & Plan Details" + Log-Info "Fetching BrowserStack plan for $normalized" + + $auth = Get-BasicAuthHeader -User $script:BROWSERSTACK_USERNAME -Key $script:BROWSERSTACK_ACCESS_KEY + $headers = @{ Authorization = $auth } + + switch ($normalized) { + "web" { + try { + $resp = Invoke-RestMethod -Method Get -Uri "https://api.browserstack.com/automate/plan.json" -Headers $headers + $script:WEB_PLAN_FETCHED = $true + $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = [int]$resp.parallel_sessions_max_allowed + Log-Line "✅ Web Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_WEB" $global:NOW_RUN_LOG_FILE + } catch { + Log-Line "❌ Web Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE + } + if (-not $script:WEB_PLAN_FETCHED) { + throw "Unable to fetch Web Testing plan details." + } + } + "app" { + try { + $resp2 = Invoke-RestMethod -Method Get -Uri "https://api-cloud.browserstack.com/app-automate/plan.json" -Headers $headers + $script:MOBILE_PLAN_FETCHED = $true + $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = [int]$resp2.parallel_sessions_max_allowed + Log-Line "✅ Mobile App Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE" $global:NOW_RUN_LOG_FILE + } catch { + Log-Line "❌ Mobile App Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE + } + if (-not $script:MOBILE_PLAN_FETCHED) { + throw "Unable to fetch Mobile App Testing plan details." + } + } + default { + throw "Unsupported TEST_TYPE: $TestType. Allowed values: Web, App." + } + } + + if ($script:IS_SILENT_MODE) { + $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = 5 + $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = 5 + Log-Line "Silent mode: Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)" $global:NOW_RUN_LOG_FILE + } else { + Log-Line "ℹ️ Plan summary: Web fetched=$script:WEB_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_WEB), Mobile fetched=$script:MOBILE_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" $global:NOW_RUN_LOG_FILE + } + +} + +function Invoke-SampleAppUpload { + Log-Line "⬆️ Uploading sample app to BrowserStack..." $global:NOW_RUN_LOG_FILE + $headers = @{ + Authorization = (Get-BasicAuthHeader -User $script:BROWSERSTACK_USERNAME -Key $script:BROWSERSTACK_ACCESS_KEY) + } + $body = @{ + url = "https://www.browserstack.com/app-automate/sample-apps/android/WikipediaSample.apk" + } + try { + $resp = Invoke-RestMethod -Method Post -Uri "https://api-cloud.browserstack.com/app-automate/upload" -Headers $headers -ContentType "application/x-www-form-urlencoded" -Body $body + $url = $resp.app_url + if ([string]::IsNullOrWhiteSpace($url)) { + throw "Sample app upload failed (empty URL)" + } + Log-Line "✅ App uploaded successfully: $url" $global:NOW_RUN_LOG_FILE + return @{ + Url = $url + Platform = "android" + } + } catch { + Log-Line "❌ Upload failed: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE + throw + } +} + +function Invoke-CustomAppUpload { + param( + [Parameter(Mandatory)][string]$FilePath + ) + + $ext = [System.IO.Path]::GetExtension($FilePath).ToLowerInvariant() + switch ($ext) { + ".apk" { $platform = "android" } + ".ipa" { $platform = "ios" } + default { throw "Unsupported app file (only .apk/.ipa)" } + } + + Log-Line "⬆️ Uploading app to BrowserStack..." $global:NOW_RUN_LOG_FILE + + $boundary = [System.Guid]::NewGuid().ToString() + $LF = "`r`n" + $fileBin = [System.IO.File]::ReadAllBytes($FilePath) + $fileName = [System.IO.Path]::GetFileName($FilePath) + + $bodyLines = ( + "--$boundary", + "Content-Disposition: form-data; name=`"file`"; filename=`"$fileName`"", + "Content-Type: application/octet-stream$LF", + [System.Text.Encoding]::GetEncoding("iso-8859-1").GetString($fileBin), + "--$boundary--$LF" + ) -join $LF + + $headers = @{ + Authorization = (Get-BasicAuthHeader -User $script:BROWSERSTACK_USERNAME -Key $script:BROWSERSTACK_ACCESS_KEY) + "Content-Type" = "multipart/form-data; boundary=$boundary" + } + + try { + $resp = Invoke-RestMethod -Method Post -Uri "https://api-cloud.browserstack.com/app-automate/upload" -Headers $headers -Body $bodyLines + $url = $resp.app_url + if ([string]::IsNullOrWhiteSpace($url)) { + throw "Upload failed (empty URL)" + } + Log-Line "✅ App uploaded successfully: $url" $global:NOW_RUN_LOG_FILE + return @{ + Url = $url + Platform = $platform + } + } catch { + Log-Line "❌ Upload failed: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE + throw + } +} + +function Identify-Run-Status-Java { + param([string]$LogFile) + + $content = Get-Content -Path $LogFile -Raw -ErrorAction SilentlyContinue + if (-not $content) { + Log-Warn "❌ No test summary line found." + return $false + } + + # Regex for "Tests run: 1, Failures: 0, Errors: 0, Skipped: 0" + if ($content -match "Tests run: (\d+), Failures: (\d+), Errors: (\d+), Skipped: (\d+)") { + $testsRun = [int]$matches[1] + $failures = [int]$matches[2] + $errors = [int]$matches[3] + $skipped = [int]$matches[4] + + $passed = $testsRun - ($failures + $errors + $skipped) + if ($passed -gt 0) { + Log-Success "Success: $passed test(s) passed." + return $true + } else { + Log-Error "Error: No tests passed (Tests run: $testsRun, Failures: $failures, Errors: $errors, Skipped: $skipped)" + return $false + } + } + + Log-Warn "❌ No test summary line found." + return $false +} + +function Identify-Run-Status-Python { + param([string]$LogFile) + + $content = Get-Content -Path $LogFile -Raw -ErrorAction SilentlyContinue + if (-not $content) { + Log-Warn "❌ No test summary line found." + return $false + } + + # Regex for "X passed" + $matches = [regex]::Matches($content, '(\d+) passed') + $passedSum = 0 + foreach ($m in $matches) { + $passedSum += [int]$m.Groups[1].Value + } + + Write-Host "✅ Total Passed: $passedSum" -ForegroundColor Green + + if ($passedSum -gt 0) { + Log-Success "Success: $passedSum test(s) completed" + return $true + } else { + Log-Error "Error: No tests completed" + return $false + } +} + +function Identify-Run-Status-NodeJS { + param([string]$LogFile) + + $content = Get-Content -Path $LogFile -Raw -ErrorAction SilentlyContinue + if (-not $content) { + Log-Warn "❌ No test summary line found." + return $false + } + + # Regex for "Spec Files:.*passed.*total" + if ($content -match "Spec Files:.*passed.*total") { + # Extract passed count + if ($content -match '(\d+) passed') { + $passed = [int]$matches[1] + if ($passed -gt 0) { + Log-Success "Success: $passed test(s) passed" + return $true + } + } + } + + Log-Error "Error: No tests passed" + return $false +} + +# ===== Dynamic config generators ===== +function Generate-Web-Platforms { + param($MaxTotalParallels, $Format) + return Pick-Terminal-Devices -PlatformName "web" -Count $MaxTotalParallels -PlatformsListContentFormat $Format +} + +function Generate-Mobile-Platforms { + param($MaxTotalParallels, $Format) + return Pick-Terminal-Devices -PlatformName $script:APP_PLATFORM -Count $MaxTotalParallels -PlatformsListContentFormat $Format +} diff --git a/common/win/device-machine-allocation.ps1 b/common/win/device-machine-allocation.ps1 new file mode 100644 index 0000000..24a16a5 --- /dev/null +++ b/common/win/device-machine-allocation.ps1 @@ -0,0 +1,90 @@ +# Device Machine Allocation for PowerShell + +$script:CONFIG_FILE = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "..\config\devices.txt" + +function Get-Matching-Devices { + param([string]$PlatformName) + + $devices = @() + if (-not (Test-Path $script:CONFIG_FILE)) { return $devices } + + $lines = Get-Content $script:CONFIG_FILE + + if ($PlatformName -eq "android" -or $PlatformName -eq "ios") { + foreach ($line in $lines) { + if ($line -match "^MOBILE\|") { + $entry = $line -replace "^MOBILE\|", "" + $prefix = ($entry -split '\|')[0] + if ($prefix -eq $PlatformName) { + $devices += $entry + } + } + } + } else { + # Web includes WEB and MOBILE + foreach ($line in $lines) { + if ($line -match "^WEB\|") { + $devices += ($line -replace "^WEB\|", "") + } elseif ($line -match "^MOBILE\|") { + $devices += ($line -replace "^MOBILE\|", "") + } + } + } + return $devices +} + +function Pick-Terminal-Devices { + param( + [string]$PlatformName, + [string]$Count, + [string]$PlatformsListContentFormat + ) + + $Count = $Count -replace ',$', '' + if (-not ($Count -match '^\d+$')) { return "" } + + $matchingDevices = Get-Matching-Devices -PlatformName $PlatformName + if ($matchingDevices.Count -eq 0) { return "" } + + $yaml = "" + $jsonList = @() + $countInt = [int]$Count + + for ($i = 1; $i -le $countInt; $i++) { + $index = ($i - 1) % $matchingDevices.Count + $entry = $matchingDevices[$index] + $parts = $entry -split '\|' + $prefixEntry = $parts[0] + $suffixEntry = $parts[1] + + $mod = $i % 4 + $hardcodedBVersion = 140 + $bVersionLiteral = "" + if (($i % 4) -ne 0) { $bVersionLiteral = "-$mod" } + $bVersion = "latest$bVersionLiteral" + + if ($PlatformsListContentFormat -eq "yaml") { + if ($prefixEntry -eq "android" -or $prefixEntry -eq "ios") { + $yaml += " - platformName: $prefixEntry`n deviceName: $suffixEntry`n" + } else { + $browserVer = $hardcodedBVersion - $i + $yaml += " - osVersion: $prefixEntry`n browserName: $suffixEntry`n browserVersion: $browserVer`n" + } + if ($i -lt $countInt) { $yaml += "`n" } + } elseif ($PlatformsListContentFormat -eq "json") { + if ($prefixEntry -eq "android" -or $prefixEntry -eq "ios") { + $obj = @{ platformName = $prefixEntry; "bstack:options" = @{ deviceName = $suffixEntry } } + $jsonList += $obj + } else { + $obj = @{ "bstack:options" = @{ os = $prefixEntry }; browserName = $suffixEntry; browserVersion = $bVersion } + $jsonList += $obj + } + } + } + + if ($PlatformsListContentFormat -eq "yaml") { + return $yaml + } else { + return ($jsonList | ConvertTo-Json -Depth 5 -Compress) + } +} diff --git a/common/win/env-prequisite-checks.ps1 b/common/win/env-prequisite-checks.ps1 new file mode 100644 index 0000000..8f74dce --- /dev/null +++ b/common/win/env-prequisite-checks.ps1 @@ -0,0 +1,154 @@ +# Environment Prerequisite Checks for PowerShell + +$script:PROXY_TEST_URL = "https://www.browserstack.com/automate/browsers.json" +$script:PROXY_HOST = "" +$script:PROXY_PORT = "" + +function Parse-Proxy { + param([string]$ProxyUrl) + # Strip protocol + $p = $ProxyUrl -replace '^https?://', '' + # Strip credentials + $p = $p -replace '^.*@', '' + + if ($p -match '^([^:]+):(\d+)$') { + $script:PROXY_HOST = $matches[1] + $script:PROXY_PORT = $matches[2] + } +} + +function Set-ProxyInEnv { + Log-Section "🌐 Network & Proxy Validation" + + # Detect proxy from env + $proxy = $env:http_proxy + if (-not $proxy) { $proxy = $env:HTTP_PROXY } + if (-not $proxy) { $proxy = $env:https_proxy } + if (-not $proxy) { $proxy = $env:HTTPS_PROXY } + + if ([string]::IsNullOrWhiteSpace($proxy)) { + Log-Warn "No proxy found. Using direct connection." + $script:PROXY_HOST = "" + $script:PROXY_PORT = "" + return + } + + Log-Line "Proxy detected: $proxy" $global:NOW_RUN_LOG_FILE + Parse-Proxy -ProxyUrl $proxy + + Log-Line "Testing reachability via proxy..." $global:NOW_RUN_LOG_FILE + + $auth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${env:BROWSERSTACK_USERNAME}:${env:BROWSERSTACK_ACCESS_KEY}")) + + try { + $resp = Invoke-WebRequest -Uri $PROXY_TEST_URL -Proxy $proxy -Headers @{ Authorization = "Basic $auth" } -Method Head -ErrorAction Stop + $statusCode = $resp.StatusCode + Log-Line "✅ Reachable. HTTP $statusCode" $global:NOW_RUN_LOG_FILE + Log-Line "Exporting PROXY_HOST=$script:PROXY_HOST" $global:NOW_RUN_LOG_FILE + Log-Line "Exporting PROXY_PORT=$script:PROXY_PORT" $global:NOW_RUN_LOG_FILE + + $env:PROXY_HOST = $script:PROXY_HOST + $env:PROXY_PORT = $script:PROXY_PORT + Log-Success "Connected to BrowserStack from proxy: $script:PROXY_HOST:$script:PROXY_PORT" + } catch { + Log-Warn "⚠️ Could not connect to BrowserStack using proxy. Using direct connection." + Log-Line "❌ Not reachable ($($_.Exception.Message)). Clearing variables." $global:NOW_RUN_LOG_FILE + $script:PROXY_HOST = "" + $script:PROXY_PORT = "" + $env:PROXY_HOST = "" + $env:PROXY_PORT = "" + } +} + +function Check-Java-Installation { + Log-Line "🔍 Checking if 'java' command exists..." $global:NOW_RUN_LOG_FILE + if (-not (Get-Command java -ErrorAction SilentlyContinue)) { + Log-Line "❌ Java command not found in PATH." $global:NOW_RUN_LOG_FILE + return $false + } + + Log-Line "🔍 Checking if Java runs correctly..." $global:NOW_RUN_LOG_FILE + try { + $output = java -version 2>&1 | Out-String + Log-Success "Java installed and functional`n$output" + return $true + } catch { + Log-Line "❌ Java exists but failed to run." $global:NOW_RUN_LOG_FILE + return $false + } +} + +function Check-Python-Installation { + Log-Line "🔍 Checking if 'python' command exists..." $global:NOW_RUN_LOG_FILE + # Windows usually uses 'python', not 'python3' + $pyCmd = Get-Command python -ErrorAction SilentlyContinue + if (-not $pyCmd) { + $pyCmd = Get-Command python3 -ErrorAction SilentlyContinue + } + + if (-not $pyCmd) { + Log-Line "❌ Python command not found in PATH." $global:NOW_RUN_LOG_FILE + return $false + } + + Log-Line "🔍 Checking if Python runs correctly..." $global:NOW_RUN_LOG_FILE + try { + $output = & $pyCmd.Name --version 2>&1 | Out-String + Log-Success "Python default installation: $output" + return $true + } catch { + Log-Line "❌ Python exists but failed to run." $global:NOW_RUN_LOG_FILE + return $false + } +} + +function Check-NodeJS-Installation { + Log-Line "🔍 Checking if 'node' command exists..." $global:NOW_RUN_LOG_FILE + if (-not (Get-Command node -ErrorAction SilentlyContinue)) { + Log-Line "❌ Node.js command not found in PATH." $global:NOW_RUN_LOG_FILE + return $false + } + + Log-Line "🔍 Checking if 'npm' command exists..." $global:NOW_RUN_LOG_FILE + if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { + Log-Line "❌ npm command not found in PATH." $global:NOW_RUN_LOG_FILE + return $false + } + + Log-Line "🔍 Checking if Node.js runs correctly..." $global:NOW_RUN_LOG_FILE + try { + $nodeVer = node -v 2>&1 | Out-String + $npmVer = npm -v 2>&1 | Out-String + Log-Success "Node.js installed: $nodeVer" + Log-Success "npm installed: $npmVer" + return $true + } catch { + Log-Line "❌ Node.js/npm exists but failed to run." $global:NOW_RUN_LOG_FILE + return $false + } +} + +function Validate-Tech-Stack { + param([string]$TechStack) + + Log-Section "🧩 System Prerequisites Check" + Log-Info "Checking prerequisites for $TechStack" + + $valid = $false + switch ($TechStack.ToLower()) { + "java" { $valid = Check-Java-Installation } + "python" { $valid = Check-Python-Installation } + "nodejs" { $valid = Check-NodeJS-Installation } + default { + Log-Line "❌ Unknown tech stack selected: $TechStack" $global:NOW_RUN_LOG_FILE + return $false + } + } + + if ($valid) { + Log-Line "✅ Prerequisites validated for $TechStack" $global:NOW_RUN_LOG_FILE + return $true + } else { + return $false + } +} diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 new file mode 100644 index 0000000..016ee69 --- /dev/null +++ b/common/win/env-setup-run.ps1 @@ -0,0 +1,274 @@ +# Environment Setup and Run for PowerShell + +$script:REPO_CONFIG = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "..\config\repos.txt" + +function Get-Repo-Name { + param([string]$Key) + if (-not (Test-Path $script:REPO_CONFIG)) { return "" } + $lines = Get-Content $script:REPO_CONFIG + foreach ($line in $lines) { + if ($line.StartsWith("$Key|")) { + return ($line -split '\|')[1] + } + } + return "" +} + +function Setup-Environment { + param( + [string]$SetupType, + [string]$TechStack + ) + + Log-Section "📦 Project Setup" + + $maxParallels = 0 + if ($SetupType -eq "web") { + $maxParallels = $script:TEAM_PARALLELS_MAX_ALLOWED_WEB + } else { + $maxParallels = $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE + } + + Log-Line "Starting ${SetupType} setup for $TechStack" $global:NOW_RUN_LOG_FILE + + $totalParallels = $maxParallels + if (-not $totalParallels -or $totalParallels -lt 1) { $totalParallels = 1 } + + $repoKey = "${SetupType}_${TechStack}" + $repoName = Get-Repo-Name -Key $repoKey + + if ([string]::IsNullOrWhiteSpace($repoName)) { + Log-Error "Unknown combination: $repoKey" + return + } + + $targetDir = Join-Path $script:GLOBAL_DIR $repoName + + # Clone + Clone-Repository -RepoGit $repoName -InstallFolder $targetDir -TestFolder "" + + $result = $false + switch ($repoKey) { + "web_java" { $result = Setup-Web-Java -TargetDir $targetDir -Parallels $totalParallels } + "app_java" { $result = Setup-App-Java -TargetDir $targetDir -Parallels $totalParallels } + "web_python" { $result = Setup-Web-Python -TargetDir $targetDir -Parallels $totalParallels } + "app_python" { $result = Setup-App-Python -TargetDir $targetDir -Parallels $totalParallels } + "web_nodejs" { $result = Setup-Web-NodeJS -TargetDir $targetDir -Parallels $totalParallels } + "app_nodejs" { $result = Setup-App-NodeJS -TargetDir $targetDir -Parallels $totalParallels } + } + + Log-Section "✅ Results" + + Log-Info "${SetupType} setup completed with exit code: $result" + + # Identify run status + $status = $false + switch ($TechStack) { + "java" { $status = Identify-Run-Status-Java -LogFile $global:NOW_RUN_LOG_FILE } + "python" { $status = Identify-Run-Status-Python -LogFile $global:NOW_RUN_LOG_FILE } + "nodejs" { $status = Identify-Run-Status-NodeJS -LogFile $global:NOW_RUN_LOG_FILE } + } + + if ($status -and $result) { + Log-Success "${SetupType} setup succeeded." + } else { + Log-Error "❌ ${SetupType} setup failed. Check logs for details." + exit 1 + } +} + +function Clone-Repository { + param($RepoGit, $InstallFolder, $TestFolder, $GitBranch) + if (Test-Path $InstallFolder) { Remove-Item -Path $InstallFolder -Recurse -Force -ErrorAction SilentlyContinue } + Log-Info "Cloning repository: $RepoGit" + $url = "https://github.com/BrowserStackCE/${RepoGit}.git" + Invoke-GitClone -Url $url -Target $InstallFolder -Branch $GitBranch -LogFile $global:NOW_RUN_LOG_FILE +} + +function Setup-Web-Java { + param($TargetDir, $Parallels) + Set-Location $TargetDir + + if (Test-DomainPrivate) { $LocalFlag = $true } else { $LocalFlag = $false } + Report-BStack-Local-Status $LocalFlag + + $configFile = Join-Path $TargetDir "browserstack.yml" + $platformYaml = Generate-Web-Platforms -MaxTotalParallels $script:TEAM_PARALLELS_MAX_ALLOWED_WEB -Format "yaml" + Add-Content -Path $configFile -Value "`nplatforms:`n$platformYaml" -Encoding UTF8 + + $env:BSTACK_PARALLELS = $Parallels + $env:BSTACK_PLATFORMS = $platformYaml + $env:BROWSERSTACK_LOCAL = $LocalFlag.ToString().ToLower() + $env:BROWSERSTACK_BUILD_NAME = "now-windows-web-java-testng" + $env:BROWSERSTACK_PROJECT_NAME = "now-windows-web" + + Print-Env-Variables + + Log-Info "Installing dependencies" + $mvn = Get-MavenCommand -RepoDir $TargetDir + Invoke-External -Exe $mvn -Arguments @("install","-DskipTests") -LogFile $global:NOW_RUN_LOG_FILE + + Log-Info "Running tests..." + $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + Show-Spinner -Process $p + $p.WaitForExit() + return ($p.ExitCode -eq 0) +} + +function Setup-App-Java { + param($TargetDir, $Parallels) + + if ($script:APP_PLATFORM -eq "all" -or $script:APP_PLATFORM -eq "android") { + Set-Location (Join-Path $TargetDir "android/testng-examples") + } else { + Set-Location (Join-Path $TargetDir "ios/testng-examples") + } + + $configFile = Join-Path (Get-Location) "browserstack.yml" + $platformYaml = Generate-Mobile-Platforms -MaxTotalParallels $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE -Format "yaml" + Add-Content -Path $configFile -Value "`napp: $script:BROWSERSTACK_APP`nplatforms:`n$platformYaml" -Encoding UTF8 + + $env:BSTACK_PARALLELS = $Parallels + $env:BROWSERSTACK_LOCAL = "true" + $env:BSTACK_PLATFORMS = $platformYaml + $env:BROWSERSTACK_BUILD_NAME = "now-windows-app-java-testng" + $env:BROWSERSTACK_PROJECT_NAME = "now-windows-app" + + Print-Env-Variables + + Log-Info "Installing dependencies" + $mvn = Get-MavenCommand -RepoDir (Get-Location).Path + Invoke-External -Exe $mvn -Arguments @("clean") -LogFile $global:NOW_RUN_LOG_FILE + + Log-Info "Running tests..." + $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + Show-Spinner -Process $p + $p.WaitForExit() + return ($p.ExitCode -eq 0) +} + +function Setup-Web-Python { + param($TargetDir, $Parallels) + Set-Location $TargetDir + Detect-Setup-Python-Env + Invoke-Py -Arguments @("-m","pip","install","--only-binary","grpcio","-r","requirements.txt") -LogFile $global:NOW_RUN_LOG_FILE + + $configFile = Join-Path $TargetDir "browserstack.yml" + $platformYaml = Generate-Web-Platforms -MaxTotalParallels $script:TEAM_PARALLELS_MAX_ALLOWED_WEB -Format "yaml" + Add-Content -Path $configFile -Value "`nplatforms:`n$platformYaml" -Encoding UTF8 + + if (Test-DomainPrivate) { $LocalFlag = $true } else { $LocalFlag = $false } + $env:BSTACK_PARALLELS = 1 + $env:BROWSERSTACK_LOCAL = $LocalFlag.ToString().ToLower() + $env:BSTACK_PLATFORMS = $platformYaml + $env:BROWSERSTACK_BUILD_NAME = "now-windows-web-python-pytest" + $env:BROWSERSTACK_PROJECT_NAME = "now-windows-web" + + Print-Env-Variables + + Log-Info "Running tests..." + $sdkExe = Join-Path $TargetDir ".venv\Scripts\browserstack-sdk.exe" + $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","tests/" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + Show-Spinner -Process $p + $p.WaitForExit() + return ($p.ExitCode -eq 0) +} + +function Setup-App-Python { + param($TargetDir, $Parallels) + Set-Location $TargetDir + Detect-Setup-Python-Env + Invoke-Py -Arguments @("-m","pip","install","--only-binary","grpcio","-r","requirements.txt") -LogFile $global:NOW_RUN_LOG_FILE + + $runDir = "android" + if ($script:APP_PLATFORM -eq "ios") { $runDir = "ios" } + + $configFile = Join-Path $TargetDir "$runDir\browserstack.yml" + $platformYaml = Generate-Mobile-Platforms -MaxTotalParallels $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE -Format "yaml" + Add-Content -Path $configFile -Value "`nplatforms:`n$platformYaml" -Encoding UTF8 + + $env:BSTACK_PARALLELS = 1 + $env:BROWSERSTACK_LOCAL = "true" + $env:BSTACK_PLATFORMS = $platformYaml + $env:BROWSERSTACK_BUILD_NAME = "now-windows-app-python-pytest" + $env:BROWSERSTACK_PROJECT_NAME = "now-windows-app" + + Print-Env-Variables + + Log-Info "Running tests..." + Set-Location $runDir + $sdkExe = Join-Path $TargetDir ".venv\Scripts\browserstack-sdk.exe" + $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","bstack_sample.py" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + Show-Spinner -Process $p + $p.WaitForExit() + return ($p.ExitCode -eq 0) +} + +function Setup-Web-NodeJS { + param($TargetDir, $Parallels) + Set-Location $TargetDir + Invoke-External -Exe "npm" -Arguments @("install") -LogFile $global:NOW_RUN_LOG_FILE + + $capsJson = Generate-Web-Platforms -MaxTotalParallels $Parallels -Format "json" + $env:BSTACK_CAPS_JSON = $capsJson + $env:BSTACK_PARALLELS = $Parallels + + if (Test-DomainPrivate) { $LocalFlag = $true } else { $LocalFlag = $false } + $env:BROWSERSTACK_LOCAL = $LocalFlag.ToString().ToLower() + $env:BROWSERSTACK_BUILD_NAME = "now-windows-web-nodejs-wdio" + $env:BROWSERSTACK_PROJECT_NAME = "now-windows-web" + + Print-Env-Variables + + Log-Info "Running tests..." + $npmCmd = Get-Command npm -ErrorAction SilentlyContinue + if ($npmCmd.Source.EndsWith(".cmd")) { $exe = "cmd.exe"; $args = @("/c", "npm", "run", "test") } else { $exe = "npm"; $args = @("run", "test") } + $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + Show-Spinner -Process $p + $p.WaitForExit() + return ($p.ExitCode -eq 0) +} + +function Setup-App-NodeJS { + param($TargetDir, $Parallels) + # App nodejs: clone to target, test in target/test + Set-Location (Join-Path $TargetDir "test") + + Invoke-External -Exe "npm" -Arguments @("install") -LogFile $global:NOW_RUN_LOG_FILE + + $capsJson = Generate-Mobile-Platforms -MaxTotalParallels $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE -Format "json" + $env:BSTACK_CAPS_JSON = $capsJson + $env:BSTACK_PARALLELS = $Parallels + $env:BROWSERSTACK_LOCAL = "true" + $env:BROWSERSTACK_APP = $script:BROWSERSTACK_APP + $env:BROWSERSTACK_BUILD_NAME = "now-windows-app-nodejs-wdio" + $env:BROWSERSTACK_PROJECT_NAME = "now-windows-app" + + Print-Env-Variables + + Log-Info "Running tests..." + $npmCmd = Get-Command npm -ErrorAction SilentlyContinue + if ($npmCmd.Source.EndsWith(".cmd")) { $exe = "cmd.exe"; $args = @("/c", "npm", "run", "test") } else { $exe = "npm"; $args = @("run", "test") } + $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + Show-Spinner -Process $p + $p.WaitForExit() + return ($p.ExitCode -eq 0) +} + +function Detect-Setup-Python-Env { + Log-Info "Detecting latest Python environment" + Set-PythonCmd + $pyExe = $script:PY_CMD[0] + Invoke-External -Exe $pyExe -Arguments @("-m","venv",".venv") -LogFile $global:NOW_RUN_LOG_FILE +} + +function Print-Env-Variables { + Log-Section "Validate Environment Variables and Platforms" + Log-Info "BrowserStack Username: $BROWSERSTACK_USERNAME" + Log-Info "BrowserStack Project Name: $BROWSERSTACK_PROJECT_NAME" + Log-Info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" + if ($TEST_TYPE -eq "app") { Log-Info "Native App Endpoint: $BROWSERSTACK_APP" } + Log-Info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" + Log-Info "Parallels per platform: $BSTACK_PARALLELS" + Log-Info "Platforms: \n$BSTACK_PLATFORMS" +} diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 new file mode 100644 index 0000000..056492f --- /dev/null +++ b/common/win/logging-utils.ps1 @@ -0,0 +1,55 @@ +# Logging Helpers for PowerShell + +# ============================================== +# 🎨 COLOR & STYLE DEFINITIONS +# ============================================== +# PowerShell uses Write-Host -ForegroundColor for colors. +# We will define helper functions instead of raw escape codes for better compatibility. + +function Log-Section { + param([string]$Message) + Write-Host "" + Write-Host "───────────────────────────────────────────────" -ForegroundColor Cyan + Write-Host $Message -ForegroundColor White + Write-Host "───────────────────────────────────────────────" -ForegroundColor Cyan +} + +function Log-Info { + param([string]$Message) + Write-Host "ℹ️ $Message" -ForegroundColor Gray +} + +function Log-Success { + param([string]$Message) + Write-Host "✅ $Message" -ForegroundColor Green +} + +function Log-Warn { + param([string]$Message) + Write-Host "⚠️ $Message" -ForegroundColor Yellow +} + +function Log-Error { + param([string]$Message) + Write-Host "❌ $Message" -ForegroundColor Red +} + +function Log-Line { + param( + [string]$Message, + [string]$LogFile + ) + $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") + $line = "[$ts] $Message" + + # Print to console if debug mode (or always, depending on usage in bash) + # Bash version: prints to console if RUN_MODE contains --debug + # But common-utils.sh log_msg_to also prints to console if debug. + # Here we just append to file if provided. + + if (-not [string]::IsNullOrWhiteSpace($LogFile)) { + $dir = Split-Path -Parent $LogFile + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + Add-Content -Path $LogFile -Value $line -Encoding UTF8 + } +} diff --git a/common/win/run.ps1 b/common/win/run.ps1 new file mode 100644 index 0000000..d7d2a8d --- /dev/null +++ b/common/win/run.ps1 @@ -0,0 +1,116 @@ +#requires -version 5.0 +<# + BrowserStack Onboarding (PowerShell 5.0+, GUI) + - Shared logic for Windows + - Uses WinForms for GUI prompts + - Logs to %USERPROFILE%\.browserstack\NOW\logs +#> + +param( + [string]$RunMode = "--interactive", + [string]$TT, + [string]$TSTACK, + [string]$TestUrl, + [string]$AppPath, + [string]$AppPlatform +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +# ===== Import utilities ===== +$script:PSScriptRootResolved = Split-Path -Parent $MyInvocation.MyCommand.Path +. (Join-Path $PSScriptRootResolved "logging-utils.ps1") +. (Join-Path $PSScriptRootResolved "common-utils.ps1") + +. (Join-Path $PSScriptRootResolved "user-interaction.ps1") +. (Join-Path $PSScriptRootResolved "env-prequisite-checks.ps1") +. (Join-Path $PSScriptRootResolved "env-setup-run.ps1") + + +# ===== Main flow (baseline steps then run) ===== +try { + # Get test type and tech stack before logging + if ($RunMode -match "--silent|--debug") { + $textInfo = (Get-Culture).TextInfo + $ttCandidate = if ($TT) { $TT } else { $env:TEST_TYPE } + if ([string]::IsNullOrWhiteSpace($ttCandidate)) { throw "TEST_TYPE is required in silent/debug mode." } + $tsCandidate = if ($TSTACK) { $TSTACK } else { $env:TECH_STACK } + if ([string]::IsNullOrWhiteSpace($tsCandidate)) { throw "TECH_STACK is required in silent/debug mode." } + $script:TEST_TYPE = $textInfo.ToTitleCase($ttCandidate.ToLowerInvariant()) + $script:TECH_STACK = $textInfo.ToTitleCase($tsCandidate.ToLowerInvariant()) + if ($TEST_TYPE -notin @("Web","App")) { throw "TEST_TYPE must be either 'Web' or 'App'." } + if ($TECH_STACK -notin @("Java","Python","NodeJS")) { throw "TECH_STACK must be one of: Java, Python, NodeJS." } + } else { + Resolve-Test-Type -RunMode $RunMode -CliValue $TT + Resolve-Tech-Stack -RunMode $RunMode -CliValue $TSTACK + } + + # Setup log file path AFTER selections + $logFileName = "{0}_{1}_run_result.log" -f $TEST_TYPE.ToLowerInvariant(), $TECH_STACK.ToLowerInvariant() + $logFile = Join-Path $script:LOG_DIR $logFileName + if (!(Test-Path $script:LOG_DIR)) { + New-Item -ItemType Directory -Path $script:LOG_DIR -Force | Out-Null + } + '' | Out-File -FilePath $logFile -Encoding UTF8 + $script:GLOBAL_LOG = $logFile + $global:NOW_RUN_LOG_FILE = $logFile + + Log-Line "ℹ️ Log file path: $logFile" $global:NOW_RUN_LOG_FILE + + # Setup Summary Header + Log-Section "🧭 Setup Summary – BrowserStack NOW" + Log-Line "ℹ️ Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE + Log-Line "ℹ️ Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE + Log-Line "ℹ️ Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE + Log-Line "ℹ️ Selected Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE + + # Setup workspace and get credentials BEFORE app upload + Setup-Workspace + Ask-BrowserStack-Credentials -RunMode $RunMode -UsernameFromEnv $env:BROWSERSTACK_USERNAME -AccessKeyFromEnv $env:BROWSERSTACK_ACCESS_KEY + + # NOW handle URL/App upload (requires credentials) + Perform-NextSteps-BasedOnTestType -TestType $TEST_TYPE -RunMode $RunMode -TestUrl $TestUrl -AppPath $AppPath -AppPlatform $AppPlatform + + # Run the setup + Setup-Environment -SetupType $TEST_TYPE.ToLower() -TechStack $TECH_STACK.ToLower() + + # Platform & Tech Stack section + Log-Section "⚙️ Platform & Tech Stack" + Log-Line "ℹ️ Platform: $TEST_TYPE" $global:NOW_RUN_LOG_FILE + Log-Line "ℹ️ Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE + + # System Prerequisites Check + Validate-Tech-Stack -TechStack $TECH_STACK + + # Account & Plan Details + Fetch-Plan-Details -TestType $TEST_TYPE + + Log-Line "Checking proxy in environment" $global:NOW_RUN_LOG_FILE + Set-ProxyInEnv + + # Getting Ready section + Log-Section "🧹 Getting Ready" + Log-Line "ℹ️ Detected Operating system: Windows" $global:NOW_RUN_LOG_FILE + Log-Line "ℹ️ Clearing old logs from NOW Home Directory inside .browserstack" $global:NOW_RUN_LOG_FILE + Clear-OldLogs + + Log-Line "ℹ️ Starting $TEST_TYPE setup for $TECH_STACK" $global:NOW_RUN_LOG_FILE + + # Run the setup + Setup-Environment -SetupType $TEST_TYPE.ToLower() -TechStack $TECH_STACK.ToLower() + +} catch { + Log-Line " " $global:NOW_RUN_LOG_FILE + Log-Line "========================================" $global:NOW_RUN_LOG_FILE + Log-Line "❌ EXECUTION FAILED" $global:NOW_RUN_LOG_FILE + Log-Line "========================================" $global:NOW_RUN_LOG_FILE + Log-Line "Error: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE + Log-Line "Check logs for details:" $global:NOW_RUN_LOG_FILE + Log-Line (" Run Log: {0}" -f $global:NOW_RUN_LOG_FILE) $global:NOW_RUN_LOG_FILE + Log-Line "========================================" $global:NOW_RUN_LOG_FILE + exit 1 +} diff --git a/win/user-interaction.ps1 b/common/win/user-interaction.ps1 similarity index 78% rename from win/user-interaction.ps1 rename to common/win/user-interaction.ps1 index 307bb8e..f63e602 100644 --- a/win/user-interaction.ps1 +++ b/common/win/user-interaction.ps1 @@ -1,4 +1,7 @@ -# User interaction helpers (GUI + CLI) for Windows BrowserStack NOW. +# User Interaction Helpers for PowerShell + +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing function Show-InputBox { param( @@ -162,21 +165,29 @@ function Ask-BrowserStack-Credentials { if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_USERNAME) -or [string]::IsNullOrWhiteSpace($script:BROWSERSTACK_ACCESS_KEY)) { throw "BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY must be provided in silent/debug mode." } - Log-Line "✅ BrowserStack credentials loaded from environment for user: $script:BROWSERSTACK_USERNAME" $GLOBAL_LOG + Log-Line "✅ BrowserStack credentials loaded from environment for user: $script:BROWSERSTACK_USERNAME" $global:NOW_RUN_LOG_FILE + + # Export to process env for child processes + $env:BROWSERSTACK_USERNAME = $script:BROWSERSTACK_USERNAME + $env:BROWSERSTACK_ACCESS_KEY = $script:BROWSERSTACK_ACCESS_KEY return } $script:BROWSERSTACK_USERNAME = Show-InputBox -Title "BrowserStack Setup" -Prompt "Enter your BrowserStack Username:`n`nLocate it on https://www.browserstack.com/accounts/profile/details" -DefaultText "" if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_USERNAME)) { - Log-Line "❌ Username empty" $GLOBAL_LOG + Log-Line "❌ Username empty" $global:NOW_RUN_LOG_FILE throw "Username is required" } $script:BROWSERSTACK_ACCESS_KEY = Show-PasswordBox -Title "BrowserStack Setup" -Prompt "Enter your BrowserStack Access Key:`n`nLocate it on https://www.browserstack.com/accounts/profile/details" if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_ACCESS_KEY)) { - Log-Line "❌ Access Key empty" $GLOBAL_LOG + Log-Line "❌ Access Key empty" $global:NOW_RUN_LOG_FILE throw "Access Key is required" } - Log-Line "✅ BrowserStack credentials captured (access key hidden)" $GLOBAL_LOG + + $env:BROWSERSTACK_USERNAME = $script:BROWSERSTACK_USERNAME + $env:BROWSERSTACK_ACCESS_KEY = $script:BROWSERSTACK_ACCESS_KEY + + Log-Line "✅ BrowserStack credentials captured (access key hidden)" $global:NOW_RUN_LOG_FILE } function Resolve-Test-Type { @@ -189,7 +200,10 @@ function Resolve-Test-Type { if ([string]::IsNullOrWhiteSpace($CliValue)) { throw "TEST_TYPE is required in silent/debug mode." } $candidate = (Get-Culture).TextInfo.ToTitleCase($CliValue.ToLowerInvariant()) if ($candidate -notin @("Web","App")) { - throw "TEST_TYPE must be either 'Web' or 'App'." + # Try to be flexible + if ($candidate -eq "Web") { $candidate = "Web" } + elseif ($candidate -eq "App") { $candidate = "App" } + else { throw "TEST_TYPE must be either 'Web' or 'App'." } } $script:TEST_TYPE = $candidate return @@ -214,7 +228,11 @@ function Resolve-Tech-Stack { $textInfo = (Get-Culture).TextInfo $candidate = $textInfo.ToTitleCase($CliValue.ToLowerInvariant()) if ($candidate -notin @("Java","Python","NodeJS")) { - throw "TECH_STACK must be one of: Java, Python, NodeJS." + # Normalize + if ($candidate -eq "Java") { } + elseif ($candidate -eq "Python") { } + elseif ($candidate -match "Node") { $candidate = "NodeJS" } + else { throw "TECH_STACK must be one of: Java, Python, NodeJS." } } $script:TECH_STACK = $candidate return @@ -231,16 +249,22 @@ function Resolve-Tech-Stack { function Ask-User-TestUrl { param([string]$RunMode,[string]$CliValue) if ($RunMode -match "--silent" -or $RunMode -match "--debug") { - $script:CX_TEST_URL = if ($CliValue) { $CliValue } elseif ($env:CX_TEST_URL) { $env:CX_TEST_URL } else { $DEFAULT_TEST_URL } + $script:CX_TEST_URL = if ($CliValue) { $CliValue } elseif ($env:CX_TEST_URL) { $env:CX_TEST_URL } else { $script:DEFAULT_TEST_URL } return } + + if (-not [string]::IsNullOrWhiteSpace($CliValue)) { + $script:CX_TEST_URL = $CliValue + Log-Line "🌐 Using custom test URL from CLI: $CliValue" $global:NOW_RUN_LOG_FILE + return + } - $testUrl = Show-InputBox -Title "Test URL Setup" -Prompt "Enter the URL you want to test with BrowserStack:`n(Leave blank for default: $DEFAULT_TEST_URL)" -DefaultText "" + $testUrl = Show-InputBox -Title "Test URL Setup" -Prompt "Enter the URL you want to test with BrowserStack:`n(Leave blank for default: $script:DEFAULT_TEST_URL)" -DefaultText "" if ([string]::IsNullOrWhiteSpace($testUrl)) { - $testUrl = $DEFAULT_TEST_URL - Log-Line "⚠️ No URL entered. Falling back to default: $testUrl" $GLOBAL_LOG + $testUrl = $script:DEFAULT_TEST_URL + Log-Line "⚠️ No URL entered. Falling back to default: $testUrl" $global:NOW_RUN_LOG_FILE } else { - Log-Line "🌐 Using custom test URL: $testUrl" $GLOBAL_LOG + Log-Line "🌐 Using custom test URL: $testUrl" $global:NOW_RUN_LOG_FILE } $script:CX_TEST_URL = $testUrl } @@ -253,65 +277,6 @@ function Show-OpenOrSampleAppDialog { return $appChoice } -function Invoke-SampleAppUpload { - $headers = @{ - Authorization = (Get-BasicAuthHeader -User $BROWSERSTACK_USERNAME -Key $BROWSERSTACK_ACCESS_KEY) - } - $body = @{ - url = "https://www.browserstack.com/app-automate/sample-apps/android/WikipediaSample.apk" - } - $resp = Invoke-RestMethod -Method Post -Uri "https://api-cloud.browserstack.com/app-automate/upload" -Headers $headers -ContentType "application/x-www-form-urlencoded" -Body $body - $url = $resp.app_url - if ([string]::IsNullOrWhiteSpace($url)) { - throw "Sample app upload failed" - } - return @{ - Url = $url - Platform = "android" - } -} - -function Invoke-CustomAppUpload { - param( - [Parameter(Mandatory)][string]$FilePath - ) - - $ext = [System.IO.Path]::GetExtension($FilePath).ToLowerInvariant() - switch ($ext) { - ".apk" { $platform = "android" } - ".ipa" { $platform = "ios" } - default { throw "Unsupported app file (only .apk/.ipa)" } - } - - $boundary = [System.Guid]::NewGuid().ToString() - $LF = "`r`n" - $fileBin = [System.IO.File]::ReadAllBytes($FilePath) - $fileName = [System.IO.Path]::GetFileName($FilePath) - - $bodyLines = ( - "--$boundary", - "Content-Disposition: form-data; name=`"file`"; filename=`"$fileName`"", - "Content-Type: application/octet-stream$LF", - [System.Text.Encoding]::GetEncoding("iso-8859-1").GetString($fileBin), - "--$boundary--$LF" - ) -join $LF - - $headers = @{ - Authorization = (Get-BasicAuthHeader -User $BROWSERSTACK_USERNAME -Key $BROWSERSTACK_ACCESS_KEY) - "Content-Type" = "multipart/form-data; boundary=$boundary" - } - - $resp = Invoke-RestMethod -Method Post -Uri "https://api-cloud.browserstack.com/app-automate/upload" -Headers $headers -Body $bodyLines - $url = $resp.app_url - if ([string]::IsNullOrWhiteSpace($url)) { - throw "Upload failed" - } - return @{ - Url = $url - Platform = $platform - } -} - function Ask-And-Upload-App { param( [string]$RunMode, @@ -322,22 +287,29 @@ function Ask-And-Upload-App { if ($RunMode -match "--silent" -or $RunMode -match "--debug") { if ($CliPath) { $result = Invoke-CustomAppUpload -FilePath $CliPath - $script:APP_URL = $result.Url + $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = if ($CliPlatform) { $CliPlatform } else { $result.Platform } return } $result = Invoke-SampleAppUpload - Log-Line "⚠️ Using auto-uploaded sample app: $($result.Url)" $GLOBAL_LOG - $script:APP_URL = $result.Url + Log-Line "⚠️ Using auto-uploaded sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE + $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform return } + + if (-not [string]::IsNullOrWhiteSpace($CliPath)) { + $result = Invoke-CustomAppUpload -FilePath $CliPath + $script:BROWSERSTACK_APP = $result.Url + $script:APP_PLATFORM = if ($CliPlatform) { $CliPlatform } else { $result.Platform } + return + } $choice = Show-OpenOrSampleAppDialog if ([string]::IsNullOrWhiteSpace($choice) -or $choice -eq "Sample App") { $result = Invoke-SampleAppUpload - Log-Line "⚠️ Using sample app: $($result.Url)" $GLOBAL_LOG - $script:APP_URL = $result.Url + Log-Line "⚠️ Using sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE + $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform return } @@ -345,19 +317,18 @@ function Ask-And-Upload-App { $path = Show-OpenFileDialog -Title "📱 Select your .apk or .ipa file" -Filter "App Files (*.apk;*.ipa)|*.apk;*.ipa|All files (*.*)|*.*" if ([string]::IsNullOrWhiteSpace($path)) { $result = Invoke-SampleAppUpload - Log-Line "⚠️ No app selected. Using sample app: $($result.Url)" $GLOBAL_LOG - $script:APP_URL = $result.Url + Log-Line "⚠️ No app selected. Using sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE + $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform return } $result = Invoke-CustomAppUpload -FilePath $path - $script:APP_URL = $result.Url + $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform - Log-Line "✅ App uploaded successfully: $($result.Url)" $GLOBAL_LOG + Log-Line "✅ App uploaded successfully: $($result.Url)" $global:NOW_RUN_LOG_FILE } -# ===== Perform next steps based on test type (like Mac's perform_next_steps_based_on_test_type) ===== function Perform-NextSteps-BasedOnTestType { param( [string]$TestType, @@ -379,4 +350,3 @@ function Perform-NextSteps-BasedOnTestType { } } } - diff --git a/common/win/windows-gui.ps1 b/common/win/windows-gui.ps1 new file mode 100644 index 0000000..e92c58d --- /dev/null +++ b/common/win/windows-gui.ps1 @@ -0,0 +1,169 @@ +param( + [string]$Command, + [string]$Title, + [string]$Prompt, + [string]$DefaultText, + [string[]]$Choices, + [string]$DefaultChoice, + [string]$Filter +) + +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +function Show-InputBox { + param( + [string]$Title = "Input", + [string]$Prompt = "Enter value:", + [string]$DefaultText = "" + ) + $form = New-Object System.Windows.Forms.Form + $form.Text = $Title + $form.Size = New-Object System.Drawing.Size(500,220) + $form.StartPosition = "CenterScreen" + + $label = New-Object System.Windows.Forms.Label + $label.Text = $Prompt + $label.MaximumSize = New-Object System.Drawing.Size(460,0) + $label.AutoSize = $true + $label.Location = New-Object System.Drawing.Point(10,20) + $form.Controls.Add($label) + + $textBox = New-Object System.Windows.Forms.TextBox + $textBox.Size = New-Object System.Drawing.Size(460,20) + $textBox.Location = New-Object System.Drawing.Point(10,($label.Bottom + 10)) + $textBox.Text = $DefaultText + $form.Controls.Add($textBox) + + $okButton = New-Object System.Windows.Forms.Button + $okButton.Text = "OK" + $okButton.Location = New-Object System.Drawing.Point(380,($textBox.Bottom + 20)) + $okButton.Add_Click({ $form.Tag = $textBox.Text; $form.Close() }) + $form.Controls.Add($okButton) + + $form.AcceptButton = $okButton + [void]$form.ShowDialog() + return [string]$form.Tag +} + +function Show-PasswordBox { + param( + [string]$Title = "Secret", + [string]$Prompt = "Enter secret:" + ) + $form = New-Object System.Windows.Forms.Form + $form.Text = $Title + $form.Size = New-Object System.Drawing.Size(500,220) + $form.StartPosition = "CenterScreen" + + $label = New-Object System.Windows.Forms.Label + $label.Text = $Prompt + $label.MaximumSize = New-Object System.Drawing.Size(460,0) + $label.AutoSize = $true + $label.Location = New-Object System.Drawing.Point(10,20) + $form.Controls.Add($label) + + $textBox = New-Object System.Windows.Forms.TextBox + $textBox.Size = New-Object System.Drawing.Size(460,20) + $textBox.Location = New-Object System.Drawing.Point(10,($label.Bottom + 10)) + $textBox.UseSystemPasswordChar = $true + $form.Controls.Add($textBox) + + $okButton = New-Object System.Windows.Forms.Button + $okButton.Text = "OK" + $okButton.Location = New-Object System.Drawing.Point(380,($textBox.Bottom + 20)) + $okButton.Add_Click({ $form.Tag = $textBox.Text; $form.Close() }) + $form.Controls.Add($okButton) + + $form.AcceptButton = $okButton + [void]$form.ShowDialog() + return [string]$form.Tag +} + +function Show-ClickChoice { + param( + [string]$Title = "Choose", + [string]$Prompt = "Select one:", + [string[]]$Choices, + [string]$DefaultChoice + ) + if (-not $Choices -or $Choices.Count -eq 0) { return "" } + + $form = New-Object System.Windows.Forms.Form + $form.Text = $Title + $form.StartPosition = "CenterScreen" + $form.MinimizeBox = $false + $form.MaximizeBox = $false + $form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog + $form.BackColor = [System.Drawing.Color]::FromArgb(245,245,245) + + $label = New-Object System.Windows.Forms.Label + $label.Text = $Prompt + $label.AutoSize = $true + $label.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Regular) + $label.Location = New-Object System.Drawing.Point(12, 12) + $form.Controls.Add($label) + + $panel = New-Object System.Windows.Forms.FlowLayoutPanel + $panel.Location = New-Object System.Drawing.Point(12, 40) + $panel.Size = New-Object System.Drawing.Size(460, 140) + $panel.WrapContents = $true + $panel.AutoScroll = $true + $panel.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight + $form.Controls.Add($panel) + + $selected = $null + foreach ($c in $Choices) { + $btn = New-Object System.Windows.Forms.Button + $btn.Text = $c + $btn.Width = 140 + $btn.Height = 40 + $btn.Margin = '8,8,8,8' + $btn.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold) + $btn.FlatStyle = 'System' + if ($c -eq $DefaultChoice) { + $btn.BackColor = [System.Drawing.Color]::FromArgb(232,240,254) + } + $btn.Add_Click({ + $script:selected = $this.Text + $form.Tag = $script:selected + $form.Close() + }) + $panel.Controls.Add($btn) + } + + $cancel = New-Object System.Windows.Forms.Button + $cancel.Text = "Cancel" + $cancel.Width = 90 + $cancel.Height = 32 + $cancel.Location = New-Object System.Drawing.Point(382, 188) + $cancel.Add_Click({ $form.Tag = ""; $form.Close() }) + $form.Controls.Add($cancel) + $form.CancelButton = $cancel + + $form.ClientSize = New-Object System.Drawing.Size(484, 230) + [void]$form.ShowDialog() + return [string]$form.Tag +} + +function Show-OpenFileDialog { + param( + [string]$Title = "Select File", + [string]$Filter = "All files (*.*)|*.*" + ) + $ofd = New-Object System.Windows.Forms.OpenFileDialog + $ofd.Title = $Title + $ofd.Filter = $Filter + $ofd.Multiselect = $false + if ($ofd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + return $ofd.FileName + } + return "" +} + +switch ($Command) { + "InputBox" { Show-InputBox -Title $Title -Prompt $Prompt -DefaultText $DefaultText } + "PasswordBox" { Show-PasswordBox -Title $Title -Prompt $Prompt } + "ClickChoice" { Show-ClickChoice -Title $Title -Prompt $Prompt -Choices $Choices -DefaultChoice $DefaultChoice } + "OpenFileDialog" { Show-OpenFileDialog -Title $Title -Filter $Filter } +} diff --git a/mac/device-machine-allocation.sh b/mac/device-machine-allocation.sh deleted file mode 100644 index 69b9512..0000000 --- a/mac/device-machine-allocation.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/bin/bash - -# --------------------------- -# Usage: ./pick_devices.sh -# Example: ./pick_devices.sh android 3 -# --------------------------- - - -# Define array of devices -MOBILE_ALL=( - # Tier 1 - "ios|iPhone 1[234567]*" - "android|Samsung Galaxy S*" - - # Tier 2 - "ios|iPad Air*" - "android|Samsung Galaxy Tab*" - "android|Samsung Galaxy M*" - "android|Google Pixel [56789]*" - "android|Vivo Y*" - "android|Oppo*" - - # Tier 4 - "ios|iPad Pro*" - "android|Samsung Galaxy A*" - "android|Google Pixel 10*" - "android|OnePlus *" - "android|Vivo V*" - "android|Xiaomi *" - "android|Huawei *" -) - -WEB_ALL=( - "Windows|Chrome" - "Windows|Firefox" - "Windows|Edge" - "Windows|Chrome" - "Windows|Chrome" - "OS X|Chrome" - "OS X|Safari" - "OS X|Chrome" - "OS X|Safari" - "OS X|Firefox" - "OS X|Safari" - # Tier 1 - "ios|iPhone 1[234567]*" - "android|Samsung Galaxy S*" - - # Tier 2 - "ios|iPad Air*" - "android|Samsung Galaxy Tab*" - "android|Samsung Galaxy M*" - "android|Google Pixel [56789]*" - "android|Vivo Y*" - "android|Oppo*" - - # Tier 4 - "ios|iPhone SE*" - "ios|iPad Pro*" - "android|Samsung Galaxy A*" - "android|Google Pixel 10*" - "android|OnePlus *" - "android|Vivo V*" - "android|Xiaomi *" - "android|Huawei *" -) - - - -pick_terminal_devices() { - local platformName="$1" - local count=$2 - count="${count%,}" # remove trailing comma if present - local platformsListContentFormat="$3" - - # --------------------------- - # Check for valid input - # --------------------------- - if [[ -z "$platformName" || -z "$count" ]]; then - log_msg_to "Platform name for parallel count is invalid: $platformName $count" - return 1 - fi - - # Validate count is a number - if ! [[ "$count" =~ ^[0-9]+$ ]]; then - log_msg_to "Error: count must be a number." - return 1 - fi - - # --------------------------- - # Filter and store matching entries - # --------------------------- - matching_devices=() - - if [[ "$platformName" == "android" || "$platformName" == "ios" ]]; then - for entry in "${MOBILE_ALL[@]}"; do - prefix="${entry%%|*}" # text before '|' - if [[ "$prefix" == "$platformName" ]]; then - matching_devices+=("$entry") - fi - done - else - for entry in "${WEB_ALL[@]}"; do - matching_devices+=("$entry") - done - fi - - # --------------------------- - # Loop as many times as 'count' - # --------------------------- - local yaml="" - local json="[" - - for ((i = 1; i <= count; i++)); do - index=$(( (i - 1) % ${#matching_devices[@]} )) - entry="${matching_devices[$index]}" - suffixEntry="${entry#*|}" - prefixEntry="${entry%%|*}" - bVersionLiteral="" - mod=$(( i % 4 )) - - local hardcodedBVersion=140 # python doesn't support dynamic latest versioning yet - - if [ $((i % 4)) -ne 0 ]; then - bVersionLiteral="-$mod" - else - bVersionLiteral="" - fi - bVersion="latest$bVersionLiteral" - if [[ "$platformsListContentFormat" == "yaml" ]]; then - if [[ "$prefixEntry" == "android" || "$prefixEntry" == "ios" ]]; then - yaml+=" - platformName: $prefixEntry - deviceName: $suffixEntry -" - else - yaml+=" - osVersion: $prefixEntry - browserName: $suffixEntry - browserVersion: $(( hardcodedBVersion-i )) -" - fi - - # Add comma-like separator logic here only if needed - if [[ $i -lt $count ]]; then - yaml+=$'\n' - fi - - elif [[ "$platformsListContentFormat" == "json" ]]; then - # JSON mode - if [[ "$prefixEntry" == "android" || "$prefixEntry" == "ios" ]]; then - json+=$'{"platformName": "'"$prefixEntry"'","bstack:options":{"deviceName": "'"$suffixEntry"'"}},' - else - json+=$'{"bstack:options":{ "os": "'"$prefixEntry"'"},"browserName": "'"$suffixEntry"'","browserVersion": "'"$bVersion"'"},' - fi - - # Stop if max reached - if [[ -n "$max_total" && $i -ge $max_total ]]; then - break - fi - fi - done - - # Close JSON array - json="${json%,}]" - - # Output based on requested format - if [[ "$platformsListContentFormat" == "yaml" ]]; then - echo "$yaml" - else - echo "$json" - fi -} \ No newline at end of file diff --git a/mac/env-setup-run.sh b/mac/env-setup-run.sh deleted file mode 100644 index 398ce24..0000000 --- a/mac/env-setup-run.sh +++ /dev/null @@ -1,548 +0,0 @@ -#!/usr/bin/env bash -# shellcheck shell=bash - -setup_environment() { - local setup_type=$1 - local tech_stack=$2 - local max_parallels - - log_section "📦 Project Setup" - - # Set variables based on setup type - if [ "$setup_type" = "web" ]; then - log_msg_to "Team max parallels for web: $TEAM_PARALLELS_MAX_ALLOWED_WEB" "$NOW_RUN_LOG_FILE" - max_parallels=$TEAM_PARALLELS_MAX_ALLOWED_WEB - else - log_msg_to "Team max parallels for mobile: $TEAM_PARALLELS_MAX_ALLOWED_MOBILE" "$NOW_RUN_LOG_FILE" - max_parallels=$TEAM_PARALLELS_MAX_ALLOWED_MOBILE - fi - - log_msg_to "Starting ${setup_type} setup for " "$tech_stack" "$NOW_RUN_LOG_FILE" - - local local_flag=false - - # Calculate parallels - local total_parallels - total_parallels=$(awk -v n="$max_parallels" 'BEGIN { printf "%d", n }') - [ -z "$total_parallels" ] && total_parallels=1 - local parallels_per_platform=$total_parallels - - log_msg_to "[${setup_type} Setup]" "$NOW_RUN_LOG_FILE" - log_msg_to "Total parallels allocated: $total_parallels" "$NOW_RUN_LOG_FILE" - - - case "$tech_stack" in - java) - "setup_${setup_type}_java" "$local_flag" "$parallels_per_platform" "$NOW_RUN_LOG_FILE" - log_section "✅ Results" - identify_run_status_java "$NOW_RUN_LOG_FILE" - check_return_value $? "$NOW_RUN_LOG_FILE" "${setup_type} setup succeeded." "❌ ${setup_type} setup failed. Check $log_file for details" - ;; - python) - "setup_${setup_type}_python" "$local_flag" "$parallels_per_platform" "$NOW_RUN_LOG_FILE" - log_section "✅ Results" - identify_run_status_python "$NOW_RUN_LOG_FILE" - check_return_value $? "$NOW_RUN_LOG_FILE" "${setup_type} setup succeeded." "❌ ${setup_type} setup failed. Check $log_file for details" - ;; - nodejs) - "setup_${setup_type}_nodejs" "$local_flag" "$parallels_per_platform" "$NOW_RUN_LOG_FILE" - log_section "✅ Results" - identify_run_status_nodejs "$NOW_RUN_LOG_FILE" - check_return_value $? "$NOW_RUN_LOG_FILE" "${setup_type} setup succeeded." "❌ ${setup_type} setup failed. Check $log_file for details" - ;; - *) - log_warn "Unknown TECH_STACK: $tech_stack" "$NOW_RUN_LOG_FILE" - return 1 - ;; - esac -} - -setup_web_java() { - local local_flag=$1 - local parallels=$2 - - REPO="now-testng-browserstack" - TARGET_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/$REPO" - - mkdir -p "$WORKSPACE_DIR/$PROJECT_FOLDER" - - clone_repository "$REPO" "$TARGET_DIR" - - cd "$TARGET_DIR"|| return 1 - - log_info "Target website: $CX_TEST_URL" - - if is_domain_private; then - local_flag=true - fi - - report_bstack_local_status "$local_flag" - - # === 5️⃣ YAML Setup === - log_msg_to "🧩 Generating YAML config (bstack.yml)" - - - # YAML config path - export BROWSERSTACK_CONFIG_FILE="./browserstack.yml" - platform_yaml=$(generate_web_platforms "$TEAM_PARALLELS_MAX_ALLOWED_WEB", "yaml") - - cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - log_success "Dependencies installed" - - - log_section "Validate Environment Variables" - log_info "BrowserStack Username: $BROWSERSTACK_USERNAME" - log_info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" - log_info "Web Application Endpoint: $CX_TEST_URL" - log_info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" - log_info "Parallels per platform: $BSTACK_PARALLELS" - log_info "Platforms: \n$BSTACK_PLATFORMS" - - - print_tests_running_log_section "mvn test -P sample-test" - log_msg_to "🚀 Running 'mvn test -P sample-test'. This could take a few minutes. Follow the Automaton build here: https://automation.browserstack.com/" - mvn test -P sample-test >> "$NOW_RUN_LOG_FILE" 2>&1 & - cmd_pid=$!|| return 1 - - show_spinner "$cmd_pid" - wait "$cmd_pid" - - cd "$WORKSPACE_DIR/$PROJECT_FOLDER" || return 1 - return 0 -} - -setup_app_java() { - local local_flag=$1 - local parallels=$2 - local log_file=$3 - - REPO="now-testng-appium-app-browserstack" - TARGET_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/$REPO" - local app_url=$BROWSERSTACK_APP - log_msg_to "APP_PLATFORM: $APP_PLATFORM" >> "$NOW_RUN_LOG_FILE" 2>&1 - - clone_repository "$REPO" "$TARGET_DIR" - - if [[ "$APP_PLATFORM" == "all" || "$APP_PLATFORM" == "android" ]]; then - cd "android/testng-examples" || return 1 - else - cd ios/testng-examples || return 1 - fi - - - # YAML config path - export BROWSERSTACK_CONFIG_FILE="./browserstack.yml" - platform_yaml=$(generate_mobile_platforms "$TEAM_PARALLELS_MAX_ALLOWED_MOBILE" "yaml") - - cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1; then - log_msg_to "❌ 'mvn clean' FAILED. See $log_file for details." - return 1 # Fail the function if clean fails - fi - log_success "Dependencies installed" - - log_section "Validate Environment Variables" - log_info "BrowserStack Username: $BROWSERSTACK_USERNAME" - log_info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" - log_info "Native App Endpoint: $BROWSERSTACK_APP" - log_info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" - log_info "Parallels per platform: $BSTACK_PARALLELS" - log_info "Platforms: \n$BSTACK_PLATFORMS" - - log_msg_to "🚀 Running 'mvn test -P sample-test'. This could take a few minutes. Follow the Automaton build here: https://automation.browserstack.com/" - print_tests_running_log_section "mvn test -P sample-test" - mvn test -P sample-test >> "$NOW_RUN_LOG_FILE" 2>&1 & - cmd_pid=$!|| return 1 - - show_spinner "$cmd_pid" - wait "$cmd_pid" - - cd "$WORKSPACE_DIR/$PROJECT_FOLDER" || return 1 - return 0 -} - -setup_web_python() { - local local_flag=$1 - local parallels=$2 - local log_file=$3 - - REPO="now-pytest-browserstack" - TARGET_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/$REPO" - - clone_repository "$REPO" "$TARGET_DIR" "" - - # detect_setup_python_env - - pip3 install --only-binary grpcio -r requirements.txt >> "$NOW_RUN_LOG_FILE" 2>&1 - pip3 uninstall -y pytest-html pytest-rerunfailures >> "$NOW_RUN_LOG_FILE" 2>&1 - log_success "Dependencies installed" - - # Update YAML at root level (browserstack.yml) - export BROWSERSTACK_CONFIG_FILE="./browserstack.yml" - platform_yaml=$(generate_web_platforms "$TEAM_PARALLELS_MAX_ALLOWED_WEB" "yaml") - export BSTACK_PLATFORMS=$platform_yaml - cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 & cmd_pid=$!|| return 1 - show_spinner "$cmd_pid" - wait "$cmd_pid" - - cd "$WORKSPACE_DIR/$PROJECT_FOLDER" || return 1 - return 0 -} - -setup_app_python() { - local local_flag=$1 - local parallels=$2 - local log_file=$3 - - REPO="now-pytest-appium-app-browserstack" - TARGET_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/$REPO" - - clone_repository "$REPO" "$TARGET_DIR" - - # detect_setup_python_env - - # Install dependencies - pip install --only-binary grpcio -r requirements.txt >> "$NOW_RUN_LOG_FILE" 2>&1 - log_success "Dependencies installed" - - local app_url=$BROWSERSTACK_APP - local platform_yaml - - export BSTACK_PARALLELS=1 - - # Decide which directory to run based on APP_PLATFORM (default to android) - local run_dir="android" - if [ "$APP_PLATFORM" = "ios" ]; then - run_dir="ios" - fi - - export BROWSERSTACK_CONFIG_FILE="./$run_dir/browserstack.yml" - platform_yaml=$(generate_mobile_platforms "$TEAM_PARALLELS_MAX_ALLOWED_MOBILE" "yaml") - - cat >> "$BROWSERSTACK_CONFIG_FILE" <> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 & cmd_pid=$!|| return 1 - show_spinner "$cmd_pid" - wait "$cmd_pid" - ) - - deactivate - cd "$WORKSPACE_DIR/$PROJECT_FOLDER" || return 1 - return 0 -} - -setup_web_nodejs() { - local local_flag=$1 - local parallels=$2 - - REPO="now-webdriverio-browserstack" - TARGET_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/$REPO" - mkdir -p "$WORKSPACE_DIR/$PROJECT_FOLDER" - - clone_repository "$REPO" "$TARGET_DIR" - - - # === 2️⃣ Install Dependencies === - log_msg_to "⚙️ Running 'npm install'" - log_info "Installing dependencies" - npm install >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - log_success "Dependencies installed" - - local caps_json="" - # === 4️⃣ Generate Capabilities JSON === - caps_json=$(generate_web_platforms "$parallels" "json") - export BSTACK_CAPS_JSON=$caps_json - export BSTACK_PARALLELS=$parallels - - if is_domain_private; then - local_flag=true - fi - - export BROWSERSTACK_LOCAL=$local_flag - export BROWSERSTACK_BUILD_NAME="now-$NOW_OS-web-nodejs-wdio" - export BROWSERSTACK_PROJECT_NAME="now-$NOW_OS-web" - - report_bstack_local_status "$local_flag" - - log_section "Validate Environment Variables" - log_info "BrowserStack Username: $BROWSERSTACK_USERNAME" - log_info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" - log_info "Web Application Endpoint: $CX_TEST_URL" - log_info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" - log_info "Parallels per platform: $BSTACK_PARALLELS" - log_info "Platforms: \n$BSTACK_CAPS_JSON" - - # === 8️⃣ Run Tests === - log_msg_to "🚀 Running 'npm run test'. This could take a few minutes. Follow the Automaton build here: https://automation.browserstack.com/" - print_tests_running_log_section "npm run test" - npm run test >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 & - cmd_pid=$!|| return 1 - - show_spinner "$cmd_pid" - wait "$cmd_pid" - - cd "$WORKSPACE_DIR/$PROJECT_FOLDER" || return 1 - return 0 -} - -setup_app_nodejs() { - local local_flag=$1 - local parallels=$2 - local log_file=$3 - local caps_json="" - - log_msg_to "Starting Mobile NodeJS setup with parallels: $parallels" >> "$NOW_RUN_LOG_FILE" 2>&1 - mkdir -p "$WORKSPACE_DIR/$PROJECT_FOLDER" - REPO="now-webdriverio-appium-app-browserstack" - TARGET_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/$REPO" - TEST_FOLDER="/test" - - clone_repository $REPO "$TARGET_DIR" "$TEST_FOLDER" - - # === 2️⃣ Install Dependencies === - log_info "Installing dependencies" - log_msg_to "⚙️ Running 'npm install'" - npm install >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - log_success "Dependencies installed" - - caps_json=$(generate_mobile_platforms "$TEAM_PARALLELS_MAX_ALLOWED_MOBILE" "json") - - - export BSTACK_CAPS_JSON=$caps_json - - local app_url=$BROWSERSTACK_APP - - export BSTACK_PARALLELS=$parallels - export BROWSERSTACK_LOCAL=true - export BROWSERSTACK_APP=$app_url - export BROWSERSTACK_BUILD_NAME="now-$NOW_OS-app-nodejs-wdio" - export BROWSERSTACK_PROJECT_NAME="now-$NOW_OS-app" - - log_section "Validate Environment Variables" - log_info "BrowserStack Username: $BROWSERSTACK_USERNAME" - log_info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" - log_info "Native App Endpoint: $BROWSERSTACK_APP" - log_info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" - log_info "Parallels per platform: $BSTACK_PARALLELS" - log_info "Platforms: \n$BSTACK_CAPS_JSON" - - # === 8️⃣ Run Tests === - log_msg_to "🚀 Running 'npm run test'. This could take a few minutes. Follow the Automaton build here: https://automation.browserstack.com/" - print_tests_running_log_section "npm run test" - npm run test >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 & - cmd_pid=$!|| return 1 - - show_spinner "$cmd_pid" - wait "$cmd_pid" - - # === 9️⃣ Wrap Up === - log_msg_to "✅ Mobile JS setup and test execution completed successfully." - - cd "$WORKSPACE_DIR/$PROJECT_FOLDER" || return 1 - return 0 -} - -clone_repository() { - local repo_git=$1 - local install_folder=$2 - local test_folder=$3 - local git_branch=$4 - - rm -rf "$install_folder" - log_msg_to "📦 Cloning repo $repo_git into $install_folder" - log_info "Cloning repository: $repo_git" - # git clone https://github.com/BrowserStackCE/"$repo_git".git "$install_folder" >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - if [ -z "$git_branch" ]; then - # git_branch is null or empty - git clone "https://github.com/BrowserStackCE/$repo_git.git" \ - "$install_folder" >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - else - # git_branch has a value - git clone -b "$git_branch" "https://github.com/BrowserStackCE/$repo_git.git" \ - "$install_folder" >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - fi - log_msg_to "✅ Cloned repository: $repo_git into $install_folder" - cd "$install_folder/$test_folder" || return 1 -} - -# ===== Orchestration: decide what to run based on TEST_TYPE and plan fetch ===== -run_setup_wrapper() { - local test_type=$1 - local tech_stack=$2 - log_msg_to "Orchestration: TEST_TYPE=$test_type, WEB_PLAN_FETCHED=$WEB_PLAN_FETCHED, MOBILE_PLAN_FETCHED=$MOBILE_PLAN_FETCHED" - - case "$test_type" in - Web) - if [ "$WEB_PLAN_FETCHED" == true ]; then - run_setup "$test_type" "$tech_stack" - else - log_msg_to "⚠️ Skipping Web setup — Web plan not fetched" - fi - ;; - App) - if [ "$MOBILE_PLAN_FETCHED" == true ]; then - run_setup "$test_type" "$tech_stack" - else - log_msg_to "⚠️ Skipping Mobile setup — Mobile plan not fetched" - fi - ;; - *) - log_msg_to "❌ Invalid TEST_TYPE: $test_type" - exit 1 - ;; - esac -} - -check_return_value() { - local return_value=$1 - local log_file=$2 - local success_message=$3 - local failure_message=$4 - - if [ "$return_value" -eq 0 ]; then - log_success "$success_message" "$NOW_RUN_LOG_FILE" - exit 0 - else - log_error "$failure_message" "$NOW_RUN_LOG_FILE" - exit 1 - fi -} - - -report_bstack_local_status() { - if [ "$local_flag" = "true" ]; then - log_msg_to "✅ BrowserStack Local is ENABLED for this run." - log_success "Target website is behind firewall. BrowserStack Local enabled for this run." - else - log_msg_to "✅ BrowserStack Local is DISABLED for this run." - log_success "Target website is publicly resolvable. BrowserStack Local disabled for this run." - fi -} - -print_tests_running_log_section() { - log_section "🚀 Running Tests: $1" - log_info "Executing: Test run command. This could take a few minutes..." - log_info "You can monitor test progress here: 🔗 https://automation.browserstack.com/" -} - - -detect_setup_python_env() { - log_info "Detecting latest Python environment" - - latest_python=$( - { ls -1 /usr/local/bin/python3.[0-9]* /usr/bin/python3.[0-9]* 2>/dev/null || true; } \ - | grep -E 'python3\.[0-9]+$' \ - | sort -V \ - | tail -n 1 - ) - - if [[ -z "$latest_python" ]]; then - log_warn "No specific Python3.x version found. Falling back to system python3." - latest_python=$(command -v python3) - fi - - if [[ -z "$latest_python" ]]; then - log_error "Python3 not found on this system." - exit 1 - fi - - echo "🐍 Switching to: $latest_python" - log_info "Using Python interpreter: $latest_python" - - "$latest_python" -m venv .venv || { - log_error "Failed to create virtual environment." - exit 1 - } - - # Activate virtual environment (handle Windows/Unix paths) - if [ -f ".venv/Scripts/activate" ]; then - # shellcheck source=/dev/null - source .venv/Scripts/activate - else - # shellcheck source=/dev/null - source .venv/bin/activate - fi - log_success "Virtual environment created and activated." -} \ No newline at end of file diff --git a/mac/run.sh b/mac/run.sh index a6a9c9b..a84c146 100755 --- a/mac/run.sh +++ b/mac/run.sh @@ -1,78 +1,2 @@ #!/bin/bash -set -o pipefail - -# Import utilities -# shellcheck source=/dev/null -source "$(dirname "$0")/common-utils.sh" -# shellcheck source=/dev/null -source "$(dirname "$0")/logging-utils.sh" -# shellcheck source=/dev/null -source "$(dirname "$0")/env-setup-run.sh" -# shellcheck source=/dev/null -source "$(dirname "$0")/user-interaction.sh" -# shellcheck source=/dev/null -source "$(dirname "$0")/env-prequisite-checks.sh" - -# ===== Web wrapper with retry logic (writes runtime logs to $NOW_RUN_LOG_FILE) ===== -# Wrapper functions using the common setup_environment function -run_setup() { - local test_type=$1 - local tech_stack=$2 - setup_environment "$test_type" "$tech_stack" -} - -# ===== Main flow (baseline steps then run) ===== - -RUN_MODE=$1 # --interactive or --silent / --debug -TT=$2 # Testing Type from env (for silent mode) -TSTACK=$3 # Tech Stack from env (for silent mode) - -log_section "🧭 Setup Summary – BrowserStack NOW" -log_info "Timestamp: $(date '+%Y-%m-%d %H:%M:%S')" - - -log_file="" -if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then - TEST_TYPE=$TT - TECH_STACK=$TSTACK - log_file="$LOG_DIR/${TEST_TYPE:unknown}_${TECH_STACK:unknown}_run_result.log" - log_info "Run Mode: ${RUN_MODE:-default}" -else - get_test_type "$RUN_MODE" - get_tech_stack "$RUN_MODE" - log_file="$LOG_DIR/${TEST_TYPE:unknown}_${TECH_STACK:unknown}_run_result.log" - perform_next_steps_based_on_test_type "$TEST_TYPE" -fi - -log_info "Log file path: $log_file" -export NOW_RUN_LOG_FILE="$log_file" -setup_workspace -get_browserstack_credentials "$RUN_MODE" - -log_section "⚙️ Platform & Tech Stack" -log_info "Platform: ${TEST_TYPE:-N/A}" -log_info "Tech Stack: ${TECH_STACK:-N/A}" - -validate_tech_stack_installed "$TECH_STACK" -fetch_plan_details "$TEST_TYPE" - -if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then - if [[ $TEST_TYPE == "app" ]]; then - get_upload_app - log_success "Sample App uploaded successfully" - fi -fi - -log_msg_to "Plan summary: WEB_PLAN_FETCHED=$WEB_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_WEB), MOBILE_PLAN_FETCHED=$MOBILE_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" -log_msg_to "Checking proxy in environment" -set_proxy_in_env - -log_section "🧹 Getting Ready" -detect_os -log_info "Detected Operating system: $NOW_OS" -log_info "Clearing old logs fron NOW Home Directory inside .browserstack" - -clear_old_logs - -log_info "Starting $TEST_TYPE setup for $TECH_STACK" -run_setup "$TEST_TYPE" "$TECH_STACK" +exec "$(dirname "$0")/../common/mac/run.sh" "$@" diff --git a/win/common-utils.ps1 b/win/common-utils.ps1 deleted file mode 100644 index 105bc69..0000000 --- a/win/common-utils.ps1 +++ /dev/null @@ -1,358 +0,0 @@ -# Common helpers shared by the Windows BrowserStack NOW scripts. - -# ===== Global Variables ===== -$script:WORKSPACE_DIR = Join-Path $env:USERPROFILE ".browserstack" -$script:PROJECT_FOLDER = "NOW" - -$script:GLOBAL_DIR = Join-Path $WORKSPACE_DIR $PROJECT_FOLDER -$script:LOG_DIR = Join-Path $GLOBAL_DIR "logs" -$script:GLOBAL_LOG = "" -$script:WEB_LOG = "" -$script:MOBILE_LOG = "" - -# Script state -$script:BROWSERSTACK_USERNAME = "" -$script:BROWSERSTACK_ACCESS_KEY = "" -$script:TEST_TYPE = "" # Web / App -$script:TECH_STACK = "" # Java / Python / JS -[double]$script:PARALLEL_PERCENTAGE = 1.00 - -$script:WEB_PLAN_FETCHED = $false -$script:MOBILE_PLAN_FETCHED = $false -[int]$script:TEAM_PARALLELS_MAX_ALLOWED_WEB = 0 -[int]$script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = 0 - -# URL handling -$script:DEFAULT_TEST_URL = "https://bstackdemo.com" -$script:CX_TEST_URL = $DEFAULT_TEST_URL - -# App handling -$script:APP_URL = "" -$script:APP_PLATFORM = "" # ios | android | all - -# Chosen Python command tokens (set during validation when Python is selected) -$script:PY_CMD = @() - -# ===== Error patterns ===== -$script:WEB_SETUP_ERRORS = @("") -$script:WEB_LOCAL_ERRORS = @("") -$script:MOBILE_SETUP_ERRORS= @("") -$script:MOBILE_LOCAL_ERRORS= @("") - -# ===== Workspace Management ===== -function Ensure-Workspace { - if (!(Test-Path $GLOBAL_DIR)) { - New-Item -ItemType Directory -Path $GLOBAL_DIR | Out-Null - Log-Line "✅ Created Onboarding workspace: $GLOBAL_DIR" $GLOBAL_LOG - } else { - Log-Line "✅ Onboarding workspace found at: $GLOBAL_DIR" $GLOBAL_LOG - } -} - -function Setup-Workspace { - Log-Section "⚙️ Environment & Credentials" $GLOBAL_LOG - Ensure-Workspace -} - -function Clear-OldLogs { - if (!(Test-Path $LOG_DIR)) { - New-Item -ItemType Directory -Path $LOG_DIR | Out-Null - } - - $legacyLogs = @("global.log","web_run_result.log","mobile_run_result.log") - foreach ($legacy in $legacyLogs) { - $legacyPath = Join-Path $LOG_DIR $legacy - if (Test-Path $legacyPath) { - Remove-Item -Path $legacyPath -Force -ErrorAction SilentlyContinue - } - } - - Log-Line "✅ Logs directory cleaned. Legacy files removed." $GLOBAL_LOG -} - -# ===== Git Clone ===== -function Invoke-GitClone { - param( - [Parameter(Mandatory)] [string]$Url, - [Parameter(Mandatory)] [string]$Target, - [string]$Branch, - [string]$LogFile - ) - $args = @("clone") - if ($Branch) { $args += @("-b", $Branch) } - $args += @($Url, $Target) - - $psi = New-Object System.Diagnostics.ProcessStartInfo - $psi.FileName = "git" - $psi.Arguments = ($args | ForEach-Object { - if ($_ -match '\s') { '"{0}"' -f $_ } else { $_ } - }) -join ' ' - $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $true - $psi.UseShellExecute = $false - $psi.CreateNoWindow = $true - $psi.WorkingDirectory = (Get-Location).Path - - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $psi - [void]$p.Start() - $stdout = $p.StandardOutput.ReadToEnd() - $stderr = $p.StandardError.ReadToEnd() - $p.WaitForExit() - - if ($LogFile) { - if ($stdout) { Add-Content -Path $LogFile -Value $stdout } - if ($stderr) { Add-Content -Path $LogFile -Value $stderr } - } - - if ($p.ExitCode -ne 0) { - throw "git clone failed (exit $($p.ExitCode)): $stderr" - } -} - -function Set-ContentNoBom { - param( - [Parameter(Mandatory)][string]$Path, - [Parameter(Mandatory)][string]$Value - ) - $enc = New-Object System.Text.UTF8Encoding($false) # no BOM - [System.IO.File]::WriteAllText($Path, $Value, $enc) -} - -function Invoke-External { - param( - [Parameter(Mandatory)][string]$Exe, - [Parameter()][string[]]$Arguments = @(), - [string]$LogFile, - [string]$WorkingDirectory - ) - $psi = New-Object System.Diagnostics.ProcessStartInfo - $exeToRun = $Exe - $argLine = ($Arguments | ForEach-Object { if ($_ -match '\s') { '"{0}"' -f $_ } else { $_ } }) -join ' ' - - $ext = [System.IO.Path]::GetExtension($Exe) - if ($ext -and ($ext.ToLowerInvariant() -in @('.cmd','.bat'))) { - if (-not (Test-Path $Exe)) { throw "Command not found: $Exe" } - $psi.FileName = "cmd.exe" - $psi.Arguments = "/c `"$Exe`" $argLine" - } else { - $psi.FileName = $exeToRun - $psi.Arguments = $argLine - } - - $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $true - $psi.UseShellExecute = $false - $psi.CreateNoWindow = $true - if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) { - $psi.WorkingDirectory = (Get-Location).Path - } else { - $psi.WorkingDirectory = $WorkingDirectory - } - - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $psi - - if ($LogFile) { - $logDir = Split-Path -Parent $LogFile - if ($logDir -and !(Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir | Out-Null } - - $stdoutAction = { - if (-not [string]::IsNullOrEmpty($EventArgs.Data)) { - Add-Content -Path $Event.MessageData -Value $EventArgs.Data - } - } - $stderrAction = { - if (-not [string]::IsNullOrEmpty($EventArgs.Data)) { - Add-Content -Path $Event.MessageData -Value $EventArgs.Data - } - } - - $stdoutEvent = Register-ObjectEvent -InputObject $p -EventName OutputDataReceived -Action $stdoutAction -MessageData $LogFile - $stderrEvent = Register-ObjectEvent -InputObject $p -EventName ErrorDataReceived -Action $stderrAction -MessageData $LogFile - - [void]$p.Start() - $p.BeginOutputReadLine() - $p.BeginErrorReadLine() - $p.WaitForExit() - - Unregister-Event -SourceIdentifier $stdoutEvent.Name - Unregister-Event -SourceIdentifier $stderrEvent.Name - Remove-Job -Id $stdoutEvent.Id -Force - Remove-Job -Id $stderrEvent.Id -Force - } else { - [void]$p.Start() - $stdout = $p.StandardOutput.ReadToEnd() - $stderr = $p.StandardError.ReadToEnd() - $p.WaitForExit() - } - - return $p.ExitCode -} - -function Get-MavenCommand { - param([Parameter(Mandatory)][string]$RepoDir) - $mvnCmd = Get-Command mvn -ErrorAction SilentlyContinue - if ($mvnCmd) { return $mvnCmd.Source } - $wrapper = Join-Path $RepoDir "mvnw.cmd" - if (Test-Path $wrapper) { return $wrapper } - throw "Maven not found in PATH and 'mvnw.cmd' not present under $RepoDir. Install Maven or ensure the wrapper exists." -} - -function Get-VenvPython { - param([Parameter(Mandatory)][string]$VenvDir) - $py = Join-Path $VenvDir "Scripts\python.exe" - if (Test-Path $py) { return $py } - throw "Python interpreter not found in venv: $VenvDir" -} - -function Set-PythonCmd { - $candidates = @( - @("python3"), - @("python"), - @("py","-3"), - @("py") - ) - foreach ($cand in $candidates) { - try { - $exe = $cand[0] - $args = @() - if ($cand.Length -gt 1) { $args = $cand[1..($cand.Length-1)] } - $code = Invoke-External -Exe $exe -Arguments ($args + @("--version")) -LogFile $null - if ($code -eq 0) { - $script:PY_CMD = $cand - return - } - } catch {} - } - throw "Python not found via python3/python/py. Please install Python 3 and ensure it's on PATH." -} - -function Invoke-Py { - param( - [Parameter(Mandatory)][string[]]$Arguments, - [string]$LogFile, - [string]$WorkingDirectory - ) - if (-not $PY_CMD -or $PY_CMD.Count -eq 0) { Set-PythonCmd } - $exe = $PY_CMD[0] - $baseArgs = @() - if ($PY_CMD.Count -gt 1) { $baseArgs = $PY_CMD[1..($PY_CMD.Count-1)] } - return (Invoke-External -Exe $exe -Arguments ($baseArgs + $Arguments) -LogFile $LogFile -WorkingDirectory $WorkingDirectory) -} - -function Show-Spinner { - param([Parameter(Mandatory)][System.Diagnostics.Process]$Process) - $spin = @('|','/','-','\') - $i = 0 - $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") - while (!$Process.HasExited) { - Write-Host "`r[$ts] ⏳ Processing... $($spin[$i])" -NoNewline - $i = ($i + 1) % 4 - Start-Sleep -Milliseconds 100 - } - Write-Host "`r[$ts] ✅ Done! " -} - -function Test-PrivateIP { - param([string]$IP) - if ([string]::IsNullOrWhiteSpace($IP)) { return $false } - $parts = $IP.Split('.') - if ($parts.Count -ne 4) { return $false } - $first = [int]$parts[0] - $second = [int]$parts[1] - if ($first -eq 10) { return $true } - if ($first -eq 192 -and $second -eq 168) { return $true } - if ($first -eq 172 -and $second -ge 16 -and $second -le 31) { return $true } - return $false -} - -function Test-DomainPrivate { - $domain = $CX_TEST_URL -replace '^https?://', '' -replace '/.*$', '' - Log-Line "Website domain: $domain" $GLOBAL_LOG - $env:NOW_WEB_DOMAIN = $CX_TEST_URL - - $IP_ADDRESS = "" - try { - $dnsResult = Resolve-DnsName -Name $domain -Type A -ErrorAction Stop | Where-Object { $_.Type -eq 'A' } | Select-Object -First 1 - if ($dnsResult) { - $IP_ADDRESS = $dnsResult.IPAddress - } - } catch { - try { - $nslookupOutput = nslookup $domain 2>&1 | Out-String - if ($nslookupOutput -match '(?:Address|Addresses):\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') { - $IP_ADDRESS = $matches[1] - } - } catch { - Log-Line "⚠️ Failed to resolve domain: $domain (assuming public domain)" $GLOBAL_LOG - $IP_ADDRESS = "" - } - } - - if ([string]::IsNullOrWhiteSpace($IP_ADDRESS)) { - Log-Line "⚠️ DNS resolution failed for: $domain (treating as public domain, BrowserStack Local will be DISABLED)" $GLOBAL_LOG - } else { - Log-Line "✅ Resolved IP: $IP_ADDRESS" $GLOBAL_LOG - } - - return (Test-PrivateIP -IP $IP_ADDRESS) -} - -function Get-BasicAuthHeader { - param([string]$User, [string]$Key) - $pair = "{0}:{1}" -f $User,$Key - $bytes = [System.Text.Encoding]::UTF8.GetBytes($pair) - "Basic {0}" -f [System.Convert]::ToBase64String($bytes) -} - -# ===== Fetch plan details ===== -function Fetch-Plan-Details { - param([string]$TestType) - - if ([string]::IsNullOrWhiteSpace($TestType)) { - throw "Test type is required to fetch plan details." - } - - $normalized = $TestType.ToLowerInvariant() - Log-Line "ℹ️ Fetching BrowserStack plan for $normalized" $GLOBAL_LOG - - $auth = Get-BasicAuthHeader -User $BROWSERSTACK_USERNAME -Key $BROWSERSTACK_ACCESS_KEY - $headers = @{ Authorization = $auth } - - switch ($normalized) { - "web" { - try { - $resp = Invoke-RestMethod -Method Get -Uri "https://api.browserstack.com/automate/plan.json" -Headers $headers - $script:WEB_PLAN_FETCHED = $true - $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = [int]$resp.parallel_sessions_max_allowed - Log-Line "✅ Web Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_WEB" $GLOBAL_LOG - } catch { - Log-Line "❌ Web Testing Plan fetch failed ($($_.Exception.Message))" $GLOBAL_LOG - } - if (-not $WEB_PLAN_FETCHED) { - throw "Unable to fetch Web Testing plan details." - } - } - "app" { - try { - $resp2 = Invoke-RestMethod -Method Get -Uri "https://api-cloud.browserstack.com/app-automate/plan.json" -Headers $headers - $script:MOBILE_PLAN_FETCHED = $true - $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = [int]$resp2.parallel_sessions_max_allowed - Log-Line "✅ Mobile App Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_MOBILE" $GLOBAL_LOG - } catch { - Log-Line "❌ Mobile App Testing Plan fetch failed ($($_.Exception.Message))" $GLOBAL_LOG - } - if (-not $MOBILE_PLAN_FETCHED) { - throw "Unable to fetch Mobile App Testing plan details." - } - } - default { - throw "Unsupported TEST_TYPE: $TestType. Allowed values: Web, App." - } - } - - Log-Line "ℹ️ Plan summary: Web fetched=$WEB_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_WEB), Mobile fetched=$MOBILE_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" $GLOBAL_LOG -} - - diff --git a/win/device-machine-allocation.ps1 b/win/device-machine-allocation.ps1 deleted file mode 100644 index 35c7a08..0000000 --- a/win/device-machine-allocation.ps1 +++ /dev/null @@ -1,285 +0,0 @@ -# Device and platform allocation utilities for the Windows BrowserStack NOW flow. -# Mirrors the macOS shell script structure so we can share logic between both platforms. - -# ===== Example Platform Templates ===== -$WEB_PLATFORM_TEMPLATES = @( - "Windows|10|Chrome", - "Windows|10|Firefox", - "Windows|11|Edge", - "Windows|11|Chrome", - "Windows|8|Chrome", - "OS X|Monterey|Chrome", - "OS X|Ventura|Chrome", - "OS X|Catalina|Firefox" -) - -# Mobile tiers (kept for parity) -$MOBILE_TIER1 = @( - "ios|iPhone 15|17", - "ios|iPhone 15 Pro|17", - "ios|iPhone 16|18", - "android|Samsung Galaxy S25|15", - "android|Samsung Galaxy S24|14" -) -$MOBILE_TIER2 = @( - "ios|iPhone 14 Pro|16", - "ios|iPhone 14|16", - "ios|iPad Air 13 2025|18", - "android|Samsung Galaxy S23|13", - "android|Samsung Galaxy S22|12", - "android|Samsung Galaxy S21|11", - "android|Samsung Galaxy Tab S10 Plus|15" -) -$MOBILE_TIER3 = @( - "ios|iPhone 13 Pro Max|15", - "ios|iPhone 13|15", - "ios|iPhone 12 Pro|14", - "ios|iPhone 12 Pro|17", - "ios|iPhone 12|17", - "ios|iPhone 12|14", - "ios|iPhone 12 Pro Max|16", - "ios|iPhone 13 Pro|15", - "ios|iPhone 13 Mini|15", - "ios|iPhone 16 Pro|18", - "ios|iPad 9th|15", - "ios|iPad Pro 12.9 2020|14", - "ios|iPad Pro 12.9 2020|16", - "ios|iPad 8th|16", - "android|Samsung Galaxy S22 Ultra|12", - "android|Samsung Galaxy S21|12", - "android|Samsung Galaxy S21 Ultra|11", - "android|Samsung Galaxy S20|10", - "android|Samsung Galaxy M32|11", - "android|Samsung Galaxy Note 20|10", - "android|Samsung Galaxy S10|9", - "android|Samsung Galaxy Note 9|8", - "android|Samsung Galaxy Tab S8|12", - "android|Google Pixel 9|15", - "android|Google Pixel 6 Pro|13", - "android|Google Pixel 8|14", - "android|Google Pixel 7|13", - "android|Google Pixel 6|12", - "android|Vivo Y21|11", - "android|Vivo Y50|10", - "android|Oppo Reno 6|11" -) -$MOBILE_TIER4 = @( - "ios|iPhone 15 Pro Max|17", - "ios|iPhone 15 Pro Max|26", - "ios|iPhone 15|26", - "ios|iPhone 15 Plus|17", - "ios|iPhone 14 Pro|26", - "ios|iPhone 14|18", - "ios|iPhone 14|26", - "ios|iPhone 13 Pro Max|18", - "ios|iPhone 13|16", - "ios|iPhone 13|17", - "ios|iPhone 13|18", - "ios|iPhone 12 Pro|18", - "ios|iPhone 14 Pro Max|16", - "ios|iPhone 14 Plus|16", - "ios|iPhone 11|13", - "ios|iPhone 8|11", - "ios|iPhone 7|10", - "ios|iPhone 17 Pro Max|26", - "ios|iPhone 17 Pro|26", - "ios|iPhone 17 Air|26", - "ios|iPhone 17|26", - "ios|iPhone 16e|18", - "ios|iPhone 16 Pro Max|18", - "ios|iPhone 16 Plus|18", - "ios|iPhone SE 2020|16", - "ios|iPhone SE 2022|15", - "ios|iPad Air 4|14", - "ios|iPad 9th|18", - "ios|iPad Air 5|26", - "ios|iPad Pro 11 2021|18", - "ios|iPad Pro 13 2024|17", - "ios|iPad Pro 12.9 2021|14", - "ios|iPad Pro 12.9 2021|17", - "ios|iPad Pro 11 2024|17", - "ios|iPad Air 6|17", - "ios|iPad Pro 12.9 2022|16", - "ios|iPad Pro 11 2022|16", - "ios|iPad 10th|16", - "ios|iPad Air 13 2025|26", - "ios|iPad Pro 11 2020|13", - "ios|iPad Pro 11 2020|16", - "ios|iPad 8th|14", - "ios|iPad Mini 2021|15", - "ios|iPad Pro 12.9 2018|12", - "ios|iPad 6th|11", - "android|Samsung Galaxy S23 Ultra|13", - "android|Samsung Galaxy S22 Plus|12", - "android|Samsung Galaxy S21 Plus|11", - "android|Samsung Galaxy S20 Ultra|10", - "android|Samsung Galaxy S25 Ultra|15", - "android|Samsung Galaxy S24 Ultra|14", - "android|Samsung Galaxy M52|11", - "android|Samsung Galaxy A52|11", - "android|Samsung Galaxy A51|10", - "android|Samsung Galaxy A11|10", - "android|Samsung Galaxy A10|9", - "android|Samsung Galaxy Tab A9 Plus|14", - "android|Samsung Galaxy Tab S9|13", - "android|Samsung Galaxy Tab S7|10", - "android|Samsung Galaxy Tab S7|11", - "android|Samsung Galaxy Tab S6|9", - "android|Google Pixel 9|16", - "android|Google Pixel 10 Pro XL|16", - "android|Google Pixel 10 Pro|16", - "android|Google Pixel 10|16", - "android|Google Pixel 9 Pro XL|15", - "android|Google Pixel 9 Pro|15", - "android|Google Pixel 6 Pro|12", - "android|Google Pixel 6 Pro|15", - "android|Google Pixel 8 Pro|14", - "android|Google Pixel 7 Pro|13", - "android|Google Pixel 5|11", - "android|OnePlus 13R|15", - "android|OnePlus 12R|14", - "android|OnePlus 11R|13", - "android|OnePlus 9|11", - "android|OnePlus 8|10", - "android|Motorola Moto G71 5G|11", - "android|Motorola Moto G9 Play|10", - "android|Vivo V21|11", - "android|Oppo A96|11", - "android|Oppo Reno 3 Pro|10", - "android|Xiaomi Redmi Note 11|11", - "android|Xiaomi Redmi Note 9|10", - "android|Huawei P30|9" -) - -# MOBILE_ALL combines the tiers -$MOBILE_ALL = @() -$MOBILE_ALL += $MOBILE_TIER1 -$MOBILE_ALL += $MOBILE_TIER2 -$MOBILE_ALL += $MOBILE_TIER3 -$MOBILE_ALL += $MOBILE_TIER4 - -# ===== Generators ===== -function Generate-Web-Platforms-Yaml { - param([int]$MaxTotalParallels) - $max = [Math]::Floor($MaxTotalParallels * $PARALLEL_PERCENTAGE) - if ($max -lt 0) { $max = 0 } - $sb = New-Object System.Text.StringBuilder - $count = 0 - - foreach ($t in $WEB_PLATFORM_TEMPLATES) { - $parts = $t.Split('|') - $os = $parts[0]; $osVersion = $parts[1]; $browserName = $parts[2] - foreach ($version in @('latest','latest-1','latest-2')) { - [void]$sb.AppendLine(" - os: $os") - [void]$sb.AppendLine(" osVersion: $osVersion") - [void]$sb.AppendLine(" browserName: $browserName") - [void]$sb.AppendLine(" browserVersion: $version") - $count++ - if ($count -ge $max -and $max -gt 0) { - return $sb.ToString() - } - } - } - return $sb.ToString() -} - -function Generate-Mobile-Platforms-Yaml { - param([int]$MaxTotalParallels) - $max = [Math]::Floor($MaxTotalParallels * $PARALLEL_PERCENTAGE) - if ($max -lt 1) { $max = 1 } - $sb = New-Object System.Text.StringBuilder - $count = 0 - - foreach ($t in $MOBILE_ALL) { - $parts = $t.Split('|') - $platformName = $parts[0] - $deviceName = $parts[1] - $platformVer = $parts[2] - - if (-not [string]::IsNullOrWhiteSpace($APP_PLATFORM)) { - if ($APP_PLATFORM -eq 'ios' -and $platformName -ne 'ios') { continue } - if ($APP_PLATFORM -eq 'android' -and $platformName -ne 'android') { continue } - } - - [void]$sb.AppendLine(" - platformName: $platformName") - [void]$sb.AppendLine(" deviceName: $deviceName") - [void]$sb.AppendLine(" platformVersion: '${platformVer}.0'") - $count++ - if ($count -ge $max) { return $sb.ToString() } - } - return $sb.ToString() -} - -function Generate-Mobile-Caps-Json { - param([int]$MaxTotalParallels, [string]$OutputFile) - $json = Generate-Mobile-Caps-Json-String -MaxTotalParallels $MaxTotalParallels - Set-ContentNoBom -Path $OutputFile -Value $json - return $json -} - -function Generate-Mobile-Caps-Json-String { - param([int]$MaxTotalParallels) - $max = $MaxTotalParallels - if ($max -lt 1) { $max = 1 } - - $items = @() - $count = 0 - - foreach ($t in $MOBILE_ALL) { - $parts = $t.Split('|') - $platformName = $parts[0] - $deviceName = $parts[1] - $platformVer = $parts[2] - - # Filter based on APP_PLATFORM - if (-not [string]::IsNullOrWhiteSpace($APP_PLATFORM)) { - if ($APP_PLATFORM -eq 'ios' -and $platformName -ne 'ios') { continue } - if ($APP_PLATFORM -eq 'android' -and $platformName -ne 'android') { continue } - } - - $items += [pscustomobject]@{ - 'bstack:options' = @{ - deviceName = $deviceName - osVersion = "${platformVer}.0" - } - } - $count++ - if ($count -ge $max) { break } - } - - $json = ($items | ConvertTo-Json -Depth 5 -Compress) - return $json -} - -function Generate-Web-Caps-Json { - param([int]$MaxTotalParallels) - $max = [Math]::Floor($MaxTotalParallels * $PARALLEL_PERCENTAGE) - if ($max -lt 1) { $max = 1 } - - $items = @() - $count = 0 - foreach ($t in $WEB_PLATFORM_TEMPLATES) { - $parts = $t.Split('|') - $os = $parts[0]; $osVersion = $parts[1]; $browserName = $parts[2] - foreach ($version in @('latest','latest-1','latest-2')) { - $items += [pscustomobject]@{ - browserName = $browserName - browserVersion = $version - 'bstack:options' = @{ - os = $os - osVersion = $osVersion - } - } - $count++ - if ($count -ge $max) { break } - } - if ($count -ge $max) { break } - } - - # Return valid JSON array (keep the brackets!) - $json = ($items | ConvertTo-Json -Depth 5 -Compress) - return $json -} - - - diff --git a/win/env-prequisite-checks.ps1 b/win/env-prequisite-checks.ps1 deleted file mode 100644 index e384d55..0000000 --- a/win/env-prequisite-checks.ps1 +++ /dev/null @@ -1,148 +0,0 @@ -# Environment prerequisite checks (proxy + tech stack validation). - -$PROXY_TEST_URL = "https://www.browserstack.com/automate/browsers.json" - -function Parse-ProxyUrl { - param([string]$ProxyUrl) - if ([string]::IsNullOrWhiteSpace($ProxyUrl)) { - return $null - } - - $cleaned = $ProxyUrl -replace '^https?://', '' - if ($cleaned -match '@') { - $cleaned = $cleaned.Substring($cleaned.IndexOf('@') + 1) - } - - if ($cleaned -match '^([^:]+):(\d+)') { - return @{ - Host = $matches[1] - Port = $matches[2] - } - } elseif ($cleaned -match '^([^:]+)') { - return @{ - Host = $matches[1] - Port = "8080" - } - } - return $null -} - -function Set-ProxyInEnv { - param( - [string]$Username, - [string]$AccessKey - ) - - Log-Section "🌐 Network & Proxy Validation" $GLOBAL_LOG - - $proxy = $env:http_proxy - if ([string]::IsNullOrWhiteSpace($proxy)) { $proxy = $env:HTTP_PROXY } - if ([string]::IsNullOrWhiteSpace($proxy)) { $proxy = $env:https_proxy } - if ([string]::IsNullOrWhiteSpace($proxy)) { $proxy = $env:HTTPS_PROXY } - - $env:PROXY_HOST = "" - $env:PROXY_PORT = "" - - if ([string]::IsNullOrWhiteSpace($proxy)) { - Log-Line "No proxy found in environment. Using direct connection." $GLOBAL_LOG - return - } - - Log-Line "Proxy detected: $proxy" $GLOBAL_LOG - $proxyInfo = Parse-ProxyUrl -ProxyUrl $proxy - if (-not $proxyInfo) { - Log-Line "❌ Failed to parse proxy URL: $proxy" $GLOBAL_LOG - return - } - - $pair = if ($Username -and $AccessKey) { "$Username`:$AccessKey" } else { "" } - $base64Creds = "" - if ($pair) { - $base64Creds = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($pair)) - } - - try { - $proxyUri = "http://$($proxyInfo.Host):$($proxyInfo.Port)" - $webProxy = New-Object System.Net.WebProxy($proxyUri) - $webClient = New-Object System.Net.WebClient - $webClient.Proxy = $webProxy - if ($base64Creds) { - $webClient.Headers.Add("Authorization", "Basic $base64Creds") - } - - $null = $webClient.DownloadString($PROXY_TEST_URL) - - Log-Line "✅ Reachable via proxy. HTTP 200" $GLOBAL_LOG - Log-Line "Exporting PROXY_HOST=$($proxyInfo.Host)" $GLOBAL_LOG - Log-Line "Exporting PROXY_PORT=$($proxyInfo.Port)" $GLOBAL_LOG - $env:PROXY_HOST = $proxyInfo.Host - $env:PROXY_PORT = $proxyInfo.Port - } catch { - $statusMsg = $_.Exception.Message - Log-Line "❌ Not reachable via proxy. Error: $statusMsg" $GLOBAL_LOG - $env:PROXY_HOST = "" - $env:PROXY_PORT = "" - } -} - -function Validate-Tech-Stack { - Log-Line "ℹ️ Checking prerequisites for $script:TECH_STACK" $GLOBAL_LOG - switch ($script:TECH_STACK) { - "Java" { - if (-not (Get-Command java -ErrorAction SilentlyContinue)) { - Log-Line "❌ Java command not found in PATH." $GLOBAL_LOG - throw "Java not found" - } - $verInfo = & cmd /c 'java -version 2>&1' - if (-not $verInfo) { - Log-Line "❌ Java exists but failed to run." $GLOBAL_LOG - throw "Java invocation failed" - } - Log-Line "✅ Java is installed. Version details:" $GLOBAL_LOG - ($verInfo -split "`r?`n") | ForEach-Object { if ($_ -ne "") { Log-Line " $_" $GLOBAL_LOG } } - } - "Python" { - try { - Set-PythonCmd - $code = Invoke-Py -Arguments @("--version") -LogFile $null -WorkingDirectory (Get-Location).Path - if ($code -eq 0) { - Log-Line ("✅ Python3 is installed: {0}" -f ( ($PY_CMD -join ' ') )) $GLOBAL_LOG - } else { - throw "Python present but failed to execute" - } - } catch { - Log-Line "❌ Python3 exists but failed to run." $GLOBAL_LOG - throw - } - } - "NodeJS" { - if (-not (Get-Command node -ErrorAction SilentlyContinue)) { - Log-Line "❌ Node.js command not found in PATH." $GLOBAL_LOG - throw "Node not found" - } - if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { - Log-Line "❌ npm command not found in PATH." $GLOBAL_LOG - throw "npm not found" - } - $nodeVer = & node -v 2>&1 - if (-not $nodeVer) { - Log-Line "❌ Node.js exists but failed to run." $GLOBAL_LOG - throw "Node.js invocation failed" - } - $npmVer = & npm -v 2>&1 - if (-not $npmVer) { - Log-Line "❌ npm exists but failed to run." $GLOBAL_LOG - throw "npm invocation failed" - } - Log-Line "✅ Node.js is installed: $nodeVer" $GLOBAL_LOG - Log-Line "✅ npm is installed: $npmVer" $GLOBAL_LOG - } - default { - Log-Line "❌ Unknown TECH_STACK: $script:TECH_STACK" $GLOBAL_LOG - throw "Unknown tech stack" - } - } -} - - - diff --git a/win/env-setup-run.ps1 b/win/env-setup-run.ps1 deleted file mode 100644 index 982bd1b..0000000 --- a/win/env-setup-run.ps1 +++ /dev/null @@ -1,589 +0,0 @@ -# Environment Setup and Run functions for Windows BrowserStack NOW. -# Mirrors the Mac env-setup-run.sh structure. - -# ===== Setup: Web (Java) ===== -function Setup-Web-Java { - param([bool]$UseLocal, [int]$ParallelsPerPlatform, [string]$LogFile) - - $REPO = "now-testng-browserstack" - $TARGET = Join-Path $GLOBAL_DIR $REPO - - New-Item -ItemType Directory -Path $GLOBAL_DIR -Force | Out-Null - if (Test-Path $TARGET) { - Remove-Item -Path $TARGET -Recurse -Force - } - - Log-Line "ℹ️ Cloning repository: $REPO" $GLOBAL_LOG - Invoke-GitClone -Url "https://github.com/BrowserStackCE/$REPO.git" -Target $TARGET -LogFile (Get-RunLogFile) - - Push-Location $TARGET - try { - Log-Line "ℹ️ Target website: $CX_TEST_URL" $GLOBAL_LOG - - if (Test-DomainPrivate) { - $UseLocal = $true - } - - Report-BStackLocalStatus -LocalFlag $UseLocal - - Log-Line "🧩 Generating YAML config (browserstack.yml)" $GLOBAL_LOG - $platforms = Generate-Web-Platforms-Yaml -MaxTotalParallels $ParallelsPerPlatform - $localFlag = if ($UseLocal) { "true" } else { "false" } - - $yamlContent = @" -userName: $BROWSERSTACK_USERNAME -accessKey: $BROWSERSTACK_ACCESS_KEY -framework: testng -browserstackLocal: $localFlag -buildName: now-windows-web-java-testng -projectName: NOW-Web-Test -percy: true -accessibility: true -platforms: -$platforms -parallelsPerPlatform: $ParallelsPerPlatform -"@ - - Set-Content "browserstack.yml" -Value $yamlContent - Log-Line "✅ Created browserstack.yml in root directory" $GLOBAL_LOG - - # Validate Environment Variables - Log-Section "Validate Environment Variables" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Username: $BROWSERSTACK_USERNAME" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Build: now-windows-web-java-testng" $GLOBAL_LOG - Log-Line "ℹ️ Web Application Endpoint: $CX_TEST_URL" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Local Flag: $localFlag" $GLOBAL_LOG - Log-Line "ℹ️ Parallels per platform: $ParallelsPerPlatform" $GLOBAL_LOG - Log-Line "ℹ️ Platforms:" $GLOBAL_LOG - $platforms -split "`n" | ForEach-Object { if ($_.Trim()) { Log-Line " $_" $GLOBAL_LOG } } - - $mvn = Get-MavenCommand -RepoDir $TARGET - Log-Line "⚙️ Running '$mvn install -DskipTests'" $GLOBAL_LOG - Log-Line "ℹ️ Installing dependencies" $GLOBAL_LOG - [void](Invoke-External -Exe $mvn -Arguments @("install","-DskipTests") -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "✅ Dependencies installed" $GLOBAL_LOG - - Print-TestsRunningSection -Command "mvn test -P sample-test" - [void](Invoke-External -Exe $mvn -Arguments @("test","-P","sample-test") -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "ℹ️ Run Test command completed." $GLOBAL_LOG - - } finally { - Pop-Location - Set-Location (Join-Path $WORKSPACE_DIR $PROJECT_FOLDER) - } -} - -# ===== Setup: Web (Python) ===== -function Setup-Web-Python { - param([bool]$UseLocal, [int]$ParallelsPerPlatform, [string]$LogFile) - - $REPO = "now-pytest-browserstack" - $TARGET = Join-Path $GLOBAL_DIR $REPO - - New-Item -ItemType Directory -Path $GLOBAL_DIR -Force | Out-Null - if (Test-Path $TARGET) { - Remove-Item -Path $TARGET -Recurse -Force - } - - Log-Line "ℹ️ Cloning repository: $REPO" $GLOBAL_LOG - Invoke-GitClone -Url "https://github.com/BrowserStackCE/$REPO.git" -Target $TARGET -LogFile (Get-RunLogFile) - - Push-Location $TARGET - try { - if (-not $PY_CMD -or $PY_CMD.Count -eq 0) { Set-PythonCmd } - $venv = Join-Path $TARGET "venv" - if (!(Test-Path $venv)) { - [void](Invoke-Py -Arguments @("-m","venv",$venv) -LogFile $LogFile -WorkingDirectory $TARGET) - } - $venvPy = Get-VenvPython -VenvDir $venv - - Log-Line "ℹ️ Installing dependencies" $GLOBAL_LOG - [void](Invoke-External -Exe $venvPy -Arguments @("-m","pip","install","-r","requirements.txt") -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "✅ Dependencies installed" $GLOBAL_LOG - - $env:PATH = (Join-Path $venv 'Scripts') + ";" + $env:PATH - $env:BROWSERSTACK_USERNAME = $BROWSERSTACK_USERNAME - $env:BROWSERSTACK_ACCESS_KEY = $BROWSERSTACK_ACCESS_KEY - - if (Test-DomainPrivate) { - $UseLocal = $true - } - - Report-BStackLocalStatus -LocalFlag $UseLocal - - $env:BROWSERSTACK_CONFIG_FILE = "browserstack.yml" - $platforms = Generate-Web-Platforms-Yaml -MaxTotalParallels $ParallelsPerPlatform - $localFlag = if ($UseLocal) { "true" } else { "false" } - -@" -userName: $BROWSERSTACK_USERNAME -accessKey: $BROWSERSTACK_ACCESS_KEY -framework: pytest -browserstackLocal: $localFlag -buildName: now-windows-web-python-pytest -projectName: NOW-Web-Test -percy: true -accessibility: true -platforms: -$platforms -parallelsPerPlatform: $ParallelsPerPlatform -"@ | Set-Content "browserstack.yml" - - Log-Line "✅ Updated browserstack.yml with platforms and credentials" $GLOBAL_LOG - - # Validate Environment Variables - Log-Section "Validate Environment Variables" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Username: $BROWSERSTACK_USERNAME" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Build: now-windows-web-python-pytest" $GLOBAL_LOG - Log-Line "ℹ️ Web Application Endpoint: $CX_TEST_URL" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Local Flag: $localFlag" $GLOBAL_LOG - Log-Line "ℹ️ Parallels per platform: $ParallelsPerPlatform" $GLOBAL_LOG - Log-Line "ℹ️ Platforms:" $GLOBAL_LOG - $platforms -split "`n" | ForEach-Object { if ($_.Trim()) { Log-Line " $_" $GLOBAL_LOG } } - - $sdk = Join-Path $venv "Scripts\browserstack-sdk.exe" - Print-TestsRunningSection -Command "browserstack-sdk pytest -s tests/bstack-sample-test.py" - [void](Invoke-External -Exe $sdk -Arguments @('pytest','-s','tests/bstack-sample-test.py') -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "ℹ️ Run Test command completed." $GLOBAL_LOG - - } finally { - Pop-Location - Set-Location (Join-Path $WORKSPACE_DIR $PROJECT_FOLDER) - } -} - -# ===== Setup: Web (NodeJS) ===== -function Setup-Web-NodeJS { - param([bool]$UseLocal, [int]$ParallelsPerPlatform, [string]$LogFile) - - $REPO = "now-webdriverio-browserstack" - $TARGET = Join-Path $GLOBAL_DIR $REPO - - if (Test-Path $TARGET) { - Remove-Item -Path $TARGET -Recurse -Force - } - New-Item -ItemType Directory -Path $GLOBAL_DIR -Force | Out-Null - - Log-Line "ℹ️ Cloning repository: $REPO" $GLOBAL_LOG - Invoke-GitClone -Url "https://github.com/BrowserStackCE/$REPO.git" -Target $TARGET -LogFile (Get-RunLogFile) - - Push-Location $TARGET - try { - Log-Line "⚙️ Running 'npm install'" $GLOBAL_LOG - Log-Line "ℹ️ Installing dependencies" $GLOBAL_LOG - [void](Invoke-External -Exe "cmd.exe" -Arguments @("/c","npm","install") -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "✅ Dependencies installed" $GLOBAL_LOG - - $caps = Generate-Web-Caps-Json -MaxTotalParallels $ParallelsPerPlatform - $env:BSTACK_PARALLELS = $ParallelsPerPlatform - $env:BSTACK_CAPS_JSON = $caps - - if (Test-DomainPrivate) { - $UseLocal = $true - } - - Report-BStackLocalStatus -LocalFlag $UseLocal - - $env:BROWSERSTACK_USERNAME = $BROWSERSTACK_USERNAME - $env:BROWSERSTACK_ACCESS_KEY = $BROWSERSTACK_ACCESS_KEY - $localFlagStr = if ($UseLocal) { "true" } else { "false" } - $env:BROWSERSTACK_LOCAL = $localFlagStr - $env:BROWSERSTACK_BUILD_NAME = "now-windows-web-nodejs-wdio" - $env:BROWSERSTACK_PROJECT_NAME = "NOW-Web-Test" - - # Validate Environment Variables - Log-Section "Validate Environment Variables" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Username: $BROWSERSTACK_USERNAME" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Build: $($env:BROWSERSTACK_BUILD_NAME)" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Project: $($env:BROWSERSTACK_PROJECT_NAME)" $GLOBAL_LOG - Log-Line "ℹ️ Web Application Endpoint: $CX_TEST_URL" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Local Flag: $localFlagStr" $GLOBAL_LOG - Log-Line "ℹ️ Parallels per platform: $ParallelsPerPlatform" $GLOBAL_LOG - Log-Line "ℹ️ Platforms:" $GLOBAL_LOG - Log-Line " $caps" $GLOBAL_LOG - - Print-TestsRunningSection -Command "npm run test" - [void](Invoke-External -Exe "cmd.exe" -Arguments @("/c","npm","run","test") -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "ℹ️ Run Test command completed." $GLOBAL_LOG - - } finally { - Pop-Location - Set-Location (Join-Path $WORKSPACE_DIR $PROJECT_FOLDER) - } -} - -# ===== Setup: Mobile (Java) ===== -function Setup-Mobile-Java { - param([bool]$UseLocal, [int]$ParallelsPerPlatform, [string]$LogFile) - - $REPO = "now-testng-appium-app-browserstack" - $TARGET = Join-Path $GLOBAL_DIR $REPO - - New-Item -ItemType Directory -Path $GLOBAL_DIR -Force | Out-Null - if (Test-Path $TARGET) { - Remove-Item -Path $TARGET -Recurse -Force - } - - Log-Line "ℹ️ Cloning repository: $REPO" $GLOBAL_LOG - Invoke-GitClone -Url "https://github.com/BrowserStackCE/$REPO.git" -Target $TARGET -LogFile (Get-RunLogFile) - - Push-Location $TARGET - try { - if ($APP_PLATFORM -eq "all" -or $APP_PLATFORM -eq "android") { - Set-Location "android\testng-examples" - } else { - Set-Location "ios\testng-examples" - } - - $env:BROWSERSTACK_USERNAME = $BROWSERSTACK_USERNAME - $env:BROWSERSTACK_ACCESS_KEY = $BROWSERSTACK_ACCESS_KEY - $env:BROWSERSTACK_CONFIG_FILE = ".\browserstack.yml" - - $platforms = Generate-Mobile-Platforms-Yaml -MaxTotalParallels $ParallelsPerPlatform - $localFlag = if ($UseLocal) { "true" } else { "false" } - - # Write complete browserstack.yml (not just append) - $yamlContent = @" -userName: $BROWSERSTACK_USERNAME -accessKey: $BROWSERSTACK_ACCESS_KEY -framework: testng -browserstackLocal: $localFlag -buildName: now-windows-app-java-testng -projectName: NOW-Mobile-Test -parallelsPerPlatform: $ParallelsPerPlatform -app: $APP_URL -platforms: -$platforms -"@ - $yamlContent | Set-Content -Path $env:BROWSERSTACK_CONFIG_FILE -Encoding UTF8 - - Report-BStackLocalStatus -LocalFlag $UseLocal - - # Validate Environment Variables - Log-Section "Validate Environment Variables" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Username: $BROWSERSTACK_USERNAME" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Build: now-windows-app-java-testng" $GLOBAL_LOG - Log-Line "ℹ️ Native App Endpoint: $APP_URL" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Local Flag: $localFlag" $GLOBAL_LOG - Log-Line "ℹ️ Parallels per platform: $ParallelsPerPlatform" $GLOBAL_LOG - Log-Line "ℹ️ Platforms:" $GLOBAL_LOG - $platforms -split "`n" | ForEach-Object { if ($_.Trim()) { Log-Line " $_" $GLOBAL_LOG } } - - $mvn = Get-MavenCommand -RepoDir (Get-Location).Path - Log-Line "⚙️ Running '$mvn clean'" $GLOBAL_LOG - Log-Line "ℹ️ Installing dependencies" $GLOBAL_LOG - $cleanExit = Invoke-External -Exe $mvn -Arguments @("clean") -LogFile $LogFile -WorkingDirectory (Get-Location).Path - if ($cleanExit -ne 0) { - Log-Line "❌ 'mvn clean' FAILED. See $LogFile for details." $GLOBAL_LOG - throw "Maven clean failed" - } - Log-Line "✅ Dependencies installed" $GLOBAL_LOG - - Print-TestsRunningSection -Command "mvn test -P sample-test" - [void](Invoke-External -Exe $mvn -Arguments @("test","-P","sample-test") -LogFile $LogFile -WorkingDirectory (Get-Location).Path) - Log-Line "ℹ️ Run Test command completed." $GLOBAL_LOG - - } finally { - Pop-Location - Set-Location (Join-Path $WORKSPACE_DIR $PROJECT_FOLDER) - } -} - -# ===== Setup: Mobile (Python) ===== -function Setup-Mobile-Python { - param([bool]$UseLocal, [int]$ParallelsPerPlatform, [string]$LogFile) - - $REPO = "now-pytest-appium-app-browserstack" - $TARGET = Join-Path $GLOBAL_DIR $REPO - - New-Item -ItemType Directory -Path $GLOBAL_DIR -Force | Out-Null - if (Test-Path $TARGET) { - Remove-Item -Path $TARGET -Recurse -Force - } - - Log-Line "ℹ️ Cloning repository: $REPO" $GLOBAL_LOG - Invoke-GitClone -Url "https://github.com/BrowserStackCE/$REPO.git" -Target $TARGET -LogFile (Get-RunLogFile) - - Push-Location $TARGET - try { - if (-not $PY_CMD -or $PY_CMD.Count -eq 0) { Set-PythonCmd } - $venv = Join-Path $TARGET "venv" - if (!(Test-Path $venv)) { - [void](Invoke-Py -Arguments @("-m","venv",$venv) -LogFile $LogFile -WorkingDirectory $TARGET) - } - $venvPy = Get-VenvPython -VenvDir $venv - - Log-Line "ℹ️ Installing dependencies" $GLOBAL_LOG - [void](Invoke-External -Exe $venvPy -Arguments @("-m","pip","install","-r","requirements.txt") -LogFile $LogFile -WorkingDirectory $TARGET) - Log-Line "✅ Dependencies installed" $GLOBAL_LOG - - $env:PATH = (Join-Path $venv 'Scripts') + ";" + $env:PATH - $env:BROWSERSTACK_USERNAME = $BROWSERSTACK_USERNAME - $env:BROWSERSTACK_ACCESS_KEY = $BROWSERSTACK_ACCESS_KEY - $env:BROWSERSTACK_APP = $APP_URL - - $originalPlatform = $APP_PLATFORM - $localFlag = if ($UseLocal) { "true" } else { "false" } - - # Generate platform YAMLs - $script:APP_PLATFORM = "android" - $platformYamlAndroid = Generate-Mobile-Platforms-Yaml -MaxTotalParallels $ParallelsPerPlatform - $androidYmlPath = Join-Path $TARGET "android\browserstack.yml" -@" -userName: $BROWSERSTACK_USERNAME -accessKey: $BROWSERSTACK_ACCESS_KEY -framework: pytest -browserstackLocal: $localFlag -buildName: now-windows-app-python-pytest -projectName: NOW-Mobile-Test -parallelsPerPlatform: $ParallelsPerPlatform -app: $APP_URL -platforms: -$platformYamlAndroid -"@ | Set-Content $androidYmlPath - - $script:APP_PLATFORM = "ios" - $platformYamlIos = Generate-Mobile-Platforms-Yaml -MaxTotalParallels $ParallelsPerPlatform - $iosYmlPath = Join-Path $TARGET "ios\browserstack.yml" -@" -userName: $BROWSERSTACK_USERNAME -accessKey: $BROWSERSTACK_ACCESS_KEY -framework: pytest -browserstackLocal: $localFlag -buildName: now-windows-app-python-pytest -projectName: NOW-Mobile-Test -parallelsPerPlatform: $ParallelsPerPlatform -app: $APP_URL -platforms: -$platformYamlIos -"@ | Set-Content $iosYmlPath - - $script:APP_PLATFORM = $originalPlatform - Log-Line "✅ Wrote platform YAMLs" $GLOBAL_LOG - - $runDirName = if ($APP_PLATFORM -eq "ios") { "ios" } else { "android" } - $runDir = Join-Path $TARGET $runDirName - $platformYaml = if ($runDirName -eq "ios") { $platformYamlIos } else { $platformYamlAndroid } - - Report-BStackLocalStatus -LocalFlag $UseLocal - - # Validate Environment Variables - Log-Section "Validate Environment Variables" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Username: $BROWSERSTACK_USERNAME" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Build: now-windows-app-python-pytest" $GLOBAL_LOG - Log-Line "ℹ️ Native App Endpoint: $APP_URL" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Local Flag: $localFlag" $GLOBAL_LOG - Log-Line "ℹ️ Parallels per platform: $ParallelsPerPlatform" $GLOBAL_LOG - Log-Line "ℹ️ Platforms:" $GLOBAL_LOG - $platformYaml -split "`n" | ForEach-Object { if ($_.Trim()) { Log-Line " $_" $GLOBAL_LOG } } - - $sdk = Join-Path $venv "Scripts\browserstack-sdk.exe" - Print-TestsRunningSection -Command "cd $runDirName && browserstack-sdk pytest -s bstack_sample.py" - - Push-Location $runDir - try { - [void](Invoke-External -Exe $sdk -Arguments @('pytest','-s','bstack_sample.py') -LogFile $LogFile -WorkingDirectory (Get-Location).Path) - } finally { - Pop-Location - } - Log-Line "ℹ️ Run Test command completed." $GLOBAL_LOG - - } finally { - Pop-Location - Set-Location (Join-Path $WORKSPACE_DIR $PROJECT_FOLDER) - } -} - -# ===== Setup: Mobile (NodeJS) ===== -function Setup-Mobile-NodeJS { - param([bool]$UseLocal, [int]$ParallelsPerPlatform, [string]$LogFile) - - $REPO = "now-webdriverio-appium-app-browserstack" - $TARGET = Join-Path $GLOBAL_DIR $REPO - - New-Item -ItemType Directory -Path $GLOBAL_DIR -Force | Out-Null - if (Test-Path $TARGET) { - Remove-Item -Path $TARGET -Recurse -Force - } - - Log-Line "ℹ️ Cloning repository: $REPO" $GLOBAL_LOG - Invoke-GitClone -Url "https://github.com/BrowserStackCE/$REPO.git" -Target $TARGET -LogFile (Get-RunLogFile) - - $testDir = Join-Path $TARGET "test" - Push-Location $testDir - try { - Log-Line "⚙️ Running 'npm install'" $GLOBAL_LOG - Log-Line "ℹ️ Installing dependencies" $GLOBAL_LOG - [void](Invoke-External -Exe "cmd.exe" -Arguments @("/c","npm","install") -LogFile $LogFile -WorkingDirectory $testDir) - Log-Line "✅ Dependencies installed" $GLOBAL_LOG - - # Generate capabilities JSON and set as environment variable (like Mac) - $capsJson = Generate-Mobile-Caps-Json-String -MaxTotalParallels $ParallelsPerPlatform - - $env:BROWSERSTACK_USERNAME = $BROWSERSTACK_USERNAME - $env:BROWSERSTACK_ACCESS_KEY = $BROWSERSTACK_ACCESS_KEY - $env:BSTACK_PARALLELS = $ParallelsPerPlatform - $env:BSTACK_CAPS_JSON = $capsJson - $env:BROWSERSTACK_APP = $APP_URL - $env:BROWSERSTACK_BUILD_NAME = "now-windows-app-nodejs-wdio" - $env:BROWSERSTACK_PROJECT_NAME = "NOW-Mobile-Test" - $env:BROWSERSTACK_LOCAL = "true" - - # Validate Environment Variables - Log-Section "Validate Environment Variables" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Username: $BROWSERSTACK_USERNAME" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Build: $($env:BROWSERSTACK_BUILD_NAME)" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Project: $($env:BROWSERSTACK_PROJECT_NAME)" $GLOBAL_LOG - Log-Line "ℹ️ Native App Endpoint: $APP_URL" $GLOBAL_LOG - Log-Line "ℹ️ BrowserStack Local Flag: $($env:BROWSERSTACK_LOCAL)" $GLOBAL_LOG - Log-Line "ℹ️ Parallels per platform: $ParallelsPerPlatform" $GLOBAL_LOG - Log-Line "ℹ️ Platforms: $capsJson" $GLOBAL_LOG - - Print-TestsRunningSection -Command "npm run test" - [void](Invoke-External -Exe "cmd.exe" -Arguments @("/c","npm","run","test") -LogFile $LogFile -WorkingDirectory $testDir) - Log-Line "ℹ️ Run Test command completed." $GLOBAL_LOG - - } finally { - Pop-Location - Set-Location (Join-Path $WORKSPACE_DIR $PROJECT_FOLDER) - } -} - -# ===== Helper Functions ===== -function Report-BStackLocalStatus { - param([bool]$LocalFlag) - if ($LocalFlag) { - Log-Line "✅ Target website is behind firewall. BrowserStack Local enabled for this run." $GLOBAL_LOG - } else { - Log-Line "✅ Target website is publicly resolvable. BrowserStack Local disabled for this run." $GLOBAL_LOG - } -} - -function Print-TestsRunningSection { - param([string]$Command) - Log-Section "🚀 Running Tests: $Command" $GLOBAL_LOG - Log-Line "ℹ️ Executing: Test run command. This could take a few minutes..." $GLOBAL_LOG - Log-Line "ℹ️ You can monitor test progress here: 🔗 https://automation.browserstack.com/" $GLOBAL_LOG -} - -function Identify-RunStatus-Java { - param([string]$LogFile) - if (!(Test-Path $LogFile)) { return $false } - $content = Get-Content $LogFile -Raw - $match = [regex]::Match($content, 'Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+),\s*Skipped:\s*(\d+)') - if (-not $match.Success) { return $false } - $passed = [int]$match.Groups[1].Value - ([int]$match.Groups[2].Value + [int]$match.Groups[3].Value + [int]$match.Groups[4].Value) - if ($passed -gt 0) { - Log-Line "✅ Success: $passed test(s) passed." $GLOBAL_LOG - return $true - } - return $false -} - -function Identify-RunStatus-Python { - param([string]$LogFile) - if (!(Test-Path $LogFile)) { return $false } - $content = Get-Content $LogFile -Raw - $matches = [regex]::Matches($content, '(\d+)\s+passed') - $passedSum = 0 - foreach ($m in $matches) { $passedSum += [int]$m.Groups[1].Value } - if ($passedSum -gt 0) { - Log-Line "✅ Success: $passedSum test(s) passed." $GLOBAL_LOG - return $true - } - return $false -} - -function Identify-RunStatus-NodeJS { - param([string]$LogFile) - if (!(Test-Path $LogFile)) { return $false } - $content = Get-Content $LogFile -Raw - $match = [regex]::Match($content, '(\d+)\s+pass') - if ($match.Success -and [int]$match.Groups[1].Value -gt 0) { - Log-Line "✅ Success: $($match.Groups[1].Value) test(s) passed." $GLOBAL_LOG - return $true - } - return $false -} - -# ===== Setup Environment Wrapper ===== -function Setup-Environment { - param( - [Parameter(Mandatory)][string]$SetupType, - [Parameter(Mandatory)][string]$TechStack, - [string]$RunMode = "--interactive" - ) - - Log-Section "📦 Project Setup" $GLOBAL_LOG - - $maxParallels = if ($SetupType -match "web") { $TEAM_PARALLELS_MAX_ALLOWED_WEB } else { $TEAM_PARALLELS_MAX_ALLOWED_MOBILE } - Log-Line "Team max parallels: $maxParallels" $GLOBAL_LOG - - $localFlag = $false - $totalParallels = [int]([Math]::Floor($maxParallels * $PARALLEL_PERCENTAGE)) - if ($totalParallels -lt 1) { $totalParallels = 1 } - - if ($RunMode -match "--silent" -and $totalParallels -gt 5) { - $originalParallels = $totalParallels - $totalParallels = 5 - Log-Line "ℹ️ Silent mode: capping parallels per platform to $totalParallels (requested $originalParallels)" $GLOBAL_LOG - } - - Log-Line "Total parallels allocated: $totalParallels" $GLOBAL_LOG - - $success = $false - $logFile = Get-RunLogFile - - switch ($TechStack) { - "Java" { - if ($SetupType -match "web") { - Setup-Web-Java -UseLocal:$localFlag -ParallelsPerPlatform $totalParallels -LogFile $logFile - $success = Identify-RunStatus-Java -LogFile $logFile - } else { - Setup-Mobile-Java -UseLocal:$localFlag -ParallelsPerPlatform $totalParallels -LogFile $logFile - $success = Identify-RunStatus-Java -LogFile $logFile - } - } - "Python" { - if ($SetupType -match "web") { - Setup-Web-Python -UseLocal:$localFlag -ParallelsPerPlatform $totalParallels -LogFile $logFile - $success = Identify-RunStatus-Python -LogFile $logFile - } else { - Setup-Mobile-Python -UseLocal:$localFlag -ParallelsPerPlatform $totalParallels -LogFile $logFile - $success = Identify-RunStatus-Python -LogFile $logFile - } - } - "NodeJS" { - if ($SetupType -match "web") { - Setup-Web-NodeJS -UseLocal:$localFlag -ParallelsPerPlatform $totalParallels -LogFile $logFile - $success = Identify-RunStatus-NodeJS -LogFile $logFile - } else { - Setup-Mobile-NodeJS -UseLocal:$localFlag -ParallelsPerPlatform $totalParallels -LogFile $logFile - $success = Identify-RunStatus-NodeJS -LogFile $logFile - } - } - default { - Log-Line "⚠️ Unknown TECH_STACK: $TechStack" $GLOBAL_LOG - return - } - } - - Log-Section "✅ Results" $GLOBAL_LOG - if ($success) { - Log-Line "✅ $SetupType setup succeeded." $GLOBAL_LOG - } else { - Log-Line "❌ $SetupType setup ended. Check $logFile for details." $GLOBAL_LOG - } -} - -# ===== Run Setup Wrapper (like Mac's run_setup) ===== -function Run-Setup { - param( - [string]$TestType, - [string]$TechStack, - [string]$RunMode = "--interactive" - ) - Setup-Environment -SetupType $TestType -TechStack $TechStack -RunMode $RunMode -} - - diff --git a/win/logging-utils.ps1 b/win/logging-utils.ps1 deleted file mode 100644 index 68da254..0000000 --- a/win/logging-utils.ps1 +++ /dev/null @@ -1,56 +0,0 @@ -# Logging helpers shared across the Windows BrowserStack NOW scripts. - -if (-not (Get-Variable -Name NOW_RUN_LOG_FILE -Scope Script -ErrorAction SilentlyContinue)) { - $script:NOW_RUN_LOG_FILE = "" -} - -function Set-RunLogFile { - param([string]$Path) - $script:NOW_RUN_LOG_FILE = $Path - if ($Path) { - $env:NOW_RUN_LOG_FILE = $Path - } else { - Remove-Item Env:NOW_RUN_LOG_FILE -ErrorAction SilentlyContinue - } -} - -function Get-RunLogFile { - return $script:NOW_RUN_LOG_FILE -} - -function Log-Line { - param( - [Parameter(Mandatory=$true)][AllowEmptyString()][string]$Message, - [string]$DestFile - ) - if (-not $DestFile) { - $DestFile = Get-RunLogFile - } - - $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") - $line = "[$ts] $Message" - Write-Host $line - if ($DestFile) { - $dir = Split-Path -Parent $DestFile - if ($dir -and !(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null } - Add-Content -Path $DestFile -Value $line - } -} - -function Log-Section { - param( - [Parameter(Mandatory)][AllowEmptyString()][string]$Title, - [string]$DestFile - ) - $divider = "───────────────────────────────────────────────" - Log-Line "" $DestFile - Log-Line $divider $DestFile - Log-Line ("{0}" -f $Title) $DestFile - Log-Line $divider $DestFile -} - -function Log-Info { param([string]$Message,[string]$DestFile) Log-Line ("ℹ️ $Message") $DestFile } -function Log-Success { param([string]$Message,[string]$DestFile) Log-Line ("✅ $Message") $DestFile } -function Log-Warn { param([string]$Message,[string]$DestFile) Log-Line ("⚠️ $Message") $DestFile } -function Log-Error { param([string]$Message,[string]$DestFile) Log-Line ("❌ $Message") $DestFile } - diff --git a/win/run.ps1 b/win/run.ps1 index 8003d2b..9949c90 100644 --- a/win/run.ps1 +++ b/win/run.ps1 @@ -1,11 +1,4 @@ #requires -version 5.0 -<# - BrowserStack Onboarding (PowerShell 5.0, GUI) - - Full parity port of macOS bash run.sh - - Uses WinForms for GUI prompts - - Logs to %USERPROFILE%\.browserstack\NOW\logs -#> - param( [string]$RunMode = "--interactive", [string]$TT, @@ -15,103 +8,18 @@ param( [string]$AppPlatform ) -Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' -Add-Type -AssemblyName System.Windows.Forms -Add-Type -AssemblyName System.Drawing - -# ===== Import utilities (like Mac's source commands) ===== -$script:PSScriptRootResolved = Split-Path -Parent $MyInvocation.MyCommand.Path -. (Join-Path $PSScriptRootResolved "logging-utils.ps1") -. (Join-Path $PSScriptRootResolved "common-utils.ps1") -. (Join-Path $PSScriptRootResolved "device-machine-allocation.ps1") -. (Join-Path $PSScriptRootResolved "user-interaction.ps1") -. (Join-Path $PSScriptRootResolved "env-prequisite-checks.ps1") -. (Join-Path $PSScriptRootResolved "env-setup-run.ps1") - -# ===== Main flow (baseline steps then run) ===== -try { - # Get test type and tech stack before logging - if ($RunMode -match "--silent|--debug") { - $textInfo = (Get-Culture).TextInfo - $ttCandidate = if ($TT) { $TT } else { $env:TEST_TYPE } - if ([string]::IsNullOrWhiteSpace($ttCandidate)) { throw "TEST_TYPE is required in silent/debug mode." } - $tsCandidate = if ($TSTACK) { $TSTACK } else { $env:TECH_STACK } - if ([string]::IsNullOrWhiteSpace($tsCandidate)) { throw "TECH_STACK is required in silent/debug mode." } - $script:TEST_TYPE = $textInfo.ToTitleCase($ttCandidate.ToLowerInvariant()) - $script:TECH_STACK = $textInfo.ToTitleCase($tsCandidate.ToLowerInvariant()) - if ($TEST_TYPE -notin @("Web","App")) { throw "TEST_TYPE must be either 'Web' or 'App'." } - if ($TECH_STACK -notin @("Java","Python","NodeJS")) { throw "TECH_STACK must be one of: Java, Python, NodeJS." } - } else { - Resolve-Test-Type -RunMode $RunMode -CliValue $TT - Resolve-Tech-Stack -RunMode $RunMode -CliValue $TSTACK - } - - # Setup log file path AFTER selections - $logFileName = "{0}_{1}_run_result.log" -f $TEST_TYPE.ToLowerInvariant(), $TECH_STACK.ToLowerInvariant() - $logFile = Join-Path $LOG_DIR $logFileName - if (!(Test-Path $LOG_DIR)) { - New-Item -ItemType Directory -Path $LOG_DIR -Force | Out-Null - } - '' | Out-File -FilePath $logFile -Encoding UTF8 - Set-RunLogFile $logFile - $script:GLOBAL_LOG = $logFile - $script:WEB_LOG = $logFile - $script:MOBILE_LOG = $logFile - Log-Line "ℹ️ Log file path: $logFile" $GLOBAL_LOG - - # Setup Summary Header - Log-Section "🧭 Setup Summary – BrowserStack NOW" $GLOBAL_LOG - Log-Line "ℹ️ Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $GLOBAL_LOG - Log-Line "ℹ️ Run Mode: $RunMode" $GLOBAL_LOG - Log-Line "ℹ️ Selected Testing Type: $TEST_TYPE" $GLOBAL_LOG - Log-Line "ℹ️ Selected Tech Stack: $TECH_STACK" $GLOBAL_LOG - - # Setup workspace and get credentials BEFORE app upload - Setup-Workspace - Ask-BrowserStack-Credentials -RunMode $RunMode -UsernameFromEnv $env:BROWSERSTACK_USERNAME -AccessKeyFromEnv $env:BROWSERSTACK_ACCESS_KEY - - # NOW handle URL/App upload (requires credentials) - Perform-NextSteps-BasedOnTestType -TestType $TEST_TYPE -RunMode $RunMode -TestUrl $TestUrl -AppPath $AppPath -AppPlatform $AppPlatform - - # Platform & Tech Stack section - Log-Section "⚙️ Platform & Tech Stack" $GLOBAL_LOG - Log-Line "ℹ️ Platform: $TEST_TYPE" $GLOBAL_LOG - Log-Line "ℹ️ Tech Stack: $TECH_STACK" $GLOBAL_LOG - - # System Prerequisites Check - Log-Section "🧩 System Prerequisites Check" $GLOBAL_LOG - Validate-Tech-Stack - - # Account & Plan Details - Log-Section "☁️ Account & Plan Details" $GLOBAL_LOG - Fetch-Plan-Details -TestType $TEST_TYPE - - Log-Line "Plan summary: WEB_PLAN_FETCHED=$WEB_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_WEB), MOBILE_PLAN_FETCHED=$MOBILE_PLAN_FETCHED (team max=$TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" $GLOBAL_LOG - Log-Line "Checking proxy in environment" $GLOBAL_LOG - Set-ProxyInEnv -Username $BROWSERSTACK_USERNAME -AccessKey $BROWSERSTACK_ACCESS_KEY - - # Getting Ready section - Log-Section "🧹 Getting Ready" $GLOBAL_LOG - Log-Line "ℹ️ Detected Operating system: Windows" $GLOBAL_LOG - Log-Line "ℹ️ Clearing old logs from NOW Home Directory inside .browserstack" $GLOBAL_LOG - Clear-OldLogs - - Log-Line "ℹ️ Starting $TEST_TYPE setup for $TECH_STACK" $GLOBAL_LOG - - # Run the setup - Run-Setup -TestType $TEST_TYPE -TechStack $TECH_STACK -RunMode $RunMode +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$commonScript = Join-Path $scriptDir "..\common\win\run.ps1" -} catch { - Log-Line " " $GLOBAL_LOG - Log-Line "========================================" $GLOBAL_LOG - Log-Line "❌ EXECUTION FAILED" $GLOBAL_LOG - Log-Line "========================================" $GLOBAL_LOG - Log-Line "Error: $($_.Exception.Message)" $GLOBAL_LOG - Log-Line "Check logs for details:" $GLOBAL_LOG - Log-Line (" Run Log: {0}" -f (Get-RunLogFile)) $GLOBAL_LOG - Log-Line "========================================" $GLOBAL_LOG - throw +# Resolve to absolute path +if (Test-Path $commonScript) { + $commonScript = (Resolve-Path $commonScript).Path +} else { + Write-Error "Common script not found at $commonScript" + exit 1 } +# Execute common script with arguments +& $commonScript -RunMode $RunMode -TT $TT -TSTACK $TSTACK -TestUrl $TestUrl -AppPath $AppPath -AppPlatform $AppPlatform From 5a08fb815588c874a8f17d988605f059da6daa27 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 16:50:44 +0530 Subject: [PATCH 02/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 2 +- common/win/run.ps1 | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index 84e3635..caac570 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -14,7 +14,7 @@ on: jobs: test-mac: name: Test mac/run.sh on macOS - # if: false + if: false runs-on: macos-latest timeout-minutes: 15 environment: BrowserStack diff --git a/common/win/run.ps1 b/common/win/run.ps1 index d7d2a8d..913d5b4 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -63,10 +63,10 @@ try { # Setup Summary Header Log-Section "🧭 Setup Summary – BrowserStack NOW" - Log-Line "ℹ️ Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE - Log-Line "ℹ️ Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE - Log-Line "ℹ️ Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE - Log-Line "ℹ️ Selected Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE + Log-Line "Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE + Log-Line "Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE + Log-Line "Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE + Log-Line "Selected Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE # Setup workspace and get credentials BEFORE app upload Setup-Workspace @@ -80,8 +80,8 @@ try { # Platform & Tech Stack section Log-Section "⚙️ Platform & Tech Stack" - Log-Line "ℹ️ Platform: $TEST_TYPE" $global:NOW_RUN_LOG_FILE - Log-Line "ℹ️ Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE + Log-Line "Platform: $TEST_TYPE" $global:NOW_RUN_LOG_FILE + Log-Line "Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE # System Prerequisites Check Validate-Tech-Stack -TechStack $TECH_STACK @@ -94,19 +94,19 @@ try { # Getting Ready section Log-Section "🧹 Getting Ready" - Log-Line "ℹ️ Detected Operating system: Windows" $global:NOW_RUN_LOG_FILE - Log-Line "ℹ️ Clearing old logs from NOW Home Directory inside .browserstack" $global:NOW_RUN_LOG_FILE + Log-Line "Detected Operating system: Windows" $global:NOW_RUN_LOG_FILE + Log-Line "Clearing old logs from NOW Home Directory inside .browserstack" $global:NOW_RUN_LOG_FILE Clear-OldLogs - Log-Line "ℹ️ Starting $TEST_TYPE setup for $TECH_STACK" $global:NOW_RUN_LOG_FILE + Log-Line "Starting $TEST_TYPE setup for $TECH_STACK" $global:NOW_RUN_LOG_FILE # Run the setup Setup-Environment -SetupType $TEST_TYPE.ToLower() -TechStack $TECH_STACK.ToLower() - -} catch { +} +catch { Log-Line " " $global:NOW_RUN_LOG_FILE Log-Line "========================================" $global:NOW_RUN_LOG_FILE - Log-Line "❌ EXECUTION FAILED" $global:NOW_RUN_LOG_FILE + Log-Line "EXECUTION FAILED" $global:NOW_RUN_LOG_FILE Log-Line "========================================" $global:NOW_RUN_LOG_FILE Log-Line "Error: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE Log-Line "Check logs for details:" $global:NOW_RUN_LOG_FILE From 03c380bd94f631aadc0067092c3fae1e6e89c9ea Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 16:55:02 +0530 Subject: [PATCH 03/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 2 +- common/win/logging-utils.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index caac570..41d1c14 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -384,7 +384,7 @@ jobs: test-linux: name: Test mac/run.sh on Linux - # if: false + if: false runs-on: ubuntu-latest timeout-minutes: 15 environment: BrowserStack diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index 056492f..6fda0f0 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -39,8 +39,8 @@ function Log-Line { [string]$Message, [string]$LogFile ) - $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") - $line = "[$ts] $Message" + #$ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") + $line = "$Message" # Print to console if debug mode (or always, depending on usage in bash) # Bash version: prints to console if RUN_MODE contains --debug From c2e52bb6762c8ed6fcadc0ce3d80854272b64b2b Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:05:07 +0530 Subject: [PATCH 04/32] win mac merge init commit --- common/win/common-utils.ps1 | 26 +++++++++++++------------- common/win/env-prequisite-checks.ps1 | 20 ++++++++++---------- common/win/env-setup-run.ps1 | 2 +- common/win/logging-utils.ps1 | 10 +++++----- common/win/user-interaction.ps1 | 16 ++++++++-------- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index 7a678c2..a74ea5b 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -316,9 +316,9 @@ function Fetch-Plan-Details { $resp = Invoke-RestMethod -Method Get -Uri "https://api.browserstack.com/automate/plan.json" -Headers $headers $script:WEB_PLAN_FETCHED = $true $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = [int]$resp.parallel_sessions_max_allowed - Log-Line "✅ Web Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_WEB" $global:NOW_RUN_LOG_FILE + Log-Line "Web Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_WEB" $global:NOW_RUN_LOG_FILE } catch { - Log-Line "❌ Web Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE + Log-Line "Web Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE } if (-not $script:WEB_PLAN_FETCHED) { throw "Unable to fetch Web Testing plan details." @@ -329,9 +329,9 @@ function Fetch-Plan-Details { $resp2 = Invoke-RestMethod -Method Get -Uri "https://api-cloud.browserstack.com/app-automate/plan.json" -Headers $headers $script:MOBILE_PLAN_FETCHED = $true $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = [int]$resp2.parallel_sessions_max_allowed - Log-Line "✅ Mobile App Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE" $global:NOW_RUN_LOG_FILE + Log-Line "Mobile App Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE" $global:NOW_RUN_LOG_FILE } catch { - Log-Line "❌ Mobile App Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE + Log-Line "Mobile App Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE } if (-not $script:MOBILE_PLAN_FETCHED) { throw "Unable to fetch Mobile App Testing plan details." @@ -347,7 +347,7 @@ function Fetch-Plan-Details { $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = 5 Log-Line "Silent mode: Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)" $global:NOW_RUN_LOG_FILE } else { - Log-Line "ℹ️ Plan summary: Web fetched=$script:WEB_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_WEB), Mobile fetched=$script:MOBILE_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" $global:NOW_RUN_LOG_FILE + Log-Line "Plan summary: Web fetched=$script:WEB_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_WEB), Mobile fetched=$script:MOBILE_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" $global:NOW_RUN_LOG_FILE } } @@ -366,13 +366,13 @@ function Invoke-SampleAppUpload { if ([string]::IsNullOrWhiteSpace($url)) { throw "Sample app upload failed (empty URL)" } - Log-Line "✅ App uploaded successfully: $url" $global:NOW_RUN_LOG_FILE + Log-Success "App uploaded successfully: $url" $global:NOW_RUN_LOG_FILE return @{ Url = $url Platform = "android" } } catch { - Log-Line "❌ Upload failed: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE + Log-Error "Upload failed: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE throw } } @@ -389,7 +389,7 @@ function Invoke-CustomAppUpload { default { throw "Unsupported app file (only .apk/.ipa)" } } - Log-Line "⬆️ Uploading app to BrowserStack..." $global:NOW_RUN_LOG_FILE + Log-Line "Uploading app to BrowserStack..." $global:NOW_RUN_LOG_FILE $boundary = [System.Guid]::NewGuid().ToString() $LF = "`r`n" @@ -421,7 +421,7 @@ function Invoke-CustomAppUpload { Platform = $platform } } catch { - Log-Line "❌ Upload failed: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE + Log-Error "Upload failed: $($_.Exception.Message)" $global:NOW_RUN_LOG_FILE throw } } @@ -431,7 +431,7 @@ function Identify-Run-Status-Java { $content = Get-Content -Path $LogFile -Raw -ErrorAction SilentlyContinue if (-not $content) { - Log-Warn "❌ No test summary line found." + Log-Warn "No test summary line found." return $false } @@ -452,7 +452,7 @@ function Identify-Run-Status-Java { } } - Log-Warn "❌ No test summary line found." + Log-Warn "No test summary line found." return $false } @@ -472,7 +472,7 @@ function Identify-Run-Status-Python { $passedSum += [int]$m.Groups[1].Value } - Write-Host "✅ Total Passed: $passedSum" -ForegroundColor Green + Write-Host "Total Passed: $passedSum" -ForegroundColor Green if ($passedSum -gt 0) { Log-Success "Success: $passedSum test(s) completed" @@ -488,7 +488,7 @@ function Identify-Run-Status-NodeJS { $content = Get-Content -Path $LogFile -Raw -ErrorAction SilentlyContinue if (-not $content) { - Log-Warn "❌ No test summary line found." + Log-Warn "No test summary line found." return $false } diff --git a/common/win/env-prequisite-checks.ps1 b/common/win/env-prequisite-checks.ps1 index 8f74dce..c6ff10a 100644 --- a/common/win/env-prequisite-checks.ps1 +++ b/common/win/env-prequisite-checks.ps1 @@ -43,7 +43,7 @@ function Set-ProxyInEnv { try { $resp = Invoke-WebRequest -Uri $PROXY_TEST_URL -Proxy $proxy -Headers @{ Authorization = "Basic $auth" } -Method Head -ErrorAction Stop $statusCode = $resp.StatusCode - Log-Line "✅ Reachable. HTTP $statusCode" $global:NOW_RUN_LOG_FILE + Log-Line "Endpoint reachable. HTTP $statusCode" $global:NOW_RUN_LOG_FILE Log-Line "Exporting PROXY_HOST=$script:PROXY_HOST" $global:NOW_RUN_LOG_FILE Log-Line "Exporting PROXY_PORT=$script:PROXY_PORT" $global:NOW_RUN_LOG_FILE @@ -51,8 +51,8 @@ function Set-ProxyInEnv { $env:PROXY_PORT = $script:PROXY_PORT Log-Success "Connected to BrowserStack from proxy: $script:PROXY_HOST:$script:PROXY_PORT" } catch { - Log-Warn "⚠️ Could not connect to BrowserStack using proxy. Using direct connection." - Log-Line "❌ Not reachable ($($_.Exception.Message)). Clearing variables." $global:NOW_RUN_LOG_FILE + Log-Error "Could not connect to BrowserStack using proxy. Using direct connection." + Log-Warn "Not reachable ($($_.Exception.Message)). Clearing variables." $global:NOW_RUN_LOG_FILE $script:PROXY_HOST = "" $script:PROXY_PORT = "" $env:PROXY_HOST = "" @@ -105,17 +105,17 @@ function Check-Python-Installation { function Check-NodeJS-Installation { Log-Line "🔍 Checking if 'node' command exists..." $global:NOW_RUN_LOG_FILE if (-not (Get-Command node -ErrorAction SilentlyContinue)) { - Log-Line "❌ Node.js command not found in PATH." $global:NOW_RUN_LOG_FILE + Log-Warn "Node.js command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } - Log-Line "🔍 Checking if 'npm' command exists..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if 'npm' command exists..." $global:NOW_RUN_LOG_FILE if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { - Log-Line "❌ npm command not found in PATH." $global:NOW_RUN_LOG_FILE + Log-Warn "npm command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } - Log-Line "🔍 Checking if Node.js runs correctly..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if Node.js runs correctly..." $global:NOW_RUN_LOG_FILE try { $nodeVer = node -v 2>&1 | Out-String $npmVer = npm -v 2>&1 | Out-String @@ -123,7 +123,7 @@ function Check-NodeJS-Installation { Log-Success "npm installed: $npmVer" return $true } catch { - Log-Line "❌ Node.js/npm exists but failed to run." $global:NOW_RUN_LOG_FILE + Log-Warn "Node.js/npm exists but failed to run." $global:NOW_RUN_LOG_FILE return $false } } @@ -131,7 +131,7 @@ function Check-NodeJS-Installation { function Validate-Tech-Stack { param([string]$TechStack) - Log-Section "🧩 System Prerequisites Check" + Log-Section "System Prerequisites Check" Log-Info "Checking prerequisites for $TechStack" $valid = $false @@ -146,7 +146,7 @@ function Validate-Tech-Stack { } if ($valid) { - Log-Line "✅ Prerequisites validated for $TechStack" $global:NOW_RUN_LOG_FILE + Log-Line "Prerequisites validated for $TechStack" $global:NOW_RUN_LOG_FILE return $true } else { return $false diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index 016ee69..630c094 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -57,7 +57,7 @@ function Setup-Environment { "app_nodejs" { $result = Setup-App-NodeJS -TargetDir $targetDir -Parallels $totalParallels } } - Log-Section "✅ Results" + Log-Section "Results" Log-Info "${SetupType} setup completed with exit code: $result" diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index 6fda0f0..55bd140 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -16,22 +16,22 @@ function Log-Section { function Log-Info { param([string]$Message) - Write-Host "ℹ️ $Message" -ForegroundColor Gray + Write-Host "$Message" -ForegroundColor Gray } function Log-Success { param([string]$Message) - Write-Host "✅ $Message" -ForegroundColor Green + Write-Host "$Message" -ForegroundColor Green } function Log-Warn { param([string]$Message) - Write-Host "⚠️ $Message" -ForegroundColor Yellow + Write-Host "$Message" -ForegroundColor Yellow } function Log-Error { param([string]$Message) - Write-Host "❌ $Message" -ForegroundColor Red + Write-Host "$Message" -ForegroundColor Red } function Log-Line { @@ -40,7 +40,7 @@ function Log-Line { [string]$LogFile ) #$ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") - $line = "$Message" + $line = $Message # Print to console if debug mode (or always, depending on usage in bash) # Bash version: prints to console if RUN_MODE contains --debug diff --git a/common/win/user-interaction.ps1 b/common/win/user-interaction.ps1 index f63e602..883f3bd 100644 --- a/common/win/user-interaction.ps1 +++ b/common/win/user-interaction.ps1 @@ -175,12 +175,12 @@ function Ask-BrowserStack-Credentials { $script:BROWSERSTACK_USERNAME = Show-InputBox -Title "BrowserStack Setup" -Prompt "Enter your BrowserStack Username:`n`nLocate it on https://www.browserstack.com/accounts/profile/details" -DefaultText "" if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_USERNAME)) { - Log-Line "❌ Username empty" $global:NOW_RUN_LOG_FILE + Log-Error "Username empty" $global:NOW_RUN_LOG_FILE throw "Username is required" } $script:BROWSERSTACK_ACCESS_KEY = Show-PasswordBox -Title "BrowserStack Setup" -Prompt "Enter your BrowserStack Access Key:`n`nLocate it on https://www.browserstack.com/accounts/profile/details" if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_ACCESS_KEY)) { - Log-Line "❌ Access Key empty" $global:NOW_RUN_LOG_FILE + Log-Error "❌ Access Key empty" $global:NOW_RUN_LOG_FILE throw "Access Key is required" } @@ -255,16 +255,16 @@ function Ask-User-TestUrl { if (-not [string]::IsNullOrWhiteSpace($CliValue)) { $script:CX_TEST_URL = $CliValue - Log-Line "🌐 Using custom test URL from CLI: $CliValue" $global:NOW_RUN_LOG_FILE + Log-Line "Using custom test URL from CLI: $CliValue" $global:NOW_RUN_LOG_FILE return } $testUrl = Show-InputBox -Title "Test URL Setup" -Prompt "Enter the URL you want to test with BrowserStack:`n(Leave blank for default: $script:DEFAULT_TEST_URL)" -DefaultText "" if ([string]::IsNullOrWhiteSpace($testUrl)) { $testUrl = $script:DEFAULT_TEST_URL - Log-Line "⚠️ No URL entered. Falling back to default: $testUrl" $global:NOW_RUN_LOG_FILE + Log-Line "No URL entered. Falling back to default: $testUrl" $global:NOW_RUN_LOG_FILE } else { - Log-Line "🌐 Using custom test URL: $testUrl" $global:NOW_RUN_LOG_FILE + Log-Line "Using custom test URL: $testUrl" $global:NOW_RUN_LOG_FILE } $script:CX_TEST_URL = $testUrl } @@ -292,7 +292,7 @@ function Ask-And-Upload-App { return } $result = Invoke-SampleAppUpload - Log-Line "⚠️ Using auto-uploaded sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE + Log-Line "Using auto-uploaded sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform return @@ -308,7 +308,7 @@ function Ask-And-Upload-App { $choice = Show-OpenOrSampleAppDialog if ([string]::IsNullOrWhiteSpace($choice) -or $choice -eq "Sample App") { $result = Invoke-SampleAppUpload - Log-Line "⚠️ Using sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE + Log-Line "Using sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform return @@ -326,7 +326,7 @@ function Ask-And-Upload-App { $result = Invoke-CustomAppUpload -FilePath $path $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform - Log-Line "✅ App uploaded successfully: $($result.Url)" $global:NOW_RUN_LOG_FILE + Log-Line "App uploaded successfully: $($result.Url)" $global:NOW_RUN_LOG_FILE } function Perform-NextSteps-BasedOnTestType { From 2cf3e463b5cdf51eacfe0064e523fa9992d657a3 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:08:40 +0530 Subject: [PATCH 05/32] win mac merge init commit --- common/win/user-interaction.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/win/user-interaction.ps1 b/common/win/user-interaction.ps1 index 883f3bd..8f89482 100644 --- a/common/win/user-interaction.ps1 +++ b/common/win/user-interaction.ps1 @@ -165,7 +165,7 @@ function Ask-BrowserStack-Credentials { if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_USERNAME) -or [string]::IsNullOrWhiteSpace($script:BROWSERSTACK_ACCESS_KEY)) { throw "BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY must be provided in silent/debug mode." } - Log-Line "✅ BrowserStack credentials loaded from environment for user: $script:BROWSERSTACK_USERNAME" $global:NOW_RUN_LOG_FILE + Log-Line "BrowserStack credentials loaded from environment for user: $script:BROWSERSTACK_USERNAME" $global:NOW_RUN_LOG_FILE # Export to process env for child processes $env:BROWSERSTACK_USERNAME = $script:BROWSERSTACK_USERNAME @@ -180,14 +180,14 @@ function Ask-BrowserStack-Credentials { } $script:BROWSERSTACK_ACCESS_KEY = Show-PasswordBox -Title "BrowserStack Setup" -Prompt "Enter your BrowserStack Access Key:`n`nLocate it on https://www.browserstack.com/accounts/profile/details" if ([string]::IsNullOrWhiteSpace($script:BROWSERSTACK_ACCESS_KEY)) { - Log-Error "❌ Access Key empty" $global:NOW_RUN_LOG_FILE + Log-Error "Access Key empty" $global:NOW_RUN_LOG_FILE throw "Access Key is required" } $env:BROWSERSTACK_USERNAME = $script:BROWSERSTACK_USERNAME $env:BROWSERSTACK_ACCESS_KEY = $script:BROWSERSTACK_ACCESS_KEY - Log-Line "✅ BrowserStack credentials captured (access key hidden)" $global:NOW_RUN_LOG_FILE + Log-Line "BrowserStack credentials captured (access key hidden)" $global:NOW_RUN_LOG_FILE } function Resolve-Test-Type { @@ -314,10 +314,10 @@ function Ask-And-Upload-App { return } - $path = Show-OpenFileDialog -Title "📱 Select your .apk or .ipa file" -Filter "App Files (*.apk;*.ipa)|*.apk;*.ipa|All files (*.*)|*.*" + $path = Show-OpenFileDialog -Title "Select your .apk or .ipa file" -Filter "App Files (*.apk;*.ipa)|*.apk;*.ipa|All files (*.*)|*.*" if ([string]::IsNullOrWhiteSpace($path)) { $result = Invoke-SampleAppUpload - Log-Line "⚠️ No app selected. Using sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE + Log-Line "No app selected. Using sample app: $($result.Url)" $global:NOW_RUN_LOG_FILE $script:BROWSERSTACK_APP = $result.Url $script:APP_PLATFORM = $result.Platform return @@ -349,4 +349,4 @@ function Perform-NextSteps-BasedOnTestType { throw "Unsupported TEST_TYPE: $TestType. Allowed values: Web, App." } } -} +} \ No newline at end of file From aaf5892d2bed9cfcb92918441215857f8b7b885d Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:11:50 +0530 Subject: [PATCH 06/32] win mac merge init commit --- common/win/common-utils.ps1 | 22 +++++++++++----------- common/win/device-machine-allocation.ps1 | 4 +--- common/win/env-prequisite-checks.ps1 | 16 ++++++++-------- common/win/env-setup-run.ps1 | 1 + common/win/logging-utils.ps1 | 1 + common/win/run.ps1 | 1 + common/win/user-interaction.ps1 | 6 +----- common/win/windows-gui.ps1 | 2 +- 8 files changed, 25 insertions(+), 28 deletions(-) diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index a74ea5b..4c03e6d 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -35,9 +35,9 @@ $script:PY_CMD = @() function Ensure-Workspace { if (!(Test-Path $script:GLOBAL_DIR)) { New-Item -ItemType Directory -Path $script:GLOBAL_DIR | Out-Null - Log-Line "✅ Created Onboarding workspace: $script:GLOBAL_DIR" $global:NOW_RUN_LOG_FILE + Log-Line "Onboarding workspace created: $script:GLOBAL_DIR" $global:NOW_RUN_LOG_FILE } else { - Log-Line "✅ Onboarding workspace found at: $script:GLOBAL_DIR" $global:NOW_RUN_LOG_FILE + Log-Line "Onboarding workspace found at: $script:GLOBAL_DIR" $global:NOW_RUN_LOG_FILE } } @@ -59,7 +59,7 @@ function Clear-OldLogs { } } - Log-Line "✅ Logs directory cleaned. Legacy files removed." $global:NOW_RUN_LOG_FILE + Log-Line "Logs directory cleaned. Legacy files removed." $global:NOW_RUN_LOG_FILE } # ===== Git Clone ===== @@ -266,15 +266,15 @@ function Test-DomainPrivate { $IP_ADDRESS = $matches[1] } } catch { - Log-Line "⚠️ Failed to resolve domain: $domain (assuming public domain)" $global:NOW_RUN_LOG_FILE + Log-Error "Failed to resolve domain: $domain (assuming public domain)" $global:NOW_RUN_LOG_FILE $IP_ADDRESS = "" } } if ([string]::IsNullOrWhiteSpace($IP_ADDRESS)) { - Log-Line "⚠️ DNS resolution failed for: $domain (treating as public domain, BrowserStack Local will be DISABLED)" $global:NOW_RUN_LOG_FILE + Log-Warn "DNS resolution failed for: $domain (treating as public domain, BrowserStack Local will be DISABLED)" $global:NOW_RUN_LOG_FILE } else { - Log-Line "✅ Resolved IP: $IP_ADDRESS" $global:NOW_RUN_LOG_FILE + Log-Info "Resolved IP: $IP_ADDRESS" $global:NOW_RUN_LOG_FILE } return (Test-PrivateIP -IP $IP_ADDRESS) @@ -304,7 +304,7 @@ function Fetch-Plan-Details { } $normalized = $TestType.ToLowerInvariant() - Log-Section "☁️ Account & Plan Details" + Log-Section "Account & Plan Details" Log-Info "Fetching BrowserStack plan for $normalized" $auth = Get-BasicAuthHeader -User $script:BROWSERSTACK_USERNAME -Key $script:BROWSERSTACK_ACCESS_KEY @@ -316,9 +316,9 @@ function Fetch-Plan-Details { $resp = Invoke-RestMethod -Method Get -Uri "https://api.browserstack.com/automate/plan.json" -Headers $headers $script:WEB_PLAN_FETCHED = $true $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = [int]$resp.parallel_sessions_max_allowed - Log-Line "Web Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_WEB" $global:NOW_RUN_LOG_FILE + Log-Success "Web Testing Plan fetched: Team max parallel sessions = $script:TEAM_PARALLELS_MAX_ALLOWED_WEB" $global:NOW_RUN_LOG_FILE } catch { - Log-Line "Web Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE + Log-Error "Web Testing Plan fetch failed ($($_.Exception.Message))" $global:NOW_RUN_LOG_FILE } if (-not $script:WEB_PLAN_FETCHED) { throw "Unable to fetch Web Testing plan details." @@ -415,7 +415,7 @@ function Invoke-CustomAppUpload { if ([string]::IsNullOrWhiteSpace($url)) { throw "Upload failed (empty URL)" } - Log-Line "✅ App uploaded successfully: $url" $global:NOW_RUN_LOG_FILE + Log-Line "App uploaded successfully: $url" $global:NOW_RUN_LOG_FILE return @{ Url = $url Platform = $platform @@ -517,4 +517,4 @@ function Generate-Web-Platforms { function Generate-Mobile-Platforms { param($MaxTotalParallels, $Format) return Pick-Terminal-Devices -PlatformName $script:APP_PLATFORM -Count $MaxTotalParallels -PlatformsListContentFormat $Format -} +} \ No newline at end of file diff --git a/common/win/device-machine-allocation.ps1 b/common/win/device-machine-allocation.ps1 index 24a16a5..be2bf30 100644 --- a/common/win/device-machine-allocation.ps1 +++ b/common/win/device-machine-allocation.ps1 @@ -1,5 +1,3 @@ -# Device Machine Allocation for PowerShell - $script:CONFIG_FILE = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "..\config\devices.txt" function Get-Matching-Devices { @@ -87,4 +85,4 @@ function Pick-Terminal-Devices { } else { return ($jsonList | ConvertTo-Json -Depth 5 -Compress) } -} +} \ No newline at end of file diff --git a/common/win/env-prequisite-checks.ps1 b/common/win/env-prequisite-checks.ps1 index c6ff10a..893eed2 100644 --- a/common/win/env-prequisite-checks.ps1 +++ b/common/win/env-prequisite-checks.ps1 @@ -18,7 +18,7 @@ function Parse-Proxy { } function Set-ProxyInEnv { - Log-Section "🌐 Network & Proxy Validation" + Log-Section "Network & Proxy Validation" # Detect proxy from env $proxy = $env:http_proxy @@ -63,7 +63,7 @@ function Set-ProxyInEnv { function Check-Java-Installation { Log-Line "🔍 Checking if 'java' command exists..." $global:NOW_RUN_LOG_FILE if (-not (Get-Command java -ErrorAction SilentlyContinue)) { - Log-Line "❌ Java command not found in PATH." $global:NOW_RUN_LOG_FILE + Log-Error "Java command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } @@ -73,13 +73,13 @@ function Check-Java-Installation { Log-Success "Java installed and functional`n$output" return $true } catch { - Log-Line "❌ Java exists but failed to run." $global:NOW_RUN_LOG_FILE + Log-Error "Java exists but failed to run." $global:NOW_RUN_LOG_FILE return $false } } function Check-Python-Installation { - Log-Line "🔍 Checking if 'python' command exists..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if 'python' command exists..." $global:NOW_RUN_LOG_FILE # Windows usually uses 'python', not 'python3' $pyCmd = Get-Command python -ErrorAction SilentlyContinue if (-not $pyCmd) { @@ -87,17 +87,17 @@ function Check-Python-Installation { } if (-not $pyCmd) { - Log-Line "❌ Python command not found in PATH." $global:NOW_RUN_LOG_FILE + Log-Error "Python command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } - Log-Line "🔍 Checking if Python runs correctly..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if Python runs correctly..." $global:NOW_RUN_LOG_FILE try { $output = & $pyCmd.Name --version 2>&1 | Out-String Log-Success "Python default installation: $output" return $true } catch { - Log-Line "❌ Python exists but failed to run." $global:NOW_RUN_LOG_FILE + Log-Error "Python exists but failed to run." $global:NOW_RUN_LOG_FILE return $false } } @@ -140,7 +140,7 @@ function Validate-Tech-Stack { "python" { $valid = Check-Python-Installation } "nodejs" { $valid = Check-NodeJS-Installation } default { - Log-Line "❌ Unknown tech stack selected: $TechStack" $global:NOW_RUN_LOG_FILE + Log-Error "Unknown tech stack selected: $TechStack" $global:NOW_RUN_LOG_FILE return $false } } diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index 630c094..3414f19 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -262,6 +262,7 @@ function Detect-Setup-Python-Env { Invoke-External -Exe $pyExe -Arguments @("-m","venv",".venv") -LogFile $global:NOW_RUN_LOG_FILE } + function Print-Env-Variables { Log-Section "Validate Environment Variables and Platforms" Log-Info "BrowserStack Username: $BROWSERSTACK_USERNAME" diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index 55bd140..1498894 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -53,3 +53,4 @@ function Log-Line { Add-Content -Path $LogFile -Value $line -Encoding UTF8 } } + diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 913d5b4..1fd542f 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -114,3 +114,4 @@ catch { Log-Line "========================================" $global:NOW_RUN_LOG_FILE exit 1 } + diff --git a/common/win/user-interaction.ps1 b/common/win/user-interaction.ps1 index 8f89482..4a48d52 100644 --- a/common/win/user-interaction.ps1 +++ b/common/win/user-interaction.ps1 @@ -1,5 +1,3 @@ -# User Interaction Helpers for PowerShell - Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing @@ -228,7 +226,6 @@ function Resolve-Tech-Stack { $textInfo = (Get-Culture).TextInfo $candidate = $textInfo.ToTitleCase($CliValue.ToLowerInvariant()) if ($candidate -notin @("Java","Python","NodeJS")) { - # Normalize if ($candidate -eq "Java") { } elseif ($candidate -eq "Python") { } elseif ($candidate -match "Node") { $candidate = "NodeJS" } @@ -348,5 +345,4 @@ function Perform-NextSteps-BasedOnTestType { default { throw "Unsupported TEST_TYPE: $TestType. Allowed values: Web, App." } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/common/win/windows-gui.ps1 b/common/win/windows-gui.ps1 index e92c58d..f5319a5 100644 --- a/common/win/windows-gui.ps1 +++ b/common/win/windows-gui.ps1 @@ -166,4 +166,4 @@ switch ($Command) { "PasswordBox" { Show-PasswordBox -Title $Title -Prompt $Prompt } "ClickChoice" { Show-ClickChoice -Title $Title -Prompt $Prompt -Choices $Choices -DefaultChoice $DefaultChoice } "OpenFileDialog" { Show-OpenFileDialog -Title $Title -Filter $Filter } -} +} \ No newline at end of file From ba05a12d5cc67dfe2f79722342be1b161e4ef4e3 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:13:05 +0530 Subject: [PATCH 07/32] win mac merge init commit --- common/win/user-interaction.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/win/user-interaction.ps1 b/common/win/user-interaction.ps1 index 4a48d52..01224e3 100644 --- a/common/win/user-interaction.ps1 +++ b/common/win/user-interaction.ps1 @@ -345,4 +345,5 @@ function Perform-NextSteps-BasedOnTestType { default { throw "Unsupported TEST_TYPE: $TestType. Allowed values: Web, App." } - } \ No newline at end of file + } +} \ No newline at end of file From ac3b203dea4547f6796efa694c1cb1d1ea05082f Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:15:10 +0530 Subject: [PATCH 08/32] win mac merge init commit --- common/win/env-prequisite-checks.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/win/env-prequisite-checks.ps1 b/common/win/env-prequisite-checks.ps1 index 893eed2..94fd416 100644 --- a/common/win/env-prequisite-checks.ps1 +++ b/common/win/env-prequisite-checks.ps1 @@ -61,13 +61,13 @@ function Set-ProxyInEnv { } function Check-Java-Installation { - Log-Line "🔍 Checking if 'java' command exists..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if 'java' command exists..." $global:NOW_RUN_LOG_FILE if (-not (Get-Command java -ErrorAction SilentlyContinue)) { Log-Error "Java command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } - Log-Line "🔍 Checking if Java runs correctly..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if Java runs correctly..." $global:NOW_RUN_LOG_FILE try { $output = java -version 2>&1 | Out-String Log-Success "Java installed and functional`n$output" @@ -103,15 +103,15 @@ function Check-Python-Installation { } function Check-NodeJS-Installation { - Log-Line "🔍 Checking if 'node' command exists..." $global:NOW_RUN_LOG_FILE + Log-Line "Checking if 'node' command exists..." $global:NOW_RUN_LOG_FILE if (-not (Get-Command node -ErrorAction SilentlyContinue)) { - Log-Warn "Node.js command not found in PATH." $global:NOW_RUN_LOG_FILE + Log-Error "Node.js command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } Log-Line "Checking if 'npm' command exists..." $global:NOW_RUN_LOG_FILE if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { - Log-Warn "npm command not found in PATH." $global:NOW_RUN_LOG_FILE + Log-Error "npm command not found in PATH." $global:NOW_RUN_LOG_FILE return $false } @@ -123,7 +123,7 @@ function Check-NodeJS-Installation { Log-Success "npm installed: $npmVer" return $true } catch { - Log-Warn "Node.js/npm exists but failed to run." $global:NOW_RUN_LOG_FILE + Log-Error "Node.js/npm exists but failed to run." $global:NOW_RUN_LOG_FILE return $false } } From 30b45ac0f8d91d115ca6f1dc09a01d721b1e1ecd Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:17:52 +0530 Subject: [PATCH 09/32] win mac merge init commit --- common/win/env-setup-run.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index 3414f19..641d55d 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -20,7 +20,7 @@ function Setup-Environment { [string]$TechStack ) - Log-Section "📦 Project Setup" + Log-Section "Project Setup" $maxParallels = 0 if ($SetupType -eq "web") { @@ -72,7 +72,7 @@ function Setup-Environment { if ($status -and $result) { Log-Success "${SetupType} setup succeeded." } else { - Log-Error "❌ ${SetupType} setup failed. Check logs for details." + Log-Error "${SetupType} setup failed. Check logs for details." exit 1 } } @@ -271,5 +271,5 @@ function Print-Env-Variables { if ($TEST_TYPE -eq "app") { Log-Info "Native App Endpoint: $BROWSERSTACK_APP" } Log-Info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" Log-Info "Parallels per platform: $BSTACK_PARALLELS" - Log-Info "Platforms: \n$BSTACK_PLATFORMS" + Log-Info "Platforms: $BSTACK_PLATFORMS" } From ba86f051b7c92ce0096b385e2e0c7cbbb058fb5d Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 17:26:35 +0530 Subject: [PATCH 10/32] win mac merge init commit --- common/mac/common-utils.sh | 44 +++++++++++------------ common/mac/env-prequisite-checks.sh | 46 ++++++++++++------------ common/mac/env-setup-run.sh | 4 +-- common/mac/logging-utils.sh | 16 ++++----- common/mac/run.sh | 6 ++-- common/mac/user-interaction.sh | 24 +++++++------ common/win/common-utils.ps1 | 8 ++--- common/win/device-machine-allocation.ps1 | 1 - common/win/env-setup-run.ps1 | 2 +- common/win/logging-utils.ps1 | 6 ++-- common/win/run.ps1 | 8 ++--- 11 files changed, 83 insertions(+), 82 deletions(-) diff --git a/common/mac/common-utils.sh b/common/mac/common-utils.sh index 313deaa..bda1845 100644 --- a/common/mac/common-utils.sh +++ b/common/mac/common-utils.sh @@ -59,18 +59,18 @@ show_spinner() { ts="$(date +"%Y-%m-%d %H:%M:%S")" while kill -0 "$pid" 2>/dev/null; do i=$(( (i+1) %4 )) - printf "\r⏳ Processing... %s" "${spin:$i:1}" + printf "\rProcessing... %s" "${spin:$i:1}" sleep 0.1 done echo "" log_info "Run Test command completed." sleep 5 - #log_msg_to "✅ Done!" + #log_msg_to "Done!" } # ===== Workspace Management ===== setup_workspace() { - log_section "⚙️ Environment & Credentials" + log_section "Environment & Credentials" local full_path="$WORKSPACE_DIR/$PROJECT_FOLDER" if [ ! -d "$full_path" ]; then mkdir -p "$full_path" @@ -132,7 +132,7 @@ handle_app_upload() { } upload_sample_app() { - log_msg_to "⬆️ Uploading sample app to BrowserStack..." + log_msg_to "Uploading sample app to BrowserStack..." local upload_response upload_response=$(curl -s -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \ -X POST "https://api-cloud.browserstack.com/app-automate/upload" \ @@ -144,11 +144,11 @@ upload_sample_app() { log_info "Uploaded app URL: $app_url" if [ -z "$app_url" ]; then - log_msg_to "❌ Upload failed. Response: $upload_response" + log_msg_to "Upload failed. Response: $upload_response" return 1 fi - log_msg_to "✅ App uploaded successfully: $app_url" + log_msg_to "App uploaded successfully: $app_url" return 0 } @@ -178,7 +178,7 @@ upload_custom_app() { file_path="${file_path%"${file_path##*[![:space:]]}"}" if [ -z "$file_path" ]; then - log_msg_to "❌ No file selected" + log_msg_to "No file selected" return 1 fi @@ -189,11 +189,11 @@ upload_custom_app() { elif [[ "$file_path" == *.apk ]]; then app_platform="android" else - log_msg_to "❌ Invalid file type. Must be .apk or .ipa" + log_msg_to "Invalid file type. Must be .apk or .ipa" return 1 fi - log_msg_to "⬆️ Uploading app to BrowserStack..." + log_msg_to "Uploading app to BrowserStack..." local upload_response upload_response=$(curl -s -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \ -X POST "https://api-cloud.browserstack.com/app-automate/upload" \ @@ -202,12 +202,12 @@ upload_custom_app() { local app_url app_url=$(echo "$upload_response" | grep -o '"app_url":"[^"]*' | cut -d'"' -f4) if [ -z "$app_url" ]; then - log_msg_to "❌ Failed to upload app" + log_msg_to "Failed to upload app" return 1 fi export BROWSERSTACK_APP=$app_url - log_msg_to "✅ App uploaded successfully" + log_msg_to "App uploaded successfully" log_info "Uploaded app URL: $app_url" log_msg_to "Exported BROWSERSTACK_APP=$BROWSERSTACK_APP" @@ -240,7 +240,7 @@ generate_mobile_platforms() { fetch_plan_details() { local test_type=$1 - log_section "☁️ Account & Plan Details" + log_section "Account & Plan Details" log_info "Fetching BrowserStack plan for $test_type" local web_unauthorized=false local mobile_unauthorized=false @@ -253,9 +253,9 @@ fetch_plan_details() { WEB_PLAN_FETCHED=true TEAM_PARALLELS_MAX_ALLOWED_WEB=$(echo "$RESPONSE_WEB_BODY" | grep -o '"parallel_sessions_max_allowed":[0-9]*' | grep -o '[0-9]*') export TEAM_PARALLELS_MAX_ALLOWED_WEB="$TEAM_PARALLELS_MAX_ALLOWED_WEB" - log_msg_to "✅ Web Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_WEB" + log_msg_to "Web Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_WEB" else - log_msg_to "❌ Web Testing Plan fetch failed ($HTTP_CODE_WEB)" + log_msg_to "Web Testing Plan fetch failed ($HTTP_CODE_WEB)" [ "$HTTP_CODE_WEB" == "401" ] && web_unauthorized=true fi fi @@ -268,9 +268,9 @@ fetch_plan_details() { MOBILE_PLAN_FETCHED=true TEAM_PARALLELS_MAX_ALLOWED_MOBILE=$(echo "$RESPONSE_MOBILE_BODY" | grep -o '"parallel_sessions_max_allowed":[0-9]*' | grep -o '[0-9]*') export TEAM_PARALLELS_MAX_ALLOWED_MOBILE="$TEAM_PARALLELS_MAX_ALLOWED_MOBILE" - log_msg_to "✅ Mobile App Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_MOBILE" + log_msg_to "Mobile App Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_MOBILE" else - log_msg_to "❌ Mobile App Testing Plan fetch failed ($HTTP_CODE_MOBILE)" + log_msg_to "Mobile App Testing Plan fetch failed ($HTTP_CODE_MOBILE)" [ "$HTTP_CODE_MOBILE" == "401" ] && mobile_unauthorized=true fi fi @@ -279,7 +279,7 @@ fetch_plan_details() { if [[ "$test_type" == "web" && "$web_unauthorized" == true ]] || \ [[ "$test_type" == "app" && "$mobile_unauthorized" == true ]]; then - log_msg_to "❌ Unauthorized to fetch required plan(s). Exiting." + log_msg_to "Unauthorized to fetch required plan(s). Exiting." exit 1 fi @@ -371,7 +371,7 @@ identify_run_status_java() { line=$(grep -m 2 -E "[INFO|ERROR].*Tests run" < "$log_file") # If not found, fail if [[ -z "$line" ]]; then - log_warn "❌ No test summary line found." + log_warn "No test summary line found." return 1 fi @@ -403,7 +403,7 @@ identify_run_status_nodejs() { line=$(grep -m 1 -E "Spec Files:.*passed.*total" < "$log_file") # If not found, fail if [[ -z "$line" ]]; then - log_warn "❌ No test summary line found." + log_warn "No test summary line found." return 1 fi @@ -428,11 +428,11 @@ identify_run_status_python() { # Extract numbers and sum them passed_sum=$(grep -oE '[0-9]+ passed' "$log_file" | awk '{sum += $1} END {print sum+0}') - echo "✅ Total Passed: $passed_sum" + echo "Total Passed: $passed_sum" # If not found, fail if [[ -z "$passed_sum" ]]; then - log_warn "❌ No test summary line found." + log_warn "No test summary line found." return 1 fi @@ -441,7 +441,7 @@ identify_run_status_python() { log_success "Success: $passed_sum test(s) completed" return 0 else - log_error "❌ Error: No tests completed" + log_error "Error: No tests completed" return 1 fi } diff --git a/common/mac/env-prequisite-checks.sh b/common/mac/env-prequisite-checks.sh index 51aa5c2..781f54d 100755 --- a/common/mac/env-prequisite-checks.sh +++ b/common/mac/env-prequisite-checks.sh @@ -25,7 +25,7 @@ parse_proxy() { } set_proxy_in_env() { - log_section "🌐 Network & Proxy Validation" + log_section "Network & Proxy Validation" base64_encoded_creds=$(printf "%s" "$BROWSERSTACK_USERNAME":"$BROWSERSTACK_ACCESS_KEY" | base64 | tr -d '\n') @@ -46,15 +46,15 @@ set_proxy_in_env() { STATUS_CODE=$(curl -sS -o /dev/null -H "Authorization: Basic ${base64_encoded_creds}" -w "%{http_code}" --proxy "$PROXY" "$PROXY_TEST_URL" 2>/dev/null) if [ "${STATUS_CODE#2}" != "$STATUS_CODE" ]; then - log_msg_to "✅ Reachable. HTTP $STATUS_CODE" + log_msg_to "Reachable. HTTP $STATUS_CODE" log_msg_to "Exporting PROXY_HOST=$PROXY_HOST" log_msg_to "Exporting PROXY_PORT=$PROXY_PORT" export PROXY_HOST export PROXY_PORT log_success "Connected to BrowserStack from proxy: $PROXY_HOST:$PROXY_PORT" else - log_warn "⚠️ Could not connect to BrowserStack using proxy. Using direct connection." - log_msg_to "❌ Not reachable (HTTP $STATUS_CODE). Clearing variables." + log_warn "Could not connect to BrowserStack using proxy. Using direct connection." + log_msg_to "Not reachable (HTTP $STATUS_CODE). Clearing variables." export PROXY_HOST="" export PROXY_PORT="" fi @@ -63,15 +63,15 @@ set_proxy_in_env() { # ===== Tech Stack Validation Functions ===== check_java_installation() { - log_msg_to "🔍 Checking if 'java' command exists..." + log_msg_to "Checking if 'java' command exists..." if ! command -v java >/dev/null 2>&1; then - log_msg_to "❌ Java command not found in PATH." + log_msg_to "Java command not found in PATH." return 1 fi - log_msg_to "🔍 Checking if Java runs correctly..." + log_msg_to "Checking if Java runs correctly..." if ! JAVA_VERSION_OUTPUT=$(java -version 2>&1); then - log_msg_to "❌ Java exists but failed to run." + log_msg_to "Java exists but failed to run." return 1 fi @@ -81,15 +81,15 @@ check_java_installation() { } check_python_installation() { - log_msg_to "🔍 Checking if 'python3' command exists..." + log_msg_to "Checking if 'python3' command exists..." if ! command -v python3 >/dev/null 2>&1; then - log_msg_to "❌ Python3 command not found in PATH." + log_msg_to "Python3 command not found in PATH." return 1 fi - log_msg_to "🔍 Checking if Python3 runs correctly..." + log_msg_to "Checking if Python3 runs correctly..." if ! PYTHON_VERSION_OUTPUT=$(python3 --version 2>&1); then - log_msg_to "❌ Python3 exists but failed to run." + log_msg_to "Python3 exists but failed to run." return 1 fi @@ -98,27 +98,27 @@ check_python_installation() { } check_nodejs_installation() { - log_msg_to "🔍 Checking if 'node' command exists..." + log_msg_to "Checking if 'node' command exists..." if ! command -v node >/dev/null 2>&1; then - log_msg_to "❌ Node.js command not found in PATH." + log_msg_to "Node.js command not found in PATH." return 1 fi - log_msg_to "🔍 Checking if 'npm' command exists..." + log_msg_to "Checking if 'npm' command exists..." if ! command -v npm >/dev/null 2>&1; then - log_msg_to "❌ npm command not found in PATH." + log_msg_to "npm command not found in PATH." return 1 fi - log_msg_to "🔍 Checking if Node.js runs correctly..." + log_msg_to "Checking if Node.js runs correctly..." if ! NODE_VERSION_OUTPUT=$(node -v 2>&1); then - log_msg_to "❌ Node.js exists but failed to run." + log_msg_to "Node.js exists but failed to run." return 1 fi - log_msg_to "🔍 Checking if npm runs correctly..." + log_msg_to "Checking if npm runs correctly..." if ! NPM_VERSION_OUTPUT=$(npm -v 2>&1); then - log_msg_to "❌ npm exists but failed to run." + log_msg_to "npm exists but failed to run." return 1 fi @@ -130,7 +130,7 @@ check_nodejs_installation() { validate_tech_stack_installed() { local tech_stack=$1 - log_section "🧩 System Prerequisites Check" + log_section "System Prerequisites Check" log_info "Checking prerequisites for $tech_stack" case "$tech_stack" in @@ -144,12 +144,12 @@ validate_tech_stack_installed() { check_nodejs_installation ;; *) - log_msg_to "❌ Unknown tech stack selected: $tech_stack" + log_msg_to "Unknown tech stack selected: $tech_stack" return 1 ;; esac - log_msg_to "✅ Prerequisites validated for $tech_stack" + log_msg_to "Prerequisites validated for $tech_stack" return 0 } diff --git a/common/mac/env-setup-run.sh b/common/mac/env-setup-run.sh index 7207630..99b2432 100644 --- a/common/mac/env-setup-run.sh +++ b/common/mac/env-setup-run.sh @@ -20,7 +20,7 @@ setup_environment() { local tech_stack=$2 local max_parallels - log_section "📦 Project Setup" + log_section "Project Setup" if [ "$setup_type" = "web" ]; then max_parallels=$TEAM_PARALLELS_MAX_ALLOWED_WEB @@ -49,7 +49,7 @@ setup_environment() { local ret=$? - log_section "✅ Results" + log_section "Results" log_info "${setup_type} setup completed with exit code: $ret" local status=1 #if [ $ret -eq 0 ]; then diff --git a/common/mac/logging-utils.sh b/common/mac/logging-utils.sh index 2358b31..078b72b 100644 --- a/common/mac/logging-utils.sh +++ b/common/mac/logging-utils.sh @@ -2,7 +2,7 @@ #set -e # ============================================== -# 🎨 COLOR & STYLE DEFINITIONS +# COLOR & STYLE DEFINITIONS # ============================================== BOLD="\033[1m" RESET="\033[0m" @@ -13,17 +13,17 @@ RED="\033[31m" LIGHT_GRAY='\033[0;37m' # ============================================== -# 🪄 LOGGING HELPERS +# LOGGING HELPERS # ============================================== log_section() { echo "" - echo -e "${BOLD}${CYAN}───────────────────────────────────────────────${RESET}" + echo -e "${BOLD}${CYAN}-----------------------------------------------${RESET}" echo -e "${BOLD}$1${RESET}" - echo -e "${BOLD}${CYAN}───────────────────────────────────────────────${RESET}" + echo -e "${BOLD}${CYAN}-----------------------------------------------${RESET}" } -log_info() { echo -e "${LIGHT_GRAY}ℹ️ $1${RESET}"; } -log_success() { echo -e "${GREEN}✅ $1${RESET}"; } -log_warn() { echo -e "${YELLOW}⚠️ $1${RESET}"; } -log_error() { echo -e "${RED}❌ $1${RESET}"; } +log_info() { echo -e "${LIGHT_GRAY}$1${RESET}"; } +log_success() { echo -e "${GREEN}$1${RESET}"; } +log_warn() { echo -e "${YELLOW}$1${RESET}"; } +log_error() { echo -e "${RED}$1${RESET}"; } diff --git a/common/mac/run.sh b/common/mac/run.sh index 951f75d..62a23ef 100755 --- a/common/mac/run.sh +++ b/common/mac/run.sh @@ -40,7 +40,7 @@ export CLI_TEST_URL export CLI_APP_PATH export CLI_APP_PLATFORM -log_section "🧭 Setup Summary – BrowserStack NOW" +log_section "Setup Summary - BrowserStack NOW" log_info "Timestamp: $(date '+%Y-%m-%d %H:%M:%S')" @@ -62,7 +62,7 @@ export NOW_RUN_LOG_FILE="$log_file" setup_workspace get_browserstack_credentials "$RUN_MODE" -log_section "⚙️ Platform & Tech Stack" +log_section "Platform & Tech Stack" log_info "Platform: ${TEST_TYPE:-N/A}" log_info "Tech Stack: ${TECH_STACK:-N/A}" @@ -80,7 +80,7 @@ log_msg_to "Plan summary: WEB_PLAN_FETCHED=$WEB_PLAN_FETCHED (team max=$TEAM_PAR log_msg_to "Checking proxy in environment" set_proxy_in_env -log_section "🧹 Getting Ready" +log_section "Getting Ready" log_info "Detected Operating system: $NOW_OS" log_info "Clearing old logs fron NOW Home Directory inside .browserstack" diff --git a/common/mac/user-interaction.sh b/common/mac/user-interaction.sh index 54fac80..d190919 100644 --- a/common/mac/user-interaction.sh +++ b/common/mac/user-interaction.sh @@ -20,7 +20,9 @@ windows_click_choice() { local prompt="$2" local default="$3" shift 3 - local choices_str=$(IFS=,; echo "$*") + local choices_str + choices_str=$(printf "%s," "$@") + choices_str="${choices_str%,}" powershell.exe -ExecutionPolicy Bypass -File "$GUI_SCRIPT" -Command "ClickChoice" -Title "$title" -Prompt "$prompt" -DefaultChoice "$default" -Choices "$choices_str" | tr -d '\r' } @@ -52,7 +54,7 @@ get_browserstack_credentials() { fi if [ -z "$username" ]; then - log_msg_to "❌ Username empty" + log_msg_to "Username empty" return 1 fi @@ -68,7 +70,7 @@ get_browserstack_credentials() { echo "" # Newline after secret input fi if [ -z "$access_key" ]; then - log_msg_to "❌ Access Key empty" + log_msg_to "Access Key empty" return 1 fi @@ -86,7 +88,7 @@ get_tech_stack() { local tech_stack="" if [[ "$run_mode" == *"--silent"* || "$run_mode" == *"--debug"* ]]; then tech_stack="$TSTACK" - log_msg_to "✅ Selected Tech Stack from environment: $tech_stack" + log_msg_to "Selected Tech Stack from environment: $tech_stack" else if [[ "$NOW_OS" == "macos" ]]; then tech_stack=$(osascript -e 'Tell application "System Events" to display dialog "Select installed tech stack:" buttons {"java", "python", "nodejs"} default button "java" with title "Testing Framework Technology Stack"' \ @@ -105,7 +107,7 @@ get_tech_stack() { done fi fi - log_msg_to "✅ Selected Tech Stack: $tech_stack" + log_msg_to "Selected Tech Stack: $tech_stack" log_info "Tech Stack: $tech_stack" export TECH_STACK="$tech_stack" @@ -119,7 +121,7 @@ get_test_url() { if [ -n "$CLI_TEST_URL" ]; then test_url="$CLI_TEST_URL" - log_msg_to "🌐 Using custom test URL from CLI: $test_url" + log_msg_to "Using custom test URL from CLI: $test_url" else if [[ "$NOW_OS" == "macos" ]]; then test_url=$(osascript -e 'Tell application "System Events" to display dialog "Enter the URL you want to test with BrowserStack:\n(Leave blank for default: '"$DEFAULT_TEST_URL"')" default answer "" with title "Test URL Setup" buttons {"OK"} default button "OK"' \ @@ -135,11 +137,11 @@ get_test_url() { fi if [ -n "$test_url" ]; then - log_msg_to "🌐 Using custom test URL: $test_url" - log_info "🌐 Using custom test URL: $test_url" + log_msg_to "Using custom test URL: $test_url" + log_info "Using custom test URL: $test_url" else test_url="$DEFAULT_TEST_URL" - log_msg_to "⚠️ No URL entered. Falling back to default: $test_url" + log_msg_to "No URL entered. Falling back to default: $test_url" log_info "No URL entered. Falling back to default: $test_url" fi @@ -152,7 +154,7 @@ get_test_type() { local test_type="" if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then test_type=$TT - log_msg_to "✅ Selected Testing Type from environment: $TEST_TYPE" + log_msg_to "Selected Testing Type from environment: $TEST_TYPE" else if [[ "$NOW_OS" == "macos" ]]; then test_type=$(osascript -e 'Tell application "System Events" to display dialog "Select testing type:" buttons {"web", "app"} default button "web" with title "Testing Type"' \ @@ -169,7 +171,7 @@ get_test_type() { esac done fi - log_msg_to "✅ Selected Testing Type: $TEST_TYPE" + log_msg_to "Selected Testing Type: $TEST_TYPE" RUN_MODE=$test_type log_info "Run Mode: ${RUN_MODE:-default}" fi diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index 4c03e6d..7468a7f 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -42,7 +42,7 @@ function Ensure-Workspace { } function Setup-Workspace { - Log-Section "⚙️ Environment & Credentials" + Log-Section "Environment & Credentials" Ensure-Workspace } @@ -226,7 +226,7 @@ function Show-Spinner { $i = 0 $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") while (!$Process.HasExited) { - Write-Host "`r[$ts] ⏳ Processing... $($spin[$i])" -NoNewline -ForegroundColor Cyan + Write-Host "`r[$ts] Processing... $($spin[$i])" -NoNewline -ForegroundColor Cyan $i = ($i + 1) % 4 Start-Sleep -Milliseconds 100 } @@ -353,7 +353,7 @@ function Fetch-Plan-Details { } function Invoke-SampleAppUpload { - Log-Line "⬆️ Uploading sample app to BrowserStack..." $global:NOW_RUN_LOG_FILE + Log-Line "Uploading sample app to BrowserStack..." $global:NOW_RUN_LOG_FILE $headers = @{ Authorization = (Get-BasicAuthHeader -User $script:BROWSERSTACK_USERNAME -Key $script:BROWSERSTACK_ACCESS_KEY) } @@ -461,7 +461,7 @@ function Identify-Run-Status-Python { $content = Get-Content -Path $LogFile -Raw -ErrorAction SilentlyContinue if (-not $content) { - Log-Warn "❌ No test summary line found." + Log-Warn "No test summary line found." return $false } diff --git a/common/win/device-machine-allocation.ps1 b/common/win/device-machine-allocation.ps1 index be2bf30..276861c 100644 --- a/common/win/device-machine-allocation.ps1 +++ b/common/win/device-machine-allocation.ps1 @@ -19,7 +19,6 @@ function Get-Matching-Devices { } } } else { - # Web includes WEB and MOBILE foreach ($line in $lines) { if ($line -match "^WEB\|") { $devices += ($line -replace "^WEB\|", "") diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index 641d55d..b402075 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -72,7 +72,7 @@ function Setup-Environment { if ($status -and $result) { Log-Success "${SetupType} setup succeeded." } else { - Log-Error "${SetupType} setup failed. Check logs for details." + Log-Error "Setup failed. Check logs for details." exit 1 } } diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index 1498894..d316cec 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -1,7 +1,7 @@ # Logging Helpers for PowerShell # ============================================== -# 🎨 COLOR & STYLE DEFINITIONS +# COLOR & STYLE DEFINITIONS # ============================================== # PowerShell uses Write-Host -ForegroundColor for colors. # We will define helper functions instead of raw escape codes for better compatibility. @@ -9,9 +9,9 @@ function Log-Section { param([string]$Message) Write-Host "" - Write-Host "───────────────────────────────────────────────" -ForegroundColor Cyan + Write-Host "-----------------------------------------------" -ForegroundColor Cyan Write-Host $Message -ForegroundColor White - Write-Host "───────────────────────────────────────────────" -ForegroundColor Cyan + Write-Host "-----------------------------------------------" -ForegroundColor Cyan } function Log-Info { diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 1fd542f..6bdca39 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -59,10 +59,10 @@ try { $script:GLOBAL_LOG = $logFile $global:NOW_RUN_LOG_FILE = $logFile - Log-Line "ℹ️ Log file path: $logFile" $global:NOW_RUN_LOG_FILE + Log-Line "Log file path: $logFile" $global:NOW_RUN_LOG_FILE # Setup Summary Header - Log-Section "🧭 Setup Summary – BrowserStack NOW" + Log-Section "Setup Summary - BrowserStack NOW" Log-Line "Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE Log-Line "Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE Log-Line "Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE @@ -79,7 +79,7 @@ try { Setup-Environment -SetupType $TEST_TYPE.ToLower() -TechStack $TECH_STACK.ToLower() # Platform & Tech Stack section - Log-Section "⚙️ Platform & Tech Stack" + Log-Section "Platform & Tech Stack" Log-Line "Platform: $TEST_TYPE" $global:NOW_RUN_LOG_FILE Log-Line "Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE @@ -93,7 +93,7 @@ try { Set-ProxyInEnv # Getting Ready section - Log-Section "🧹 Getting Ready" + Log-Section "Getting Ready" Log-Line "Detected Operating system: Windows" $global:NOW_RUN_LOG_FILE Log-Line "Clearing old logs from NOW Home Directory inside .browserstack" $global:NOW_RUN_LOG_FILE Clear-OldLogs From c229158e1f5075c919be648fce68f59e628d2465 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:13:03 +0530 Subject: [PATCH 11/32] win mac merge init commit --- common/win/logging-utils.ps1 | 23 +++++++++++------------ common/win/run.ps1 | 3 +++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index d316cec..4b5b2ed 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -39,18 +39,17 @@ function Log-Line { [string]$Message, [string]$LogFile ) - #$ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") - $line = $Message - - # Print to console if debug mode (or always, depending on usage in bash) - # Bash version: prints to console if RUN_MODE contains --debug - # But common-utils.sh log_msg_to also prints to console if debug. - # Here we just append to file if provided. - - if (-not [string]::IsNullOrWhiteSpace($LogFile)) { - $dir = Split-Path -Parent $LogFile - if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } - Add-Content -Path $LogFile -Value $line -Encoding UTF8 + if (-not $DestFile) { + $DestFile = Get-RunLogFile + } + + $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") + $line = "$Message" + Write-Host $line + if ($DestFile) { + $dir = Split-Path -Parent $DestFile + if ($dir -and !(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null } + Add-Content -Path $DestFile -Value $line } } diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 6bdca39..afbfe35 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -112,6 +112,9 @@ catch { Log-Line "Check logs for details:" $global:NOW_RUN_LOG_FILE Log-Line (" Run Log: {0}" -f $global:NOW_RUN_LOG_FILE) $global:NOW_RUN_LOG_FILE Log-Line "========================================" $global:NOW_RUN_LOG_FILE + Set-Location -Path $CurrentDir exit 1 +} finally { + Set-Location -Path $CurrentDir } From 2e3dd13b5b6907d163193f0fe60f1ec2c0dc3762 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:17:24 +0530 Subject: [PATCH 12/32] win mac merge init commit --- common/win/run.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index afbfe35..8bbbd13 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -64,6 +64,9 @@ try { # Setup Summary Header Log-Section "Setup Summary - BrowserStack NOW" Log-Line "Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE + + $script:CurrentDir = (Get-Location).Path + Log-Line "Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE Log-Line "Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE Log-Line "Selected Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE From 6353344b6240c2ff1265669fb8786191d7cb3773 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:18:29 +0530 Subject: [PATCH 13/32] win mac merge init commit --- common/win/run.ps1 | 8 -------- mac/run.sh | 1 - 2 files changed, 9 deletions(-) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 8bbbd13..cfad5e0 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -1,11 +1,3 @@ -#requires -version 5.0 -<# - BrowserStack Onboarding (PowerShell 5.0+, GUI) - - Shared logic for Windows - - Uses WinForms for GUI prompts - - Logs to %USERPROFILE%\.browserstack\NOW\logs -#> - param( [string]$RunMode = "--interactive", [string]$TT, diff --git a/mac/run.sh b/mac/run.sh index a84c146..aef69b6 100755 --- a/mac/run.sh +++ b/mac/run.sh @@ -1,2 +1 @@ -#!/bin/bash exec "$(dirname "$0")/../common/mac/run.sh" "$@" From 8736b2c2f3530a1699ffe1f77cf57a1a06214ce3 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:19:44 +0530 Subject: [PATCH 14/32] win mac merge init commit --- win/run.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/win/run.ps1 b/win/run.ps1 index 9949c90..ce68703 100644 --- a/win/run.ps1 +++ b/win/run.ps1 @@ -1,5 +1,4 @@ -#requires -version 5.0 -param( +param( [string]$RunMode = "--interactive", [string]$TT, [string]$TSTACK, From 87fd2fe83a8737d0868ffaf8dca8b44ddd815943 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:21:27 +0530 Subject: [PATCH 15/32] win mac merge init commit --- common/win/run.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index cfad5e0..3e0691a 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -107,9 +107,9 @@ catch { Log-Line "Check logs for details:" $global:NOW_RUN_LOG_FILE Log-Line (" Run Log: {0}" -f $global:NOW_RUN_LOG_FILE) $global:NOW_RUN_LOG_FILE Log-Line "========================================" $global:NOW_RUN_LOG_FILE - Set-Location -Path $CurrentDir + Set-Location -Path $script:CurrentDir exit 1 } finally { - Set-Location -Path $CurrentDir + Set-Location -Path $script:CurrentDir } From 31a0ec5e0c01e7b3559a1bfda5b8566bbe3872f5 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:22:29 +0530 Subject: [PATCH 16/32] win mac merge init commit --- common/win/run.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 3e0691a..5fe7e59 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -25,6 +25,9 @@ $script:PSScriptRootResolved = Split-Path -Parent $MyInvocation.MyCommand.Path # ===== Main flow (baseline steps then run) ===== try { + + $script:CurrentDir = (Get-Location).Path + # Get test type and tech stack before logging if ($RunMode -match "--silent|--debug") { $textInfo = (Get-Culture).TextInfo @@ -56,8 +59,6 @@ try { # Setup Summary Header Log-Section "Setup Summary - BrowserStack NOW" Log-Line "Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE - - $script:CurrentDir = (Get-Location).Path Log-Line "Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE Log-Line "Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE From 52a1732553aa9f6e74001649d1ec5a403f0736be Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:23:45 +0530 Subject: [PATCH 17/32] win mac merge init commit --- common/win/logging-utils.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index 4b5b2ed..20f02e6 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -39,7 +39,7 @@ function Log-Line { [string]$Message, [string]$LogFile ) - if (-not $DestFile) { + if (-not $LogFile) { $DestFile = Get-RunLogFile } From 2541a2a7eadccf9dc202885fa85b554132eaa693 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:26:04 +0530 Subject: [PATCH 18/32] win mac merge init commit --- common/win/logging-utils.ps1 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/common/win/logging-utils.ps1 b/common/win/logging-utils.ps1 index 20f02e6..3b68bf7 100644 --- a/common/win/logging-utils.ps1 +++ b/common/win/logging-utils.ps1 @@ -39,17 +39,13 @@ function Log-Line { [string]$Message, [string]$LogFile ) - if (-not $LogFile) { - $DestFile = Get-RunLogFile - } - $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") $line = "$Message" Write-Host $line - if ($DestFile) { - $dir = Split-Path -Parent $DestFile + if ($LogFile) { + $dir = Split-Path -Parent $LogFile if ($dir -and !(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null } - Add-Content -Path $DestFile -Value $line + Add-Content -Path $LogFile -Value $line } } From d6ce12c4e198f7ce44b4a044b198c05e3002717f Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:39:08 +0530 Subject: [PATCH 19/32] win mac merge init commit --- common/win/run.ps1 | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 5fe7e59..1593154 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -27,7 +27,7 @@ $script:PSScriptRootResolved = Split-Path -Parent $MyInvocation.MyCommand.Path try { $script:CurrentDir = (Get-Location).Path - + # Get test type and tech stack before logging if ($RunMode -match "--silent|--debug") { $textInfo = (Get-Culture).TextInfo @@ -59,22 +59,13 @@ try { # Setup Summary Header Log-Section "Setup Summary - BrowserStack NOW" Log-Line "Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE - Log-Line "Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE - Log-Line "Selected Testing Type: $TEST_TYPE" $global:NOW_RUN_LOG_FILE - Log-Line "Selected Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE + Log-Line "Log file path: $logFile" $global:NOW_RUN_LOG_FILE # Setup workspace and get credentials BEFORE app upload Setup-Workspace Ask-BrowserStack-Credentials -RunMode $RunMode -UsernameFromEnv $env:BROWSERSTACK_USERNAME -AccessKeyFromEnv $env:BROWSERSTACK_ACCESS_KEY - # NOW handle URL/App upload (requires credentials) - Perform-NextSteps-BasedOnTestType -TestType $TEST_TYPE -RunMode $RunMode -TestUrl $TestUrl -AppPath $AppPath -AppPlatform $AppPlatform - - # Run the setup - Setup-Environment -SetupType $TEST_TYPE.ToLower() -TechStack $TECH_STACK.ToLower() - - # Platform & Tech Stack section Log-Section "Platform & Tech Stack" Log-Line "Platform: $TEST_TYPE" $global:NOW_RUN_LOG_FILE Log-Line "Tech Stack: $TECH_STACK" $global:NOW_RUN_LOG_FILE @@ -85,6 +76,11 @@ try { # Account & Plan Details Fetch-Plan-Details -TestType $TEST_TYPE + # NOW handle URL/App upload (requires credentials) + Perform-NextSteps-BasedOnTestType -TestType $TEST_TYPE -RunMode $RunMode -TestUrl $TestUrl -AppPath $AppPath -AppPlatform $AppPlatform + + + Log-Line "Checking proxy in environment" $global:NOW_RUN_LOG_FILE Set-ProxyInEnv From b8cfde12f18e7c0536aeb56644386d423567c0dc Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:44:49 +0530 Subject: [PATCH 20/32] win mac merge init commit --- common/mac/env-setup-run.sh | 16 +++++++++------- common/win/env-setup-run.ps1 | 16 ++++++++-------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/common/mac/env-setup-run.sh b/common/mac/env-setup-run.sh index 99b2432..4a73d59 100644 --- a/common/mac/env-setup-run.sh +++ b/common/mac/env-setup-run.sh @@ -85,13 +85,15 @@ EOF export BROWSERSTACK_BUILD_NAME="now-$NOW_OS-web-java-testng" export BROWSERSTACK_PROJECT_NAME="now-$NOW_OS-web" + print_env_vars + log_info "Installing dependencies" mvn install -DskipTests >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - print_env_vars - log_info "Running tests..." + + log_section "BrowserStack SDK Test Run Execution" mvn test -P sample-test >> "$NOW_RUN_LOG_FILE" 2>&1 & cmd_pid=$! show_spinner "$cmd_pid" @@ -127,7 +129,7 @@ EOF log_info "Installing dependencies" mvn clean >> "$NOW_RUN_LOG_FILE" 2>&1 || return 1 - log_info "Running tests..." + log_section "BrowserStack SDK Test Run Execution" mvn test -P sample-test >> "$NOW_RUN_LOG_FILE" 2>&1 & cmd_pid=$! show_spinner "$cmd_pid" @@ -158,7 +160,7 @@ EOF print_env_vars - log_info "Running tests..." + log_section "BrowserStack SDK Test Run Execution" browserstack-sdk pytest -s tests/*.py >> "$NOW_RUN_LOG_FILE" 2>&1 & cmd_pid=$! show_spinner "$cmd_pid" @@ -191,7 +193,7 @@ EOF print_env_vars - log_info "Running tests..." + log_section "BrowserStack SDK Test Run Execution" ( cd "$run_dir" && browserstack-sdk pytest -s bstack_sample.py >> "$NOW_RUN_LOG_FILE" 2>&1 ) & @@ -218,7 +220,7 @@ setup_web_nodejs() { print_env_vars - log_info "Running tests..." + log_section "BrowserStack SDK Test Run Execution" npm run test >> "$NOW_RUN_LOG_FILE" 2>&1 & cmd_pid=$! show_spinner "$cmd_pid" @@ -247,7 +249,7 @@ setup_app_nodejs() { print_env_vars - log_info "Running tests..." + log_section "BrowserStack SDK Test Run Execution" npm run test >> "$NOW_RUN_LOG_FILE" 2>&1 & cmd_pid=$! show_spinner "$cmd_pid" diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index b402075..3549ba5 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -102,13 +102,13 @@ function Setup-Web-Java { $env:BROWSERSTACK_BUILD_NAME = "now-windows-web-java-testng" $env:BROWSERSTACK_PROJECT_NAME = "now-windows-web" - Print-Env-Variables - Log-Info "Installing dependencies" $mvn = Get-MavenCommand -RepoDir $TargetDir Invoke-External -Exe $mvn -Arguments @("install","-DskipTests") -LogFile $global:NOW_RUN_LOG_FILE + + Print-Env-Variables - Log-Info "Running tests..." + Log-Section "BrowserStack SDK Test Run Execution" $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() @@ -140,7 +140,7 @@ function Setup-App-Java { $mvn = Get-MavenCommand -RepoDir (Get-Location).Path Invoke-External -Exe $mvn -Arguments @("clean") -LogFile $global:NOW_RUN_LOG_FILE - Log-Info "Running tests..." + Log-Section "BrowserStack SDK Test Run Execution" $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() @@ -166,7 +166,7 @@ function Setup-Web-Python { Print-Env-Variables - Log-Info "Running tests..." + Log-Section "BrowserStack SDK Test Run Execution" $sdkExe = Join-Path $TargetDir ".venv\Scripts\browserstack-sdk.exe" $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","tests/" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow Show-Spinner -Process $p @@ -195,7 +195,7 @@ function Setup-App-Python { Print-Env-Variables - Log-Info "Running tests..." + Log-Section "BrowserStack SDK Test Run Execution" Set-Location $runDir $sdkExe = Join-Path $TargetDir ".venv\Scripts\browserstack-sdk.exe" $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","bstack_sample.py" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow @@ -220,7 +220,7 @@ function Setup-Web-NodeJS { Print-Env-Variables - Log-Info "Running tests..." + Log-Section "BrowserStack SDK Test Run Execution" $npmCmd = Get-Command npm -ErrorAction SilentlyContinue if ($npmCmd.Source.EndsWith(".cmd")) { $exe = "cmd.exe"; $args = @("/c", "npm", "run", "test") } else { $exe = "npm"; $args = @("run", "test") } $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow @@ -246,7 +246,7 @@ function Setup-App-NodeJS { Print-Env-Variables - Log-Info "Running tests..." + Log-Section "BrowserStack SDK Test Run Execution" $npmCmd = Get-Command npm -ErrorAction SilentlyContinue if ($npmCmd.Source.EndsWith(".cmd")) { $exe = "cmd.exe"; $args = @("/c", "npm", "run", "test") } else { $exe = "npm"; $args = @("run", "test") } $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow From f09196b1349f2b0dc81c9597799a71a7464e1988 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:53:02 +0530 Subject: [PATCH 21/32] win mac merge init commit --- common/win/common-utils.ps1 | 10 +++++----- common/win/env-prequisite-checks.ps1 | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index 7468a7f..cae3342 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -342,11 +342,11 @@ function Fetch-Plan-Details { } } - if ($script:IS_SILENT_MODE) { - $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = 5 - $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = 5 - Log-Line "Silent mode: Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)" $global:NOW_RUN_LOG_FILE - } else { + if ($RunMode -match "--silent|--debug") { + $script:TEAM_PARALLELS_MAX_ALLOWED_WEB = 5 + $script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE = 5 + Log-Line "Silent mode: Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)" $global:NOW_RUN_LOG_FILE + } else { Log-Line "Plan summary: Web fetched=$script:WEB_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_WEB), Mobile fetched=$script:MOBILE_PLAN_FETCHED (team max=$script:TEAM_PARALLELS_MAX_ALLOWED_MOBILE)" $global:NOW_RUN_LOG_FILE } diff --git a/common/win/env-prequisite-checks.ps1 b/common/win/env-prequisite-checks.ps1 index 94fd416..2e69c22 100644 --- a/common/win/env-prequisite-checks.ps1 +++ b/common/win/env-prequisite-checks.ps1 @@ -69,8 +69,8 @@ function Check-Java-Installation { Log-Line "Checking if Java runs correctly..." $global:NOW_RUN_LOG_FILE try { - $output = java -version 2>&1 | Out-String - Log-Success "Java installed and functional`n$output" + $output = & cmd /c 'java -version 2>&1' | Out-String + Log-Success "Java installed and functional. \n$output" return $true } catch { Log-Error "Java exists but failed to run." $global:NOW_RUN_LOG_FILE From d445397ecb9b92fc0a8d625f95de97530eef8b93 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 18:55:16 +0530 Subject: [PATCH 22/32] win mac merge init commit --- common/win/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 1593154..71a89ec 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -21,6 +21,7 @@ $script:PSScriptRootResolved = Split-Path -Parent $MyInvocation.MyCommand.Path . (Join-Path $PSScriptRootResolved "user-interaction.ps1") . (Join-Path $PSScriptRootResolved "env-prequisite-checks.ps1") . (Join-Path $PSScriptRootResolved "env-setup-run.ps1") +. (Join-Path $PSScriptRootResolved "device-machine-allocation.ps1") # ===== Main flow (baseline steps then run) ===== @@ -80,7 +81,6 @@ try { Perform-NextSteps-BasedOnTestType -TestType $TEST_TYPE -RunMode $RunMode -TestUrl $TestUrl -AppPath $AppPath -AppPlatform $AppPlatform - Log-Line "Checking proxy in environment" $global:NOW_RUN_LOG_FILE Set-ProxyInEnv From 4385fe6183325cfc424e8482a02da89905c37b27 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 19:01:14 +0530 Subject: [PATCH 23/32] win mac merge init commit --- common/win/env-prequisite-checks.ps1 | 3 ++- common/win/env-setup-run.ps1 | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/common/win/env-prequisite-checks.ps1 b/common/win/env-prequisite-checks.ps1 index 2e69c22..e77599f 100644 --- a/common/win/env-prequisite-checks.ps1 +++ b/common/win/env-prequisite-checks.ps1 @@ -70,7 +70,8 @@ function Check-Java-Installation { Log-Line "Checking if Java runs correctly..." $global:NOW_RUN_LOG_FILE try { $output = & cmd /c 'java -version 2>&1' | Out-String - Log-Success "Java installed and functional. \n$output" + Log-Success "Java installed and functional" + Log-Success "$output" return $true } catch { Log-Error "Java exists but failed to run." $global:NOW_RUN_LOG_FILE diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index 3549ba5..0afd131 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -265,11 +265,11 @@ function Detect-Setup-Python-Env { function Print-Env-Variables { Log-Section "Validate Environment Variables and Platforms" - Log-Info "BrowserStack Username: $BROWSERSTACK_USERNAME" - Log-Info "BrowserStack Project Name: $BROWSERSTACK_PROJECT_NAME" - Log-Info "BrowserStack Build: $BROWSERSTACK_BUILD_NAME" - if ($TEST_TYPE -eq "app") { Log-Info "Native App Endpoint: $BROWSERSTACK_APP" } - Log-Info "BrowserStack Local Flag: $BROWSERSTACK_LOCAL" - Log-Info "Parallels per platform: $BSTACK_PARALLELS" - Log-Info "Platforms: $BSTACK_PLATFORMS" + Log-Info "BrowserStack Username: $env:BROWSERSTACK_USERNAME" + Log-Info "BrowserStack Project Name: $env:BROWSERSTACK_PROJECT_NAME" + Log-Info "BrowserStack Build: $env:BROWSERSTACK_BUILD_NAME" + if ($TEST_TYPE -eq "app") { Log-Info "Native App Endpoint: $env:BROWSERSTACK_APP" } + Log-Info "BrowserStack Local Flag: $env:BROWSERSTACK_LOCAL" + Log-Info "Parallels per platform: $env:BSTACK_PARALLELS" + Log-Info "Platforms: $env:BSTACK_PLATFORMS" } From f3d12672e68f13d792aa5b964d7150b41a2d4ac9 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 19:09:17 +0530 Subject: [PATCH 24/32] win mac merge init commit --- common/win/common-utils.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index cae3342..151974e 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -80,7 +80,7 @@ function Invoke-GitClone { if ($_ -match '\s') { '"{0}"' -f $_ } else { $_ } }) -join ' ' $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $true + $psi.RedirectStandardError = $false $psi.UseShellExecute = $false $psi.CreateNoWindow = $true $psi.WorkingDirectory = (Get-Location).Path @@ -124,7 +124,7 @@ function Invoke-External { } $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $true + $psi.RedirectStandardError = $false $psi.UseShellExecute = $false $psi.CreateNoWindow = $true if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) { From c75c86001ad6d2d2f8647a470eaefced41079b65 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 19:14:37 +0530 Subject: [PATCH 25/32] win mac merge init commit --- common/win/common-utils.ps1 | 4 ++-- common/win/env-setup-run.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index 151974e..cae3342 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -80,7 +80,7 @@ function Invoke-GitClone { if ($_ -match '\s') { '"{0}"' -f $_ } else { $_ } }) -join ' ' $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $false + $psi.RedirectStandardError = $true $psi.UseShellExecute = $false $psi.CreateNoWindow = $true $psi.WorkingDirectory = (Get-Location).Path @@ -124,7 +124,7 @@ function Invoke-External { } $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $false + $psi.RedirectStandardError = $true $psi.UseShellExecute = $false $psi.CreateNoWindow = $true if ([string]::IsNullOrWhiteSpace($WorkingDirectory)) { diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index 0afd131..de28002 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -109,7 +109,7 @@ function Setup-Web-Java { Print-Env-Variables Log-Section "BrowserStack SDK Test Run Execution" - $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE-err" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) From a5a7655989b781159622085174231c220abd9319 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 19:36:25 +0530 Subject: [PATCH 26/32] win mac merge init commit --- common/win/common-utils.ps1 | 3 +-- common/win/env-setup-run.ps1 | 12 ++++++------ common/win/run.ps1 | 5 +++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/common/win/common-utils.ps1 b/common/win/common-utils.ps1 index cae3342..119e961 100644 --- a/common/win/common-utils.ps1 +++ b/common/win/common-utils.ps1 @@ -224,9 +224,8 @@ function Show-Spinner { param([Parameter(Mandatory)][System.Diagnostics.Process]$Process) $spin = @('|','/','-','\') $i = 0 - $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") while (!$Process.HasExited) { - Write-Host "`r[$ts] Processing... $($spin[$i])" -NoNewline -ForegroundColor Cyan + Write-Host "`rProcessing... $($spin[$i])" -NoNewline -ForegroundColor Cyan $i = ($i + 1) % 4 Start-Sleep -Milliseconds 100 } diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index de28002..d1e26c9 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -109,7 +109,7 @@ function Setup-Web-Java { Print-Env-Variables Log-Section "BrowserStack SDK Test Run Execution" - $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE-err" -PassThru -NoNewWindow + $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE_ERR" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) @@ -141,7 +141,7 @@ function Setup-App-Java { Invoke-External -Exe $mvn -Arguments @("clean") -LogFile $global:NOW_RUN_LOG_FILE Log-Section "BrowserStack SDK Test Run Execution" - $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + $p = Start-Process -FilePath $mvn -ArgumentList "test","-P","sample-test" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE_ERR" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) @@ -168,7 +168,7 @@ function Setup-Web-Python { Log-Section "BrowserStack SDK Test Run Execution" $sdkExe = Join-Path $TargetDir ".venv\Scripts\browserstack-sdk.exe" - $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","tests/" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","tests/" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE_ERR" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) @@ -198,7 +198,7 @@ function Setup-App-Python { Log-Section "BrowserStack SDK Test Run Execution" Set-Location $runDir $sdkExe = Join-Path $TargetDir ".venv\Scripts\browserstack-sdk.exe" - $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","bstack_sample.py" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + $p = Start-Process -FilePath $sdkExe -ArgumentList "pytest","-s","bstack_sample.py" -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE_ERR" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) @@ -223,7 +223,7 @@ function Setup-Web-NodeJS { Log-Section "BrowserStack SDK Test Run Execution" $npmCmd = Get-Command npm -ErrorAction SilentlyContinue if ($npmCmd.Source.EndsWith(".cmd")) { $exe = "cmd.exe"; $args = @("/c", "npm", "run", "test") } else { $exe = "npm"; $args = @("run", "test") } - $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE_ERR" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) @@ -249,7 +249,7 @@ function Setup-App-NodeJS { Log-Section "BrowserStack SDK Test Run Execution" $npmCmd = Get-Command npm -ErrorAction SilentlyContinue if ($npmCmd.Source.EndsWith(".cmd")) { $exe = "cmd.exe"; $args = @("/c", "npm", "run", "test") } else { $exe = "npm"; $args = @("run", "test") } - $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError $global:NOW_RUN_LOG_FILE -PassThru -NoNewWindow + $p = Start-Process -FilePath $exe -ArgumentList $args -RedirectStandardOutput $global:NOW_RUN_LOG_FILE -RedirectStandardError "$global:NOW_RUN_LOG_FILE_ERR" -PassThru -NoNewWindow Show-Spinner -Process $p $p.WaitForExit() return ($p.ExitCode -eq 0) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 71a89ec..5547703 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -47,13 +47,17 @@ try { # Setup log file path AFTER selections $logFileName = "{0}_{1}_run_result.log" -f $TEST_TYPE.ToLowerInvariant(), $TECH_STACK.ToLowerInvariant() + $errLogFileName = "{0}_{1}_run_result_err.log" -f $TEST_TYPE.ToLowerInvariant(), $TECH_STACK.ToLowerInvariant() $logFile = Join-Path $script:LOG_DIR $logFileName + $errLogFile = Join-Path $script:LOG_DIR $errLogFileName if (!(Test-Path $script:LOG_DIR)) { New-Item -ItemType Directory -Path $script:LOG_DIR -Force | Out-Null } '' | Out-File -FilePath $logFile -Encoding UTF8 + '' | Out-File -FilePath $errLogFile -Encoding UTF8 $script:GLOBAL_LOG = $logFile $global:NOW_RUN_LOG_FILE = $logFile + $global:NOW_RUN_LOG_FILE_ERR = $errLogFile Log-Line "Log file path: $logFile" $global:NOW_RUN_LOG_FILE @@ -62,6 +66,7 @@ try { Log-Line "Timestamp: $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $global:NOW_RUN_LOG_FILE Log-Line "Run Mode: $RunMode" $global:NOW_RUN_LOG_FILE Log-Line "Log file path: $logFile" $global:NOW_RUN_LOG_FILE + Log-Line "Error log file path: $errLogFile" $global:NOW_RUN_LOG_FILE # Setup workspace and get credentials BEFORE app upload Setup-Workspace From 64a2e7119fb79ed0d1abb6cccf3c2cfd17ea4a94 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 20:02:39 +0530 Subject: [PATCH 27/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 63 ++++++++++-------------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index 41d1c14..40c5ca7 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -294,56 +294,35 @@ jobs: ) $overallFailed = $false + $logRoot = Join-Path $env:TEMP "now-tests" New-Item -ItemType Directory -Force -Path $logRoot | Out-Null - $logPath = Join-Path $logRoot "run_test_app_nodejs.log" - - Write-Host "================================" - Write-Host "Testing: $scriptPath --silent app nodejs" - Write-Host "================================" - & $scriptPath --silent app nodejs 2>&1 | Tee-Object -FilePath $logPath -Append - $exitCode = $LASTEXITCODE + foreach ($config in $testConfigs) { + $testType = $config[0] + $techStack = $config[1] - if ($exitCode -eq 0) { - Write-Host "✅ app / nodejs completed (exit code: $exitCode)" - } else { - Write-Host "⚠️ app / nodejs exited with code: $exitCode" - if (Test-Path $logPath) { - Write-Host "Log output (last 20 lines):" - Get-Content -Path $logPath -Tail 20 - } - exit 1 - } + Write-Host "================================" + Write-Host "Testing: $scriptPath --silent $testType $techStack" + Write-Host "================================" - # $logRoot = Join-Path $env:TEMP "now-tests" - # New-Item -ItemType Directory -Force -Path $logRoot | Out-Null + $logPath = Join-Path $logRoot "run_test_${testType}_${techStack}.log" - # foreach ($config in $testConfigs) { - # $testType = $config[0] - # $techStack = $config[1] + & $scriptPath --silent $testType $techStack 2>&1 | Tee-Object -FilePath $logPath -Append + $exitCode = $LASTEXITCODE - # Write-Host "================================" - # Write-Host "Testing: $scriptPath --silent $testType $techStack" - # Write-Host "================================" + if ($exitCode -eq 0) { + Write-Host "✅ $testType / $techStack completed (exit code: $exitCode)" + } else { + Write-Host "⚠️ $testType / $techStack exited with code: $exitCode" + $overallFailed = $true - # $logPath = Join-Path $logRoot "run_test_${testType}_${techStack}.log" - - # & $scriptPath --silent $testType $techStack 2>&1 | Tee-Object -FilePath $logPath -Append - # $exitCode = $LASTEXITCODE - - # if ($exitCode -eq 0) { - # Write-Host "✅ $testType / $techStack completed (exit code: $exitCode)" - # } else { - # Write-Host "⚠️ $testType / $techStack exited with code: $exitCode" - # $overallFailed = $true - - # if (Test-Path $logPath) { - # Write-Host "Log output (last 20 lines):" - # Get-Content -Path $logPath -Tail 20 - # } - # } - # } + if (Test-Path $logPath) { + Write-Host "Log output (last 20 lines):" + Get-Content -Path $logPath -Tail 20 + } + } + } if ($overallFailed) { Write-Error "One or more configurations failed." From 16bd696ddea0186110548883a8506007329c8dac Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 20:44:23 +0530 Subject: [PATCH 28/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 15 +++++++++++++-- common/config/repos.txt | 12 ++++++------ common/win/env-setup-run.ps1 | 11 +++++++++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index 40c5ca7..b9d977c 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -308,8 +308,19 @@ jobs: $logPath = Join-Path $logRoot "run_test_${testType}_${techStack}.log" - & $scriptPath --silent $testType $techStack 2>&1 | Tee-Object -FilePath $logPath -Append - $exitCode = $LASTEXITCODE + # Run with timeout (600 seconds) + $p = Start-Process -FilePath "pwsh" -ArgumentList "-File", $scriptPath, "--silent", $testType, $techStack -RedirectStandardOutput $logPath -RedirectStandardError $logPath -PassThru -NoNewWindow + + # Wait for 600 seconds (600000 ms) + $exited = $p.WaitForExit(600000) + + if (-not $exited) { + Write-Host "⚠️ $testType / $techStack timed out after 600 seconds" + $p.Kill() + $exitCode = 124 + } else { + $exitCode = $p.ExitCode + } if ($exitCode -eq 0) { Write-Host "✅ $testType / $techStack completed (exit code: $exitCode)" diff --git a/common/config/repos.txt b/common/config/repos.txt index a040489..f57e9e6 100644 --- a/common/config/repos.txt +++ b/common/config/repos.txt @@ -1,6 +1,6 @@ -web_java|now-testng-browserstack -app_java|now-testng-appium-app-browserstack -web_python|now-pytest-browserstack -app_python|now-pytest-appium-app-browserstack -web_nodejs|now-webdriverio-browserstack -app_nodejs|now-webdriverio-appium-app-browserstack +web_java|now-testng-browserstack| +app_java|now-testng-appium-app-browserstack| +web_python|now-pytest-browserstack| +app_python|now-pytest-appium-app-browserstack| +web_nodejs|now-webdriverio-browserstack| +app_nodejs|now-webdriverio-appium-app-browserstack| diff --git a/common/win/env-setup-run.ps1 b/common/win/env-setup-run.ps1 index d1e26c9..8ffa4f4 100644 --- a/common/win/env-setup-run.ps1 +++ b/common/win/env-setup-run.ps1 @@ -151,7 +151,11 @@ function Setup-Web-Python { param($TargetDir, $Parallels) Set-Location $TargetDir Detect-Setup-Python-Env - Invoke-Py -Arguments @("-m","pip","install","--only-binary","grpcio","-r","requirements.txt") -LogFile $global:NOW_RUN_LOG_FILE + + $pyExe = $script:PY_CMD[0] + Log-Line "ℹ️ Installing dependencies" $global:NOW_RUN_LOG_FILE + [void](Invoke-External -Exe $pyExe -Arguments @("-m","pip","install","-r","requirements.txt") -LogFile $global:NOW_RUN_LOG_FILE -WorkingDirectory $TargetDir) + Log-Line "✅ Dependencies installed" $global:NOW_RUN_LOG_FILE $configFile = Join-Path $TargetDir "browserstack.yml" $platformYaml = Generate-Web-Platforms -MaxTotalParallels $script:TEAM_PARALLELS_MAX_ALLOWED_WEB -Format "yaml" @@ -178,7 +182,10 @@ function Setup-App-Python { param($TargetDir, $Parallels) Set-Location $TargetDir Detect-Setup-Python-Env - Invoke-Py -Arguments @("-m","pip","install","--only-binary","grpcio","-r","requirements.txt") -LogFile $global:NOW_RUN_LOG_FILE + $pyExe = $script:PY_CMD[0] + Log-Line "ℹ️ Installing dependencies" $global:NOW_RUN_LOG_FILE + [void](Invoke-External -Exe $pyExe -Arguments @("-m","pip","install","-r","requirements.txt") -LogFile $global:NOW_RUN_LOG_FILE -WorkingDirectory $TargetDir) + Log-Line "✅ Dependencies installed" $global:NOW_RUN_LOG_FILE $runDir = "android" if ($script:APP_PLATFORM -eq "ios") { $runDir = "ios" } From 0fe7dc65b52dbfe13eea136b817e956de6b5ca51 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 20:47:45 +0530 Subject: [PATCH 29/32] win mac merge init commit --- common/win/run.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/win/run.ps1 b/common/win/run.ps1 index 5547703..96df2f5 100644 --- a/common/win/run.ps1 +++ b/common/win/run.ps1 @@ -94,8 +94,6 @@ try { Log-Line "Detected Operating system: Windows" $global:NOW_RUN_LOG_FILE Log-Line "Clearing old logs from NOW Home Directory inside .browserstack" $global:NOW_RUN_LOG_FILE Clear-OldLogs - - Log-Line "Starting $TEST_TYPE setup for $TECH_STACK" $global:NOW_RUN_LOG_FILE # Run the setup Setup-Environment -SetupType $TEST_TYPE.ToLower() -TechStack $TECH_STACK.ToLower() From b496873fb2f711ed5c3671e5c0e417cbc3a3f8b8 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 20:53:40 +0530 Subject: [PATCH 30/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index b9d977c..54a082c 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -285,8 +285,6 @@ jobs: $scriptPath = Join-Path $env:GITHUB_WORKSPACE "win\run.ps1" $testConfigs = @( - @("web", "java"), - @("app", "java"), @("web", "python"), @("app", "python"), @("web", "nodejs"), From 0609a1e050103c38da764849b10144e3e391d7b1 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 21:00:57 +0530 Subject: [PATCH 31/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index 54a082c..ddcc599 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -305,9 +305,10 @@ jobs: Write-Host "================================" $logPath = Join-Path $logRoot "run_test_${testType}_${techStack}.log" + $logPathErr = Join-Path $logRoot "run_test_${testType}_${techStack}.err" # Run with timeout (600 seconds) - $p = Start-Process -FilePath "pwsh" -ArgumentList "-File", $scriptPath, "--silent", $testType, $techStack -RedirectStandardOutput $logPath -RedirectStandardError $logPath -PassThru -NoNewWindow + $p = Start-Process -FilePath "pwsh" -ArgumentList "-File", $scriptPath, "--silent", $testType, $techStack -RedirectStandardOutput $logPath -RedirectStandardError $logPathErr -PassThru -NoNewWindow # Wait for 600 seconds (600000 ms) $exited = $p.WaitForExit(600000) @@ -331,6 +332,11 @@ jobs: Get-Content -Path $logPath -Tail 20 } } + + if (Test-Path $logPathErr) { + Write-Host "Error output (last 20 lines):" + Get-Content -Path $logPathErr -Tail 20 + } } if ($overallFailed) { From ea595eb40c59e396970e124e5c658b82ea32c823 Mon Sep 17 00:00:00 2001 From: Samiran Saha Date: Sat, 6 Dec 2025 21:08:21 +0530 Subject: [PATCH 32/32] win mac merge init commit --- .github/workflows/test-scripts.yml | 66 ++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index ddcc599..26677fb 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -200,7 +200,7 @@ jobs: - name: Check PowerShell version run: | $PSVersionTable.PSVersion - Write-Host "✅ PowerShell version check complete" + Write-Host "PowerShell version check complete" - name: Validate PowerShell script syntax run: | @@ -209,7 +209,7 @@ jobs: $null = [System.Management.Automation.PSParser]::Tokenize((Get-Content -Raw $ScriptPath), [ref]$null) $CommonScriptPath = "common/win/run.ps1" $null = [System.Management.Automation.PSParser]::Tokenize((Get-Content -Raw $CommonScriptPath), [ref]$null) - Write-Host "✅ win/run.ps1 syntax is valid" + Write-Host "win/run.ps1 syntax is valid" - name: Validate supporting PowerShell scripts syntax run: | @@ -224,7 +224,7 @@ jobs: ) foreach ($Script in $Scripts) { $null = [System.Management.Automation.PSParser]::Tokenize((Get-Content -Raw $Script), [ref]$null) - Write-Host "✅ $Script syntax is valid" + Write-Host "$Script syntax is valid" } - name: Run PSScriptAnalyzer @@ -236,7 +236,7 @@ jobs: Write-Host "Running PSScriptAnalyzer..." Invoke-ScriptAnalyzer -Path "win" -Recurse -ReportSummary -ErrorAction Continue - Write-Host "✅ PSScriptAnalyzer analysis complete (continuing even if issues are found)" + Write-Host "PSScriptAnalyzer analysis complete (continuing even if issues are found)" - name: Check script file encoding run: | @@ -254,14 +254,14 @@ jobs: } Write-Host "Detected encoding (heuristic): $encoding" - Write-Host "✅ Encoding check complete" + Write-Host "Encoding check complete" - name: Verify required dependencies run: | Write-Host "Checking required dependencies..." - if (Get-Command curl.exe -ErrorAction SilentlyContinue) { Write-Host "✅ curl found" } else { Write-Host "⚠️ curl not found" } - if (Get-Command git.exe -ErrorAction SilentlyContinue) { Write-Host "✅ git found" } else { Write-Host "⚠️ git not found" } - Write-Host "✅ PowerShell dependencies verified" + if (Get-Command curl.exe -ErrorAction SilentlyContinue) { Write-Host "curl found" } else { Write-Host "⚠️ curl not found" } + if (Get-Command git.exe -ErrorAction SilentlyContinue) { Write-Host "git found" } else { Write-Host "⚠️ git not found" } + Write-Host "PowerShell dependencies verified" - name: Integration Test - Silent Mode Execution if: success() @@ -284,6 +284,28 @@ jobs: # Absolute path is safer in CI $scriptPath = Join-Path $env:GITHUB_WORKSPACE "win\run.ps1" + $logRoot = Join-Path $env:TEMP "now-tests" + New-Item -ItemType Directory -Force -Path $logRoot | Out-Null + $logPath = Join-Path $logRoot "run_test_web_python.log" + + Write-Host "================================" + Write-Host "Testing: $scriptPath --silent web python" + Write-Host "================================" + + & $scriptPath --silent web python 2>&1 | Tee-Object -FilePath $logPath -Append + $exitCode = $LASTEXITCODE + + if ($exitCode -eq 0) { + Write-Host "web / python completed (exit code: $exitCode)" + } else { + Write-Host "web / python exited with code: $exitCode" + if (Test-Path $logPath) { + Write-Host "Log output (last 20 lines):" + Get-Content -Path $logPath -Tail 20 + } + exit 1 + } + $testConfigs = @( @("web", "python"), @("app", "python"), @@ -314,7 +336,7 @@ jobs: $exited = $p.WaitForExit(600000) if (-not $exited) { - Write-Host "⚠️ $testType / $techStack timed out after 600 seconds" + Write-Host "$testType / $techStack timed out after 600 seconds" $p.Kill() $exitCode = 124 } else { @@ -322,9 +344,9 @@ jobs: } if ($exitCode -eq 0) { - Write-Host "✅ $testType / $techStack completed (exit code: $exitCode)" + Write-Host "$testType / $techStack completed (exit code: $exitCode)" } else { - Write-Host "⚠️ $testType / $techStack exited with code: $exitCode" + Write-Host "$testType / $techStack exited with code: $exitCode" $overallFailed = $true if (Test-Path $logPath) { @@ -344,7 +366,7 @@ jobs: exit 1 } - Write-Host "✅ All integration tests completed successfully" + Write-Host "All integration tests completed successfully" - name: Sync BrowserStack logs to workspace (Windows) if: always() @@ -399,7 +421,7 @@ jobs: echo "Validating mac/run.sh syntax..." bash -n mac/run.sh bash -n common/mac/run.sh - echo "✅ mac/run.sh syntax is valid" + echo "mac/run.sh syntax is valid" - name: Validate supporting scripts syntax run: | @@ -409,7 +431,7 @@ jobs: bash -n common/mac/env-setup-run.sh bash -n common/mac/user-interaction.sh bash -n common/mac/env-prequisite-checks.sh - echo "✅ All supporting scripts are valid" + echo "All supporting scripts are valid" - name: Check if scripts are executable run: | @@ -419,7 +441,7 @@ jobs: chmod +x common/mac/env-setup-run.sh chmod +x common/mac/user-interaction.sh chmod +x common/mac/env-prequisite-checks.sh - echo "✅ All scripts are executable" + echo "All scripts are executable" - name: Install ShellCheck run: | @@ -438,23 +460,23 @@ jobs: shellcheck -x common/mac/env-setup-run.sh || true shellcheck -x common/mac/user-interaction.sh || true shellcheck -x common/mac/env-prequisite-checks.sh || true - echo "✅ ShellCheck analysis complete" + echo "ShellCheck analysis complete" - name: Verify required dependencies run: | echo "Checking required dependencies..." - command -v bash && echo "✅ bash found" - command -v curl && echo "✅ curl found" - command -v git && echo "✅ git found" - command -v bc && echo "✅ bc found" + command -v bash && echo "bash found" + command -v curl && echo "curl found" + command -v git && echo "git found" + command -v bc && echo "bc found" echo "All required dependencies are available" - name: Test script sourcing (dry run) run: | set -e echo "Testing script sourcing..." - bash -c "source common/mac/common-utils.sh && echo '✅ common-utils.sh sourced successfully'" - echo "✅ Script sourcing successful" + bash -c "source common/mac/common-utils.sh && echo 'common-utils.sh sourced successfully'" + echo "Script sourcing successful" - name: Integration Test - Silent Mode Execution if: success()