diff --git a/.github/workflows/e2e-ios.yml b/.github/workflows/e2e-ios.yml new file mode 100644 index 0000000000..ea72121928 --- /dev/null +++ b/.github/workflows/e2e-ios.yml @@ -0,0 +1,143 @@ +--- +name: E2E Tests (iOS) + +on: + workflow_dispatch: + +jobs: + e2e-ios: + name: E2E Tests (iOS) + runs-on: macos-26-xlarge + timeout-minutes: 60 + steps: + - name: โฌ‡๏ธ Checkout + uses: actions/checkout@v4 + + - name: ๐Ÿ”ง Setup Node + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: yarn + + - name: โš™๏ธ Install dependencies + run: yarn install --frozen-lockfile + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: "26.0" + + - name: โ˜•๏ธ Setup Cocoapods + uses: maxim-lobanov/setup-cocoapods@v1 + with: + version: 1.16.2 + + - name: ๐Ÿ’พ Cache Pods + uses: actions/cache@v4 + with: + path: ./ios/Pods + key: ${{ runner.os }}-pods-${{ hashFiles('yarn.lock') }} + + - name: ๐Ÿ”ค Compile translations + run: yarn intl:build + + - name: โœ๏ธ Write .env + run: | + cp .env.example .env + sed -i '' 's/^EXPO_PUBLIC_ENV=.*/EXPO_PUBLIC_ENV=e2e/' .env + + - name: ๐Ÿ—๏ธ Build iOS app (release) + run: > + EXPO_PUBLIC_ENV=e2e + NODE_ENV=test + RN_SRC_EXT=e2e.ts,e2e.tsx + npx expo run:ios --configuration Release --no-install + + - name: ๐Ÿ“ฑ Find .app path + id: find-app + run: | + APP_PATH=$(find ~/Library/Developer/Xcode/DerivedData -name "Bluesky.app" -path "*/Release-iphonesimulator/*" | head -1) + if [ -z "$APP_PATH" ]; then + echo "Could not find built .app" + exit 1 + fi + echo "APP_PATH=$APP_PATH" >> $GITHUB_OUTPUT + echo "Found app at: $APP_PATH" + + - name: ๐Ÿ˜ Setup Postgres + run: | + brew install postgresql@14 + export PATH="/opt/homebrew/opt/postgresql@14/bin:$PATH" + initdb -D /tmp/pgdata -U pg + echo "password" > /tmp/pgpassfile + pg_ctl -D /tmp/pgdata -o "-p 5433 -k /tmp" -l /tmp/pg.log start + # Set password for pg user + psql -h /tmp -p 5433 -U pg -d postgres -c "ALTER USER pg PASSWORD 'password';" + # Update pg_hba.conf to use md5 auth for TCP connections + echo "host all all 127.0.0.1/32 md5" >> /tmp/pgdata/pg_hba.conf + echo "host all all ::1/128 md5" >> /tmp/pgdata/pg_hba.conf + pg_ctl -D /tmp/pgdata -o "-p 5433 -k /tmp" reload + + - name: ๐Ÿ”ด Setup Redis + run: | + brew install redis + redis-server --port 6380 --daemonize yes --logfile /tmp/redis.log + + - name: ๐Ÿ–ฅ๏ธ Start mock server + run: | + DB_POSTGRES_URL="postgresql://pg:password@127.0.0.1:5433/postgres" \ + REDIS_HOST="127.0.0.1:6380" \ + yarn ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts & + # Wait for mock server to be ready + echo "Waiting for mock server on port 1986..." + for i in $(seq 1 30); do + if curl -s http://localhost:1986 > /dev/null 2>&1; then + echo "Mock server is ready" + break + fi + if [ $i -eq 30 ]; then + echo "Mock server failed to start" + exit 1 + fi + sleep 1 + done + + - name: ๐Ÿ“ฒ Boot simulator and install app + id: sim + run: | + SIM_UDID=$(xcrun simctl create "E2E-iPhone" "iPhone 16 Pro") + echo "SIM_UDID=$SIM_UDID" >> $GITHUB_OUTPUT + xcrun simctl boot "$SIM_UDID" + xcrun simctl install "$SIM_UDID" "${{ steps.find-app.outputs.APP_PATH }}" + + - name: ๐Ÿ”„ Swap setupApp for CI + run: cp __e2e__/setupApp.ci.yml __e2e__/setupApp.yml + + - name: ๐ŸŽญ Install Maestro + run: | + curl -Ls "https://get.maestro.mobile.dev" | bash + echo "$HOME/.maestro/bin" >> $GITHUB_PATH + + - name: ๐Ÿงช Run Maestro tests + run: > + $HOME/.maestro/bin/maestro + --device "${{ steps.sim.outputs.SIM_UDID }}" + test __e2e__/flows + --format junit + --output maestro-results.xml + + - name: ๐Ÿ“Š Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: maestro-results + path: maestro-results.xml + + - name: ๐Ÿ“‹ Upload failure logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: failure-logs + path: | + /tmp/pg.log + /tmp/redis.log + ~/.maestro/tests/**/* diff --git a/__e2e__/setupApp.ci.yml b/__e2e__/setupApp.ci.yml new file mode 100644 index 0000000000..62357b3b81 --- /dev/null +++ b/__e2e__/setupApp.ci.yml @@ -0,0 +1,11 @@ +appId: xyz.blueskyweb.app +--- +- launchApp: + appId: "xyz.blueskyweb.app" + clearState: true + arguments: + "-EXDevMenuIsOnboardingFinished": true +- tapOn: + id: e2eProxyHeaderInput +- inputText: ${output.result} +- pressKey: Enter