Skip to content

Commit 6e136bc

Browse files
Copilotiamgergo
andcommitted
Add comprehensive tests for discount rules functionality
Co-authored-by: iamgergo <6567179+iamgergo@users.noreply.github.com>
1 parent 9149986 commit 6e136bc

File tree

7 files changed

+460
-0
lines changed

7 files changed

+460
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cone\Bazar\Database\Factories;
6+
7+
use Cone\Bazar\Enums\DiscountRuleType;
8+
use Cone\Bazar\Models\DiscountRule;
9+
use Illuminate\Database\Eloquent\Factories\Factory;
10+
11+
class DiscountRuleFactory extends Factory
12+
{
13+
/**
14+
* The name of the factory's corresponding model.
15+
*
16+
* @var class-string<\Illuminate\Database\Eloquent\Model>
17+
*/
18+
protected $model = DiscountRule::class;
19+
20+
/**
21+
* Get the name of the model that is generated by the factory.
22+
*
23+
* @return class-string<\Illuminate\Database\Eloquent\Model|TModel>
24+
*/
25+
public function modelName(): string
26+
{
27+
return $this->model::getProxiedClass();
28+
}
29+
30+
/**
31+
* Define the model's default state.
32+
*/
33+
public function definition(): array
34+
{
35+
return [
36+
'active' => true,
37+
'name' => fake()->words(3, true),
38+
'rules' => [],
39+
'stackable' => false,
40+
'type' => DiscountRuleType::CART,
41+
];
42+
}
43+
}

src/Models/DiscountRule.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44

55
namespace Cone\Bazar\Models;
66

7+
use Cone\Bazar\Database\Factories\DiscountRuleFactory;
78
use Cone\Bazar\Enums\DiscountRuleType;
89
use Cone\Bazar\Interfaces\Discountable;
910
use Cone\Bazar\Interfaces\Models\DiscountRule as Contract;
1011
use Cone\Root\Models\User;
1112
use Cone\Root\Traits\InteractsWithProxy;
13+
use Illuminate\Database\Eloquent\Factories\HasFactory;
1214
use Illuminate\Database\Eloquent\Model;
1315
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
1416

