What's New / App Intents & System Integration

What's new in AppIntentsTesting

+33 NewiOS · macOS · tvOS · watchOS

AppIntentsTesting provides test-side support for App Intents, the framework that exposes app actions, entities, and enums to Siri, Shortcuts, and Spotlight. It gives tests typed handles to intent definitions and queries.

33 new APIs, no deprecations or removals. New type-erased wrappers cover the core App Intents concepts: AnyAppEntity, AnyAppEnum, AnyAppIntent, AnyEntityQuery, and AnyTransientAppEntity. Definition types for inspecting an intent's shape arrive as well: AppEntityDefinition, AppEnumDefinition, AppIntentDefinition, IntentDefinitions, and the AppIntentTypeDefinition protocol. The dynamic property path types DynamicPropertyPath and DynamicPropertyPathCollection are also added.

New

33
struct

AnyAppEntity

NewiOSmacOStvOSwatchOS
public struct AnyAppEntity : Sendable, Equatable

A type-erased, intermediate representation of your app entity for testing purposes.

The AnyAppEntity structure resolves to your actual entity type and gives you access to its properties, enabling you to test your app entity code:

// Define your app entity type from your app bundle:
let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let exampleEntity = definitions.entities[
    "ExampleEntity"
]

// Create an entity from an identifier.
let entity = exampleEntity.makeReference(
    identifier: "my-example"
)

// Type-safe access to the entity's properties.
let name: String? = entity.name
let itemCount: Int? = entity.itemCount

// Accessing nested properties (requires try).
if try entity.profile.name == "John Doe" {
    print("User found")
}
Declaration
@dynamicMemberLookup public struct AnyAppEntity : Sendable, Equatable {

    /// The value that uniquely identifies the app entity.
    public var identifier: AttributedEntityIdentifier

    /// Accesses an entity property by name, for comparison with a known value.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// try entity.someName == "My Name"
    /// try entity[dynamicMember: "someName"] == "My Name"
    /// ```
    ///
    /// If the property's value isn't an instance of the type `T`,
    /// this subscript throws an error.
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript<T>(dynamicMember identifier: String) -> T where T : IntentValueConvertible { get throws }

    /// Accesses an entity property by name, without casting.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// entity.someName == nil
    /// entity[dynamicMember: "someName"] == nil
    ///
    /// CreateCoffeeIntent.makeIntent(customerName: entity.someName)
    /// CreateCoffeeIntent.makeIntent(customerName: entity[dynamicMember: "someName"])
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember identifier: String) -> (any IntentValueExpressing)? { get }

    /// Accesses a nested entity property by name.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// try entity.customer.name == "My Name"
    /// try entity[dynamicMember: "customer"][dynamicMember: "name"] == "My Name"
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember identifier: String) -> DynamicPropertyPath { get }

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: AnyAppEntity, b: AnyAppEntity) -> Bool
}
extension

AnyAppEntity

NewiOSmacOStvOSwatchOS
extension AnyAppEntity : IntentValueConvertible
Declaration
extension AnyAppEntity : IntentValueConvertible {
}
extension

AnyAppEntity

NewiOSmacOStvOSwatchOS
extension AnyAppEntity
Declaration
extension AnyAppEntity {

    /// Exports this entity's content as an ``IntentFile``.
    ///
    /// When no content type is specified, the entity's first registered `TransferRepresentation`
    /// is used.
    ///
    /// The returned file contains the exported data and, when available, a sandbox-extended
    /// file URL that can be passed directly as a parameter to another intent.
    ///
    /// - Parameter contentType: The desired export format (e.g., `.json`, `.png`).
    ///   Pass `nil` to use the entity's default representation.
    /// - Returns: The exported content as an ``IntentFile``.
    /// - Throws: If the entity does not conform to `Transferable` or does not support
    ///   the requested format.
    public func exported(as contentType: UTType? = nil) async throws -> IntentFile

    /// Exports this entity as a transferable intent value type.
    ///
    /// Use this for types that conform to both `Transferable` and `IntentValueConvertible`, such as
    /// `IntentPerson`. The entity must declare a `ValueRepresentation` for the requested type.
    ///
    /// - Parameter type: The target value type (e.g., `IntentPerson.self`).
    /// - Returns: An instance of the requested type.
    /// - Throws: If the entity does not support the requested value conversion.
    public func exported<T>(as type: T.Type) async throws -> T where T : IntentValueConvertible, T : Transferable

    /// Exports this entity as a system intent value type.
    ///
    /// Use this for system-provided currency types that conform to `_SystemIntentValue`, such as
    /// `PlaceDescriptor`. The entity must declare a `ValueRepresentation` for the requested type.
    ///
    /// - Parameter type: The target system intent value type.
    /// - Returns: An instance of the requested type.
    /// - Throws: If the entity does not support the requested value conversion.
    public func exported<T>(as type: T.Type) async throws -> T where T : _SystemIntentValue, T : IntentValueConvertible
}
struct

AnyAppEnum

NewiOSmacOStvOSwatchOS
public struct AnyAppEnum : Sendable, Equatable

