Skip to content

Commit

Permalink
Merge pull request #5235 from novuhq/NV-3262_onboarding_tests
Browse files Browse the repository at this point in the history
[Onboarding] NV-3262 | Cypress tests
  • Loading branch information
LetItRock authored Feb 27, 2024
2 parents 9dfc413 + 934a653 commit c14c1a9
Show file tree
Hide file tree
Showing 15 changed files with 498 additions and 45 deletions.
8 changes: 8 additions & 0 deletions apps/web/cypress/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

type IMountType = import('cypress/react').mount;
type ICreateNotificationTemplateDto = import('@novu/shared').ICreateNotificationTemplateDto;
type FeatureFlagsKeysEnum = import('@novu/shared').FeatureFlagsKeysEnum;

declare namespace Cypress {
interface Chainable {
Expand Down Expand Up @@ -45,6 +46,13 @@ declare namespace Cypress {
*/
inviteUser(email: string): Chainable<Response>;

/**
* Intercept feature flags from LaunchDarkly and mock their response.
*
* Must be in beforeEach (vs before) because intercepts are cleared before each test run.
*/
mockFeatureFlags(featureFlags: Partial<Record<FeatureFlagsKeysEnum, boolean>>): Chainable<void>;

loginWithGitHub(): Chainable<any>;

makeBlueprints(): Chainable<any>;
Expand Down
92 changes: 91 additions & 1 deletion apps/web/cypress/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ import {
EnvironmentService,
} from '@novu/testing';
import { JobsService } from '@novu/testing';
import { ChannelTypeEnum, getPopularTemplateIds, ProvidersIdEnum } from '@novu/shared';
import {
ChannelTypeEnum,
getPopularTemplateIds,
getGetStartedTemplateIds,
ProvidersIdEnum,
TriggerTypeEnum,
StepTypeEnum,
} from '@novu/shared';

const jobsService = new JobsService();

Expand Down Expand Up @@ -198,6 +205,11 @@ module.exports = (on, config) => {
_environmentId: productionEnvironmentId,
_organizationId: organizationId,
});
const productionGetStartedGroup = await notificationGroupRepository.findOne({
name: 'Get started',
_environmentId: productionEnvironmentId,
_organizationId: organizationId,
});

if (!productionGeneralGroup) {
await notificationGroupRepository.create({
Expand All @@ -206,6 +218,13 @@ module.exports = (on, config) => {
_organizationId: organizationId,
});
}
if (!productionGetStartedGroup) {
await notificationGroupRepository.create({
name: 'Get started',
_environmentId: productionEnvironmentId,
_organizationId: organizationId,
});
}

const productionNotificationTemplateService = new NotificationTemplateService(
user._id,
Expand All @@ -214,6 +233,7 @@ module.exports = (on, config) => {
);

const popularTemplateIds = getPopularTemplateIds({ production: false });
const getStartedTemplateIds = getGetStartedTemplateIds({ production: false });

const blueprintTemplates = await productionNotificationTemplateService.getBlueprintTemplates(
organizationId,
Expand All @@ -236,6 +256,76 @@ module.exports = (on, config) => {
name: ':fa-solid fa-lock: Password reset',
isBlueprint: true,
}),
productionNotificationTemplateService.createTemplate({
_id: getStartedTemplateIds[0],
noFeedId: true,
noLayoutId: true,
name: ':fa-solid fa-clock: Delay',
isBlueprint: true,
steps: [
{
type: StepTypeEnum.DELAY,
name: 'Delay',
content: '',
},
],
triggers: [
{
identifier: 'get-started-delay',
type: TriggerTypeEnum.EVENT,
variables: [],
},
],
}),
productionNotificationTemplateService.createTemplate({
_id: getStartedTemplateIds[1],
noFeedId: true,
noLayoutId: true,
name: ':fa-solid fa-layer-group: Digest',
isBlueprint: true,
steps: [
{
type: StepTypeEnum.DIGEST,
name: 'Digest',
content: '',
},
],
triggers: [
{
identifier: 'get-started-digest',
type: TriggerTypeEnum.EVENT,
variables: [],
},
],
}),
productionNotificationTemplateService.createTemplate({
_id: getStartedTemplateIds[2],
noFeedId: true,
noLayoutId: true,
name: ':fa-solid fa-bell: In-App',
isBlueprint: true,
triggers: [
{
identifier: 'get-started-in-app',
type: TriggerTypeEnum.EVENT,
variables: [],
},
],
}),
productionNotificationTemplateService.createTemplate({
_id: getStartedTemplateIds[3],
noFeedId: true,
noLayoutId: true,
name: ':fa-solid fa-earth-americas: Multi-channel',
isBlueprint: true,
triggers: [
{
identifier: 'get-started-multi-channel',
type: TriggerTypeEnum.EVENT,
variables: [],
},
],
}),
]);
}

Expand Down
29 changes: 28 additions & 1 deletion apps/web/cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// load the global Cypress types
/// <reference types="cypress" />

import { MemberRoleEnum, MemberStatusEnum } from '@novu/shared';
import { MemberRoleEnum, MemberStatusEnum, FeatureFlagsKeysEnum } from '@novu/shared';
import 'cypress-wait-until';

Cypress.Commands.add('getByTestId', (selector, ...args) => {
Expand Down Expand Up @@ -167,4 +167,31 @@ Cypress.Commands.add('loginWithGitHub', () => {
);
});

/**
* Intercept feature flags from LaunchDarkly and mock their response.
*
* Must be in beforeEach (vs before) because intercepts are cleared before each test run.
* https://medium.com/@kutnickclose/how-to-use-cypress-with-launchdarkly-897349b7f976
*/
Cypress.Commands.add('mockFeatureFlags', (featureFlags: Partial<Record<FeatureFlagsKeysEnum, boolean>>) => {
// turn off push (EventSource) updates from LaunchDarkly
cy.intercept({ hostname: /.*clientstream.launchdarkly.com/ }, (req) => {
req.reply('data: no streaming feature flag data here\n\n', {
'content-type': 'text/event-stream; charset=utf-8',
});
});

// ignore api calls to events endpoint
cy.intercept({ hostname: /.*events.launchdarkly.com/ }, { body: {} });

// return feature flag values in format expected by launchdarkly client
cy.intercept({ hostname: /.*app.launchdarkly.com/ }, (req) => {
const body = {};
Object.entries(featureFlags).forEach(([featureFlagName, featureFlagValue]) => {
body[featureFlagName] = { value: featureFlagValue };
});
req.reply({ body });
});
});

export {};
Loading

0 comments on commit c14c1a9

Please sign in to comment.