@flusys/nestjs-event-manager 6.0.2 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/adapters/event-manager.adapter.spec.js +104 -0
- package/cjs/controllers/event.controller.spec.js +156 -0
- package/cjs/docs/event-manager-swagger.config.spec.js +65 -0
- package/cjs/entities/index.spec.js +18 -0
- package/cjs/modules/event-manager.module.spec.js +146 -0
- package/cjs/services/event-manager-config.service.spec.js +111 -0
- package/cjs/services/event-manager-datasource.provider.spec.js +198 -0
- package/cjs/services/event-manager-helper.service.spec.js +327 -0
- package/cjs/services/event.service.js +9 -4
- package/cjs/services/event.service.spec.js +855 -0
- package/fesm/adapters/event-manager.adapter.spec.js +100 -0
- package/fesm/controllers/event.controller.spec.js +152 -0
- package/fesm/docs/event-manager-swagger.config.spec.js +61 -0
- package/fesm/entities/index.spec.js +14 -0
- package/fesm/modules/event-manager.module.spec.js +142 -0
- package/fesm/services/event-manager-config.service.spec.js +107 -0
- package/fesm/services/event-manager-datasource.provider.spec.js +194 -0
- package/fesm/services/event-manager-helper.service.spec.js +323 -0
- package/fesm/services/event.service.js +9 -4
- package/fesm/services/event.service.spec.js +851 -0
- package/package.json +3 -3
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
6
|
+
const _eventmanageradapter = require("./event-manager.adapter");
|
|
7
|
+
describe('EventManagerAdapter', ()=>{
|
|
8
|
+
let adapter;
|
|
9
|
+
let mockHelper;
|
|
10
|
+
beforeEach(()=>{
|
|
11
|
+
mockHelper = {
|
|
12
|
+
createEvent: jest.fn(),
|
|
13
|
+
updateParticipantStatus: jest.fn(),
|
|
14
|
+
getEventsForUser: jest.fn(),
|
|
15
|
+
getEventById: jest.fn()
|
|
16
|
+
};
|
|
17
|
+
adapter = new _eventmanageradapter.EventManagerAdapter(mockHelper);
|
|
18
|
+
});
|
|
19
|
+
describe('createEvent', ()=>{
|
|
20
|
+
it('delegates to the helper service and returns its result', async ()=>{
|
|
21
|
+
const options = {
|
|
22
|
+
title: 'Sprint Planning',
|
|
23
|
+
eventDate: '2026-04-03',
|
|
24
|
+
startTime: '09:00',
|
|
25
|
+
endTime: '10:00'
|
|
26
|
+
};
|
|
27
|
+
const expected = {
|
|
28
|
+
id: 'event-uuid-1',
|
|
29
|
+
title: 'Sprint Planning',
|
|
30
|
+
description: null,
|
|
31
|
+
eventDate: '2026-04-03',
|
|
32
|
+
startTime: '09:00',
|
|
33
|
+
endTime: '10:00',
|
|
34
|
+
isAllDay: false,
|
|
35
|
+
recurrenceType: 'none',
|
|
36
|
+
recurrenceEndDate: null,
|
|
37
|
+
weekDays: null,
|
|
38
|
+
color: '#3B82F6',
|
|
39
|
+
meetingLink: null,
|
|
40
|
+
isActive: true,
|
|
41
|
+
companyId: null,
|
|
42
|
+
createdAt: new Date(),
|
|
43
|
+
updatedAt: new Date()
|
|
44
|
+
};
|
|
45
|
+
mockHelper.createEvent.mockResolvedValue(expected);
|
|
46
|
+
const result = await adapter.createEvent(options);
|
|
47
|
+
expect(mockHelper.createEvent).toHaveBeenCalledWith(options);
|
|
48
|
+
expect(result).toBe(expected);
|
|
49
|
+
});
|
|
50
|
+
it('propagates errors thrown by the helper service', async ()=>{
|
|
51
|
+
mockHelper.createEvent.mockRejectedValue(new Error('boom'));
|
|
52
|
+
await expect(adapter.createEvent({})).rejects.toThrow('boom');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('updateParticipantStatus', ()=>{
|
|
56
|
+
it('delegates to the helper service', async ()=>{
|
|
57
|
+
mockHelper.updateParticipantStatus.mockResolvedValue(undefined);
|
|
58
|
+
await adapter.updateParticipantStatus('participant-uuid-1', _nestjsshared.ParticipantStatus.ACCEPTED);
|
|
59
|
+
expect(mockHelper.updateParticipantStatus).toHaveBeenCalledWith('participant-uuid-1', _nestjsshared.ParticipantStatus.ACCEPTED);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('getEventsForUser', ()=>{
|
|
63
|
+
it('converts Date range boundaries to YYYY-MM-DD strings before delegating', async ()=>{
|
|
64
|
+
mockHelper.getEventsForUser.mockResolvedValue([]);
|
|
65
|
+
const startDate = new Date('2026-04-01T00:00:00.000Z');
|
|
66
|
+
const endDate = new Date('2026-04-30T23:59:59.000Z');
|
|
67
|
+
await adapter.getEventsForUser('user-uuid-1', startDate, endDate, 'company-uuid-1');
|
|
68
|
+
expect(mockHelper.getEventsForUser).toHaveBeenCalledWith('user-uuid-1', '2026-04-01', '2026-04-30', 'company-uuid-1');
|
|
69
|
+
});
|
|
70
|
+
it('forwards undefined companyId when not supplied', async ()=>{
|
|
71
|
+
mockHelper.getEventsForUser.mockResolvedValue([]);
|
|
72
|
+
const startDate = new Date('2026-04-01T00:00:00.000Z');
|
|
73
|
+
const endDate = new Date('2026-04-02T00:00:00.000Z');
|
|
74
|
+
await adapter.getEventsForUser('user-uuid-1', startDate, endDate);
|
|
75
|
+
expect(mockHelper.getEventsForUser).toHaveBeenCalledWith('user-uuid-1', '2026-04-01', '2026-04-02', undefined);
|
|
76
|
+
});
|
|
77
|
+
it('returns the events resolved by the helper service', async ()=>{
|
|
78
|
+
const events = [
|
|
79
|
+
{
|
|
80
|
+
id: 'event-uuid-1'
|
|
81
|
+
}
|
|
82
|
+
];
|
|
83
|
+
mockHelper.getEventsForUser.mockResolvedValue(events);
|
|
84
|
+
const result = await adapter.getEventsForUser('user-uuid-1', new Date('2026-01-01T00:00:00.000Z'), new Date('2026-01-31T00:00:00.000Z'));
|
|
85
|
+
expect(result).toBe(events);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('getEventById', ()=>{
|
|
89
|
+
it('returns the event resolved by the helper service', async ()=>{
|
|
90
|
+
const event = {
|
|
91
|
+
id: 'event-uuid-1'
|
|
92
|
+
};
|
|
93
|
+
mockHelper.getEventById.mockResolvedValue(event);
|
|
94
|
+
const result = await adapter.getEventById('event-uuid-1');
|
|
95
|
+
expect(mockHelper.getEventById).toHaveBeenCalledWith('event-uuid-1');
|
|
96
|
+
expect(result).toBe(event);
|
|
97
|
+
});
|
|
98
|
+
it('returns null when the helper service finds no matching event', async ()=>{
|
|
99
|
+
mockHelper.getEventById.mockResolvedValue(null);
|
|
100
|
+
const result = await adapter.getEventById('missing-uuid');
|
|
101
|
+
expect(result).toBeNull();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _common = require("@nestjs/common");
|
|
6
|
+
const _enums = require("@flusys/nestjs-shared/enums");
|
|
7
|
+
const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
|
|
8
|
+
const _config = require("../config");
|
|
9
|
+
const _eventcontroller = require("./event.controller");
|
|
10
|
+
function buildCalendarEvent(overrides = {}) {
|
|
11
|
+
return {
|
|
12
|
+
id: 'event-uuid-1',
|
|
13
|
+
title: 'Sprint Planning',
|
|
14
|
+
description: null,
|
|
15
|
+
eventDate: '2026-04-03',
|
|
16
|
+
startTime: '09:00',
|
|
17
|
+
endTime: '10:00',
|
|
18
|
+
isAllDay: false,
|
|
19
|
+
recurrenceType: _enums.RecurrenceType.NONE,
|
|
20
|
+
recurrenceEndDate: null,
|
|
21
|
+
weekDays: null,
|
|
22
|
+
color: '#3B82F6',
|
|
23
|
+
meetingLink: null,
|
|
24
|
+
isActive: true,
|
|
25
|
+
createdAt: new Date('2026-01-01T00:00:00Z'),
|
|
26
|
+
updatedAt: new Date('2026-01-01T00:00:00Z'),
|
|
27
|
+
deletedAt: null,
|
|
28
|
+
createdById: null,
|
|
29
|
+
updatedById: null,
|
|
30
|
+
deletedById: null,
|
|
31
|
+
...overrides
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
describe('EventController', ()=>{
|
|
35
|
+
let controller;
|
|
36
|
+
let mockService;
|
|
37
|
+
const user = (0, _loggedusermock.buildMockUser)();
|
|
38
|
+
beforeEach(()=>{
|
|
39
|
+
mockService = {
|
|
40
|
+
getEventsForCalendarRange: jest.fn(),
|
|
41
|
+
updateParticipantStatus: jest.fn()
|
|
42
|
+
};
|
|
43
|
+
controller = new _eventcontroller.EventController(mockService);
|
|
44
|
+
});
|
|
45
|
+
describe('getCalendarEvents', ()=>{
|
|
46
|
+
it('returns a ListResponseDto shaped payload with meta reflecting the result count', async ()=>{
|
|
47
|
+
const events = [
|
|
48
|
+
buildCalendarEvent(),
|
|
49
|
+
buildCalendarEvent({
|
|
50
|
+
id: 'event-uuid-2'
|
|
51
|
+
})
|
|
52
|
+
];
|
|
53
|
+
mockService.getEventsForCalendarRange.mockResolvedValue(events);
|
|
54
|
+
const dto = {
|
|
55
|
+
startDate: '2026-04-01',
|
|
56
|
+
endDate: '2026-04-30'
|
|
57
|
+
};
|
|
58
|
+
const result = await controller.getCalendarEvents(dto, user);
|
|
59
|
+
expect(mockService.getEventsForCalendarRange).toHaveBeenCalledWith(dto, user);
|
|
60
|
+
expect(result.success).toBe(true);
|
|
61
|
+
expect(result.messageKey).toBe(_config.EVENT_MESSAGES.GET_ALL_SUCCESS);
|
|
62
|
+
expect(result.data).toHaveLength(2);
|
|
63
|
+
expect(result.meta).toEqual({
|
|
64
|
+
total: 2,
|
|
65
|
+
page: 0,
|
|
66
|
+
pageSize: 2,
|
|
67
|
+
count: 2
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
it('returns an empty payload with zeroed meta when no events are found', async ()=>{
|
|
71
|
+
mockService.getEventsForCalendarRange.mockResolvedValue([]);
|
|
72
|
+
const dto = {
|
|
73
|
+
startDate: '2026-04-01',
|
|
74
|
+
endDate: '2026-04-01'
|
|
75
|
+
};
|
|
76
|
+
const result = await controller.getCalendarEvents(dto, user);
|
|
77
|
+
expect(result.data).toEqual([]);
|
|
78
|
+
expect(result.meta).toEqual({
|
|
79
|
+
total: 0,
|
|
80
|
+
page: 0,
|
|
81
|
+
pageSize: 0,
|
|
82
|
+
count: 0
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
it('serializes events through CalendarEventResponseDto, exposing only declared fields', async ()=>{
|
|
86
|
+
const events = [
|
|
87
|
+
buildCalendarEvent({
|
|
88
|
+
originalEventId: 'event-uuid-1',
|
|
89
|
+
isRecurrenceInstance: true,
|
|
90
|
+
// extraneous field that must be stripped by excludeExtraneousValues
|
|
91
|
+
...{
|
|
92
|
+
secretInternalField: 'should-not-leak'
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
];
|
|
96
|
+
mockService.getEventsForCalendarRange.mockResolvedValue(events);
|
|
97
|
+
const dto = {
|
|
98
|
+
startDate: '2026-04-01',
|
|
99
|
+
endDate: '2026-04-30'
|
|
100
|
+
};
|
|
101
|
+
const result = await controller.getCalendarEvents(dto, user);
|
|
102
|
+
const [firstEvent] = result.data ?? [];
|
|
103
|
+
expect(firstEvent).not.toHaveProperty('secretInternalField');
|
|
104
|
+
expect(firstEvent).toMatchObject({
|
|
105
|
+
id: 'event-uuid-1',
|
|
106
|
+
originalEventId: 'event-uuid-1',
|
|
107
|
+
isRecurrenceInstance: true
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
it('propagates errors raised by the service', async ()=>{
|
|
111
|
+
mockService.getEventsForCalendarRange.mockRejectedValue(new Error('db down'));
|
|
112
|
+
const dto = {
|
|
113
|
+
startDate: '2026-04-01',
|
|
114
|
+
endDate: '2026-04-30'
|
|
115
|
+
};
|
|
116
|
+
await expect(controller.getCalendarEvents(dto, user)).rejects.toThrow('db down');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('updateParticipantStatus', ()=>{
|
|
120
|
+
it('returns a SingleResponseDto shaped payload on success', async ()=>{
|
|
121
|
+
const participant = {
|
|
122
|
+
id: 'participant-uuid-1',
|
|
123
|
+
eventId: 'event-uuid-1',
|
|
124
|
+
userId: user.id,
|
|
125
|
+
status: _enums.ParticipantStatus.ACCEPTED,
|
|
126
|
+
isOrganizer: false,
|
|
127
|
+
createdAt: new Date('2026-01-01T00:00:00Z'),
|
|
128
|
+
updatedAt: new Date('2026-01-02T00:00:00Z')
|
|
129
|
+
};
|
|
130
|
+
mockService.updateParticipantStatus.mockResolvedValue(participant);
|
|
131
|
+
const dto = {
|
|
132
|
+
id: 'participant-uuid-1',
|
|
133
|
+
status: _enums.ParticipantStatus.ACCEPTED
|
|
134
|
+
};
|
|
135
|
+
const result = await controller.updateParticipantStatus(dto, user);
|
|
136
|
+
expect(mockService.updateParticipantStatus).toHaveBeenCalledWith(dto, user);
|
|
137
|
+
expect(result.success).toBe(true);
|
|
138
|
+
expect(result.messageKey).toBe(_config.EVENT_PARTICIPANT_MESSAGES.STATUS_UPDATE_SUCCESS);
|
|
139
|
+
expect(result.data).toMatchObject({
|
|
140
|
+
id: 'participant-uuid-1',
|
|
141
|
+
status: _enums.ParticipantStatus.ACCEPTED
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
it('propagates a NotFoundException raised by the service', async ()=>{
|
|
145
|
+
mockService.updateParticipantStatus.mockRejectedValue(new _common.NotFoundException({
|
|
146
|
+
message: 'Event participant not found',
|
|
147
|
+
messageKey: _config.EVENT_PARTICIPANT_MESSAGES.NOT_FOUND
|
|
148
|
+
}));
|
|
149
|
+
const dto = {
|
|
150
|
+
id: 'missing-uuid',
|
|
151
|
+
status: _enums.ParticipantStatus.DECLINED
|
|
152
|
+
};
|
|
153
|
+
await expect(controller.updateParticipantStatus(dto, user)).rejects.toThrow(_common.NotFoundException);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _eventmanagerswaggerconfig = require("./event-manager-swagger.config");
|
|
6
|
+
describe('eventManagerSwaggerConfig', ()=>{
|
|
7
|
+
it('should default to company feature enabled and single-database mode when no config is given', ()=>{
|
|
8
|
+
const config = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)();
|
|
9
|
+
expect(config.title).toBe('Event Manager API');
|
|
10
|
+
expect(config.path).toBe('api/docs/event-manager');
|
|
11
|
+
expect(config.bearerAuth).toBe(true);
|
|
12
|
+
expect(config.excludeSchemaProperties).toBeUndefined();
|
|
13
|
+
expect(config.description).not.toContain('Multi-Tenant Mode');
|
|
14
|
+
});
|
|
15
|
+
it('should exclude companyId schema properties when the company feature is disabled', ()=>{
|
|
16
|
+
const config = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)({
|
|
17
|
+
enableCompanyFeature: false
|
|
18
|
+
});
|
|
19
|
+
expect(config.excludeSchemaProperties).toEqual([
|
|
20
|
+
{
|
|
21
|
+
schemaName: 'EventResponseDto',
|
|
22
|
+
properties: [
|
|
23
|
+
'companyId'
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
schemaName: 'CalendarEventResponseDto',
|
|
28
|
+
properties: [
|
|
29
|
+
'companyId'
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
it('should not exclude any schema properties when the company feature is enabled', ()=>{
|
|
35
|
+
const config = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)({
|
|
36
|
+
enableCompanyFeature: true
|
|
37
|
+
});
|
|
38
|
+
expect(config.excludeSchemaProperties).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
it('should describe company-scoped events and multi-tenant support only when the company feature is enabled', ()=>{
|
|
41
|
+
const withCompany = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)({
|
|
42
|
+
enableCompanyFeature: true
|
|
43
|
+
});
|
|
44
|
+
const withoutCompany = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)({
|
|
45
|
+
enableCompanyFeature: false
|
|
46
|
+
});
|
|
47
|
+
expect(withCompany.description).toContain('Company-scoped events');
|
|
48
|
+
expect(withCompany.description).toContain('Company isolation');
|
|
49
|
+
expect(withCompany.description).toContain('## Multi-Tenant Support');
|
|
50
|
+
expect(withCompany.description).toContain('and multi-tenant capabilities');
|
|
51
|
+
expect(withoutCompany.description).not.toContain('Company-scoped events');
|
|
52
|
+
expect(withoutCompany.description).not.toContain('Company isolation');
|
|
53
|
+
expect(withoutCompany.description).not.toContain('## Multi-Tenant Support');
|
|
54
|
+
});
|
|
55
|
+
it('should mention multi-tenant mode in the description only for multi-tenant database mode', ()=>{
|
|
56
|
+
const multiTenant = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)({
|
|
57
|
+
databaseMode: 'multi-tenant'
|
|
58
|
+
});
|
|
59
|
+
const single = (0, _eventmanagerswaggerconfig.eventManagerSwaggerConfig)({
|
|
60
|
+
databaseMode: 'single'
|
|
61
|
+
});
|
|
62
|
+
expect(multiTenant.description).toContain('Multi-Tenant Mode');
|
|
63
|
+
expect(single.description).not.toContain('Multi-Tenant Mode');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _index = require("./index");
|
|
6
|
+
const _eventparticipantentity = require("./event-participant.entity");
|
|
7
|
+
describe('getEventManagerEntitiesByConfig', ()=>{
|
|
8
|
+
it('returns the core entities when the company feature is disabled', ()=>{
|
|
9
|
+
expect((0, _index.getEventManagerEntitiesByConfig)(false)).toBe(_index.EventManagerCoreEntities);
|
|
10
|
+
});
|
|
11
|
+
it('returns the company-scoped entities when the company feature is enabled', ()=>{
|
|
12
|
+
expect((0, _index.getEventManagerEntitiesByConfig)(true)).toBe(_index.EventManagerCompanyEntities);
|
|
13
|
+
});
|
|
14
|
+
it('EventParticipant is shared between core and company entity sets (event-scoped, not company-scoped)', ()=>{
|
|
15
|
+
expect((0, _index.getEventManagerEntitiesByConfig)(false)).toContain(_eventparticipantentity.EventParticipant);
|
|
16
|
+
expect((0, _index.getEventManagerEntitiesByConfig)(true)).toContain(_eventparticipantentity.EventParticipant);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _interfaces = require("@flusys/nestjs-shared/interfaces");
|
|
6
|
+
const _eventmanagermodule = require("./event-manager.module");
|
|
7
|
+
const _eventmanagerconstants = require("../config/event-manager.constants");
|
|
8
|
+
const _controllers = require("../controllers");
|
|
9
|
+
const _adapters = require("../adapters");
|
|
10
|
+
function _define_property(obj, key, value) {
|
|
11
|
+
if (key in obj) {
|
|
12
|
+
Object.defineProperty(obj, key, {
|
|
13
|
+
value: value,
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true
|
|
17
|
+
});
|
|
18
|
+
} else {
|
|
19
|
+
obj[key] = value;
|
|
20
|
+
}
|
|
21
|
+
return obj;
|
|
22
|
+
}
|
|
23
|
+
function providerTokens(providers) {
|
|
24
|
+
return providers.map((p)=>typeof p === 'function' ? p : p.provide);
|
|
25
|
+
}
|
|
26
|
+
describe('EventManagerModule', ()=>{
|
|
27
|
+
describe('forRoot', ()=>{
|
|
28
|
+
it('should default to a non-global module with the event controller registered', ()=>{
|
|
29
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRoot({});
|
|
30
|
+
expect(dynamicModule.module).toBe(_eventmanagermodule.EventManagerModule);
|
|
31
|
+
expect(dynamicModule.global).toBe(false);
|
|
32
|
+
expect(dynamicModule.controllers).toEqual([
|
|
33
|
+
_controllers.EventController
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
it('should respect global: true', ()=>{
|
|
37
|
+
expect(_eventmanagermodule.EventManagerModule.forRoot({
|
|
38
|
+
global: true
|
|
39
|
+
}).global).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it('should register no controllers when includeController is false', ()=>{
|
|
42
|
+
expect(_eventmanagermodule.EventManagerModule.forRoot({
|
|
43
|
+
includeController: false
|
|
44
|
+
}).controllers).toEqual([]);
|
|
45
|
+
});
|
|
46
|
+
it('should register the EVENT_MANAGER_ADAPTER provider backed by EventManagerAdapter', ()=>{
|
|
47
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRoot({});
|
|
48
|
+
const adapterProvider = dynamicModule.providers.find((p)=>p.provide === _interfaces.EVENT_MANAGER_ADAPTER);
|
|
49
|
+
expect(adapterProvider.useClass).toBe(_adapters.EventManagerAdapter);
|
|
50
|
+
});
|
|
51
|
+
it('should export EVENT_MANAGER_ADAPTER alongside the base services', ()=>{
|
|
52
|
+
expect(_eventmanagermodule.EventManagerModule.forRoot({}).exports).toContain(_interfaces.EVENT_MANAGER_ADAPTER);
|
|
53
|
+
});
|
|
54
|
+
it('should register an EVENT_MANAGER_MODULE_OPTIONS provider carrying the given options', ()=>{
|
|
55
|
+
const options = {
|
|
56
|
+
bootstrapAppConfig: {
|
|
57
|
+
enableCompanyFeature: true
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRoot(options);
|
|
61
|
+
const provider = dynamicModule.providers.find((p)=>p.provide === _eventmanagerconstants.EVENT_MANAGER_MODULE_OPTIONS);
|
|
62
|
+
expect(provider.useValue).toBe(options);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('forRootAsync', ()=>{
|
|
66
|
+
it('should forward external imports alongside CacheModule/UtilsModule', ()=>{
|
|
67
|
+
let FakeImportedModule = class FakeImportedModule {
|
|
68
|
+
};
|
|
69
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRootAsync({
|
|
70
|
+
imports: [
|
|
71
|
+
FakeImportedModule
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
expect(dynamicModule.imports).toEqual(expect.arrayContaining([
|
|
75
|
+
FakeImportedModule
|
|
76
|
+
]));
|
|
77
|
+
});
|
|
78
|
+
it('should still wire the adapter provider when using async registration', ()=>{
|
|
79
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRootAsync({
|
|
80
|
+
useFactory: jest.fn()
|
|
81
|
+
});
|
|
82
|
+
const adapterProvider = dynamicModule.providers.find((p)=>p.provide === _interfaces.EVENT_MANAGER_ADAPTER);
|
|
83
|
+
expect(adapterProvider.useClass).toBe(_adapters.EventManagerAdapter);
|
|
84
|
+
});
|
|
85
|
+
it('useFactory: builds an EVENT_MANAGER_MODULE_OPTIONS provider merging resolved config', async ()=>{
|
|
86
|
+
const useFactory = jest.fn().mockResolvedValue({
|
|
87
|
+
foo: 'bar'
|
|
88
|
+
});
|
|
89
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRootAsync({
|
|
90
|
+
useFactory,
|
|
91
|
+
inject: [
|
|
92
|
+
'SOME_TOKEN'
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
const provider = dynamicModule.providers.find((p)=>p.provide === _eventmanagerconstants.EVENT_MANAGER_MODULE_OPTIONS);
|
|
96
|
+
expect(provider.inject).toEqual([
|
|
97
|
+
'SOME_TOKEN'
|
|
98
|
+
]);
|
|
99
|
+
const resolved = await provider.useFactory('injected');
|
|
100
|
+
expect(useFactory).toHaveBeenCalledWith('injected');
|
|
101
|
+
expect(resolved.config).toEqual({
|
|
102
|
+
foo: 'bar'
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
it('useClass: registers both the class provider and an options provider calling createEventManagerOptions()', async ()=>{
|
|
106
|
+
let MyOptionsFactory = class MyOptionsFactory {
|
|
107
|
+
constructor(){
|
|
108
|
+
_define_property(this, "createEventManagerOptions", jest.fn().mockResolvedValue({
|
|
109
|
+
foo: 'from-class'
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRootAsync({
|
|
114
|
+
useClass: MyOptionsFactory
|
|
115
|
+
});
|
|
116
|
+
const classProvider = dynamicModule.providers.find((p)=>p.provide === MyOptionsFactory);
|
|
117
|
+
expect(classProvider.useClass).toBe(MyOptionsFactory);
|
|
118
|
+
const optionsProvider = dynamicModule.providers.find((p)=>p.provide === _eventmanagerconstants.EVENT_MANAGER_MODULE_OPTIONS);
|
|
119
|
+
const instance = new MyOptionsFactory();
|
|
120
|
+
const resolved = await optionsProvider.useFactory(instance);
|
|
121
|
+
expect(instance.createEventManagerOptions).toHaveBeenCalled();
|
|
122
|
+
expect(resolved.config).toEqual({
|
|
123
|
+
foo: 'from-class'
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
it('useExisting: registers a single options provider without a duplicate class registration', ()=>{
|
|
127
|
+
let MyOptionsFactory = class MyOptionsFactory {
|
|
128
|
+
constructor(){
|
|
129
|
+
_define_property(this, "createEventManagerOptions", jest.fn());
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRootAsync({
|
|
133
|
+
useExisting: MyOptionsFactory
|
|
134
|
+
});
|
|
135
|
+
expect(dynamicModule.providers.filter((p)=>p.provide === MyOptionsFactory)).toHaveLength(0);
|
|
136
|
+
const optionsProvider = dynamicModule.providers.find((p)=>p.provide === _eventmanagerconstants.EVENT_MANAGER_MODULE_OPTIONS);
|
|
137
|
+
expect(optionsProvider.inject).toEqual([
|
|
138
|
+
MyOptionsFactory
|
|
139
|
+
]);
|
|
140
|
+
});
|
|
141
|
+
it('should register no EVENT_MANAGER_MODULE_OPTIONS provider when neither useFactory, useClass, nor useExisting is given', ()=>{
|
|
142
|
+
const dynamicModule = _eventmanagermodule.EventManagerModule.forRootAsync({});
|
|
143
|
+
expect(providerTokens(dynamicModule.providers)).not.toContain(_eventmanagerconstants.EVENT_MANAGER_MODULE_OPTIONS);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _eventmanagerconfigservice = require("./event-manager-config.service");
|
|
6
|
+
function buildOptions(overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
bootstrapAppConfig: undefined,
|
|
9
|
+
config: undefined,
|
|
10
|
+
...overrides
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
describe('EventManagerConfigService', ()=>{
|
|
14
|
+
describe('isCompanyFeatureEnabled', ()=>{
|
|
15
|
+
it('returns true when bootstrap config enables the company feature', ()=>{
|
|
16
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
17
|
+
bootstrapAppConfig: {
|
|
18
|
+
enableCompanyFeature: true
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
expect(service.isCompanyFeatureEnabled()).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it('returns false when bootstrap config disables the company feature', ()=>{
|
|
24
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
25
|
+
bootstrapAppConfig: {
|
|
26
|
+
enableCompanyFeature: false
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
expect(service.isCompanyFeatureEnabled()).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
it('defaults to false when bootstrapAppConfig is missing', ()=>{
|
|
32
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions());
|
|
33
|
+
expect(service.isCompanyFeatureEnabled()).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('getDatabaseMode', ()=>{
|
|
37
|
+
it('returns the configured database mode', ()=>{
|
|
38
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
39
|
+
bootstrapAppConfig: {
|
|
40
|
+
databaseMode: 'multi-tenant'
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
expect(service.getDatabaseMode()).toBe('multi-tenant');
|
|
44
|
+
});
|
|
45
|
+
it('defaults to "single" when not configured', ()=>{
|
|
46
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions());
|
|
47
|
+
expect(service.getDatabaseMode()).toBe('single');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('isMultiTenant', ()=>{
|
|
51
|
+
it('returns true when database mode is multi-tenant', ()=>{
|
|
52
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
53
|
+
bootstrapAppConfig: {
|
|
54
|
+
databaseMode: 'multi-tenant'
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
expect(service.isMultiTenant()).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
it('returns false when database mode is single', ()=>{
|
|
60
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
61
|
+
bootstrapAppConfig: {
|
|
62
|
+
databaseMode: 'single'
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
expect(service.isMultiTenant()).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
it('returns false when database mode is not configured', ()=>{
|
|
68
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions());
|
|
69
|
+
expect(service.isMultiTenant()).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('getDefaultColor', ()=>{
|
|
73
|
+
it('returns the configured default color', ()=>{
|
|
74
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
75
|
+
config: {
|
|
76
|
+
defaultColor: '#FF0000'
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
expect(service.getDefaultColor()).toBe('#FF0000');
|
|
80
|
+
});
|
|
81
|
+
it('falls back to the built-in default color', ()=>{
|
|
82
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions());
|
|
83
|
+
expect(service.getDefaultColor()).toBe('#3B82F6');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('getMaxRecurrenceOccurrences', ()=>{
|
|
87
|
+
it('returns the configured max occurrences', ()=>{
|
|
88
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions({
|
|
89
|
+
config: {
|
|
90
|
+
maxRecurrenceOccurrences: 50
|
|
91
|
+
}
|
|
92
|
+
}));
|
|
93
|
+
expect(service.getMaxRecurrenceOccurrences()).toBe(50);
|
|
94
|
+
});
|
|
95
|
+
it('falls back to the built-in default of 365', ()=>{
|
|
96
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(buildOptions());
|
|
97
|
+
expect(service.getMaxRecurrenceOccurrences()).toBe(365);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe('getOptions', ()=>{
|
|
101
|
+
it('returns the raw options object as-is', ()=>{
|
|
102
|
+
const options = buildOptions({
|
|
103
|
+
config: {
|
|
104
|
+
defaultColor: '#ABCDEF'
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
const service = new _eventmanagerconfigservice.EventManagerConfigService(options);
|
|
108
|
+
expect(service.getOptions()).toBe(options);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|