Dan Brown

Updated testcases for new search system.

Finishes implementation of new search system.
Closes #271
Closes #344
Fixes #285
Fixes #269
Closes #64
...@@ -219,6 +219,7 @@ class EntityRepo ...@@ -219,6 +219,7 @@ class EntityRepo
219 * @param int $count 219 * @param int $count
220 * @param int $page 220 * @param int $page
221 * @param bool|callable $additionalQuery 221 * @param bool|callable $additionalQuery
222 + * @return Collection
222 */ 223 */
223 public function getRecentlyCreated($type, $count = 20, $page = 0, $additionalQuery = false) 224 public function getRecentlyCreated($type, $count = 20, $page = 0, $additionalQuery = false)
224 { 225 {
...@@ -237,6 +238,7 @@ class EntityRepo ...@@ -237,6 +238,7 @@ class EntityRepo
237 * @param int $count 238 * @param int $count
238 * @param int $page 239 * @param int $page
239 * @param bool|callable $additionalQuery 240 * @param bool|callable $additionalQuery
241 + * @return Collection
240 */ 242 */
241 public function getRecentlyUpdated($type, $count = 20, $page = 0, $additionalQuery = false) 243 public function getRecentlyUpdated($type, $count = 20, $page = 0, $additionalQuery = false)
242 { 244 {
...@@ -330,7 +332,7 @@ class EntityRepo ...@@ -330,7 +332,7 @@ class EntityRepo
330 if ($rawEntity->entity_type === 'BookStack\\Page') { 332 if ($rawEntity->entity_type === 'BookStack\\Page') {
331 $entities[$index] = $this->page->newFromBuilder($rawEntity); 333 $entities[$index] = $this->page->newFromBuilder($rawEntity);
332 if ($renderPages) { 334 if ($renderPages) {
333 - $entities[$index]->html = $rawEntity->description; 335 + $entities[$index]->html = $rawEntity->html;
334 $entities[$index]->html = $this->renderPage($entities[$index]); 336 $entities[$index]->html = $this->renderPage($entities[$index]);
335 }; 337 };
336 } else if ($rawEntity->entity_type === 'BookStack\\Chapter') { 338 } else if ($rawEntity->entity_type === 'BookStack\\Chapter') {
...@@ -357,6 +359,7 @@ class EntityRepo ...@@ -357,6 +359,7 @@ class EntityRepo
357 * Get the child items for a chapter sorted by priority but 359 * Get the child items for a chapter sorted by priority but
358 * with draft items floated to the top. 360 * with draft items floated to the top.
359 * @param Chapter $chapter 361 * @param Chapter $chapter
362 + * @return \Illuminate\Database\Eloquent\Collection|static[]
360 */ 363 */
361 public function getChapterChildren(Chapter $chapter) 364 public function getChapterChildren(Chapter $chapter)
362 { 365 {
...@@ -470,7 +473,7 @@ class EntityRepo ...@@ -470,7 +473,7 @@ class EntityRepo
470 473
471 /** 474 /**
472 * Update entity details from request input. 475 * Update entity details from request input.
473 - * Use for books and chapters 476 + * Used for books and chapters
474 * @param string $type 477 * @param string $type
475 * @param Entity $entityModel 478 * @param Entity $entityModel
476 * @param array $input 479 * @param array $input
......
1 <?php namespace Tests; 1 <?php namespace Tests;
2 2
3 -class EntitySearchTest extends BrowserKitTest 3 +
4 +class EntitySearchTest extends TestCase
4 { 5 {
5 6
6 public function test_page_search() 7 public function test_page_search()
...@@ -8,91 +9,57 @@ class EntitySearchTest extends BrowserKitTest ...@@ -8,91 +9,57 @@ class EntitySearchTest extends BrowserKitTest
8 $book = \BookStack\Book::all()->first(); 9 $book = \BookStack\Book::all()->first();
9 $page = $book->pages->first(); 10 $page = $book->pages->first();
10 11
11 - $this->asAdmin() 12 + $search = $this->asEditor()->get('/search?term=' . urlencode($page->name));
12 - ->visit('/') 13 + $search->assertSee('Search Results');
13 - ->type($page->name, 'term') 14 + $search->assertSee($page->name);
14 - ->press('header-search-box-button')
15 - ->see('Search Results')
16 - ->seeInElement('.entity-list', $page->name)
17 - ->clickInElement('.entity-list', $page->name)
18 - ->seePageIs($page->getUrl());
19 } 15 }
20 16
21 public function test_invalid_page_search() 17 public function test_invalid_page_search()
22 { 18 {
23 - $this->asAdmin() 19 + $resp = $this->asEditor()->get('/search?term=' . urlencode('<p>test</p>'));
24 - ->visit('/') 20 + $resp->assertSee('Search Results');
25 - ->type('<p>test</p>', 'term') 21 + $resp->assertStatus(200);
26 - ->press('header-search-box-button') 22 + $this->get('/search?term=cat+-')->assertStatus(200);
27 - ->see('Search Results')
28 - ->seeStatusCode(200);
29 } 23 }
30 24
31 - public function test_empty_search_redirects_back() 25 + public function test_empty_search_shows_search_page()
32 { 26 {
33 - $this->asAdmin() 27 + $res = $this->asEditor()->get('/search');
34 - ->visit('/') 28 + $res->assertStatus(200);
35 - ->visit('/search/all')
36 - ->seePageIs('/');
37 } 29 }
38 30
39 - public function test_book_search() 31 + public function test_searching_accents_and_small_terms()
40 { 32 {
41 - $book = \BookStack\Book::all()->first(); 33 + $page = $this->newPage(['name' => 'My new test quaffleachits', 'html' => 'some áéííúü¿¡ test content {a2 orange dog']);
42 - $page = $book->pages->last(); 34 + $this->asEditor();
43 - $chapter = $book->chapters->last();
44 35
45 - $this->asAdmin() 36 + $accentSearch = $this->get('/search?term=' . urlencode('áéíí'));
46 - ->visit('/search/book/' . $book->id . '?term=' . urlencode($page->name)) 37 + $accentSearch->assertStatus(200)->assertSee($page->name);
47 - ->see($page->name)
48 38
49 - ->visit('/search/book/' . $book->id . '?term=' . urlencode($chapter->name)) 39 + $smallSearch = $this->get('/search?term=' . urlencode('{a'));
50 - ->see($chapter->name); 40 + $smallSearch->assertStatus(200)->assertSee($page->name);
51 } 41 }
52 42
53 - public function test_empty_book_search_redirects_back() 43 + public function test_book_search()
54 { 44 {
55 $book = \BookStack\Book::all()->first(); 45 $book = \BookStack\Book::all()->first();
56 - $this->asAdmin() 46 + $page = $book->pages->last();
57 - ->visit('/books') 47 + $chapter = $book->chapters->last();
58 - ->visit('/search/book/' . $book->id . '?term=')
59 - ->seePageIs('/books');
60 - }
61 -
62 -
63 - public function test_pages_search_listing()
64 - {
65 - $page = \BookStack\Page::all()->last();
66 - $this->asAdmin()->visit('/search/pages?term=' . $page->name)
67 - ->see('Page Search Results')->see('.entity-list', $page->name);
68 - }
69 48
70 - public function test_chapters_search_listing() 49 + $pageTestResp = $this->asEditor()->get('/search/book/' . $book->id . '?term=' . urlencode($page->name));
71 - { 50 + $pageTestResp->assertSee($page->name);
72 - $chapter = \BookStack\Chapter::all()->last();
73 - $this->asAdmin()->visit('/search/chapters?term=' . $chapter->name)
74 - ->see('Chapter Search Results')->seeInElement('.entity-list', $chapter->name);
75 - }
76 51
77 - public function test_search_quote_term_preparation() 52 + $chapterTestResp = $this->asEditor()->get('/search/book/' . $book->id . '?term=' . urlencode($chapter->name));
78 - { 53 + $chapterTestResp->assertSee($chapter->name);
79 - $termString = '"192" cat "dog hat"';
80 - $repo = $this->app[\BookStack\Repos\EntityRepo::class];
81 - $preparedTerms = $repo->prepareSearchTerms($termString);
82 - $this->assertTrue($preparedTerms === ['"192"','"dog hat"', 'cat']);
83 } 54 }
84 55
85 - public function test_books_search_listing() 56 + public function test_chapter_search()
86 { 57 {
87 - $book = \BookStack\Book::all()->last(); 58 + $chapter = \BookStack\Chapter::has('pages')->first();
88 - $this->asAdmin()->visit('/search/books?term=' . $book->name) 59 + $page = $chapter->pages[0];
89 - ->see('Book Search Results')->see('.entity-list', $book->name);
90 - }
91 60
92 - public function test_searching_hypen_doesnt_break() 61 + $pageTestResp = $this->asEditor()->get('/search/chapter/' . $chapter->id . '?term=' . urlencode($page->name));
93 - { 62 + $pageTestResp->assertSee($page->name);
94 - $this->visit('/search/all?term=cat+-')
95 - ->seeStatusCode(200);
96 } 63 }
97 64
98 public function test_tag_search() 65 public function test_tag_search()
...@@ -114,27 +81,99 @@ class EntitySearchTest extends BrowserKitTest ...@@ -114,27 +81,99 @@ class EntitySearchTest extends BrowserKitTest
114 $pageB = \BookStack\Page::all()->last(); 81 $pageB = \BookStack\Page::all()->last();
115 $pageB->tags()->create(['name' => 'animal', 'value' => 'dog']); 82 $pageB->tags()->create(['name' => 'animal', 'value' => 'dog']);
116 83
117 - $this->asAdmin()->visit('/search/all?term=%5Banimal%5D') 84 + $this->asEditor();
118 - ->seeLink($pageA->name) 85 + $tNameSearch = $this->get('/search?term=%5Banimal%5D');
119 - ->seeLink($pageB->name); 86 + $tNameSearch->assertSee($pageA->name)->assertSee($pageB->name);
120 87
121 - $this->visit('/search/all?term=%5Bcolor%5D') 88 + $tNameSearch2 = $this->get('/search?term=%5Bcolor%5D');
122 - ->seeLink($pageA->name) 89 + $tNameSearch2->assertSee($pageA->name)->assertDontSee($pageB->name);
123 - ->dontSeeLink($pageB->name); 90 +
91 + $tNameValSearch = $this->get('/search?term=%5Banimal%3Dcat%5D');
92 + $tNameValSearch->assertSee($pageA->name)->assertDontSee($pageB->name);
93 + }
94 +
95 + public function test_exact_searches()
96 + {
97 + $page = $this->newPage(['name' => 'My new test page', 'html' => 'this is a story about an orange donkey']);
124 98
125 - $this->visit('/search/all?term=%5Banimal%3Dcat%5D') 99 + $exactSearchA = $this->asEditor()->get('/search?term=' . urlencode('"story about an orange"'));
126 - ->seeLink($pageA->name) 100 + $exactSearchA->assertStatus(200)->assertSee($page->name);
127 - ->dontSeeLink($pageB->name);
128 101
102 + $exactSearchB = $this->asEditor()->get('/search?term=' . urlencode('"story not about an orange"'));
103 + $exactSearchB->assertStatus(200)->assertDontSee($page->name);
104 + }
105 +
106 + public function test_search_filters()
107 + {
108 + $page = $this->newPage(['name' => 'My new test quaffleachits', 'html' => 'this is about an orange donkey danzorbhsing']);
109 + $this->asEditor();
110 + $editorId = $this->getEditor()->id;
111 +
112 + // Viewed filter searches
113 + $this->get('/search?term=' . urlencode('danzorbhsing {not_viewed_by_me}'))->assertSee($page->name);
114 + $this->get('/search?term=' . urlencode('danzorbhsing {viewed_by_me}'))->assertDontSee($page->name);
115 + $this->get($page->getUrl());
116 + $this->get('/search?term=' . urlencode('danzorbhsing {not_viewed_by_me}'))->assertDontSee($page->name);
117 + $this->get('/search?term=' . urlencode('danzorbhsing {viewed_by_me}'))->assertSee($page->name);
118 +
119 + // User filters
120 + $this->get('/search?term=' . urlencode('danzorbhsing {created_by:me}'))->assertDontSee($page->name);
121 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:me}'))->assertDontSee($page->name);
122 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:'.$editorId.'}'))->assertDontSee($page->name);
123 + $page->created_by = $editorId;
124 + $page->save();
125 + $this->get('/search?term=' . urlencode('danzorbhsing {created_by:me}'))->assertSee($page->name);
126 + $this->get('/search?term=' . urlencode('danzorbhsing {created_by:'.$editorId.'}'))->assertSee($page->name);
127 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:me}'))->assertDontSee($page->name);
128 + $page->updated_by = $editorId;
129 + $page->save();
130 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:me}'))->assertSee($page->name);
131 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:'.$editorId.'}'))->assertSee($page->name);
132 +
133 + // Content filters
134 + $this->get('/search?term=' . urlencode('{in_name:danzorbhsing}'))->assertDontSee($page->name);
135 + $this->get('/search?term=' . urlencode('{in_body:danzorbhsing}'))->assertSee($page->name);
136 + $this->get('/search?term=' . urlencode('{in_name:test quaffleachits}'))->assertSee($page->name);
137 + $this->get('/search?term=' . urlencode('{in_body:test quaffleachits}'))->assertDontSee($page->name);
138 +
139 + // Restricted filter
140 + $this->get('/search?term=' . urlencode('danzorbhsing {is_restricted}'))->assertDontSee($page->name);
141 + $page->restricted = true;
142 + $page->save();
143 + $this->get('/search?term=' . urlencode('danzorbhsing {is_restricted}'))->assertSee($page->name);
144 +
145 + // Date filters
146 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_after:2037-01-01}'))->assertDontSee($page->name);
147 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_before:2037-01-01}'))->assertSee($page->name);
148 + $page->updated_at = '2037-02-01';
149 + $page->save();
150 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_after:2037-01-01}'))->assertSee($page->name);
151 + $this->get('/search?term=' . urlencode('danzorbhsing {updated_before:2037-01-01}'))->assertDontSee($page->name);
152 +
153 + $this->get('/search?term=' . urlencode('danzorbhsing {created_after:2037-01-01}'))->assertDontSee($page->name);
154 + $this->get('/search?term=' . urlencode('danzorbhsing {created_before:2037-01-01}'))->assertSee($page->name);
155 + $page->created_at = '2037-02-01';
156 + $page->save();
157 + $this->get('/search?term=' . urlencode('danzorbhsing {created_after:2037-01-01}'))->assertSee($page->name);
158 + $this->get('/search?term=' . urlencode('danzorbhsing {created_before:2037-01-01}'))->assertDontSee($page->name);
129 } 159 }
130 160
131 public function test_ajax_entity_search() 161 public function test_ajax_entity_search()
132 { 162 {
133 $page = \BookStack\Page::all()->last(); 163 $page = \BookStack\Page::all()->last();
134 $notVisitedPage = \BookStack\Page::first(); 164 $notVisitedPage = \BookStack\Page::first();
135 - $this->visit($page->getUrl()); 165 +
136 - $this->asAdmin()->visit('/ajax/search/entities?term=' . $page->name)->see('.entity-list', $page->name); 166 + // Visit the page to make popular
137 - $this->asAdmin()->visit('/ajax/search/entities?types=book&term=' . $page->name)->dontSee('.entity-list', $page->name); 167 + $this->asEditor()->get($page->getUrl());
138 - $this->asAdmin()->visit('/ajax/search/entities')->see('.entity-list', $page->name)->dontSee($notVisitedPage->name); 168 +
169 + $normalSearch = $this->get('/ajax/search/entities?term=' . urlencode($page->name));
170 + $normalSearch->assertSee($page->name);
171 +
172 + $bookSearch = $this->get('/ajax/search/entities?types=book&term=' . urlencode($page->name));
173 + $bookSearch->assertDontSee($page->name);
174 +
175 + $defaultListTest = $this->get('/ajax/search/entities');
176 + $defaultListTest->assertSee($page->name);
177 + $defaultListTest->assertDontSee($notVisitedPage->name);
139 } 178 }
140 } 179 }
......
...@@ -76,4 +76,16 @@ abstract class TestCase extends BaseTestCase ...@@ -76,4 +76,16 @@ abstract class TestCase extends BaseTestCase
76 public function newChapter($input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book) { 76 public function newChapter($input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book) {
77 return $this->app[EntityRepo::class]->createFromInput('chapter', $input, $book); 77 return $this->app[EntityRepo::class]->createFromInput('chapter', $input, $book);
78 } 78 }
79 +
80 + /**
81 + * Create and return a new test page
82 + * @param array $input
83 + * @return Chapter
84 + */
85 + public function newPage($input = ['name' => 'test page', 'html' => 'My new test page']) {
86 + $book = Book::first();
87 + $entityRepo = $this->app[EntityRepo::class];
88 + $draftPage = $entityRepo->getDraftPage($book);
89 + return $entityRepo->publishPageDraft($draftPage, $input);
90 + }
79 } 91 }
...\ No newline at end of file ...\ No newline at end of file
......