3 namespace Tests\References;
5 use BookStack\App\Model;
6 use BookStack\Entities\Repos\PageRepo;
7 use BookStack\Entities\Tools\TrashCan;
8 use BookStack\References\Reference;
11 class ReferencesTest extends TestCase
13 public function test_references_created_on_page_update()
15 $pageA = $this->entities->page();
16 $pageB = $this->entities->page();
18 $this->assertDatabaseMissing('references', ['from_id' => $pageA->id, 'from_type' => $pageA->getMorphClass()]);
20 $this->asEditor()->put($pageA->getUrl(), [
21 'name' => 'Reference test',
22 'html' => '<a href="' . $pageB->getUrl() . '">Testing</a>',
25 $this->assertDatabaseHas('references', [
26 'from_id' => $pageA->id,
27 'from_type' => $pageA->getMorphClass(),
28 'to_id' => $pageB->id,
29 'to_type' => $pageB->getMorphClass(),
33 public function test_references_created_on_book_chapter_bookshelf_update()
35 $entities = [$this->entities->book(), $this->entities->chapter(), $this->entities->shelf()];
36 $shelf = $this->entities->shelf();
38 foreach ($entities as $entity) {
40 $this->assertDatabaseMissing('references', ['from_id' => $entity->id, 'from_type' => $entity->getMorphClass()]);
42 $this->asEditor()->put($entity->getUrl(), [
43 'name' => 'Reference test',
44 'description_html' => '<a href="' . $shelf->getUrl() . '">Testing</a>',
47 $this->assertDatabaseHas('references', [
48 'from_id' => $entity->id,
49 'from_type' => $entity->getMorphClass(),
50 'to_id' => $shelf->id,
51 'to_type' => $shelf->getMorphClass(),
56 public function test_references_deleted_on_page_delete()
58 $pageA = $this->entities->page();
59 $pageB = $this->entities->page();
61 $this->createReference($pageA, $pageB);
62 $this->createReference($pageB, $pageA);
64 $this->assertDatabaseHas('references', ['from_id' => $pageA->id, 'from_type' => $pageA->getMorphClass()]);
65 $this->assertDatabaseHas('references', ['to_id' => $pageA->id, 'to_type' => $pageA->getMorphClass()]);
67 app(PageRepo::class)->destroy($pageA);
68 app(TrashCan::class)->empty();
70 $this->assertDatabaseMissing('references', ['from_id' => $pageA->id, 'from_type' => $pageA->getMorphClass()]);
71 $this->assertDatabaseMissing('references', ['to_id' => $pageA->id, 'to_type' => $pageA->getMorphClass()]);
74 public function test_references_from_deleted_on_book_chapter_shelf_delete()
76 $entities = [$this->entities->chapter(), $this->entities->book(), $this->entities->shelf()];
77 $shelf = $this->entities->shelf();
79 foreach ($entities as $entity) {
80 $this->createReference($entity, $shelf);
81 $this->assertDatabaseHas('references', ['from_id' => $entity->id, 'from_type' => $entity->getMorphClass()]);
83 $this->asEditor()->delete($entity->getUrl());
84 app(TrashCan::class)->empty();
86 $this->assertDatabaseMissing('references', [
87 'from_id' => $entity->id,
88 'from_type' => $entity->getMorphClass()
93 public function test_references_to_count_visible_on_entity_show_view()
95 $entities = $this->entities->all();
96 $otherPage = $this->entities->page();
99 foreach ($entities as $entity) {
100 $this->createReference($entities['page'], $entity);
103 foreach ($entities as $entity) {
104 $resp = $this->get($entity->getUrl());
105 $resp->assertSee('Referenced by 1 item');
106 $resp->assertDontSee('Referenced by 1 items');
109 $this->createReference($otherPage, $entities['page']);
110 $resp = $this->get($entities['page']->getUrl());
111 $resp->assertSee('Referenced by 2 items');
114 public function test_references_to_visible_on_references_page()
116 $entities = $this->entities->all();
118 foreach ($entities as $entity) {
119 $this->createReference($entities['page'], $entity);
122 foreach ($entities as $entity) {
123 $resp = $this->get($entity->getUrl('/references'));
124 $resp->assertSee('References');
125 $resp->assertSee($entities['page']->name);
126 $resp->assertDontSee('There are no tracked references');
130 public function test_reference_not_visible_if_view_permission_does_not_permit()
132 $page = $this->entities->page();
133 $pageB = $this->entities->page();
134 $this->createReference($pageB, $page);
136 $this->permissions->setEntityPermissions($pageB);
138 $this->asEditor()->get($page->getUrl('/references'))->assertDontSee($pageB->name);
139 $this->asAdmin()->get($page->getUrl('/references'))->assertSee($pageB->name);
142 public function test_reference_page_shows_empty_state_with_no_references()
144 $page = $this->entities->page();
147 ->get($page->getUrl('/references'))
148 ->assertSee('There are no tracked references');
151 public function test_pages_leading_to_entity_updated_on_url_change()
153 $pageA = $this->entities->page();
154 $pageB = $this->entities->page();
155 $book = $this->entities->book();
157 foreach ([$pageA, $pageB] as $page) {
158 $page->html = '<a href="' . $book->getUrl() . '">Link</a>';
160 $this->createReference($page, $book);
163 $this->asEditor()->put($book->getUrl(), [
164 'name' => 'my updated book slugaroo',
167 foreach ([$pageA, $pageB] as $page) {
169 $this->assertStringContainsString('href="http://localhost/books/my-updated-book-slugaroo"', $page->html);
170 $this->assertDatabaseHas('page_revisions', [
171 'page_id' => $page->id,
172 'summary' => 'System auto-update of internal links',
177 public function test_pages_linking_to_other_page_updated_on_parent_book_url_change()
179 $bookPage = $this->entities->page();
180 $otherPage = $this->entities->page();
181 $book = $bookPage->book;
183 $otherPage->html = '<a href="' . $bookPage->getUrl() . '">Link</a>';
185 $this->createReference($otherPage, $bookPage);
187 $this->asEditor()->put($book->getUrl(), [
188 'name' => 'my updated book slugaroo',
191 $otherPage->refresh();
192 $this->assertStringContainsString('href="http://localhost/books/my-updated-book-slugaroo/page/' . $bookPage->slug . '"', $otherPage->html);
193 $this->assertDatabaseHas('page_revisions', [
194 'page_id' => $otherPage->id,
195 'summary' => 'System auto-update of internal links',
199 public function test_pages_linking_to_chapter_updated_on_parent_book_url_change()
201 $bookChapter = $this->entities->chapter();
202 $otherPage = $this->entities->page();
203 $book = $bookChapter->book;
205 $otherPage->html = '<a href="' . $bookChapter->getUrl() . '">Link</a>';
207 $this->createReference($otherPage, $bookChapter);
209 $this->asEditor()->put($book->getUrl(), [
210 'name' => 'my updated book slugaroo',
213 $otherPage->refresh();
214 $this->assertStringContainsString('href="http://localhost/books/my-updated-book-slugaroo/chapter/' . $bookChapter->slug . '"', $otherPage->html);
215 $this->assertDatabaseHas('page_revisions', [
216 'page_id' => $otherPage->id,
217 'summary' => 'System auto-update of internal links',
221 public function test_markdown_links_leading_to_entity_updated_on_url_change()
223 $page = $this->entities->page();
224 $book = $this->entities->book();
226 $bookUrl = $book->getUrl();
228 [An awesome link](' . $bookUrl . ')
229 [An awesome link with query & hash](' . $bookUrl . '?test=yes#cats)
230 [An awesome link with path](' . $bookUrl . '/an/extra/trail)
231 [An awesome link with title](' . $bookUrl . ' "title")
232 [ref]: ' . $bookUrl . '?test=yes#dogs
233 [ref_without_space]:' . $bookUrl . '
234 [ref_with_title]: ' . $bookUrl . ' "title"';
235 $page->markdown = $markdown;
237 $this->createReference($page, $book);
239 $this->asEditor()->put($book->getUrl(), [
240 'name' => 'my updated book slugadoo',
244 $expected = str_replace($bookUrl, 'http://localhost/books/my-updated-book-slugadoo', $markdown);
245 $this->assertEquals($expected, $page->markdown);
248 public function test_description_links_from_book_chapter_shelf_updated_on_url_change()
250 $entities = [$this->entities->chapter(), $this->entities->book(), $this->entities->shelf()];
251 $shelf = $this->entities->shelf();
254 foreach ($entities as $entity) {
255 $this->put($entity->getUrl(), [
256 'name' => 'Reference test',
257 'description_html' => '<a href="' . $shelf->getUrl() . '">Testing</a>',
261 $oldUrl = $shelf->getUrl();
262 $this->put($shelf->getUrl(), ['name' => 'My updated shelf link']);
264 $this->assertNotEquals($oldUrl, $shelf->getUrl());
266 foreach ($entities as $entity) {
267 $oldHtml = $entity->description_html;
269 $this->assertNotEquals($oldHtml, $entity->description_html);
270 $this->assertStringContainsString($shelf->getUrl(), $entity->description_html);
274 protected function createReference(Model $from, Model $to)
276 (new Reference())->forceFill([
277 'from_type' => $from->getMorphClass(),
278 'from_id' => $from->id,
279 'to_type' => $to->getMorphClass(),