A type-erased representation of an app enumeration that provides dynamic enumeration value access.

Use AnyAppEnum to work with enumerations when you don't know the specific enumeration type at compile time. At compile, the AnyAppEnum structure resolves to your app enum type and gives you access to its value as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let colorEnum = definitions.enums["Color"]
let priorityEnum = definitions.enums["Priority"]

// Creating enumeration cases.
let redCase = colorEnum.makeCase("red")
let highPriority = priorityEnum.makeCase("high")

// Accessing enumeration properties.
let rawValue = redCase.rawValue  // "red"

// Converting raw values in a type-safe way.
let colorName = try redCase.as(String.self)
let priorityLevel = try highPriority.as(String.self)
Declaration
public struct AnyAppEnum : Sendable, Equatable {

    /// The enumeration's type identifier.
    public var typeIdentifier: String

    /// The raw value of the selected enumeration option.
    public var rawValue: String

    /// Creates a new instance with the specified enumeration identifier and raw value.
    public init(typeIdentifier: String, rawValue: String)

    /// Casts the raw value to the specified type.
    ///
    /// If the raw value isn't an instance of that type, this method throws an error.
    /// ```swift
    /// let enumCase = MyEnumDefinition.makeCase("caseName")
    ///
    /// try enumCase.as(String.self) == "caseName"
    /// ```
    /// - Throws: If the raw value cannot be represented as the target type.
    public func `as`<T>(_ type: T.Type) throws -> T where T : LosslessStringConvertible

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: AnyAppEnum, b: AnyAppEnum) -> Bool
}
extension

AnyAppEnum

NewiOSmacOStvOSwatchOS
extension AnyAppEnum
Declaration
extension AnyAppEnum {

    /// Creates an enumeration with a typed raw value.
    ///
    /// - Parameters:
    ///   - typeIdentifier: The enumeration type identifier.
    ///   - value: The raw, typed value that gets converted to a string representation.
    public init(typeIdentifier: String, value: any LosslessStringConvertible)
}
extension

AnyAppEnum

NewiOSmacOStvOSwatchOS
extension AnyAppEnum : CustomStringConvertible
Declaration
extension AnyAppEnum : CustomStringConvertible {

    /// A textual representation of this app enumeration value.
    public var description: String { get }
}
extension

AnyAppEnum

NewiOSmacOStvOSwatchOS
extension AnyAppEnum : IntentValueConvertible
Declaration
extension AnyAppEnum : IntentValueConvertible {
}
struct

AnyAppIntent

NewiOSmacOStvOSwatchOS
public struct AnyAppIntent : Sendable, Equatable

A type-erased, intermediate representation of an app intent for testing purposes.

The AnyAppIntent structure resolves to your actual app intent type and gives you access to its parameters and results at runtime, enabling you to test your app intent code as shown in the following example:

// Getting an intent definition and creating an instance.
let definitions = IntentDefinitions(
    bundleIdentifier: "com.example.app"
)
var intent = definitions.intents["CreateNote"]
    .makeIntent()

// Setting any intent parameters.
intent.title = "Meeting Notes"
intent.priority = 5
intent.isUrgent = true

// Reading parameters, when needed.
let title: String? = try intent.title

// Performing the intent.
let result = try await intent.run()

// Adding your verification code.
// ...
Declaration
@dynamicMemberLookup public struct AnyAppIntent : Sendable, Equatable {

    /// The bundle identifier of the app that contains this intent.
    public let bundleIdentifier: String

    /// The unique identifier for the intent type.
    public let identifier: String

    /// Accesses an intent parameter by name, for comparison with a known value.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    ///
    /// ```swift
    /// try intent.someName == "My Name"
    /// try intent[dynamicMember: "someName"] == "My Name"
    /// ```
    ///
    /// If the property's value isn't an instance of the type `T`,
    /// this subscript throws an error.
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript<T>(dynamicMember identifier: String) -> T where T : IntentValueConvertible { get throws }

    /// Accesses an intent parameter by name, without casting.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    ///
    /// ```swift
    /// // Accessing parameters
    /// intent.someName == nil
    /// intent[dynamicMember: "someName"] == nil
    ///
    /// CreateCoffeeIntent.makeIntent(customerName: intent.someName)
    /// CreateCoffeeIntent.makeIntent(customerName: intent[dynamicMember: "someName"])
    ///
    /// // Modifying parameter values
    /// intent.someName = "My Name 2"
    /// intent[dynamicMember: "someName"] = "My Name 2"
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember identifier: String) -> (any IntentValueExpressing)?

    /// Accesses a nested entity property by name.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    ///
    /// ```swift
    /// try intent.customer.name == "My Name"
    /// try intent[dynamicMember: "customer"][dynamicMember: "name"] == "My Name"
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember identifier: String) -> DynamicPropertyPath { get }

    /// Performs the intent in the current test session.
    ///
    /// - Returns: The resolved result that contains the intent's return value.
    @discardableResult
    public func run() async throws -> ResolvedIntentResult

    /// Returns a Boolean value indicating whether two values are equal.

