Files
orca/mobile/src/notifications/push-preference-update.test.ts
T
Jinwoo Hong 341b13cf67 Restore mobile push and fix cold-start dismissals (#20068)
* Restore mobile push for delivery validation

* fix(mobile): register push task before headless startup

* Add authenticated mobile push test and fix iOS release entitlements

* Mock push-test transport in notification consent tests

* Fix slept workspace test for structured remount result

* Fix mobile notification review findings

* Pad Android notification icon to prevent square cropping

* fix(mobile): present visible Android data pushes in foreground

* test: use deterministic clock for teardown deadline

* fix(mobile): present foreground pushes through Expo public APIs

* fix(mobile): check push eligibility before foreground scheduling

* fix(mobile): register push from shared host connection lifecycle
2026-09-12 01:03:57 -04:00

87 lines
2.8 KiB
TypeScript

vi.mock('./desktop-notification-channel', () => ({
ensureDesktopNotificationChannel: vi.fn(async () => {})
}))
import { AppState } from 'react-native'
import { beforeEach, expect, it, vi } from 'vitest'
import {
attachPushRegistration,
resetPushRegistrationForTests,
setNotificationDeliveryPreferences,
NOTIFICATIONS_REMOTE_PUSH_CAPABILITY
} from './push-registration'
import { DEFAULT_NOTIFICATION_DELIVERY } from './notification-delivery-preferences'
const storage = new Map<string, string>()
vi.mock('@react-native-async-storage/async-storage', () => ({
default: {
getItem: vi.fn(async (key: string) => storage.get(key) ?? null),
setItem: vi.fn(async (key: string, value: string) => {
storage.set(key, value)
})
}
}))
vi.mock('react-native', () => ({
AppState: { currentState: 'active', addEventListener: vi.fn(() => ({ remove: vi.fn() })) }
}))
vi.mock('./push-token', () => ({
getDevicePushToken: vi.fn(async () => ({
platform: 'ios',
token: 'a'.repeat(64),
apnsEnvironment: 'sandbox'
})),
addPushTokenListener: vi.fn()
}))
beforeEach(() => {
AppState.currentState = 'active'
resetPushRegistrationForTests()
storage.clear()
storage.set('orca:pushServiceNotificationsEnabled', 'true')
})
it('replaces an in-flight registration with the latest away and sound preferences', async () => {
const calls: { method: string; params: unknown }[] = []
let finishFirst: ((value: unknown) => void) | undefined
const client = {
sendRequest: vi.fn(async (method: string, params?: unknown) => {
calls.push({ method, params })
if (method === 'status.get') {
return { ok: true, result: { capabilities: [NOTIFICATIONS_REMOTE_PUSH_CAPABILITY] } }
}
if (method === 'notifications.registerPush') {
if (!finishFirst) {
return new Promise((resolve) => {
finishFirst = resolve
})
}
return { ok: true, result: { registered: true, registrationId: 'new' } }
}
return { ok: true, result: { unregistered: true } }
})
}
const detach = attachPushRegistration('host', client as never)
await vi.waitFor(() => expect(finishFirst).toBeDefined())
const update = setNotificationDeliveryPreferences({
...DEFAULT_NOTIFICATION_DELIVERY,
onlyWhenDesktopAway: false,
sound: false
})
finishFirst!({ ok: true, result: { registered: true, registrationId: 'old' } })
await update
await vi.waitFor(() =>
expect(
calls.filter((call) => call.method === 'notifications.registerPush').length
).toBeGreaterThan(1)
)
const latest = calls.findLast((call) => call.method === 'notifications.registerPush')
expect(latest?.params).toMatchObject({
filter: {
onlyWhenDesktopAway: false,
sound: false
}
})
expect(calls.some((call) => call.method === 'notifications.unregisterPush')).toBe(true)
detach()
})