Skip to content

Commit 464d824

Browse files
committed
add unit tests
1 parent 9080998 commit 464d824

File tree

9 files changed

+392
-711
lines changed

9 files changed

+392
-711
lines changed

src/plugins/newsfeed/public/lib/api.test.ts

Lines changed: 0 additions & 695 deletions
This file was deleted.

src/plugins/newsfeed/public/lib/api.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export function getApi(
4646
): NewsfeedApi {
4747
const userLanguage = i18n.getLocale();
4848
const fetchInterval = config.fetchInterval.asMilliseconds();
49-
const mainInterval = 2000; // config.mainInterval.asMilliseconds();
49+
const mainInterval = config.mainInterval.asMilliseconds();
5050
const storage = new NewsfeedStorage(newsfeedId);
5151
const driver = new NewsfeedApiDriver(kibanaVersion, userLanguage, fetchInterval, storage);
5252

@@ -65,14 +65,14 @@ export function getApi(
6565
})
6666
)
6767
),
68-
tap(() => driver.updateLastFetch())
68+
tap(() => storage.setLastFetchTime(new Date()))
6969
);
7070

71-
const merged$ = combineLatest([results$, storage.getUnreadStatus$()]).pipe(
72-
map(([results, unreadStatus]) => {
71+
const merged$ = combineLatest([results$, storage.isAnyUnread$()]).pipe(
72+
map(([results, isAnyUnread]) => {
7373
return {
7474
...results,
75-
hasNew: results.error ? false : unreadStatus,
75+
hasNew: results.error ? false : isAnyUnread,
7676
};
7777
})
7878
);
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
import moment from 'moment';
10+
import { omit } from 'lodash';
11+
import { validateIntegrity, validatePublishedDate, convertItem } from './convert_items';
12+
import type { ApiItem, NewsfeedItem } from '../types';
13+
14+
const createApiItem = (parts: Partial<ApiItem> = {}): ApiItem => ({
15+
hash: 'hash',
16+
expire_on: new Date(),
17+
publish_on: new Date(),
18+
title: {},
19+
description: {},
20+
link_url: {},
21+
...parts,
22+
});
23+
24+
const createNewsfeedItem = (parts: Partial<NewsfeedItem> = {}): NewsfeedItem => ({
25+
title: 'title',
26+
description: 'description',
27+
linkText: 'linkText',
28+
linkUrl: 'linkUrl',
29+
badge: 'badge',
30+
publishOn: moment(),
31+
expireOn: moment(),
32+
hash: 'hash',
33+
...parts,
34+
});
35+
36+
describe('convertItem', () => {
37+
const item = createApiItem({
38+
languages: ['en', 'fr'],
39+
title: {
40+
en: 'en title',
41+
fr: 'fr title',
42+
},
43+
description: {
44+
en: 'en desc',
45+
fr: 'fr desc',
46+
},
47+
link_text: {
48+
en: 'en link text',
49+
fr: 'fr link text',
50+
},
51+
link_url: {
52+
en: 'en link url',
53+
fr: 'fr link url',
54+
},
55+
badge: {
56+
en: 'en badge',
57+
fr: 'fr badge',
58+
},
59+
publish_on: new Date('2014-10-31T04:23:47Z'),
60+
expire_on: new Date('2049-10-31T04:23:47Z'),
61+
hash: 'hash',
62+
});
63+
64+
it('converts api items to newsfeed items using the specified language', () => {
65+
expect(convertItem(item, 'fr')).toMatchObject({
66+
title: 'fr title',
67+
description: 'fr desc',
68+
linkText: 'fr link text',
69+
linkUrl: 'fr link url',
70+
badge: 'fr badge',
71+
hash: 'hash',
72+
});
73+
});
74+
75+
it('fallbacks to `en` is the language is not present', () => {
76+
expect(convertItem(item, 'de')).toMatchObject({
77+
title: 'en title',
78+
description: 'en desc',
79+
linkText: 'en link text',
80+
linkUrl: 'en link url',
81+
badge: 'en badge',
82+
hash: 'hash',
83+
});
84+
});
85+
});
86+
87+
describe('validatePublishedDate', () => {
88+
it('returns false when the publish date is not reached yet', () => {
89+
expect(
90+
validatePublishedDate(
91+
createApiItem({
92+
publish_on: new Date('2055-10-31T04:23:47Z'), // too new
93+
expire_on: new Date('2056-10-31T04:23:47Z'),
94+
})
95+
)
96+
).toBe(false);
97+
});
98+
99+
it('returns false when the expire date is already reached', () => {
100+
expect(
101+
validatePublishedDate(
102+
createApiItem({
103+
publish_on: new Date('2013-10-31T04:23:47Z'),
104+
expire_on: new Date('2014-10-31T04:23:47Z'), // too old
105+
})
106+
)
107+
).toBe(false);
108+
});
109+
110+
it('returns true when current date is between the publish and expire dates', () => {
111+
expect(
112+
validatePublishedDate(
113+
createApiItem({
114+
publish_on: new Date('2014-10-31T04:23:47Z'),
115+
expire_on: new Date('2049-10-31T04:23:47Z'),
116+
})
117+
)
118+
).toBe(true);
119+
});
120+
});
121+
122+
describe('validateIntegrity', () => {
123+
it('returns false if `title` is missing', () => {
124+
expect(validateIntegrity(omit(createNewsfeedItem(), 'title'))).toBe(false);
125+
});
126+
it('returns false if `description` is missing', () => {
127+
expect(validateIntegrity(omit(createNewsfeedItem(), 'description'))).toBe(false);
128+
});
129+
it('returns false if `linkText` is missing', () => {
130+
expect(validateIntegrity(omit(createNewsfeedItem(), 'linkText'))).toBe(false);
131+
});
132+
it('returns false if `linkUrl` is missing', () => {
133+
expect(validateIntegrity(omit(createNewsfeedItem(), 'linkUrl'))).toBe(false);
134+
});
135+
it('returns false if `publishOn` is missing', () => {
136+
expect(validateIntegrity(omit(createNewsfeedItem(), 'publishOn'))).toBe(false);
137+
});
138+
it('returns false if `hash` is missing', () => {
139+
expect(validateIntegrity(omit(createNewsfeedItem(), 'hash'))).toBe(false);
140+
});
141+
it('returns true if all mandatory fields are present', () => {
142+
expect(validateIntegrity(createNewsfeedItem())).toBe(true);
143+
});
144+
});

src/plugins/newsfeed/public/lib/convert_items.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const convertItems = (items: ApiItem[], userLanguage: string): NewsfeedIt
1717
.filter(validateIntegrity);
1818
};
1919

20-
const validatePublishedDate = (item: ApiItem): boolean => {
20+
export const validatePublishedDate = (item: ApiItem): boolean => {
2121
if (moment(item.expire_on).isBefore(Date.now())) {
2222
return false; // ignore item if expired
2323
}
@@ -28,7 +28,7 @@ const validatePublishedDate = (item: ApiItem): boolean => {
2828
return true;
2929
};
3030

31-
const convertItem = (rawItem: ApiItem, userLanguage: string): NewsfeedItem => {
31+
export const convertItem = (rawItem: ApiItem, userLanguage: string): NewsfeedItem => {
3232
const {
3333
expire_on: expireOnUtc,
3434
publish_on: publishOnUtc,
@@ -58,7 +58,7 @@ const convertItem = (rawItem: ApiItem, userLanguage: string): NewsfeedItem => {
5858
};
5959
};
6060

61-
const validateIntegrity = (item: Partial<NewsfeedItem>): boolean => {
61+
export const validateIntegrity = (item: Partial<NewsfeedItem>): boolean => {
6262
const hasMissing = [
6363
item.title,
6464
item.description,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
import { NewsfeedApiDriver } from './driver';
10+
import { storageMock } from './storage.mock';
11+
12+
const kibanaVersion = '8.0.0';
13+
const userLanguage = 'en';
14+
const fetchInterval = 2000;
15+
16+
describe('NewsfeedApiDriver', () => {
17+
let driver: NewsfeedApiDriver;
18+
let storage: ReturnType<typeof storageMock.create>;
19+
20+
beforeEach(() => {
21+
storage = storageMock.create();
22+
driver = new NewsfeedApiDriver(kibanaVersion, userLanguage, fetchInterval, storage);
23+
});
24+
25+
describe('shouldFetch', () => {
26+
it('returns true if no value is present in the storage', () => {
27+
storage.getLastFetchTime.mockReturnValue(undefined);
28+
expect(driver.shouldFetch()).toBe(true);
29+
expect(storage.getLastFetchTime).toHaveBeenCalledTimes(1);
30+
});
31+
32+
it('returns true if last fetch time precedes page load time', () => {
33+
storage.getLastFetchTime.mockReturnValue(new Date(322642800000)); // 1980-03-23
34+
expect(driver.shouldFetch()).toBe(true);
35+
});
36+
37+
it('returns false if last fetch time is recent enough', () => {
38+
storage.getLastFetchTime.mockReturnValue(new Date(3005017200000)); // 2065-03-23
39+
expect(driver.shouldFetch()).toBe(false);
40+
});
41+
});
42+
});

src/plugins/newsfeed/public/lib/driver.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ export class NewsfeedApiDriver {
4747
return duration.asMilliseconds() > this.fetchInterval;
4848
}
4949

50-
updateLastFetch() {
51-
this.storage.setLastFetchTime(new Date());
52-
}
53-
5450
fetchNewsfeedItems(http: HttpSetup, config: ApiConfig): Rx.Observable<FetchResult> {
5551
const urlPath = config.pathTemplate.replace('{VERSION}', this.kibanaVersion);
5652
const fullUrl = (config.urlRoot || NEWSFEED_DEFAULT_SERVICE_BASE_URL) + urlPath;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
import { PublicMethodsOf } from '@kbn/utility-types';
10+
import type { NewsfeedStorage } from './storage';
11+
12+
const createStorageMock = () => {
13+
const mock: jest.Mocked<PublicMethodsOf<NewsfeedStorage>> = {
14+
getLastFetchTime: jest.fn(),
15+
setLastFetchTime: jest.fn(),
16+
setFetchedItems: jest.fn(),
17+
markItemsAsRead: jest.fn(),
18+
isAnyUnread: jest.fn(),
19+
isAnyUnread$: jest.fn(),
20+
};
21+
return mock as jest.Mocked<NewsfeedStorage>;
22+
};
23+
24+
export const storageMock = {
25+
create: createStorageMock,
26+
};

0 commit comments

Comments
 (0)