Truncated.

extension

AnyAppIntent

NewiOSmacOStvOSwatchOS
extension AnyAppIntent : CustomStringConvertible
Declaration
extension AnyAppIntent : CustomStringConvertible {

    /// A string representation of this app intent.
    public var description: String { get }
}
struct

AnyEntityQuery

NewiOSmacOStvOSwatchOS
public struct AnyEntityQuery : Sendable, Equatable

A type-erased, intermediate representation of your entity query for testing purposes.

The AnyEntityQuery structure resolves to your concrete query type, and allows you to test your entity queries and verify their results as shown in the following example:

let landmarkDef = definitions.entities["LandmarkEntity"]

// Query by string.
let stringQueryResults = try await landmarkDef.entities(matching: "Yosemite")

// Query by identifiers.
let specific = try await landmarkDef.entities(identifiers: ["yosemite-falls"])

// Get all entities.
let all = try await landmarkDef.allEntities()
Declaration
public struct AnyEntityQuery : Sendable, Equatable {

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: AnyEntityQuery, b: AnyEntityQuery) -> Bool
}
struct

AnyTransientAppEntity

NewiOSmacOStvOSwatchOS
public struct AnyTransientAppEntity : Sendable, Equatable

A type-erased representation of a transient app entity that provides dynamic property access.

Use AnyTransientAppEntity to work with transient entities when you don't know the specific entity type at compile time.

// Getting transient entity definitions.
let definitions = IntentDefinitions(bundleIdentifier: "com.apple.example")
let sessionEntity = definitions.transientEntities["UserSessionEntity"]

// Creating a transient entity with properties.
var entity = sessionEntity.withProperties(
    name: "John Doe",
    age: 30
)

// Accessing properties with type safety.
let userName: String? = try entity.name
let userAge: Int? = try entity.age

// Accessing nested properties (requires try).
if try entity.profile.name == "John Doe" {
    print("User found")
}
Declaration
@dynamicMemberLookup public struct AnyTransientAppEntity : Sendable, Equatable {

    /// The type of transient app entity represented by this identifier.
    public var entityType: AttributedTypeIdentifier

    /// Accesses an entity property by name, for comparison with a known value.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// try entity.someName == "My Name"
    /// try entity[dynamicMember: "someName"] == "My Name"
    /// ```
    ///
    /// If the property's value isn't an instance of the type `T`,
    /// this subscript throws an error.
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript<T>(dynamicMember identifier: String) -> T where T : IntentValueConvertible { get throws }

    /// Accesses an entity property by name, without casting.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// entity.someName == nil
    /// entity[dynamicMember: "someName"] == nil
    ///
    /// CreateCoffeeIntent.makeIntent(customerName: entity.someName)
    /// CreateCoffeeIntent.makeIntent(customerName: entity[dynamicMember: "someName"])
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember identifier: String) -> (any IntentValueExpressing)?

    /// Accesses a nested entity property by name.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// try entity.customer.name == "My Name"
    /// try entity[dynamicMember: "customer"][dynamicMember: "name"] == "My Name"
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember identifier: String) -> DynamicPropertyPath { get }

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: AnyTransientAppEntity, b: AnyTransientAppEntity) -> Bool
}
extension

AnyTransientAppEntity

NewiOSmacOStvOSwatchOS
extension AnyTransientAppEntity
Declaration
extension AnyTransientAppEntity {

    /// Exports this transient entity's content as an ``IntentFile``.
    ///
    /// When no content type is specified, the entity's first registered `TransferRepresentation`
    /// is used.
    ///
    /// The exported file can be passed as a parameter to another intent or used to verify the
    /// entity's export format. To resolve exported content back into an entity, use
    /// ``AppEntityDefinition/resolved(from:)-8f2x`` on a non-transient entity definition —
    /// transient entities are not resolvable by design since they have no stable identifier.
    ///
    /// - Parameter contentType: The desired export format (e.g., `.json`, `.png`).
    ///   Pass `nil` to use the entity's default representation.
    /// - Returns: The exported content as an ``IntentFile``.
    /// - Throws: If the entity does not conform to `Transferable` or does not support
    ///   the requested format.
    public func exported(as contentType: UTType? = nil) async throws -> IntentFile

    /// Exports this transient entity as a transferable intent value type.
    ///
    /// - Parameter type: The target value type (e.g., `IntentPerson.self`).
    /// - Returns: An instance of the requested type.
    /// - Throws: If the entity does not support the requested value conversion.
    public func exported<T>(as type: T.Type) async throws -> T where T : IntentValueConvertible, T : Transferable

    /// Exports this transient entity as a system intent value type.
    ///
    /// - Parameter type: The target system intent value type.
    /// - Returns: An instance of the requested type.
    /// - Throws: If the entity does not support the requested value conversion.
    public func exported<T>(as type: T.Type) async throws -> T where T : _SystemIntentValue, T : IntentValueConvertible
}
extension

AnyTransientAppEntity

