Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
4e1b968
feat: add CircleCI job for maestro E2E tests
ajpallares Feb 27, 2026
d688b75
fix: add CircleCI context and narrow sed targeting
ajpallares Feb 27, 2026
8a3221f
fix: use e2e-tests context and production App Store API key for iOS m…
ajpallares Mar 25, 2026
9be7e12
feat: split maestro e2e tests into separate iOS and Android workflows
ajpallares Mar 25, 2026
91cb71f
feat: pass MAESTRO_STORE env var to maestro tests in Fastlane lanes
ajpallares Mar 25, 2026
ea02b52
fix: use RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE for Android maestr…
ajpallares Mar 25, 2026
2b85031
refactor: use test store for all maestro e2e tests (iOS and Android)
ajpallares Mar 30, 2026
e1f0740
Add Maestro e2e test jobs to test PR workflow
ajpallares Mar 30, 2026
a31006e
Fix Fastlane path resolution and Android emulator boot timing
ajpallares Mar 30, 2026
5f321fc
Use Xcode 26.3 and iPhone 17 simulator for Maestro iOS e2e tests
ajpallares Mar 30, 2026
f3ff1f7
Fix Flutter Maestro CI: add flutter precache and ADB reconnection
ajpallares Mar 30, 2026
c3a57b8
Create test_output directory before maestro test report generation
ajpallares Mar 30, 2026
2248f52
Add screenshots and test output dir to Maestro e2e tests
ajpallares Mar 30, 2026
0608ede
Fix Android emulator recovery after long Gradle build
ajpallares Mar 30, 2026
38f4219
Refactor Android Maestro CI: use android orb, build before emulator
ajpallares Mar 30, 2026
a005fa4
Fix screenshot timing: capture before extendedWaitUntil
ajpallares Mar 30, 2026
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
84 changes: 84 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,62 @@ jobs:
name: Dry Run Release for purchases_ui_flutter
command: cd purchases_ui_flutter && flutter pub publish --dry-run

run-maestro-e2e-tests-ios:
executor:
name: macos-executor
xcode_version: "26.3"
steps:
- checkout
- revenuecat/install-gem-mac-dependencies:
cache-version: v1
- setup-flutter
- install-correct-cocoapods
- revenuecat/install-maestro
- run:
name: Boot iOS Simulator
command: |
xcrun simctl boot "iPhone 17" || true
xcrun simctl bootstatus "iPhone 17" -b
- run:
name: Run Maestro E2E Tests (iOS)
command: bundle exec fastlane run_maestro_e2e_tests_ios
no_output_timeout: 15m
- store_test_results:
path: fastlane/test_output
- store_artifacts:
path: fastlane/test_output

run-maestro-e2e-tests-android:
<<: *android-machine-emulator
steps:
- checkout
- run:
name: Install Ruby and Bundler
command: |
gem install bundler
bundle install
- setup-flutter
- run:
name: Build Maestro app (Android)
command: bundle exec fastlane build_maestro_app_android
no_output_timeout: 15m
- android/create-avd:
avd-name: test-e2e
system-image: system-images;android-34;google_apis;x86_64
install: true
- android/start-emulator:
avd-name: test-e2e
post-emulator-launch-assemble-command: ""
- revenuecat/install-maestro
- run:
name: Run Maestro E2E Tests (Android)
command: bundle exec fastlane run_maestro_e2e_tests_android
no_output_timeout: 15m
- store_test_results:
path: fastlane/test_output
- store_artifacts:
path: fastlane/test_output

update-hybrid-common-versions:
description: "Creates a PR updating purchases-hybrid-common to latest release"
docker:
Expand Down Expand Up @@ -551,6 +607,14 @@ workflows:
- android-integration-test-build
- test_main_sdk_min_version_compatibility
- test_ui_sdk_min_version_compatibility
- run-maestro-e2e-tests-ios:
context:
- maestro-e2e-tests
- e2e-tests
- run-maestro-e2e-tests-android:
context:
- maestro-e2e-tests
- e2e-tests

