Skip to content

Commit 45c08bf

Browse files
committed
refactor(preferences): simplify merge logic in tests
1 parent db660a6 commit 45c08bf

File tree

2 files changed

+142
-102
lines changed

2 files changed

+142
-102
lines changed

libs/application-generic/src/usecases/get-subscriber-preference/get-subscriber-preference.usecase.ts

+17-13
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,26 @@ export class GetSubscriberPreference {
6363
templatesSize: workflowList.length,
6464
},
6565
);
66+
const workflowIds = workflowList.map((wf) => wf._id);
6667

6768
const [
68-
workflowPreferences,
69-
subscriberWorkflowPreference,
69+
workflowResourcePreferences,
70+
workflowUserPreferences,
71+
subscriberWorkflowPreferences,
7072
subscriberGlobalPreference,
7173
] = await Promise.all([
7274
this.preferencesRepository.find({
73-
_templateId: { $in: workflowList.map((wf) => wf._id) },
75+
_templateId: { $in: workflowIds },
7476
_environmentId: command.environmentId,
75-
type: {
76-
$in: [
77-
PreferencesTypeEnum.WORKFLOW_RESOURCE,
78-
PreferencesTypeEnum.USER_WORKFLOW,
79-
],
80-
},
81-
}),
77+
type: PreferencesTypeEnum.WORKFLOW_RESOURCE,
78+
}) as Promise<PreferenceSet['workflowResourcePreference'][] | null>,
79+
this.preferencesRepository.find({
80+
_templateId: { $in: workflowIds },
81+
_environmentId: command.environmentId,
82+
type: PreferencesTypeEnum.USER_WORKFLOW,
83+
}) as Promise<PreferenceSet['workflowUserPreference'][] | null>,
8284
this.preferencesRepository.find({
85+
_templateId: { $in: workflowIds },
8386
_subscriberId: subscriber._id,
8487
_environmentId: command.environmentId,
8588
type: PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
@@ -92,8 +95,9 @@ export class GetSubscriberPreference {
9295
]);
9396

9497
const allWorkflowPreferences = [
95-
...workflowPreferences,
96-
...subscriberWorkflowPreference,
98+
...workflowResourcePreferences,
99+
...workflowUserPreferences,
100+
...subscriberWorkflowPreferences,
97101
];
98102

99103
const workflowPreferenceSets = allWorkflowPreferences.reduce<
@@ -139,7 +143,7 @@ export class GetSubscriberPreference {
139143
workflowUserPreference: preferences.workflowUserPreference,
140144
subscriberWorkflowPreference:
141145
preferences.subscriberWorkflowPreference,
142-
subscriberGlobalPreference,
146+
...(subscriberGlobalPreference ? { subscriberGlobalPreference } : {}),
143147
});
144148
const merged = MergePreferences.execute(mergeCommand);
145149

libs/application-generic/src/usecases/merge-preferences/merge-preferences.spec.ts

+125-89
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
import {
22
DEFAULT_WORKFLOW_PREFERENCES,
33
PreferencesTypeEnum,
4+
WorkflowPreferences,
45
} from '@novu/shared';
56
import { describe, expect, it } from 'vitest';
67
import { MergePreferencesCommand } from './merge-preferences.command';
78
import { MergePreferences } from './merge-preferences.usecase';
8-
import { PreferenceSet } from '../..';
9+
import { PreferenceSet } from '../get-preferences/get-preferences.usecase';
910

