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
This commit is contained in:
@@ -392,6 +392,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Phase 4: TimeSafari Components Testing -->
|
||||||
|
<div class="ui-section">
|
||||||
|
<h3>🚀 Phase 4: TimeSafari Components</h3>
|
||||||
|
<div class="button-grid">
|
||||||
|
<button id="test-security-manager" class="btn-primary">Test SecurityManager</button>
|
||||||
|
<button id="test-endorser-api-client" class="btn-primary">Test EndorserAPIClient</button>
|
||||||
|
<button id="test-notification-manager" class="btn-primary">Test NotificationManager</button>
|
||||||
|
<button id="test-phase4-integration" class="btn-secondary">Test Complete Integration</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Error Handling Section -->
|
<!-- Error Handling Section -->
|
||||||
<div class="ui-section">
|
<div class="ui-section">
|
||||||
<h3>⚠️ Error Handling</h3>
|
<h3>⚠️ Error Handling</h3>
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
import { Capacitor } from '@capacitor/core';
|
import { Capacitor } from '@capacitor/core';
|
||||||
|
import { DailyNotificationPlugin } from '@timesafari/daily-notification-plugin';
|
||||||
|
|
||||||
// Mock classes for testing when shared utilities aren't available
|
// 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 {
|
class ConfigLoader {
|
||||||
private static instance: ConfigLoader;
|
private static instance: ConfigLoader;
|
||||||
private config: any;
|
private config: any;
|
||||||
@@ -25,13 +37,28 @@ class ConfigLoader {
|
|||||||
},
|
},
|
||||||
endorser: {
|
endorser: {
|
||||||
baseUrl: 'http://10.0.2.2:3001/api/v2/report',
|
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: {
|
testData: {
|
||||||
userDid: 'user:test',
|
userDid: 'did:example:android-test-user',
|
||||||
lastKnownOfferId: '0',
|
lastKnownOfferId: '0',
|
||||||
lastKnownPlanId: '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}`;
|
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 {
|
getAuthHeaders(): any {
|
||||||
return {
|
return {
|
||||||
'Authorization': `Bearer ${this.config.endorser.apiKey}`,
|
'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 {
|
class TimeSafariAndroidTestApp {
|
||||||
private statusElement: HTMLElement;
|
private statusElement: HTMLElement;
|
||||||
private logElement: HTMLElement;
|
private logElement: HTMLElement;
|
||||||
@@ -346,6 +406,11 @@ class TimeSafariAndroidTestApp {
|
|||||||
private notificationService: MockDailyNotificationService;
|
private notificationService: MockDailyNotificationService;
|
||||||
private logger: TestLogger;
|
private logger: TestLogger;
|
||||||
|
|
||||||
|
// Phase 4: TimeSafari components
|
||||||
|
private endorserAPIClient: EndorserAPIClient;
|
||||||
|
private securityManager: SecurityManager;
|
||||||
|
private timeSafariNotificationManager: TimeSafariNotificationManager;
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private permissionManager: PermissionManager;
|
private permissionManager: PermissionManager;
|
||||||
private settingsPanel: SettingsPanel;
|
private settingsPanel: SettingsPanel;
|
||||||
@@ -359,6 +424,11 @@ class TimeSafariAndroidTestApp {
|
|||||||
this.logger = new TestLogger('debug');
|
this.logger = new TestLogger('debug');
|
||||||
this.notificationService = new MockDailyNotificationService(this.configLoader.getConfig());
|
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
|
// Initialize UI components
|
||||||
this.permissionManager = new PermissionManager(
|
this.permissionManager = new PermissionManager(
|
||||||
document.getElementById('permission-status-container')!,
|
document.getElementById('permission-status-container')!,
|
||||||
@@ -370,7 +440,8 @@ class TimeSafariAndroidTestApp {
|
|||||||
|
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.initializeUI();
|
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() {
|
private setupEventListeners() {
|
||||||
@@ -392,6 +463,12 @@ class TimeSafariAndroidTestApp {
|
|||||||
document.getElementById('battery-status')?.addEventListener('click', () => this.checkBatteryStatus());
|
document.getElementById('battery-status')?.addEventListener('click', () => this.checkBatteryStatus());
|
||||||
document.getElementById('exact-alarm-status')?.addEventListener('click', () => this.checkExactAlarmStatus());
|
document.getElementById('exact-alarm-status')?.addEventListener('click', () => this.checkExactAlarmStatus());
|
||||||
document.getElementById('reboot-recovery')?.addEventListener('click', () => this.checkRebootRecovery());
|
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<void> {
|
private async initializeUI(): Promise<void> {
|
||||||
@@ -408,6 +485,49 @@ class TimeSafariAndroidTestApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 4: Initialize TimeSafari components
|
||||||
|
private async initializePhase4Components(): Promise<void> {
|
||||||
|
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
|
// Enhanced UI methods
|
||||||
private async checkPermissions(): Promise<void> {
|
private async checkPermissions(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -802,6 +922,200 @@ class TimeSafariAndroidTestApp {
|
|||||||
private updateStatus(status: string) {
|
private updateStatus(status: string) {
|
||||||
this.statusElement.textContent = status;
|
this.statusElement.textContent = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 4: TimeSafari component test methods
|
||||||
|
private async testSecurityManager(): Promise<void> {
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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
|
// Initialize app when DOM is ready
|
||||||
|
|||||||
Reference in New Issue
Block a user