cozy-dataproxy-lib
Version:
Library meant to be by Cozy Cloud's DataProxy apps for data manipulation
930 lines (874 loc) • 34.4 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _cozyClient = require("cozy-client");
var _SearchEngine = require("./SearchEngine");
var consts = _interopRequireWildcard(require("./consts"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
jest.mock('flexsearch');
jest.mock('flexsearch/dist/module/lang/latin/simple');
jest.mock("./helpers/client", function () {
return {
getPouchLink: jest.fn()
};
});
jest.mock("./helpers/getSearchEncoder", function () {
return {
getSearchEncoder: jest.fn()
};
});
jest.mock("./helpers/normalizeSearchResult", function () {
return {
enrichResultsWithDocs: jest.fn(),
normalizeSearchResult: jest.fn()
};
});
jest.mock("./storage", function () {
return {
getExportDate: jest.fn(),
importSearchIndexes: jest.fn(),
exportSearchIndexes: jest.fn()
};
});
jest.mock("./indexDocs", function () {
return {
indexAllDocs: jest.fn(),
indexOnChanges: jest.fn(),
indexSingleDoc: jest.fn(),
initDoctypeAfterIndexImport: jest.fn(),
initSearchIndex: jest.fn()
};
});
jest.mock("./queries", function () {
return {
queryLocalOrRemoteDocs: jest.fn()
};
});
jest.mock("./consts", function () {
return {
LIMIT_DOCTYPE_SEARCH: 3,
SEARCH_SCHEMA: {
'io.cozy.files': ['name', 'path'],
'io.cozy.contacts': ['displayName', 'fullname'],
'io.cozy.apps': ['slug', 'name']
},
DOCTYPE_DEFAULT_ORDER: {
'io.cozy.apps': 0,
'io.cozy.contacts': 1,
'io.cozy.files': 2
},
FILES_DOCTYPE: 'io.cozy.files',
CONTACTS_DOCTYPE: 'io.cozy.contacts',
APPS_DOCTYPE: 'io.cozy.apps',
SHARED_DRIVE_FILES_DOCTYPE: 'io.cozy.files.shareddrives',
SHARED_DRIVES_DIR_ID: 'io.cozy.files.shared-drives-dir',
SEARCHABLE_DOCTYPES: ['io.cozy.files', 'io.cozy.contacts', 'io.cozy.apps']
};
}); // Mock realtime dependencies
jest.mock('cozy-realtime', function () {
return {
RealtimePlugin: {
pluginName: 'realtime'
},
__esModule: true,
default: jest.fn()
};
});
describe('sortSearchResults', function () {
var searchEngine;
beforeEach(function () {
var client = (0, _cozyClient.createMockClient)();
searchEngine = new _SearchEngine.SearchEngine(client);
});
afterEach(function () {
jest.clearAllMocks();
});
it('should sort results by doctype order', function () {
var searchResults = [{
doctype: consts.FILES_DOCTYPE,
doc: {
_type: consts.FILES_DOCTYPE
}
}, {
doctype: consts.APPS_DOCTYPE,
doc: {
_type: consts.APPS_DOCTYPE
}
}, {
doctype: consts.CONTACTS_DOCTYPE,
doc: {
_type: consts.CONTACTS_DOCTYPE
}
}];
var sortedResults = searchEngine.sortSearchResults(searchResults);
expect(sortedResults[0].doctype).toBe(consts.APPS_DOCTYPE);
expect(sortedResults[1].doctype).toBe(consts.CONTACTS_DOCTYPE);
expect(sortedResults[2].doctype).toBe(consts.FILES_DOCTYPE);
});
it('should sort apps by slug', function () {
var searchResults = [{
doctype: consts.APPS_DOCTYPE,
doc: {
slug: 'appB',
_type: consts.APPS_DOCTYPE
}
}, {
doctype: consts.APPS_DOCTYPE,
doc: {
slug: 'appA',
_type: consts.APPS_DOCTYPE
}
}];
var sortedResults = searchEngine.sortSearchResults(searchResults);
expect(sortedResults[0].doc.slug).toBe('appA');
expect(sortedResults[1].doc.slug).toBe('appB');
});
it('should sort contacts by displayName', function () {
var searchResults = [{
doctype: consts.CONTACTS_DOCTYPE,
doc: {
displayName: 'June',
_type: consts.CONTACTS_DOCTYPE
}
}, {
doctype: consts.CONTACTS_DOCTYPE,
doc: {
displayName: 'Alice',
_type: consts.CONTACTS_DOCTYPE
}
}];
var sortedResults = searchEngine.sortSearchResults(searchResults);
expect(sortedResults[0].doc.displayName).toBe('Alice');
expect(sortedResults[1].doc.displayName).toBe('June');
});
it('should sort files by type and name', function () {
var searchResults = [{
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'fileB',
type: 'file',
_type: consts.FILES_DOCTYPE
},
fields: ['name']
}, {
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'fileA',
type: 'file',
_type: consts.FILES_DOCTYPE
},
fields: ['name']
}, {
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'folderA',
type: 'directory',
_type: consts.FILES_DOCTYPE
},
fields: ['name']
}];
var sortedResults = searchEngine.sortSearchResults(searchResults);
expect(sortedResults[0].doc.type).toBe('directory'); // Folders should come first
expect(sortedResults[1].doc.name).toBe('fileA');
expect(sortedResults[2].doc.name).toBe('fileB');
});
it('should sort files first if they match on name, then path', function () {
var searchResults = [{
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'test11',
path: 'test/test11',
type: 'file',
_type: consts.FILES_DOCTYPE
},
fields: ['name']
}, {
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'test1',
path: 'test/test1',
type: 'file',
_type: consts.FILES_DOCTYPE
},
fields: ['name']
}, {
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'DirName1',
path: 'test1/path',
type: 'directory',
_type: consts.FILES_DOCTYPE
},
fields: ['path']
}, {
doctype: consts.FILES_DOCTYPE,
doc: {
name: 'DirName2',
path: 'test1/path',
type: 'directory',
_type: consts.FILES_DOCTYPE
},
fields: ['name']
}];
var sortedResults = searchEngine.sortSearchResults(searchResults);
expect(sortedResults[0].doc.name).toBe('DirName2'); // Dir match on name
expect(sortedResults[1].doc.name).toBe('test1'); // File match on name
expect(sortedResults[2].doc.name).toBe('test11'); // File match on name
expect(sortedResults[3].doc.name).toBe('DirName1'); // Directory
});
});
describe('limitSearchResults', function () {
var searchEngine;
beforeEach(function () {
var client = (0, _cozyClient.createMockClient)();
searchEngine = new _SearchEngine.SearchEngine(client);
});
afterEach(function () {
jest.clearAllMocks();
});
it('should return all results if doctype count is below or equal the limit', function () {
var searchResults = [{
doctype: consts.FILES_DOCTYPE,
id: 1
}, {
doctype: consts.FILES_DOCTYPE,
id: 2
}, {
doctype: consts.FILES_DOCTYPE,
id: 3
}];
var filteredResults = searchEngine.limitSearchResults(searchResults);
expect(filteredResults).toEqual(searchResults);
});
it('should filter results exceeding the limit for a specific doctype', function () {
var searchResults = [{
doctype: consts.FILES_DOCTYPE,
id: 1
}, {
doctype: consts.FILES_DOCTYPE,
id: 2
}, {
doctype: consts.FILES_DOCTYPE,
id: 3
}, {
doctype: consts.FILES_DOCTYPE,
id: 4
}, {
doctype: consts.CONTACTS_DOCTYPE,
id: 5
}];
var filteredResults = searchEngine.limitSearchResults(searchResults);
expect(filteredResults).toEqual([{
doctype: consts.FILES_DOCTYPE,
id: 1
}, {
doctype: consts.FILES_DOCTYPE,
id: 2
}, {
doctype: consts.FILES_DOCTYPE,
id: 3
}, {
doctype: consts.CONTACTS_DOCTYPE,
id: 5
}]);
});
it('should return an empty array if input is empty', function () {
var searchResults = [];
var filteredResults = searchEngine.limitSearchResults(searchResults);
expect(filteredResults).toEqual([]);
});
});
describe('getSharedDrivesDoctypes', function () {
var searchEngine;
var mockClient;
var mockPouchLink;
beforeEach(function () {
mockClient = (0, _cozyClient.createMockClient)();
mockPouchLink = {
doctypes: ['io.cozy.files', 'io.cozy.contacts', 'io.cozy.apps', 'io.cozy.files.shareddrives.drive1', 'io.cozy.files.shareddrives.drive2']
};
var _require = require("./helpers/client"),
getPouchLink = _require.getPouchLink;
getPouchLink.mockReturnValue(mockPouchLink);
searchEngine = new _SearchEngine.SearchEngine(mockClient, {}, undefined, {
shouldInit: false
});
});
afterEach(function () {
jest.clearAllMocks();
});
it('should return shared drives doctypes when pouch link exists', function () {
var sharedDrivesDoctypes = searchEngine.getSharedDrivesDoctypes();
expect(sharedDrivesDoctypes).toEqual(['io.cozy.files.shareddrives.drive1', 'io.cozy.files.shareddrives.drive2']);
});
it('should return empty array when pouch link does not exist', function () {
var _require2 = require("./helpers/client"),
getPouchLink = _require2.getPouchLink;
getPouchLink.mockReturnValue(null);
var sharedDrivesDoctypes = searchEngine.getSharedDrivesDoctypes();
expect(sharedDrivesDoctypes).toEqual([]);
});
it('should return empty array when no shared drives doctypes exist', function () {
mockPouchLink.doctypes = ['io.cozy.files', 'io.cozy.contacts', 'io.cozy.apps'];
var sharedDrivesDoctypes = searchEngine.getSharedDrivesDoctypes();
expect(sharedDrivesDoctypes).toEqual([]);
});
});
describe('search method with shared drives integration', function () {
var searchEngine;
var mockClient;
var mockPouchLink;
var mockStorage;
beforeEach(function () {
mockClient = (0, _cozyClient.createMockClient)();
mockStorage = {
storeData: jest.fn(),
getData: jest.fn()
};
mockPouchLink = {
doctypes: ['io.cozy.files', 'io.cozy.contacts', 'io.cozy.apps', 'io.cozy.files.shareddrives.drive1', 'io.cozy.files.shareddrives.drive2']
};
var _require3 = require("./helpers/client"),
getPouchLink = _require3.getPouchLink;
getPouchLink.mockReturnValue(mockPouchLink);
searchEngine = new _SearchEngine.SearchEngine(mockClient, mockStorage, undefined, {
shouldInit: false
}); // Mock search indexes with shared drives
searchEngine.searchIndexes = {
'io.cozy.files': {
index: {
search: jest.fn().mockReturnValue([])
}
},
'io.cozy.files.shareddrives.drive1': {
index: {
search: jest.fn().mockReturnValue([])
}
},
'io.cozy.files.shareddrives.drive2': {
index: {
search: jest.fn().mockReturnValue([])
}
}
};
});
afterEach(function () {
jest.clearAllMocks();
});
it('should include shared drives doctypes when searching files without specific doctypes', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
var _require4, enrichResultsWithDocs, normalizeSearchResult, searchOnIndexesSpy;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_require4 = require("./helpers/normalizeSearchResult"), enrichResultsWithDocs = _require4.enrichResultsWithDocs, normalizeSearchResult = _require4.normalizeSearchResult;
enrichResultsWithDocs.mockResolvedValue([]);
normalizeSearchResult.mockReturnValue({
title: 'test',
doc: {}
});
searchOnIndexesSpy = jest.spyOn(searchEngine, 'searchOnIndexes');
searchOnIndexesSpy.mockReturnValue([]);
_context.next = 7;
return searchEngine.search('test query', {
doctypes: [consts.FILES_DOCTYPE]
});
case 7:
expect(searchOnIndexesSpy).toHaveBeenCalledWith('test query', [consts.FILES_DOCTYPE, 'io.cozy.files.shareddrives.drive1', 'io.cozy.files.shareddrives.drive2']);
case 8:
case "end":
return _context.stop();
}
}
}, _callee);
})));
it('should include shared drives doctypes when searching without specific doctypes', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
var _require5, enrichResultsWithDocs, normalizeSearchResult, searchOnIndexesSpy;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_require5 = require("./helpers/normalizeSearchResult"), enrichResultsWithDocs = _require5.enrichResultsWithDocs, normalizeSearchResult = _require5.normalizeSearchResult;
enrichResultsWithDocs.mockResolvedValue([]);
normalizeSearchResult.mockReturnValue({
title: 'test',
doc: {}
});
searchOnIndexesSpy = jest.spyOn(searchEngine, 'searchOnIndexes');
searchOnIndexesSpy.mockReturnValue([]);
_context2.next = 7;
return searchEngine.search('test query', {});
case 7:
expect(searchOnIndexesSpy).toHaveBeenCalledWith('test query', ['io.cozy.files.shareddrives.drive1', 'io.cozy.files.shareddrives.drive2']);
case 8:
case "end":
return _context2.stop();
}
}
}, _callee2);
})));
it('should not include shared drives doctypes when searching specific non-files doctypes', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
var _require6, enrichResultsWithDocs, normalizeSearchResult, searchOnIndexesSpy;
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_require6 = require("./helpers/normalizeSearchResult"), enrichResultsWithDocs = _require6.enrichResultsWithDocs, normalizeSearchResult = _require6.normalizeSearchResult;
enrichResultsWithDocs.mockResolvedValue([]);
normalizeSearchResult.mockReturnValue({
title: 'test',
doc: {}
});
searchOnIndexesSpy = jest.spyOn(searchEngine, 'searchOnIndexes');
searchOnIndexesSpy.mockReturnValue([]);
_context3.next = 7;
return searchEngine.search('test query', {
doctypes: [consts.CONTACTS_DOCTYPE]
});
case 7:
expect(searchOnIndexesSpy).toHaveBeenCalledWith('test query', [consts.CONTACTS_DOCTYPE]);
case 8:
case "end":
return _context3.stop();
}
}
}, _callee3);
})));
it('should clean up non-existing doctypes from search indexes', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
var _require7, enrichResultsWithDocs, normalizeSearchResult, searchOnIndexesSpy;
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
// Set up search indexes with doctypes that don't exist in pouch link
searchEngine.searchIndexes = {
'io.cozy.files': {
index: {
search: jest.fn().mockReturnValue([])
}
},
'io.cozy.files.shareddrives.drive1': {
index: {
search: jest.fn().mockReturnValue([])
}
},
'non.existing.doctype': {
index: {
search: jest.fn().mockReturnValue([])
}
}
};
_require7 = require("./helpers/normalizeSearchResult"), enrichResultsWithDocs = _require7.enrichResultsWithDocs, normalizeSearchResult = _require7.normalizeSearchResult;
enrichResultsWithDocs.mockResolvedValue([]);
normalizeSearchResult.mockReturnValue({
title: 'test',
doc: {}
});
searchOnIndexesSpy = jest.spyOn(searchEngine, 'searchOnIndexes');
searchOnIndexesSpy.mockReturnValue([]);
_context4.next = 8;
return searchEngine.search('test query', {});
case 8:
// Check that non-existing doctype was removed
expect(searchEngine.searchIndexes['non.existing.doctype']).toBeUndefined();
expect(searchEngine.searchIndexes['io.cozy.files']).toBeDefined();
expect(searchEngine.searchIndexes['io.cozy.files.shareddrives.drive1']).toBeDefined();
case 11:
case "end":
return _context4.stop();
}
}
}, _callee4);
})));
});
describe('indexDocumentsAtInit with shared drives', function () {
var searchEngine;
var mockClient;
var mockStorage;
var mockPouchLink;
beforeEach(function () {
mockClient = (0, _cozyClient.createMockClient)();
mockStorage = {
storeData: jest.fn(),
getData: jest.fn().mockResolvedValue(null) // No persisted index
};
mockPouchLink = {
doctypes: ['io.cozy.files', 'io.cozy.contacts', 'io.cozy.apps', 'io.cozy.files.shareddrives.drive1', 'io.cozy.files.shareddrives.drive2']
};
var _require8 = require("./helpers/client"),
getPouchLink = _require8.getPouchLink;
getPouchLink.mockReturnValue(mockPouchLink);
searchEngine = new _SearchEngine.SearchEngine(mockClient, mockStorage, undefined, {
shouldInit: false
});
searchEngine.isLocalSearch = true;
});
afterEach(function () {
jest.clearAllMocks();
});
it('should index shared drives doctypes during initialization', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
var _require9, getExportDate, _require10, queryLocalOrRemoteDocs, _require11, initSearchIndex, indexAllDocs, indexDocsForSearchSpy;
return _regenerator.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
_require9 = require("./storage"), getExportDate = _require9.getExportDate;
_require10 = require("./queries"), queryLocalOrRemoteDocs = _require10.queryLocalOrRemoteDocs;
_require11 = require("./indexDocs"), initSearchIndex = _require11.initSearchIndex, indexAllDocs = _require11.indexAllDocs;
getExportDate.mockResolvedValue(null); // No persisted index
queryLocalOrRemoteDocs.mockResolvedValue([]);
initSearchIndex.mockReturnValue({
search: jest.fn()
});
indexAllDocs.mockImplementation(function () {});
indexDocsForSearchSpy = jest.spyOn(searchEngine, 'indexDocsForSearch');
indexDocsForSearchSpy.mockResolvedValue({
index: {
search: jest.fn()
},
lastSeq: 1,
lastUpdated: new Date().toISOString()
});
_context5.next = 11;
return searchEngine.indexDocumentsAtInit();
case 11:
// Should be called for standard doctypes + shared drives doctypes
expect(indexDocsForSearchSpy).toHaveBeenCalledWith('io.cozy.files');
expect(indexDocsForSearchSpy).toHaveBeenCalledWith('io.cozy.contacts');
expect(indexDocsForSearchSpy).toHaveBeenCalledWith('io.cozy.apps');
expect(indexDocsForSearchSpy).toHaveBeenCalledWith('io.cozy.files.shareddrives.drive1');
expect(indexDocsForSearchSpy).toHaveBeenCalledWith('io.cozy.files.shareddrives.drive2');
case 16:
case "end":
return _context5.stop();
}
}
}, _callee5);
})));
}); // Realtime features tests
describe('Realtime features', function () {
var searchEngine;
var mockClient;
var mockStorage;
var mockPouchLink;
var mockRealtimePlugin;
var mockCozyRealtime;
beforeEach(function () {
mockClient = (0, _cozyClient.createMockClient)();
mockStorage = {
storeData: jest.fn(),
getData: jest.fn()
};
mockPouchLink = {
doctypes: ['io.cozy.files', 'io.cozy.contacts', 'io.cozy.apps'],
startReplicationWithDebounce: jest.fn(),
getDbInfo: jest.fn().mockResolvedValue({
update_seq: 1
}),
getSharedDriveDoctypes: jest.fn().mockReturnValue([])
};
mockRealtimePlugin = {
subscribe: jest.fn()
};
mockCozyRealtime = jest.fn().mockImplementation(function () {
return {
subscribe: jest.fn(),
stop: jest.fn()
};
});
var _require12 = require("./helpers/client"),
getPouchLink = _require12.getPouchLink;
getPouchLink.mockReturnValue(mockPouchLink);
var CozyRealtime = require('cozy-realtime').default;
CozyRealtime.mockImplementation(mockCozyRealtime); // Mock client plugins
mockClient.plugins = {
realtime: mockRealtimePlugin
};
mockClient.registerPlugin = jest.fn();
mockClient.on = jest.fn();
mockClient.isLogged = true;
searchEngine = new _SearchEngine.SearchEngine(mockClient, mockStorage, undefined, {
shouldInit: false
});
searchEngine.isLocalSearch = true;
});
afterEach(function () {
jest.clearAllMocks();
});
describe('init method - realtime setup', function () {
it('should setup shared drives realtime if pouch link has shared drives doctypes', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6() {
return _regenerator.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
mockPouchLink.getSharedDriveDoctypes.mockReturnValue(['io.cozy.files.shareddrives-drive1', 'io.cozy.files.shareddrives-drive2']);
_context6.next = 3;
return searchEngine.init();
case 3:
expect(mockCozyRealtime).toHaveBeenCalledWith({
client: mockClient,
sharedDriveId: 'drive1',
background: true
});
expect(mockCozyRealtime).toHaveBeenCalledWith({
client: mockClient,
sharedDriveId: 'drive2',
background: true
});
case 5:
case "end":
return _context6.stop();
}
}
}, _callee6);
})));
});
describe('handleUpdatedOrCreatedDoc method', function () {
beforeEach(function () {
searchEngine.searchIndexes = {
'io.cozy.files': {
index: {
search: jest.fn()
}
}
};
});
it('should return early if doctype is not a searched doctype', function () {
var _require13 = require("./indexDocs"),
indexSingleDoc = _require13.indexSingleDoc;
var doc = {
_type: 'io.cozy.notsearched',
_id: 'test-id'
};
searchEngine.handleUpdatedOrCreatedDoc(doc);
expect(indexSingleDoc).not.toHaveBeenCalled();
});
it('should return early if no search index exists for doctype', function () {
var _require14 = require("./indexDocs"),
indexSingleDoc = _require14.indexSingleDoc;
var doc = {
_type: 'io.cozy.contacts',
_id: 'test-id'
};
searchEngine.handleUpdatedOrCreatedDoc(doc);
expect(indexSingleDoc).not.toHaveBeenCalled();
});
it('should call indexSingleDoc for valid doctype with existing index', function () {
var _require15 = require("./indexDocs"),
indexSingleDoc = _require15.indexSingleDoc;
var doc = {
_type: 'io.cozy.files',
_id: 'test-id'
};
searchEngine.handleUpdatedOrCreatedDoc(doc);
expect(indexSingleDoc).toHaveBeenCalledWith(searchEngine.searchIndexes['io.cozy.files'].index, doc);
});
it('should trigger debounced replication for local search', function () {
var doc = {
_type: 'io.cozy.files',
_id: 'test-id'
};
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
searchEngine.handleUpdatedOrCreatedDoc(doc);
expect(debouncedReplicationSpy).toHaveBeenCalled();
});
it('should not trigger debounced replication for non-local search', function () {
searchEngine.isLocalSearch = false;
var doc = {
_type: 'io.cozy.files',
_id: 'test-id'
};
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
searchEngine.handleUpdatedOrCreatedDoc(doc);
expect(debouncedReplicationSpy).not.toHaveBeenCalled();
});
});
describe('handleDeletedDoc method', function () {
beforeEach(function () {
var mockIndex = {
remove: jest.fn()
};
searchEngine.searchIndexes = {
'io.cozy.files': {
index: mockIndex
}
};
});
it('should return early if doctype is not a searched doctype', function () {
var doc = {
_type: 'io.cozy.notsearched',
_id: 'test-id'
};
searchEngine.handleDeletedDoc(doc);
expect(searchEngine.searchIndexes['io.cozy.files'].index.remove).not.toHaveBeenCalled();
});
it('should return early if no search index exists for doctype', function () {
var doc = {
_type: 'io.cozy.contacts',
_id: 'test-id'
};
searchEngine.handleDeletedDoc(doc);
expect(searchEngine.searchIndexes['io.cozy.files'].index.remove).not.toHaveBeenCalled();
});
it('should remove document from search index for valid doctype', function () {
var doc = {
_type: 'io.cozy.files',
_id: 'test-id'
};
searchEngine.handleDeletedDoc(doc);
expect(searchEngine.searchIndexes['io.cozy.files'].index.remove).toHaveBeenCalledWith('test-id');
});
it('should trigger debounced replication for local search', function () {
var doc = {
_type: 'io.cozy.files',
_id: 'test-id'
};
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
searchEngine.handleDeletedDoc(doc);
expect(debouncedReplicationSpy).toHaveBeenCalled();
});
it('should not trigger debounced replication for non-local search', function () {
searchEngine.isLocalSearch = false;
var doc = {
_type: 'io.cozy.files',
_id: 'test-id'
};
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
searchEngine.handleDeletedDoc(doc);
expect(debouncedReplicationSpy).not.toHaveBeenCalled();
});
});
describe('Shared drives realtime functionality', function () {
beforeEach(function () {
var mockRealtimeInstance = {
subscribe: jest.fn(),
stop: jest.fn()
};
mockCozyRealtime.mockReturnValue(mockRealtimeInstance);
});
describe('addSharedDrive method', function () {
it('should seed an index, add shared drive realtime and trigger replication', function () {
var _require16 = require("./indexDocs"),
initSearchIndex = _require16.initSearchIndex;
initSearchIndex.mockReturnValue({
search: jest.fn()
});
var addSharedDriveRealtimeSpy = jest.spyOn(searchEngine, 'addSharedDriveRealtime');
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
var indexDocsForSearchSpy = jest.spyOn(searchEngine, 'indexDocsForSearch').mockResolvedValue(undefined);
searchEngine.addSharedDrive('drive1'); // The index is seeded immediately so realtime events are not dropped
// while the first replication is still running.
expect(searchEngine.searchIndexes['io.cozy.files.shareddrives-drive1']).toBeDefined();
expect(addSharedDriveRealtimeSpy).toHaveBeenCalledWith('drive1');
expect(debouncedReplicationSpy).toHaveBeenCalled(); // Existing replicated documents are indexed without waiting for a refresh.
expect(indexDocsForSearchSpy).toHaveBeenCalledWith('io.cozy.files.shareddrives-drive1');
});
it('should not trigger replication for non-local search', function () {
searchEngine.isLocalSearch = false;
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
searchEngine.addSharedDrive('drive1');
expect(debouncedReplicationSpy).not.toHaveBeenCalled();
});
});
describe('removeSharedDrive method', function () {
beforeEach(function () {
var mockRealtimeInstance = {
subscribe: jest.fn(),
stop: jest.fn()
};
searchEngine.sharedDrivesRealtimes = {
drive1: mockRealtimeInstance
};
searchEngine.searchIndexes = {
'io.cozy.files.shareddrives-drive1': {
index: {
search: jest.fn()
}
}
};
});
it('should stop realtime, remove from indexes and trigger replication', function () {
var mockRealtimeInstance = searchEngine.sharedDrivesRealtimes.drive1;
searchEngine.removeSharedDrive('drive1');
expect(mockRealtimeInstance.stop).toHaveBeenCalled();
expect(searchEngine.sharedDrivesRealtimes.drive1).toBeUndefined();
expect(searchEngine.searchIndexes['io.cozy.files.shareddrives-drive1']).toBeUndefined();
});
it('should not trigger replication for non-local search', function () {
searchEngine.isLocalSearch = false;
var debouncedReplicationSpy = jest.spyOn(searchEngine, 'debouncedReplication');
searchEngine.removeSharedDrive('drive1');
expect(debouncedReplicationSpy).not.toHaveBeenCalled();
});
});
describe('addSharedDriveRealtime private method', function () {
it('should create CozyRealtime instance and subscribe to files doctype', function () {
var mockRealtimeInstance = {
subscribe: jest.fn(),
stop: jest.fn()
};
mockCozyRealtime.mockReturnValue(mockRealtimeInstance);
searchEngine.addSharedDriveRealtime('drive1');
expect(mockCozyRealtime).toHaveBeenCalledWith({
client: mockClient,
sharedDriveId: 'drive1',
background: true
});
expect(mockRealtimeInstance.subscribe).toHaveBeenCalledWith('created', consts.FILES_DOCTYPE, expect.any(Function));
expect(mockRealtimeInstance.subscribe).toHaveBeenCalledWith('updated', consts.FILES_DOCTYPE, expect.any(Function));
expect(mockRealtimeInstance.subscribe).toHaveBeenCalledWith('deleted', consts.FILES_DOCTYPE, expect.any(Function));
expect(searchEngine.sharedDrivesRealtimes.drive1).toBe(mockRealtimeInstance);
});
});
describe('shared drives realtime lifecycle', function () {
it('stops the previous realtime when re-subscribing the same drive', function () {
var firstInstance = {
subscribe: jest.fn(),
stop: jest.fn()
};
var secondInstance = {
subscribe: jest.fn(),
stop: jest.fn()
};
mockCozyRealtime.mockReturnValueOnce(firstInstance).mockReturnValueOnce(secondInstance);
searchEngine.addSharedDriveRealtime('drive1');
searchEngine.addSharedDriveRealtime('drive1');
expect(firstInstance.stop).toHaveBeenCalledTimes(1);
expect(searchEngine.sharedDrivesRealtimes.drive1).toBe(secondInstance);
});
it('stopSharedDrivesRealtimes stops every socket and clears the map', function () {
var driveA = {
subscribe: jest.fn(),
stop: jest.fn()
};
var driveB = {
subscribe: jest.fn(),
stop: jest.fn()
};
searchEngine.sharedDrivesRealtimes = {
driveA: driveA,
driveB: driveB
};
searchEngine.stopSharedDrivesRealtimes();
expect(driveA.stop).toHaveBeenCalledTimes(1);
expect(driveB.stop).toHaveBeenCalledTimes(1);
expect(searchEngine.sharedDrivesRealtimes).toEqual({});
});
it('stops all shared drives realtimes when the client logs out', function () {
var _mockClient$on$mock$c;
var stopSpy = jest.spyOn(searchEngine, 'stopSharedDrivesRealtimes');
var logoutHandler = (_mockClient$on$mock$c = mockClient.on.mock.calls.find(function (_ref7) {
var _ref8 = (0, _slicedToArray2.default)(_ref7, 1),
event = _ref8[0];
return event === 'logout';
})) === null || _mockClient$on$mock$c === void 0 ? void 0 : _mockClient$on$mock$c[1];
expect(logoutHandler).toBeDefined();
logoutHandler();
expect(stopSpy).toHaveBeenCalled();
});
});
});
});