1517
class DiscountRule extends Model implements Contract
1618
{
19+
use HasFactory;
1720
use InteractsWithProxy;
1821

1922
/**
@@ -70,6 +73,14 @@ public function getMorphClass(): string
7073
return static::getProxiedClass();
7174
}
7275

76+
/**
77+
* Create a new factory instance for the model.
78+
*/
79+
protected static function newFactory(): DiscountRuleFactory
80+
{
81+
return DiscountRuleFactory::new();
82+
}
83+
7384
/**
7485
* {@inheritdoc}
7586
*/
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cone\Bazar\Tests\Enums;
6+
7+
use Cone\Bazar\Enums\DiscountRuleType;
8+
use Cone\Bazar\Tests\TestCase;
9+
10+
class DiscountRuleTypeTest extends TestCase
11+
{
12+
public function test_discount_rule_type_has_cart_case(): void
13+
{
14+
$this->assertEquals('cart', DiscountRuleType::CART->value);
15+
}
16+
17+
public function test_discount_rule_type_has_buyable_case(): void
18+
{
19+
$this->assertEquals('buyable', DiscountRuleType::BUYABLE->value);
20+
}
21+
22+
public function test_discount_rule_type_has_shipping_case(): void
23+
{
24+
$this->assertEquals('shipping', DiscountRuleType::SHIPPING->value);
25+
}
26+
27+
public function test_cart_type_has_highest_priority(): void
28+
{
29+
$this->assertEquals(3, DiscountRuleType::CART->priority());
30+
}
31+
32+
public function test_buyable_type_has_medium_priority(): void
33+
{
34+
$this->assertEquals(2, DiscountRuleType::BUYABLE->priority());
35+
}
36+
37+
public function test_shipping_type_has_lowest_priority(): void
38+
{
39+
$this->assertEquals(1, DiscountRuleType::SHIPPING->priority());
40+
}
41+
42+
public function test_cart_type_has_correct_label(): void
43+
{
44+
$this->assertEquals('Cart Total', DiscountRuleType::CART->label());
45+
}
46+
47+
public function test_buyable_type_has_correct_label(): void
48+
{
49+
$this->assertEquals('Buyable Item', DiscountRuleType::BUYABLE->label());
50+
}
51+
52+
public function test_shipping_type_has_correct_label(): void
53+
{
54+
$this->assertEquals('Shipping', DiscountRuleType::SHIPPING->label());
55+
}
56+
57+
public function test_priorities_are_ordered_correctly(): void
58+
{
59+
$this->assertGreaterThan(
60+
DiscountRuleType::BUYABLE->priority(),
61+
DiscountRuleType::CART->priority()
62+
);
63+
64+
$this->assertGreaterThan(
65+
DiscountRuleType::SHIPPING->priority(),
66+
DiscountRuleType::BUYABLE->priority()
67+
);
68+
}
69+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cone\Bazar\Tests\Enums;
6+
7+
use Cone\Bazar\Enums\DiscountValueType;
8+
use Cone\Bazar\Tests\TestCase;
9+
10+
class DiscountValueTypeTest extends TestCase
11+
{
12+
public function test_discount_value_type_has_fix_case(): void
13+
{
14+
$this->assertEquals('fixed_amount', DiscountValueType::FIX->value);
15+
}
16+
17+
public function test_discount_value_type_has_percent_case(): void
18+
{
19+
$this->assertEquals('percent', DiscountValueType::PERCENT->value);
20+
}
21+
22+
public function test_all_cases_are_present(): void
23+
{
24+
$cases = DiscountValueType::cases();
25+
26+
$this->assertCount(2, $cases);
27+
$this->assertContains(DiscountValueType::FIX, $cases);
28+
$this->assertContains(DiscountValueType::PERCENT, $cases);
29+
}
30+
}

tests/Models/DiscountRuleTest.php

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cone\Bazar\Tests\Models;
6+
7+
use Cone\Bazar\Enums\DiscountRuleType;
8+
use Cone\Bazar\Models\Cart;
9+
use Cone\Bazar\Models\DiscountRule;
10+
use Cone\Bazar\Models\Item;
11+
use Cone\Bazar\Models\Product;
12+
use Cone\Bazar\Tests\TestCase;
13+
use Cone\Bazar\Tests\User;
14+
15+
class DiscountRuleTest extends TestCase
16+
{
17+
protected DiscountRule $discountRule;
18+
19+
protected Cart $cart;
20+
21+
protected function setUp(): void
22+
{
23+
parent::setUp();
24+
25+
$this->discountRule = DiscountRule::factory()->create();
26+
27+
$this->cart = Cart::factory()->create();
28+
29+
Product::factory(3)->create()->each(function ($product) {
30+
$this->cart->items()->create([
31+
'buyable_id' => $product->id,
32+
'buyable_type' => Product::class,
33+
'quantity' => mt_rand(1, 5),
34+
'price' => $product->price,
35+
'name' => $product->name,
36+
]);
37+
});
38+
}
39+
40+
public function test_discount_rule_has_default_attributes(): void
41+
{
42+
$this->assertTrue($this->discountRule->active);
43+
$this->assertFalse($this->discountRule->stackable);
44+
$this->assertEquals(DiscountRuleType::CART, $this->discountRule->type);
45+
$this->assertIsArray($this->discountRule->rules);
46+
}
47+
48+
public function test_discount_rule_can_have_rules(): void
49+
{
50+
$this->discountRule->rules = ['min_amount' => 100];
51+
$this->discountRule->save();
52+
53+
$this->assertSame(['min_amount' => 100], $this->discountRule->rules);
54+
}
55+
56+
public function test_discount_rule_can_be_associated_with_users(): void
57+
{
58+
$users = User::factory()->count(2)->create();
59+
60+
$this->discountRule->users()->attach($users);
61+
62+
$this->assertCount(2, $this->discountRule->users);
63+
$this->assertTrue($this->discountRule->users->contains($users[0]));
64+
$this->assertTrue($this->discountRule->users->contains($users[1]));
65+
}
66+
67+
public function test_discount_rule_can_calculate_discount(): void
68+
{
69+
$value = $this->discountRule->calculate($this->cart);
70+
71+
$this->assertIsFloat($value);
72+
$this->assertEquals(0.0, $value);
73+
}
74+
75+
public function test_discount_rule_can_be_applied_to_discountable(): void
76+
{
77+
$this->assertCount(0, $this->cart->discounts);
78+
79+
$this->discountRule->apply($this->cart);
80+
81+
$this->cart->refresh();
82+
83+
$this->assertCount(1, $this->cart->discounts);
84+
$this->assertTrue($this->cart->discounts->contains($this->discountRule));
85+
}
86+
87+
public function test_discount_rule_can_be_applied_to_item(): void
88+
{
89+
$item = $this->cart->items->first();
90+
91+
$this->assertCount(0, $item->discounts);
92+
93+
$this->discountRule->apply($item);
94+
95+
$item->refresh();
96+
97+
$this->assertCount(1, $item->discounts);
98+
$this->assertTrue($item->discounts->contains($this->discountRule));
99+
}
100+
101+
public function test_discount_rule_types_have_priorities(): void
102+
{
103+
$this->assertEquals(3, DiscountRuleType::CART->priority());
104+
$this->assertEquals(2, DiscountRuleType::BUYABLE->priority());
105+
$this->assertEquals(1, DiscountRuleType::SHIPPING->priority());
106+
}
107+
108+
public function test_discount_rule_types_have_labels(): void
109+
{
110+
$this->assertEquals('Cart Total', DiscountRuleType::CART->label());
111+
$this->assertEquals('Buyable Item', DiscountRuleType::BUYABLE->label());
112+
$this->assertEquals('Shipping', DiscountRuleType::SHIPPING->label());
113+
}
114+
115+
public function test_discount_rule_can_have_different_types(): void
116+
{
117+
$cartRule = DiscountRule::factory()->create(['type' => DiscountRuleType::CART]);
118+
$buyableRule = DiscountRule::factory()->create(['type' => DiscountRuleType::BUYABLE]);
119+
$shippingRule = DiscountRule::factory()->create(['type' => DiscountRuleType::SHIPPING]);
120+
121+
$this->assertEquals(DiscountRuleType::CART, $cartRule->type);
122+
$this->assertEquals(DiscountRuleType::BUYABLE, $buyableRule->type);
123+
$this->assertEquals(DiscountRuleType::SHIPPING, $shippingRule->type);
124+
}
125+
}

tests/Models/DiscountTest.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cone\Bazar\Tests\Models;
6+
7+
use Cone\Bazar\Models\Cart;
8+
use Cone\Bazar\Models\Discount;
9+
use Cone\Bazar\Models\DiscountRule;
10+
use Cone\Bazar\Models\Product;
11+
use Cone\Bazar\Tests\TestCase;
12+
13+
class DiscountTest extends TestCase
14+
{
15+
protected DiscountRule $discountRule;
16+
17+
protected Cart $cart;
18+
19+
protected function setUp(): void
20+
{
21+
parent::setUp();
22+
23+
$this->discountRule = DiscountRule::factory()->create();
24+
25+
$this->cart = Cart::factory()->create();
26+
27+
Product::factory(3)->create()->each(function ($product) {
28+
$this->cart->items()->create([
29+
'buyable_id' => $product->id,
30+
'buyable_type' => Product::class,
31+
'quantity' => mt_rand(1, 5),
32+
'price' => $product->price,
33+
'name' => $product->name,
34+
]);
35+
});
36+
}
37+
38+
public function test_discount_has_default_value(): void
39+
{
40+
$this->discountRule->apply($this->cart);
41+
42+
$discount = $this->cart->discounts()->first()->discount;
43+
44+
$this->assertInstanceOf(Discount::class, $discount);
45+
$this->assertEquals(0.0, $discount->value);
46+
}
47+
48+
public function test_discount_value_can_be_set(): void
49+
{
50+
$this->cart->discounts()->attach($this->discountRule, ['value' => 25.50]);
51+
52+
$discount = $this->cart->discounts()->first()->discount;
53+
54+
$this->assertEquals(25.50, $discount->value);
55+
}
56+
57+
public function test_discount_can_be_formatted(): void
58+
{
59+
$this->cart->discounts()->attach($this->discountRule, ['value' => 10.00]);
60+
61+
$discount = $this->cart->discounts()->first()->discount;
62+
63+
$formatted = $discount->format();
64+
65+
$this->assertIsString($formatted);
66+
}
67+
68+
public function test_discount_has_formatted_value_attribute(): void
69+
{
70+
$this->cart->discounts()->attach($this->discountRule, ['value' => 15.00]);
71+
72+
$discount = $this->cart->discounts()->first()->discount;
73+
74+
$this->assertIsString($discount->formatted_value);
75+
}
76+
}

0 commit comments

Comments
 (0)