NewiOSmacOStvOSwatchOS
extension AnyTransientAppEntity : IntentValueConvertible
Declaration
extension AnyTransientAppEntity : IntentValueConvertible {
}
struct

AppEntityDefinition

NewiOSmacOStvOSwatchOS
public struct AppEntityDefinition : Sendable, Equatable

A definition you use to dynamically create entity instances for testing.

To create an app entity instance for testing, load the definition for your app entity, using IntentDefinitions and its entities property, then create an entity instance as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let landmarkEntity = definitions.entities[
    "LandmarkEntity"
]
let entity = landmarkEntity.makeReference(
    identifier: "yosemite-falls"
)
Declaration
public struct AppEntityDefinition : Sendable, Equatable {

    /// The bundle identifier of the app that includes the app entity.
    public let bundleIdentifier: String

    /// The entity type's unique identifier.
    public let typeIdentifier: String

    /// Creates an app entity instance of the given entity type.
    ///
    /// ```swift
    /// let entityDefinition: AppEntityDefinition!
    ///
    /// let entityRef = entityDefinition.reference(identifier: "unique-id-123")
    /// ``
    ///
    /// - Parameter identifier: The entity instance's unique identifier.
    public func makeReference(identifier: String) -> AnyAppEntity

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: AppEntityDefinition, b: AppEntityDefinition) -> Bool
}
extension

AppEntityDefinition

NewiOSmacOStvOSwatchOS
extension AppEntityDefinition : AppIntentTypeDefinition
Declaration
extension AppEntityDefinition : AppIntentTypeDefinition {

    /// The instance type that corresponds to this definition type.
    public typealias Instance = AnyAppEntity

    /// Validates that the provided entity instance matches this entity definition's type.
    ///
    /// - Parameter value: The enum instance to validate.
    public func isInstance(_ value: AnyAppEntity) throws
}
extension

AppEntityDefinition

NewiOSmacOStvOSwatchOS
extension AppEntityDefinition
Declaration
extension AppEntityDefinition {

    /// Provides the currently visible onscreen entities.
    ///
    /// - Returns: An array of view annotations, with selection state and entity data.
    /// - Throws: An error if the view annotations query fails.
    public func viewAnnotations() async throws -> [ViewAnnotation]
}
struct

AppEnumDefinition

NewiOSmacOStvOSwatchOS
public struct AppEnumDefinition

An app enumeration definition for testing and dynamic enumeration creation.

To create an app enum for testing, load the enum definition using IntentDefinitions and its enums property. Then, set its value as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let colorEnum = definitions.enums["Color"]
let redCase = colorEnum.makeCase("red") // Matches `Color.red`.
Declaration
public struct AppEnumDefinition {

    /// The enum type's unique identifier.
    public let typeIdentifier: String

    /// Creates an enumeration case with the specified raw value.
    ///
    /// The provided `rawValue` needs to match one of your enum's cases.
    ///
    /// - Parameter rawValue: The string representation of the enumeration case.
    /// - Returns: A type-erased enumeration instance with the specified value.
    public func makeCase(_ rawValue: String) -> AnyAppEnum
}
extension

AppEnumDefinition

NewiOSmacOStvOSwatchOS
extension AppEnumDefinition : AppIntentTypeDefinition
Declaration
extension AppEnumDefinition : AppIntentTypeDefinition {

    /// The instance type that corresponds to this definition type.
    public typealias Instance = AnyAppEnum

    /// Validates that the provided enumeration instance matches the definition's type.
    ///
    /// - Parameter value: The enum instance to validate.
    public func isInstance(_ value: AnyAppEnum) throws
}
struct

AppIntentDefinition

NewiOSmacOStvOSwatchOS
public struct AppIntentDefinition : Sendable, Equatable

A definition you use to dynamically create intent instances for testing.

To create an app intent instance for testing, instantiate its corresponding intent definition for your app intent using IntentDefinitions, then create an intent instance using makeIntent as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let orderIntent = definitions.intents[
    "OrderCoffeeIntent"
]
let intent = orderIntent.makeIntent(
    size: "large",
    type: "latte"
)
Declaration
public struct AppIntentDefinition : Sendable, Equatable {

    /// The bundle identifier of the app that includes this intent.
    public let bundleIdentifier: String

    /// The intent's identifier.
    public let identifier: String

    /// Creates a populated instance of this intent.
    ///
    /// The following example shows how you can create an intent instance:
    /// 
    /// ```swift
    /// let definitions = IntentDefinitions(bundleIdentifier: "com.example.exampleapp")
    /// let exampleIntentDefinition = definitions.intents["MyExampleIntent"]
    ///
    /// let intent = exampleIntentDefinition.makeIntent(
    ///     paramA: "Hello World",
    ///     paramB: 1234
    /// )
    /// ```
    public var makeIntent: IntentValuePropertiesCallable<AnyAppIntent> { get }

    @available(*, deprecated, renamed: "makeIntent")
    public var withParameters: IntentValuePropertiesCallable<AnyAppIntent> { get }

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: AppIntentDefinition, b: AppIntentDefinition) -> Bool
}
protocol

AppIntentTypeDefinition

