Files
daily-notification-plugin/doc/IOS_PHASE1_TESTING_GUIDE.md
Server 5844b92e18 feat(ios): implement Phase 1 permission methods and fix build issues
Implement checkPermissionStatus() and requestNotificationPermissions()
methods for iOS plugin, matching Android functionality. Fix compilation
errors across plugin files and add comprehensive build/test infrastructure.

Key Changes:
- Add checkPermissionStatus() and requestNotificationPermissions() methods
- Fix 13+ categories of Swift compilation errors (type conversions, logger
  API, access control, async/await, etc.)
- Create DailyNotificationScheduler, DailyNotificationStorage,
  DailyNotificationStateActor, and DailyNotificationErrorCodes components
- Fix CoreData initialization to handle missing model gracefully for Phase 1
- Add iOS test app build script with simulator auto-detection
- Update directive with lessons learned from build and permission work

Build Status:  BUILD SUCCEEDED
Test App:  Ready for iOS Simulator testing

Files Modified:
- doc/directives/0003-iOS-Android-Parity-Directive.md (lessons learned)
- ios/Plugin/DailyNotificationPlugin.swift (Phase 1 methods)
- ios/Plugin/DailyNotificationModel.swift (CoreData fix)
- 11+ other plugin files (compilation fixes)

Files Added:
- ios/Plugin/DailyNotificationScheduler.swift
- ios/Plugin/DailyNotificationStorage.swift
- ios/Plugin/DailyNotificationStateActor.swift
- ios/Plugin/DailyNotificationErrorCodes.swift
- scripts/build-ios-test-app.sh
- scripts/setup-ios-test-app.sh
- test-apps/ios-test-app/ (full test app)
- Multiple Phase 1 documentation files
2025-11-13 05:14:24 -08:00

14 KiB

iOS Phase 1 Testing Guide

Status: READY FOR TESTING
Phase: Phase 1 - Core Infrastructure Parity
Target: iOS Simulator (primary) or Physical Device


Quick Start Testing

Prerequisites

  • Xcode Version: 15.0 or later
  • macOS Version: 13.0 (Ventura) or later
  • iOS Deployment Target: iOS 15.0 or later
  • Test App: test-apps/ios-test-app/ (to be created)

Testing Environment Setup

  1. Build Test App:

    # From repo root
    ./scripts/build-ios-test-app.sh --simulator
    

    Note: If build script doesn't exist yet, see "Manual Build Steps" below.

  2. Open in Xcode:

    cd test-apps/ios-test-app
    open App.xcworkspace  # or App.xcodeproj
    
  3. Run on Simulator:

    • Select target device (iPhone 15, iPhone 15 Pro, etc.)
    • Press Cmd+R to build and run
    • Or use Xcode menu: Product → Run

Phase 1 Test Cases

Test Case 1: Plugin Initialization

Objective: Verify plugin loads and initializes correctly

Steps:

  1. Launch test app on iOS Simulator
  2. Check Console.app logs for: DNP-PLUGIN: Daily Notification Plugin loaded on iOS
  3. Verify no initialization errors

Expected Results:

  • Plugin loads without errors
  • Storage and scheduler components initialized
  • State actor created (iOS 13+)

Logs to Check:

DNP-PLUGIN: Daily Notification Plugin loaded on iOS
DailyNotificationStorage: Database opened successfully at [path]
DailyNotificationScheduler: Notification category setup complete

Test Case 2: Configure Method

Objective: Test plugin configuration

JavaScript Test Code:

import { DailyNotification } from '@capacitor-community/daily-notification';

// Test configure
await DailyNotification.configure({
  options: {
    storage: 'tiered',
    ttlSeconds: 3600,
    prefetchLeadMinutes: 5,
    maxNotificationsPerDay: 1,
    retentionDays: 7
  }
});

Steps:

  1. Call configure() with options
  2. Check Console.app for: DNP-PLUGIN: Plugin configuration completed successfully
  3. Verify settings stored in UserDefaults

Expected Results:

  • Configuration succeeds without errors
  • Settings stored correctly
  • Database path set correctly

Verification:

// In Xcode debugger or Console.app
po UserDefaults.standard.dictionary(forKey: "DailyNotificationPrefs")

Test Case 3: Schedule Daily Notification

Objective: Test main scheduling method with prefetch

JavaScript Test Code:

// Schedule notification for 5 minutes from now
const now = new Date();
const scheduleTime = new Date(now.getTime() + 5 * 60 * 1000);
const hour = scheduleTime.getHours();
const minute = scheduleTime.getMinutes();
const timeString = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;

await DailyNotification.scheduleDailyNotification({
  options: {
    time: timeString,
    title: "Test Notification",
    body: "This is a Phase 1 test notification",
    sound: true,
    url: null
  }
});

Steps:

  1. Schedule notification 5 minutes from now
  2. Verify prefetch scheduled 5 minutes before notification time
  3. Check Console.app logs
  4. Wait for notification to appear

