diff --git a/.github/actions/archive-test-results/action.yaml b/.github/actions/archive-test-results/action.yaml new file mode 100644 index 000000000..e3ec9f8a0 --- /dev/null +++ b/.github/actions/archive-test-results/action.yaml @@ -0,0 +1,40 @@ +name: Archive Test Results +description: Archive runtime logs, screenshots, and artifacts from test runs +inputs: + platform: + description: Platform (android or ios) + required: true + test-type: + description: Test type (widget name or js-actions) + required: true + workspace-path: + description: Workspace path for artifacts + required: false + default: ${{ github.workspace }} + +runs: + using: composite + steps: + - name: Archive runtime logs + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 + if: always() + with: + name: ${{ inputs.platform }}-runtime-logs-${{ inputs.test-type }} + path: log/*.log + if-no-files-found: ignore + + - name: Archive test screenshots + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 + if: always() + with: + name: ${{ inputs.platform }}-screenshots-${{ inputs.test-type }} + path: ${{ inputs.workspace-path }}/maestro/images/actual/${{ inputs.platform }}/**/*.png + if-no-files-found: ignore + + - name: Archive artifacts + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 + if: always() + with: + name: ${{ inputs.platform }}-artifacts-${{ inputs.test-type }} + path: packages/pluggableWidgets/**/artifacts/ + if-no-files-found: ignore \ No newline at end of file diff --git a/.github/actions/create-native-bundle/action.yml b/.github/actions/create-native-bundle/action.yml index 91dd7f185..4ae5ea850 100644 --- a/.github/actions/create-native-bundle/action.yml +++ b/.github/actions/create-native-bundle/action.yml @@ -16,20 +16,23 @@ runs: apt install curl -y shell: bash - name: "Download test project" - run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/main.zip + run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/mx-version/10.zip shell: bash - name: "Extract test project" uses: montudor/action-zip@v1.0.0 with: args: unzip -qq project.zip + - name: "Rename extracted directory" + run: mv Native-Mobile-Resources-mx-version-10 Native-Mobile-Resources-mx10 + shell: bash - name: "Extract deployment package" uses: montudor/action-zip@v1.0.0 with: - args: unzip -qq ${{ inputs.mda-file }} -d Native-Mobile-Resources-main/deployment + args: unzip -qq ${{ inputs.mda-file }} -d Native-Mobile-Resources-mx10/deployment - name: "Create bundle for ${{ inputs.platform }}" run: | mkdir -p ${{ inputs.platform }}/assets - cd Native-Mobile-Resources-main/deployment/native && \ + cd Native-Mobile-Resources-mx10/deployment/native && \ /tmp/mxbuild/modeler/tools/node/linux-x64/node \ /tmp/mxbuild/modeler/tools/node/node_modules/react-native/cli.js \ bundle --verbose --platform ${{ inputs.platform }} --dev false \ diff --git a/.github/actions/setup-maestro/action.yaml b/.github/actions/setup-maestro/action.yaml new file mode 100644 index 000000000..ca316aee2 --- /dev/null +++ b/.github/actions/setup-maestro/action.yaml @@ -0,0 +1,21 @@ +name: "Setup Maestro" +description: "Install and cache Maestro" +runs: + using: "composite" + steps: + - name: "Cache Maestro" + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 + with: + path: $HOME/.local/bin/maestro + key: maestro-${{ runner.os }}-v1 + + - name: "Install Maestro" + shell: bash + run: | + if [ ! -f "$HOME/.local/bin/maestro/bin/maestro" ]; then + mkdir -p $HOME/.local/bin + curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip + unzip maestro.zip -d $HOME/.local/bin + chmod +x $HOME/.local/bin/maestro/bin/maestro + fi + echo "$HOME/.local/bin" >> $GITHUB_PATH \ No newline at end of file diff --git a/.github/actions/setup-node-with-cache/action.yaml b/.github/actions/setup-node-with-cache/action.yaml new file mode 100644 index 000000000..719b600dd --- /dev/null +++ b/.github/actions/setup-node-with-cache/action.yaml @@ -0,0 +1,30 @@ +name: 'Setup Node with Cached Dependencies' +description: 'Set up Node.js and install dependencies with caching' +runs: + using: 'composite' + steps: + - name: "Set up node" + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 + with: + node-version-file: .nvmrc + + - name: "Cache yarn dependencies" + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 + with: + path: | + .yarn/cache + .yarn/unplugged + .yarn/install-state.gz + node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', '.yarnrc.yml') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: "Install dependencies" + shell: bash + run: | + if [ ! -d "node_modules" ]; then + yarn install --immutable + else + echo "Dependencies already installed from cache" + fi \ No newline at end of file diff --git a/.github/actions/setup-python/action.yaml b/.github/actions/setup-python/action.yaml new file mode 100644 index 000000000..4f63b3a6a --- /dev/null +++ b/.github/actions/setup-python/action.yaml @@ -0,0 +1,10 @@ +name: "Setup Python Common" +description: "Setup Python and install dependencies" +runs: + using: "composite" + steps: + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: '3.12' + - run: pip install PyYAML httplib2 + shell: bash \ No newline at end of file diff --git a/.github/actions/setup-tools/action.yaml b/.github/actions/setup-tools/action.yaml new file mode 100644 index 000000000..ef6661bf5 --- /dev/null +++ b/.github/actions/setup-tools/action.yaml @@ -0,0 +1,42 @@ +name: "Setup Tools" +description: "Common setup for widget and js test jobs" +inputs: + mendix_version: + description: "Mendix version" + required: true +outputs: + java-path: + description: "Path to the installed Java" + value: ${{ steps.setup-java.outputs.path }} +runs: + using: "composite" + steps: + - name: "Setup Python and dependencies" + uses: ./.github/actions/setup-python + + - name: "Setup Node and dependencies" + uses: ./.github/actions/setup-node-with-cache + + - name: "Setup Java 21" + id: setup-java + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 #v4 + with: + distribution: "temurin" + java-version: "21" + + - name: "Cache Mendix runtime" + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 #v4 + with: + path: tmp/runtime.tar.gz + key: mendix-runtime-${{ inputs.mendix_version }} + + - name: "Cache m2ee-tools" + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 #v4 + with: + path: tmp/m2ee + key: m2ee-tools-v1 + + - name: "Install Maestro" + uses: ./.github/actions/setup-maestro + + diff --git a/.github/actions/setup-xcode-cli-tools/action.yaml b/.github/actions/setup-xcode-cli-tools/action.yaml new file mode 100644 index 000000000..4062c9e05 --- /dev/null +++ b/.github/actions/setup-xcode-cli-tools/action.yaml @@ -0,0 +1,14 @@ +name: "Setup Xcode CLI Tools" +description: "Ensure Xcode CLI tools are configured" +runs: + using: "composite" + steps: + - name: "Verify and set Xcode CLI tools" + shell: bash + run: | + if ! xcode-select --print-path; then + echo "Xcode CLI tools not set. Setting them now." + sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer + else + echo "Xcode CLI tools are already configured." + fi \ No newline at end of file diff --git a/.github/actions/start-runtime/action.yml b/.github/actions/start-runtime/action.yml deleted file mode 100644 index 908276941..000000000 --- a/.github/actions/start-runtime/action.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: "Start the runtime" -description: "Start the runtime in preparation of the native e2e tests" -inputs: - mda-file: - description: "Path to the deployment package" - required: true - mendix-version: - description: "Mendix version to use for the runtime" - required: true -runs: - using: composite - steps: - - name: "Setup Python" - uses: actions/setup-python@v4.5.0 - with: - python-version: "3.x" - - - name: "Install Python dependencies" - run: pip install pyaml httplib2 - shell: bash - - - name: "Setup Java 21" - id: setup-java - uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 #v4 - with: - distribution: "temurin" - java-version: "21" - - - name: "Make setup-runtime.sh executable" - run: chmod +x .github/scripts/setup-runtime.sh - shell: bash - - - name: "Initial setup" - run: | - .github/scripts/setup-runtime.sh "${{ inputs.mda-file }}" "${{ inputs.mendix-version }}" "${{ steps.setup-java.outputs.path }}" "${{ github.workspace }}" - shell: bash - - - name: "Start mxruntime with retries" - run: | - MAX_RETRIES=3 - RETRY=0 - until bin/m2ee -c ${{ github.workspace }}/project/m2ee-native.yml --verbose --yolo start; do - RETRY=$((RETRY+1)) - if [ $RETRY -ge $MAX_RETRIES ]; then - echo "mxruntime failed after $MAX_RETRIES attempts." - exit 1 - fi - echo "mxruntime failed, retrying ($RETRY/$MAX_RETRIES)..." - .github/scripts/setup-runtime.sh "${{ inputs.mda-file }}" "${{ inputs.mendix-version }}" "${{ steps.setup-java.outputs.path }}" "${{ github.workspace }}" - done - shell: bash \ No newline at end of file diff --git a/.github/actions/use-arficats-from-specific-run/action.yaml b/.github/actions/use-arficats-from-specific-run/action.yaml new file mode 100644 index 000000000..ac4075172 --- /dev/null +++ b/.github/actions/use-arficats-from-specific-run/action.yaml @@ -0,0 +1,46 @@ +name: "Download Artifact from Specific Run" +description: "Download an artifact from a specific workflow run using GitHub CLI" +inputs: + artifact_name: + description: "Name of the artifact to download" + required: true + run_id: + description: "Workflow run ID" + required: true + output_dir: + description: "Directory to extract the artifact" + required: true + platform: + description: "Platform (android or ios)" + required: true +runs: + using: "composite" + steps: + - name: "Install GitHub CLI" + shell: bash + run: | + if ! command -v gh &> /dev/null; then + if [[ "$RUNNER_OS" == "Linux" ]]; then + sudo apt update + sudo apt install -y gh + elif [[ "$RUNNER_OS" == "macOS" ]]; then + brew install gh + fi + fi + - name: "Authenticate GitHub CLI" + shell: bash + run: | + unset GITHUB_TOKEN + echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token + - name: "Fetch artifact URL" + id: fetch-artifacts + shell: bash + run: | + url=$(gh api "repos/${{ github.repository }}/actions/runs/${{ inputs.run_id }}/artifacts" --jq '.artifacts[] | select(.name == "${{ inputs.artifact_name }}") | .archive_download_url') + echo "artifacts_url=$url" >> $GITHUB_ENV + - name: "Download and extract artifact" + if: env.artifacts_url != '' + shell: bash + run: | + curl -L -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -o ${{ inputs.platform }}-app.zip "$artifacts_url" + unzip ${{ inputs.platform }}-app.zip -d ${{ inputs.output_dir }} \ No newline at end of file diff --git a/.github/scripts/setup-runtime.sh b/.github/scripts/setup-runtime.sh index 1d4f7c2f3..72b26aa76 100644 --- a/.github/scripts/setup-runtime.sh +++ b/.github/scripts/setup-runtime.sh @@ -15,14 +15,19 @@ sed -i -- "s=\$ROOT_PATH=$WORKSPACE=g" project/m2ee-native.yml sed -i -- "s=\$JAVA_HOME=$JAVA_PATH=g" project/m2ee-native.yml mkdir -p var/log var/opt/m2ee var/run bin tmp -git clone https://github.com/KevinVlaanderen/m2ee-tools.git tmp/m2ee +# Clone m2ee-tools only if not cached +if [ ! -d tmp/m2ee ]; then + git clone https://github.com/KevinVlaanderen/m2ee-tools.git tmp/m2ee +fi mv tmp/m2ee/src/* var/opt/m2ee chmod a=rwx var/log/ var/run/ echo "#!/bin/bash -x" > bin/m2ee echo "python3 var/opt/m2ee/m2ee.py \$@" >>bin/m2ee chmod +x bin/m2ee +# Download only if not cached mkdir -p "$WORKSPACE/project/runtimes" "$WORKSPACE/project/data/model-upload" "$WORKSPACE/project/data/database" "$WORKSPACE/project/data/files" "$WORKSPACE/project/data/tmp" -wget -q "https://cdn.mendix.com/runtime/mendix-$MENDIX_VERSION.tar.gz" -O tmp/runtime.tar.gz -tar xfz tmp/runtime.tar.gz --directory "$WORKSPACE/project/runtimes" -rm tmp/runtime.tar.gz \ No newline at end of file +if [ ! -f tmp/runtime.tar.gz ]; then + wget -q "https://cdn.mendix.com/runtime/mendix-$MENDIX_VERSION.tar.gz" -O tmp/runtime.tar.gz +fi +tar xfz tmp/runtime.tar.gz --directory "$WORKSPACE/project/runtimes" \ No newline at end of file diff --git a/.github/scripts/start-runtime-with-verification.sh b/.github/scripts/start-runtime-with-verification.sh new file mode 100644 index 000000000..cb6f181e3 --- /dev/null +++ b/.github/scripts/start-runtime-with-verification.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -e + +# Arguments +MDA_FILE="$1" +MENDIX_VERSION="$2" +JAVA_PATH="$3" +WORKSPACE="$4" + +# Ensure setup script is executable +chmod +x .github/scripts/setup-runtime.sh + +# Run setup +.github/scripts/setup-runtime.sh "$MDA_FILE" "$MENDIX_VERSION" "$JAVA_PATH" "$WORKSPACE" + +# Stop any running Mendix runtime before starting a new one +if bin/m2ee -c "$WORKSPACE/project/m2ee-native.yml" status | grep -q "running"; then + echo "Stopping previous Mendix runtime..." + bin/m2ee -c "$WORKSPACE/project/m2ee-native.yml" stop + sleep 10 +fi + +# Start runtime +START_OUTPUT=$(bin/m2ee -c "$WORKSPACE/project/m2ee-native.yml" --verbose --yolo start 2>&1) +echo "Full output from start command:" +echo "$START_OUTPUT" +if [ $? -eq 0 ]; then + echo "Runtime started successfully (exit code)." + exit 0 +fi + +echo "Runtime did not start successfully." +exit 1 \ No newline at end of file diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 7b418cf16..3dc9af2c7 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -3,11 +3,11 @@ name: Run build on: push: branches: - - main + - mx-version/10 - 'mx/release/**' pull_request: branches: - - main + - mx-version/10 - 'mx/release/**' jobs: test: @@ -23,7 +23,7 @@ jobs: uses: softprops/diffset@db8c4e13f5cc3f8ab666ba2cb6998b688058a41c # v1 if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository with: - base: main + base: mx-version/10 global_files: | !{packages/**/*,configs/e2e/*.json,scripts/**/*,data/**/*} env: diff --git a/.github/workflows/NativePipeline.yml b/.github/workflows/NativePipeline.yml index 3acf5ead4..145c2f4df 100644 --- a/.github/workflows/NativePipeline.yml +++ b/.github/workflows/NativePipeline.yml @@ -2,6 +2,10 @@ name: Run Native Pipeline on: workflow_dispatch: inputs: + run_name: + description: "Provide a name for the run" + required: false + default: "" mendix_version: description: "Provide the SP version to be used (e.g., 10.14.0.43709) - has to be a released version (Default: latest from Mendix versions.json)" required: false @@ -11,6 +15,10 @@ on: default: "" required: false type: string + LOCAL_TEST_ARTIFACT_RUN_ID: + description: "Workflow run ID for local artifact download (leave empty for normal CI)" + required: false + default: "" workspace: description: "Select a widget to test (Default will run all)" required: true @@ -57,12 +65,17 @@ on: - toggle-buttons-native - video-player-native - web-view-native - - # Run at 0:00 UTC (2:00 AM CET time during summer, 1:00 AM during winter) + + # Run at 4:00 UTC (6:00 AM CET time during summer, 5:00 AM during winter) schedule: - - cron: '0 0 * * *' + - cron: '0 4 * * *' # Trigger on PR - # pull_request: + pull_request: + +# Use default name in case no input +run-name: ${{ github.event.inputs.run_name || 'Run Native Pipeline' }} +env: + LOCAL_TEST_ARTIFACT_RUN_ID: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID || '' }} permissions: packages: write jobs: @@ -247,11 +260,13 @@ jobs: apt update && apt upgrade -y apt install curl -y - name: "Download test project" - run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/main.zip + run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/mx-version/10.zip - name: "Extract test project" uses: montudor/action-zip@0852c26906e00f8a315c704958823928d8018b28 # v1.0.0 with: args: unzip -qq project.zip -d . + - name: "Rename extracted directory" # Doing this since mxbuild fails with - path too long + run: mv Native-Mobile-Resources-mx-version-10 Native-Mobile-Resources-mx10 - name: "Download resources artifact" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: @@ -265,26 +280,26 @@ jobs: run: | if compgen -G 'resources/pluggableWidgets/**/dist/*/*.mpk' > /dev/null; then for oldPath in resources/pluggableWidgets/**/dist/*/*.mpk; do - newPath=Native-Mobile-Resources-main/widgets/$(basename $oldPath) + newPath=Native-Mobile-Resources-mx10/widgets/$(basename $oldPath) mv -f $oldPath $newPath done - mx update-widgets --loose-version-check Native-Mobile-Resources-main/NativeComponentsTestProject.mpr + mx update-widgets --loose-version-check Native-Mobile-Resources-mx10/NativeComponentsTestProject.mpr fi - name: "Move mobile-resources" shell: bash run: | if compgen -G 'resources/jsActions/mobile-resources-native/*' > /dev/null; then - mv -f resources/jsActions/mobile-resources-native/* Native-Mobile-Resources-main/javascriptsource/nativemobileresources/actions/ + mv -f resources/jsActions/mobile-resources-native/* Native-Mobile-Resources-mx10/javascriptsource/nativemobileresources/actions/ fi - name: "Move nanoflow-actions" shell: bash run: | if compgen -G 'resources/jsActions/mobile-resources-native/*' > /dev/null; then - mv -f resources/jsActions/nanoflow-actions-native/* Native-Mobile-Resources-main/javascriptsource/nanoflowcommons/actions/ + mv -f resources/jsActions/nanoflow-actions-native/* Native-Mobile-Resources-mx10/javascriptsource/nanoflowcommons/actions/ fi - name: "Force rebuild test project" run: | - mxbuild -o automation.mda --loose-version-check Native-Mobile-Resources-main/NativeComponentsTestProject.mpr + mxbuild -o automation.mda --loose-version-check Native-Mobile-Resources-mx10/NativeComponentsTestProject.mpr - name: "Upload MDA" uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 with: @@ -465,7 +480,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 60 strategy: - max-parallel: 10 + max-parallel: 5 matrix: widget: ${{ fromJson(needs.scope.outputs.widgets) }} fail-fast: false @@ -474,70 +489,38 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: yarn install --immutable - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - - # USED ONLY FOR TESTING PURPOSE - TO SKIP APP BUILD PART AND DOWNLOAD FROM SPECIFIC RUN - # - name: "Install GitHub CLI" - # run: | - # curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg - # sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg - # echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - # sudo apt update - # sudo apt install gh - # - name: "Authenticate GitHub CLI" - # run: | - # unset GITHUB_TOKEN - # echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - # - name: "Fetch artifacts from run 676" - # id: fetch-artifacts - # run: | - # artifacts_url=$(gh api "repos/${{ github.repository }}/actions/runs/13453887084/artifacts" --jq '.artifacts[] | select(.name == "android-app") | .archive_download_url') - # echo "Artifacts URL: $artifacts_url" - # echo "artifacts_url=$artifacts_url" >> $GITHUB_ENV - # - name: "Download Android app" - # if: env.artifacts_url != '' - # run: | - # if [ -z "$artifacts_url" ]; then - # echo "No artifacts URL found." - # exit 1 - # fi - # curl -L -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -o android-app.zip "$artifacts_url" - # unzip android-app.zip -d android-app - + # Used only for local testing, will be empty on GitHub + - name: "Download Android app from specific run" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} + uses: ./.github/actions/use-arficats-from-specific-run + with: + artifact_name: android-app + run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} + output_dir: android-app + platform: android - name: "Download Android app" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: android-app path: android-app - - - name: "Start runtime" - uses: ./.github/actions/start-runtime + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Verify maestro - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: Set up Android SDK - run: echo "ANDROID_HOME=$ANDROID_SDK_ROOT" >> $GITHUB_ENV - + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 20 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -546,7 +529,7 @@ jobs: - name: "Run android tests" uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.0.0 with: - api-level: 30 + api-level: 35 target: google_apis arch: x86_64 profile: pixel @@ -558,27 +541,11 @@ jobs: bash maestro/helpers/prepare_android.sh bash maestro/run_maestro_widget_tests.sh android "${{ matrix.widget }}" - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: android-runtime-logs-${{ matrix.widget }} - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-screenshots-${{ matrix.widget }} - path: ${{ github.workspace }}/maestro/images/actual/android/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-artifacts-${{ matrix.widget }} - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: android + test-type: ${{ matrix.widget }} ios-widget-tests: needs: [scope, mendix-version, project, ios-app] @@ -586,7 +553,7 @@ jobs: runs-on: macos-15 timeout-minutes: 60 strategy: - max-parallel: 10 + max-parallel: 5 matrix: widget: ${{ fromJson(needs.scope.outputs.widgets) }} fail-fast: false @@ -595,80 +562,40 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: | - yarn cache clean - yarn install --immutable - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - - - # USED ONLY FOR TESTING PURPOSE - TO SKIP APP BUILD PART AND DOWNLOAD APP FROM SPECIFIC RUN - # - name: "Install GitHub CLI" - # run: | - # brew install gh - # - name: "Authenticate GitHub CLI" - # run: | - # unset GITHUB_TOKEN - # echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - # - name: "Fetch artifacts from run 676" - # id: fetch-artifacts - # run: | - # artifacts_url=$(gh api "repos/${{ github.repository }}/actions/runs/13453887084/artifacts" --jq '.artifacts[] | select(.name == "ios-app") | .archive_download_url') - # echo "Artifacts URL: $artifacts_url" - # echo "artifacts_url=$artifacts_url" >> $GITHUB_ENV - # - name: "Download iOS app" - # if: env.artifacts_url != '' - # run: | - # if [ -z "$artifacts_url" ]; then - # echo "No artifacts URL found." - # exit 1 - # fi - # curl -L -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -o ios-app.zip "$artifacts_url" - # unzip ios-app.zip -d ios-app - - - name: "Start runtime" - uses: ./.github/actions/start-runtime - with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - + # Used only for local testing, will be empty on GitHub + - name: "Download iOS app from specific run" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} + uses: ./.github/actions/use-arficats-from-specific-run + with: + artifact_name: ios-app + run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} + output_dir: ios-app + platform: ios - name: "Download iOS app" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: ios-app path: ios-app - - name: Check iOS App Path - run: ls ios-app - - - name: "Verify Xcode CLI Tools" - run: | - if ! xcode-select --print-path; then - echo "Xcode CLI tools not set. Setting them now." - sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer - else - echo "Xcode CLI tools are already configured." - fi - - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: "Verify maestro" - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: "List Available Simulators" - run: xcrun simctl list devices - + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools + with: + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" + + - name: "Setup Xcode CLI Tools" + uses: ./.github/actions/setup-xcode-cli-tools - name: "Run iOS tests" run: | chmod +x maestro/helpers/prepare_ios.sh @@ -676,27 +603,11 @@ jobs: bash maestro/helpers/prepare_ios.sh bash maestro/run_maestro_widget_tests.sh ios "${{ matrix.widget }}" - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-runtime-logs-${{ matrix.widget }} - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-screenshots-${{ matrix.widget }} - path: ${{ github.workspace }}/maestro/images/actual/ios/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: ios-artifacts-${{ matrix.widget }} - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: ios + test-type: ${{ matrix.widget }} android-js-tests: if: ${{ github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions'}} @@ -708,13 +619,6 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: yarn install --immutable - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: @@ -724,22 +628,19 @@ jobs: with: name: android-app path: android-app - - name: "Start runtime" - uses: ./.github/actions/start-runtime - with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Verify maestro - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: Set up Android SDK - run: echo "ANDROID_HOME=$ANDROID_SDK_ROOT" >> $GITHUB_ENV + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools + with: + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -748,7 +649,7 @@ jobs: - name: "Run android tests" uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.0.0 with: - api-level: 30 + api-level: 35 target: google_apis arch: x86_64 profile: pixel @@ -760,27 +661,11 @@ jobs: bash maestro/helpers/prepare_android.sh bash maestro/run_maestro_jsactions_tests.sh android - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-runtime-logs-js-actions - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-screenshots-js-actions - path: ${{ github.workspace }}/maestro/images/actual/android/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: android-artifacts-js-actions - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: android + test-type: js-actions ios-js-tests: if: ${{ github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions'}} @@ -792,52 +677,31 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: | - yarn cache clean - yarn install --immutable - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - - name: "Start runtime" - uses: ./.github/actions/start-runtime - with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - - name: "Download iOS app" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: ios-app path: ios-app - - name: Check iOS App Path - run: ls ios-app - - - name: "Verify Xcode CLI Tools" - run: | - if ! xcode-select --print-path; then - echo "Xcode CLI tools not set. Setting them now." - sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer - else - echo "Xcode CLI tools are already configured." - fi - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: "Verify maestro" - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: "List Available Simulators" - run: xcrun simctl list devices + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools + with: + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" + + - name: "Setup Xcode CLI Tools" + uses: ./.github/actions/setup-xcode-cli-tools - name: "Run iOS tests" run: | chmod +x maestro/helpers/prepare_ios.sh @@ -845,27 +709,11 @@ jobs: bash maestro/helpers/prepare_ios.sh bash maestro/run_maestro_jsactions_tests.sh ios - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-runtime-logs-js-actions - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: ios-screenshots-js-actions - path: ${{ github.workspace }}/maestro/images/actual/ios/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-artifacts-js-actions - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: ios + test-type: js-actions compare-screenshots: needs: [scope, android-widget-tests, ios-widget-tests, android-js-tests, ios-js-tests] runs-on: ubuntu-latest @@ -904,15 +752,9 @@ jobs: gh run download ${{ github.run_id }} --name ios-screenshots-js-actions --dir images/actual/ios/ || true ls -l images/actual/ios/ - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn + - name: "Setup Node and dependencies" + uses: ./.github/actions/setup-node-with-cache - - name: "Install dependencies" - run: yarn install - - name: "Compare Android screenshots" continue-on-error: true run: node ${{ github.workspace }}/maestro/helpers/compare_screenshots.js android diff --git a/.github/workflows/PublishDockerImage.yml b/.github/workflows/PublishDockerImage.yml index 0c6624bc5..87c079a0c 100644 --- a/.github/workflows/PublishDockerImage.yml +++ b/.github/workflows/PublishDockerImage.yml @@ -2,7 +2,7 @@ name: Publishing docker images for mxbuild on: push: - branches: [main] + branches: [mx-version/10] paths: - "configs/e2e/mendix-versions.json" diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 0b5226f2f..fba51882a 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -2,9 +2,9 @@ name: Run release on: push: - branches: [main] + branches: [mx-version/10] pull_request: - branches: [main] + branches: [mx-version/10] jobs: test: @@ -20,7 +20,7 @@ jobs: uses: softprops/diffset@db8c4e13f5cc3f8ab666ba2cb6998b688058a41c # v1 if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository with: - base: main + base: mx-version/10 global_files: | !{packages/**/*,configs/e2e/*.json,scripts/**/*,data/**/*} env: diff --git a/.github/workflows/ShaCheck.yml b/.github/workflows/ShaCheck.yml index e69a08fb4..4d684e28b 100644 --- a/.github/workflows/ShaCheck.yml +++ b/.github/workflows/ShaCheck.yml @@ -2,11 +2,11 @@ name: Ensure SHA pinned actions on: push: - branches: [main] + branches: [mx-version/10] paths: - ".github/workflows/*.yml" pull_request: - branches: [main] + branches: [mx-version/10] paths: - ".github/workflows/*.yml" diff --git a/.github/workflows/UnitTests.yml b/.github/workflows/UnitTests.yml index 554ee1b75..aaf7f21c6 100644 --- a/.github/workflows/UnitTests.yml +++ b/.github/workflows/UnitTests.yml @@ -2,9 +2,9 @@ name: Run unit tests on: push: - branches: [main] + branches: [mx-version/10] pull_request: - branches: [main] + branches: [mx-version/10] jobs: test: @@ -17,7 +17,7 @@ jobs: uses: softprops/diffset@d5947696689a571f7a984a52505e2649eead5c22 # v1 if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository with: - base: main + base: mx-version/10 global_files: | !{packages/**/*,configs/e2e/*.json,scripts/**/*,data/**/*} env: diff --git a/.yarnrc.yml b/.yarnrc.yml index a5fe79487..8a6d9718f 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,9 +1,9 @@ changesetBaseRefs: - - main - - origin/main - - upstream/main - - refs/remotes/origin/main - - +refs/heads/main + - mx-version/10 + - origin/mx-version/10 + - upstream/mx-version/10 + - refs/remotes/origin/mx-version/10 + - +refs/heads/mx-version/10 compressionLevel: mixed diff --git a/configs/e2e/mendix-versions.json b/configs/e2e/mendix-versions.json index 599550788..1bb0404c1 100644 --- a/configs/e2e/mendix-versions.json +++ b/configs/e2e/mendix-versions.json @@ -1,3 +1,3 @@ { - "latest": "10.24.0.73019" + "latest": "10.24.4.77222" } diff --git a/maestro/helpers/prepare_ios.sh b/maestro/helpers/prepare_ios.sh index 63af57742..87f639cf5 100644 --- a/maestro/helpers/prepare_ios.sh +++ b/maestro/helpers/prepare_ios.sh @@ -1,25 +1,72 @@ #!/bin/bash +# Configuration - modify these values as needed +DEVICE_TYPE="iPhone 16" +IOS_VERSION="18.5" + start_simulator() { echo "Starting iOS Simulator..." - xcrun simctl boot "iPhone 16" || echo "Simulator already booted" + echo "Looking for: $DEVICE_TYPE with iOS $IOS_VERSION" + + # List available simulators to debug + # echo "Available simulators:" + # xcrun simctl list devices available + + # Try to find the specified device with the specified iOS version + DEVICE_ID=$(xcrun simctl list devices available | grep -A1 "iOS $IOS_VERSION" | grep "$DEVICE_TYPE " | head -1 | grep -o "[A-F0-9-]{36}") + + if [ -z "$DEVICE_ID" ]; then + echo "No $DEVICE_TYPE with iOS $IOS_VERSION found. Trying to create one..." + # Try to create the device with the specified iOS version + IOS_RUNTIME="com.apple.CoreSimulator.SimRuntime.iOS-${IOS_VERSION//./-}" + DEVICE_TYPE_ID="com.apple.CoreSimulator.SimDeviceType.${DEVICE_TYPE// /-}" + DEVICE_ID=$(xcrun simctl create "${DEVICE_TYPE} Test" "$DEVICE_TYPE_ID" "$IOS_RUNTIME" 2>/dev/null) + + if [ -z "$DEVICE_ID" ]; then + echo "Failed to create $DEVICE_TYPE with iOS $IOS_VERSION. Using any available $DEVICE_TYPE." + DEVICE_ID=$(xcrun simctl list devices available | grep "$DEVICE_TYPE " | head -1 | grep -o "[A-F0-9-]{36}") + fi + fi + + if [ -z "$DEVICE_ID" ]; then + echo "Error: Could not find or create any $DEVICE_TYPE device" + exit 1 + fi + + echo "Using device ID: $DEVICE_ID" + export SIMULATOR_DEVICE_ID="$DEVICE_ID" + + # Boot the device + xcrun simctl boot "$DEVICE_ID" || echo "Simulator already booted" sleep 30 - xcrun simctl bootstatus || echo "Simulator booted successfully" + xcrun simctl bootstatus "$DEVICE_ID" || echo "Simulator booted successfully" } set_status_bar() { echo "Setting status bar on iOS Simulator..." - xcrun simctl status_bar "iPhone 16" override --time "11:01" --wifiBars 3 --cellularBars 4 --batteryState charged --batteryLevel 100 + if [ -z "$SIMULATOR_DEVICE_ID" ]; then + echo "Error: SIMULATOR_DEVICE_ID not set" + return 1 + fi + xcrun simctl status_bar "$SIMULATOR_DEVICE_ID" override --time "11:01" --wifiBars 3 --cellularBars 4 --batteryState charged --batteryLevel 100 } install_ios_app() { echo "Installing iOS app on simulator..." - xcrun simctl install booted ios-app/Debug-iphonesimulator/NativeTemplate.app + if [ -z "$SIMULATOR_DEVICE_ID" ]; then + echo "Error: SIMULATOR_DEVICE_ID not set" + return 1 + fi + xcrun simctl install "$SIMULATOR_DEVICE_ID" ios-app/Debug-iphonesimulator/NativeTemplate.app } verify_installed_app() { echo "Verifying installed app..." - xcrun simctl get_app_container booted com.mendix.native.template + if [ -z "$SIMULATOR_DEVICE_ID" ]; then + echo "Error: SIMULATOR_DEVICE_ID not set" + return 1 + fi + xcrun simctl get_app_container "$SIMULATOR_DEVICE_ID" com.mendix.native.template } start_simulator diff --git a/maestro/images/expected/android/accordion_custom.png b/maestro/images/expected/android/accordion_custom.png index 2ecf94d4b..9c2232912 100644 Binary files a/maestro/images/expected/android/accordion_custom.png and b/maestro/images/expected/android/accordion_custom.png differ diff --git a/maestro/images/expected/android/accordion_multiple.png b/maestro/images/expected/android/accordion_multiple.png index 26a19048e..aa75378a6 100644 Binary files a/maestro/images/expected/android/accordion_multiple.png and b/maestro/images/expected/android/accordion_multiple.png differ diff --git a/maestro/images/expected/android/accordion_noncollapsible.png b/maestro/images/expected/android/accordion_noncollapsible.png index 98a570805..3ced2fb4c 100644 Binary files a/maestro/images/expected/android/accordion_noncollapsible.png and b/maestro/images/expected/android/accordion_noncollapsible.png differ diff --git a/maestro/images/expected/android/animation.png b/maestro/images/expected/android/animation.png index abfae0649..69fde3a6c 100644 Binary files a/maestro/images/expected/android/animation.png and b/maestro/images/expected/android/animation.png differ diff --git a/maestro/images/expected/android/authentication.png b/maestro/images/expected/android/authentication.png index 6cbd9375f..da2c54511 100644 Binary files a/maestro/images/expected/android/authentication.png and b/maestro/images/expected/android/authentication.png differ diff --git a/maestro/images/expected/android/background_gradient.png b/maestro/images/expected/android/background_gradient.png index c5bd858ff..f365aefd3 100644 Binary files a/maestro/images/expected/android/background_gradient.png and b/maestro/images/expected/android/background_gradient.png differ diff --git a/maestro/images/expected/android/bg_image_clickable_container.png b/maestro/images/expected/android/bg_image_clickable_container.png index 3f2e600db..3b236773c 100644 Binary files a/maestro/images/expected/android/bg_image_clickable_container.png and b/maestro/images/expected/android/bg_image_clickable_container.png differ diff --git a/maestro/images/expected/android/bg_image_conditional_visibility.png b/maestro/images/expected/android/bg_image_conditional_visibility.png index cf305054d..99455bed3 100644 Binary files a/maestro/images/expected/android/bg_image_conditional_visibility.png and b/maestro/images/expected/android/bg_image_conditional_visibility.png differ diff --git a/maestro/images/expected/android/bg_image_dynamic_image.png b/maestro/images/expected/android/bg_image_dynamic_image.png index ab6aaad57..e60cea4b4 100644 Binary files a/maestro/images/expected/android/bg_image_dynamic_image.png and b/maestro/images/expected/android/bg_image_dynamic_image.png differ diff --git a/maestro/images/expected/android/bg_image_layout_grid.png b/maestro/images/expected/android/bg_image_layout_grid.png index 30ce98909..5affc44f2 100644 Binary files a/maestro/images/expected/android/bg_image_layout_grid.png and b/maestro/images/expected/android/bg_image_layout_grid.png differ diff --git a/maestro/images/expected/android/bg_image_nested.png b/maestro/images/expected/android/bg_image_nested.png index 9c106c9f6..cd70758b1 100644 Binary files a/maestro/images/expected/android/bg_image_nested.png and b/maestro/images/expected/android/bg_image_nested.png differ diff --git a/maestro/images/expected/android/bg_image_static_images.png b/maestro/images/expected/android/bg_image_static_images.png index 7ce112274..376ec8bb9 100644 Binary files a/maestro/images/expected/android/bg_image_static_images.png and b/maestro/images/expected/android/bg_image_static_images.png differ diff --git a/maestro/images/expected/android/bg_image_static_svg.png b/maestro/images/expected/android/bg_image_static_svg.png index 76879ea75..dc9a4b965 100644 Binary files a/maestro/images/expected/android/bg_image_static_svg.png and b/maestro/images/expected/android/bg_image_static_svg.png differ diff --git a/maestro/images/expected/android/bottom_sheet_expanding.png b/maestro/images/expected/android/bottom_sheet_expanding.png index e7805e362..472702c32 100644 Binary files a/maestro/images/expected/android/bottom_sheet_expanding.png and b/maestro/images/expected/android/bottom_sheet_expanding.png differ diff --git a/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png b/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png index a1593e748..650086465 100644 Binary files a/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png and b/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png differ diff --git a/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png b/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png index ed6858015..4e1d3be77 100644 Binary files a/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png and b/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png differ diff --git a/maestro/images/expected/android/bottom_sheet_modal_custom.png b/maestro/images/expected/android/bottom_sheet_modal_custom.png index f25e03129..c0b019750 100644 Binary files a/maestro/images/expected/android/bottom_sheet_modal_custom.png and b/maestro/images/expected/android/bottom_sheet_modal_custom.png differ diff --git a/maestro/images/expected/android/clipboard.png b/maestro/images/expected/android/clipboard.png index a11de62ae..9ac82d3f1 100644 Binary files a/maestro/images/expected/android/clipboard.png and b/maestro/images/expected/android/clipboard.png differ diff --git a/maestro/images/expected/android/color_picker_conditional.png b/maestro/images/expected/android/color_picker_conditional.png index c17e36f18..81d0f2783 100644 Binary files a/maestro/images/expected/android/color_picker_conditional.png and b/maestro/images/expected/android/color_picker_conditional.png differ diff --git a/maestro/images/expected/android/color_picker_disabled.png b/maestro/images/expected/android/color_picker_disabled.png index b816f98b3..91b1e4e64 100644 Binary files a/maestro/images/expected/android/color_picker_disabled.png and b/maestro/images/expected/android/color_picker_disabled.png differ diff --git a/maestro/images/expected/android/color_picker_normal.png b/maestro/images/expected/android/color_picker_normal.png index c1820ee44..6f0927d2f 100644 Binary files a/maestro/images/expected/android/color_picker_normal.png and b/maestro/images/expected/android/color_picker_normal.png differ diff --git a/maestro/images/expected/android/color_picker_partial.png b/maestro/images/expected/android/color_picker_partial.png index bba4d66a7..3928a935c 100644 Binary files a/maestro/images/expected/android/color_picker_partial.png and b/maestro/images/expected/android/color_picker_partial.png differ diff --git a/maestro/images/expected/android/device_info.png b/maestro/images/expected/android/device_info.png index 3e9e0914f..2391fbd55 100644 Binary files a/maestro/images/expected/android/device_info.png and b/maestro/images/expected/android/device_info.png differ diff --git a/maestro/images/expected/android/doughnut_chart_custom.png b/maestro/images/expected/android/doughnut_chart_custom.png index e5d291f47..a7c8776bc 100644 Binary files a/maestro/images/expected/android/doughnut_chart_custom.png and b/maestro/images/expected/android/doughnut_chart_custom.png differ diff --git a/maestro/images/expected/android/doughnut_chart_multiple_data_points.png b/maestro/images/expected/android/doughnut_chart_multiple_data_points.png index e62426900..e1d588631 100644 Binary files a/maestro/images/expected/android/doughnut_chart_multiple_data_points.png and b/maestro/images/expected/android/doughnut_chart_multiple_data_points.png differ diff --git a/maestro/images/expected/android/floating_action_button.png b/maestro/images/expected/android/floating_action_button.png index 1d843e4e0..e0b82aa64 100644 Binary files a/maestro/images/expected/android/floating_action_button.png and b/maestro/images/expected/android/floating_action_button.png differ diff --git a/maestro/images/expected/android/image_dynamic.png b/maestro/images/expected/android/image_dynamic.png index 1184ed349..88031dc22 100644 Binary files a/maestro/images/expected/android/image_dynamic.png and b/maestro/images/expected/android/image_dynamic.png differ diff --git a/maestro/images/expected/android/image_icon.png b/maestro/images/expected/android/image_icon.png index e09ba7ef2..7d8fea92f 100644 Binary files a/maestro/images/expected/android/image_icon.png and b/maestro/images/expected/android/image_icon.png differ diff --git a/maestro/images/expected/android/image_static.png b/maestro/images/expected/android/image_static.png index 21f087061..9499064f8 100644 Binary files a/maestro/images/expected/android/image_static.png and b/maestro/images/expected/android/image_static.png differ diff --git a/maestro/images/expected/android/image_url.png b/maestro/images/expected/android/image_url.png index 8423bd7ff..298349b73 100644 Binary files a/maestro/images/expected/android/image_url.png and b/maestro/images/expected/android/image_url.png differ diff --git a/maestro/images/expected/android/line_chart.png b/maestro/images/expected/android/line_chart.png index 59f929f1a..d1078c00a 100644 Binary files a/maestro/images/expected/android/line_chart.png and b/maestro/images/expected/android/line_chart.png differ diff --git a/maestro/images/expected/android/pie_chart_custom.png b/maestro/images/expected/android/pie_chart_custom.png index 0e4ba44b7..ba713a628 100644 Binary files a/maestro/images/expected/android/pie_chart_custom.png and b/maestro/images/expected/android/pie_chart_custom.png differ diff --git a/maestro/images/expected/android/pie_chart_multiple_data_points.png b/maestro/images/expected/android/pie_chart_multiple_data_points.png index da2dcd8b8..196807000 100644 Binary files a/maestro/images/expected/android/pie_chart_multiple_data_points.png and b/maestro/images/expected/android/pie_chart_multiple_data_points.png differ diff --git a/maestro/images/expected/android/popup_menu_alert.png b/maestro/images/expected/android/popup_menu_alert.png index 8ebae2d26..a48f6bed5 100644 Binary files a/maestro/images/expected/android/popup_menu_alert.png and b/maestro/images/expected/android/popup_menu_alert.png differ diff --git a/maestro/images/expected/android/progress_bar.png b/maestro/images/expected/android/progress_bar.png index 4bc545bb4..8bc7985cc 100644 Binary files a/maestro/images/expected/android/progress_bar.png and b/maestro/images/expected/android/progress_bar.png differ diff --git a/maestro/images/expected/android/progress_circle.png b/maestro/images/expected/android/progress_circle.png index f5b0d1277..ec2fd3f89 100644 Binary files a/maestro/images/expected/android/progress_circle.png and b/maestro/images/expected/android/progress_circle.png differ diff --git a/maestro/images/expected/android/qr_code.png b/maestro/images/expected/android/qr_code.png index ff5bf9491..1147e57d2 100644 Binary files a/maestro/images/expected/android/qr_code.png and b/maestro/images/expected/android/qr_code.png differ diff --git a/maestro/images/expected/android/radio_buttons.png b/maestro/images/expected/android/radio_buttons.png index 23599aeec..0dc485000 100644 Binary files a/maestro/images/expected/android/radio_buttons.png and b/maestro/images/expected/android/radio_buttons.png differ diff --git a/maestro/images/expected/android/range_slider.png b/maestro/images/expected/android/range_slider.png index bbcb5787b..2287617c2 100644 Binary files a/maestro/images/expected/android/range_slider.png and b/maestro/images/expected/android/range_slider.png differ diff --git a/maestro/images/expected/android/rating.png b/maestro/images/expected/android/rating.png index 0495c9cee..6f3002d40 100644 Binary files a/maestro/images/expected/android/rating.png and b/maestro/images/expected/android/rating.png differ diff --git a/maestro/images/expected/android/safe_area_view_bottom_bar.png b/maestro/images/expected/android/safe_area_view_bottom_bar.png index 3b99d90a0..c1b9360ed 100644 Binary files a/maestro/images/expected/android/safe_area_view_bottom_bar.png and b/maestro/images/expected/android/safe_area_view_bottom_bar.png differ diff --git a/maestro/images/expected/android/safe_area_view_container.png b/maestro/images/expected/android/safe_area_view_container.png index fcd350883..a0b3a5c8d 100644 Binary files a/maestro/images/expected/android/safe_area_view_container.png and b/maestro/images/expected/android/safe_area_view_container.png differ diff --git a/maestro/images/expected/android/safe_area_view_image.png b/maestro/images/expected/android/safe_area_view_image.png index 06f5b0809..d1be50de8 100644 Binary files a/maestro/images/expected/android/safe_area_view_image.png and b/maestro/images/expected/android/safe_area_view_image.png differ diff --git a/maestro/images/expected/android/safe_area_view_list_view.png b/maestro/images/expected/android/safe_area_view_list_view.png index 269341161..574554adb 100644 Binary files a/maestro/images/expected/android/safe_area_view_list_view.png and b/maestro/images/expected/android/safe_area_view_list_view.png differ diff --git a/maestro/images/expected/android/safe_area_view_text.png b/maestro/images/expected/android/safe_area_view_text.png index 91727de84..661a8b482 100644 Binary files a/maestro/images/expected/android/safe_area_view_text.png and b/maestro/images/expected/android/safe_area_view_text.png differ diff --git a/maestro/images/expected/android/safe_area_view_top_bar.png b/maestro/images/expected/android/safe_area_view_top_bar.png index 691100edd..e6c219432 100644 Binary files a/maestro/images/expected/android/safe_area_view_top_bar.png and b/maestro/images/expected/android/safe_area_view_top_bar.png differ diff --git a/maestro/images/expected/android/slider.png b/maestro/images/expected/android/slider.png index 529dcc361..21d15a1af 100644 Binary files a/maestro/images/expected/android/slider.png and b/maestro/images/expected/android/slider.png differ diff --git a/maestro/images/expected/android/toggle_buttons.png b/maestro/images/expected/android/toggle_buttons.png index 6d8a5b469..b5639ef06 100644 Binary files a/maestro/images/expected/android/toggle_buttons.png and b/maestro/images/expected/android/toggle_buttons.png differ diff --git a/maestro/images/expected/android/toggle_sidebar.png b/maestro/images/expected/android/toggle_sidebar.png index 91af73a1f..6aec5f577 100644 Binary files a/maestro/images/expected/android/toggle_sidebar.png and b/maestro/images/expected/android/toggle_sidebar.png differ diff --git a/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml b/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml index 5ca416f79..eb8374bc8 100644 --- a/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml +++ b/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml @@ -12,5 +12,10 @@ appId: "${APP_ID}" text: "Set clipboard content to 'Hi there'" - tapOn: text: "Get clipboard content" +# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible +- extendedWaitUntil: + visible: randText # Any random text that does not exist in the UI + optional: true # This should be true so that the test won't fail + timeout: 5000 # 5 seconds - takeScreenshot: path: "maestro/images/actual/${PLATFORM}/clipboard" diff --git a/scripts/test/e2e-native.js b/scripts/test/e2e-native.js deleted file mode 100644 index 281aa08b3..000000000 --- a/scripts/test/e2e-native.js +++ /dev/null @@ -1,253 +0,0 @@ -const { execSync } = require("child_process"); -const fetch = require("node-fetch"); -const { join } = require("path"); -const { cat, mkdir, rm, mv } = require("shelljs"); -const { pipeline } = require("stream"); -const { promisify } = require("util"); -const { createWriteStream } = require("fs"); -const { tmpdir } = require("os"); -const nodeIp = require("ip"); - -main().catch(e => { - console.error(e); - process.exit(-1); -}); - -// todo: add all docker run inside a try finally, cleanup. -// not sure of docker container lifecycles in github actions environment -async function main() { - const mendixVersion = await getMendixVersion(); - const ip = nodeIp.address(); - const ghcr = process.env.CI && process.env.FORKED !== "true" ? "ghcr.io/mendix/native-widgets/" : ""; - - const testArchivePath = await getTestProject("https://github.com/mendix/Native-Mobile-Resources", "main"); - const root = process.cwd(); - const projectsRoot = join(root, "tests"); - const projectDir = join(root, "tests/testProject"); - try { - mkdir("-p", projectsRoot); - execSync(`unzip -o ${testArchivePath} -d ${projectsRoot}`); - mv(`${projectsRoot}/Native-Mobile-Resources-main`, projectDir); - rm("-f", testArchivePath); - } catch (e) { - throw new Error("Failed to unzip the test project into testProject", e.message); - } - - const output = execSync("yarn workspaces list --json --since origin/master"); - const packages = JSON.parse(output); - - execSync("yarn workspaces foreach run release --since origin/master"); - - packages.forEach(({ name, location }) => { - if (["mobile-resources-native", "nanoflow-actions-native"].includes(name)) { - // for js actions - const path = name === "mobile-resources-native" ? "nativemobileresources" : "nanoflowcommons"; - const jsActionsPath = `${projectDir}/javascriptsource/${path}/actions`; - rm("-rf", jsActionsPath); - cp("-r", `${location}/dist`, jsActionsPath); - } else { - // for widgets - // this is acceptable if there's one built version. - cp(`${location}/dist/**/*.mpk`, `${projectDir}/widgets`); - } - }); - - // When running on CI pull the docker image from Github Container Registry - if (ghcr) { - console.log(`Pulling mxbuild docker image from Github Container Registry...`); - execSync(`docker pull ${ghcr}mxbuild:${mendixVersion}`); - } - - const existingImages = execSync(`docker image ls -q ${ghcr}mxbuild:${mendixVersion}`).toString().trim(); - const scriptsPath = join(root, "scripts/automation"); - - if (!existingImages) { - console.log(`Creating new mxbuild docker image...`); - execSync( - `docker build -f ${join(scriptsPath, "mxbuild.Dockerfile")} ` + - `--build-arg MENDIX_VERSION=${mendixVersion} ` + - `-t mxbuild:${mendixVersion} ${scriptsPath}`, - { stdio: "inherit" } - ); - } - - if (ghcr) { - console.log(`Pulling mxruntime docker image from Github Container Registry...`); - execSync(`docker pull ${ghcr}mxruntime:${mendixVersion}`); - } - - const existingRuntimeImages = execSync(`docker image ls -q ${ghcr}mxruntime:${mendixVersion}`).toString().trim(); - if (!existingRuntimeImages) { - console.log(`Creating new runtime docker image...`); - execSync( - `docker build -f ${join(scriptsPath, "runtime.Dockerfile")} ` + - `--build-arg MENDIX_VERSION=${mendixVersion} ` + - `-t mxruntime:${mendixVersion} ${scriptsPath}`, - { stdio: "inherit" } - ); - } - - let runtimeContainerId; - let mxbuildContainerId; - try { - // Build testProject via mxbuild - const projectFile = "/source/tests/testProject/NativeComponentsTestProject.mpr"; - mxbuildContainerId = execSync( - `docker run -p 8083:8083 -td -v ${root}:/source --rm ${ghcr}mxbuild:${mendixVersion} bash` - ) - .toString() - .trim(); - - console.log("Updating widgets with mx util..."); - execSync( - `docker exec -t ${mxbuildContainerId} bash -c "mx update-widgets --loose-version-check ${projectFile}"`, - { - stdio: "inherit" - } - ); - - console.log("Building project with mxbuild..."); - execSync(`docker exec -t ${mxbuildContainerId} bash -c "mxbuild -o /tmp/automation.mda ${projectFile}"`, { - stdio: "inherit" - }); - console.log("All widgets are updated and project .mpr created."); - - console.log("Starting metro..."); - execSync( - `docker exec -td ${mxbuildContainerId} bash -c "cd /source/tests/testProject/deployment/native && ` + - `/tmp/mxbuild/modeler/tools/node/node /tmp/mxbuild/modeler/tools/node/node_modules/react-native/local-cli/cli.js ` + - `start --port '8083' --config '/source/tests/testProject/deployment/native/metro.config.json' --no-interactive"`, - { stdio: "inherit" } - ); - - // wait until metro bundler is alive - let metroRequestAttempts = 60; - for (; metroRequestAttempts > 0; --metroRequestAttempts) { - try { - const response = await fetch(`http://localhost:8083/status`); - if (response.ok) { - break; - } - } catch (e) { - console.log(`Could not reach Metro, trying again...`); - } - await new Promise(resolve => setTimeout(resolve, 3000)); - } - - if (metroRequestAttempts === 0) { - throw new Error("Metro bundler did not start in time..."); - } - console.log("Metro started."); - - console.log("Preheating bundler for Android dev=false minify=true"); - await Promise.race([ - fetch("http://localhost:8083/index.bundle?platform=android&dev=false&minify=true"), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Preheating call timed out!")), 10 * 60 * 1000) - ) - ]); - console.log("Preheating done!"); - - // Spin up the runtime and run testProject - runtimeContainerId = execSync( - `docker run -td -v ${root}:/source -v ${scriptsPath}:/shared:ro -w /source -p 8080:8080 ` + - `-e MENDIX_VERSION=${mendixVersion} --entrypoint /bin/bash ` + - `--rm ${ghcr}mxruntime:${mendixVersion} /shared/runtime.sh` - ) - .toString() - .trim(); - - // wait until runtime is alive - let attempts = 60; - for (; attempts > 0; --attempts) { - try { - const response = await fetch(`http://localhost:8083`); - if (response.ok) { - break; - } - } catch (e) { - console.log(`Could not reach http://localhost:8083, trying again...`); - } - await new Promise(resolve => setTimeout(resolve, 3000)); - } - - if (attempts === 0) { - throw new Error("Runtime didn't start in time, existing now..."); - } - const changedPackages = packages.map(package => package.name).join(","); - console.log("Setup for android..."); - execSync("yarn setup-android"); - console.log("Android successfully setup"); - // https://github.com/lerna/lerna/issues/1846 - // execSync(`npx lerna run test:e2e:local:android --stream --concurrency 1 --scope '{${changedPackages},}'`); - execSync(`yarn workspaces run test:e2e:local:android --from '{bar-chart-native,}'`); - } catch (e) { - try { - execSync(`docker logs ${mxbuildContainerId}`, { stdio: "inherit" }); - execSync( - `docker exec -td ${mxbuildContainerId} bash -c "cat /source/tests/testProject/deployment/log/native_packager_log.txt"`, - { stdio: "inherit" } - ); - execSync(`docker logs ${runtimeContainerId}`, { stdio: "inherit" }); - } catch (_) {} - if (runtimeContainerId) { - console.log(cat("results/runtime.log").toString()); - } - throw e; - } finally { - execSync(`docker rm -f ${runtimeContainerId}`); - execSync(`docker rm -f ${mxbuildContainerId}`); - } -} - -async function getTestProject(repository, branch) { - const downloadedArchivePath = join(tmpdir(), `testProject.zip`); - - if (!repository.includes("github.com")) { - throw new Error("githubUrl is not a valid github repository!"); - } - - try { - await promisify(pipeline)( - ( - await fetch(`${repository}/archive/refs/heads/${branch}.zip`) - ).body, - createWriteStream(downloadedArchivePath) - ); - return downloadedArchivePath; - } catch (e) { - console.log(`Url is not available :(`); - rm("-f", downloadedArchivePath); - } - throw new Error("Cannot find test project in GitHub repository. Try again later."); -} - -async function getMendixVersion() { - const mendixOptionIndex = process.argv.indexOf("--mx-version"); - const targetMendixVersion = mendixOptionIndex >= 0 ? process.argv[mendixOptionIndex + 1] : undefined; - let mendixVersion; - - if (process.env.MENDIX_VERSION) { - return process.env.MENDIX_VERSION; - } - try { - const mendixVersions = await fetch( - "https://raw.githubusercontent.com/mendix/native-widgets/master/configs/e2e/mendix-versions.json" - ); - - const mendixVersionsJson = await mendixVersions.json(); - - if (targetMendixVersion && targetMendixVersion in mendixVersionsJson) { - mendixVersion = mendixVersionsJson[targetMendixVersion]; - } else { - mendixVersion = mendixVersionsJson.latest; - } - } catch (e) { - throw new Error("Couldn't reach github.com. Make sure you are connected to internet."); - } - if (!mendixVersion) { - throw new Error("Couldn't retrieve Mendix version from github.com. Try again later."); - } - - return mendixVersion; -}