NewiOSmacOStvOSwatchOS
public protocol AppIntentTypeDefinition

A protocol that associates a definition type with its corresponding instance type.

The AppIntentTypeDefinition bridges a definition type you use to retrieve your intent, entity, and enum type, and the type-erased instance of your concrete intent, entity, or enum. For example, AppIntentTypeDefinition bridges AppEntityDefinition to the AnyAppEntity. Validate that a given instance was produced from the correct definition using the isInstance(_:) function.

Declaration
public protocol AppIntentTypeDefinition {

    /// The instance type that corresponds to this definition type.
    associatedtype Instance : IntentValueConvertible

    /// Validates that the provided value matches this definition's type.
    ///
    /// If validation fails, this method throws an error.
    ///
    /// - Parameter value: The value to validate.
    func isInstance(_ value: Self.Instance) throws
}
struct

DynamicPropertyPath

NewiOSmacOStvOSwatchOS
public struct DynamicPropertyPath : Sendable

A type-safe, dynamic path to access nested intent values.

You typically don't create instances of DynamicPropertyPath directly. The system returns instances of the type to indicate that you can further traverse a nested property. Use DynamicPropertyPath for chained property access and array indexing on entities and intent results.

// Navigate nested properties.
let name: String = try entity.profile.name

// Index properties into an array.
let first: String = try entity.tags[0]

// Cast the entity to a known entity type definition.
let coffee: AnyAppEntity = try result.value.as(CoffeeEntity)
Declaration
@dynamicMemberLookup public struct DynamicPropertyPath : Sendable {

    /// Accesses a collection element by index, for comparison with a known value.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// let result = try await intent.run() // Expected an array as result value
    ///
    /// try result.value[0] == "My Name"
    /// ```
    ///
    /// If the property's value isn't an instance of the type `T`,
    /// this subscript throws an error.
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript<T>(index: Int) -> T where T : IntentValueConvertible { get throws }

    /// Accesses a collection element by index, without casting.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// let result = try await intent.run() // Expected an array as result value
    ///
    /// result.value[0] == nil
    /// CreateCoffeeIntent.makeIntent(customerName: result.value[0])
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(index: Int) -> (any IntentValueExpressing)? { get throws }

    /// Accesses a nested property on a collection element by index.
    ///
    /// The code below shows the syntactic sugar
    /// and the equivalent, desugared, subscript syntax.
    ///
    /// ```swift
    /// let result = try await intent.run() // Expected an array of customer entities
    ///
    /// result.value[0].name == nil
    /// CreateCoffeeIntent.makeIntent(customerName: result.value[0].name)
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(index: Int) -> DynamicPropertyPath { get }

    /// Casts a property to the provided type.
    ///
    /// If the value's type doesn't match,
    /// this method throws an error.
    ///
    /// ```swift
    /// let result = try await intent.run()
    /// try result.value.as(String.self) == "My Name"
    /// ```
    public func `as`<T>(_ type: T.Type) throws -> T where T : IntentValueConvertible

    /// Casts the value to the given type.
    ///
    /// If the value's type doesn't match,
    /// this method throws an error.
    ///
    /// ```swift
    /// let CoffeeEntity = definitions.entities["CoffeeEntity"]
    /// let coffee: AnyAppEntity = try result.value.as(CoffeeEntity)

Truncated.

extension

DynamicPropertyPath

NewiOSmacOStvOSwatchOS
extension DynamicPropertyPath
Declaration
extension DynamicPropertyPath {

    /// Accesses a typed property at the current path by name.
    public subscript<T>(dynamicMember identifier: String) -> T where T : IntentValueConvertible { get throws }

    /// Accesses a property by name without casting.
    ///
    /// Use this subscript to check for `nil` values and to assign values to intent parameters.
    public subscript(dynamicMember identifier: String) -> (any IntentValueExpressing)? { get throws }

    /// Creates a dynamic path for navigating deeper into a nested property hierarchy.
    public subscript(dynamicMember identifier: String) -> DynamicPropertyPath { get }
}
struct

DynamicPropertyPathCollection

NewiOSmacOStvOSwatchOS
public struct DynamicPropertyPathCollection : Sendable

Indexed result items from an intent value query.

Access query results by index and navigate their properties using dynamic member lookup:

let result = try await searchQuery.values(for: "Arizona")

XCTAssertEqual(result.items.count, 3)
XCTAssertEqual(try result.items[0].name, "Botanical Garden")
Declaration
public struct DynamicPropertyPathCollection : Sendable {

    /// The number of items in the collection.
    public var count: Int { get }

    /// A Boolean value that indicates whether the collection is empty.
    public var isEmpty: Bool { get }

    /// Accesses typed properties from the intent value at the given index.
    public subscript<T>(position: Int) -> T where T : IntentValueConvertible { get throws }

    /// Accesses an item for nil checking and assigning to intent parameters without casting.
    public subscript(position: Int) -> (any IntentValueExpressing)? { get throws }

