Fastlane uses UI tests to navigate your app and capture screenshots at specific moments.
Create ios/TipCalculatorUITests/TipCalculatorUITests.swift:
import XCTest
class TipCalculatorUITests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
}
func testTakeScreenshots() throws {
let app = XCUIApplication()
app.launch()
// Screenshot 1: Empty calculator
snapshot("01CalculatorEmpty")
// Navigate to bill input
let billField = app.textFields["Bill Amount"]
billField.tap()
billField.typeText("100.00")
// Screenshot 2: Bill entered
snapshot("02CalculatorBillEntered")
// Select 15% tip
app.buttons["15%"].tap()
snapshot("03Calculator15Percent")
// Select 20% tip
app.buttons["20%"].tap()
snapshot("04Calculator20Percent")
// Add person
app.buttons["Plus"].tap()
snapshot("05CalculatorSplit2People")
// Add another person
app.buttons["Plus"].tap()
snapshot("06CalculatorSplit3People")
}
}
In fastlane/Fastfile:
platform :ios do
desc "Take screenshots"
lane :screenshots do
snapshot(
scheme: "TipCalculator",
testplan: "ScreenshotTests",
devices: ["iPhone 14", "iPhone 14 Pro Max"],
languages: ["en-US"],
clear_previous_screenshots: true
)
end
end
Create android/app/src/androidTest/java/com/subnext/tipcalcbillsplit/ScreenshotTest.kt:
package com.subnext.tipcalcbillsplit
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import tools.fastlane.screengrab.Screengrab
import tools.fastlane.screengrab.locale.LocaleTestRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ScreenshotTest {
@get:Rule
val localeTestRule = LocaleTestRule()
@Test
fun testTakeScreenshots() {
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// Screenshot 1: Empty calculator
Screengrab.screenshot("01_calculator_empty")
// Find and fill bill amount
val billField = device.findObject(UiSelector().textContains("Bill Amount"))
billField.click()
billField.text = "100.00"
// Screenshot 2: Bill entered
Screengrab.screenshot("02_calculator_bill_entered")
// Select 15% tip
device.findObject(UiSelector().text("15%")).click()
Screengrab.screenshot("03_calculator_15_percent")
// Select 20% tip
device.findObject(UiSelector().text("20%")).click()
Screengrab.screenshot("04_calculator_20_percent")
// Add person
device.findObject(UiSelector().description("Plus")).click()
Screengrab.screenshot("05_calculator_split_2_people")
// Add another person
device.findObject(UiSelector().description("Plus")).click()
Screengrab.screenshot("06_calculator_split_3_people")
}
}
In fastlane/Fastfile:
platform :android do
desc "Take screenshots"
lane :screenshots do
screengrab(
app_apk_path: "android/app/build/outputs/apk/release/app-release.apk",
tests_apk_path: "android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk",
locales: ["en-US"],
clear_previous_screenshots: true,
app_package_name: "com.subnext.tipcalcbillsplit",
test_instrumentation_runner: "androidx.test.runner.AndroidJUnitRunner"
)
end
end
snapshot() (iOS) or Screengrab.screenshot() (Android) at key moments# iOS
fastlane ios screenshots
# Android
fastlane android screenshots
accessibilityLabel props we added make element finding reliableThis approach ensures consistent, professional screenshots that meet app store requirements!