2026 AI & Machine Learning
WWDC26 · 26 min · AI & Machine Learning
Validate your App Intents adoption with AppIntentsTesting
Meet AppIntentsTesting, a new framework for validating your App Intents through the same infrastructure used by Siri, Shortcuts, and Spotlight. Discover how to execute intents, inspect results, and test entities and queries — all without requiring UI automation. Find out how to verify integrations like View annotations and Spotlight indexing, helping you catch bugs early in your development workflow.
Watch at developer.apple.com ↗Chapters
- 0:16 — Introduction
- 2:01 — Meet CometCal: your first test
- 2:29 — How AppIntentsTesting works
- 9:39 — Testing entity queries
- 13:49 — Combining multiple intents
- 16:27 — Test-only intents
- 18:22 — Testing Spotlight indexing
- 20:56 — Testing view annotations
- 24:00 — The App Intents testing workflow
- 25:19 — Next steps
Code shown on screen · 7 snippets
Your first test: execute an intent
import AppIntentsTesting
func testCreateCalendar() async throws {
let definitions = IntentDefinitions(bundleIdentifier: "com.example.apple-samplecode.CometCal")
let createCalendar = definitions.intents["CreateCalendarIntent"]
let result = try await createCalendar.makeIntent(
name: "Occupy Saturn",
color: "red"
).run()
XCTAssertEqual(try result.value.title, "Occupy Saturn")
} Test an entity string query
// Testing Entity string queries
func testEventStringQuery() async throws {
let results = try await eventEntityDefinition
.entities(matching: "Cosmic Ray")
XCTAssertEqual(results.count, 1)
XCTAssertEqual(try results[0].title, "Cosmic Ray Calibration")
} Implement the EntityStringQuery under test
// Updated query implementation
struct EventEntityQuery: EntityStringQuery {
func entities(for identifiers: [EventEntity.ID]) async throws -> [EventEntity] {
}
func suggestedEntities() async throws -> [EventEntity] {
}
func entities(matching string: String) async throws -> [EventEntity] {
try calendarManager.fetchEvents()
.filter { $0.title.localizedCaseInsensitiveContains(string) }
.map(\.entity)
}
} Chain multiple intents in one test
// Test event creation followed by update
func testCreateAndUpdateEvent() async throws {
let createResult = try await createEventDefinition.makeIntent(
title: "Asteroid Dodgeball Practice",
startDate: Date(),
isAllDay: false,
calendar: "Deep Space"
).run()
XCTAssertEqual(try createResult.value.title, "Asteroid Dodgeball Practice")
let updateResult = try await updateEventDefinition.makeIntent(
title: "Asteroid Dodgeball Rules Overview",
event: createResult.value
).run()
XCTAssertEqual(try updateResult.value.title, "Asteroid Dodgeball Rules Overview")
} Make an intent test-only
// Test-only intent: SeedSampleEventsIntent
#if DEBUG
struct SeedSampleEventsIntent: AppIntent {
static let isDiscoverable = false
func perform() async throws -> some IntentResult {
// Create known list of events
return .result()
}
}
#endif Test Spotlight indexing
// Testing Spotlight indexing
func testNewEventIndexedInSpotlight() async throws {
let before = try await eventEntityDefinition.spotlightQuery("Supernova Viewing Party")
XCTAssertTrue(before.isEmpty, "Event should not exist in Spotlight yet")
// ... Create "Supernova Viewing Party" Event
let after = try await eventEntityDefinition.spotlightQuery("Supernova Viewing Party")
XCTAssertEqual(after.count, 1)
XCTAssertEqual(try after[0].title, "Supernova Viewing Party")
} Test view annotations
/ Testing view annotations
func testEventViewAnnotation() async throws {
try await openEventDefinition.makeIntent(target: "Morning Launch Briefing").run()
// Confirm correct event page
let app = XCUIApplication()
let title = app.staticTexts["Morning Launch Briefing"]
XCTAssertTrue(title.waitForExistence(timeout: 5))
let annotations = try await eventEntityDefinition.viewAnnotations()
XCTAssertEqual(annotations.count, 1, "Expected exactly one view annotation")
XCTAssertEqual(try annotations[0].entity.title, "Morning Launch Briefing")
}