Skip to content
Open
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
83 changes: 83 additions & 0 deletions .github/workflows/ci-browserstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI/CD with BrowserStack

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:

env:
NODE_VERSION: '20'
JAVA_VERSION: '17'

jobs:
test:
name: Build & Test on BrowserStack
runs-on: ubuntu-22.04
timeout-minutes: 30

steps:
- name: 📥 Checkout code
uses: actions/checkout@v4

- name: 📦 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: ☕ Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}

- name: 📱 Setup Android SDK
run: |
mkdir -p $HOME/android-sdk
cd $HOME/android-sdk
wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip
unzip -q commandlinetools-linux-9477386_latest.zip
mkdir -p cmdline-tools/latest
mv cmdline-tools/* latest/ 2>/dev/null || true
mv latest cmdline-tools/ 2>/dev/null || true
yes | ./cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null 2>&1 || true
./cmdline-tools/latest/bin/sdkmanager "platform-tools" "platforms;android-33" "build-tools;33.0.0"
echo "ANDROID_HOME=$HOME/android-sdk" >> $GITHUB_ENV
echo "ANDROID_SDK_ROOT=$HOME/android-sdk" >> $GITHUB_ENV
echo "$HOME/android-sdk/platform-tools" >> $GITHUB_PATH

- name: 📥 Install dependencies
run: npm ci

- name: 🔨 Build Android APK
run: |
cd android && ./gradlew assembleDebug && cd ..
env:
ANDROID_HOME: ${{ env.ANDROID_HOME }}
ANDROID_SDK_ROOT: ${{ env.ANDROID_SDK_ROOT }}

- name: 🧪 Run E2E Tests on BrowserStack
run: npm run test:e2e:browserstack:all
env:
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
BROWSERSTACK_APP_ID: ${{ secrets.BROWSERSTACK_APP_ID }}

- name: 📊 Generate Allure Report
if: always()
run: npm run allure:generate

- name: 📤 Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
allure-results/
test-results/
screenshots/
retention-days: 7
if-no-files-found: ignore

149 changes: 149 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
name: E2E Tests

on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
workflow_dispatch:

jobs:
e2e-tests:
name: Appium E2E Tests
runs-on: macos-latest

strategy:
matrix:
api-level: [33]
target: [default]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}

- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
android/.gradle
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Install dependencies
run: npm ci

- name: Create Android emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: x86_64
profile: Nexus 6
script: |
echo "Emulator is ready"
adb devices

- name: Build Android APK
working-directory: android
run: |
chmod +x gradlew
./gradlew assembleDebug
env:
ANDROID_HOME: ${{ env.ANDROID_HOME }}
ANDROID_SDK_ROOT: ${{ env.ANDROID_SDK_ROOT }}

- name: Verify APK exists
run: |
if [ ! -f "android/app/build/outputs/apk/debug/app-debug.apk" ]; then
echo "APK not found!"
exit 1
fi
ls -lh android/app/build/outputs/apk/debug/

- name: Install Appium
run: |
npm install -g appium@latest
appium driver install uiautomator2

- name: Start Appium server
run: |
appium --log-level info --log ./logs/appium.log &
sleep 10
echo "Appium server started"

- name: Wait for emulator to be ready
run: |
adb wait-for-device
adb shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\''\r'\'') ]]; do sleep 1; done'
adb shell input keyevent 82
echo "Emulator is fully booted"

- name: Run E2E tests
run: npm run test:e2e
env:
ANDROID_HOME: ${{ env.ANDROID_HOME }}
ANDROID_SDK_ROOT: ${{ env.ANDROID_SDK_ROOT }}

- name: Generate Allure report
if: always()
run: |
npm run allure:generate || true

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
test-results/**/*.xml
allure-results/**/*
screenshots/**/*
logs/**/*.log
retention-days: 30

- name: Upload Allure report
if: always()
uses: actions/upload-artifact@v4
with:
name: allure-report
path: allure-report/
retention-days: 30

- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v4
with:
name: failure-screenshots
path: screenshots/
retention-days: 7

- name: Check test results
if: always()
run: |
if [ -f "test-results/results-0-0.xml" ]; then
echo "Test results found"
else
echo "No test results found"
fi

8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ metro-health-check*
# Testing & Coverage
# ===============================
/coverage
/e2e/logs
/e2e/test-results
/e2e/inspector-capabilities-ready.json
/logs
/test-results
/screenshots
/allure-results
/allure-report

# ===============================
# Misc / Temp / Local
Expand Down
77 changes: 77 additions & 0 deletions BROWSERSTACK_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# BrowserStack CI/CD Setup

Simple guide for setting up BrowserStack E2E testing with CI/CD.

## 🚀 Quick Setup

### 1. Get BrowserStack Credentials
From [browserstack.com/accounts/settings](https://www.browserstack.com/accounts/settings):
```bash
export BROWSERSTACK_USERNAME="your_username"
export BROWSERSTACK_ACCESS_KEY="your_access_key"
```

### 2. Build & Upload APK
```bash
# Build
cd android && ./gradlew assembleDebug && cd ..

# Upload to BrowserStack
npm run browserstack:upload-app

# Copy the App ID from output
export BROWSERSTACK_APP_ID="bs://your_app_id"
```

### 3. Run Tests
```bash
# Local
npm run test:e2e:browserstack:all

# CI/CD - Add to GitHub Secrets:
# - BROWSERSTACK_USERNAME
# - BROWSERSTACK_ACCESS_KEY
# - BROWSERSTACK_APP_ID
```

## 📋 Commands

```bash
npm run browserstack:upload-app # Upload APK
npm run test:e2e:browserstack:all # Run all tests
npm run test:e2e:browserstack:home # Run home tests
npm run test:e2e:browserstack:cross-feature-integration
npm run test:e2e:browserstack:semester-content
```

## 🐛 Troubleshooting

| Issue | Solution |
|-------|----------|
| "Credentials required" | Set `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY` |
| "App ID required" | Upload APK: `npm run browserstack:upload-app` |
| "App not found" | App ID expired (30 days), re-upload |
| Upload fails (401) | Check credentials |
| APK not found | Build first: `cd android && ./gradlew assembleDebug` |

## ⚙️ Configuration

**Default Device:** Samsung Galaxy S23 (Android 13.0)

**Custom Device:**
```bash
DEVICE_NAME="Google Pixel 7" OS_VERSION="13.0" \
npm run test:e2e:browserstack:all
```

**CI/CD Workflow:** `.github/workflows/ci-browserstack.yml`
- Builds APK
- Runs tests on BrowserStack
- Generates Allure reports
- Uploads artifacts

## 📊 Reports

- **Allure:** `npm run allure:generate && npm run allure:open`
- **BrowserStack Dashboard:** [app-automate.browserstack.com](https://app-automate.browserstack.com/dashboard/v2/builds)
- **GitHub Artifacts:** Available after workflow runs
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ android {
applicationId "technark.bca_courprogramming"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 117
versionName "10.86"
versionCode 118
versionName "10.88"
}
signingConfigs {
debug {
Expand Down
Loading