diff --git a/.circleci/config.yml b/.circleci/config.yml index ef743965d..8cbe20b8e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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: @@ -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: @@ -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 >> ] diff --git a/e2e-tests/MaestroTestApp/test/widget_test.dart b/e2e-tests/MaestroTestApp/test/widget_test.dart new file mode 100644 index 000000000..1be85b2fd --- /dev/null +++ b/e2e-tests/MaestroTestApp/test/widget_test.dart @@ -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); + }); +} diff --git a/e2e-tests/maestro/e2e_tests/purchase_through_paywall.yaml b/e2e-tests/maestro/e2e_tests/purchase_through_paywall.yaml index c8c77376f..d4bf89990 100644 --- a/e2e-tests/maestro/e2e_tests/purchase_through_paywall.yaml +++ b/e2e-tests/maestro/e2e_tests/purchase_through_paywall.yaml @@ -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: @@ -32,4 +36,5 @@ name: Purchase through paywall - extendedWaitUntil: visible: "Entitlements: pro" timeout: 15000 +- takeScreenshot: purchase_through_paywall - Entitlements unlocked - assertVisible: "Entitlements: pro" diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9f258a1be..a22690969 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -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)