# 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:**
   ```bash
   # 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:**
   ```bash
   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:**
```javascript
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:**
```swift
// 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:**
```javascript
// 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:**
```bash
# 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:@"org.timesafari.dailynotification.fetch"]
```

---

### Test Case 4: Get Last Notification

**Objective:** Test last notification retrieval

**JavaScript Test Code:**
```javascript
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:**
```json
{
  "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:**
```javascript
// 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:**
```javascript
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:**
```json
{
  "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:**
```javascript
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):**
```bash
# In Xcode debugger (LLDB)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"org.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:**
   ```javascript
   await DailyNotification.scheduleDailyNotification({
     options: {} // Missing 'time' parameter
   });
   ```
   **Expected Error:**
   ```json
   {
     "error": "missing_required_parameter",
     "message": "Missing required parameter: time"
   }
   ```

2. **Invalid Time Format:**
   ```javascript
   await DailyNotification.scheduleDailyNotification({
     options: { time: "invalid" }
   });
   ```
   **Expected Error:**
   ```json
   {
     "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:**
```json
{
  "error": "notifications_denied",
  "message": "Notification permissions denied"
}
```

---

## Manual Build Steps (If Build Script Not Available)

### Step 1: Install Dependencies

```bash
cd ios
pod install
```

### Step 2: Open in Xcode

```bash
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:
   ```xml
   <key>BGTaskSchedulerPermittedIdentifiers</key>
   <array>
     <string>org.timesafari.dailynotification.fetch</string>
     <string>org.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:**
```swift
po UNUserNotificationCenter.current().pendingNotificationRequests()
```

**Check Permission Status:**
```swift
po await UNUserNotificationCenter.current().notificationSettings()
```

**Check BGTask Status (Simulator Only):**
```swift
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"org.timesafari.dailynotification.fetch"]
```

**Check Storage:**
```swift
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:** `doc/testing/NOTIFICATION_PROCEDURES.md`
- **Comprehensive Testing:** `doc/testing/COMPREHENSIVE_GUIDE.md`

---

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

