Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 81 additions & 85 deletions redisinsight/api/src/__mocks__/custom-tutorial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,116 +48,106 @@ export const mockCustomTutorialMacosxAdmZipEntry = {
} as AdmZip.IZipEntry;

export const mockUploadCustomTutorialDto = Object.assign(new UploadCustomTutorialDto(), {
name: mockCustomTutorial.name,
file: mockCustomTutorialZipFile,
});

export const mockUploadCustomTutorialExternalLinkDto = Object.assign(new UploadCustomTutorialDto(), {
name: mockCustomTutorial.name,
link: mockCustomTutorialsHttpLink,
});

export const mockCustomTutorialManifestManifestJson = [
{
type: 'group',
id: 'ct-folder-1',
label: 'ct-folder-1',
// args: {
// withBorder: true,
// initialIsOpen: true,
// },
children: [
{
type: CustomTutorialManifestType.Group,
id: 'ct-sub-folder-1',
label: 'ct-sub-folder-1',
// args: {
// initialIsOpen: false,
// },
children: [
{
type: CustomTutorialManifestType.InternalLink,
id: 'introduction',
label: 'introduction',
args: {
path: '/ct-folder-1/ct-sub-folder-1/introduction.md',
export const mockCustomTutorialManifestJson = {
type: CustomTutorialManifestType.Group,
id: mockCustomTutorialId,
label: mockCustomTutorial.name,
children: [
{
type: 'group',
id: 'ct-folder-1',
label: 'ct-folder-1',
children: [
{
type: CustomTutorialManifestType.Group,
id: 'ct-sub-folder-1',
label: 'ct-sub-folder-1',
children: [
{
type: CustomTutorialManifestType.InternalLink,
id: 'introduction',
label: 'introduction',
args: {
path: '/ct-folder-1/ct-sub-folder-1/introduction.md',
},
},
},
{
type: CustomTutorialManifestType.InternalLink,
id: 'working-with-hashes',
label: 'working-with-hashes',
args: {
path: '/ct-folder-1/ct-sub-folder-1/working-with-hashes.md',
{
type: CustomTutorialManifestType.InternalLink,
id: 'working-with-hashes',
label: 'working-with-hashes',
args: {
path: '/ct-folder-1/ct-sub-folder-1/working-with-hashes.md',
},
},
},
],
},
{
type: CustomTutorialManifestType.Group,
id: 'ct-sub-folder-2',
label: 'ct-sub-folder-2',
// args: {
// withBorder: true,
// initialIsOpen: false,
// },
children: [
{
type: CustomTutorialManifestType.InternalLink,
id: 'introduction',
label: 'introduction',
args: {
path: '/ct-folder-1/ct-sub-folder-2/introduction.md',
],
},
{
type: CustomTutorialManifestType.Group,
id: 'ct-sub-folder-2',
label: 'ct-sub-folder-2',
children: [
{
type: CustomTutorialManifestType.InternalLink,
id: 'introduction',
label: 'introduction',
args: {
path: '/ct-folder-1/ct-sub-folder-2/introduction.md',
},
},
},
{
type: CustomTutorialManifestType.InternalLink,
id: 'working-with-graphs',
label: 'working-with-graphs',
args: {
path: '/ct-folder-1/ct-sub-folder-2/working-with-graphs.md',
{
type: CustomTutorialManifestType.InternalLink,
id: 'working-with-graphs',
label: 'working-with-graphs',
args: {
path: '/ct-folder-1/ct-sub-folder-2/working-with-graphs.md',
},
},
},
],
},
],
},
];
],
},
],
},
],
};

export const mockCustomTutorialManifestManifest = {
export const mockCustomTutorialManifest = {
...mockCustomTutorialManifestJson,
type: CustomTutorialManifestType.Group,
id: mockCustomTutorialId,
label: mockCustomTutorial.name,
_actions: mockCustomTutorial.actions,
_path: mockCustomTutorial.path,
children: mockCustomTutorialManifestManifestJson,
};

export const mockCustomTutorialManifestManifest2 = {
export const mockCustomTutorialManifest2 = {
type: CustomTutorialManifestType.Group,
id: mockCustomTutorialId2,
label: mockCustomTutorial2.name,
_actions: mockCustomTutorial2.actions,
_path: mockCustomTutorial2.path,
children: mockCustomTutorialManifestManifestJson,
children: [mockCustomTutorialManifestJson],
};

export const globalCustomTutorialManifest = [
{
type: CustomTutorialManifestType.Group,
id: 'custom-tutorials',
label: 'MY TUTORIALS',
_actions: [CustomTutorialActions.CREATE],
args: {
withBorder: true,
initialIsOpen: true,
},
children: [
mockCustomTutorialManifestManifest,
mockCustomTutorialManifestManifest2,
],
export const globalCustomTutorialManifest = {
type: CustomTutorialManifestType.Group,
id: 'custom-tutorials',
label: 'MY TUTORIALS',
_actions: [CustomTutorialActions.CREATE],
args: {
withBorder: true,
initialIsOpen: true,
},
];
children: [
mockCustomTutorialManifest,
mockCustomTutorialManifest2,
],
};

export const mockCustomTutorialFsProvider = jest.fn(() => ({
unzipFromMemoryStoredFile: jest.fn().mockResolvedValue(mockCustomTutorialTmpPath),
Expand All @@ -168,8 +158,9 @@ export const mockCustomTutorialFsProvider = jest.fn(() => ({
}));

export const mockCustomTutorialManifestProvider = jest.fn(() => ({
getManifestJson: jest.fn().mockResolvedValue(mockCustomTutorialManifestManifestJson),
generateTutorialManifest: jest.fn().mockResolvedValue(mockCustomTutorialManifestManifest),
getOriginalManifestJson: jest.fn().mockResolvedValue(mockCustomTutorialManifestJson),
getManifestJson: jest.fn().mockResolvedValue(mockCustomTutorialManifestJson),
generateTutorialManifest: jest.fn().mockResolvedValue(mockCustomTutorialManifest),
}));

export const mockCustomTutorialRepository = jest.fn(() => ({
Expand All @@ -181,3 +172,8 @@ export const mockCustomTutorialRepository = jest.fn(() => ({
mockCustomTutorial2,
]),
}));

export const mockCustomTutorialAnalytics = jest.fn(() => ({
sendImportSucceeded: jest.fn(),
sendImportFailed: jest.fn(),
}));
3 changes: 3 additions & 0 deletions redisinsight/api/src/constants/telemetry-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export enum TelemetryEvents {
WorkbenchCommandExecuted = 'WORKBENCH_COMMAND_EXECUTED',
WorkbenchCommandErrorReceived = 'WORKBENCH_COMMAND_ERROR_RECEIVED',
WorkbenchCommandDeleted = 'WORKBENCH_COMMAND_DELETE_COMMAND',
// Custom tutorials
WorkbenchEnablementAreaImportSucceeded = 'WORKBENCH_ENABLEMENT_AREA_IMPORT_SUCCEEDED',
WorkbenchEnablementAreaImportFailed = 'WORKBENCH_ENABLEMENT_AREA_IMPORT_FAILED',

// Profiler
ProfilerLogDownloaded = 'PROFILER_LOG_DOWNLOADED',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Test, TestingModule } from '@nestjs/testing';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { TelemetryEvents } from 'src/constants';
import { CustomTutorialAnalytics } from 'src/modules/custom-tutorial/custom-tutorial.analytics';
import { BadRequestException } from '@nestjs/common';

describe('CustomTutorialAnalytics', () => {
let service: CustomTutorialAnalytics;
let sendEventSpy;

beforeEach(async () => {
jest.clearAllMocks();

const module: TestingModule = await Test.createTestingModule({
providers: [
EventEmitter2,
CustomTutorialAnalytics,
],
}).compile();

service = await module.get(CustomTutorialAnalytics);
sendEventSpy = jest.spyOn(service as any, 'sendEvent');
});

describe('sendImportSucceeded', () => {
it('should emit succeed event with manifest "yes"', () => {
service.sendImportSucceeded({ manifest: true });

expect(sendEventSpy).toHaveBeenNthCalledWith(
1,
TelemetryEvents.WorkbenchEnablementAreaImportSucceeded,
{
manifest: 'yes',
},
);
});
it('should emit succeed event with manifest "no"', () => {
service.sendImportSucceeded({ manifest: false });

expect(sendEventSpy).toHaveBeenNthCalledWith(
1,
TelemetryEvents.WorkbenchEnablementAreaImportSucceeded,
{
manifest: 'no',
},
);
});
});

describe('sendImportFailed', () => {
it('should emit 1 event with "Error" cause', () => {
service.sendImportFailed(new Error());

expect(sendEventSpy).toHaveBeenNthCalledWith(
1,
TelemetryEvents.WorkbenchEnablementAreaImportFailed,
{
error: 'Error',
},
);
});
it('should emit 1 event with "BadRequestException" cause', () => {
service.sendImportFailed(new BadRequestException());

expect(sendEventSpy).toHaveBeenNthCalledWith(
1,
TelemetryEvents.WorkbenchEnablementAreaImportFailed,
{
error: 'BadRequestException',
},
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Injectable } from '@nestjs/common';
import { TelemetryBaseService } from 'src/modules/analytics/telemetry.base.service';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { TelemetryEvents } from 'src/constants';

@Injectable()
export class CustomTutorialAnalytics extends TelemetryBaseService {
constructor(protected eventEmitter: EventEmitter2) {
super(eventEmitter);
}

sendImportSucceeded(data: any = {}): void {
this.sendEvent(
TelemetryEvents.WorkbenchEnablementAreaImportSucceeded,
{
manifest: data?.manifest ? 'yes' : 'no',
},
);
}

sendImportFailed(e: Error): void {
this.sendEvent(
TelemetryEvents.WorkbenchEnablementAreaImportFailed,
{
error: e?.constructor?.name || 'UncaughtError',
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export class CustomTutorialController {
},
],
})
async getGlobalManifest(): Promise<RootCustomTutorialManifest[]> {
return this.service.getGlobalManifest();
async getGlobalManifest(): Promise<RootCustomTutorialManifest> {
return await this.service.getGlobalManifest();
}

@Delete('/:id')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CustomTutorialRepository } from 'src/modules/custom-tutorial/repositori
import {
LocalCustomTutorialRepository,
} from 'src/modules/custom-tutorial/repositories/local.custom-tutorial.repository';
import { CustomTutorialAnalytics } from 'src/modules/custom-tutorial/custom-tutorial.analytics';

@Module({})
export class CustomTutorialModule {
Expand All @@ -22,6 +23,7 @@ export class CustomTutorialModule {
CustomTutorialService,
CustomTutorialFsProvider,
CustomTutorialManifestProvider,
CustomTutorialAnalytics,
{
provide: CustomTutorialRepository,
useClass: repository,
Expand Down
Loading