Skip to content

Commit

Permalink
feat(api): add channel preference type validation (#5603) nv-3827
Browse files Browse the repository at this point in the history
* feat(api): add enable type validation

* feat: add preferences test
  • Loading branch information
djabarovgeorge authored May 20, 2024
1 parent 7d0314e commit d993982
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
5 changes: 5 additions & 0 deletions apps/api/src/app/shared/dtos/channel-preference.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { ApiProperty } from '@nestjs/swagger';
import { ChannelTypeEnum } from '@novu/shared';
import { IsBoolean, IsDefined, IsEnum } from 'class-validator';

export class ChannelPreference {
@ApiProperty({
type: ChannelTypeEnum,
enum: ChannelTypeEnum,
description: 'The type of channel that is enabled or not',
})
@IsDefined()
@IsEnum(ChannelTypeEnum)
type: ChannelTypeEnum;

@ApiProperty({
type: Boolean,
description: 'If channel is enabled or not',
})
@IsBoolean()
@IsDefined()
enabled: boolean;
}
8 changes: 8 additions & 0 deletions apps/api/src/app/subscribers/e2e/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ export async function updatePreference(
);
}

export async function updatePreferences(data: UpdateSubscriberPreferenceRequestDto, session: UserSession) {
return await axiosInstance.patch(`${session.serverUrl}/v1/subscribers/${session.subscriberId}/preferences`, data, {
headers: {
authorization: `ApiKey ${session.apiKey}`,
},
});
}

export async function updateGlobalPreferences(data: UpdateSubscriberGlobalPreferencesRequestDto, session: UserSession) {
return await axiosInstance.patch(`${session.serverUrl}/v1/subscribers/${session.subscriberId}/preferences`, data, {
headers: {
Expand Down
50 changes: 46 additions & 4 deletions apps/api/src/app/subscribers/e2e/update-preference.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import {
StepTypeEnum,
} from '@novu/shared';

import { getNotificationTemplate, updateNotificationTemplate, getPreference, updatePreference } from './helpers';
import {
getNotificationTemplate,
updateNotificationTemplate,
getPreference,
updatePreference,
updatePreferences,
} from './helpers';

describe('Update Subscribers preferences - /subscribers/:subscriberId/preferences/:templateId (PATCH)', function () {
let session: UserSession;
Expand All @@ -31,7 +37,7 @@ describe('Update Subscribers preferences - /subscribers/:subscriberId/preference

try {
const response = await updatePreference(updateDataEmailFalse as any, session, template._id);
expect(response).to.not.be;
expect(response).to.not.be.ok;
} catch (error) {
expect(error.toJSON()).to.have.include({
status: 400,
Expand All @@ -51,7 +57,7 @@ describe('Update Subscribers preferences - /subscribers/:subscriberId/preference

try {
const response = await updatePreference(updateDataEmailFalse as any, session, template._id);
expect(response).to.not.be;
expect(response).to.not.be.ok;
} catch (error) {
expect(error.toJSON()).to.have.include({
status: 400,
Expand All @@ -71,7 +77,7 @@ describe('Update Subscribers preferences - /subscribers/:subscriberId/preference

try {
const response = await updatePreference(updateDataEmailFalse as any, session, '63cc6e0b561e0a609f223e27');
expect(response).to.not.be;
expect(response).to.not.be.ok;
} catch (error) {
const { response } = error;
expect(response.status).to.eql(404);
Expand All @@ -83,6 +89,42 @@ describe('Update Subscribers preferences - /subscribers/:subscriberId/preference
}
});

it('should fail on invalid "enabled" param (string)', async function () {
const updatePreferenceDataEmailFalse = {
channel: {
type: ChannelTypeEnum.EMAIL,
enabled: '',
},
};

try {
const response = await updatePreference(updatePreferenceDataEmailFalse as any, session, template._id);
expect(response).to.not.be.ok;
} catch (error) {
const { response } = error;
expect(response.status).to.eql(400);
expect(response.data.message[0]).to.be.equal('channel.enabled must be a boolean value');
}

const updatePreferencesDataEmailFalse = {
preferences: [
{
type: ChannelTypeEnum.EMAIL,
enabled: '',
},
],
};

try {
const response = await updatePreferences(updatePreferencesDataEmailFalse as any, session);
expect(response).to.not.be.ok;
} catch (error) {
const { response } = error;
expect(response.status).to.eql(400);
expect(response.data.message[0]).to.be.equal('preferences.0.enabled must be a boolean value');
}
});

it('should not do any action or error when sending an empty channels property', async function () {
const initialPreferences = (await getPreference(session)).data.data[0];
expect(initialPreferences.preference.enabled).to.eql(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IsBoolean, IsOptional, ValidateNested } from 'class-validator';
import { ApiExtraModels, ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ChannelPreference } from '../../shared/dtos/channel-preference';
import { Type } from 'class-transformer';

@ApiExtraModels(ChannelPreference)
export class UpdateSubscriberPreferenceRequestDto {
Expand All @@ -9,6 +10,8 @@ export class UpdateSubscriberPreferenceRequestDto {
description: 'The subscriber preferences for every ChannelTypeEnum for the workflow assigned.',
})
@ValidateNested()
@Type(() => ChannelPreference)
@IsOptional()
channel?: ChannelPreference;

@ApiPropertyOptional({
Expand Down

0 comments on commit d993982

Please sign in to comment.