ReviewOS

also looking at this

craft-native/craft

fix(ios): schedule a notification with the data the page gave it

#262
Merged glennmichael123 wants to merge fix/ios-notification-data into main
8 files +242 -22
scripts/mobile-e2e/protocol.tsmodified+39-6
Changes to scripts/mobile-e2e/protocol.ts
@@ -453,8 +453,11 @@ export const NOTIFICATION_ROUTE = '/e2e/notification-tap'
453453 */
454454export type PushStage = 'cold' | 'foreground'
455455
456/** The banner text of a stage's push, which the UI test finds the banner by. */
457export function notificationBody(run: string, stage: PushStage): string {
456/**
457 * The banner text of a stage's notification, which the UI test finds the
458 * banner by: a pushed stage, or `local`, the one the page schedules (#258).
459 */
460export function notificationBody(run: string, stage: PushStage | 'local'): string {
458461 return `${run} ${stage}`
459462}
460463
@@ -485,12 +488,15 @@ export interface NotificationTapReport {
485488 * The page's report the UI test printed, read out of xcodebuild's output.
486489 *
487490 * `ios-uitests/NotificationTapColdStartTests.swift` writes one
488 * `CRAFT-E2E-NOTIFICATION-RESULT CRAFT-E2E-NOTIFICATION {json}` line. None,
489 * or one whose JSON does not parse, is null: the test never got that far.
491 * `<label> CRAFT-E2E-NOTIFICATION {json}` line per tap: labelled
492 * `CRAFT-E2E-NOTIFICATION-RESULT` for the push, `CRAFT-E2E-LOCAL-RESULT` for
493 * the scheduled notification. None, or one whose JSON does not parse, is
494 * null: the test never got that far.
490495 */
491export function notificationTapReport(output: string): NotificationTapReport | null {
496export function notificationTapReport(output: string, label = 'CRAFT-E2E-NOTIFICATION-RESULT'): NotificationTapReport | null {
492497 for (const line of output.split('\n')) {
493 const match = line.match(/CRAFT-E2E-NOTIFICATION-RESULT CRAFT-E2E-NOTIFICATION (\{.*\})\s*$/)
498 const at = line.indexOf(`${label} CRAFT-E2E-NOTIFICATION `)
499 const match = at === -1 ? null : line.slice(at + label.length + 1).match(/^CRAFT-E2E-NOTIFICATION (\{.*\})\s*$/)
494500 if (!match) continue
495501 try {
496502 const report = JSON.parse(match[1]!) as NotificationTapReport
@@ -534,6 +540,33 @@ export function notificationTapProblems(
534540 return problems
535541}
536542
543/**
544 * Why the tap on the notification the page scheduled is not a pass (#258).
545 *
546 * The page scheduled it with `data`, and the tap must hand that back once,
547 * nested values included. The bug handed the page `{}`: neither scheduler put
548 * `data` into userInfo, so there was nothing for the tap to carry.
549 */
550export function localNotificationProblems(
551 report: NotificationTapReport | null,
552 run: string,
553 evidence = 'xcodebuild-notification.log',
554): string[] {
555 if (!report)
556 return [`the tap on the scheduled notification never reported; see ${evidence}`]
557 if (report.dispatched === 0)
558 return ['the app never dispatched the tap on the scheduled notification']
559 if (report.taps.length === 1 && Object.keys(report.taps[0]!).length === 0)
560 return ['a tap on a scheduled notification handed the page {}: the data it was scheduled with never reached userInfo']
561
562 const ours = report.taps.filter(tap => tap.craftE2E === run && tap.stage === 'local')
563 if (ours.length !== 1 || report.taps.length !== 1)
564 return [`a tap on the scheduled notification handed the page ${JSON.stringify(report.taps)}, expected the data it was scheduled with once`]
565 if ((ours[0]!.nested as { kept?: unknown } | undefined)?.kept !== true)
566 return [`the scheduled notification's nested data did not survive: it carried ${JSON.stringify(ours[0])}`]
567 return []
568}
569
537570/** What a page that was open when a push arrived was handed by onReceive. */
538571export interface NotificationReceiptReport {
539572 received: Record<string, unknown>[]