Skip to content

Commit

Permalink
added product controller with test
Browse files Browse the repository at this point in the history
  • Loading branch information
phi-rakib committed Jun 4, 2024
1 parent 04fb4a4 commit f9cd511
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 8 deletions.
69 changes: 67 additions & 2 deletions app/Http/Controllers/ProductController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,74 @@

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests\StoreProductRequest;
use App\Models\Price;
use App\Models\Product;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

class ProductController extends Controller
{
//
public function index()
{
Gate::authorize('viewAny', Product::class);

return Product::latest()->with(['category', 'brand', 'unitType', 'warehouses', 'creator'])->paginate(20);
}

public function show(Product $product)
{
Gate::authorize('view', $product);

return $product->load(['category', 'brand', 'unitType', 'warehouses', 'creator', 'latestPrice', 'prices', 'attributes']);
}

public function store(StoreProductRequest $request)
{
Gate::authorize('create', Product::class);

DB::transaction(function () use ($request) {
$product = Product::create($request->validated());

$product->prices()->create(['price' => $request->price]);

$product->attributes()->attach($request->input('attributes'));
});

return response()->json(['message' => 'Product created successfully'], 201);
}

public function update(StoreProductRequest $request, Product $product)
{
Gate::authorize('update', $product);

DB::transaction(function () use ($request, $product) {
$product->update($request->validated());

$product->attributes()->sync($request->input('attributes'));

$latestPrice = $product->latestPrice;

if ($latestPrice == null || $latestPrice->price != $request->input('price')) {
Price::create([
'product_id' => $product->id,
'price' => $request->input('price'),
]);
}
});

return response()->json(['message' => 'Product updated successfully'], 200);
}

public function destroy(Product $product)
{
Gate::authorize('delete', $product);

$product->deleted_by = auth()->id();
$product->save();

$product->delete();

return response()->json(['message' => 'Product deleted successfully'], 204);
}
}
258 changes: 252 additions & 6 deletions tests/Feature/ProductTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,265 @@

namespace Tests\Feature;

use App\Models\Attribute;
use App\Models\Product;
use App\Models\User;
use App\Models\Warehouse;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Auth;
use Tests\TestCase;

class ProductTest extends TestCase
{
/**
* A basic feature test example.
*/
public function test_example(): void
use RefreshDatabase;

private User $user;

public function setUp(): void
{
parent::setUp();

$this->user = Auth::user();
}

public function test_user_can_view_all_products()
{
$this->user->givePermissionTo('product-list');

$products = Product::factory(10)->create();
$warehouses = Warehouse::factory(3)->create();

$products->each(function ($product) use ($warehouses) {
$product->warehouses()->attach($warehouses->random(1)->pluck('id'));
});

$response = $this->get(route('products.index'));

$response->assertOk();

$response->assertJsonCount(10, 'data');

$response->assertJsonStructure([
'data' => [
'*' => [
'id',
'name',
'category' => [
'id',
'name',
],
'brand' => [
'id',
'name',
],
'unit_type' => [
'id',
'name',
],
'creator' => [
'id',
'name',
],
'warehouses' => [
'*' => [
'id',
'name',
'pivot' => [
'quantity',
],
],
],
],
],
]);
}

public function test_user_can_view_product()
{
$this->user->givePermissionTo('product-list');

$product = Product::factory()->create();
$attributes = Attribute::factory(10)->create();
$randomAttributes = $attributes->random(3)->pluck('id')->toArray();

$product->attributes()->attach($randomAttributes);

$product->prices()->create([
'price' => $price = rand(100, 1000),
]);

$response = $this->get(route('products.show', $product));

$response->assertOk();

$response->assertJsonStructure([
'id',
'name',
'category' => [
'id',
'name',
],
'brand' => [
'id',
'name',
],
'unit_type' => [
'id',
'name',
],
'creator' => [
'id',
'name',
],
'attributes' => [
'*' => [
'id',
'name',
],
],
'prices' => [
'*' => [
'price',
],
],
'warehouses' => [
'*' => [
'id',
'name',
'pivot' => [
'quantity',
],
],
],
]);

}

public function test_user_can_create_a_product()
{
$this->user->givePermissionTo('product-create');

$attributes = Attribute::factory(10)->create();
$product = Product::factory()->make();
$randomAttributes = $attributes->random(3)->pluck('id')->toArray();

$data = [
'price' => $price = rand(100, 1000),
...$product->toArray(),
'attributes' => $randomAttributes,
];

$this->post(route('products.store'), $data)
->assertCreated();

$this->assertDatabaseHas('products', [
'name' => $product->name,
'category_id' => $product->category_id,
'brand_id' => $product->brand_id,
'unit_type_id' => $product->unit_type_id,
'created_by' => $this->user->id,
]);

$productId = Product::first()->id;

$this->assertDatabaseHas('prices', [
'price' => $price,
'product_id' => $productId,
]);

$this->assertDatabaseCount('attribute_product', count($randomAttributes));

foreach ($randomAttributes as $attribute) {
$this->assertDatabaseHas('attribute_product', [
'product_id' => $productId,
'attribute_id' => $attribute,
]);
}
}

public function test_user_can_update_a_product()
{
$response = $this->get('/');
$this->user->givePermissionTo('product-edit');

$product = Product::factory()->create();
$attributes = Attribute::factory(10)->create();
$randomAttributes = $attributes->random(3)->pluck('id')->toArray();

$product->attributes()->attach($randomAttributes);

$product->prices()->create([
'price' => rand(100, 1000),
]);

$newRandomAttributes = $attributes->random(5)->pluck('id')->toArray();
$data = [
'price' => $newPrice = rand(100, 1000),
'name' => 'updated name',
'attributes' => $newRandomAttributes,
'category_id' => $product->category_id,
'brand_id' => $product->brand_id,
'unit_type_id' => $product->unit_type_id,
];

$response = $this->put(route('products.update', $product->id), $data);

$response->assertStatus(200);

$this->assertDatabaseHas('products', [
'id' => $product->id,
'name' => 'updated name',
'updated_by' => $this->user->id,
]);

$this->assertDatabaseHas('prices', [
'price' => $newPrice,
'product_id' => $product->id,
]);

$this->assertDatabaseCount('attribute_product', count($newRandomAttributes));

foreach ($newRandomAttributes as $attribute) {
$this->assertDatabaseHas('attribute_product', [
'product_id' => $product->id,
'attribute_id' => $attribute,
]);
}
}

public function test_user_can_delete_a_product()
{
$this->user->givePermissionTo('product-delete');

$product = Product::factory()->create();
$attributes = Attribute::factory(10)->create();
$randomAttributes = $attributes->random(3)->pluck('id')->toArray();

$product->attributes()->attach($randomAttributes);

$product->prices()->create([
'price' => $price = rand(100, 1000),
]);

$this->delete(route('products.destroy', $product->id))
->assertNoContent();

$this->assertSoftDeleted('products', [
'id' => $product->id,
'deleted_by' => $this->user->id,
]);

$this->assertDatabaseHas('prices', [
'price' => $price,
'product_id' => $product->id,
]);

$this->assertDatabaseCount('attribute_product', count($randomAttributes));

foreach ($randomAttributes as $attribute) {
$this->assertDatabaseHas('attribute_product', [
'product_id' => $product->id,
'attribute_id' => $attribute,
]);
}
}
}

0 comments on commit f9cd511

Please sign in to comment.