@ideal-photography/shared
Version:
Shared MongoDB and utility logic for Ideal Photography PWAs: users, products, services, bookings, orders/cart, galleries, reviews, notifications, campaigns, settings, audit logs, minimart items/orders, and push notification subscriptions.
173 lines (140 loc) • 5.89 kB
JavaScript
import { jest } from '@jest/globals';
import { emitAlert } from '../index.js';
import AlertBus from '../AlertBus.js';
// Mock NotificationService
const mockNotificationService = {
createAndSend: jest.fn().mockResolvedValue({
_id: 'notif123',
title: 'Welcome to IDEAS MEDIA COMPANY'
})
};
// Mock the module before importing
jest.unstable_mockModule('../../services/NotificationService.js', () => ({
default: mockNotificationService
}));
// Mock models
const mockModels = {
Notification: {
create: jest.fn().mockResolvedValue({
_id: 'notif123',
title: 'Test Notification',
status: 'sent',
sentAt: new Date()
})
},
User: {
find: jest.fn().mockResolvedValue([])
}
};
jest.unstable_mockModule('../../mongoDB/index.js', () => ({
models: mockModels
}));
describe('Alert Flow: emitAlert → handlers → NotificationService', () => {
beforeEach(() => {
jest.clearAllMocks();
// Clear any existing listeners
AlertBus.removeAllListeners('alert');
AlertBus.removeAllListeners('user.registered');
AlertBus.removeAllListeners('booking.created');
});
test('emitAlert enqueues alert to AlertBus', (done) => {
const testPayload = { userId: '123', userName: 'Test User' };
AlertBus.once('alert', ({ trigger, payload }) => {
expect(trigger).toBe('user.registered');
expect(payload).toEqual(testPayload);
done();
});
emitAlert('user.registered', testPayload);
});
test('emitAlert throws error for invalid trigger', () => {
expect(() => emitAlert('', {})).toThrow('trigger must be non-empty string');
expect(() => emitAlert(null, {})).toThrow('trigger must be non-empty string');
});
test('handler receives payload and generates alertMeta', async () => {
const mockUser = {
_id: 'user123',
name: 'John Doe',
email: 'john@example.com'
};
// Import and test auth handler directly
const { registered } = await import('../../alerts/handlers/auth.js');
const alertMeta = registered({ user: mockUser });
expect(alertMeta).toEqual(
expect.objectContaining({
title: expect.stringContaining('Welcome'),
recipients: { users: [mockUser._id] },
channels: expect.objectContaining({ email: true }),
emailTemplate: 'welcome',
emailData: expect.objectContaining({ name: mockUser.name, email: mockUser.email })
})
);
});
test('booking.created handler generates correct alertMeta', async () => {
const mockBooking = {
_id: 'booking123',
shortId: 'BK001',
date: new Date('2025-10-15'),
time: '14:00'
};
const mockUser = {
_id: 'user123',
name: 'Jane Smith'
};
const mockProduct = {
name: 'Studio Portrait Session'
};
// Import and test booking handler directly
const { created } = await import('../../alerts/handlers/bookings.js');
const alertMeta = created({ booking: mockBooking, user: mockUser, product: mockProduct });
expect(alertMeta).toEqual(
expect.objectContaining({
title: 'Booking received',
message: expect.stringContaining('BK001'),
type: 'booking',
recipients: { users: [mockUser._id] },
channels: expect.objectContaining({ email: true }),
emailTemplate: 'booking-confirmation'
})
);
});
test('AlertBus processes queue in order', (done) => {
const results = [];
AlertBus.on('alert', ({ trigger }) => {
results.push(trigger);
});
emitAlert('user.registered', {});
emitAlert('booking.created', {});
emitAlert('booking.reminder.6h', {});
setTimeout(() => {
expect(results).toEqual(['user.registered', 'booking.created', 'booking.reminder.6h']);
done();
}, 100);
});
test('channel overrides in opts are applied', async () => {
const mockUser = { _id: 'user123', name: 'Test' };
// Test that opts override default channels
const { registered } = await import('../../alerts/handlers/auth.js');
const alertMeta = registered({ user: mockUser });
// Default should have email: true
expect(alertMeta.channels.email).toBe(true);
expect(alertMeta.channels.push).toBe(true);
// Test that opts would override these (this is tested in NotificationService)
const overriddenChannels = { ...alertMeta.channels, email: false, push: false };
expect(overriddenChannels).toEqual({
inApp: true,
email: false,
push: false
});
});
test('priority override in opts is applied', async () => {
const mockUser = { _id: 'user123', name: 'Test' };
// Test that handlers generate default priority
const { registered } = await import('../../alerts/handlers/auth.js');
const alertMeta = registered({ user: mockUser });
// Handler doesn't set priority, so it should be undefined (defaults to 'normal' in model)
expect(alertMeta.priority).toBeUndefined();
// Test that opts would override this (this is tested in NotificationService)
const overriddenPriority = { ...alertMeta, priority: 'urgent' };
expect(overriddenPriority.priority).toBe('urgent');
});
});