deploy:
when:
Expand Down Expand Up @@ -606,6 +670,26 @@ workflows:
equal: [ bump, << pipeline.parameters.action >> ]
jobs:
- revenuecat/automatic-bump
maestro-e2e-tests-ios:
when:
or:
- equal: ["maestro_e2e_tests", << pipeline.schedule.name >>]
jobs:
- run-maestro-e2e-tests-ios:
context:
- maestro-e2e-tests
- e2e-tests

maestro-e2e-tests-android:
when:
or:
- equal: ["maestro_e2e_tests", << pipeline.schedule.name >>]
jobs:
- run-maestro-e2e-tests-android:
context:
- maestro-e2e-tests
- e2e-tests

update-hybrid-common-versions:
when:
equal: [ upgrade-hybrid-common, << pipeline.parameters.action >> ]
Expand Down
30 changes: 30 additions & 0 deletions e2e-tests/MaestroTestApp/test/widget_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:maestro_test_app/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());

// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);

// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();

// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
5 changes: 5 additions & 0 deletions e2e-tests/maestro/e2e_tests/purchase_through_paywall.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ name: Purchase through paywall
- clearState
- pressKey: home
- launchApp
- takeScreenshot: purchase_through_paywall - Initial state after launch
- extendedWaitUntil:
visible: "Test Cases"
timeout: 30000
- takeScreenshot: purchase_through_paywall - After Test Cases visible
- assertVisible: "Test Cases"
- tapOn:
text: "Purchase through paywall"
- extendedWaitUntil:
visible: "Entitlements: none"
timeout: 15000
- takeScreenshot: purchase_through_paywall - Purchase screen
- assertVisible: "Entitlements: none"
- assertVisible: "Present Paywall"
- tapOn:
text: "Present Paywall"
- assertVisible: "Paywall V2"
- takeScreenshot: purchase_through_paywall - Paywall
- tapOn:
text: "Yearly"
- tapOn:
Expand All @@ -32,4 +36,5 @@ name: Purchase through paywall
- extendedWaitUntil:
visible: "Entitlements: pro"
timeout: 15000
- takeScreenshot: purchase_through_paywall - Entitlements unlocked
- assertVisible: "Entitlements: pro"
30 changes: 30 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,36 @@ lane :update_hybrid_common do |options|
)
end

desc "Run maestro E2E tests on iOS"
lane :run_maestro_e2e_tests_ios do
Dir.chdir("../e2e-tests/MaestroTestApp") do
sh("sed -i '' 's/MAESTRO_TESTS_REVENUECAT_API_KEY/'\"$RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE\"'/g' lib/main.dart")
sh("flutter precache --ios")
sh("flutter pub get")
sh("cd ios && pod install && cd ..")
sh("xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 17' -derivedDataPath build")
sh("xcrun simctl install booted build/Build/Products/Debug-iphonesimulator/Runner.app")
end
sh("mkdir -p test_output")
sh("maestro test --format junit --output test_output/report.xml --test-output-dir test_output ../e2e-tests/maestro/")
end

desc "Build maestro E2E test app for Android"
lane :build_maestro_app_android do
Dir.chdir("../e2e-tests/MaestroTestApp") do
sh("sed -i 's/MAESTRO_TESTS_REVENUECAT_API_KEY/'\"$RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE\"'/g' lib/main.dart")
sh("flutter pub get")
sh("flutter build apk --debug")
end
end

desc "Run maestro E2E tests on Android (emulator must be running)"
lane :run_maestro_e2e_tests_android do
sh("adb install ../e2e-tests/MaestroTestApp/build/app/outputs/flutter-apk/app-debug.apk")
sh("mkdir -p test_output")
sh("maestro test --format junit --output test_output/report.xml --test-output-dir test_output ../e2e-tests/maestro/")
end

desc "Trigger bump"
lane :trigger_bump do
trigger_action_in_circle_ci(action: 'bump', repo_name: repo_name)
Expand Down