In an Appium fleet, how do you stop a degraded link on Android or iOS from outliving its session?
answer
- device state, not test state
- restore in teardown, including on failure
- read the state back, do not assume
- pair enable with disable on Apple
- do not cut your own control channel
basics
~20 sUndo it explicitly in teardown, on both paths. Android radios stay exactly as mobile: setConnectivity left them, so restore them and confirm with mobile: getConnectivity; on Apple hardware call mobile: disableConditionInducer. Do not assume deleting the session restores either.
solid answer
~40 sTreat link degradation as device state you borrowed, not as a test step. On **Android**, `mobile: setConnectivity` changes the real device: radios you switched off are still off for whatever runs next, and an emulator keeps whatever `mobile: networkSpeed` set until it is rebooted. Restore in a teardown that also runs on failure, and verify with `mobile: getConnectivity` instead of trusting the write. On **Apple real devices**, pair every `mobile: enableConditionInducer` with `mobile: disableConditionInducer`, and call the disable defensively at session start too. Two hazards make this worse than ordinary cleanup: a device attached over Wi-Fi loses the very transport carrying your commands the moment you switch Wi-Fi off, and a shared device left disconnected looks like broken hardware to whoever picks it up next.
go deeper
Know that these commands change the device itself: if a run switches Wi-Fi off with mobile: setConnectivity and never switches it back, the phone stays that way after the test process has exited.
Explain the undo on each side — writing the flags back with mobile: setConnectivity and confirming with mobile: getConnectivity on Android, mobile: disableConditionInducer on Apple hardware — and why a recycled emulator keeps a networkSpeed profile.
Demonstrate the operational habits: restore unconditionally, verify rather than assume, and recognise that a device left in airplane mode is reported as failing hardware by whoever picks it up next.
Own the policy: whether degraded-link work gets dedicated targets or a mandatory pre-session reset, so one leaked setting cannot quietly poison every later run on the same device.
## Degradation is device state, not test state Most of what a test does dies with the session: the app is closed, the element cache is dropped, the driver goes away. Network degradation does not. `mobile: setConnectivity` writes to the device's radios and `mobile: enableConditionInducer` turns on a profile in the operating system, and both of those outlive the process that asked for them. On a laptop with one attached phone that is a nuisance; on a shared fleet it is a defect that shows up in someone else's run. ## Android: what stays behind On Android there are two separate leftovers, and they are cleaned differently. - **Radios**, set by `mobile: setConnectivity`. Nothing in the session teardown puts them back. If a parking-permit renewal case switched mobile data off to assert the queued-renewal notice and then failed the assertion, the device is still without data when the next session starts. - **Emulator link speed**, set by the emulator-only `mobile: networkSpeed`. A re-used emulator carries that profile forward; a freshly booted one does not, which is why the symptom looks intermittent on a pool that sometimes recycles instances. The read-back is what turns cleanup from hope into verification: `mobile: getConnectivity` reports the state the device is actually in. Assert on it after restoring, and the difference between a leaked setting and a genuinely sick device stops being guesswork. ## Apple: pair every enable with a disable On Apple real devices, `mobile: enableConditionInducer` has an explicit counterpart, `mobile: disableConditionInducer`. Call it. There are two places worth calling it from: 1. **Teardown**, unconditionally, so a failing assertion cannot skip it. 2. **Session start**, defensively, so a device abandoned mid-run by an earlier crash starts clean rather than inheriting a profile. `mobile: listConditionInducers` tells you what the device can impose, which is also how you avoid hardcoding an identifier that a given device does not offer. The one thing not to do is rely on the session ending as the cleanup mechanism — the run should undo what it did, on the same path where it did it. ## Do not cut the branch you are sitting on There is a hazard on this leaf that other environment controls do not have: **the degradation can sever your own control channel**. Appium commands reach the device over a host connection. If that connection runs over the network rather than a cable, switching Wi-Fi off with `mobile: setConnectivity` kills the transport the next command needed, and the session dies holding the device in the state you were about to undo. On a fleet, prefer wired attachment for cases that take the radios down, and if that is not possible, degrade something narrower than the radio your control path is using. ## Undo, side by side | Left behind | Android | Apple real device | |---|---|---| | what leaks | radio state, emulator link profile | an enabled condition profile | | the undo | write the flags back with `mobile: setConnectivity` | `mobile: disableConditionInducer` | | the check | `mobile: getConnectivity` | `mobile: listConditionInducers` before enabling | | clears on reboot | emulator profile does, handset radios do not | not something to rely on | ## A restore that actually runs The practices that separate a suite that leaks from one that does not are unglamorous: - Put the restore in unconditional teardown, never as the last line of the test body, so a throw cannot skip it. - Restore before you assert wherever the assertion does not need the link down. - Verify the restore rather than assuming the write landed. - Reset defensively at session start, because the previous run may have died before its own teardown. - Log the degraded window with timestamps, so a later failure on the same device can be traced to a leak instead of to hardware. ## The symptom to recognise The reason this is a senior question is the shape of the bug report it produces. Nobody reports a leaked setting. They report that a device in the pool is unreliable, that installs time out on it, or that one device fails cases the others pass. A device stuck in airplane mode or holding a condition profile presents exactly like failing hardware, and the fix is a teardown fifty lines away in a case that already passed. Knowing that these two commands write through to the device — and that Appium keeps no snapshot to roll back to — is what lets you look in the right place.
- How do you tell a leaked network setting from genuinely broken device hardware in a fleet?Read or reset the state instead of guessing. On Android, `mobile: getConnectivity` reports the radios, so a device that behaves again after an explicit restore was leaking rather than failing. On an Apple real device, call `mobile: disableConditionInducer` at session start rather than trusting that the previous run cleaned up after itself.
- Where should the restore live so it survives a failing assertion?In unconditional teardown around the case, not the last line of the test body. If the assertion throws while the link is down, a restore written after it never runs and the next session inherits the damage. The same applies to the Apple side: `mobile: disableConditionInducer` belongs where a failure cannot skip it.
saying these in an interview costs you the question
- Assumes deleting the session restores connectivity
- Restores the link only on the happy path
- Leaves a condition inducer enabled on a shared iPhone
- Switches Wi-Fi off on a device attached over Wi-Fi
- Trusts the toggle instead of reading the state back
- Blames the next run's failure on flaky hardware