    /// Creates a dynamic path for navigating into the item's properties.
    public subscript(position: Int) -> DynamicPropertyPath { get }
}
struct

IntentDefinitions

NewiOSmacOStvOSwatchOS
public struct IntentDefinitions : Sendable

A collection of definitions that catalog your app's intents, enums, entities, and queries.

Use the IntentDefinitions structure as the entry point for creating type-erased app intents for testing. Provide the bundle identifier of the app under test, then use subscript syntax to retrieve definitions for intents, entities, enums, or value queries as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)

let intent = definitions.intents["OrderCoffeeIntent"]
    .makeIntent(size: "large")
let entity = definitions.entities["CoffeeEntity"]
    .makeReference(identifier: "latte-123")
let enumCase = definitions.enums["CoffeeSizeEnum"]
    .makeCase("large")
Declaration
public struct IntentDefinitions : Sendable {

    /// The bundle identifier of the app target under test.
    public let bundleIdentifier: String

    /// Creates a new collection of definitions for intents that the specified app bundle contains.
    ///
    /// - Parameter bundleIdentifier: The bundle identifier of the app target under test.
    public init(bundleIdentifier: String)

    /// A collection of a specific type of definition.
    ///
    /// Retrieve individual definitions using their type identifier string as shown in the following example:
    ///
    /// ```swift
    /// let orderIntent = definitions.intents[
    ///     "OrderCoffeeIntent"
    /// ]
    /// ```
    public struct DefinitionCollection<Definition> : Sendable {

        /// Retrieves a type definition using its identifier.
        public subscript(typeIdentifier: String) -> Definition { get }
    }

    /// The definitions for the target app's app intents.
    ///
    /// Access individual intent definitions using subscript syntax
    /// with the intent's type name as shown in the following example:
    ///
    /// ```swift
    /// let definitions = IntentDefinitions(
    ///     bundleIdentifier: "com.apple.example"
    /// )
    /// let orderIntent = definitions.intents[
    ///     "OrderCoffeeIntent"
    /// ]
    /// ```
    public var intents: IntentDefinitions.DefinitionCollection<AppIntentDefinition> { get }

    /// The definitions for the target app's app enums.
    ///
    /// Access individual enum definitions using subscript syntax
    /// with the enum's type name as shown in the following example:
    ///
    /// ```swift
    /// let definitions = IntentDefinitions(
    ///     bundleIdentifier: "com.apple.example"
    /// )
    /// let coffeeSizeEnum = definitions.enums[
    ///     "CoffeeSizeEnum"
    /// ]
    /// ```
    public var enums: IntentDefinitions.DefinitionCollection<AppEnumDefinition> { get }
}
extension

IntentDefinitions

NewiOSmacOStvOSwatchOS
extension IntentDefinitions
Declaration
extension IntentDefinitions {

    /// The definitions for the target app's app entities.
    ///
    /// Access individual entity definitions using subscript syntax
    /// with the entity's type name as shown in the following example:
    ///
    /// ```swift
    /// let definitions = IntentDefinitions(
    ///     bundleIdentifier: "com.apple.example"
    /// )
    /// let coffeeEntity = definitions.entities[
    ///     "CoffeeEntity"
    /// ]
    /// ```
    public var entities: IntentDefinitions.DefinitionCollection<AppEntityDefinition> { get }

    /// Retrieve a transient app entity definition using subscript syntax.
    ///
    /// Access individual transient entity definitions using subscript
    /// syntax with the entity's type name as shown in the following example:
    ///
    /// ```swift
    /// let definitions = IntentDefinitions(
    ///     bundleIdentifier: "com.apple.example"
    /// )
    /// let tempOrder = definitions.transientEntities[
    ///     "TempOrderEntity"
    /// ]
    /// ```
    public var transientEntities: IntentDefinitions.DefinitionCollection<TransientAppEntityDefinition> { get }

    /// The definitions for the app's intent value queries.
    ///
    /// Access individual value query definitions using subscript syntax
    /// with the query's type name as shown in the following example:
    ///
    /// ```swift
    /// let definitions = IntentDefinitions(
    ///     bundleIdentifier: "com.apple.example"
    /// )
    /// let landmarkQuery = definitions.valueQueries[
    ///     "LandmarkIntentValueQuery"
    /// ]
    /// ```
    public var valueQueries: IntentDefinitions.DefinitionCollection<IntentValueQueryDefinition> { get }
}
struct

IntentValuePropertiesCallable

NewiOSmacOStvOSwatchOS
public struct IntentValuePropertiesCallable<T> : Sendable

A callable wrapper that creates app intent instances from keyword arguments.

The IntentValuePropertiesCallable wrapper uses the @dynamicCallable attribute to provide a natural function-call syntax for setting properties on type-erased app intents instances. Don't create instances of this type directly. Instead, use makeIntent or makeEntity.

Declaration
@dynamicCallable public struct IntentValuePropertiesCallable<T> : Sendable {

