mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-03-22 21:05:13 +08:00
Sorting: Covered sort set management with tests
This commit is contained in:
parent
a65701294e
commit
a208c46b62
@ -4,14 +4,13 @@ namespace BookStack\Sorting;
|
||||
|
||||
use BookStack\Activity\ActivityType;
|
||||
use BookStack\Http\Controller;
|
||||
use BookStack\Http\Request;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SortSetController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('can:settings-manage');
|
||||
// TODO - Test
|
||||
}
|
||||
|
||||
public function create()
|
||||
|
@ -26,7 +26,9 @@ class BookFactory extends Factory
|
||||
'name' => $this->faker->sentence(),
|
||||
'slug' => Str::random(10),
|
||||
'description' => $description,
|
||||
'description_html' => '<p>' . e($description) . '</p>'
|
||||
'description_html' => '<p>' . e($description) . '</p>',
|
||||
'sort_set_id' => null,
|
||||
'default_template_id' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ return [
|
||||
'sorting_book_default_desc' => 'Select the default sort set to apply to new books. This won\'t affect existing books, and can be overridden per-book.',
|
||||
'sorting_sets' => 'Sort Sets',
|
||||
'sorting_sets_desc' => 'These are predefined sorting operations which can be applied to content in the system.',
|
||||
'sort_set_assigned_to_x_books' => 'Assigned to :count Book|Assigned to :count Books',
|
||||
'sort_set_create' => 'Create Sort Set',
|
||||
'sort_set_edit' => 'Edit Sort Set',
|
||||
'sort_set_delete' => 'Delete Sort Set',
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{ implode(', ', array_map(fn ($op) => $op->getLabel(), $set->getOperations())) }}
|
||||
</div>
|
||||
<div>
|
||||
<span title="{{ trans('entities.tags_assigned_books') }}"
|
||||
<span title="{{ trans_choice('settings.sort_set_assigned_to_x_books', $set->books_count ?? 0) }}"
|
||||
class="flex fill-area min-width-xxs bold text-right text-book"><span class="opacity-60">@icon('book')</span>{{ $set->books_count ?? 0 }}</span>
|
||||
</div>
|
||||
</div>
|
200
tests/Sorting/SortSetTest.php
Normal file
200
tests/Sorting/SortSetTest.php
Normal file
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace Sorting;
|
||||
|
||||
use BookStack\Activity\ActivityType;
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Sorting\SortSet;
|
||||
use Tests\Api\TestsApi;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SortSetTest extends TestCase
|
||||
{
|
||||
use TestsApi;
|
||||
|
||||
public function test_manage_settings_permission_required()
|
||||
{
|
||||
$set = SortSet::factory()->create();
|
||||
$user = $this->users->viewer();
|
||||
$this->actingAs($user);
|
||||
|
||||
$actions = [
|
||||
['GET', '/settings/sorting'],
|
||||
['POST', '/settings/sorting/sets'],
|
||||
['GET', "/settings/sorting/sets/{$set->id}"],
|
||||
['PUT', "/settings/sorting/sets/{$set->id}"],
|
||||
['DELETE', "/settings/sorting/sets/{$set->id}"],
|
||||
];
|
||||
|
||||
foreach ($actions as [$method, $path]) {
|
||||
$resp = $this->call($method, $path);
|
||||
$this->assertPermissionError($resp);
|
||||
}
|
||||
|
||||
$this->permissions->grantUserRolePermissions($user, ['settings-manage']);
|
||||
|
||||
foreach ($actions as [$method, $path]) {
|
||||
$resp = $this->call($method, $path);
|
||||
$this->assertNotPermissionError($resp);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_create_flow()
|
||||
{
|
||||
$resp = $this->asAdmin()->get('/settings/sorting');
|
||||
$this->withHtml($resp)->assertLinkExists(url('/settings/sorting/sets/new'));
|
||||
|
||||
$resp = $this->get('/settings/sorting/sets/new');
|
||||
$this->withHtml($resp)->assertElementExists('form[action$="/settings/sorting/sets"] input[name="name"]');
|
||||
$resp->assertSeeText('Name - Alphabetical (Asc)');
|
||||
|
||||
$details = ['name' => 'My new sort', 'sequence' => 'name_asc'];
|
||||
$resp = $this->post('/settings/sorting/sets', $details);
|
||||
$resp->assertRedirect('/settings/sorting');
|
||||
|
||||
$this->assertActivityExists(ActivityType::SORT_SET_CREATE);
|
||||
$this->assertDatabaseHas('sort_sets', $details);
|
||||
}
|
||||
|
||||
public function test_listing_in_settings()
|
||||
{
|
||||
$set = SortSet::factory()->create(['name' => 'My super sort set', 'sequence' => 'name_asc']);
|
||||
$books = Book::query()->limit(5)->get();
|
||||
foreach ($books as $book) {
|
||||
$book->sort_set_id = $set->id;
|
||||
$book->save();
|
||||
}
|
||||
|
||||
$resp = $this->asAdmin()->get('/settings/sorting');
|
||||
$resp->assertSeeText('My super sort set');
|
||||
$resp->assertSeeText('Name - Alphabetical (Asc)');
|
||||
$this->withHtml($resp)->assertElementContains('.item-list-row [title="Assigned to 5 Books"]', '5');
|
||||
}
|
||||
|
||||
public function test_update_flow()
|
||||
{
|
||||
$set = SortSet::factory()->create(['name' => 'My sort set to update', 'sequence' => 'name_asc']);
|
||||
|
||||
$resp = $this->asAdmin()->get("/settings/sorting/sets/{$set->id}");
|
||||
$respHtml = $this->withHtml($resp);
|
||||
$respHtml->assertElementContains('.configured-option-list', 'Name - Alphabetical (Asc)');
|
||||
$respHtml->assertElementNotContains('.available-option-list', 'Name - Alphabetical (Asc)');
|
||||
|
||||
$updateData = ['name' => 'My updated sort', 'sequence' => 'name_desc,chapters_last'];
|
||||
$resp = $this->put("/settings/sorting/sets/{$set->id}", $updateData);
|
||||
|
||||
$resp->assertRedirect('/settings/sorting');
|
||||
$this->assertActivityExists(ActivityType::SORT_SET_UPDATE);
|
||||
$this->assertDatabaseHas('sort_sets', $updateData);
|
||||
}
|
||||
|
||||
public function test_update_triggers_resort_on_assigned_books()
|
||||
{
|
||||
$book = $this->entities->bookHasChaptersAndPages();
|
||||
$chapter = $book->chapters()->first();
|
||||
$set = SortSet::factory()->create(['name' => 'My sort set to update', 'sequence' => 'name_asc']);
|
||||
$book->sort_set_id = $set->id;
|
||||
$book->save();
|
||||
$chapter->priority = 10000;
|
||||
$chapter->save();
|
||||
|
||||
$resp = $this->asAdmin()->put("/settings/sorting/sets/{$set->id}", ['name' => $set->name, 'sequence' => 'chapters_last']);
|
||||
$resp->assertRedirect('/settings/sorting');
|
||||
|
||||
$chapter->refresh();
|
||||
$this->assertNotEquals(10000, $chapter->priority);
|
||||
}
|
||||
|
||||
public function test_delete_flow()
|
||||
{
|
||||
$set = SortSet::factory()->create();
|
||||
|
||||
$resp = $this->asAdmin()->get("/settings/sorting/sets/{$set->id}");
|
||||
$resp->assertSeeText('Delete Sort Set');
|
||||
|
||||
$resp = $this->delete("settings/sorting/sets/{$set->id}");
|
||||
$resp->assertRedirect('/settings/sorting');
|
||||
|
||||
$this->assertActivityExists(ActivityType::SORT_SET_DELETE);
|
||||
$this->assertDatabaseMissing('sort_sets', ['id' => $set->id]);
|
||||
}
|
||||
|
||||
public function test_delete_requires_confirmation_if_books_assigned()
|
||||
{
|
||||
$set = SortSet::factory()->create();
|
||||
$books = Book::query()->limit(5)->get();
|
||||
foreach ($books as $book) {
|
||||
$book->sort_set_id = $set->id;
|
||||
$book->save();
|
||||
}
|
||||
|
||||
$resp = $this->asAdmin()->get("/settings/sorting/sets/{$set->id}");
|
||||
$resp->assertSeeText('Delete Sort Set');
|
||||
|
||||
$resp = $this->delete("settings/sorting/sets/{$set->id}");
|
||||
$resp->assertRedirect("/settings/sorting/sets/{$set->id}#delete");
|
||||
$resp = $this->followRedirects($resp);
|
||||
|
||||
$resp->assertSeeText('This sort set is currently used on 5 book(s). Are you sure you want to delete this?');
|
||||
$this->assertDatabaseHas('sort_sets', ['id' => $set->id]);
|
||||
|
||||
$resp = $this->delete("settings/sorting/sets/{$set->id}", ['confirm' => 'true']);
|
||||
$resp->assertRedirect('/settings/sorting');
|
||||
$this->assertDatabaseMissing('sort_sets', ['id' => $set->id]);
|
||||
$this->assertDatabaseMissing('books', ['sort_set_id' => $set->id]);
|
||||
}
|
||||
|
||||
public function test_page_create_triggers_book_sort()
|
||||
{
|
||||
$book = $this->entities->bookHasChaptersAndPages();
|
||||
$set = SortSet::factory()->create(['sequence' => 'name_asc,chapters_first']);
|
||||
$book->sort_set_id = $set->id;
|
||||
$book->save();
|
||||
|
||||
$resp = $this->actingAsApiEditor()->post("/api/pages", [
|
||||
'book_id' => $book->id,
|
||||
'name' => '1111 page',
|
||||
'markdown' => 'Hi'
|
||||
]);
|
||||
$resp->assertOk();
|
||||
|
||||
$this->assertDatabaseHas('pages', [
|
||||
'book_id' => $book->id,
|
||||
'name' => '1111 page',
|
||||
'priority' => $book->chapters()->count() + 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_name_numeric_ordering()
|
||||
{
|
||||
$book = Book::factory()->create();
|
||||
$set = SortSet::factory()->create(['sequence' => 'name_numeric_asc']);
|
||||
$book->sort_set_id = $set->id;
|
||||
$book->save();
|
||||
$this->permissions->regenerateForEntity($book);
|
||||
|
||||
$namesToAdd = [
|
||||
"1 - Pizza",
|
||||
"2.0 - Tomato",
|
||||
"2.5 - Beans",
|
||||
"10 - Bread",
|
||||
"20 - Milk",
|
||||
];
|
||||
|
||||
foreach ($namesToAdd as $name) {
|
||||
$this->actingAsApiEditor()->post("/api/pages", [
|
||||
'book_id' => $book->id,
|
||||
'name' => $name,
|
||||
'markdown' => 'Hello'
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($namesToAdd as $index => $name) {
|
||||
$this->assertDatabaseHas('pages', [
|
||||
'book_id' => $book->id,
|
||||
'name' => $name,
|
||||
'priority' => $index + 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user