-
Notifications
You must be signed in to change notification settings - Fork 171
Expand file tree
/
Copy pathsearch-service.test.js
More file actions
114 lines (91 loc) · 3.86 KB
/
Copy pathsearch-service.test.js
File metadata and controls
114 lines (91 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const SearchService = require("../src/search-service");
import 'fake-indexeddb/auto';
// The following line is necessary to mock the jQuery library and
// provide a default implementation for the '$' function in the test
// environment, since it is not defined by default. The mock
// implementation is necessary to allow the 'SearchService' class
// to select the "#tag" and "#search-overlay" elements
// without throwing errors during testing.
jest.mock('jquery');
// Mock the console functions to prevent logs during testing
console.log = jest.fn();
console.debug = jest.fn();
describe('SearchService', () => {
let data;
let searchService;
beforeAll(() => {
data = require('./mock-index.json');
});
beforeEach(() => {
searchService = new SearchService('search-service', null);
});
afterEach(async () => {
searchService = null;
});
it('Access data from mock-index.json', () => {
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBe(10);
expect(data[0].id).toBe(1);
expect(data[0].title).toBe('Introduction to Machine Learning');
expect(data[0].content).toContain('Machine learning is a subfield');
});
test('Initialize SearchService instance', () => {
expect(searchService.db).toBeDefined();
expect(searchService.contentDb).toBeDefined();
expect(searchService.searchIndexDb).toBeDefined();
expect(searchService.attackIndex).toBeDefined();
});
test('Add new documents to the search engine', async () => {
await searchService.initializeAsync(data);
expect(searchService.maxSearchResults).toEqual(data.length);
const tableResults = await searchService.contentDb.getAll();
expect(tableResults).toEqual(data);
});
test('Waits for FlexSearch indexing before backing up the search index', async () => {
let resolveAddBulk;
searchService.attackIndex.addBulk = jest.fn(() => new Promise((resolve) => {
resolveAddBulk = resolve;
}));
searchService.backupSearchIndex = jest.fn(() => Promise.resolve());
const initialization = searchService.initializeAsync(data);
await Promise.resolve();
expect(searchService.backupSearchIndex).not.toHaveBeenCalled();
resolveAddBulk();
await initialization;
expect(searchService.backupSearchIndex).toHaveBeenCalled();
});
test('Backup search index completes when FlexSearch exports fewer than nine persisted chunks', async () => {
const exportedChunks = [
['title.1.map', 'title map data'],
['content.1.map', 'content map data'],
['content.1.ctx', 'content context data'],
['1.reg', 'register data'],
];
searchService.attackIndex = {
index: {
export: jest.fn((handler) => {
exportedChunks.forEach(([key, value], index) => {
setTimeout(() => handler(key, value), index);
});
}),
},
};
searchService.searchIndexDb = {
put: jest.fn(() => Promise.resolve()),
};
const result = await Promise.race([
searchService.backupSearchIndex().then(() => 'completed'),
new Promise((resolve) => setTimeout(() => resolve('timed out'), 250)),
]);
expect(result).toBe('completed');
expect(searchService.searchIndexDb.put).toHaveBeenCalledTimes(exportedChunks.length);
});
test('Resolve search results', async () => {
await searchService.initializeAsync(data);
const positions = [1, 2, 5];
const results = await searchService.resolveSearchResults(positions);
results.forEach((doc, index) => {
expect(doc.id).toEqual(positions[index]);
});
});
});