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

581 lines
14 KiB
Markdown

# 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:@"com.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:@"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:**
```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>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:**
```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:@"com.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:** `docs/notification-testing-procedures.md`
- **Comprehensive Testing:** `docs/comprehensive-testing-guide-v2.md`
---
**Status:****READY FOR TESTING**
**Last Updated:** 2025-01-XX