test updates & working on calculating condition values based on orders

This commit is contained in:
Joel Male
2024-08-15 17:21:19 +10:00
parent 77fa8601b9
commit 85ae0c30c5
10 changed files with 1758 additions and 972 deletions
+41 -1
View File
@@ -341,7 +341,14 @@ #### Getting conditions on the cart: **Cart::getConditions()**
$condition->getAttributes(); // the attributes of the condition, returns an empty [] if no attributes added $condition->getAttributes(); // the attributes of the condition, returns an empty [] if no attributes added
``` ```
### Calculating condition value: **Cart::getCondition('Tax: 10%')->getCalculatedValue($subTotal)** ### Calculating condition value
There are 2 ways to calculate the value of a condition:
1. Using the `getCalculatedValue` method on the condition instance
2. Using the `getCalculatedValueForCondition` method on the cart instance and passing the condition name
#### Using the `getCalculatedValue` method on the condition instance
```php ```php
$subTotal = Cart::getSubTotal(); $subTotal = Cart::getSubTotal();
@@ -349,6 +356,39 @@ ### Calculating condition value: **Cart::getCondition('Tax: 10%')->getCalculated
$conditionCalculatedValue = $condition->getCalculatedValue($subTotal); $conditionCalculatedValue = $condition->getCalculatedValue($subTotal);
``` ```
#### Using the `getCalculatedValueForCondition` method on the cart instance
This method automatically calculates the value of a condition by it's name based on the order of the conditions.
```php
Cart::add([
'id' => 1,
'name' => 'Apple iPhone 15',
'price' => 200,
'quantity' => 1,
'attributes' => [],
]);
$couponDiscount = new CartCondition([
'name' => 'Coupon Discount',
'type' => 'discount',
'target' => 'subtotal',
'value' => '-200',
'order' => 1,
]);
$giftCard = new CartCondition([
'name' => 'Gift Card',
'type' => 'discount',
'target' => 'subtotal',
'value' => '-200',
'order' => 2,
]);
Cart::getCalculatedValueForCondition('Coupon Discount'); // returns 200
Cart::getCalculatedValueForCondition('Gift Card'); // returns 0 as the coupon discount is applied first and brings the subtotal to 0
```
### Condition on items ### Condition on items
Item conditions are useful if you have discounts to be applied specifically on an item and not on the whole cart value. Item conditions are useful if you have discounts to be applied specifically on an item and not on the whole cart value.
+2 -1
View File
@@ -27,7 +27,8 @@
"require-dev": { "require-dev": {
"mockery/mockery": "^1.4.2", "mockery/mockery": "^1.4.2",
"laravel/pint": "dev-main", "laravel/pint": "dev-main",
"pestphp/pest": "2.34.4" "pestphp/pest": "2.34.4",
"larapack/dd": "dev-master"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
Generated
+145 -21
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b25e260acd3e7cf87e600ba7103131f4", "content-hash": "b15572aabc5ce8af520d03870b1943ea",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@@ -816,12 +816,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/validation.git", "url": "https://github.com/illuminate/validation.git",
"reference": "9398c6e24bf1b0ac12a7160f85bd0cc5e8f4305d" "reference": "60474ce720aab7264ed8d75a344e8a8af911e417"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/validation/zipball/9398c6e24bf1b0ac12a7160f85bd0cc5e8f4305d", "url": "https://api.github.com/repos/illuminate/validation/zipball/60474ce720aab7264ed8d75a344e8a8af911e417",
"reference": "9398c6e24bf1b0ac12a7160f85bd0cc5e8f4305d", "reference": "60474ce720aab7264ed8d75a344e8a8af911e417",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -869,7 +869,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2024-08-05T13:45:12+00:00" "time": "2024-08-13T17:23:08+00:00"
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
@@ -1212,12 +1212,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "51c0ff591e6295f21e1789e55a6e57457980895e" "reference": "0470b8dc10ca08d23aeaabbed5b961c928e4d89d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/51c0ff591e6295f21e1789e55a6e57457980895e", "url": "https://api.github.com/repos/symfony/finder/zipball/0470b8dc10ca08d23aeaabbed5b961c928e4d89d",
"reference": "51c0ff591e6295f21e1789e55a6e57457980895e", "reference": "0470b8dc10ca08d23aeaabbed5b961c928e4d89d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1268,7 +1268,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-08-12T10:26:02+00:00" "time": "2024-08-13T14:29:53+00:00"
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
@@ -1276,12 +1276,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-foundation.git", "url": "https://github.com/symfony/http-foundation.git",
"reference": "4187b642a75b3d56ae1bf1461091eedbef2e06d6" "reference": "79d0023c23d92d49c43be47c726e92366b4d3a81"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/4187b642a75b3d56ae1bf1461091eedbef2e06d6", "url": "https://api.github.com/repos/symfony/http-foundation/zipball/79d0023c23d92d49c43be47c726e92366b4d3a81",
"reference": "4187b642a75b3d56ae1bf1461091eedbef2e06d6", "reference": "79d0023c23d92d49c43be47c726e92366b4d3a81",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1345,7 +1345,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-08-06T10:13:58+00:00" "time": "2024-08-13T12:32:31+00:00"
}, },
{ {
"name": "symfony/mime", "name": "symfony/mime",
@@ -1353,12 +1353,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mime.git", "url": "https://github.com/symfony/mime.git",
"reference": "ab31998ee18185ce4cdea28bb52ffbda575378ee" "reference": "52dc06994d8ee1f97bdc6a80c758c1a6bc482f78"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/ab31998ee18185ce4cdea28bb52ffbda575378ee", "url": "https://api.github.com/repos/symfony/mime/zipball/52dc06994d8ee1f97bdc6a80c758c1a6bc482f78",
"reference": "ab31998ee18185ce4cdea28bb52ffbda575378ee", "reference": "52dc06994d8ee1f97bdc6a80c758c1a6bc482f78",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1429,7 +1429,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-08-12T12:27:03+00:00" "time": "2024-08-13T14:29:53+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-idn", "name": "symfony/polyfill-intl-idn",
@@ -2465,6 +2465,47 @@
}, },
"time": "2024-08-01T12:14:16+00:00" "time": "2024-08-01T12:14:16+00:00"
}, },
{
"name": "larapack/dd",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/larapack/dd.git",
"reference": "561b5111a13d0094b59b5c81b1572489485fb948"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larapack/dd/zipball/561b5111a13d0094b59b5c81b1572489485fb948",
"reference": "561b5111a13d0094b59b5c81b1572489485fb948",
"shasum": ""
},
"require": {
"symfony/var-dumper": "*"
},
"default-branch": true,
"type": "package",
"autoload": {
"files": [
"src/helper.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Topper",
"email": "hi@webman.io"
}
],
"description": "`dd` is a helper method in Laravel. This package will add the `dd` to your application.",
"support": {
"issues": "https://github.com/larapack/dd/issues",
"source": "https://github.com/larapack/dd/tree/v1.1"
},
"time": "2016-12-15T09:34:34+00:00"
},
{ {
"name": "laravel/pint", "name": "laravel/pint",
"version": "dev-main", "version": "dev-main",
@@ -4918,12 +4959,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "2204ca36f39ffe9bc0856123d45fd6cea52a2681" "reference": "3c43d7ec3eb45e0eac993e86bee2905bfee5246b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/2204ca36f39ffe9bc0856123d45fd6cea52a2681", "url": "https://api.github.com/repos/symfony/console/zipball/3c43d7ec3eb45e0eac993e86bee2905bfee5246b",
"reference": "2204ca36f39ffe9bc0856123d45fd6cea52a2681", "reference": "3c43d7ec3eb45e0eac993e86bee2905bfee5246b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5003,7 +5044,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-08-12T10:26:02+00:00" "time": "2024-08-13T14:29:53+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -5464,6 +5505,89 @@
], ],
"time": "2024-08-12T10:26:02+00:00" "time": "2024-08-12T10:26:02+00:00"
}, },
{
"name": "symfony/var-dumper",
"version": "7.2.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "122ba59267fc82caa8f1f509332d4b94a223013b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/122ba59267fc82caa8f1f509332d4b94a223013b",
"reference": "122ba59267fc82caa8f1f509332d4b94a223013b",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/console": "<6.4"
},
"require-dev": {
"ext-iconv": "*",
"symfony/console": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/uid": "^6.4|^7.0",
"twig/twig": "^3.0.4"
},
"bin": [
"Resources/bin/var-dump-server"
],
"type": "library",
"autoload": {
"files": [
"Resources/functions/dump.php"
],
"psr-4": {
"Symfony\\Component\\VarDumper\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides mechanisms for walking through any arbitrary PHP variable",
"homepage": "https://symfony.com",
"keywords": [
"debug",
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/7.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-08-13T14:29:53+00:00"
},
{ {
"name": "ta-tikoma/phpunit-architecture-test", "name": "ta-tikoma/phpunit-architecture-test",
"version": "0.8.4", "version": "0.8.4",
+52 -44
View File
@@ -360,7 +360,7 @@ public function clear()
* *
* @throws InvalidConditionException * @throws InvalidConditionException
*/ */
public function condition($condition) public function condition(CartCondition $condition)
{ {
if (is_array($condition)) { if (is_array($condition)) {
foreach ($condition as $c) { foreach ($condition as $c) {
@@ -568,81 +568,89 @@ public function getSubTotalWithoutConditions($formatted = true)
* get cart sub total * get cart sub total
* *
* @param bool $formatted * @param bool $formatted
* @return float
*/ */
public function getSubTotal($formatted = true) public function getSubTotal($formatted = true): int|float
{ {
$cart = $this->getContent(); $subTotal = 0.00;
// add all the items together with conditions applied
$sum = $cart->sum(function (ItemCollection $item) { $subTotalSum = $this->getContent()->sum(function (ItemCollection $item) {
return $item->getPriceSumWithConditions(false); return $item->getPriceSumWithConditions(false);
}); });
// get the conditions that are meant to be applied // get the conditions that are meant to be applied
// on the subtotal and apply it here before returning the subtotal // on the subtotal and apply it here before returning the subtotal
$conditions = $this $conditionsForSubtotal = $this->getConditions()
->getConditions() ->filter(function (CartCondition $condition) {
->filter(function (CartCondition $cond) { return $condition->getTarget() === 'subtotal';
return $cond->getTarget() === 'subtotal'; })
->sortBy(function (CartCondition $condition) {
return $condition->getOrder();
}); });
// if there is no conditions, lets just return the sum if ($conditionsForSubtotal->isEmpty()) {
if (! $conditions->count()) { return Helpers::formatValue($subTotalSum, $formatted, $this->config);
return Helpers::formatValue($sum, $formatted, $this->config);
} }
// there are conditions, lets apply it $index = 0;
$newTotal = 0.00;
$process = 0;
$conditions->each(function (CartCondition $cond) use ($sum, &$newTotal, &$process) { $conditionsForSubtotal->each(function (CartCondition $condition) use ($subTotalSum, &$subTotal, &$index) {
$toBeCalculated = $index > 0 ? $subTotal : $subTotalSum;
// if this is the first iteration, the toBeCalculated $subTotal = $condition->applyCondition($toBeCalculated);
// should be the sum as initial point of value.
$toBeCalculated = ($process > 0) ? $newTotal : $sum;
$newTotal = $cond->applyCondition($toBeCalculated); $index++;
$process++;
}); });
return Helpers::formatValue((float) $newTotal, $formatted, $this->config); return Helpers::formatValue($subTotal, $formatted, $this->config);
} }
/** /**
* the new total in which conditions are already applied * Get the total of the cart with conditions applied
*
* @return float
*/ */
public function getTotal() public function getTotal(): int|float
{ {
$total = 0.00;
$subTotal = $this->getSubTotal(false); $subTotal = $this->getSubTotal(false);
$newTotal = 0.00; $conditionsForTotal = $this->getConditions()
->filter(function (CartCondition $condition) {
$process = 0; return $condition->getTarget() === 'total';
$conditions = $this
->getConditions()
->filter(function (CartCondition $cond) {
return $cond->getTarget() === 'total';
}); });
// if no conditions were added, just return the sub total // if no conditions were added, just return the sub total
if (! $conditions->count()) { if (! $conditionsForTotal->count()) {
return Helpers::formatValue($subTotal, $this->config['format_numbers'], $this->config); return Helpers::formatValue($subTotal, $this->config['format_numbers'], $this->config);
} }
$conditions $conditionsForTotal->each(function (CartCondition $condition) use ($subTotal, &$total) {
->each(function (CartCondition $cond) use ($subTotal, &$newTotal, &$process) { $toBeCalculated = $total > 0 ? $total : $subTotal;
$toBeCalculated = ($process > 0) ? $newTotal : $subTotal;
$newTotal = $cond->applyCondition($toBeCalculated); $total = $condition->applyCondition($toBeCalculated);
$process++;
}); });
return Helpers::formatValue($newTotal, $this->config['format_numbers'], $this->config); return Helpers::formatValue($total, $this->config['format_numbers'], $this->config);
}
/**
* Get the calculated value for a condition by it's name
*/
public function getCalculatedValueForCondition(string $conditionName): int|float
{
$conditions = $this->getConditions();
$subTotal = $this->getSubTotalWithoutConditions(false);
foreach ($conditions as $condition) {
$conditionValue = $condition->getCalculatedValue($subTotal);
if ($condition->getName() === $conditionName) {
return $conditionValue;
}
$subTotal -= $conditionValue;
}
return 0;
} }
/** /**
+19 -5
View File
@@ -16,7 +16,7 @@ class CartCondition
/** /**
* the parsed raw value of the condition * the parsed raw value of the condition
*/ */
public $parsedRawValue; public $parsedRawValue = 0;
/** /**
* @param array $args (name, type, target, value) * @param array $args (name, type, target, value)
@@ -77,14 +77,20 @@ public function getAttributes()
/** /**
* the value of this the condition * the value of this the condition
*
* @return mixed
*/ */
public function getValue() public function getValue(): int|float
{ {
return $this->args['value']; return $this->args['value'];
} }
/**
* Set the value of this condition
*/
public function setValue($value): void
{
$this->args['value'] = $value;
}
/** /**
* Set the order to apply this condition. If no argument order is applied we return 0 as * Set the order to apply this condition. If no argument order is applied we return 0 as
* indicator that no assignment has been made * indicator that no assignment has been made
@@ -123,9 +129,11 @@ public function applyCondition($totalOrSubTotalOrPrice)
* *
* @return mixed * @return mixed
*/ */
public function getCalculatedValue($totalOrSubTotalOrPrice) public function getCalculatedValue($totalOrSubTotalOrPrice = null): int|float
{ {
if ($totalOrSubTotalOrPrice) {
$this->apply($totalOrSubTotalOrPrice, $this->getValue()); $this->apply($totalOrSubTotalOrPrice, $this->getValue());
}
return $this->parsedRawValue; return $this->parsedRawValue;
} }
@@ -137,6 +145,12 @@ public function getCalculatedValue($totalOrSubTotalOrPrice)
*/ */
protected function apply($totalOrSubTotalOrPrice, $conditionValue) protected function apply($totalOrSubTotalOrPrice, $conditionValue)
{ {
if ($totalOrSubTotalOrPrice <= 0) {
$this->parsedRawValue = 0;
return;
}
// if value has a percentage sign on it, we will get first // if value has a percentage sign on it, we will get first
// its percentage then we will evaluate again if the value // its percentage then we will evaluate again if the value
// has a minus or plus sign so we can decide what to do with the // has a minus or plus sign so we can decide what to do with the
+4
View File
@@ -56,6 +56,10 @@ public static function issetAndHasValueOrAssignDefault(&$var, $default = false)
public static function formatValue($value, $formatNumber, $config) public static function formatValue($value, $formatNumber, $config)
{ {
if (! $value) {
return 0;
}
if ($formatNumber || $config['format_numbers']) { if ($formatNumber || $config['format_numbers']) {
return floatval(number_format($value, $config['decimals'], $config['dec_point'], $config['thousands_sep'])); return floatval(number_format($value, $config['decimals'], $config['dec_point'], $config['thousands_sep']));
} else { } else {
+9
View File
@@ -0,0 +1,9 @@
<?php
return [
'format_numbers' => true,
'decimals' => 2,
'dec_point' => '.',
'thousands_sep' => ',',
'use_cents' => false,
];
-40
View File
@@ -27,43 +27,3 @@
expect()->extend('toBeOne', function () { expect()->extend('toBeOne', function () {
return $this->toBe(1); return $this->toBe(1);
}); });
/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/
function fillCart()
{
$items = [
[
'id' => 456,
'name' => 'Sample Item 1',
'price' => 67.99,
'quantity' => 1,
'attributes' => [],
],
[
'id' => 568,
'name' => 'Sample Item 2',
'price' => 69.25,
'quantity' => 1,
'attributes' => [],
],
[
'id' => 856,
'name' => 'Sample Item 3',
'price' => 50.25,
'quantity' => 1,
'attributes' => [],
],
];
$this->cart->add($items);
}
File diff suppressed because it is too large Load Diff
+18 -7
View File
@@ -21,25 +21,35 @@
Mockery::close(); Mockery::close();
}); });
test('cart can add item', function () { describe('cart', function () {
$this->cart->add(455, 'Sample Item', 100.99, 2, []); test('can add an item', function () {
$this->cart->add(1, 'Sample Item', 100.99, 2, []);
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty'); expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1'); expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
expect($this->cart->getContent()->first()['id'])->toEqual(455, 'Item added has ID of 455 so first content ID should be 455'); expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
expect($this->cart->getContent()->first()['price'])->toEqual(100.99, 'Item added has price of 100.99 so first content price should be 100.99'); expect($this->cart->getContent()->first()['price'])->toEqual(100.99, 'Item added has price of 100.99 so first content price should be 100.99');
}); });
test('cart can add item with no price', function () { test('can add an item in cents', function () {
$this->cart->add(1, 'Sample Item', 10099, 2, []);
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
expect($this->cart->getContent()->first()['price'])->toEqual(10099, 'Item added has price of 100.99 so first content price should be 100.99');
})->only();
test('can add an item with no price', function () {
$this->cart->add(455, 'Sample Item', 0, 2, []); $this->cart->add(455, 'Sample Item', 0, 2, []);
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty'); expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1'); expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
expect($this->cart->getContent()->first()['id'])->toEqual(455, 'Item added has ID of 455 so first content ID should be 455'); expect($this->cart->getContent()->first()['id'])->toEqual(455, 'Item added has ID of 455 so first content ID should be 455');
expect($this->cart->getTotal())->toEqual(0, 'Total should be 0'); expect($this->cart->getTotal())->toEqual(0, 'Total should be 0');
}); });
test('cart can add items as array', function () { test('can add items as array', function () {
$item = [ $item = [
'id' => 456, 'id' => 456,
'name' => 'Sample Item', 'name' => 'Sample Item',
@@ -54,6 +64,7 @@
expect($this->cart->getContent()->count())->toEqual(1, 'Cart should have 1 item on it'); expect($this->cart->getContent()->count())->toEqual(1, 'Cart should have 1 item on it');
expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456'); expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456');
expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"'); expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"');
});
}); });
test('cart can add items with multidimensional array', function () { test('cart can add items with multidimensional array', function () {