diff --git a/src/plugins/newsfeed/public/lib/api.test.mocks.ts b/src/plugins/newsfeed/public/lib/api.test.mocks.ts new file mode 100644 index 00000000000000..677bc203cbef3f --- /dev/null +++ b/src/plugins/newsfeed/public/lib/api.test.mocks.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { storageMock } from './storage.mock'; +import { driverMock } from './driver.mock'; + +export const storageInstanceMock = storageMock.create(); +jest.doMock('./storage', () => ({ + NewsfeedStorage: jest.fn().mockImplementation(() => storageInstanceMock), +})); + +export const driverInstanceMock = driverMock.create(); +jest.doMock('./driver', () => ({ + NewsfeedApiDriver: jest.fn().mockImplementation(() => driverInstanceMock), +})); diff --git a/src/plugins/newsfeed/public/lib/api.test.ts b/src/plugins/newsfeed/public/lib/api.test.ts new file mode 100644 index 00000000000000..9727557587cd1e --- /dev/null +++ b/src/plugins/newsfeed/public/lib/api.test.ts @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { driverInstanceMock, storageInstanceMock } from './api.test.mocks'; +import moment from 'moment'; +import { httpServiceMock } from '../../../../core/public/mocks'; +import { getApi } from './api'; +import { TestScheduler } from 'rxjs/testing'; +import { FetchResult, NewsfeedPluginBrowserConfig } from '../types'; +import { take } from 'rxjs/operators'; + +const kibanaVersion = '8.0.0'; +const newsfeedId = 'test'; + +const getTestScheduler = () => + new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + +const createConfig = (mainInternal: number): NewsfeedPluginBrowserConfig => ({ + mainInterval: moment.duration(mainInternal, 'ms'), + fetchInterval: moment.duration(mainInternal, 'ms'), + service: { + urlRoot: 'urlRoot', + pathTemplate: 'pathTemplate', + }, +}); + +const createFetchResult = (parts: Partial): FetchResult => ({ + feedItems: [], + hasNew: false, + error: null, + kibanaVersion, + ...parts, +}); + +describe('getApi', () => { + let http: ReturnType; + + beforeEach(() => { + http = httpServiceMock.createSetupContract(); + driverInstanceMock.shouldFetch.mockReturnValue(true); + }); + + afterEach(() => { + storageInstanceMock.isAnyUnread$.mockReset(); + driverInstanceMock.fetchNewsfeedItems.mockReset(); + }); + + it('merges the newsfeed and unread observables', () => { + getTestScheduler().run(({ expectObservable, cold }) => { + storageInstanceMock.isAnyUnread$.mockImplementation(() => { + return cold('a|', { + a: true, + }); + }); + driverInstanceMock.fetchNewsfeedItems.mockReturnValue( + cold('a|', { + a: createFetchResult({ feedItems: ['item' as any] }), + }) + ); + const api = getApi(http, createConfig(1000), kibanaVersion, newsfeedId); + + expectObservable(api.fetchResults$.pipe(take(1))).toBe('(a|)', { + a: createFetchResult({ + feedItems: ['item' as any], + hasNew: true, + }), + }); + }); + }); + + it('emits based on the predefined interval', () => { + getTestScheduler().run(({ expectObservable, cold }) => { + storageInstanceMock.isAnyUnread$.mockImplementation(() => { + return cold('a|', { + a: true, + }); + }); + driverInstanceMock.fetchNewsfeedItems.mockReturnValue( + cold('a|', { + a: createFetchResult({ feedItems: ['item' as any] }), + }) + ); + const api = getApi(http, createConfig(2), kibanaVersion, newsfeedId); + + expectObservable(api.fetchResults$.pipe(take(2))).toBe('a-(b|)', { + a: createFetchResult({ + feedItems: ['item' as any], + hasNew: true, + }), + b: createFetchResult({ + feedItems: ['item' as any], + hasNew: true, + }), + }); + }); + }); + + it('re-emits when the unread status changes', () => { + getTestScheduler().run(({ expectObservable, cold }) => { + storageInstanceMock.isAnyUnread$.mockImplementation(() => { + return cold('a--b', { + a: true, + b: false, + }); + }); + driverInstanceMock.fetchNewsfeedItems.mockReturnValue( + cold('(a|)', { + a: createFetchResult({}), + }) + ); + const api = getApi(http, createConfig(10), kibanaVersion, newsfeedId); + + expectObservable(api.fetchResults$.pipe(take(2))).toBe('a--(b|)', { + a: createFetchResult({ + hasNew: true, + }), + b: createFetchResult({ + hasNew: false, + }), + }); + }); + }); +}); diff --git a/src/plugins/newsfeed/public/lib/driver.mock.ts b/src/plugins/newsfeed/public/lib/driver.mock.ts new file mode 100644 index 00000000000000..8ae4ad1a82c4d6 --- /dev/null +++ b/src/plugins/newsfeed/public/lib/driver.mock.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PublicMethodsOf } from '@kbn/utility-types'; +import type { NewsfeedApiDriver } from './driver'; + +const createDriverMock = () => { + const mock: jest.Mocked> = { + shouldFetch: jest.fn(), + fetchNewsfeedItems: jest.fn(), + }; + return mock as jest.Mocked; +}; + +export const driverMock = { + create: createDriverMock, +};