Blolabel
← Notes
foundational 7 min read

Apple's AppIntentsTesting runs an app's own intents with "no mocks, no stubs" and no UI at all; phoneshell's one Shortcuts call is a URL string with no return type

Every tool this site measures drives a phone by pretending to be a finger: tap a point, type into a field, read the screen back. Apple's own AppIntentsTesting framework, shown at WWDC26, skips the finger and the screen entirely by calling an app's intent code directly and checking what comes back. phoneshell's nearest equivalent is a URL string with nothing to check at all.

WWDC26 session 295, "Validate your App Intents adoption with AppIntentsTesting," a roughly 26-minute talk, introduces AppIntentsTesting as a framework for checking an app's App Intents through the same infrastructure Siri, Shortcuts and Spotlight already use to call into it. The session's own description says it lets a developer "execute intents, inspect results, and test entities and queries" without UI automation. Working from a sample calendar app called CometCal, the speaker builds a UI-testing bundle, constructs an IntentDefinitions object from the app's bundle identifier, calls makeIntent with parameters, runs the intent on-device, and asserts on the entity it returns, stating directly that the test runner "executes your App Intents across process boundaries" and receives results "with no mocks, no stubs," and that the tests "don't depend on any UI" at all. The test bundle needs only the target app's bundle identifier, not a copy of its source.

Abstract technical illustration on a dark grid: on one side a chain of glyphs showing a finger-tap icon feeding a screen-rectangle icon feeding an eye icon reading it back, representing UI automation, and on the other side a single direct glowing line from a code-bracket icon straight to a typed-value icon, bypassing any screen shape entirely, cool blues and teals with one amber accent on the direct line

What changed, and when

App Intents itself is not new: Apple has been pushing developers toward it since SiriKit's deprecation was raised at WWDC 2026, and this site has already covered the companion session on onscreen awareness from the same week. What session 295 adds is specifically a testing story, and the gap it closes is concrete. Before AppIntentsTesting, confirming that an app's own App Intents worked meant either driving the UI that exposes them (a Shortcuts run, a Siri request, a Spotlight tap) or writing bespoke unit tests against intent classes directly, with no shared harness and no guarantee either path matched what the system actually does when it calls an intent for real. AppIntentsTesting routes a test through the exact mechanism Siri, Shortcuts and Spotlight use, so passing it is evidence about the real call path, not a proxy for it.

The session also describes a layered testing strategy rather than a single tool: unit-test the fundamental types first, actions, data, and queries, in isolation; then integration-test the deeper system reaches, view annotations, Spotlight indexing, and intents that combine across apps; and still test manually with Siri and Shortcuts on top of both, because AppIntentsTesting validates the intent layer, not the voice or suggestion layer sitting above it.

Two ways to check whether an app did the thing UI automation (phoneshell, XCUITest, Appium) agent / test script simulated tap / type rendered UI changes read screenshot / a11y tree back to check AppIntentsTesting test bundle, app's bundle id makeIntent(params) runs in app's own processno mocks, no stubs typed entity, asserted directly No screen, no tap, no screenshot, and no accessibility-tree read anywhere in the second path. Source: WWDC26 session 295 transcript and chapter list, developer.apple.com/videos/play/wwdc2026/295, read 23 October 2026.

What phoneshell has instead of an intent layer

phoneshell/apps.py defines an APP_SHORTCUTS table of deeplinks it can fire to skip past UI steps, and exactly one entry in that table touches Apple's own intents system at all: "com.apple.shortcuts": {"run": "shortcuts://run-shortcut?name={name}&input=text&text={text}"}, a URL scheme that asks the Shortcuts app to run a named shortcut with a single text input. It has none of the structure AppIntentsTesting is built around: no typed parameter list, no entity query, and critically, no return value. Firing the URL tells iOS to go run something; whatever that something actually did has to be confirmed the same way every other phoneshell task confirms anything, by reading the screen or the accessibility tree afterward. phoneshell's whole grading model, scoring a task from device state rather than an agent's self-report, exists because it has no other channel into what happened; AppIntentsTesting's whole point is that App Intents give you that other channel for free, a typed value handed back across a process boundary with no screen involved at any point.

DimensionAppIntentsTestingphoneshellSource
What gets calledThe app's own App Intent, via makeIntentA Shortcuts URL scheme, shortcuts://run-shortcutWWDC26 session 295; phoneshell/apps.py
ParametersTyped, declared on the intentTwo untyped strings interpolated into a URLWWDC26 session 295; phoneshell/apps.py
Return valueA typed entity, asserted on directlyNone; the URL call returns nothing to checkWWDC26 session 295; phoneshell/apps.py
How success is confirmedIn-process assertion, same callA later screenshot or accessibility-tree read, separate stepWWDC26 session 295; phoneshell/bench checks
UI involvedNone; explicitly stated in the sessionAlways; it is the only channel phoneshell hasWWDC26 session 295; phoneshell houseFacts

What it means for anyone grading a phone agent rather than an app's own code

Three layers for Apple's intents, one layer for all 80 phoneshell tasks AppIntentsTesting's layered strategy (WWDC26 session 295) Unit layer actions, data, queries, in isolation Integration layer view annotations, Spotlight indexing, cross-app intents Manual layer Siri and Shortcuts tested on top of both phoneshell's strategy 1 layer, applied to all 80 tasks device-state check: a screenshot or accessibility-tree read, taken after the action runs same depth whether the task is a single tap or a compound, multi-step action across several apps no unit layer, no integration layer, no separate manual pass: 1 check stands in for all three Source: WWDC26 session 295 transcript and chapter list; phoneshell bench task definitions, read 23 October 2026.

Check it yourself

# WWDC26 session 295's own description and chapter list
open "https://developer.apple.com/videos/play/wwdc2026/295"
# community transcript and chapter index:
curl -s https://nonstrict.eu/wwdcindex/wwdc2026/295/ | grep -i "makeIntent\|no mocks\|no UI\|IntentDefinitions"

git clone https://github.com/Blomega/phoneshell && cd phoneshell
grep -n "APP_SHORTCUTS" -A5 phoneshell/apps.py     # the one Shortcuts deeplink, and everything it is missing
grep -rn "makeIntent\|IntentDefinitions\|AppIntentsTesting" phoneshell/ || echo "phoneshell has no App Intents test layer"

What would prove this wrong

We claim phoneshell has no channel for confirming an action's result other than reading the screen or accessibility tree afterward. That is wrong the moment any call in phoneshell/apps.py or elsewhere in the repository reads a typed return value from an intent, a Shortcuts run, or any API call rather than inferring success from device state; we found none as of 23 October 2026. We also report AppIntentsTesting as requiring only the target app's bundle identifier, not its source, based on the session's own framing; that is wrong if the full documentation describes additional requirements the 26-minute session omitted, which we will check against Apple's AppIntentsTesting reference pages by 30 April 2027.

Sources

  1. Apple, Validate your App Intents adoption with AppIntentsTesting, WWDC26 session 295, read 23 October 2026.
  2. Community transcript and chapter index, nonstrict.eu/wwdcindex/wwdc2026/295, read 23 October 2026.
  3. Session summary, wwdcnotes.com, read 23 October 2026.
  4. Blolabel, phoneshell/apps.py, APP_SHORTCUTS, read 23 October 2026.