Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try iOS tests build #6919

Draft
wants to merge 28 commits into
base: try/remove-gutenberg-clean-step
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 69 additions & 19 deletions .buildkite/commands/build-ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,45 @@

PLATFORM=$(uname -s)
ARCHITECTURE=$(uname -m)
PODFILE_HASH=$(hash_file gutenberg/packages/react-native-editor/ios/Podfile.lock)

# Base Paths
REACT_NATIVE_EDITOR_PATH="gutenberg/packages/react-native-editor/ios"
BUILD_PATH="$REACT_NATIVE_EDITOR_PATH/build"
PRODUCTS_PATH="$BUILD_PATH/GutenbergDemo/Build/Products/Release-iphonesimulator"
APP_PATH="$PRODUCTS_PATH/GutenbergDemo.app"
PODS_PATH="$REACT_NATIVE_EDITOR_PATH"

# Pods
PODFILE_HASH=$(hash_file "$REACT_NATIVE_EDITOR_PATH/Podfile.lock")
PODFILE_CACHEKEY="$BUILDKITE_PIPELINE_SLUG-pods-$PLATFORM-$ARCHITECTURE-$PODFILE_HASH"
PODS_PATH="gutenberg/packages/react-native-editor/ios"
PODS_FOLDER="Pods"

echo '--- :desktop_computer: Clear up some disk space'
rm -rfv ~/.Trash/15.1.xip

.buildkite/commands/install-node-dependencies.sh

# Generate build key
find package-lock.json \
gutenberg/packages/react-native-editor/ios \
gutenberg/packages/react-native-aztec/ios \
gutenberg/packages/react-native-bridge/ios \
-type f -print0 | sort -z | xargs -0 shasum | tee ios-checksums.txt
APP_BUILD_HASH=$(hash_file ios-checksums.txt)
APP_BUILD_CACHEKEY="$BUILDKITE_PIPELINE_SLUG-ios-app-$PLATFORM-$ARCHITECTURE-$APP_BUILD_HASH"
WDA_BUILD_CACHEKEY="$BUILDKITE_PIPELINE_SLUG-ios-wda-$PLATFORM-$ARCHITECTURE-$APP_BUILD_HASH"

echo "--- :ios: Restore App build if present"
mkdir -p "$PRODUCTS_PATH"
pushd "$PRODUCTS_PATH"
restore_cache "$APP_BUILD_CACHEKEY"
popd

echo "--- :ios: Restore WDA build if present"
pushd "$BUILD_PATH"
restore_cache "$WDA_BUILD_CACHEKEY"
popd

echo "--- :cocoapods: Restore Pods if present"
pushd "$PODS_PATH"
restore_cache "$PODFILE_CACHEKEY"
Expand All @@ -20,35 +49,56 @@ popd
echo '--- :ios: Set env var for iOS E2E testing'
set -x
export TEST_RN_PLATFORM=ios
export TEST_ENV=sauce
export TEST_ENV=local
# We must use a simulator that's available on the selected Xcode version
# otherwsie Xcode fallbacks to "generic destination" which requires provision
# profiles to built the Demo app.
export RN_EDITOR_E2E_IOS_DESTINATION="platform=iOS Simulator,name=iPhone 15"
set +x

echo "--- :react: Prepare tests setup"
npm run core test:e2e:setup

echo '--- :react: Build iOS bundle for E2E testing'
npm run test:e2e:bundle:ios

echo '--- :react: Build iOS app for E2E testing'
npm run core test:e2e:build-app:ios

echo '--- :compression: Prepare artifact for SauceLabs upload'
WORK_DIR=$(pwd) \
&& pushd ./gutenberg/packages/react-native-editor/ios/build/GutenbergDemo/Build/Products/Release-iphonesimulator \
&& zip -r "$WORK_DIR/gutenberg/packages/react-native-editor/ios/GutenbergDemo.app.zip" GutenbergDemo.app \
&& popd

