3 namespace Tests\Entity;
5 use BookStack\Actions\ActivityType;
6 use BookStack\Entities\Models\Page;
7 use BookStack\Entities\Repos\PageRepo;
10 class PageRevisionTest extends TestCase
13 public function test_revision_links_visible_to_viewer()
15 /** @var Page $page */
16 $page = Page::query()->first();
18 $html = $this->withHtml($this->asViewer()->get($page->getUrl()));
19 $html->assertLinkExists($page->getUrl('/revisions'));
20 $html->assertElementContains('a', 'Revisions');
21 $html->assertElementContains('a', 'Revision #1');
24 public function test_page_revision_views_viewable()
28 $pageRepo = app(PageRepo::class);
29 $page = Page::first();
30 $pageRepo->update($page, ['name' => 'updated page', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
31 $pageRevision = $page->revisions->last();
33 $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id);
34 $revisionView->assertStatus(200);
35 $revisionView->assertSee('new content');
37 $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id . '/changes');
38 $revisionView->assertStatus(200);
39 $revisionView->assertSee('new content');
42 public function test_page_revision_preview_shows_content_of_revision()
46 $pageRepo = app(PageRepo::class);
47 $page = Page::first();
48 $pageRepo->update($page, ['name' => 'updated page', 'html' => '<p>new revision content</p>', 'summary' => 'page revision testing']);
49 $pageRevision = $page->revisions->last();
50 $pageRepo->update($page, ['name' => 'updated page', 'html' => '<p>Updated content</p>', 'summary' => 'page revision testing 2']);
52 $revisionView = $this->get($page->getUrl() . '/revisions/' . $pageRevision->id);
53 $revisionView->assertStatus(200);
54 $revisionView->assertSee('new revision content');
57 public function test_page_revision_restore_updates_content()
61 $pageRepo = app(PageRepo::class);
62 $page = Page::first();
63 $pageRepo->update($page, ['name' => 'updated page abc123', 'html' => '<p>new contente def456</p>', 'summary' => 'initial page revision testing']);
64 $pageRepo->update($page, ['name' => 'updated page again', 'html' => '<p>new content</p>', 'summary' => 'page revision testing']);
65 $page = Page::find($page->id);
67 $pageView = $this->get($page->getUrl());
68 $pageView->assertDontSee('abc123');
69 $pageView->assertDontSee('def456');
71 $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
72 $restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
73 $page = Page::find($page->id);
75 $restoreReq->assertStatus(302);
76 $restoreReq->assertRedirect($page->getUrl());
78 $pageView = $this->get($page->getUrl());
79 $pageView->assertSee('abc123');
80 $pageView->assertSee('def456');
83 public function test_page_revision_restore_with_markdown_retains_markdown_content()
87 $pageRepo = app(PageRepo::class);
88 $page = Page::first();
89 $pageRepo->update($page, ['name' => 'updated page abc123', 'markdown' => '## New Content def456', 'summary' => 'initial page revision testing']);
90 $pageRepo->update($page, ['name' => 'updated page again', 'markdown' => '## New Content Updated', 'summary' => 'page revision testing']);
91 $page = Page::find($page->id);
93 $pageView = $this->get($page->getUrl());
94 $pageView->assertDontSee('abc123');
95 $pageView->assertDontSee('def456');
97 $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
98 $restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
99 $page = Page::find($page->id);
101 $restoreReq->assertStatus(302);
102 $restoreReq->assertRedirect($page->getUrl());
104 $pageView = $this->get($page->getUrl());
105 $this->assertDatabaseHas('pages', [
107 'markdown' => '## New Content def456',
109 $pageView->assertSee('abc123');
110 $pageView->assertSee('def456');
113 public function test_page_revision_restore_sets_new_revision_with_summary()
117 $pageRepo = app(PageRepo::class);
118 $page = Page::first();
119 $pageRepo->update($page, ['name' => 'updated page abc123', 'html' => '<p>new contente def456</p>', 'summary' => 'My first update']);
120 $pageRepo->update($page, ['name' => 'updated page again', 'html' => '<p>new content</p>', 'summary' => '']);
123 $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
124 $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
127 $this->assertDatabaseHas('page_revisions', [
128 'page_id' => $page->id,
129 'text' => 'new contente def456',
131 'summary' => "Restored from #{$revToRestore->id}; My first update",
134 $detail = "Revision #{$revToRestore->revision_number} (ID: {$revToRestore->id}) for page ID {$revToRestore->page_id}";
135 $this->assertActivityExists(ActivityType::REVISION_RESTORE, null, $detail);
138 public function test_page_revision_count_increments_on_update()
140 $page = Page::first();
141 $startCount = $page->revision_count;
142 $resp = $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
143 $resp->assertStatus(302);
145 $this->assertTrue(Page::find($page->id)->revision_count === $startCount + 1);
148 public function test_revision_count_shown_in_page_meta()
150 $page = Page::first();
151 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
153 $page = Page::find($page->id);
154 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
156 $page = Page::find($page->id);
157 $pageView = $this->get($page->getUrl());
158 $pageView->assertSee('Revision #' . $page->revision_count);
161 public function test_revision_deletion()
163 /** @var Page $page */
164 $page = Page::query()->first();
165 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
168 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
171 $beforeRevisionCount = $page->revisions->count();
173 // Delete the first revision
174 $revision = $page->revisions->get(1);
175 $resp = $this->asEditor()->delete($revision->getUrl('/delete/'));
176 $resp->assertRedirect($page->getUrl('/revisions'));
179 $afterRevisionCount = $page->revisions->count();
181 $this->assertTrue($beforeRevisionCount === ($afterRevisionCount + 1));
183 $detail = "Revision #{$revision->revision_number} (ID: {$revision->id}) for page ID {$revision->page_id}";
184 $this->assertActivityExists(ActivityType::REVISION_DELETE, null, $detail);
186 // Try to delete the latest revision
187 $beforeRevisionCount = $page->revisions->count();
188 $resp = $this->asEditor()->delete($page->currentRevision->getUrl('/delete/'));
189 $resp->assertRedirect($page->getUrl('/revisions'));
192 $afterRevisionCount = $page->revisions->count();
193 $this->assertTrue($beforeRevisionCount === $afterRevisionCount);
196 public function test_revision_limit_enforced()
198 config()->set('app.revision_limit', 2);
199 $page = Page::first();
200 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
201 $page = Page::find($page->id);
202 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
203 for ($i = 0; $i < 10; $i++) {
204 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
207 $revisionCount = $page->revisions()->count();
208 $this->assertEquals(2, $revisionCount);
211 public function test_false_revision_limit_allows_many_revisions()
213 config()->set('app.revision_limit', false);
214 $page = Page::first();
215 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
216 $page = Page::find($page->id);
217 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
218 for ($i = 0; $i < 10; $i++) {
219 $this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
222 $revisionCount = $page->revisions()->count();
223 $this->assertEquals(12, $revisionCount);
226 public function test_revision_list_shows_editor_type()
228 /** @var Page $page */
229 $page = Page::first();
230 $this->asAdmin()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html']);
232 $resp = $this->get($page->refresh()->getUrl('/revisions'));
233 $this->withHtml($resp)->assertElementContains('td', '(WYSIWYG)');
234 $this->withHtml($resp)->assertElementNotContains('td', '(Markdown)');
236 $this->asAdmin()->put($page->getUrl(), ['name' => 'Updated page', 'markdown' => '# Some markdown content']);
237 $resp = $this->get($page->refresh()->getUrl('/revisions'));
238 $this->withHtml($resp)->assertElementContains('td', '(Markdown)');