]> BookStack Code Mirror - bookstack/blob - tests/Entity/PageRevisionTest.php
Merge branch 'development' of github.com:BookStackApp/BookStack into development
[bookstack] / tests / Entity / PageRevisionTest.php
1 <?php
2
3 namespace Tests\Entity;
4
5 use BookStack\Activity\ActivityType;
6 use BookStack\Entities\Models\Page;
7 use Tests\TestCase;
8
9 class PageRevisionTest extends TestCase
10 {
11     public function test_revision_links_visible_to_viewer()
12     {
13         $page = $this->entities->page();
14
15         $html = $this->withHtml($this->asViewer()->get($page->getUrl()));
16         $html->assertLinkExists($page->getUrl('/revisions'));
17         $html->assertElementContains('a', 'Revisions');
18         $html->assertElementContains('a', 'Revision #1');
19     }
20
21     public function test_page_revision_views_viewable()
22     {
23         $this->asEditor();
24         $page = $this->entities->page();
25         $this->createRevisions($page, 1, ['name' => 'updated page', 'html' => '<p>new content</p>']);
26         $pageRevision = $page->revisions->last();
27
28         $resp = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id);
29         $resp->assertStatus(200);
30         $resp->assertSee('new content');
31
32         $resp = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id . '/changes');
33         $resp->assertStatus(200);
34         $resp->assertSee('new content');
35     }
36
37     public function test_page_revision_preview_shows_content_of_revision()
38     {
39         $this->asEditor();
40         $page = $this->entities->page();
41         $this->createRevisions($page, 1, ['name' => 'updated page', 'html' => '<p>new revision content</p>']);
42         $pageRevision = $page->revisions->last();
43         $this->createRevisions($page, 1, ['name' => 'updated page', 'html' => '<p>Updated content</p>']);
44
45         $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id);
46         $revisionView->assertStatus(200);
47         $revisionView->assertSee('new revision content');
48     }
49
50     public function test_page_revision_restore_updates_content()
51     {
52         $this->asEditor();
53         $page = $this->entities->page();
54         $this->createRevisions($page, 1, ['name' => 'updated page abc123', 'html' => '<p>new contente def456</p>']);
55         $this->createRevisions($page, 1, ['name' => 'updated page again', 'html' => '<p>new content</p>']);
56         $page = Page::find($page->id);
57
58         $pageView = $this->get($page->getUrl());
59         $pageView->assertDontSee('abc123');
60         $pageView->assertDontSee('def456');
61
62         $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
63         $restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
64         $page = Page::find($page->id);
65
66         $restoreReq->assertStatus(302);
67         $restoreReq->assertRedirect($page->getUrl());
68
69         $pageView = $this->get($page->getUrl());
70         $pageView->assertSee('abc123');
71         $pageView->assertSee('def456');
72     }
73
74     public function test_page_revision_restore_with_markdown_retains_markdown_content()
75     {
76         $this->asEditor();
77         $page = $this->entities->page();
78         $this->createRevisions($page, 1, ['name' => 'updated page abc123', 'markdown' => '## New Content def456']);
79         $this->createRevisions($page, 1, ['name' => 'updated page again', 'markdown' => '## New Content Updated']);
80         $page = Page::find($page->id);
81
82         $pageView = $this->get($page->getUrl());
83         $pageView->assertDontSee('abc123');
84         $pageView->assertDontSee('def456');
85
86         $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
87         $restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
88         $page = Page::find($page->id);
89
90         $restoreReq->assertStatus(302);
91         $restoreReq->assertRedirect($page->getUrl());
92
93         $pageView = $this->get($page->getUrl());
94         $this->assertDatabaseHas('pages', [
95             'id'       => $page->id,
96             'markdown' => '## New Content def456',
97         ]);
98         $pageView->assertSee('abc123');
99         $pageView->assertSee('def456');
100     }
101
102     public function test_page_revision_restore_sets_new_revision_with_summary()
103     {
104         $this->asEditor();
105         $page = $this->entities->page();
106         $this->createRevisions($page, 1, ['name' => 'updated page abc123', 'html' => '<p>new contente def456</p>', 'summary' => 'My first update']);
107         $this->createRevisions($page, 1, ['html' => '<p>new content</p>']);
108         $page->refresh();
109
110         $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
111         $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
112         $page->refresh();
113
114         $this->assertDatabaseHas('page_revisions', [
115             'page_id' => $page->id,
116             'text'    => 'new contente def456',
117             'type'    => 'version',
118             'summary' => "Restored from #{$revToRestore->id}; My first update",
119         ]);
120
121         $detail = "Revision #{$revToRestore->revision_number} (ID: {$revToRestore->id}) for page ID {$revToRestore->page_id}";
122         $this->assertActivityExists(ActivityType::REVISION_RESTORE, null, $detail);
123     }
124
125     public function test_page_revision_count_increments_on_update()
126     {
127         $page = $this->entities->page();
128         $startCount = $page->revision_count;
129         $this->createRevisions($page, 1);
130
131         $this->assertTrue(Page::find($page->id)->revision_count === $startCount + 1);
132     }
133
134     public function test_revision_count_shown_in_page_meta()
135     {
136         $page = $this->entities->page();
137         $this->createRevisions($page, 2);
138
139         $pageView = $this->asViewer()->get($page->getUrl());
140         $pageView->assertSee('Revision #' . $page->revision_count);
141     }
142
143     public function test_revision_deletion()
144     {
145         $page = $this->entities->page();
146         $this->createRevisions($page, 2);
147         $beforeRevisionCount = $page->revisions->count();
148
149         // Delete the first revision
150         $revision = $page->revisions->get(1);
151         $resp = $this->asEditor()->delete($revision->getUrl('/delete/'));
152         $resp->assertRedirect($page->getUrl('/revisions'));
153
154         $page->refresh();
155         $afterRevisionCount = $page->revisions->count();
156
157         $this->assertTrue($beforeRevisionCount === ($afterRevisionCount + 1));
158
159         $detail = "Revision #{$revision->revision_number} (ID: {$revision->id}) for page ID {$revision->page_id}";
160         $this->assertActivityExists(ActivityType::REVISION_DELETE, null, $detail);
161
162         // Try to delete the latest revision
163         $beforeRevisionCount = $page->revisions->count();
164         $resp = $this->asEditor()->delete($page->currentRevision->getUrl('/delete/'));
165         $resp->assertRedirect($page->getUrl('/revisions'));
166
167         $page->refresh();
168         $afterRevisionCount = $page->revisions->count();
169         $this->assertTrue($beforeRevisionCount === $afterRevisionCount);
170     }
171
172     public function test_revision_limit_enforced()
173     {
174         config()->set('app.revision_limit', 2);
175         $page = $this->entities->page();
176         $this->createRevisions($page, 12);
177
178         $revisionCount = $page->revisions()->count();
179         $this->assertEquals(2, $revisionCount);
180     }
181
182     public function test_false_revision_limit_allows_many_revisions()
183     {
184         config()->set('app.revision_limit', false);
185         $page = $this->entities->page();
186         $this->createRevisions($page, 12);
187
188         $revisionCount = $page->revisions()->count();
189         $this->assertEquals(12, $revisionCount);
190     }
191
192     public function test_revision_list_shows_editor_type()
193     {
194         $page = $this->entities->page();
195         $this->createRevisions($page, 1, ['html' => 'new page html']);
196
197         $resp = $this->asAdmin()->get($page->refresh()->getUrl('/revisions'));
198         $this->withHtml($resp)->assertElementContains('.item-list-row > div:nth-child(2)', 'WYSIWYG)');
199         $this->withHtml($resp)->assertElementNotContains('.item-list-row > div:nth-child(2)', 'Markdown)');
200
201         $this->createRevisions($page, 1, ['markdown' => '# Some markdown content']);
202         $resp = $this->get($page->refresh()->getUrl('/revisions'));
203         $this->withHtml($resp)->assertElementContains('.item-list-row > div:nth-child(2)', 'Markdown)');
204     }
205
206     public function test_revision_changes_link_not_shown_for_oldest_revision()
207     {
208         $page = $this->entities->page();
209         $this->createRevisions($page, 3, ['html' => 'new page html']);
210
211         $resp = $this->asAdmin()->get($page->refresh()->getUrl('/revisions'));
212         $html = $this->withHtml($resp);
213
214         $html->assertElementNotExists('.item-list > .item-list-row:last-child a[href*="/changes"]');
215         $html->assertElementContains('.item-list > .item-list-row:nth-child(2)', 'Changes');
216     }
217
218     public function test_revision_restore_action_only_visible_with_permission()
219     {
220         $page = $this->entities->page();
221         $this->createRevisions($page, 2);
222
223         $viewer = $this->users->viewer();
224         $this->actingAs($viewer);
225         $respHtml = $this->withHtml($this->get($page->getUrl('/revisions')));
226         $respHtml->assertElementNotContains('.actions a', 'Restore');
227         $respHtml->assertElementNotExists('form[action$="/restore"]');
228
229         $this->permissions->grantUserRolePermissions($viewer, ['page-update-all']);
230
231         $respHtml = $this->withHtml($this->get($page->getUrl('/revisions')));
232         $respHtml->assertElementContains('.actions a', 'Restore');
233         $respHtml->assertElementExists('form[action$="/restore"]');
234     }
235
236     public function test_revision_delete_action_only_visible_with_permission()
237     {
238         $page = $this->entities->page();
239         $this->createRevisions($page, 2);
240
241         $viewer = $this->users->viewer();
242         $this->actingAs($viewer);
243         $respHtml = $this->withHtml($this->get($page->getUrl('/revisions')));
244         $respHtml->assertElementNotContains('.actions a', 'Delete');
245         $respHtml->assertElementNotExists('form[action$="/delete"]');
246
247         $this->permissions->grantUserRolePermissions($viewer, ['page-delete-all']);
248
249         $respHtml = $this->withHtml($this->get($page->getUrl('/revisions')));
250         $respHtml->assertElementContains('.actions a', 'Delete');
251         $respHtml->assertElementExists('form[action$="/delete"]');
252     }
253
254     protected function createRevisions(Page $page, int $times, array $attrs = [])
255     {
256         $user = user();
257
258         for ($i = 0; $i < $times; $i++) {
259             $data = ['name' => 'Page update' . $i, 'summary' => 'Update entry' . $i];
260             if (!isset($attrs['markdown'])) {
261                 $data['html'] = '<p>My update page</p>';
262             }
263             $this->asAdmin()->put($page->getUrl(), array_merge($data, $attrs));
264             $page->refresh();
265         }
266
267         $this->actingAs($user);
268     }
269 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.