echo '--- :saucelabs: Upload app artifact to SauceLabs'
SAUCE_FILENAME=${BUILDKITE_BRANCH//[\/]/-}
curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
--location \
--request POST 'https://api.us-west-1.saucelabs.com/v1/storage/upload' \
--form 'payload=@"./gutenberg/packages/react-native-editor/ios/GutenbergDemo.app.zip"' \
--form "name=Gutenberg-$SAUCE_FILENAME.app.zip" \
--form 'description="Gutenberg"'
test -e "$APP_PATH/GutenbergDemo" || npm run core test:e2e:build-app:ios

echo '--- :react: Build WDA for E2E testing'
test -d "$BUILD_PATH/WDA" || npm run core test:e2e:build-wda

echo '--- :compression: Prepare artifacts'
# Set the working directory
WORK_DIR=$(pwd)

# Compress the GutenbergDemo.app
pushd "$PRODUCTS_PATH"
zip -r "$WORK_DIR/$REACT_NATIVE_EDITOR_PATH/GutenbergDemo.app.zip" GutenbergDemo.app
popd

# Compress the WDA directory
pushd "$BUILD_PATH/WDA"
zip -r "$WORK_DIR/$REACT_NATIVE_EDITOR_PATH/WDA.zip" ./*
popd

echo "--- :arrow_up: Upload Build"
upload_artifact "$REACT_NATIVE_EDITOR_PATH/GutenbergDemo.app.zip"
upload_artifact "$REACT_NATIVE_EDITOR_PATH/WDA.zip"

echo "--- :cocoapods: Save Pods cache if necessary"
pushd "$PODS_PATH"
save_cache "$PODS_FOLDER" "$PODFILE_CACHEKEY"
popd

echo "--- :ios: Save App build cache if necessary"
rm "$APP_PATH/main.jsbundle"
rm -rf "$APP_PATH/assets"
pushd "$PRODUCTS_PATH"
save_cache "GutenbergDemo.app" "$APP_BUILD_CACHEKEY"
popd

echo "--- :ios: Save WDA build cache if necessary"
pushd "$BUILD_PATH"
save_cache "WDA" "$WDA_BUILD_CACHEKEY"
popd
50 changes: 38 additions & 12 deletions .buildkite/commands/test-ios.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/bin/bash -eu

CONFIG_FILE="$(pwd)/gutenberg/packages/react-native-editor/__device-tests__/helpers/device-config.json"
DEVICE_NAME=$(jq -r '.ios.local.deviceName' "$CONFIG_FILE")
DEVICE_TABLET_NAME=$(jq -r '.ios.local.deviceTabletName' "$CONFIG_FILE")

MODE="iphone"
INPUT="${1-}"
while [ "$INPUT" != "" ]; do
Expand All @@ -19,6 +23,29 @@ while [ "$INPUT" != "" ]; do
INPUT="${1-}"
done

if [ "$MODE" == 'canary' ]; then
SECTION='--- :react: Test iOS Canary Pages'
TESTS_CMD='device-tests-canary'
elif [ "$MODE" == "ipad" ]; then
SECTION='--- :react: Test iOS iPad'
DEVICE_NAME=$DEVICE_TABLET_NAME
TESTS_CMD='device-tests-ipad'
else
SECTION='--- :react: Test iOS iPhone'
TESTS_CMD='device-tests'
fi

echo "--- :ios: Start booting up simulator"
xcrun simctl boot "$DEVICE_NAME" &

echo "--- 📦 Downloading Build Artifacts"
export IOS_APP_PATH=./gutenberg/packages/react-native-editor/ios/GutenbergDemo.app.zip
download_artifact "GutenbergDemo.app.zip" "$IOS_APP_PATH"

export WDA_PATH=./gutenberg/packages/react-native-editor/ios/build/WDA
download_artifact "WDA.zip" "$WDA_PATH/WDA.zip"
unzip "$WDA_PATH/WDA.zip" -d "$WDA_PATH"

# First, restore the caches, if any
.buildkite/commands/install-node-dependencies.sh --restore-only
# Second, set up the gutenberg-mobile dependencies without building the i18n cache (--ignore-scripts)
Expand All @@ -27,28 +54,27 @@ echo "--- :npm: Install Node dependencies"
npm ci --prefer-offline --no-progress --no-audit --ignore-scripts
# Finally, set up the gutenberg submodule dependencies, bypassed by the step above.
# We need them because some E2E logic lives in gutenberg.
npm ci --prefer-offline --no-progress --no-audit --prefix gutenberg
npm ci --prefer-offline --no-progress --no-audit --prefix gutenberg --ignore-scripts

echo '--- :ios: Set env var for iOS E2E testing'
set -x
export TEST_RN_PLATFORM=ios
export TEST_ENV=sauce
export TEST_ENV=local
export JEST_JUNIT_OUTPUT_FILE="reports/test-results/ios-test-results.xml"
# This is a relic of the CircleCI setup.
# It should be removed once the migration to Buildkite is completed.
export CIRCLE_BRANCH=${BUILDKITE_BRANCH}
set +x

if [ "$MODE" == 'canary' ]; then
SECTION='--- :saucelabs: Test iOS Canary Pages'
TESTS_CMD='device-tests-canary'
elif [ "$MODE" == "ipad" ]; then
SECTION='--- :saucelabs: Test iOS iPad'
TESTS_CMD='device-tests-ipad'
else
SECTION='--- :saucelabs: Test iOS iPhone'
TESTS_CMD='device-tests'
fi
echo "--- 📦 Install WDA"

APP_PATH="$WDA_PATH/Build/Products/Debug-iphonesimulator/WebDriverAgentRunner-Runner.app"

# Install the app to the booted simulator
xcrun simctl install booted $APP_PATH &

echo "--- :react: Prepare tests setup"
npm run core test:e2e:setup

set +e
echo "$SECTION"
Expand Down
17 changes: 9 additions & 8 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ steps:
queue: mac
env: *xcode_agent_env

- label: iOS Build and Sauce Labs
key: ios-build-and-saucelabs
- label: iOS Build
key: ios-build
command: .buildkite/commands/build-ios.sh
plugins:
- *ci_toolkit_plugin
Expand All @@ -152,13 +152,14 @@ steps:
env: *xcode_agent_env

- label: Test iOS on Device – Canary Pages
depends_on: ios-build-and-saucelabs
depends_on: ios-build
command: .buildkite/commands/test-ios.sh --canary
plugins:
- *ci_toolkit_plugin
- *nvm_plugin
artifact_paths:
- reports/test-results/ios-test-results.xml
- ios-screen-recordings/*
agents:
queue: mac
env: *xcode_agent_env
Expand Down Expand Up @@ -198,13 +199,13 @@ steps:
if: *is_branch_for_quick_ui_tests
key: run-full-ui-test
prompt: "Run full UI tests suites?"
depends_on: ios-build-and-saucelabs
depends_on: ios

- label: Test iOS on Device – Full iPhone
# The quick UI tests suite version depends on the block step being unblocked
if: *is_branch_for_quick_ui_tests
depends_on:
- ios-build-and-saucelabs
- ios-build
- run-full-ui-test
command: .buildkite/commands/test-ios.sh
plugins:
Expand All @@ -221,7 +222,7 @@ steps:
# The full UI tests suite version depends only on the ios-build step, meaning it has no manual step that triggers it
if: *is_branch_for_full_ui_tests
depends_on:
- ios-build-and-saucelabs
- ios-build
command: .buildkite/commands/test-ios.sh
plugins:
- *ci_toolkit_plugin
Expand All @@ -236,7 +237,7 @@ steps:
# The quick UI tests suite version depends on the block step being unblocked
if: *is_branch_for_quick_ui_tests
depends_on:
- ios-build-and-saucelabs
- ios-build
- run-full-ui-test
command: .buildkite/commands/test-ios.sh --ipad
plugins:
Expand All @@ -252,7 +253,7 @@ steps:
# The full UI tests suite version depends only on the ios-build step, meaning it has no manual step that triggers it
if: *is_branch_for_full_ui_tests
depends_on:
- ios-build-and-saucelabs
- ios-build
command: .buildkite/commands/test-ios.sh --ipad
plugins:
- *ci_toolkit_plugin
Expand Down
30 changes: 30 additions & 0 deletions bin/test-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash -e

set -o pipefail

# Using the ':' operator with ':=' to check if a variable is set.
# If the variable is unset or null, the value after ':=' is assigned to it.
: ${IOS_APP_PATH:='./gutenberg/packages/react-native-editor/ios/build/GutenbergDemo/Build/Products/Release-iphonesimulator/GutenbergDemo.app'}
: ${WDA_PATH:='./gutenberg/packages/react-native-editor/ios/build/WDA'}
: ${ANDROID_APP_PATH:='./gutenberg/packages/react-native-editor/android/app/build/outputs/apk/debug/app-debug.apk'}

export IOS_APP_PATH
export WDA_PATH
export ANDROID_APP_PATH

export APPIUM_HOME=~/.appium
export NODE_ENV=test

if [ "$TEST_RN_PLATFORM" == "android" ]; then
MAX_WORKERS=2
else
MAX_WORKERS=1
fi

# Check for debug mode
if [ "$1" == "--debug" ]; then
shift # Remove first argument
node $NODE_DEBUG_OPTION --inspect-brk node_modules/jest/bin/jest --runInBand --detectOpenHandles --verbose --config jest_ui.config.js "$@"
else
jest --config ./jest_ui.config.js --maxWorkers $MAX_WORKERS --forceExit "$@"
fi
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@
"test": "cross-env NODE_ENV=test jest --config ./jest.config.js",
"test:update": "cross-env NODE_ENV=test jest --config ./jest.config.js --updateSnapshot",
"test:debug": "cross-env NODE_ENV=test node --inspect-brk node_modules/.bin/jest --runInBand --verbose --config jest.config.js",
"device-tests": "cross-env NODE_ENV=test jest --maxWorkers=2 --testPathIgnorePatterns='canary|gutenberg-editor-rendering|ipad' --config jest_ui.config.js",
"device-tests-canary": "cross-env NODE_ENV=test jest --maxWorkers=2 --testPathPattern=@canary --config jest_ui.config.js",
"device-tests-ipad": "cross-env NODE_ENV=test IPAD=true jest --maxWorkers=2 --testPathPattern=@ipad --config jest_ui.config.js",
"device-tests:local": "APPIUM_HOME=~/.appium IOS_APP_PATH='./gutenberg/packages/react-native-editor/ios/build/GutenbergDemo/Build/Products/Release-iphonesimulator/GutenbergDemo.app' WDA_PATH='./gutenberg/packages/react-native-editor/ios/build/WDA' ANDROID_APP_PATH='./gutenberg/packages/react-native-editor/android/app/build/outputs/apk/debug/app-debug.apk' NODE_ENV=test jest --maxWorkers=2 --detectOpenHandles --config jest_ui.config.js",
"device-tests:debug": "IOS_APP_PATH='./gutenberg/packages/react-native-editor/ios/build/GutenbergDemo/Build/Products/Release-iphonesimulator/GutenbergDemo.app' WDA_PATH='./gutenberg/packages/react-native-editor/ios/build/WDA' ANDROID_APP_PATH='./gutenberg/packages/react-native-editor/android/app/build/outputs/apk/debug/app-debug.apk' cross-env NODE_ENV=test node $NODE_DEBUG_OPTION --inspect-brk node_modules/jest/bin/jest --runInBand --detectOpenHandles --verbose --config jest_ui.config.js",
"device-tests": "./bin/test-e2e.sh --testPathIgnorePatterns='canary|gutenberg-editor-rendering|ipad'",
"device-tests-canary": "./bin/test-e2e.sh --testPathPattern=@canary",
"device-tests-ipad": "IPAD=true ./bin/test-e2e.sh --testPathPattern=@ipad",
"device-tests:local": "./bin/test-e2e.sh --detectOpenHandles",
"device-tests:debug": "./bin/test-e2e.sh --debug --runInBand --detectOpenHandles --verbose",
"test:e2e:bundle:android": "npm run test:e2e:bundle:android:text && npm run test:e2e:bundle:android:bytecode",
"test:e2e:bundle:android:text": "mkdir -p gutenberg/packages/react-native-editor/android/app/src/main/assets && npm run rn-bundle -- -- -- -- --config ../../../metro.config.js --reset-cache --platform android --dev false --minify false --entry-file index.js --bundle-output ./android/app/src/main/assets/index.android.text.bundle --assets-dest ./android/app/src/main/res",
"test:e2e:bundle:android:bytecode": "./gutenberg/node_modules/react-native/sdks/hermesc/`node -e \"const platform=require('os').platform();console.log(platform === 'darwin' ? 'osx-bin' : (platform === 'linux' ? 'linux64-bin' : (platform === 'win32' ? 'win64-bin' : 'unsupported-os')));\"`/hermesc -emit-binary -O -out gutenberg/packages/react-native-editor/android/app/src/main/assets/index.android.bundle gutenberg/packages/react-native-editor/android/app/src/main/assets/index.android.text.bundle -output-source-map",
Expand Down