10-
const DEFAULT_WORKFLOW_PREFERENCES_WITH_EMAIL_DISABLED = {
11+
/**
12+
* This test spec is used to test the merge preferences usecase.
13+
* It covers all the possible combinations of preferences types and readOnly flag.
14+
*/
15+
16+
const MOCK_SUBSCRIBER_GLOBAL_PREFERENCE = {
1117
...DEFAULT_WORKFLOW_PREFERENCES,
1218
channels: {
1319
...DEFAULT_WORKFLOW_PREFERENCES.channels,
1420
email: { enabled: false },
21+
in_app: { enabled: true },
22+
},
23+
};
24+
25+
const MOCK_SUBSCRIBER_WORKFLOW_PREFERENCE = {
26+
...DEFAULT_WORKFLOW_PREFERENCES,
27+
channels: {
28+
...DEFAULT_WORKFLOW_PREFERENCES.channels,
29+
email: { enabled: true },
30+
in_app: { enabled: true },
1531
},
1632
};
1733

@@ -20,7 +36,6 @@ type TestCase = {
2036
types: PreferencesTypeEnum[];
2137
expectedType: PreferencesTypeEnum;
2238
readOnly: boolean;
23-
subscriberOverrides?: boolean;
2439
};
2540

2641
const testCases: TestCase[] = [
@@ -144,7 +159,6 @@ const testCases: TestCase[] = [
144159
],
145160
expectedType: PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
146161
readOnly: false,
147-
subscriberOverrides: true,
148162
},
149163
{
150164
comment: 'Subscriber global overrides workflow resource',
@@ -154,7 +168,6 @@ const testCases: TestCase[] = [
154168
],
155169
expectedType: PreferencesTypeEnum.SUBSCRIBER_GLOBAL,
156170
readOnly: false,
157-
subscriberOverrides: true,
158171
},
159172
{
160173
comment: 'Subscriber workflow overrides user workflow',
@@ -165,7 +178,6 @@ const testCases: TestCase[] = [
165178
],
166179
expectedType: PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
167180
readOnly: false,
168-
subscriberOverrides: true,
169181
},
170182
{
171183
comment: 'Subscriber global overrides user workflow',
@@ -176,7 +188,17 @@ const testCases: TestCase[] = [
176188
],
177189
expectedType: PreferencesTypeEnum.SUBSCRIBER_GLOBAL,
178190
readOnly: false,
179-
subscriberOverrides: true,
191+
},
192+
{
193+
comment: 'Subscriber workflow overrides subscriber global',
194+
types: [
195+
PreferencesTypeEnum.WORKFLOW_RESOURCE,
196+
PreferencesTypeEnum.USER_WORKFLOW,
197+
PreferencesTypeEnum.SUBSCRIBER_GLOBAL,
198+
PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
199+
],
200+
expectedType: PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
201+
readOnly: false,
180202
},
181203
// Subscriber overrides with readOnly true behavior
182204
{
@@ -188,7 +210,6 @@ const testCases: TestCase[] = [
188210
],
189211
expectedType: PreferencesTypeEnum.WORKFLOW_RESOURCE,
190212
readOnly: true,
191-
subscriberOverrides: true,
192213
},
193214
{
194215
comment:
@@ -199,7 +220,6 @@ const testCases: TestCase[] = [
199220
],
200221
expectedType: PreferencesTypeEnum.WORKFLOW_RESOURCE,
201222
readOnly: true,
202-
subscriberOverrides: true,
203223
},
204224
{
205225
comment:
@@ -211,7 +231,6 @@ const testCases: TestCase[] = [
211231
],
212232
expectedType: PreferencesTypeEnum.USER_WORKFLOW,
213233
readOnly: true,
214-
subscriberOverrides: true,
215234
},
216235
{
217236
comment:
@@ -223,97 +242,111 @@ const testCases: TestCase[] = [
223242
],
224243
expectedType: PreferencesTypeEnum.USER_WORKFLOW,
225244
readOnly: true,
226-
subscriberOverrides: true,
245+
},
246+
{
247+
comment:
248+
'Subscriber global+workflow cannot override user workflow when readOnly is true',
249+
types: [
250+
PreferencesTypeEnum.WORKFLOW_RESOURCE,
251+
PreferencesTypeEnum.USER_WORKFLOW,
252+
PreferencesTypeEnum.SUBSCRIBER_GLOBAL,
253+
PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
254+
],
255+
expectedType: PreferencesTypeEnum.USER_WORKFLOW,
256+
readOnly: true,
227257
},
228258
];
229259

