Files
Swiftgram/docs/ui-testing.md
2026-02-15 22:53:21 +04:00

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

  1. Create a new .swift file in Telegram/Tests/Sources/.
  2. The file is automatically picked up by the iOSAppUITestSuite target via the Bazel build — no manual target membership changes needed.
  3. Run with the same xcodebuild test command.

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:

  • X is the DC number (1, 2, or 3)
  • YYYY are 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) -> code 11111
  • DC 2 (+999 662 YYYY) -> code 22222
  • DC 3 (+999 663 YYYY) -> code 33333

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.