also looking at this
test(ios): tap a real pushed notification that launches the app, and judge what the page gets
#257
5 files
+308
-10
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import { describe, expect, it } from 'bun:test' |
| 2 | 2 | import { readFileSync } from 'node:fs' |
| 3 | 3 | import { join } from 'node:path' |
| 4 | import { ANDROID_DECLINE_PHRASES, androidDeclines, awaitedNeeds, deepLinkProblems, deepLinkReports, deepLinkResults, DISMISS_SHARE_MENU, elfSectionNames, evaluateRun, hasTerminated, parseDriverOutput, REQUIRED_CASES, requiredCaseProblems, runtimePermissionGranted, shareMenuInFront, strippedLibraryProblems, ZIG_REFUSED_ACTIONS, ZIG_SERVED_ACTIONS, ZIG_TESTED_ACTIONS, zigDispatchedActions, zigHandBacks, zigRefusals } from './protocol' | |
| 4 | import { ANDROID_DECLINE_PHRASES, androidDeclines, awaitedNeeds, deepLinkProblems, deepLinkReports, deepLinkResults, DISMISS_SHARE_MENU, elfSectionNames, evaluateRun, hasTerminated, NOTIFICATION_ROUTE, notificationPayload, notificationTapProblems, notificationTapReport, parseDriverOutput, REQUIRED_CASES, requiredCaseProblems, runtimePermissionGranted, shareMenuInFront, strippedLibraryProblems, ZIG_REFUSED_ACTIONS, ZIG_SERVED_ACTIONS, ZIG_TESTED_ACTIONS, zigDispatchedActions, zigHandBacks, zigRefusals } from './protocol' | |
| 5 | 5 | |
| 6 | 6 | const ESC = String.fromCharCode(27) |
| 7 | 7 | |
| @@ -382,6 +382,55 @@ describe('cold-start deep links', () => { | ||
| 382 | 382 | }) |
| 383 | 383 | }) |
| 384 | 384 | |
| 385 | describe('notification tap cold start', () => { | |
| 386 | const RUN = 'craft-e2e-ios-shim-1' | |
| 387 | const line = (report: object) => `CRAFT-E2E-NOTIFICATION-RESULT CRAFT-E2E-NOTIFICATION ${JSON.stringify(report)}` | |
| 388 | const tap = { aps: { alert: { title: 'Craft E2E', body: RUN } }, craftE2E: RUN, route: NOTIFICATION_ROUTE } | |
| 389 | const judge = (report: object) => notificationTapProblems(notificationTapReport(`Test Case started.\n${line(report)}\n** TEST SUCCEEDED **`), RUN) | |
| 390 | ||
| 391 | it('passes a late subscriber handed the tap that launched the app, once', () => { | |
| 392 | expect(judge({ dispatched: 1, taps: [tap], onTap: 'function', unsubscribe: 'function' })).toEqual([]) | |
| 393 | }) | |
| 394 | ||
| 395 | // The two halves of #255, told apart. | |
| 396 | it('blames native code when the app never dispatched the tap', () => { | |
| 397 | expect(judge({ dispatched: 0, taps: [], onTap: 'function', unsubscribe: 'function' })) | |
| 398 | .toEqual(['the app never dispatched the tap that launched it; native code dropped it before the page existed']) | |
| 399 | }) | |
| 400 | ||
| 401 | it('blames the page when the tap was dispatched before anyone subscribed', () => { | |
| 402 | const problems = judge({ dispatched: 1, taps: [], onTap: 'function', unsubscribe: 'function' }) | |
| 403 | expect(problems).toHaveLength(1) | |
| 404 | expect(problems[0]).toContain('subscribed to notifications.onTap after launch was handed []') | |
| 405 | }) | |
| 406 | ||
| 407 | it('fails a tap handed over twice, one from another run, or one that lost its route', () => { | |
| 408 | expect(judge({ dispatched: 1, taps: [tap, tap], onTap: 'function', unsubscribe: 'function' })[0]).toContain('expected the tap that launched the app once') | |
| 409 | expect(judge({ dispatched: 1, taps: [{ ...tap, craftE2E: 'an-earlier-run' }], onTap: 'function', unsubscribe: 'function' })[0]).toContain('expected the tap that launched the app once') | |
| 410 | expect(judge({ dispatched: 1, taps: [{ ...tap, route: undefined }], onTap: 'function', unsubscribe: 'function' })[0]).toContain('without the push\'s route') | |
| 411 | }) | |
| 412 | ||
| 413 | it('fails a bridge with no onTap, or one that returns no way to unsubscribe', () => { | |
| 414 | expect(judge({ dispatched: 1, taps: [], onTap: 'undefined', unsubscribe: null })) | |
| 415 | .toEqual(['notifications.onTap is undefined, so a page has no way to be handed a tap']) | |
| 416 | expect(judge({ dispatched: 1, taps: [tap], onTap: 'function', unsubscribe: 'undefined' })) | |
| 417 | .toEqual(['notifications.onTap returned undefined, expected a function that unsubscribes']) | |
| 418 | }) | |
| 419 | ||
| 420 | it('names a run that never reported', () => { | |
| 421 | expect(notificationTapProblems(notificationTapReport('** TEST FAILED **'), RUN, 'ios-shim/xcodebuild-notification.log')) | |
| 422 | .toEqual(['the notification tap cold start never reported; see ios-shim/xcodebuild-notification.log']) | |
| 423 | }) | |
| 424 | ||
| 425 | it('sends a push simctl accepts, whose body is the run the banner is found by', () => { | |
| 426 | const payload = notificationPayload(RUN) | |
| 427 | expect(new TextEncoder().encode(payload).length).toBeLessThanOrEqual(4096) | |
| 428 | const parsed = JSON.parse(payload) | |
| 429 | expect(parsed.aps.alert.body).toBe(RUN) | |
| 430 | expect(parsed).toMatchObject({ craftE2E: RUN, route: NOTIFICATION_ROUTE }) | |
| 431 | }) | |
| 432 | }) | |
| 433 | ||
| 385 | 434 | describe('cold-start deep links on Android', () => { |
| 386 | 435 | const LINK = 'crafte2eprobe://e2e/cold?run=craft-e2e-android-shim-1' |
| 387 | 436 | const report = { launch: `${LINK}&receive=subscribe`, receive: 'subscribe', onLink: [{ url: `${LINK}&receive=subscribe`, initial: true }], initialURL: null, unsubscribe: 'function' } |