Skip to content

Commit

Permalink
Write tests for new telemetry files
Browse files Browse the repository at this point in the history
  • Loading branch information
cee-chen committed Apr 28, 2020
1 parent 757fe71 commit c89ab55
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { mount } from 'enzyme';

import { sendTelemetry, SendAppSearchTelemetry } from './';
import { mountWithKibanaContext } from '../../test_utils/helpers';

describe('Shared Telemetry Helpers', () => {
describe('sendTelemetry', () => {
it('successfully calls the server-side telemetry endpoint', () => {
const httpMock = { put: jest.fn(() => Promise.resolve()) };

sendTelemetry({
http: httpMock,
product: 'enterprise_search',
action: 'viewed',
metric: 'setup_guide',
});

expect(httpMock.put).toHaveBeenCalledWith('/api/enterprise_search/telemetry', {
headers: { 'content-type': 'application/json' },
body: '{"action":"viewed","metric":"setup_guide"}',
});
});

it('throws an error if the telemetry endpoint fails', () => {
const httpMock = { put: jest.fn(() => Promise.reject()) };

expect(sendTelemetry({ http: httpMock })).rejects.toThrow('Unable to send telemetry');
});
});

describe('React component helpers', () => {
const httpMock = { put: jest.fn(() => Promise.resolve()) };

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

it('SendAppSearchTelemetry component', () => {
const wrapper = mountWithKibanaContext(
<SendAppSearchTelemetry action="clicked" metric="button" />,
{ http: httpMock }
);

expect(httpMock.put).toHaveBeenCalledWith('/api/app_search/telemetry', {
headers: { 'content-type': 'application/json' },
body: '{"action":"clicked","metric":"button"}',
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { savedObjectsRepositoryMock } from 'src/core/server/mocks';

import { registerTelemetryUsageCollector, incrementUICounter } from './telemetry';

/**
* Since these route callbacks are so thin, these serve simply as integration tests
* to ensure they're wired up to the lib functions correctly. Business logic is tested
* more thoroughly in the lib/telemetry tests.
*/
describe('App Search Telemetry Usage Collector', () => {
const makeUsageCollectorStub = jest.fn();
const registerStub = jest.fn();

const savedObjectsRepoStub = {
get: () => ({
attributes: {
'ui_viewed.setup_guide': 10,
'ui_viewed.engines_overview': 20,
'ui_error.cannot_connect': 3,
'ui_error.no_as_account': 4,
'ui_clicked.header_launch_button': 50,
'ui_clicked.engine_table_link': 60,
},
}),
incrementCounter: jest.fn(),
};
const dependencies = {
usageCollection: {
makeUsageCollector: makeUsageCollectorStub,
registerCollector: registerStub,
},
savedObjects: {
createInternalRepository: jest.fn(() => savedObjectsRepoStub),
},
};

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

describe('registerTelemetryUsageCollector', () => {
it('should make and register the usage collector', () => {
registerTelemetryUsageCollector(dependencies);

expect(registerStub).toHaveBeenCalledTimes(1);
expect(makeUsageCollectorStub).toHaveBeenCalledTimes(1);
expect(makeUsageCollectorStub.mock.calls[0][0].type).toBe('app_search_kibana_telemetry');
});
});

describe('fetchTelemetryMetrics', () => {
it('should return existing saved objects data', async () => {
registerTelemetryUsageCollector(dependencies);
const savedObjectsCounts = await makeUsageCollectorStub.mock.calls[0][0].fetch();

expect(savedObjectsCounts).toEqual({
ui_viewed: {
setup_guide: 10,
engines_overview: 20,
},
ui_error: {
cannot_connect: 3,
no_as_account: 4,
},
ui_clicked: {
header_launch_button: 50,
engine_table_link: 60,
},
});
});

it('should not error & should return a default telemetry object if no saved data exists', async () => {
registerTelemetryUsageCollector({
...dependencies,
savedObjects: { createInternalRepository: () => ({}) },
});
const savedObjectsCounts = await makeUsageCollectorStub.mock.calls[0][0].fetch();

expect(savedObjectsCounts).toEqual({
ui_viewed: {
setup_guide: 0,
engines_overview: 0,
},
ui_error: {
cannot_connect: 0,
no_as_account: 0,
},
ui_clicked: {
header_launch_button: 0,
engine_table_link: 0,
},
});
});
});

describe('incrementUICounter', () => {
it('should increment the saved objects internal repository', async () => {
const { savedObjects } = dependencies;

const response = await incrementUICounter({
savedObjects,
uiAction: 'ui_clicked',
metric: 'button',
});

expect(savedObjectsRepoStub.incrementCounter).toHaveBeenCalledWith(
'app_search_kibana_telemetry',
'app_search_kibana_telemetry',
'ui_clicked.button'
);
expect(response).toEqual({ success: true });
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { mockRouter, RouterMock } from 'src/core/server/http/router/router.mock';
import { savedObjectsServiceMock } from 'src/core/server/saved_objects/saved_objects_service.mock';
import { httpServerMock } from 'src/core/server/http/http_server.mocks';

import { registerTelemetryRoute } from './telemetry';

jest.mock('../../collectors/app_search/telemetry', () => ({
incrementUICounter: jest.fn(),
}));
import { incrementUICounter } from '../../collectors/app_search/telemetry';

describe('App Search Telemetry API', () => {
let router: RouterMock;
const mockResponseFactory = httpServerMock.createResponseFactory();

beforeEach(() => {
jest.resetAllMocks();
router = mockRouter.create();
registerTelemetryRoute({
router,
getSavedObjectsService: () => savedObjectsServiceMock.create(),
});
});

describe('PUT /api/app_search/telemetry', () => {
it('increments the saved objects counter', async () => {
const successResponse = { success: true };
incrementUICounter.mockImplementation(jest.fn(() => successResponse));

await callThisRoute('put', { body: { action: 'viewed', metric: 'setup_guide' } });

expect(incrementUICounter).toHaveBeenCalledWith({
savedObjects: expect.any(Object),
uiAction: 'ui_viewed',
metric: 'setup_guide',
});
expect(mockResponseFactory.ok).toHaveBeenCalledWith({ body: successResponse });
});

it('throws an error when incrementing fails', async () => {
incrementUICounter.mockImplementation(jest.fn(() => Promise.reject()));

await callThisRoute('put', { body: { action: 'error', metric: 'error' } });

expect(incrementUICounter).toHaveBeenCalled();
expect(mockResponseFactory.internalError).toHaveBeenCalled();
});
});

/**
* Test helpers
*/

const callThisRoute = async (method, request) => {
const [_, handler] = router[method].mock.calls[0];

const context = {};
await handler(context, httpServerMock.createKibanaRequest(request), mockResponseFactory);
};
});

0 comments on commit c89ab55

Please sign in to comment.