4.7 KiB
UI Testing
Running Tests
xcodebuild test \
-project Telegram/Telegram.xcodeproj \
-scheme iOSAppUITestSuite \
-destination 'platform=iOS Simulator,name=iPhone 17,OS=26.1'
Pick any available simulator. List them with xcrun simctl list devices available iPhone.
Test Environment
Tests launch the app with the --ui-test argument. When the app detects this flag:
- It uses an isolated data directory (
telegram-ui-tests-data/inside the app group container), completely separate from production data. - That directory is wiped on every launch, so each test run starts with a clean slate.
- The app connects to Telegram test servers (not production). Test server accounts are independent of production accounts.
This means every test begins with the app in its first-launch state: no accounts, no data, showing the welcome/auth screen.
Writing Tests
Test files live in Telegram/Tests/Sources/. The test target is iOSAppUITestSuite.
Tests use Apple's XCUITest framework. Each test class extends XCTestCase and interacts with the app through XCUIApplication.
Template
import XCTest
class MyFeatureTests: XCTestCase {
private var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
app.launchArguments.append("--ui-test")
}
override func tearDownWithError() throws {
app = nil
}
func testSomething() throws {
app.launch()
// Find elements
let button = app.buttons["Start Messaging"]
// Wait for elements to appear
XCTAssert(button.waitForExistence(timeout: 5.0))
// Interact
button.tap()
// Assert
XCTAssert(app.textFields["Phone Number"].waitForExistence(timeout: 3.0))
}
}
Key Patterns
Always pass --ui-test in launchArguments. Without it, the app uses production servers and the real database.
Wait for elements rather than assuming they exist immediately. Use element.waitForExistence(timeout:) before interacting.
Find elements by accessibility identifier, label, or type:
app.buttons["Continue"] // by label
app.textFields["Phone Number"] // by placeholder/label
app.staticTexts["Welcome"] // static text
app.navigationBars["Settings"] // navigation bar
Relaunch between tests if needed. Each app.launch() call with --ui-test wipes the database, so every test method that calls launch() gets a fresh app state.
Type text into fields:
let field = app.textFields["Phone Number"]
field.tap()
field.typeText("9996621234")
Adding a New Test File
- Create a new
.swiftfile inTelegram/Tests/Sources/. - The file is automatically picked up by the
iOSAppUITestSuitetarget via the Bazel build — no manual target membership changes needed. - Run with the same
xcodebuild testcommand.
Telegram Test Servers
The test environment uses 3 separate Telegram datacenters, completely independent from production.
OS Environment
Test logins are guarded behind a specialized OS environment. The simulator or device must be configured for the test environment before test accounts can authenticate.
Test Phone Numbers
Test phone numbers follow the format 99966XYYYY:
Xis the DC number (1, 2, or 3)YYYYare random digits
The country code for test numbers is 999, and the remaining digits are 66XYYYY.
Examples: +999 66 2 1234, +999 66 1 0000, +999 66 3 0001.
Verification Codes
Test accounts do not receive real SMS. The confirmation code is the DC number repeated 5 times:
- DC 1 (
+999 661 YYYY) -> code11111 - DC 2 (
+999 662 YYYY) -> code22222 - DC 3 (
+999 663 YYYY) -> code33333
Flood Limits
Test numbers are still subject to flood limits. If a number gets rate-limited, pick a different YYYY suffix.
Deleting Test Accounts
Tests that exercise the sign-up flow create an account on the test servers. Re-running the same test with the same phone number will skip sign-up because the account already exists. To get a fresh sign-up screen, delete the account first with the test-helper CLI:
cd build-system/test-helper
swift run test-helper delete-account \
--api-id <id> --api-hash <hash> --phone 9996625678
The tool connects to the test datacenters, authenticates with the given number, and deletes the account. If no account exists, it exits successfully. Run it before any test that needs a clean sign-up flow.
The --api-id and --api-hash are your Telegram API credentials from my.telegram.org.
Security
Do not store any important or private information in test accounts. Anyone can use the simplified authorization mechanism to access them.