fix: Resolve daily-notification test suite issues
- Fix test structure to use DailyNotification class with mocks - Add proper validation for required URL parameter - Fix event handler error handling in setupEventListeners - Update all tests to use mock plugin instead of Capacitor plugin - Add comprehensive validation tests for URL, time, timezone, retry settings - All 18 daily-notification tests now passing
This commit is contained in:
@@ -142,13 +142,20 @@ export class DailyNotification {
|
||||
private setupEventListeners(): void {
|
||||
document.addEventListener('notification', (event: Event) => {
|
||||
this.eventListeners.get('notification')?.forEach(handler => {
|
||||
handler(event);
|
||||
try {
|
||||
handler(event);
|
||||
} catch (error) {
|
||||
console.error('Error in event handler:', error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private validateOptions(options: NotificationOptions): void {
|
||||
if (options.url && !this.isValidUrl(options.url)) {
|
||||
if (!options.url) {
|
||||
throw new Error('URL is required');
|
||||
}
|
||||
if (!this.isValidUrl(options.url)) {
|
||||
throw new Error('Invalid URL format');
|
||||
}
|
||||
if (options.time && !this.isValidTime(options.time)) {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
/**
|
||||
* Tests for the Daily Notification plugin
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
*/
|
||||
|
||||
import { registerPlugin } from '@capacitor/core';
|
||||
import { DailyNotification } from '../src/daily-notification';
|
||||
import { DailyNotificationPlugin, NotificationOptions, NotificationStatus, NotificationResponse, NotificationSettings } from '../src/definitions';
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
|
||||
const DailyNotification = registerPlugin<DailyNotificationPlugin>('DailyNotification');
|
||||
|
||||
describe('DailyNotification Plugin', () => {
|
||||
let plugin: DailyNotification;
|
||||
let mockPlugin: jest.Mocked<DailyNotificationPlugin>;
|
||||
|
||||
const mockOptions: NotificationOptions = {
|
||||
url: 'https://api.example.com/daily-content',
|
||||
time: '08:00',
|
||||
@@ -17,24 +20,46 @@ describe('DailyNotification Plugin', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// Create mock plugin with all required methods
|
||||
mockPlugin = {
|
||||
scheduleDailyNotification: jest.fn(),
|
||||
getLastNotification: jest.fn(),
|
||||
cancelAllNotifications: jest.fn(),
|
||||
getNotificationStatus: jest.fn(),
|
||||
updateSettings: jest.fn(),
|
||||
getBatteryStatus: jest.fn(),
|
||||
requestBatteryOptimizationExemption: jest.fn(),
|
||||
setAdaptiveScheduling: jest.fn(),
|
||||
getPowerState: jest.fn(),
|
||||
checkPermissions: jest.fn(),
|
||||
requestPermissions: jest.fn(),
|
||||
};
|
||||
|
||||
// Create plugin instance with mock
|
||||
plugin = new DailyNotification(mockPlugin);
|
||||
|
||||
// Reset mocks before each test
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('scheduleDailyNotification', () => {
|
||||
it('should schedule a basic notification', async () => {
|
||||
await DailyNotification.scheduleDailyNotification(mockOptions);
|
||||
// Verify the native implementation was called with correct parameters
|
||||
expect(DailyNotification.scheduleDailyNotification).toHaveBeenCalledWith(mockOptions);
|
||||
await plugin.scheduleDailyNotification(mockOptions);
|
||||
// Verify the mock was called with correct parameters
|
||||
expect(mockPlugin.scheduleDailyNotification).toHaveBeenCalledWith(mockOptions);
|
||||
});
|
||||
|
||||
it('should handle network errors gracefully', async () => {
|
||||
mockPlugin.scheduleDailyNotification.mockRejectedValueOnce(
|
||||
new Error('Network error')
|
||||
);
|
||||
|
||||
const errorOptions: NotificationOptions = {
|
||||
...mockOptions,
|
||||
url: 'https://invalid-url.com'
|
||||
};
|
||||
|
||||
await expect(DailyNotification.scheduleDailyNotification(errorOptions))
|
||||
await expect(plugin.scheduleDailyNotification(errorOptions))
|
||||
.rejects
|
||||
.toThrow('Network error');
|
||||
});
|
||||
@@ -44,7 +69,7 @@ describe('DailyNotification Plugin', () => {
|
||||
time: '08:00'
|
||||
} as NotificationOptions;
|
||||
|
||||
await expect(DailyNotification.scheduleDailyNotification(invalidOptions))
|
||||
await expect(plugin.scheduleDailyNotification(invalidOptions))
|
||||
.rejects
|
||||
.toThrow('URL is required');
|
||||
});
|
||||
@@ -59,21 +84,25 @@ describe('DailyNotification Plugin', () => {
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
const result = await DailyNotification.getLastNotification();
|
||||
mockPlugin.getLastNotification.mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await plugin.getLastNotification();
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
it('should return null when no notifications exist', async () => {
|
||||
const result = await DailyNotification.getLastNotification();
|
||||
mockPlugin.getLastNotification.mockResolvedValueOnce(null);
|
||||
|
||||
const result = await plugin.getLastNotification();
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelAllNotifications', () => {
|
||||
it('should cancel all scheduled notifications', async () => {
|
||||
await DailyNotification.cancelAllNotifications();
|
||||
// Verify the native implementation was called
|
||||
expect(DailyNotification.cancelAllNotifications).toHaveBeenCalled();
|
||||
await plugin.cancelAllNotifications();
|
||||
// Verify the mock was called
|
||||
expect(mockPlugin.cancelAllNotifications).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,7 +115,9 @@ describe('DailyNotification Plugin', () => {
|
||||
settings: {}
|
||||
};
|
||||
|
||||
const result = await DailyNotification.getNotificationStatus();
|
||||
mockPlugin.getNotificationStatus.mockResolvedValueOnce(mockStatus);
|
||||
|
||||
const result = await plugin.getNotificationStatus();
|
||||
expect(result).toEqual(mockStatus);
|
||||
});
|
||||
|
||||
@@ -99,7 +130,9 @@ describe('DailyNotification Plugin', () => {
|
||||
settings: {}
|
||||
};
|
||||
|
||||
const result = await DailyNotification.getNotificationStatus();
|
||||
mockPlugin.getNotificationStatus.mockResolvedValueOnce(mockErrorStatus);
|
||||
|
||||
const result = await plugin.getNotificationStatus();
|
||||
expect(result).toEqual(mockErrorStatus);
|
||||
});
|
||||
});
|
||||
@@ -112,40 +145,109 @@ describe('DailyNotification Plugin', () => {
|
||||
timezone: 'UTC'
|
||||
};
|
||||
|
||||
await DailyNotification.updateSettings(settings);
|
||||
expect(DailyNotification.updateSettings).toHaveBeenCalledWith(settings);
|
||||
await plugin.updateSettings(settings);
|
||||
expect(mockPlugin.updateSettings).toHaveBeenCalledWith(settings);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBatteryStatus', () => {
|
||||
it('should return battery status', async () => {
|
||||
const result = await DailyNotification.getBatteryStatus();
|
||||
expect(result).toHaveProperty('level');
|
||||
expect(result).toHaveProperty('isCharging');
|
||||
expect(result).toHaveProperty('powerState');
|
||||
expect(result).toHaveProperty('isOptimizationExempt');
|
||||
const mockBatteryStatus = {
|
||||
level: 85,
|
||||
isCharging: false,
|
||||
powerState: 1,
|
||||
isOptimizationExempt: false
|
||||
};
|
||||
|
||||
mockPlugin.getBatteryStatus.mockResolvedValueOnce(mockBatteryStatus);
|
||||
|
||||
const result = await plugin.getBatteryStatus();
|
||||
expect(result).toEqual(mockBatteryStatus);
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestBatteryOptimizationExemption', () => {
|
||||
it('should request battery optimization exemption', async () => {
|
||||
await DailyNotification.requestBatteryOptimizationExemption();
|
||||
expect(DailyNotification.requestBatteryOptimizationExemption).toHaveBeenCalled();
|
||||
await plugin.requestBatteryOptimizationExemption();
|
||||
expect(mockPlugin.requestBatteryOptimizationExemption).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAdaptiveScheduling', () => {
|
||||
it('should set adaptive scheduling', async () => {
|
||||
await DailyNotification.setAdaptiveScheduling({ enabled: true });
|
||||
expect(DailyNotification.setAdaptiveScheduling).toHaveBeenCalledWith({ enabled: true });
|
||||
await plugin.setAdaptiveScheduling({ enabled: true });
|
||||
expect(mockPlugin.setAdaptiveScheduling).toHaveBeenCalledWith({ enabled: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPowerState', () => {
|
||||
it('should return power state', async () => {
|
||||
const result = await DailyNotification.getPowerState();
|
||||
expect(result).toHaveProperty('powerState');
|
||||
expect(result).toHaveProperty('isOptimizationExempt');
|
||||
const mockPowerState = {
|
||||
powerState: 1,
|
||||
isOptimizationExempt: false
|
||||
};
|
||||
|
||||
mockPlugin.getPowerState.mockResolvedValueOnce(mockPowerState);
|
||||
|
||||
const result = await plugin.getPowerState();
|
||||
expect(result).toEqual(mockPowerState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validation', () => {
|
||||
it('should validate URL format', async () => {
|
||||
const invalidOptions = {
|
||||
...mockOptions,
|
||||
url: 'invalid-url'
|
||||
};
|
||||
|
||||
await expect(plugin.scheduleDailyNotification(invalidOptions))
|
||||
.rejects
|
||||
.toThrow('Invalid URL format');
|
||||
});
|
||||
|
||||
it('should validate time format', async () => {
|
||||
const invalidOptions = {
|
||||
...mockOptions,
|
||||
time: '25:00'
|
||||
};
|
||||
|
||||
await expect(plugin.scheduleDailyNotification(invalidOptions))
|
||||
.rejects
|
||||
.toThrow('Invalid time format');
|
||||
});
|
||||
|
||||
it('should validate timezone format', async () => {
|
||||
const invalidOptions = {
|
||||
...mockOptions,
|
||||
timezone: 'Invalid/Timezone'
|
||||
};
|
||||
|
||||
await expect(plugin.scheduleDailyNotification(invalidOptions))
|
||||
.rejects
|
||||
.toThrow('Invalid timezone');
|
||||
});
|
||||
|
||||
it('should validate retry count range', async () => {
|
||||
const invalidOptions = {
|
||||
...mockOptions,
|
||||
retryCount: 15
|
||||
};
|
||||
|
||||
await expect(plugin.scheduleDailyNotification(invalidOptions))
|
||||
.rejects
|
||||
.toThrow('Retry count must be between 0 and 10');
|
||||
});
|
||||
|
||||
it('should validate retry interval range', async () => {
|
||||
const invalidOptions = {
|
||||
...mockOptions,
|
||||
retryInterval: 50
|
||||
};
|
||||
|
||||
await expect(plugin.scheduleDailyNotification(invalidOptions))
|
||||
.rejects
|
||||
.toThrow('Retry interval must be between 100ms and 60s');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -149,7 +149,11 @@ describe('DailyNotification Edge Cases', () => {
|
||||
});
|
||||
|
||||
it('should handle malformed responses', async () => {
|
||||
const malformedResponse = new Response('Invalid JSON');
|
||||
// Mock Response object for test environment
|
||||
const mockResponse = {
|
||||
json: jest.fn().mockImplementation(() => Promise.reject(new Error('Invalid JSON')))
|
||||
};
|
||||
|
||||
mockPlugin.scheduleDailyNotification.mockRejectedValueOnce(
|
||||
new Error('Invalid response format')
|
||||
);
|
||||
@@ -159,11 +163,15 @@ describe('DailyNotification Edge Cases', () => {
|
||||
url: 'https://api.example.com/malformed',
|
||||
time: '09:00',
|
||||
contentHandler: async () => {
|
||||
const data = await malformedResponse.json();
|
||||
return {
|
||||
title: data.title,
|
||||
body: data.content,
|
||||
};
|
||||
try {
|
||||
const data = await mockResponse.json() as any;
|
||||
return {
|
||||
title: data.title,
|
||||
body: data.content,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error('Invalid response format');
|
||||
}
|
||||
},
|
||||
})
|
||||
).rejects.toThrow('Invalid response format');
|
||||
|
||||
Reference in New Issue
Block a user