Expected Results:

  • Notification scheduled successfully
  • Prefetch BGTask scheduled 5 minutes before notification
  • Notification appears at scheduled time (±180s tolerance)

Logs to Check:

DNP-PLUGIN: Scheduling daily notification
DNP-PLUGIN: Daily notification scheduled successfully
DNP-FETCH-SCHEDULE: Background fetch scheduled for [date]
DailyNotificationScheduler: Notification scheduled successfully for [date]

Verification Commands:

# Check pending notifications (in Xcode debugger)
po UNUserNotificationCenter.current().pendingNotificationRequests()

# Check BGTask scheduling (simulator only)
# Use LLDB command in Xcode debugger:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]

Test Case 4: Get Last Notification

Objective: Test last notification retrieval

JavaScript Test Code:

const lastNotification = await DailyNotification.getLastNotification();
console.log('Last notification:', lastNotification);

Steps:

  1. Schedule a notification
  2. Wait for it to fire (or manually trigger)
  3. Call getLastNotification()
  4. Verify returned data structure

Expected Results:

  • Returns notification object with: id, title, body, timestamp, url
  • Returns empty object {} if no notifications exist
  • Thread-safe retrieval via state actor

Expected Response:

{
  "id": "daily_1234567890",
  "title": "Test Notification",
  "body": "This is a Phase 1 test notification",
  "timestamp": 1234567890000,
  "url": null
}

Test Case 5: Cancel All Notifications

Objective: Test cancellation of all scheduled notifications

JavaScript Test Code:

// Schedule multiple notifications first
await DailyNotification.scheduleDailyNotification({...});
await DailyNotification.scheduleDailyNotification({...});

// Then cancel all
await DailyNotification.cancelAllNotifications();

Steps:

  1. Schedule 2-3 notifications
  2. Verify they're scheduled: getNotificationStatus()
  3. Call cancelAllNotifications()
  4. Verify all cancelled

Expected Results:

  • All notifications cancelled
  • Storage cleared
  • Pending count = 0

Logs to Check:

DNP-PLUGIN: All notifications cancelled successfully
DailyNotificationScheduler: All notifications cancelled
DailyNotificationStorage: All notifications cleared

Test Case 6: Get Notification Status

Objective: Test status retrieval

JavaScript Test Code:

const status = await DailyNotification.getNotificationStatus();
console.log('Status:', status);

Steps:

  1. Call getNotificationStatus()
  2. Verify response structure
  3. Check permission status
  4. Check pending count

Expected Results:

  • Returns complete status object
  • Permission status accurate
  • Pending count accurate
  • Next notification time calculated

Expected Response:

{
  "isEnabled": true,
  "isScheduled": true,
  "lastNotificationTime": 1234567890000,
  "nextNotificationTime": 1234567895000,
  "pending": 1,
  "settings": {
    "storageMode": "tiered",
    "ttlSeconds": 3600
  }
}

Test Case 7: Update Settings

Objective: Test settings update

JavaScript Test Code:

await DailyNotification.updateSettings({
  settings: {
    sound: false,
    priority: "high",
    timezone: "America/New_York"
  }
});

Steps:

  1. Call updateSettings() with new settings
  2. Verify settings stored
  3. Retrieve settings and verify changes

Expected Results:

  • Settings updated successfully
  • Changes persisted
  • Thread-safe update via state actor

Test Case 8: BGTask Miss Detection

Objective: Test BGTask miss detection and rescheduling

Steps:

  1. Schedule a notification with prefetch
  2. Note the BGTask earliestBeginDate from logs
  3. Simulate missing the BGTask window:
    • Wait 15+ minutes after earliestBeginDate
    • Ensure no successful run recorded
  4. Launch app (triggers checkForMissedBGTask())
  5. Verify BGTask rescheduled

Expected Results:

  • Miss detection triggers on app launch
  • BGTask rescheduled for 1 minute from now
  • Logs show: DNP-FETCH: BGTask missed window; rescheduling

Logs to Check:

DNP-FETCH: BGTask missed window; rescheduling
DNP-FETCH: BGTask rescheduled for [date]

Manual Trigger (Simulator Only):

# In Xcode debugger (LLDB)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]

Test Case 9: Permission Auto-Healing

Objective: Test automatic permission request

Steps:

  1. Reset notification permissions (Settings → [App] → Notifications → Off)
  2. Call scheduleDailyNotification()
  3. Verify permission request dialog appears
  4. Grant permissions
  5. Verify scheduling succeeds

Expected Results:

  • Permission request dialog appears automatically
  • Scheduling succeeds after granting
  • Error returned if permissions denied

Logs to Check:

DailyNotificationScheduler: Permission request result: true
DailyNotificationScheduler: Scheduling notification: [id]

Test Case 10: Error Handling

Objective: Test error code responses

