From f33d96d7a6db1b1e43bd4c528b238dd18f6737df Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Sat, 4 Oct 2025 05:41:21 +0000 Subject: [PATCH] feat(test-apps): update Android test app with Phase 4 TimeSafari components - Added Phase 4 imports: EndorserAPIClient, SecurityManager, TimeSafariNotificationManager - Enhanced ConfigLoader with Phase 4 configuration methods - Updated TimeSafariAndroidTestApp class with Phase 4 component integration - Added comprehensive Phase 4 test methods: - testSecurityManager(): JWT generation/verification testing - testEndorserAPIClient(): Endorser.ch API integration testing - testTimeSafariNotificationManager(): Notification generation testing - testPhase4Integration(): Complete workflow testing - Added Phase 4 initialization in constructor and setupEventListeners - Updated HTML with Phase 4 test buttons and UI sections - Enhanced configuration with security and EndorserAPI settings - Added TimeSafari user configuration with preferences and test data Android test app now fully supports Phase 4 TimeSafari integration testing --- test-apps/android-test/src/index.html | 11 + test-apps/android-test/src/index.ts | 328 +++++++++++++++++++++++++- 2 files changed, 332 insertions(+), 7 deletions(-) diff --git a/test-apps/android-test/src/index.html b/test-apps/android-test/src/index.html index 709cd62..fa27a41 100644 --- a/test-apps/android-test/src/index.html +++ b/test-apps/android-test/src/index.html @@ -392,6 +392,17 @@ + +
+

🚀 Phase 4: TimeSafari Components

+
+ + + + +
+
+

⚠️ Error Handling

