Test iOS Dynamic Type layouts on a cloud Mac

Test iOS Dynamic Type layouts on a cloud Mac

The order confirmation page shows the full address and submit button at the default text size. But when a user increases the text size on their iPhone, the fixed bar at the bottom covers the button. This is easy to miss when opening the page once on a development machine: Dynamic Type changes line wrapping, cell heights, and the scrollable area—not just the size of the text. The steps below use an iOS Simulator on a cloud Mac to keep test conditions consistent, then use UI tests to check the critical user path.

Define the test scope and pass criteria

Choose a real page with substantial content, such as an order confirmation, settings detail, or error explanation. Record the Xcode project, scheme, simulator device, iOS runtime, and test account state. Use the same set of conditions for every comparison. If several people share the cloud Mac, assign this test its own simulator device so another task cannot change the text size or clear the app’s data.

List the actions a user must be able to complete before writing assertions. At a minimum, check that the heading is readable, the primary button works, the end of a long explanation can be reached by scrolling, and the user can go back. Checking that a view exists does not prove its text has not been clipped.

What to check Testable pass criterion What to review manually
Page heading The expected accessibility identifier can be found Whether wrapped text overlaps adjacent content
Primary action The button can be tapped after scrolling and leads to the expected state Whether the button label is fully visible
Long explanation The final section can be scrolled into view Whether text or container edges are clipped

Break “looks fine” into actions the test can perform and screenshots someone needs to review. Assertions catch clear failures; screenshots reveal visual problems the assertions do not yet describe.

Keep the simulator consistent and change text size

On the cloud Mac, first confirm that the Xcode command-line tools point to the expected version, then list the available devices. Do not assume booted always refers to the same device: concurrent tasks on the same machine may start multiple simulators. Put the target device’s UDID in the task configuration, start it, and wait for it to finish booting.

xcode-select -p
xcrun simctl list devices available
export SIM_UDID="从上一步选择的设备 UDID"
xcrun simctl boot "$SIM_UDID"
xcrun simctl bootstatus "$SIM_UDID" -b
xcrun simctl help ui

If the device is already running, boot will report its current state. After confirming the UDID, proceed directly to bootstatus. Check the text-size values accepted by simctl ui against the help supplied with the installed tools; do not copy size names from a different Xcode version into the script. Pass a locally verified value to the test task—for example, through the TEXT_SIZE environment variable—then run:

: "${TEXT_SIZE:?set a supported content size}"
xcrun simctl ui "$SIM_UDID" content_size "$TEXT_SIZE"
xcrun simctl ui "$SIM_UDID" content_size

Test at least the default size, a larger size, and the largest size the product promises to support. Do not test only the extremes: an intermediate size may make a heading wrap onto an extra line without triggering the layout intended for the largest size. Relaunch the app after each change so the page under test is not left in a state cached before the switch.

Use UI tests to check the user path

Give key controls stable accessibility identifiers in the app, such as checkout.title, checkout.submit, and checkout.lastNote. Identifiers should describe a control’s function rather than depend on button text that changes with the language. Start the test from the same initial page each time. If login or test data is required, use the project’s existing test environment; do not put real credentials in test code or logs.

The XCTest snippet below illustrates the assertions. Replace the navigation and success-state identifiers to match the project. On a long page, scroll before checking whether the final section and button can be reached and used:

let app = XCUIApplication()
app.launch()
let title = app.staticTexts["checkout.title"]
XCTAssertTrue(title.waitForExistence(timeout: 10))

let page = app.scrollViews["checkout.content"]
let lastNote = app.staticTexts["checkout.lastNote"]
for _ in 0..<6 where !lastNote.isHittable {
    page.swipeUp()
}
XCTAssertTrue(lastNote.isHittable)

let submit = app.buttons["checkout.submit"]
for _ in 0..<6 where !submit.isHittable {
    page.swipeUp()
}
XCTAssertTrue(submit.isHittable)
submit.tap()
XCTAssertTrue(app.staticTexts["checkout.success"].waitForExistence(timeout: 10))

If the page is not a ScrollView, do not force the example’s selector to fit; adapt it to the actual container. Limiting the number of swipes prevents a broken layout from leaving the test waiting indefinitely. But a tappable button may still have a clipped label, so keep the screenshots.

Capture evidence for each size and diagnose failures

For each size, record the device UDID, runtime, Xcode version, text-size setting, and test result. When a test fails, save its UI-test attachments first. Then rerun at the same size and capture a simulator screenshot. Include the size and page name in the screenshot filename so concurrent tasks do not overwrite one another’s files. To capture a screenshot from the command line, run xcrun simctl io "$SIM_UDID" screenshot output.png; in the actual task, replace the fixed filename with a unique output path.

When reviewing a screenshot, look for the cause in the outer layout first. A fixed-height heading container can hide the second line; a label and amount arranged horizontally can compete for width; a floating button at the bottom of the screen can cover the final paragraph. Prefer letting text containers grow with their content. Where necessary, stack information vertically instead of horizontally and leave room below scrollable content. Do not hide a large-text failure by reducing the text size.

If a test passes only intermittently, first check that it always uses the same UDID, that the app relaunches after each size change, and that an assertion has not selected an identically named element off-screen. Stabilize those conditions before changing the layout, so device-state contamination is not mistaken for a code regression.

Turn the checks into a maintainable checklist

Put the device, runtime, and supported text sizes in the test task configuration, and run the same UI tests at every size. For each failure, keep the size, assertion location, and screenshot. After each fix, retest at least the failing size and its neighboring sizes. Schedule screenshot reviews for clipping and overlap that lack reliable automated checks; do not treat “element exists” as a release-ready verdict.

Finally, walk through the most important user path by hand: enlarge the text, read the explanation to the end, find the primary button, complete the action, and go back. The goal is not to produce identical screenshots at every text size. It is to ensure that users can read all the content and complete the actions at every supported size.

Frequently asked questions

Is testing only the largest text size enough?

No. Check at least the default size, a larger size, and your highest supported size. An intermediate step can introduce its own line-wrap failure.

Does finding an element in a UI test prove the layout works?

No. Verify that important actions are reachable and content can be scrolled into view, then inspect failure screenshots for clipping.

Hand your next build to a dedicated cloud Mac.

Compare ViewMini models, regions, and rental terms, then choose a physical node that fits your workflow.

Configure your cloud Mac

Compare devices and rental terms

Choose from three models, with daily, weekly, monthly, and quarterly pricing. Review the full plans before ordering.

View models and pricing Configure your cloud Mac