search-service.test.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import mongoose from 'mongoose';
  2. import SearchService from '~/server/service/search';
  3. import NamedQuery from '~/server/models/named-query';
  4. const { getInstance } = require('../../setup-crowi');
  5. describe('SearchService test', () => {
  6. let crowi;
  7. let searchService;
  8. const DEFAULT = 'FullTextSearch';
  9. const PRIVATE_LEGACY_PAGES = 'PrivateLegacyPages';
  10. // let NamedQuery;
  11. let dummyAliasOf;
  12. let namedQuery1;
  13. let namedQuery2;
  14. const dummyFullTextSearchDelegator = {
  15. search() {
  16. return;
  17. },
  18. };
  19. beforeAll(async() => {
  20. crowi = await getInstance();
  21. searchService = new SearchService(crowi);
  22. searchService.nqDelegators = {
  23. ...searchService.nqDelegators,
  24. [DEFAULT]: dummyFullTextSearchDelegator, // override with dummy full-text search delegator
  25. };
  26. dummyAliasOf = 'match -notmatch "phrase" -"notphrase" prefix:/pre1 -prefix:/pre2 tag:Tag1 -tag:Tag2';
  27. await NamedQuery.insertMany([
  28. { name: 'named_query1', delegatorName: PRIVATE_LEGACY_PAGES },
  29. { name: 'named_query2', aliasOf: dummyAliasOf },
  30. ]);
  31. namedQuery1 = await NamedQuery.findOne({ name: 'named_query1' });
  32. namedQuery2 = await NamedQuery.findOne({ name: 'named_query2' });
  33. });
  34. describe('parseQueryString()', () => {
  35. test('should parse queryString', async() => {
  36. const queryString = 'match -notmatch "phrase" -"notphrase" prefix:/pre1 -prefix:/pre2 tag:Tag1 -tag:Tag2';
  37. const terms = await searchService.parseQueryString(queryString);
  38. const expected = { // QueryTerms
  39. match: ['match'],
  40. not_match: ['notmatch'],
  41. phrase: ['"phrase"'],
  42. not_phrase: ['"notphrase"'],
  43. prefix: ['/pre1'],
  44. not_prefix: ['/pre2'],
  45. tag: ['Tag1'],
  46. not_tag: ['Tag2'],
  47. };
  48. expect(terms).toStrictEqual(expected);
  49. });
  50. });
  51. describe('parseSearchQuery()', () => {
  52. test('should return result with delegatorName', async() => {
  53. const queryString = '[nq:named_query1]';
  54. const parsedQuery = await searchService.parseSearchQuery(queryString);
  55. const expected = {
  56. queryString,
  57. delegatorName: PRIVATE_LEGACY_PAGES,
  58. };
  59. expect(parsedQuery).toStrictEqual(expected);
  60. });
  61. test('should return result with expanded aliasOf value', async() => {
  62. const queryString = '[nq:named_query2]';
  63. const parsedQuery = await searchService.parseSearchQuery(queryString);
  64. const expected = {
  65. queryString: dummyAliasOf,
  66. terms: {
  67. match: ['match'],
  68. not_match: ['notmatch'],
  69. phrase: ['"phrase"'],
  70. not_phrase: ['"notphrase"'],
  71. prefix: ['/pre1'],
  72. not_prefix: ['/pre2'],
  73. tag: ['Tag1'],
  74. not_tag: ['Tag2'],
  75. },
  76. };
  77. expect(parsedQuery).toStrictEqual(expected);
  78. });
  79. });
  80. describe('resolve()', () => {
  81. test('should resolve as full-text search delegator', async() => {
  82. const parsedQuery = {
  83. queryString: dummyAliasOf,
  84. terms: {
  85. match: ['match'],
  86. not_match: ['notmatch'],
  87. phrase: ['"phrase"'],
  88. not_phrase: ['"notphrase"'],
  89. prefix: ['/pre1'],
  90. not_prefix: ['/pre2'],
  91. tag: ['Tag1'],
  92. not_tag: ['Tag2'],
  93. },
  94. };
  95. const [delegator, data] = await searchService.resolve(parsedQuery);
  96. const expectedData = parsedQuery;
  97. expect(data).toStrictEqual(expectedData);
  98. expect(typeof delegator.search).toBe('function');
  99. });
  100. test('should resolve as custom search delegator', async() => {
  101. const queryString = '[nq:named_query1]';
  102. const parsedQuery = {
  103. queryString,
  104. delegatorName: PRIVATE_LEGACY_PAGES,
  105. };
  106. const [delegator, data] = await searchService.resolve(parsedQuery);
  107. const expectedData = null;
  108. expect(data).toBe(expectedData);
  109. expect(typeof delegator.search).toBe('function');
  110. });
  111. });
  112. describe('searchKeyword()', () => {
  113. test('should search with custom search delegator', async() => {
  114. const Page = mongoose.model('Page');
  115. const User = mongoose.model('User');
  116. await User.insertMany([
  117. { name: 'dummyuser1', username: 'dummyuser1', email: 'dummyuser1@example.com' },
  118. { name: 'dummyuser2', username: 'dummyuser2', email: 'dummyuser2@example.com' },
  119. ]);
  120. const testUser1 = await User.findOne({ username: 'dummyuser1' });
  121. const testUser2 = await User.findOne({ username: 'dummyuser2' });
  122. await Page.insertMany([
  123. {
  124. path: '/user1',
  125. grant: Page.GRANT_PUBLIC,
  126. creator: testUser1,
  127. lastUpdateUser: testUser1,
  128. },
  129. {
  130. path: '/user1_owner',
  131. grant: Page.GRANT_OWNER,
  132. creator: testUser1,
  133. lastUpdateUser: testUser1,
  134. grantedUsers: [testUser1._id],
  135. },
  136. {
  137. path: '/user2_public',
  138. grant: Page.GRANT_PUBLIC,
  139. creator: testUser2,
  140. lastUpdateUser: testUser2,
  141. },
  142. ]);
  143. const page1 = await Page.findOne({ path: '/user1' });
  144. await Page.insertMany([
  145. {
  146. path: '/user1/hasParent',
  147. grant: Page.GRANT_PUBLIC,
  148. creator: testUser1,
  149. lastUpdateUser: testUser1,
  150. parent: page1,
  151. },
  152. ]);
  153. const queryString = '[nq:named_query1]';
  154. const [result, delegatorName] = await searchService.searchKeyword(queryString, testUser1, null, { offset: 0, limit: 100 });
  155. const resultPaths = result.data.map(page => page.path);
  156. const flag = resultPaths.includes('/user1') && resultPaths.includes('/user1_owner') && resultPaths.includes('/user2_public');
  157. expect(flag).toBe(true);
  158. expect(delegatorName).toBe(PRIVATE_LEGACY_PAGES);
  159. });
  160. });
  161. });