]> BookStack Code Mirror - bookstack/blob - tests/Entity/PageDraftTest.php
acf6b01e894950f5ada5f75d3f0a5ac54c96ec50
[bookstack] / tests / Entity / PageDraftTest.php
1 <?php
2
3 namespace Tests\Entity;
4
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Page;
7 use BookStack\Entities\Models\PageRevision;
8 use BookStack\Entities\Repos\PageRepo;
9 use Tests\TestCase;
10
11 class PageDraftTest extends TestCase
12 {
13     /**
14      * @var Page
15      */
16     protected $page;
17
18     /**
19      * @var PageRepo
20      */
21     protected $pageRepo;
22
23     protected function setUp(): void
24     {
25         parent::setUp();
26         $this->page = Page::query()->first();
27         $this->pageRepo = app()->make(PageRepo::class);
28     }
29
30     public function test_draft_content_shows_if_available()
31     {
32         $addedContent = '<p>test message content</p>';
33
34         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
35         $this->withHtml($resp)->assertElementNotContains('[name="html"]', $addedContent);
36
37         $newContent = $this->page->html . $addedContent;
38         $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]);
39         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
40         $this->withHtml($resp)->assertElementContains('[name="html"]', $newContent);
41     }
42
43     public function test_draft_not_visible_by_others()
44     {
45         $addedContent = '<p>test message content</p>';
46         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
47         $this->withHtml($resp)->assertElementNotContains('[name="html"]', $addedContent);
48
49         $newContent = $this->page->html . $addedContent;
50         $newUser = $this->getEditor();
51         $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]);
52
53         $resp = $this->actingAs($newUser)->get($this->page->getUrl('/edit'));
54         $this->withHtml($resp)->assertElementNotContains('[name="html"]', $newContent);
55     }
56
57     public function test_alert_message_shows_if_editing_draft()
58     {
59         $this->asAdmin();
60         $this->pageRepo->updatePageDraft($this->page, ['html' => 'test content']);
61         $this->asAdmin()->get($this->page->getUrl('/edit'))
62             ->assertSee('You are currently editing a draft');
63     }
64
65     public function test_alert_message_shows_if_someone_else_editing()
66     {
67         $nonEditedPage = Page::query()->take(10)->get()->last();
68         $addedContent = '<p>test message content</p>';
69         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
70         $this->withHtml($resp)->assertElementNotContains('[name="html"]', $addedContent);
71
72         $newContent = $this->page->html . $addedContent;
73         $newUser = $this->getEditor();
74         $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]);
75
76         $this->actingAs($newUser)
77             ->get($this->page->getUrl('/edit'))
78             ->assertSee('Admin has started editing this page');
79         $this->flushSession();
80         $resp = $this->get($nonEditedPage->getUrl() . '/edit');
81         $this->withHtml($resp)->assertElementNotContains('.notification', 'Admin has started editing this page');
82     }
83
84     public function test_draft_save_shows_alert_if_draft_older_than_last_page_update()
85     {
86         $admin = $this->getAdmin();
87         $editor = $this->getEditor();
88         $page = $this->entities->page();
89
90         $this->actingAs($editor)->put('/ajax/page/' . $page->id . '/save-draft', [
91             'name' => $page->name,
92             'html' => '<p>updated draft</p>',
93         ]);
94
95         /** @var PageRevision $draft */
96         $draft = $page->allRevisions()
97             ->where('type', '=', 'update_draft')
98             ->where('created_by', '=', $editor->id)
99             ->first();
100         $draft->created_at = now()->subMinute(1);
101         $draft->save();
102
103         $this->actingAs($admin)->put($page->refresh()->getUrl(), [
104             'name' => $page->name,
105             'html' => '<p>admin update</p>',
106         ]);
107
108         $resp = $this->actingAs($editor)->put('/ajax/page/' . $page->id . '/save-draft', [
109             'name' => $page->name,
110             'html' => '<p>updated draft again</p>',
111         ]);
112
113         $resp->assertJson([
114             'warning' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
115         ]);
116     }
117
118     public function test_draft_save_shows_alert_if_draft_edit_started_by_someone_else()
119     {
120         $admin = $this->getAdmin();
121         $editor = $this->getEditor();
122         $page = $this->entities->page();
123
124         $this->actingAs($admin)->put('/ajax/page/' . $page->id . '/save-draft', [
125             'name' => $page->name,
126             'html' => '<p>updated draft</p>',
127         ]);
128
129         $resp = $this->actingAs($editor)->put('/ajax/page/' . $page->id . '/save-draft', [
130             'name' => $page->name,
131             'html' => '<p>updated draft again</p>',
132         ]);
133
134         $resp->assertJson([
135             'warning' => 'Admin has started editing this page in the last 60 minutes. Take care not to overwrite each other\'s updates!',
136         ]);
137     }
138
139     public function test_draft_pages_show_on_homepage()
140     {
141         $book = $this->entities->book();
142         $resp = $this->asAdmin()->get('/');
143         $this->withHtml($resp)->assertElementNotContains('#recent-drafts', 'New Page');
144
145         $this->get($book->getUrl() . '/create-page');
146
147         $this->withHtml($this->get('/'))->assertElementContains('#recent-drafts', 'New Page');
148     }
149
150     public function test_draft_pages_not_visible_by_others()
151     {
152         $book = $this->entities->book();
153         $chapter = $book->chapters->first();
154         $newUser = $this->getEditor();
155
156         $this->actingAs($newUser)->get($book->getUrl('/create-page'));
157         $this->get($chapter->getUrl('/create-page'));
158         $resp = $this->get($book->getUrl());
159         $this->withHtml($resp)->assertElementContains('.book-contents', 'New Page');
160
161         $resp = $this->asAdmin()->get($book->getUrl());
162         $this->withHtml($resp)->assertElementNotContains('.book-contents', 'New Page');
163         $resp = $this->get($chapter->getUrl());
164         $this->withHtml($resp)->assertElementNotContains('.book-contents', 'New Page');
165     }
166
167     public function test_page_html_in_ajax_fetch_response()
168     {
169         $this->asAdmin();
170         $page = $this->entities->page();
171
172         $this->getJson('/ajax/page/' . $page->id)->assertJson([
173             'html' => $page->html,
174         ]);
175     }
176
177     public function test_updating_page_draft_with_markdown_retains_markdown_content()
178     {
179         $book = $this->entities->book();
180         $this->asEditor()->get($book->getUrl('/create-page'));
181         /** @var Page $draft */
182         $draft = Page::query()->where('draft', '=', true)->where('book_id', '=', $book->id)->firstOrFail();
183
184         $resp = $this->put('/ajax/page/' . $draft->id . '/save-draft', [
185             'name'     => 'My updated draft',
186             'markdown' => "# My markdown page\n\n[A link](https://example.com)",
187             'html'     => '<p>checking markdown takes priority over this</p>',
188         ]);
189         $resp->assertOk();
190
191         $this->assertDatabaseHas('pages', [
192             'id'       => $draft->id,
193             'draft'    => true,
194             'name'     => 'My updated draft',
195             'markdown' => "# My markdown page\n\n[A link](https://example.com)",
196         ]);
197
198         $draft->refresh();
199         $this->assertStringContainsString('href="https://example.com"', $draft->html);
200     }
201
202     public function test_slug_generated_on_draft_publish_to_page_when_no_name_change()
203     {
204         $book = $this->entities->book();
205         $this->asEditor()->get($book->getUrl('/create-page'));
206         /** @var Page $draft */
207         $draft = Page::query()->where('draft', '=', true)->where('book_id', '=', $book->id)->firstOrFail();
208
209         $this->put('/ajax/page/' . $draft->id . '/save-draft', [
210             'name'     => 'My page',
211             'markdown' => 'Update test',
212         ])->assertOk();
213
214         $draft->refresh();
215         $this->assertEmpty($draft->slug);
216
217         $this->post($draft->getUrl(), [
218             'name'     => 'My page',
219             'markdown' => '# My markdown page',
220         ]);
221
222         $this->assertDatabaseHas('pages', [
223             'id'    => $draft->id,
224             'draft' => false,
225             'slug'  => 'my-page',
226         ]);
227     }
228 }