diff --git a/test-apps/android-test/src/index.ts b/test-apps/android-test/src/index.ts index 68d8782..fe8b43c 100644 --- a/test-apps/android-test/src/index.ts +++ b/test-apps/android-test/src/index.ts @@ -1,6 +1,18 @@ import { Capacitor } from '@capacitor/core'; - -// Mock classes for testing when shared utilities aren't available +import { DailyNotificationPlugin } from '@timesafari/daily-notification-plugin'; + +// Phase 4: Import TimeSafari components +import { EndorserAPIClient, TIMESAFARI_ENDSORER_CONFIG } from '../../../src/typescript/EndorserAPIClient'; +import { SecurityManager, TIMESAFARI_SECURITY_CONFIG } from '../../../src/typescript/SecurityManager'; +import { TimeSafariNotificationManager, DEFAULT_TIMESAFARI_PREFERENCES } from '../../../src/typescript/TimeSafariNotificationManager'; +import { + TimeSafariUser, + TimeSafariPreferences, + EnhancedTimeSafariNotification, + TimeSafariNotificationType +} from '../../../src/definitions'; + +// Enhanced ConfigLoader for Phase 4 class ConfigLoader { private static instance: ConfigLoader; private config: any; @@ -25,13 +37,28 @@ class ConfigLoader { }, endorser: { baseUrl: 'http://10.0.2.2:3001/api/v2/report', - apiKey: 'test-api-key' + apiKey: 'test-api-key', + // Phase 4: Enhanced EndorserAPI configuration + timeoutMs: 15000, + maxRetries: 3, + enableParallel: true, + maxConcurrent: 3 + }, + security: { + // Phase 4: Security configuration + enableCryptoSigning: true, + enableJWTGeneration: true, + jwtExpirationMinutes: 60, + signatureAlgorithm: 'ES256K', + credentialStorage: 'secure_element' }, testData: { - userDid: 'user:test', + userDid: 'did:example:android-test-user', lastKnownOfferId: '0', lastKnownPlanId: '0', - starredPlanIds: ['plan:test'] + starredPlanIds: ['plan:test-1', 'plan:test-2'], + favoritePersonIds: ['person:test-1'], + favoriteItemIds: ['item:test-1'] } }; } @@ -50,6 +77,39 @@ class ConfigLoader { return `${this.config.endorser.baseUrl}${endpoints[endpoint] || endpoint}`; } + // Phase 4: Enhanced configuration methods + getEndorserAPIConfig() { + return { + baseUrl: this.config.endorser.baseUrl.replace('/api/v2/report', ''), + timeoutMs: this.config.endorser.timeoutMs, + maxRetries: this.config.endorser.maxRetries, + enableParallel: this.config.endorser.enableParallel, + maxConcurrent: this.config.endorser.maxConcurrent + }; + } + + getSecurityConfig() { + return { + enableCryptoSigning: this.config.security.enableCryptoSigning, + enableJWTGeneration: this.config.security.enableJWTGeneration, + jwtExpirationMinutes: this.config.security.jwtExpirationMinutes, + signatureAlgorithm: this.config.security.signatureAlgorithm, + credentialStorage: this.config.security.credentialStorage + }; + } + + getTimeSafariUser(): TimeSafariUser { + return { + activeDid: this.config.testData.userDid, + preferences: DEFAULT_TIMESAFARI_PREFERENCES, + starredPlanIds: this.config.testData.starredPlanIds, + favoritePersonIds: this.config.testData.favoritePersonIds, + favoriteItemIds: this.config.testData.favoriteItemIds, + lastKnownOfferId: this.config.testData.lastKnownOfferId, + lastKnownPlanId: this.config.testData.lastKnownPlanId + }; + } + getAuthHeaders(): any { return { 'Authorization': `Bearer ${this.config.endorser.apiKey}`, @@ -338,7 +398,7 @@ class ErrorDisplay { } } -// Enhanced test interface for TimeSafari Android integration +// Enhanced test interface for TimeSafari Android integration with Phase 4 components class TimeSafariAndroidTestApp { private statusElement: HTMLElement; private logElement: HTMLElement; @@ -346,6 +406,11 @@ class TimeSafariAndroidTestApp { private notificationService: MockDailyNotificationService; private logger: TestLogger; + // Phase 4: TimeSafari components + private endorserAPIClient: EndorserAPIClient; + private securityManager: SecurityManager; + private timeSafariNotificationManager: TimeSafariNotificationManager; + // UI Components private permissionManager: PermissionManager; private settingsPanel: SettingsPanel; @@ -359,6 +424,11 @@ class TimeSafariAndroidTestApp { this.logger = new TestLogger('debug'); this.notificationService = new MockDailyNotificationService(this.configLoader.getConfig()); + // Phase 4: Initialize TimeSafari components + this.endorserAPIClient = new EndorserAPIClient(this.configLoader.getEndorserAPIConfig()); + this.securityManager = new SecurityManager(this.configLoader.getSecurityConfig()); + this.timeSafariNotificationManager = new TimeSafariNotificationManager(); + // Initialize UI components this.permissionManager = new PermissionManager( document.getElementById('permission-status-container')!, @@ -370,7 +440,8 @@ class TimeSafariAndroidTestApp { this.setupEventListeners(); this.initializeUI(); - this.log('TimeSafari Android Test app initialized with enhanced UI'); + this.initializePhase4Components(); + this.log('TimeSafari Android Test app initialized with Phase 4 components'); } private setupEventListeners() { @@ -392,6 +463,12 @@ class TimeSafariAndroidTestApp { document.getElementById('battery-status')?.addEventListener('click', () => this.checkBatteryStatus()); document.getElementById('exact-alarm-status')?.addEventListener('click', () => this.checkExactAlarmStatus()); document.getElementById('reboot-recovery')?.addEventListener('click', () => this.checkRebootRecovery()); + + // Phase 4: TimeSafari component testing + document.getElementById('test-security-manager')?.addEventListener('click', () => this.testSecurityManager()); + document.getElementById('test-endorser-api-client')?.addEventListener('click', () => this.testEndorserAPIClient()); + document.getElementById('test-notification-manager')?.addEventListener('click', () => this.testTimeSafariNotificationManager()); + document.getElementById('test-phase4-integration')?.addEventListener('click', () => this.testPhase4Integration()); } private async initializeUI(): Promise { @@ -408,6 +485,49 @@ class TimeSafariAndroidTestApp { } } + // Phase 4: Initialize TimeSafari components + private async initializePhase4Components(): Promise { + try { + this.log('Initializing Phase 4 TimeSafari components...'); + + // Initialize SecurityManager with test DID + const timeSafariUser = this.configLoader.getTimeSafariUser(); + const securityInitialized = await this.securityManager.initialize(timeSafariUser.activeDid); + + if (securityInitialized) { + this.log('✅ SecurityManager initialized successfully'); + + // Generate JWT token for API authentication + const jwt = await this.securityManager.generateJWT({ + scope: 'notifications', + audience: 'endorser-api' + }); + + if (jwt) { + this.endorserAPIClient.setAuthToken(jwt); + this.log('✅ JWT token generated and set for EndorserAPI'); + } + } else { + this.log('❌ SecurityManager initialization failed'); + } + + // Initialize TimeSafariNotificationManager + const managerInitialized = await this.timeSafariNotificationManager.initialize(timeSafariUser); + + if (managerInitialized) { + this.log('✅ TimeSafariNotificationManager initialized successfully'); + } else { + this.log('❌ TimeSafariNotificationManager initialization failed'); + } + + this.log('Phase 4 components initialization completed'); + + } catch (error) { + this.log('Error initializing Phase 4 components:', error); + this.errorDisplay.showError(error as Error); + } + } + // Enhanced UI methods private async checkPermissions(): Promise { try { @@ -802,6 +922,200 @@ class TimeSafariAndroidTestApp { private updateStatus(status: string) { this.statusElement.textContent = status; } + + // Phase 4: TimeSafari component test methods + private async testSecurityManager(): Promise { + try { + this.log('🔐 Testing SecurityManager...'); + + const timeSafariUser = this.configLoader.getTimeSafariUser(); + + // Test JWT generation + const jwt = await this.securityManager.generateJWT({ + scope: 'test', + audience: 'test-api' + }); + + if (jwt) { + this.log('✅ JWT generation successful'); + this.log('JWT token:', jwt.substring(0, 50) + '...'); + + // Test JWT verification + const claims = await this.securityManager.verifyJWT(jwt); + if (claims) { + this.log('✅ JWT verification successful'); + this.log('Claims:', claims); + } else { + this.log('❌ JWT verification failed'); + } + } else { + this.log('❌ JWT generation failed'); + } + + // Test operation history + const history = this.securityManager.getOperationHistory(); + this.log(`Security operations performed: ${history.length}`); + + this.log('SecurityManager test completed'); + + } catch (error) { + this.log('SecurityManager test failed:', error); + this.errorDisplay.showError(error as Error); + } + } + + private async testEndorserAPIClient(): Promise { + try { + this.log('🌐 Testing EndorserAPIClient...'); + + const timeSafariUser = this.configLoader.getTimeSafariUser(); + + // Test offers to person + this.log('Testing offers to person...'); + const offersResponse = await this.endorserAPIClient.fetchOffersToPerson( + timeSafariUser.activeDid, + timeSafariUser.lastKnownOfferId, + undefined + ); + + this.log(`✅ Offers fetched: ${offersResponse.data.length} offers`); + if (offersResponse.data.length > 0) { + this.log('Sample offer:', offersResponse.data[0]); + } + + // Test offers to projects + this.log('Testing offers to projects...'); + const projectsResponse = await this.endorserAPIClient.fetchOffersToProjectsOwnedByMe( + timeSafariUser.lastKnownOfferId + ); + + this.log(`✅ Project offers fetched: ${projectsResponse.data.length} offers`); + + // Test project updates + if (timeSafariUser.starredPlanIds && timeSafariUser.starredPlanIds.length > 0) { + this.log('Testing project updates...'); + const updatesResponse = await this.endorserAPIClient.fetchProjectsLastUpdated( + timeSafariUser.starredPlanIds, + timeSafariUser.lastKnownPlanId, + undefined + ); + + this.log(`✅ Project updates fetched: ${updatesResponse.data.length} updates`); + } + + this.log('EndorserAPIClient test completed'); + + } catch (error) { + this.log('EndorserAPIClient test failed:', error); + this.errorDisplay.showError(error as Error); + } + } + + private async testTimeSafariNotificationManager(): Promise { + try { + this.log('📱 Testing TimeSafariNotificationManager...'); + + // Test notification generation + this.log('Generating TimeSafari notifications...'); + const notifications = await this.timeSafariNotificationManager.generateNotifications({ + forceFetch: false, + includeMetadata: true, + filterByPriority: true, + maxNotifications: 10, + cacheTtl: 300000 + }); + + this.log(`✅ Generated ${notifications.length} notifications`); + + // Display notification details + notifications.forEach((notification, index) => { + this.log(`Notification ${index + 1}:`, { + type: notification.type, + subtype: notification.subtype, + priority: notification.notificationPriority, + timestamp: new Date(notification.timestamp).toISOString(), + disabled: notification.disabled, + sound: notification.sound, + vibration: notification.vibration + }); + }); + + // Test statistics + const stats = this.timeSafariNotificationManager.getStatistics(); + this.log('Manager statistics:', stats); + + this.log('TimeSafariNotificationManager test completed'); + + } catch (error) { + this.log('TimeSafariNotificationManager test failed:', error); + this.errorDisplay.showError(error as Error); + } + } + + private async testPhase4Integration(): Promise { + try { + this.log('🚀 Testing complete Phase 4 integration...'); + + const timeSafariUser = this.configLoader.getTimeSafariUser(); + + // Test complete workflow + this.log('Step 1: Security authentication...'); + const jwt = await this.securityManager.generateJWT({ + scope: 'notifications', + audience: 'endorser-api' + }); + + if (!jwt) { + throw new Error('JWT generation failed'); + } + + this.endorserAPIClient.setAuthToken(jwt); + this.log('✅ Authentication successful'); + + this.log('Step 2: Fetching TimeSafari data...'); + const bundle = await this.endorserAPIClient.fetchAllTimeSafariNotifications({ + activeDid: timeSafariUser.activeDid, + starredPlanIds: timeSafariUser.starredPlanIds || [], + lastKnownOfferId: timeSafariUser.lastKnownOfferId, + lastKnownPlanId: timeSafariUser.lastKnownPlanId, + fetchOffersToPerson: true, + fetchOffersToProjects: true, + fetchProjectUpdates: true, + notificationPreferences: { + offers: true, + projects: true, + people: false, + items: true + } + }); + + this.log(`✅ Data fetched successfully: ${bundle.success}`); + this.log('Bundle metadata:', bundle.metadata); + + this.log('Step 3: Generating notifications...'); + const notifications = await this.timeSafariNotificationManager.generateNotifications({ + forceFetch: true, + includeMetadata: true, + maxNotifications: 20 + }); + + this.log(`✅ Generated ${notifications.length} notifications`); + + // Summary + this.log('🎉 Phase 4 integration test completed successfully!'); + this.log('Summary:', { + securityInitialized: this.securityManager.isInitialized(), + apiClientReady: !!this.endorserAPIClient, + managerInitialized: this.timeSafariNotificationManager.isInitialized(), + notificationsGenerated: notifications.length, + bundleSuccess: bundle.success + }); + + } catch (error) { + this.log('Phase 4 integration test failed:', error); + this.errorDisplay.showError(error as Error); + } + } } // Initialize app when DOM is ready