Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Testing macOS Focus Mode Notification Blocking

Start here: build a tiny two-shortcut toggle for Do Not Disturb, ship a minimal UNUserNotificationCenter call inside your real app (not a UI-test runner), fire one notification per interruption level, and record what the host actually does — a banner, a silent entry in Notification Center, or nothing. Run it on a Figment M-series Mac from $95/month for Apple silicon toolchains, or on the $29/month virtual Intel macOS instance (2 vCPU, 8 GiB RAM, 80 GiB disk; browser console access) when your project builds with Xcode 26 or earlier. Chip, RAM, disk and macOS version are confirmed in the quote at request a configuration.

What macOS Focus actually exposes to your app

Focus is a user-controlled system state. Your app cannot activate it from code and cannot inspect its full configuration. INFocusStatusCenter in the Intents framework is available on iOS 15+, iPadOS 15+, Mac Catalyst 15+, macOS 12.0+, visionOS 1.0+ and watchOS 8+ — so it is a native macOS API, not a Catalyst-only shim. Call requestAuthorization once; after the user approves Focus Status access for your bundle, focusStatus.isFocused returns a Bool?.

Read Apple's own definition of that property carefully: isFocused reports the user's preference for receiving communication notifications. It is the shared "do you want to be reachable" bit the system exposes to other people and to communication-style apps. Treat it as a hint about notifications-silenced state, not as an authoritative "any Focus is on" flag, and not as a lookup for which Focus (Work, Personal, Sleep, Driving, custom) is active. For per-Focus detail the user must configure a Focus filter and your app must opt into that filter.

Focus filters and notification-suppression rules are not the same thing. A Focus filter can change in-app content, hide accounts or alter UI; notification-delivery rules decide whether banners, sounds and list entries make it through. Test each separately so a green result on one does not mask a regression in the other.

Toggle Do Not Disturb with the shortcuts CLI

The shortcuts command-line tool runs saved shortcuts from the current user session. Apple documents the syntax in Run shortcuts from the command line: shortcuts run "Name" to execute, shortcuts list to enumerate, and shortcuts view "Name" to open in the editor.

Build two one-action Shortcuts on the test host using the Shortcuts app:

  1. Focus DND On — Set Focus → Do Not Disturb → Turn On.
  2. Focus DND Off — Set Focus → Do Not Disturb → Turn Off.

From Terminal:

shortcuts run "Focus DND On"
sleep 2
shortcuts run "Focus DND Off"

Watch for the Control Center moon indicator to appear and clear. Record the exact Shortcut names in your test README so anyone rebuilding the host reproduces the same two toggles. Reserve a dedicated test-only macOS login — one that owns these Shortcuts, has notification permissions pre-granted for your test build, and is not anyone's daily account — so a stuck DND state cannot bleed into personal work.

Minimal app-side notification scheduling

The notification code belongs in your app target, not the UI-test runner. An XCUITest process is a separate bundle identifier with its own notification authorization; whatever you grant it is not what ships to users. Add a debug-only menu command or #if DEBUG AppKit button that calls:

import UserNotifications

enum FocusProbe {
    static func request(level: UNNotificationInterruptionLevel, id: String) {
        let center = UNUserNotificationCenter.current()
        var opts: UNAuthorizationOptions = [.alert, .sound, .badge]
        if level == .critical { opts.insert(.criticalAlert) }

        center.requestAuthorization(options: opts) { granted, error in
            guard granted, error == nil else { return }
            let content = UNMutableNotificationContent()
            content.title = "Focus probe \(id)"
            content.body  = "level=\(level.rawValue)"
            content.interruptionLevel = level
            if level == .critical { content.sound = .defaultCritical }

            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: false)
            center.add(UNNotificationRequest(identifier: id, content: content, trigger: trigger))
        }
    }
}

.criticalAlert in the authorization request is the piece most first drafts omit: without it the system drops .critical content even when the entitlement is present. .critical itself requires the Apple-approved com.apple.developer.usernotifications.critical-alerts entitlement, which is a separate application you make to Apple — the entitlement is not tier-bound, and no hosting choice unlocks it.

Target requirements: macOS 12+ for interruptionLevel, a code-signed app bundle so the authorization prompt appears, and a login session with Notification Center running. Figment's VM browser console is a login session; a headless terminal-only connection is not.

QA evidence matrix

Run the probe once per interruption level inside a single DND window, log the outcome, and attach a Notification Center screenshot. Apple documents .critical behavior as "The system always presents this notification, even when Do Not Disturb is active" (see UNNotificationInterruptionLevel.critical); the other levels depend on the user's per-app Focus choices, so record what you see rather than what you expected.

LevelDND on, banner?DND on, in Notification Center list?EntitlementAuthorization option
.passiveNo (silent by design)YesNone.alert
.activeUsually suppressedOften yesNone.alert
.timeSensitiveUser-controllable per app per FocusYescom.apple.developer.usernotifications.time-sensitive.alert
.criticalYes, per Apple docsYescom.apple.developer.usernotifications.critical-alerts.criticalAlert

The useful distinction is banner observation versus delivered state: getDeliveredNotifications can return a notification whose banner was suppressed, and a visible banner is not proof the entry persisted in the list. Log both in the same row. Repeat the matrix on each macOS point release you support — behavior drifts between Ventura, Sonoma, Sequoia and Tahoe, and the whole point of this test is to catch that drift early.

Which Figment Mac fits this workflow

  • M-series Mac from $95/month — the straightforward choice when you need current Xcode on Apple silicon. Exact chip, RAM, disk and macOS version are quoted per request.
  • Virtual Intel macOS $29/month — real macOS on Linux/KVM reached through a browser console: 2 vCPU, 8 GiB RAM, 80 GiB disk, no GPU acceleration, no audio. Fine for Focus and UNUserNotificationCenter testing when your targets build with Xcode 26 or earlier.
  • i3 Mac $49/month and physical M-series — request-based while supply is confirmed.

Nothing about critical-alerts, time-sensitive entitlements or Focus authorization is tier-bound; the only questions are whether your toolchain, chip and macOS version match what the test needs, and whether the account is a dedicated test login. Start a configuration request with the Xcode and macOS version your Focus test target depends on, or browse the plan grid at /mac-hosting.

Related testing guides:


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms