diff --git a/.github/configs/labeler.yml b/.github/configs/labeler.yml index 72f7f97ee..da87fd831 100644 --- a/.github/configs/labeler.yml +++ b/.github/configs/labeler.yml @@ -1,12 +1,18 @@ documentation: - - all: ["*.md"] + - changed-files: + - any-glob-to-any-file: "*.md" Core: - - .github/**/* - - .husky/**/* - - data/**/* - - scripts/**/* + - changed-files: + - any-glob-to-any-file: + - .github/**/* + - .husky/**/* + - data/**/* + - scripts/**/* Widget: - - packages/**/*-native*/**/* - - packages/**/*_native*/**/* + - changed-files: + - any-glob-to-any-file: + - packages/**/*-native*/**/* + - packages/**/*_native*/**/* test: - - all: ["*.spec.*"] + - changed-files: + - any-glob-to-any-file: "*.spec.*" diff --git a/.github/workflows/PullRequestLabeler.yml b/.github/workflows/PullRequestLabeler.yml index 170b785fb..7f78dcabd 100644 --- a/.github/workflows/PullRequestLabeler.yml +++ b/.github/workflows/PullRequestLabeler.yml @@ -2,10 +2,21 @@ name: "Pull Request Labeler" on: - pull_request_target +permissions: + contents: read + pull-requests: write + jobs: triage: runs-on: ubuntu-latest steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + sparse-checkout: | + .github/configs/labeler.yml + sparse-checkout-cone-mode: false - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 with: repo-token: ${{ secrets.GH_PAT }} diff --git a/maestro/helpers/helpers.sh b/maestro/helpers/helpers.sh index 742855f5c..bcbd6b002 100644 --- a/maestro/helpers/helpers.sh +++ b/maestro/helpers/helpers.sh @@ -2,6 +2,101 @@ MAX_RETRIES=3 RETRY_DELAY=10 +SESSION_REUSE_DIR="" + +resolve_maestro_bin() { + if [ -n "${MAESTRO_BIN:-}" ]; then + echo "$MAESTRO_BIN" + elif [ -x "$HOME/.local/bin/maestro/bin/maestro" ]; then + echo "$HOME/.local/bin/maestro/bin/maestro" + elif command -v maestro >/dev/null 2>&1; then + command -v maestro + else + echo "maestro" + fi +} + +maestro_precondition_path() { + echo "$SCRIPT_DIR/Precondition.yaml" +} + +prepare_suite_session_reuse() { + local precondition_src precondition_dst + precondition_src=$(maestro_precondition_path) + [ -f "$precondition_src" ] || { echo "Missing Maestro precondition: $precondition_src"; return 1; } + + if [ -z "$SESSION_REUSE_DIR" ]; then + SESSION_REUSE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/native-widgets-maestro-session-reuse.XXXXXX") + fi + precondition_dst="$SESSION_REUSE_DIR/Precondition.yaml" + + python3 - "$precondition_src" "$precondition_dst" <<'PY' +import pathlib +import sys + +source_path = pathlib.Path(sys.argv[1]) +dest_path = pathlib.Path(sys.argv[2]) +content = source_path.read_text(encoding="utf-8") +updated = content.replace("clearState: true", "clearState: false", 1) +if updated == content: + raise SystemExit("Precondition.yaml does not contain 'clearState: true'") +dest_path.write_text(updated, encoding="utf-8") +PY +} + +rewrite_test_for_session_reuse() { + local source_file="$1" + local file_hash output_file + file_hash=$(python3 - "$source_file" <<'PY' +import hashlib +import sys + +print(hashlib.sha256(sys.argv[1].encode("utf-8")).hexdigest()) +PY +) + output_file="$SESSION_REUSE_DIR/${file_hash}.yaml" + + python3 - "$source_file" "$output_file" <<'PY' +import pathlib +import re +import sys + +source_path = pathlib.Path(sys.argv[1]) +dest_path = pathlib.Path(sys.argv[2]) +content = source_path.read_text(encoding="utf-8") +updated, replacements = re.subn( + r'(^\s*file:\s*["\']).*Precondition\.yaml(["\']\s*$)', + r'\1Precondition.yaml\2', + content, + count=1, + flags=re.MULTILINE, +) +if replacements == 0: + raise SystemExit(f"No Precondition.yaml reference found in {source_path}") +dest_path.write_text(updated, encoding="utf-8") +PY + + echo "$output_file" +} + +stop_test_session() { + if [ "$PLATFORM" == "ios" ]; then + xcrun simctl terminate "${DEVICE_ID:-booted}" "$APP_ID" >/dev/null 2>&1 || true + else + if [ -n "${DEVICE_ID:-}" ]; then + adb -s "$DEVICE_ID" shell am force-stop "$APP_ID" >/dev/null 2>&1 || true + else + adb shell am force-stop "$APP_ID" >/dev/null 2>&1 || true + fi + fi +} + +run_maestro_test() { + local yaml_test_file="$1" + local maestro_bin + maestro_bin=$(resolve_maestro_bin) + "$maestro_bin" test --env APP_ID="$APP_ID" --env PLATFORM="$PLATFORM" --env MAESTRO_DRIVER_STARTUP_TIMEOUT=300000 "$yaml_test_file" +} # Function to restart the iOS simulator restart_simulator() { @@ -61,19 +156,31 @@ ensure_emulator_ready() { # Function to run tests run_tests() { local test_files=("$@") + local test_index=0 + + prepare_suite_session_reuse || return 1 + for yaml_test_file in "${test_files[@]}"; do - echo "๐Ÿงช Testing: $yaml_test_file" + test_index=$((test_index + 1)) + local effective_test_file="$yaml_test_file" + if [ "$test_index" -eq 1 ]; then + echo "๐Ÿงช Testing: $yaml_test_file (clean app state)" + else + effective_test_file=$(rewrite_test_for_session_reuse "$yaml_test_file") || return 1 + echo "๐Ÿงช Testing: $yaml_test_file (reused session)" + fi if [ "$PLATFORM" == "android" ]; then ensure_emulator_ready set_status_bar fi - if $HOME/.local/bin/maestro/bin/maestro test --env APP_ID=$APP_ID --env PLATFORM=$PLATFORM --env MAESTRO_DRIVER_STARTUP_TIMEOUT=300000 "$yaml_test_file"; then + if run_maestro_test "$effective_test_file"; then echo "โœ… Test passed: $yaml_test_file" passed_tests+=("$yaml_test_file") else echo "โŒ Test failed: $yaml_test_file" failed_tests+=("$yaml_test_file") fi + stop_test_session completed_tests=$((completed_tests + 1)) remaining_tests=$((total_tests - completed_tests)) echo "๐Ÿ“Š Progress: $completed_tests/$total_tests tests completed, $remaining_tests tests remaining. โœ… ${#passed_tests[@]} passed, โŒ ${#failed_tests[@]} failed." @@ -95,7 +202,7 @@ rerun_failed_tests() { fi local attempt=0 while [ $attempt -lt $MAX_RETRIES ]; do - if $HOME/.local/bin/maestro/bin/maestro test --env APP_ID=$APP_ID --env PLATFORM=$PLATFORM --env MAESTRO_DRIVER_STARTUP_TIMEOUT=300000 "$yaml_test_file"; then + if run_maestro_test "$yaml_test_file"; then echo "โœ… Test passed: $yaml_test_file" passed_tests+=("$yaml_test_file") break @@ -110,6 +217,7 @@ rerun_failed_tests() { fi fi done + stop_test_session echo "๐Ÿ“Š Retry Progress: $retry_count/$total_retries tests completed, ${#passed_tests[@]} passed, ${#final_failed_tests[@]} failed." done } \ No newline at end of file diff --git a/maestro/run_maestro_jsactions_tests.sh b/maestro/run_maestro_jsactions_tests.sh index 204c5c59e..e5885a331 100644 --- a/maestro/run_maestro_jsactions_tests.sh +++ b/maestro/run_maestro_jsactions_tests.sh @@ -43,6 +43,9 @@ run_jsactions_tests() { return 0 fi + total_tests=${#all_yaml_files[@]} + completed_tests=0 + passed_tests=() failed_tests=() final_failed_tests=() diff --git a/maestro/run_maestro_jsactions_tests_local.sh b/maestro/run_maestro_jsactions_tests_local.sh index b0a351205..f671199ad 100644 --- a/maestro/run_maestro_jsactions_tests_local.sh +++ b/maestro/run_maestro_jsactions_tests_local.sh @@ -1,7 +1,13 @@ #!/bin/bash -# Update DEVICE_ID and path to the yaml file according to needs -# Use command like: ./run_maestro_tests_local.sh android/ios proggress-circle-native +# Update DEVICE_ID according to needs +# Use command like: ./run_maestro_jsactions_tests_local.sh android/ios mobile-resources-native + +SCRIPT_DIR=$(dirname "$0") + +source "$SCRIPT_DIR/helpers/helpers.sh" || { echo "Failed to source helpers.sh"; exit 1; } + +command -v run_tests >/dev/null 2>&1 || { echo "run_tests function not found"; exit 1; } if [ "$1" == "android" ]; then APP_ID="com.mendix.nativetemplate" @@ -17,6 +23,10 @@ else fi ACTION=${2:-*-native} +passed_tests=() +failed_tests=() +final_failed_tests=() +completed_tests=0 # Determine the search path based on the widget selection if [ "$ACTION" == "*-native" ]; then @@ -25,8 +35,14 @@ else search_path="../packages/jsActions/$ACTION" fi -# Find all .yaml files under the determined search path, excluding platform-specific files -for yaml_test_file in $(find $search_path -type f -path "*/maestro/*.yaml" ! -name "*_ios.yaml" ! -name "*_android.yaml"); do - echo "Running test: $yaml_test_file" - maestro --device $DEVICE_ID test --env APP_ID=$APP_ID --env PLATFORM=$PLATFORM "$yaml_test_file" -done \ No newline at end of file +yaml_test_files=() +while IFS= read -r yaml_test_file; do + yaml_test_files+=("$yaml_test_file") +done < <(find "$search_path" -type f -path "*/maestro/*.yaml" ! -name "*_ios.yaml" ! -name "*_android.yaml" | sort) +total_tests=${#yaml_test_files[@]} + +[ "$total_tests" -gt 0 ] || { echo "No Maestro YAML tests found in $search_path"; exit 0; } + +run_tests "${yaml_test_files[@]}" + +[ ${#failed_tests[@]} -eq 0 ] || exit 1 \ No newline at end of file diff --git a/maestro/run_maestro_widget_tests_local.sh b/maestro/run_maestro_widget_tests_local.sh index a184c00cd..5d9bbb924 100644 --- a/maestro/run_maestro_widget_tests_local.sh +++ b/maestro/run_maestro_widget_tests_local.sh @@ -1,7 +1,13 @@ #!/bin/bash -# Update DEVICE_ID and path to the yaml file according to needs -# Use command like: ./run_maestro_tests_local.sh android/ios proggress-circle-native +# Update DEVICE_ID according to needs +# Use command like: ./run_maestro_widget_tests_local.sh android/ios progress-circle-native + +SCRIPT_DIR=$(dirname "$0") + +source "$SCRIPT_DIR/helpers/helpers.sh" || { echo "Failed to source helpers.sh"; exit 1; } + +command -v run_tests >/dev/null 2>&1 || { echo "run_tests function not found"; exit 1; } if [ "$1" == "android" ]; then APP_ID="com.mendix.nativetemplate" @@ -17,6 +23,10 @@ else fi WIDGET=${2:-*-native} +passed_tests=() +failed_tests=() +final_failed_tests=() +completed_tests=0 # Determine the search path based on the widget selection if [ "$WIDGET" == "*-native" ]; then @@ -25,8 +35,14 @@ else search_path="../packages/pluggableWidgets/$WIDGET" fi -# Find all .yaml files under the determined search path, excluding platform-specific files -for yaml_test_file in $(find $search_path -type f -path "*/maestro/*.yaml" ! -name "*_ios.yaml" ! -name "*_android.yaml"); do - echo "Running test: $yaml_test_file" - maestro --device $DEVICE_ID test --env APP_ID=$APP_ID --env PLATFORM=$PLATFORM "$yaml_test_file" -done \ No newline at end of file +yaml_test_files=() +while IFS= read -r yaml_test_file; do + yaml_test_files+=("$yaml_test_file") +done < <(find "$search_path" -type f -path "*/maestro/*.yaml" ! -name "*_ios.yaml" ! -name "*_android.yaml" | sort) +total_tests=${#yaml_test_files[@]} + +[ "$total_tests" -gt 0 ] || { echo "No Maestro YAML tests found in $search_path"; exit 0; } + +run_tests "${yaml_test_files[@]}" + +[ ${#failed_tests[@]} -eq 0 ] || exit 1 \ No newline at end of file