652 lines
23 KiB
PHP
652 lines
23 KiB
PHP
<?php
|
||
|
||
namespace Blax\Shop\Tests\Feature\Checkout;
|
||
|
||
use Blax\Shop\Enums\ProductType;
|
||
use Blax\Shop\Models\Cart;
|
||
use Blax\Shop\Models\Product;
|
||
use Blax\Shop\Models\ProductPrice;
|
||
use Blax\Shop\Tests\TestCase;
|
||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
use Workbench\App\Models\User;
|
||
use PHPUnit\Framework\Attributes\Test;
|
||
|
||
class CartCheckoutSessionTest extends TestCase
|
||
{
|
||
use RefreshDatabase;
|
||
|
||
protected User $user;
|
||
protected Cart $cart;
|
||
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
|
||
$this->user = User::factory()->create();
|
||
$this->cart = Cart::factory()->create([
|
||
'customer_id' => $this->user->id,
|
||
'customer_type' => get_class($this->user),
|
||
]);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_throws_exception_when_stripe_is_disabled()
|
||
{
|
||
config(['shop.stripe.enabled' => false]);
|
||
|
||
$product = Product::factory()->create(['manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000,
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$this->expectException(\Exception::class);
|
||
$this->expectExceptionMessage('Stripe is not enabled');
|
||
|
||
$this->cart->checkoutSession();
|
||
}
|
||
|
||
#[Test]
|
||
public function it_builds_checkout_session_with_simple_product_without_stripe_api()
|
||
{
|
||
// Enable Stripe but don't actually call the API
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['shop.currency' => 'usd']);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create([
|
||
'name' => 'Test Product',
|
||
'short_description' => 'Short desc',
|
||
'manage_stock' => false,
|
||
]);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1500, // $15.00
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
$this->cart->addToCart($product, 2);
|
||
|
||
// Mock the Stripe API to avoid actual calls
|
||
$this->mockStripeCheckoutSession();
|
||
|
||
$session = $this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
// Verify the session was created with correct parameters
|
||
$this->assertNotNull($session);
|
||
$this->assertEquals('mock_session_id', $session->id);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_includes_booking_dates_in_product_name()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$bookingProduct = Product::factory()->create([
|
||
'name' => 'Hotel Room',
|
||
'type' => ProductType::BOOKING,
|
||
'manage_stock' => true,
|
||
]);
|
||
$bookingProduct->increaseStock(10);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $bookingProduct->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 10000, // $100 per day
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
$from = now()->addDays(1)->startOfDay();
|
||
$until = now()->addDays(3)->startOfDay(); // 2 days
|
||
|
||
$this->cart->addToCart($bookingProduct, 1, [], $from, $until);
|
||
|
||
// Capture the session params
|
||
$sessionParams = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$sessionParams) {
|
||
$sessionParams = $params;
|
||
$mockSession = new \stdClass();
|
||
$mockSession->id = 'mock_session_id';
|
||
return $mockSession;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
$data = $sessionParams['line_items'][0]['price_data']['product_data'];
|
||
|
||
$this->assertStringContainsString('Hotel Room', $data['name']);
|
||
$this->assertStringContainsString('from', $data['description']);
|
||
$this->assertStringContainsString('to', $data['description']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_calculates_correct_unit_amount_in_cents()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Test Product', 'manage_stock' => false]);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 2550, // $25.50
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
// Capture the session params
|
||
$sessionParams = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$sessionParams) {
|
||
$sessionParams = $params;
|
||
$mockSession = new \stdClass();
|
||
$mockSession->id = 'mock_session_id';
|
||
return $mockSession;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
// Price is stored in cents (2550), Stripe expects cents (2550)
|
||
$this->assertEquals(2550, $sessionParams['line_items'][0]['price_data']['unit_amount']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_handles_booking_with_fractional_days()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$bookingProduct = Product::factory()->create([
|
||
'name' => 'Parking Spot',
|
||
'type' => ProductType::BOOKING,
|
||
'manage_stock' => true,
|
||
]);
|
||
$bookingProduct->increaseStock(10);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $bookingProduct->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000, // $10 per day
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
// 4 hours booking (0.1667 days)
|
||
$from = now()->addDays(1)->setTime(10, 0);
|
||
$until = now()->addDays(1)->setTime(14, 0);
|
||
|
||
$this->cart->addToCart($bookingProduct, 1, [], $from, $until);
|
||
|
||
// Capture the session params
|
||
$sessionParams = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$sessionParams) {
|
||
$sessionParams = $params;
|
||
$mockSession = new \stdClass();
|
||
$mockSession->id = 'mock_session_id';
|
||
return $mockSession;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
// The cart item should have calculated the fractional day price
|
||
$cartItem = $this->cart->items->first();
|
||
|
||
// Price is already in cents, no conversion needed
|
||
$this->assertEquals($cartItem->price, $sessionParams['line_items'][0]['price_data']['unit_amount']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_creates_separate_line_items_for_multiple_products()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product1 = Product::factory()->create(['name' => 'Product 1', 'manage_stock' => false]);
|
||
$product2 = Product::factory()->create(['name' => 'Product 2', 'manage_stock' => false]);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product1->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000,
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
'type' => 'one_time',
|
||
]);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product2->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 2000,
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
'type' => 'one_time',
|
||
]);
|
||
|
||
$this->cart->addToCart($product1, 2);
|
||
$this->cart->addToCart($product2, 1);
|
||
|
||
// Capture the session params
|
||
$sessionParams = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$sessionParams) {
|
||
$sessionParams = $params;
|
||
$mockSession = new \stdClass();
|
||
$mockSession->id = 'mock_session_id';
|
||
return $mockSession;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
$this->assertCount(2, $sessionParams['line_items']);
|
||
$this->assertEquals(2, $sessionParams['line_items'][0]['quantity']);
|
||
$this->assertEquals(1, $sessionParams['line_items'][1]['quantity']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_uses_configured_currency()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['shop.currency' => 'eur']);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Product', 'manage_stock' => false]);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
// Capture the session params
|
||
$sessionParams = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$sessionParams) {
|
||
$sessionParams = $params;
|
||
$mockSession = new \stdClass();
|
||
$mockSession->id = 'mock_session_id';
|
||
return $mockSession;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
$this->assertEquals('eur', $sessionParams['line_items'][0]['price_data']['currency']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_stores_session_id_in_cart_meta()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Product', 'manage_stock' => false]);
|
||
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000,
|
||
'currency' => 'USD',
|
||
'is_default' => true,
|
||
]);
|
||
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$this->mockStripeCheckoutSession();
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/success',
|
||
'cancel_url' => 'https://example.com/cancel',
|
||
]);
|
||
|
||
$this->cart->refresh();
|
||
$meta = $this->cart->meta;
|
||
|
||
$this->assertNotNull($meta->stripe_session_id ?? null);
|
||
$this->assertEquals('mock_session_id', $meta->stripe_session_id);
|
||
}
|
||
|
||
#[Test]
|
||
public function checkout_session_emits_lowercase_currency_codes(): void
|
||
{
|
||
// Regression: Cart::checkoutSession() used to call
|
||
// `strtoupper($this->currency)`, but Stripe expects lowercase ISO
|
||
// codes — host apps were sending 'USD' / 'EUR' to Stripe by mistake.
|
||
// The implementation now consistently lowercases the resolved
|
||
// currency at both the session level and per line item.
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['shop.currency' => 'eur']);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'P', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000,
|
||
'currency' => 'EUR', // intentionally uppercase on the price model
|
||
'is_default' => true,
|
||
]);
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$captured = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$captured) {
|
||
$captured = $params;
|
||
$session = new \stdClass();
|
||
$session->id = 'mock';
|
||
return $session;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/s',
|
||
'cancel_url' => 'https://example.com/c',
|
||
]);
|
||
|
||
// Session-level: lowercase regardless of how the cart row spells it.
|
||
$this->assertSame('eur', $captured['currency']);
|
||
// Line-item: derives from the price model's currency and lowercases it.
|
||
$this->assertSame('eur', $captured['line_items'][0]['price_data']['currency']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_uses_subscription_mode_and_synced_price_for_recurring_lines()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Sub', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1990,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
'type' => 'recurring',
|
||
'interval' => 'month',
|
||
'interval_count' => 1,
|
||
'stripe_price_id' => 'price_sub_123',
|
||
]);
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$captured = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$captured) {
|
||
$captured = $params;
|
||
$s = new \stdClass();
|
||
$s->id = 'mock';
|
||
return $s;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/s',
|
||
'cancel_url' => 'https://example.com/c',
|
||
]);
|
||
|
||
$this->assertSame('subscription', $captured['mode']);
|
||
// Recurring line with a synced Stripe Price uses `price`, not price_data.
|
||
$this->assertSame('price_sub_123', $captured['line_items'][0]['price']);
|
||
$this->assertArrayNotHasKey('price_data', $captured['line_items'][0]);
|
||
// The cart id rides along on the subscription for webhook mapping.
|
||
$this->assertSame($this->cart->id, $captured['subscription_data']['metadata']['cart_id']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_builds_recurring_price_data_when_no_stripe_price_id()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Sub2', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 2500,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
'type' => 'recurring',
|
||
'interval' => 'year',
|
||
'interval_count' => 1,
|
||
'stripe_price_id' => null,
|
||
]);
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$captured = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$captured) {
|
||
$captured = $params;
|
||
$s = new \stdClass();
|
||
$s->id = 'mock';
|
||
return $s;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/s',
|
||
'cancel_url' => 'https://example.com/c',
|
||
]);
|
||
|
||
$this->assertSame('subscription', $captured['mode']);
|
||
$recurring = $captured['line_items'][0]['price_data']['recurring'];
|
||
$this->assertSame('year', $recurring['interval']);
|
||
$this->assertSame(1, $recurring['interval_count']);
|
||
$this->assertSame(2500, $captured['line_items'][0]['price_data']['unit_amount']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_maps_quarter_interval_to_three_months()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Q', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 9000,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
'type' => 'recurring',
|
||
'interval' => 'quarter',
|
||
'interval_count' => 1,
|
||
'stripe_price_id' => null,
|
||
]);
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$captured = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$captured) {
|
||
$captured = $params;
|
||
$s = new \stdClass();
|
||
$s->id = 'mock';
|
||
return $s;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/s',
|
||
'cancel_url' => 'https://example.com/c',
|
||
]);
|
||
|
||
$recurring = $captured['line_items'][0]['price_data']['recurring'];
|
||
$this->assertSame('month', $recurring['interval']);
|
||
$this->assertSame(3, $recurring['interval_count']);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_uses_payment_mode_for_one_time_prices()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'OT', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 500,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
'type' => 'one_time',
|
||
'interval' => null,
|
||
'interval_count' => null,
|
||
]);
|
||
$this->cart->addToCart($product, 1);
|
||
|
||
$captured = null;
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$captured) {
|
||
$captured = $params;
|
||
$s = new \stdClass();
|
||
$s->id = 'mock';
|
||
return $s;
|
||
};
|
||
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/s',
|
||
'cancel_url' => 'https://example.com/c',
|
||
]);
|
||
|
||
$this->assertSame('payment', $captured['mode']);
|
||
$this->assertArrayNotHasKey('recurring', $captured['line_items'][0]['price_data']);
|
||
$this->assertArrayNotHasKey('subscription_data', $captured);
|
||
}
|
||
|
||
#[Test]
|
||
public function it_throws_when_mixing_recurring_and_one_time_prices()
|
||
{
|
||
config(['shop.stripe.enabled' => true]);
|
||
config(['services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$sub = Product::factory()->create(['name' => 'S', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $sub->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 1000,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
'type' => 'recurring',
|
||
'interval' => 'month',
|
||
'interval_count' => 1,
|
||
]);
|
||
|
||
$one = Product::factory()->create(['name' => 'O', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $one->id,
|
||
'purchasable_type' => Product::class,
|
||
'unit_amount' => 2000,
|
||
'currency' => 'EUR',
|
||
'is_default' => true,
|
||
'type' => 'one_time',
|
||
'interval' => null,
|
||
'interval_count' => null,
|
||
]);
|
||
|
||
$this->cart->addToCart($sub, 1);
|
||
$this->cart->addToCart($one, 1);
|
||
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) {
|
||
$s = new \stdClass();
|
||
$s->id = 'mock';
|
||
return $s;
|
||
};
|
||
|
||
$this->expectException(\Blax\Shop\Exceptions\MixedCheckoutModeException::class);
|
||
$this->cart->checkoutSession([
|
||
'success_url' => 'https://example.com/s',
|
||
'cancel_url' => 'https://example.com/c',
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Mock Stripe Checkout Session creation to avoid actual API calls
|
||
*/
|
||
protected function mockStripeCheckoutSession()
|
||
{
|
||
// Create a simple mock that returns a session object
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) {
|
||
$mockSession = new \stdClass();
|
||
$mockSession->id = 'mock_session_id';
|
||
$mockSession->url = 'https://checkout.stripe.com/mock';
|
||
return $mockSession;
|
||
};
|
||
}
|
||
}
|
||
|
||
// Add a simple mock capability to Stripe Session class for testing
|
||
namespace Stripe\Checkout;
|
||
|
||
class Session
|
||
{
|
||
public static $createCallback = null;
|
||
|
||
public static function create($params)
|
||
{
|
||
if (self::$createCallback) {
|
||
return call_user_func(self::$createCallback, $params);
|
||
}
|
||
|
||
// If no callback, throw exception (actual Stripe call would be made)
|
||
throw new \Exception('Stripe API call attempted without mock. Set createCallback first.');
|
||
}
|
||
|
||
public static function resetMock()
|
||
{
|
||
self::$createCallback = null;
|
||
}
|
||
|
||
#[Test]
|
||
public function line_item_names_the_chosen_price_only_when_enabled()
|
||
{
|
||
config(['shop.stripe.enabled' => true, 'services.stripe.secret' => 'sk_test_fake']);
|
||
|
||
$product = Product::factory()->create(['name' => 'Flat Art', 'manage_stock' => false]);
|
||
ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id, 'purchasable_type' => Product::class,
|
||
'unit_amount' => 5000, 'currency' => 'EUR', 'is_default' => true, 'name' => 'A5',
|
||
]);
|
||
$a4 = ProductPrice::factory()->create([
|
||
'purchasable_id' => $product->id, 'purchasable_type' => Product::class,
|
||
'unit_amount' => 7000, 'currency' => 'EUR', 'is_default' => false, 'name' => 'A4',
|
||
]);
|
||
|
||
$this->cart->addToCart($a4, 1);
|
||
|
||
$names = [];
|
||
\Stripe\Checkout\Session::$createCallback = function ($params) use (&$names) {
|
||
$names[] = $params['line_items'][0]['price_data']['product_data']['name'];
|
||
$mock = new \stdClass;
|
||
$mock->id = 'mock_session_id';
|
||
|
||
return $mock;
|
||
};
|
||
|
||
$this->cart->checkoutSession(['success_url' => 'https://example.com/s', 'cancel_url' => 'https://example.com/c']);
|
||
config(['shop.stripe.line_item_price_name' => true]);
|
||
$this->cart->checkoutSession(['success_url' => 'https://example.com/s', 'cancel_url' => 'https://example.com/c']);
|
||
|
||
$this->assertSame(['Flat Art', 'Flat Art – A4'], $names);
|
||
}
|
||
}
|