    /// Returns an instance of `T` by applying the provided argument values to the properties.
    ///
    /// Typically, you use this subscript implicitly via function-call syntax, for example:
    /// ```swift
    /// let intent = CreateCoffeeIntent.makeIntent(customerName: "MyName", size: 12.0)
    /// ```
    ///
    /// This is equivalent to the desugared syntax:
    /// ```swift
    /// let intent = CreateCoffeeIntent.makeIntent.dynamicallyCall([
    ///     "customerName": "MyName",
    ///     "size": 12.0
    /// ])
    /// ```
    public func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, (any IntentValueExpressing)?>) -> T
}
struct

IntentValueQueryDefinition

NewiOSmacOStvOSwatchOS
public struct IntentValueQueryDefinition : Sendable

A definition you use to create an intent value query for testing.

To create an intent value for testing and verify its results, first get its definition using IntentDefinitions and its valueQueries property. Then, perform the query and verify that it returns the expected results as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let searchQuery = definitions.valueQueries[
    "LandmarkIntentValueQuery"
]

let result = try await searchQuery.values(for: "Arizona")

// Code to verify the query's results.
// ...
Declaration
public struct IntentValueQueryDefinition : Sendable {

    /// The bundle identifier of the app that includes the query.
    public let bundleIdentifier: String

    /// The query's unique identifier.
    public let queryIdentifier: String

    /// Performs the value query with the given input and returns matching results.
    ///
    /// Use this function to verify that the system can query your app for app entities as shown in
    /// the following example:
    ///
    /// ```swift
    /// let searchQuery = definitions.valueQueries[
    ///     "LandmarkIntentValueQuery"
    /// ]
    /// let result = try await searchQuery.values(
    ///     for: "Arizona"
    /// )
    /// let name: String = try result.items[0].name
    /// ```
    ///
    /// - Parameter input: The value to use in this query.
    /// - Returns: Results matching the query.
    public func values(for input: some IntentValueConvertible) async throws -> ResolvedValueQueryResult
}
struct

ResolvedIntentResult

NewiOSmacOStvOSwatchOS
public struct ResolvedIntentResult : Sendable, Equatable

A type-safe result from performing an app intent.

After performing the app intent with run(), use the value property to inspect the output as shown in the following example:

let result = try await intent.run()

// Compare the result with an expected value.
XCTAssertEqual(try result.value, "Hello World")

// Access the return value's nested properties.
let name: String = try result.value.customerName

// Pass the return value to another intent for additional verification.
intent2.coffee = try result.value
Declaration
@dynamicMemberLookup public struct ResolvedIntentResult : Sendable, Equatable {

    /// A structure that enables key-path syntax for the intent result.
    ///
    /// You normally don't use this type directly, instead you use it indirectly when writing
    /// key paths like `\.value`.
    public struct ValueKeyPath {

        public let value: Never
    }

    /// Returns the intent's output, converted to the inferred type.
    ///
    /// Access the return value using the `value` key path, for example:
    ///
    /// ```swift
    /// let result = try await intent.run()
    ///
    /// // Compare the result with a concrete value.
    /// XCTAssertEqual(try result.value, "Hello World")
    /// ```
    ///
    /// If the property's value isn't an instance of the type `T`,
    /// this subscript throws an error.
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript<T>(dynamicMember keyPath: KeyPath<ResolvedIntentResult.ValueKeyPath, Never>) -> T where T : IntentValueConvertible { get throws }

    /// Accesses the return value of the result, without casting.
    ///
    /// For example:
    ///
    /// ```swift
    /// let result = try await intent.run()
    ///
    /// // Checking for nil.
    /// result.value == nil
    ///
    /// // Use it to populate other intents
    /// let intent = PayCoffeeIntent.makeIntent(coffee: result.value)
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember keyPath: KeyPath<ResolvedIntentResult.ValueKeyPath, Never>) -> (any IntentValueExpressing)? { get }

    /// Accesses nested properties of the result's return value.
    ///
    /// For example:
    ///
    ///
    /// ```swift
    /// let result = try await intent.run()
    ///
    /// // Accessing properties.
    /// try result.value.customerName == "My Name"
    /// ```
    ///
    /// For more information about dynamic-member syntax,
    /// see [dynamicMemberLookup][] in *[The Swift Programming Language][tspl]*.
    ///
    /// [dynamicMemberLookup]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes#dynamicMemberLookup
    /// [tspl]: https://docs.swift.org/swift-book/
    public subscript(dynamicMember keyPath: KeyPath<ResolvedIntentResult.ValueKeyPath, Never>) -> DynamicPropertyPath { get }

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.

Truncated.

struct

ResolvedValueQueryResult

NewiOSmacOStvOSwatchOS
public struct ResolvedValueQueryResult : Sendable

The result of an intent value query.

Use the resolved value query result to verify that your <doc://com.apple.documentation/documentation/appintents/intentvaluequery> returns the expected results as shown in the following example:

let result = try await searchQuery.values(for: "Arizona")

// Verify individual items.
XCTAssertEqual(try result.items[0].name, "Botanical Garden")

// Cast items to a concrete value for additional verifications.
let entity: AnyAppEntity =
    try result.items[0].as(AnyAppEntity.self)
Declaration
public struct ResolvedValueQueryResult : Sendable {