230260
describe('MergePreferences', () => {
231261
describe('merging readOnly and subscriberOverrides', () => {
232-
testCases.forEach(
233-
({
234-
types,
235-
expectedType,
236-
readOnly,
237-
subscriberOverrides = false,
238-
comment = '',
239-
}) => {
240-
it(`should merge preferences for types: ${types.join(', ')} with readOnly: ${readOnly}${comment ? ` (${comment})` : ''}`, () => {
241-
const preferenceSet = types.reduce((acc, type, index) => {
242-
const preference = {
243-
_id: `${index + 1}`,
244-
_organizationId: '1',
245-
_environmentId: '1',
246-
type,
247-
preferences: {
248-
// default
249-
...DEFAULT_WORKFLOW_PREFERENCES,
250-
// readOnly
251-
all: { ...DEFAULT_WORKFLOW_PREFERENCES.all, readOnly },
252-
// subscriber overrides
253-
...([
254-
PreferencesTypeEnum.SUBSCRIBER_GLOBAL,
255-
PreferencesTypeEnum.SUBSCRIBER_WORKFLOW,
256-
].includes(type) &&
257-
subscriberOverrides &&
258-
// only apply subscriber overrides if readOnly is false
259-
!readOnly
260-
? DEFAULT_WORKFLOW_PREFERENCES_WITH_EMAIL_DISABLED
261-
: {}),
262-
},
263-
};
262+
testCases.forEach(({ types, expectedType, readOnly, comment = '' }) => {
263+
it(`should merge preferences for types: ${types.join(', ')} with readOnly: ${readOnly}${comment ? ` (${comment})` : ''}`, () => {
264+
const preferenceSet = types.reduce((acc, type, index) => {
265+
const preference = {
266+
_id: `${index + 1}`,
267+
_organizationId: '1',
268+
_environmentId: '1',
269+
type,
270+
preferences: {
271+
// default
272+
...DEFAULT_WORKFLOW_PREFERENCES,
273+
// readOnly
274+
all: { ...DEFAULT_WORKFLOW_PREFERENCES.all, readOnly },
275+
// subscriber overrides
276+
...(PreferencesTypeEnum.SUBSCRIBER_GLOBAL === type
277+
? MOCK_SUBSCRIBER_GLOBAL_PREFERENCE
278+
: {}),
279+
...(PreferencesTypeEnum.SUBSCRIBER_WORKFLOW === type
280+
? MOCK_SUBSCRIBER_WORKFLOW_PREFERENCE
281+
: {}),
282+
},
283+
};
264284

265-
switch (type) {
266-
case PreferencesTypeEnum.WORKFLOW_RESOURCE:
267-
acc.workflowResourcePreference = preference;
268-
break;
269-
case PreferencesTypeEnum.USER_WORKFLOW:
270-
acc.workflowUserPreference = preference;
271-
break;
272-
case PreferencesTypeEnum.SUBSCRIBER_GLOBAL:
273-
acc.subscriberGlobalPreference = preference;
274-
break;
275-
case PreferencesTypeEnum.SUBSCRIBER_WORKFLOW:
276-
acc.subscriberWorkflowPreference = preference;
277-
break;
278-
default:
279-
throw new Error(`Unknown preference type: ${type}`);
280-
}
285+
switch (type) {
286+
case PreferencesTypeEnum.WORKFLOW_RESOURCE:
287+
acc.workflowResourcePreference = preference;
288+
break;
289+
case PreferencesTypeEnum.USER_WORKFLOW:
290+
acc.workflowUserPreference = preference;
291+
break;
292+
case PreferencesTypeEnum.SUBSCRIBER_GLOBAL:
293+
acc.subscriberGlobalPreference = preference;
294+
break;
295+
case PreferencesTypeEnum.SUBSCRIBER_WORKFLOW:
296+
acc.subscriberWorkflowPreference = preference;
297+
break;
298+
default:
299+
throw new Error(`Unknown preference type: ${type}`);
300+
}
281301

282-
return acc;
283-
}, {} as PreferenceSet);
302+
return acc;
303+
}, {} as PreferenceSet);
284304

285-
const command = MergePreferencesCommand.create(preferenceSet);
305+
const command = MergePreferencesCommand.create(preferenceSet);
286306

287-
const result = MergePreferences.execute(command);
307+
const result = MergePreferences.execute(command);
288308

289-
const expectedPreferences =
290-
subscriberOverrides && !readOnly
291-
? DEFAULT_WORKFLOW_PREFERENCES_WITH_EMAIL_DISABLED
292-
: {
293-
...DEFAULT_WORKFLOW_PREFERENCES,
294-
all: { ...DEFAULT_WORKFLOW_PREFERENCES.all, readOnly },
295-
};
309+
const hasSubscriberGlobalPreference =
310+
!!preferenceSet.subscriberGlobalPreference;
311+
const hasSubscriberWorkflowPreference =
312+
!!preferenceSet.subscriberWorkflowPreference;
296313

297-
expect(result).toEqual({
298-
preferences: expectedPreferences,
299-
type: expectedType,
300-
source: {
301-
[PreferencesTypeEnum.WORKFLOW_RESOURCE]: null,
302-
[PreferencesTypeEnum.USER_WORKFLOW]: null,
303-
[PreferencesTypeEnum.SUBSCRIBER_GLOBAL]: null,
304-
[PreferencesTypeEnum.SUBSCRIBER_WORKFLOW]: null,
305-
...Object.entries(preferenceSet).reduce((acc, [key, pref]) => {
306-
if (pref) {
307-
acc[pref.type] = pref.preferences;
308-
}
314+
let expectedPreferences: WorkflowPreferences;
309315

310-
return acc;
311-
}, {}),
312-
},
313-
});
316+
if (!readOnly) {
317+
if (hasSubscriberWorkflowPreference) {
318+
expectedPreferences = MOCK_SUBSCRIBER_WORKFLOW_PREFERENCE;
319+
} else if (hasSubscriberGlobalPreference) {
320+
expectedPreferences = MOCK_SUBSCRIBER_GLOBAL_PREFERENCE;
321+
} else {
322+
expectedPreferences = DEFAULT_WORKFLOW_PREFERENCES;
323+
}
324+
} else {
325+
expectedPreferences = {
326+
...DEFAULT_WORKFLOW_PREFERENCES,
327+
all: { ...DEFAULT_WORKFLOW_PREFERENCES.all, readOnly },
328+
};
329+
}
330+
331+
expect(result).toEqual({
332+
preferences: expectedPreferences,
333+
type: expectedType,
334+
source: {
335+
[PreferencesTypeEnum.WORKFLOW_RESOURCE]: null,
336+
[PreferencesTypeEnum.USER_WORKFLOW]: null,
337+
[PreferencesTypeEnum.SUBSCRIBER_GLOBAL]: null,
338+
[PreferencesTypeEnum.SUBSCRIBER_WORKFLOW]: null,
339+
...Object.entries(preferenceSet).reduce((acc, [key, pref]) => {
340+
if (pref) {
341+
acc[pref.type] = pref.preferences;
342+
}
343+
344+
return acc;
345+
}, {}),
346+
},
314347
});
315-
},
316-
);
348+
});
349+
});
317350
});
318351

319352
it('should have test cases for all combinations of PreferencesTypeEnum', () => {
@@ -344,7 +377,10 @@ describe('MergePreferences', () => {
344377

345378
allCombinations.forEach((combination) => {
346379
const combinationKey = combination.sort().join(',');
347-
expect(coveredCombinations).toContain(combinationKey);
380+
expect(
381+
coveredCombinations,
382+
`Combination ${combinationKey} is not covered`,
383+
).toContain(combinationKey);
348384
});
349385
});
350386
});

0 commit comments

Comments
 (0)