Test Scenarios:

  1. Missing Parameters:

    await DailyNotification.scheduleDailyNotification({
      options: {} // Missing 'time' parameter
    });
    

    Expected Error:

    {
      "error": "missing_required_parameter",
      "message": "Missing required parameter: time"
    }
    
  2. Invalid Time Format:

    await DailyNotification.scheduleDailyNotification({
      options: { time: "invalid" }
    });
    

    Expected Error:

    {
      "error": "invalid_time_format",
      "message": "Invalid time format. Use HH:mm"
    }
    
  3. Notifications Denied:

    • Deny notification permissions
    • Try to schedule notification
    • Verify error code returned

Expected Error:

{
  "error": "notifications_denied",
  "message": "Notification permissions denied"
}

Manual Build Steps (If Build Script Not Available)

Step 1: Install Dependencies

cd ios
pod install

Step 2: Open in Xcode

open DailyNotificationPlugin.xcworkspace
# or
open DailyNotificationPlugin.xcodeproj

Step 3: Configure Build Settings

  1. Select project in Xcode
  2. Go to Signing & Capabilities
  3. Add Background Modes:
    • Background fetch
    • Background processing
  4. Add to Info.plist:
    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
      <string>com.timesafari.dailynotification.fetch</string>
      <string>com.timesafari.dailynotification.notify</string>
    </array>
    

Step 4: Build and Run

  • Select target device (Simulator or Physical Device)
  • Press Cmd+R or Product → Run

Debugging Tools

Console.app Logging

View Logs:

  1. Open Console.app (Applications → Utilities)
  2. Select your device/simulator
  3. Filter by: DNP- or DailyNotification

Key Log Prefixes:

  • DNP-PLUGIN: - Main plugin operations
  • DNP-FETCH: - Background fetch operations
  • DNP-FETCH-SCHEDULE: - BGTask scheduling
  • DailyNotificationStorage: - Storage operations
  • DailyNotificationScheduler: - Scheduling operations

Xcode Debugger Commands

Check Pending Notifications:

po UNUserNotificationCenter.current().pendingNotificationRequests()

Check Permission Status:

po await UNUserNotificationCenter.current().notificationSettings()

Check BGTask Status (Simulator Only):

e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]

Check Storage:

po UserDefaults.standard.dictionary(forKey: "DailyNotificationPrefs")

Common Issues & Solutions

Issue 1: BGTaskScheduler Not Running

Symptoms:

  • BGTask never executes
  • No logs from handleBackgroundFetch()

Solutions:

  1. Verify Info.plist has BGTaskSchedulerPermittedIdentifiers
  2. Check task registered in setupBackgroundTasks()
  3. Simulator workaround: Use LLDB command to manually trigger (see above)

Issue 2: Notifications Not Delivering

Symptoms:

  • Notification scheduled but never appears
  • No notification in notification center

Solutions:

  1. Check permissions: UNUserNotificationCenter.current().getNotificationSettings()
  2. Verify notification scheduled: getPendingNotificationRequests()
  3. Check notification category registered
  4. Verify time hasn't passed (iOS may deliver immediately if time passed)

Issue 3: Build Failures

Symptoms:

  • Xcode build errors
  • Missing dependencies

Solutions:

  1. Run pod install in ios/ directory
  2. Clean build folder: Product → Clean Build Folder (Cmd+Shift+K)
  3. Verify Capacitor plugin path in capacitor.plugins.json
  4. Check Xcode scheme matches workspace

Issue 4: Background Tasks Expiring

Symptoms:

  • BGTask starts but expires before completion
  • Logs show: Background fetch task expired

Solutions:

  1. Ensure task.setTaskCompleted(success:) called before expiration
  2. Keep processing efficient (< 30 seconds)
  3. Schedule next task immediately after completion

Testing Checklist

Phase 1 Core Methods

  • configure() - Configuration succeeds
  • scheduleDailyNotification() - Notification schedules correctly
  • getLastNotification() - Returns correct notification
  • cancelAllNotifications() - All notifications cancelled
  • getNotificationStatus() - Status accurate
  • updateSettings() - Settings updated correctly

Background Tasks

  • BGTask scheduled 5 minutes before notification
  • BGTask executes successfully
  • BGTask miss detection works
  • BGTask rescheduling works

Error Handling

  • Missing parameter errors returned
  • Invalid time format errors returned
  • Permission denied errors returned
  • Error codes match Android format

Thread Safety

  • No race conditions observed
  • State actor used for all storage operations
  • Background tasks use state actor

Next Steps After Testing

  1. Document Issues: Create GitHub issues for any bugs found
  2. Update Test Cases: Add test cases for edge cases discovered
  3. Performance Testing: Test with multiple notifications
  4. Phase 2 Preparation: Begin Phase 2 advanced features

References

  • Directive: doc/directives/0003-iOS-Android-Parity-Directive.md
  • Phase 1 Summary: doc/PHASE1_COMPLETION_SUMMARY.md
  • Android Testing: docs/notification-testing-procedures.md
  • Comprehensive Testing: docs/comprehensive-testing-guide-v2.md

Status: READY FOR TESTING
Last Updated: 2025-01-XX