    /// The results that the query returns.
    public let items: DynamicPropertyPathCollection
}
struct

TransientAppEntityDefinition

NewiOSmacOStvOSwatchOS
public struct TransientAppEntityDefinition : Sendable, Equatable

A definition you use to dynamically create transient app entities for testing.

To create a transient app entity instance for testing, load the definition for your transient app entity using IntentDefinitions and its transientEntities property, then create an entity instance as shown in the following example:

let definitions = IntentDefinitions(
    bundleIdentifier: "com.apple.example"
)
let sessionEntity = definitions.transientEntities[
    "UserSessionEntity"
]
let entity = sessionEntity.makeEntity(
    sessionId: "temp-session-123",
    startTime: Date()
)
Declaration
public struct TransientAppEntityDefinition : Sendable, Equatable {

    /// The bundle identifier of the app that contains this entity.
    public let bundleIdentifier: String

    /// The entity type's identifier.
    public let typeIdentifier: String

    /// Creates a populated instance of this transient entity.
    ///
    /// ```swift
    /// let entityDefinition: TransientAppEntityDefinition = definitions.transientEntities["SomeEntityName"]
    ///
    /// let entity = entityDefinition.makeEntity(
    ///     sessionId: "temp-session-123",
    ///     startTime: Date()
    /// )
    /// ```
    public var makeEntity: IntentValuePropertiesCallable<AnyTransientAppEntity> { get }

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: TransientAppEntityDefinition, b: TransientAppEntityDefinition) -> Bool
}
extension

TransientAppEntityDefinition

NewiOSmacOStvOSwatchOS
extension TransientAppEntityDefinition : AppIntentTypeDefinition
Declaration
extension TransientAppEntityDefinition : AppIntentTypeDefinition {

    /// The instance type that corresponds to this definition type.
    public typealias Instance = AnyTransientAppEntity

    /// Validates that the provided transient entity instance matches this definition's type.
    ///
    /// - Parameter value: The transient entity instance to validate.
    public func isInstance(_ value: AnyTransientAppEntity) throws
}
extension

TransientAppEntityDefinition

NewiOSmacOStvOSwatchOS
extension TransientAppEntityDefinition
Declaration
extension TransientAppEntityDefinition {

    /// Resolves a transient entity from an exported ``IntentFile`` through the entity type's
    /// `Transferable` conformance.
    ///
    /// Use this to verify the import direction — that an ``IntentFile`` produced by
    /// ``AnyTransientAppEntity/exported(as:)-swift.method`` (or constructed from test data) can be resolved
    /// back into a transient entity through the same pipeline used at runtime.
    ///
    /// - Parameter file: The ``IntentFile`` containing the exported entity data.
    /// - Returns: The resolved transient entity.
    /// - Throws: If the entity type does not support the file's content type.
    ///
    /// ```swift
    /// let file = try await transientEntity.exported(as: .json)
    /// let resolved = try await sessionEntityDef.resolved(from: file)
    /// ```
    public func resolved(from file: IntentFile) async throws -> AnyTransientAppEntity

    /// Resolves a transient entity from a transferable intent value type through the entity type's
    /// `Transferable` conformance.
    ///
    /// The value is serialized through its `TransferRepresentation` and resolved into
    /// the transient entity type through the same pipeline used at runtime.
    ///
    /// - Parameter value: The transferable intent value (e.g., an `IntentPerson` instance).
    /// - Returns: The resolved transient entity.
    /// - Throws: If the entity type does not support the given value type.
    ///
    /// ```swift
    /// let person = try await transientEntity.exported(as: IntentPerson.self)
    /// let resolved = try await sessionEntityDef.resolved(from: person)
    /// ```
    public func resolved<T>(from value: T) async throws -> AnyTransientAppEntity where T : IntentValueConvertible, T : Transferable

    /// Resolves a transient entity from a system intent value type through the entity type's
    /// `Transferable` conformance.
    ///
    /// - Parameter value: The system intent value (e.g., a `PlaceDescriptor` instance).
    /// - Returns: The resolved transient entity.
    /// - Throws: If the entity type does not support the given value type.
    public func resolved<T>(from value: T) async throws -> AnyTransientAppEntity where T : _SystemIntentValue, T : IntentValueConvertible
}
struct

ViewAnnotation

NewiOSmacOStvOSwatchOS
public struct ViewAnnotation : Sendable, Equatable

The onscreen context you provide to the system by annotating a view with an app entity.

Use the ViewAnnotation structure to test whether the currently visible user interface and its views have the expected entity view annotations you created to provide onscreen context to the system. Retrieve visible view annotations using viewAnnotations(), then inspect their selection state and which entities are visible on-screen.

Declaration
public struct ViewAnnotation : Sendable, Equatable {

    /// A Boolean value that indicates whether the entity's associated view is selected.
    public let isSelected: Bool

    /// The underlying app entity data.
    public let entity: AnyAppEntity

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: ViewAnnotation, b: ViewAnnotation) -> Bool
}

No APIs match your filter.

← More in App Intents & System Integration