The final part of testing the CRUD of products is, of course, the delete.
Again, first, the code for the Controller, Route, and delete button.
app/Http/Controllers/ProductController.php:
use Illuminate\Http\RedirectResponse; class ProductController extends Controller{ // ... public function destroy(Product $product): RedirectResponse { $product->delete(); return redirect()->route('products.index'); }}
routes/web.php:
use App\Http\Controllers\ProductController; Route::middleware('auth')->group(function () { Route::get('products', [ProductController::class, 'index'])->name('products.index'); Route::middleware('is_admin')->group(function () { Route::get('products/create', [ProductController::class, 'create'])->name('products.create'); Route::post('products', [ProductController::class, 'store'])->name('products.store'); Route::get('products/{product}/edit', [ProductController::class, 'edit'])->name('products.edit'); Route::put('products/{product}', [ProductController::class, 'update'])->name('products.update'); Route::delete('products/{product}', [ProductController::class, 'destroy'])->name('products.destroy'); });});
resources/views/products/index.blade.php:
// ... @if (auth()->user()->is_admin) <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900"> <a href="{{ route('products.edit', $product) }}" class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150"> Edit </a> <form action="{{ route('products.destroy', $product) }}" method="POST" class="inline-block"> @csrf @method('DELETE') <x-primary-button onclick="return confirm('Are you sure?')" class="bg-red-600 text-white">Delete</x-primary-button> </form> </td> @endif// ...
After visiting the /products
URL, we now see a Delete
button, which is working.
In the test, we will simulate the DELETE request and assert the database.
The start of this test is the same as with the previous test. We create a product using Factory and make the delete request acting as an admin user. The first two assertions are the same: the status code is 302, and the redirect URL is back to /products
.
tests/Feature/ProductsTest.php:
class ProductsTest extends TestCase{ // ... public function test_product_delete_successful() { $product = Product::factory()->create(); $response = $this->actingAs($this->admin)->delete('products/' . $product->id); $response->assertStatus(302); $response->assertRedirect('products'); } private function createUser(bool $isAdmin = false): User { return User::factory()->create([ 'is_admin' => $isAdmin, ]); }}
In the previous lesson, we had assertDatabaseHas
. In this case, there is an assertion called assertDatabaseMissing
where the first parameter is the table and the second the array of values.
Also, let's count the database. In the beginning, the table is empty, then we create one record and delete it. So, at the end of the test, the table should be empty.
tests/Feature/ProductsTest.php:
class ProductsTest extends TestCase{ // ... public function test_product_delete_successful() { $product = Product::factory()->create(); $response = $this->actingAs($this->admin)->delete('products/' . $product->id); $response->assertStatus(302); $response->assertRedirect('products'); $this->assertDatabaseMissing('products', $product->toArray()); $this->assertDatabaseCount('products', 0); } private function createUser(bool $isAdmin = false): User { return User::factory()->create([ 'is_admin' => $isAdmin, ]); }}
These two database assertions can be made with different assertions. For assertDatabaseMissing
, the assertModelMissing
can be used. And for assertDatabaseCount
, the assertDatabaseEmpty
can be used in this particular case.
tests/Feature/ProductsTest.php:
class ProductsTest extends TestCase{ // ... public function test_product_delete_successful() { $product = Product::factory()->create(); $response = $this->actingAs($this->admin)->delete('products/' . $product->id); $response->assertStatus(302); $response->assertRedirect('products'); $this->assertDatabaseMissing('products', $product->toArray()); $this->assertDatabaseCount('products', 0); $this->assertModelMissing($product); $this->assertDatabaseEmpty('products'); } private function createUser(bool $isAdmin = false): User { return User::factory()->create([ 'is_admin' => $isAdmin, ]); }}