← back to the section

Checkout has been tested inside out: card, promo code, receipt. Then the phone rings while a real user is typing the card number. A minute later he comes back — the cart is empty, the promo code is gone, the app has reopened on the home screen. The feature works; the payment does not exist.

A phone differs from a browser by more than screen size — layout and screen sets have their own article. This one is about something else: the screen, the memory, the network and the camera belong to the operating system, which can push your app aside or unload it entirely at any moment.

the checkout screen: what is still in memory at every step 1 · opencart: 3 itemspromo appliedstep 2 of 3hold timer runs 2 · backgrounda call, a bannerprocess alivescreen hiddenvideo and sound? 3 · resumedprocess alive —everything intacthold expired?request twice? 4 · killedmemory ran outprocess killedfields are emptyscreen built anew the user never saw the process die:he came back to the app and found an empty form

The fourth step is not an edge case but normal behaviour when memory runs low. If the app has not saved the state of the screen, coming back from the background looks like a reset: the typed data is gone, the form step is forgotten, and the hold on the goods may have expired meanwhile. To the user all four steps are one action — "I switched away and came back".

Native, hybrid, web and PWA

"Mobile app" means four different things, and which one you have in front of you decides where to look for the cause.

Native is written for one system (Kotlin or Java on Android, Swift on iOS) and installed from a store. Hybrid is a web page inside a wrapper window: the buttons look native but are drawn with HTML and CSS, so half of the defects here are plain web defects and half live on the seam with the camera and notifications. A mobile site lives in the phone browser and updates instantly. A PWA is the same site placed on the home screen: its own icon, no address bar, part of the data available without a network.

Three things differ for testing: how a new version arrives (a store with review and a staged rollout — or a page refresh for everyone at once), where the logs are (the system journal — or the browser console), and what the system grants (camera, fingerprint, notifications, files — a web version gets less).

Interruptions: the first thing to check

A call, an alarm, a notification, the home button, a map on top — the screen goes into the background and comes back a minute later. Sometimes not the same one: the system ran short of memory and unloaded the process.

This is checked first because almost everything breaks here: an unsaved draft, a hold timer, a video that kept playing over the call, a payment sent twice after the return.

The set is the same for any app: minimise halfway through a form and come back; take an incoming call; pull down the notification shade; rotate the screen; lock and unlock; close the app from the task list and open it again.

Waiting for a real kill is pointless: the Android developer menu has a "Don't keep activities" switch — the system destroys the screen the moment it leaves the foreground, and lost state shows up in a minute.

Network: switching and offline

Wi-Fi is steady on the test bench; the user has a subway, a lift and a switch from home Wi-Fi to mobile data at the door. A phone network is not simply on or off: it can be slow and it breaks in the middle of a transfer.

What to check: airplane mode halfway through a submit — the app says there is no connection instead of an empty screen, and keeps what was typed; the network comes back — data reloads by itself or on a button, without a restart; a switch from Wi-Fi to mobile data during a request; a slow channel — speed profiles exist in the emulator and in DevTools.

The main trap is the retry: the request went out, the server ran it, the response never arrived, the app sent it again — and a second order appeared. The check: cut the network right after "Pay", bring it back, and count how many orders and charges you got.

Permissions: granted, denied, revoked

The camera, location, notifications, contacts and files all come from the system, and the user can change his mind at any moment. There are three states, and usually only one is tested.

Granted is the normal path. Denied — the app must stay usable: explain why the permission is needed and leave a way around it (an address typed by hand instead of geolocation). Revoked later in the settings is the most fragile case: on Android revoking kills the process and the app starts from scratch. "Deny and don't ask again" needs its own check: the system dialog never appears again, so the app itself has to lead the user into the settings.

Install, upgrade and version

A clean install and an upgrade over an old build are two different scenarios, and it is usually the second that breaks: the user already has data from the previous version, a saved login and a cache, and the new build has to survive all of it.

The order is: install the previous version, log in, create data, then upgrade to the new build. The login survived, the data opened, the old screens do not crash.

A build carries two numbers: the one the user sees (3.4.1) and an internal one that grows with every build. A defect report needs both, plus the phone model and the system version, or there is nothing to reproduce on. The store also rolls a release out gradually: "mine updated, yours didn't" is normal, not a defect.

A deep link opens a specific screen rather than the home one: an email about an order goes straight to that order. Check it in three app states: open, backgrounded, closed. The third breaks most often — the app starts from scratch and loses the link on the way. Two more cases: the user is not logged in (after the login he must land on the intended screen) and the object is deleted (a clear message instead of a blank).

Notifications have the same three states: open — the notification does not cover the work; backgrounded — it lands in the shade; closed — a tap wakes the app and opens the right screen. Plus the small things: long text cut off, several notifications in a row, the badge counter, notifications switched off in the system settings.

Where to test: devices, emulators, farms

There are thousands of phone models, dozens of system versions, and on top of them vendor shells that save battery by killing background work their own way. The set is picked from your audience statistics; four or five devices usually cover it: the most common model, the oldest supported system version, the smallest screen, one iPhone and one Android.

An Android emulator runs a real system image on your computer. An iOS simulator is not a phone but a build of the app for macOS: memory and speed behave differently and some capabilities are missing. Neither gives a real camera, a fingerprint, a weak processor, a draining battery or an actual mobile network. So screens are covered on the emulator, while money, camera, network and interruptions go on a live device. No such model on the team — rent a cloud device farm: real phones by the minute, with a remote screen and logs.

Where to read the logs

"It crashed" without logs is not a defect, it is a note about bad luck. On Android the journal is read through adb: adb devices shows the connected phone, adb logcat streams the system journal (in Android Studio this is the LogCat tab with a filter by app), adb install app.apk installs a build, adb shell pm clear <package> wipes its data back to a clean install. On iOS the same thing lives in Console on a Mac or in the Xcode devices window. A crash stack in the bug report saves a developer a day of searching.

In short

  • A mobile app lives under the system: it is backgrounded, unloaded and stripped of permissions without asking.
  • Interruptions come first; a kill by the system is reproduced with the "Don't keep activities" switch in the Android developer menu.
  • The network switches and dies mid-request; the main trap is a retry that creates a second order.
  • A permission has three states — granted, denied, revoked later — and revoking restarts the app on Android.
  • An upgrade over an old build is its own scenario: data, login and cache must survive the new version.
  • Emulators and simulators are fine for screens; money, camera, network and interruptions belong on a live device.