]> BookStack Code Mirror - bookstack/blob - tests/Entity/BookShelfTest.php
Added testing to favourite system
[bookstack] / tests / Entity / BookShelfTest.php
1 <?php namespace Tests\Entity;
2
3 use BookStack\Auth\User;
4 use BookStack\Entities\Models\Book;
5 use BookStack\Entities\Models\Bookshelf;
6 use BookStack\Uploads\Image;
7 use Illuminate\Support\Str;
8 use Tests\TestCase;
9 use Tests\Uploads\UsesImages;
10
11 class BookShelfTest extends TestCase
12 {
13
14     use UsesImages;
15
16     public function test_shelves_shows_in_header_if_have_view_permissions()
17     {
18         $viewer = $this->getViewer();
19         $resp = $this->actingAs($viewer)->get('/');
20         $resp->assertElementContains('header', 'Shelves');
21
22         $viewer->roles()->delete();
23         $this->giveUserPermissions($viewer);
24         $resp = $this->actingAs($viewer)->get('/');
25         $resp->assertElementNotContains('header', 'Shelves');
26
27         $this->giveUserPermissions($viewer, ['bookshelf-view-all']);
28         $resp = $this->actingAs($viewer)->get('/');
29         $resp->assertElementContains('header', 'Shelves');
30
31         $viewer->roles()->delete();
32         $this->giveUserPermissions($viewer, ['bookshelf-view-own']);
33         $resp = $this->actingAs($viewer)->get('/');
34         $resp->assertElementContains('header', 'Shelves');
35     }
36
37     public function test_shelves_shows_in_header_if_have_any_shelve_view_permission()
38     {
39         $user = factory(User::class)->create();
40         $this->giveUserPermissions($user, ['image-create-all']);
41         $shelf = Bookshelf::first();
42         $userRole = $user->roles()->first();
43
44         $resp = $this->actingAs($user)->get('/');
45         $resp->assertElementNotContains('header', 'Shelves');
46
47         $this->setEntityRestrictions($shelf, ['view'], [$userRole]);
48
49         $resp = $this->get('/');
50         $resp->assertElementContains('header', 'Shelves');
51     }
52
53     public function test_shelves_page_contains_create_link()
54     {
55         $resp = $this->asEditor()->get('/shelves');
56         $resp->assertElementContains('a', 'New Shelf');
57     }
58
59     public function test_book_not_visible_in_shelf_list_view_if_user_cant_view_shelf()
60     {
61         config()->set([
62             'setting-defaults.user.bookshelves_view_type' => 'list',
63         ]);
64         $shelf = Bookshelf::query()->first();
65         $book = $shelf->books()->first();
66
67         $resp = $this->asEditor()->get('/shelves');
68         $resp->assertSee($book->name);
69         $resp->assertSee($book->getUrl());
70
71         $this->setEntityRestrictions($book, []);
72
73         $resp = $this->asEditor()->get('/shelves');
74         $resp->assertDontSee($book->name);
75         $resp->assertDontSee($book->getUrl());
76     }
77
78     public function test_shelves_create()
79     {
80         $booksToInclude = Book::take(2)->get();
81         $shelfInfo = [
82             'name' => 'My test book' . Str::random(4),
83             'description' => 'Test book description ' . Str::random(10)
84         ];
85         $resp = $this->asEditor()->post('/shelves', array_merge($shelfInfo, [
86             'books' => $booksToInclude->implode('id', ','),
87             'tags' => [
88                 [
89                     'name' => 'Test Category',
90                     'value' => 'Test Tag Value',
91                 ]
92             ],
93         ]));
94         $resp->assertRedirect();
95         $editorId = $this->getEditor()->id;
96         $this->assertDatabaseHas('bookshelves', array_merge($shelfInfo, ['created_by' => $editorId, 'updated_by' => $editorId]));
97
98         $shelf = Bookshelf::where('name', '=', $shelfInfo['name'])->first();
99         $shelfPage = $this->get($shelf->getUrl());
100         $shelfPage->assertSee($shelfInfo['name']);
101         $shelfPage->assertSee($shelfInfo['description']);
102         $shelfPage->assertElementContains('.tag-item', 'Test Category');
103         $shelfPage->assertElementContains('.tag-item', 'Test Tag Value');
104
105         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[0]->id]);
106         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
107     }
108
109     public function test_shelves_create_sets_cover_image()
110     {
111         $shelfInfo = [
112             'name' => 'My test book' . Str::random(4),
113             'description' => 'Test book description ' . Str::random(10)
114         ];
115
116         $imageFile = $this->getTestImage('shelf-test.png');
117         $resp = $this->asEditor()->call('POST', '/shelves', $shelfInfo, [], ['image' => $imageFile]);
118         $resp->assertRedirect();
119
120         $lastImage = Image::query()->orderByDesc('id')->firstOrFail();
121         $shelf = Bookshelf::query()->where('name', '=', $shelfInfo['name'])->first();
122         $this->assertDatabaseHas('bookshelves', [
123             'id' => $shelf->id,
124             'image_id' => $lastImage->id,
125         ]);
126         $this->assertEquals($lastImage->id, $shelf->cover->id);
127     }
128
129     public function test_shelf_view()
130     {
131         $shelf = Bookshelf::first();
132         $resp = $this->asEditor()->get($shelf->getUrl());
133         $resp->assertStatus(200);
134         $resp->assertSeeText($shelf->name);
135         $resp->assertSeeText($shelf->description);
136
137         foreach ($shelf->books as $book) {
138             $resp->assertSee($book->name);
139         }
140     }
141
142     public function test_shelf_view_shows_action_buttons()
143     {
144         $shelf = Bookshelf::first();
145         $resp = $this->asAdmin()->get($shelf->getUrl());
146         $resp->assertSee($shelf->getUrl('/create-book'));
147         $resp->assertSee($shelf->getUrl('/edit'));
148         $resp->assertSee($shelf->getUrl('/permissions'));
149         $resp->assertSee($shelf->getUrl('/delete'));
150         $resp->assertElementContains('a', 'New Book');
151         $resp->assertElementContains('a', 'Edit');
152         $resp->assertElementContains('a', 'Permissions');
153         $resp->assertElementContains('a', 'Delete');
154
155         $resp = $this->asEditor()->get($shelf->getUrl());
156         $resp->assertDontSee($shelf->getUrl('/permissions'));
157     }
158
159     public function test_shelf_view_has_sort_control_that_defaults_to_default()
160     {
161         $shelf = Bookshelf::query()->first();
162         $resp = $this->asAdmin()->get($shelf->getUrl());
163         $resp->assertElementExists('form[action$="change-sort/shelf_books"]');
164         $resp->assertElementContains('form[action$="change-sort/shelf_books"] [aria-haspopup="true"]', 'Default');
165     }
166
167     public function test_shelf_view_sort_takes_action()
168     {
169         $shelf = Bookshelf::query()->whereHas('books')->with('books')->first();
170         $books = Book::query()->take(3)->get(['id', 'name']);
171         $books[0]->fill(['name' => 'bsfsdfsdfsd'])->save();
172         $books[1]->fill(['name' => 'adsfsdfsdfsd'])->save();
173         $books[2]->fill(['name' => 'hdgfgdfg'])->save();
174
175         // Set book ordering
176         $this->asAdmin()->put($shelf->getUrl(), [
177             'books' => $books->implode('id', ','),
178             'tags' => [], 'description' => 'abc', 'name' => 'abc'
179         ]);
180         $this->assertEquals(3, $shelf->books()->count());
181         $shelf->refresh();
182
183         $resp = $this->asEditor()->get($shelf->getUrl());
184         $resp->assertElementContains('.book-content a.grid-card', $books[0]->name, 1);
185         $resp->assertElementNotContains('.book-content a.grid-card', $books[0]->name, 3);
186
187         setting()->putUser($this->getEditor(), 'shelf_books_sort_order', 'desc');
188         $resp = $this->asEditor()->get($shelf->getUrl());
189         $resp->assertElementNotContains('.book-content a.grid-card', $books[0]->name, 1);
190         $resp->assertElementContains('.book-content a.grid-card', $books[0]->name, 3);
191
192         setting()->putUser($this->getEditor(), 'shelf_books_sort_order', 'desc');
193         setting()->putUser($this->getEditor(), 'shelf_books_sort', 'name');
194         $resp = $this->asEditor()->get($shelf->getUrl());
195         $resp->assertElementContains('.book-content a.grid-card', 'hdgfgdfg', 1);
196         $resp->assertElementContains('.book-content a.grid-card', 'bsfsdfsdfsd', 2);
197         $resp->assertElementContains('.book-content a.grid-card', 'adsfsdfsdfsd', 3);
198     }
199
200     public function test_shelf_edit()
201     {
202         $shelf = Bookshelf::first();
203         $resp = $this->asEditor()->get($shelf->getUrl('/edit'));
204         $resp->assertSeeText('Edit Bookshelf');
205
206         $booksToInclude = Book::take(2)->get();
207         $shelfInfo = [
208             'name' => 'My test book' . Str::random(4),
209             'description' => 'Test book description ' . Str::random(10)
210         ];
211
212         $resp = $this->asEditor()->put($shelf->getUrl(), array_merge($shelfInfo, [
213             'books' => $booksToInclude->implode('id', ','),
214             'tags' => [
215                 [
216                     'name' => 'Test Category',
217                     'value' => 'Test Tag Value',
218                 ]
219             ],
220         ]));
221         $shelf = Bookshelf::find($shelf->id);
222         $resp->assertRedirect($shelf->getUrl());
223         $this->assertSessionHas('success');
224
225         $editorId = $this->getEditor()->id;
226         $this->assertDatabaseHas('bookshelves', array_merge($shelfInfo, ['id' => $shelf->id, 'created_by' => $editorId, 'updated_by' => $editorId]));
227
228         $shelfPage = $this->get($shelf->getUrl());
229         $shelfPage->assertSee($shelfInfo['name']);
230         $shelfPage->assertSee($shelfInfo['description']);
231         $shelfPage->assertElementContains('.tag-item', 'Test Category');
232         $shelfPage->assertElementContains('.tag-item', 'Test Tag Value');
233
234         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[0]->id]);
235         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
236     }
237
238     public function test_shelf_create_new_book()
239     {
240         $shelf = Bookshelf::first();
241         $resp = $this->asEditor()->get($shelf->getUrl('/create-book'));
242
243         $resp->assertSee('Create New Book');
244         $resp->assertSee($shelf->getShortName());
245
246         $testName = 'Test Book in Shelf Name';
247
248         $createBookResp = $this->asEditor()->post($shelf->getUrl('/create-book'), [
249             'name' => $testName,
250             'description' => 'Book in shelf description'
251         ]);
252         $createBookResp->assertRedirect();
253
254         $newBook = Book::query()->orderBy('id', 'desc')->first();
255         $this->assertDatabaseHas('bookshelves_books', [
256             'bookshelf_id' => $shelf->id,
257             'book_id' => $newBook->id,
258         ]);
259
260         $resp = $this->asEditor()->get($shelf->getUrl());
261         $resp->assertSee($testName);
262     }
263
264     public function test_shelf_delete()
265     {
266         $shelf = Bookshelf::query()->whereHas('books')->first();
267         $this->assertNull($shelf->deleted_at);
268         $bookCount = $shelf->books()->count();
269
270         $deleteViewReq = $this->asEditor()->get($shelf->getUrl('/delete'));
271         $deleteViewReq->assertSeeText('Are you sure you want to delete this bookshelf?');
272
273         $deleteReq = $this->delete($shelf->getUrl());
274         $deleteReq->assertRedirect(url('/shelves'));
275         $this->assertActivityExists('bookshelf_delete', $shelf);
276
277         $shelf->refresh();
278         $this->assertNotNull($shelf->deleted_at);
279
280         $this->assertTrue($shelf->books()->count() === $bookCount);
281         $this->assertTrue($shelf->deletions()->count() === 1);
282
283         $redirectReq = $this->get($deleteReq->baseResponse->headers->get('location'));
284         $redirectReq->assertNotificationContains('Bookshelf Successfully Deleted');
285     }
286
287     public function test_shelf_copy_permissions()
288     {
289         $shelf = Bookshelf::first();
290         $resp = $this->asAdmin()->get($shelf->getUrl('/permissions'));
291         $resp->assertSeeText('Copy Permissions');
292         $resp->assertSee("action=\"{$shelf->getUrl('/copy-permissions')}\"");
293
294         $child = $shelf->books()->first();
295         $editorRole = $this->getEditor()->roles()->first();
296         $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default");
297         $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default");
298
299         $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]);
300         $resp = $this->post($shelf->getUrl('/copy-permissions'));
301         $child = $shelf->books()->first();
302
303         $resp->assertRedirect($shelf->getUrl());
304         $this->assertTrue(boolval($child->restricted), "Child book should now be restricted");
305         $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions");
306         $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]);
307         $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]);
308     }
309
310     public function test_bookshelves_show_in_breadcrumbs_if_in_context()
311     {
312         $shelf = Bookshelf::first();
313         $shelfBook = $shelf->books()->first();
314         $shelfPage = $shelfBook->pages()->first();
315         $this->asAdmin();
316
317         $bookVisit = $this->get($shelfBook->getUrl());
318         $bookVisit->assertElementNotContains('.breadcrumbs', 'Shelves');
319         $bookVisit->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
320
321         $this->get($shelf->getUrl());
322         $bookVisit = $this->get($shelfBook->getUrl());
323         $bookVisit->assertElementContains('.breadcrumbs', 'Shelves');
324         $bookVisit->assertElementContains('.breadcrumbs', $shelf->getShortName());
325
326         $pageVisit = $this->get($shelfPage->getUrl());
327         $pageVisit->assertElementContains('.breadcrumbs', 'Shelves');
328         $pageVisit->assertElementContains('.breadcrumbs', $shelf->getShortName());
329
330         $this->get('/books');
331         $pageVisit = $this->get($shelfPage->getUrl());
332         $pageVisit->assertElementNotContains('.breadcrumbs', 'Shelves');
333         $pageVisit->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
334     }
335
336     public function test_bookshelves_show_on_book()
337     {
338         // Create shelf
339         $shelfInfo = [
340             'name' => 'My test shelf' . Str::random(4),
341             'description' => 'Test shelf description ' . Str::random(10)
342         ];
343
344         $this->asEditor()->post('/shelves', $shelfInfo);
345         $shelf = Bookshelf::where('name', '=', $shelfInfo['name'])->first();
346
347         // Create book and add to shelf
348         $this->asEditor()->post($shelf->getUrl('/create-book'), [
349             'name' => 'Test book name',
350             'description' => 'Book in shelf description'
351         ]);
352
353         $newBook = Book::query()->orderBy('id', 'desc')->first();
354
355         $resp = $this->asEditor()->get($newBook->getUrl());
356         $resp->assertElementContains('.tri-layout-left-contents', $shelfInfo['name']);
357
358         // Remove shelf
359         $this->delete($shelf->getUrl());
360
361         $resp = $this->asEditor()->get($newBook->getUrl());
362         $resp->assertDontSee($shelfInfo['name']);
363     }
364 }