Lock File Updated And Squashed All Commits

This commit is contained in:
Devansh 2022-01-11 18:52:47 +05:30
parent 0ec071674a
commit 0c486dcf61
74 changed files with 2573 additions and 1105 deletions

View File

@ -77,6 +77,9 @@ jobs:
- name: Execute Trigger Tests
run: set -e && vendor/bin/codecept run trigger
- name: Execute API Tests
run: set -e && vendor/bin/codecept run api
- name: Persist Test Artifacts
uses: actions/upload-artifact@v1
if: always()

View File

@ -35,6 +35,7 @@ class Kernel extends HttpKernel
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
'bindings',
],

View File

@ -9,11 +9,10 @@
"type": "project",
"require": {
"php": "^7.4|^8.0",
"algolia/algoliasearch-client-php": "^2.2",
"astrotomic/laravel-translatable": "^11.0.0",
"aws/aws-sdk-php": "^3.171",
"babenkoivan/elastic-scout-driver": "^1.1",
"bagisto/legacy-api": "^1.0",
"bagisto/rest-api": "dev-master",
"bagistobrasil/bagisto-product-social-share": "^0.1.2",
"barryvdh/laravel-debugbar": "^3.1",
"barryvdh/laravel-dompdf": "^0.8.5|^0.9.0",
@ -31,6 +30,7 @@
"khaled.alshamaa/ar-php": "^6.0.0",
"konekt/concord": "^1.2",
"laravel/framework": "^8.75",
"laravel/sanctum": "^2.12",
"laravel/scout": "^8.0",
"laravel/socialite": "^5.0",
"laravel/tinker": "^2.0",
@ -45,6 +45,7 @@
"codeception/module-asserts": "^1.1",
"codeception/module-filesystem": "^1.0",
"codeception/module-laravel": "^2.0",
"codeception/module-rest": "^1.4",
"codeception/module-webdriver": "^1.0",
"filp/whoops": "^2.0",
"mockery/mockery": "^1.3.1",
@ -108,10 +109,10 @@
},
"autoload-dev": {
"psr-4": {
"Tests\\Acceptance\\": "tests/acceptance/",
"Tests\\API\\": "tests/api/",
"Tests\\Functional\\": "tests/functional/",
"Tests\\Unit\\": "tests/unit/",
"Tests\\Trigger\\": "tests/trigger/"
"Tests\\Trigger\\": "tests/trigger/",
"Tests\\Unit\\": "tests/unit/"
}
},
"extra": {

1065
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,60 +2,56 @@
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'admins',
'guard' => 'customer',
'passwords' => 'customers',
],
'guards' => [
'web' => [
'driver' => 'session',
'customer' => [
'driver' => 'session',
'provider' => 'customers',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'jwt',
'driver' => 'jwt',
'provider' => 'customers',
],
'customer' => [
'driver' => 'session',
'provider' => 'customers'
],
'admin' => [
'driver' => 'session',
'provider' => 'admins'
],
'admin-api' => [
'driver' => 'jwt',
'driver' => 'jwt',
'provider' => 'admins',
]
],
],
'providers' => [
'customers' => [
'driver' => 'eloquent',
'model' => Webkul\Customer\Models\Customer::class,
'model' => Webkul\Customer\Models\Customer::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => Webkul\User\Models\Admin::class,
]
'model' => Webkul\User\Models\Admin::class,
],
],
'passwords' => [
'admins' => [
'provider' => 'admins',
'table' => 'admin_password_resets',
'expire' => 60,
'throttle' => 60,
],
'customers' => [
'provider' => 'customers',
'table' => 'customer_password_resets',
'expire' => 60,
'table' => 'customer_password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'admin_password_resets',
'expire' => 60,
'throttle' => 60,
],
],

View File

@ -5,6 +5,7 @@ return [
'convention' => Webkul\Core\CoreConvention::class,
'modules' => [
/**
* Example:
* VendorA\ModuleX\Providers\ModuleServiceProvider::class,
@ -37,5 +38,6 @@ return [
\Webkul\Ui\Providers\ModuleServiceProvider::class,
\Webkul\User\Providers\ModuleServiceProvider::class,
\Webkul\Velocity\Providers\ModuleServiceProvider::class,
]
];
],
];

65
config/sanctum.php Normal file
View File

@ -0,0 +1,65 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['customer'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];

119
config/scout.php Normal file
View File

@ -0,0 +1,119 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Search Engine
|--------------------------------------------------------------------------
|
| This option controls the default search connection that gets used while
| using Laravel Scout. This connection is used when syncing all models
| to the search service. You should adjust this based on your needs.
|
| Supported: "algolia", "null"
|
*/
'driver' => env('SCOUT_DRIVER', null),
/*
|--------------------------------------------------------------------------
| Index Prefix
|--------------------------------------------------------------------------
|
| Here you may specify a prefix that will be applied to all search index
| names used by Scout. This prefix may be useful if you have multiple
| "tenants" or applications sharing the same search infrastructure.
|
*/
'prefix' => env('SCOUT_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Queue Data Syncing
|--------------------------------------------------------------------------
|
| This option allows you to control if the operations that sync your data
| with your search engines are queued. When this is set to "true" then
| all automatic data syncing will get queued for better performance.
|
*/
'queue' => env('SCOUT_QUEUE', false),
/*
|--------------------------------------------------------------------------
| Database Transactions
|--------------------------------------------------------------------------
|
| This configuration option determines if your data will only be synced
| with your search indexes after every open database transaction has
| been committed, thus preventing any discarded data from syncing.
|
*/
'after_commit' => false,
/*
|--------------------------------------------------------------------------
| Chunk Sizes
|--------------------------------------------------------------------------
|
| These options allow you to control the maximum chunk size when you are
| mass importing data into the search engine. This allows you to fine
| tune each of these chunk sizes based on the power of the servers.
|
*/
'chunk' => [
'searchable' => 500,
'unsearchable' => 500,
],
/*
|--------------------------------------------------------------------------
| Soft Deletes
|--------------------------------------------------------------------------
|
| This option allows to control whether to keep soft deleted records in
| the search indexes. Maintaining soft deleted records can be useful
| if your application still needs to search for the records later.
|
*/
'soft_delete' => false,
/*
|--------------------------------------------------------------------------
| Identify User
|--------------------------------------------------------------------------
|
| This option allows you to control whether to notify the search engine
| of the user performing the search. This is sometimes useful if the
| engine supports any analytics based on this application's users.
|
| Supported engines: "algolia"
|
*/
'identify' => env('SCOUT_IDENTIFY', false),
/*
|--------------------------------------------------------------------------
| Algolia Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your Algolia settings. Algolia is a cloud hosted
| search engine which works great with Scout out of the box. Just plug
| in your application ID and admin API key to get started searching.
|
*/
'algolia' => [
'id' => env('ALGOLIA_APP_ID', ''),
'secret' => env('ALGOLIA_SECRET', ''),
],
];

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePersonalAccessTokensTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->bigIncrements('id');
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('personal_access_tokens');
}
}

View File

@ -150,8 +150,8 @@ class CartRule
$customerGroupId = null;
if (Cart::getCurrentCustomer()->check()) {
$customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id;
if (auth()->guard()->check()) {
$customerGroupId = auth()->guard()->user()->customer_group_id;
} else {
$customerGuestGroup = $this->customerGroupRepository->getCustomerGuestGroup();

View File

@ -50,18 +50,6 @@ class CatalogRuleProductPrice
$this->customerGroupRepository = $customerGroupRepository;
}
/**
* Return current logged in customer
*
* @return \Webkul\Customer\Contracts\Customer|bool
*/
public function getCurrentCustomer()
{
$guard = request()->has('token') ? 'api' : 'customer';
return auth()->guard($guard);
}
/**
* Collect discount on cart
*
@ -198,8 +186,8 @@ class CatalogRuleProductPrice
*/
public function getRulePrice($product)
{
if ($this->getCurrentCustomer()->check()) {
$customerGroupId = $this->getCurrentCustomer()->user()->customer_group_id;
if (auth()->guard()->check()) {
$customerGroupId = auth()->guard()->user()->customer_group_id;
} else {
$customerGroup = $this->customerGroupRepository->getCustomerGuestGroup();

View File

@ -110,18 +110,6 @@ class Cart
$this->customerAddressRepository = $customerAddressRepository;
}
/**
* Return current logged in customer.
*
* @return \Webkul\Customer\Contracts\Customer|bool
*/
public function getCurrentCustomer()
{
$guard = request()->has('token') ? 'api' : 'customer';
return auth()->guard($guard);
}
/**
* Returns cart.
*
@ -131,9 +119,9 @@ class Cart
{
$cart = null;
if ($this->getCurrentCustomer()->check()) {
if (auth()->guard()->check()) {
$cart = $this->cartRepository->findOneWhere([
'customer_id' => $this->getCurrentCustomer()->user()->id,
'customer_id' => auth()->guard()->user()->id,
'is_active' => 1,
]);
} else if (session()->has('cart')) {
@ -261,12 +249,12 @@ class Cart
/**
* Fill in the customer data, as far as possible.
*/
if ($this->getCurrentCustomer()->check()) {
$cartData['customer_id'] = $this->getCurrentCustomer()->user()->id;
if (auth()->guard()->check()) {
$cartData['customer_id'] = auth()->guard()->user()->id;
$cartData['is_guest'] = 0;
$cartData['customer_first_name'] = $this->getCurrentCustomer()->user()->first_name;
$cartData['customer_last_name'] = $this->getCurrentCustomer()->user()->last_name;
$cartData['customer_email'] = $this->getCurrentCustomer()->user()->email;
$cartData['customer_first_name'] = auth()->guard()->user()->first_name;
$cartData['customer_last_name'] = auth()->guard()->user()->last_name;
$cartData['customer_email'] = auth()->guard()->user()->email;
} else {
$cartData['is_guest'] = 1;
}
@ -573,8 +561,8 @@ class Cart
$address = $cart->billing_address;
}
if ($address === null && auth()->guard('customer')->check()) {
$address = auth()->guard('customer')->user()->addresses()
if ($address === null && auth()->guard()->check()) {
$address = auth()->guard()->user()->addresses()
->where('default_address', 1)->first();
}
@ -670,7 +658,7 @@ class Cart
'customer_email' => $data['customer_email'],
'customer_first_name' => $data['customer_first_name'],
'customer_last_name' => $data['customer_last_name'],
'customer' => $this->getCurrentCustomer()->check() ? $this->getCurrentCustomer()->user() : null,
'customer' => auth()->guard()->check() ? auth()->guard()->user() : null,
'total_item_count' => $data['items_count'],
'total_qty_ordered' => $data['items_qty'],
'base_currency_code' => $data['base_currency_code'],
@ -809,8 +797,8 @@ class Cart
private function assignCustomerFields(\Webkul\Checkout\Contracts\Cart $cart): void
{
if (
$this->getCurrentCustomer()->check()
&& ($user = $this->getCurrentCustomer()->user())
auth()->guard()->check()
&& ($user = auth()->guard()->user())
&& $this->profileIsComplete($user)
) {
$cart->customer_email = $user->email;
@ -880,7 +868,7 @@ class Cart
{
$attributes = [];
$user = $this->getCurrentCustomer()->user();
$user = auth()->guard()->user();
if ($user) {
$attributes['first_name'] = $user->first_name;

View File

@ -2,11 +2,9 @@
namespace Webkul\Checkout\Database\Factories;
use Illuminate\Support\Facades\DB;
use Webkul\Customer\Models\Customer;
use Webkul\Checkout\Models\Cart;
use Webkul\Checkout\Models\CartAddress;
use Illuminate\Database\Eloquent\Factories\Factory;
use Webkul\Checkout\Models\Cart;
use Webkul\Customer\Models\Customer;
class CartFactory extends Factory
{
@ -24,34 +22,42 @@ class CartFactory extends Factory
*/
public function definition(): array
{
$now = date("Y-m-d H:i:s");
$lastOrder = DB::table('orders')
->orderBy('id', 'desc')
->select('id')
->first();
$customer = Customer::factory()
->create();
$now = date('Y-m-d H:i:s');
return [
'is_guest' => 0,
'is_active' => 1,
'customer_id' => $customer->id,
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'is_gift' => 0,
'base_currency_code' => 'EUR',
'is_guest' => 0,
'is_active' => 1,
'is_gift' => 0,
'base_currency_code' => 'EUR',
'channel_currency_code' => 'EUR',
'grand_total' => 0.0000,
'base_grand_total' => 0.0000,
'sub_total' => 0.0000,
'base_sub_total' => 0.0000,
'channel_id' => 1,
'created_at' => $now,
'updated_at' => $now,
'grand_total' => 0.0000,
'base_grand_total' => 0.0000,
'sub_total' => 0.0000,
'base_sub_total' => 0.0000,
'channel_id' => 1,
'created_at' => $now,
'updated_at' => $now,
];
}
}
/**
* Adjust customer.
*
* @return array
*/
public function adjustCustomer()
{
return $this->state(function (array $attributes) {
$customer = isset($attributes['customer_id'])
? Customer::query()->where('id', $attributes['customer_id'])->first()
: Customer::factory()->create();
return [
'customer_id' => $customer->id,
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
];
});
}
}

View File

@ -2,11 +2,10 @@
namespace Webkul\Checkout\Database\Factories;
use Faker\Generator as Faker;
use Illuminate\Database\Eloquent\Factories\Factory;
use Webkul\Checkout\Models\Cart;
use Webkul\Checkout\Models\CartItem;
use Webkul\Product\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
class CartItemFactory extends Factory
{
@ -24,32 +23,40 @@ class CartItemFactory extends Factory
*/
public function definition(): array
{
$now = date("Y-m-d H:i:s");
if (isset($attributes['product_id'])) {
$product = Product::query()
->where('id', $attributes['product_id'])
->first();
} else {
$product = Product::factory()
->create();
}
$fallbackPrice = $this->faker->randomFloat(4, 0, 1000);
$now = date('Y-m-d H:i:s');
return [
'quantity' => 1,
'sku' => $product->sku,
'type' => $product->type,
'name' => $product->name,
'price' => $product->price ?? $fallbackPrice,
'base_price' => $product->price ?? $fallbackPrice,
'total' => $product->price ?? $fallbackPrice,
'base_total' => $product->price ?? $fallbackPrice,
'product_id' => $product->id,
'cart_id' => Cart::factory(),
'quantity' => 1,
'cart_id' => Cart::factory(),
'created_at' => $now,
'updated_at' => $now,
];
}
/**
* Adjust product.
*
* @return array
*/
public function adjustProduct()
{
return $this->state(function (array $attributes) {
$product = isset($attributes['product_id'])
? Product::query()->where('id', $attributes['product_id'])->first()
: Product::factory()->create();
$fallbackPrice = $this->faker->randomFloat(4, 0, 1000);
return [
'sku' => $product->sku,
'type' => $product->type,
'name' => $product->name,
'price' => $product->price ?? $fallbackPrice,
'base_price' => $product->price ?? $fallbackPrice,
'total' => $product->price ?? $fallbackPrice,
'base_total' => $product->price ?? $fallbackPrice,
'product_id' => $product->id,
];
});
}
}

View File

@ -8,6 +8,8 @@ class CustomerAddressForm extends FormRequest
{
/**
* Rules.
*
* @var array
*/
protected $rules = [];
@ -100,9 +102,7 @@ class CustomerAddressForm extends FormRequest
*/
private function getCustomerAddressIds(): string
{
$guard = request()->has('token') ? 'api' : 'customer';
if ($customer = auth($guard)->user()) {
if ($customer = auth()->guard()->user()) {
return $customer->addresses->pluck('id')->join(',');
}

View File

@ -2,21 +2,26 @@
namespace Webkul\Checkout\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\ServiceProvider;
use Webkul\Checkout\Facades\Cart;
class CheckoutServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
include __DIR__ . '/../Http/helpers.php';
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
$this->app->register(ModuleServiceProvider::class);
$this->app->register(EventServiceProvider::class);
$this->app->register(ModuleServiceProvider::class);
}
/**
@ -30,22 +35,20 @@ class CheckoutServiceProvider extends ServiceProvider
}
/**
* Register Bouncer as a singleton.
* Register cart as a singleton.
*
* @return void
*/
protected function registerFacades(): void
{
//to make the cart facade and bind the
//alias to the class needed to be called.
$loader = AliasLoader::getInstance();
$loader->alias('cart', Cart::class);
$this->app->singleton('cart', function () {
return new cart();
return new Cart();
});
$this->app->bind('cart', 'Webkul\Checkout\Cart');
$this->app->bind('cart', \Webkul\Checkout\Cart::class);
}
}
}

View File

@ -19,7 +19,7 @@ trait CartTools
*/
public function putCart($cart)
{
if (! $this->getCurrentCustomer()->check()) {
if (! auth()->guard()->check()) {
session()->put('cart', $cart);
}
}
@ -33,7 +33,7 @@ trait CartTools
{
if (session()->has('cart')) {
$cart = $this->cartRepository->findOneWhere([
'customer_id' => $this->getCurrentCustomer()->user()->id,
'customer_id' => auth()->guard()->user()->id,
'is_active' => 1,
]);
@ -44,11 +44,11 @@ trait CartTools
*/
if (! $cart) {
$this->cartRepository->update([
'customer_id' => $this->getCurrentCustomer()->user()->id,
'customer_id' => auth()->guard()->user()->id,
'is_guest' => 0,
'customer_first_name' => $this->getCurrentCustomer()->user()->first_name,
'customer_last_name' => $this->getCurrentCustomer()->user()->last_name,
'customer_email' => $this->getCurrentCustomer()->user()->email,
'customer_first_name' => auth()->guard()->user()->first_name,
'customer_last_name' => auth()->guard()->user()->last_name,
'customer_email' => auth()->guard()->user()->email,
], $guestCart->id);
session()->forget('cart');
@ -204,7 +204,7 @@ trait CartTools
}
$wishlistItems = $this->wishlistRepository->findWhere([
'customer_id' => $this->getCurrentCustomer()->user()->id,
'customer_id' => auth()->guard()->user()->id,
'product_id' => $cartItem->product_id,
]);
@ -225,7 +225,7 @@ trait CartTools
if (! $found) {
$this->wishlistRepository->create([
'channel_id' => $cart->channel_id,
'customer_id' => $this->getCurrentCustomer()->user()->id,
'customer_id' => auth()->guard()->user()->id,
'product_id' => $cartItem->product_id,
'additional' => $cartItem->additional,
]);

View File

@ -19,7 +19,7 @@ trait CartValidators
*/
public function hasProduct($product): bool
{
$cart = \Cart::getCart();
$cart = $this->getCart();
if (! $cart) {
return false;

View File

@ -5,6 +5,7 @@ return [
'convention' => Webkul\Core\CoreConvention::class,
'modules' => [
/**
* Example:
* VendorA\ModuleX\Providers\ModuleServiceProvider::class,
@ -37,5 +38,6 @@ return [
\Webkul\Ui\Providers\ModuleServiceProvider::class,
\Webkul\User\Providers\ModuleServiceProvider::class,
\Webkul\Velocity\Providers\ModuleServiceProvider::class,
]
];
],
];

View File

@ -0,0 +1,65 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['customer'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];

View File

@ -41,7 +41,20 @@ return [
|
*/
'queue' => env('SCOUT_QUEUE', true),
'queue' => env('SCOUT_QUEUE', false),
/*
|--------------------------------------------------------------------------
| Database Transactions
|--------------------------------------------------------------------------
|
| This configuration option determines if your data will only be synced
| with your search indexes after every open database transaction has
| been committed, thus preventing any discarded data from syncing.
|
*/
'after_commit' => false,
/*
|--------------------------------------------------------------------------
@ -72,6 +85,21 @@ return [
'soft_delete' => false,
/*
|--------------------------------------------------------------------------
| Identify User
|--------------------------------------------------------------------------
|
| This option allows you to control whether to notify the search engine
| of the user performing the search. This is sometimes useful if the
| engine supports any analytics based on this application's users.
|
| Supported engines: "algolia"
|
*/
'identify' => env('SCOUT_IDENTIFY', false),
/*
|--------------------------------------------------------------------------
| Algolia Configuration

View File

@ -38,6 +38,7 @@ class CoreServiceProvider extends ServiceProvider
$this->publishes([
dirname(__DIR__) . '/Config/concord.php' => config_path('concord.php'),
dirname(__DIR__) . '/Config/sanctum.php' => config_path('sanctum.php'),
dirname(__DIR__) . '/Config/scout.php' => config_path('scout.php'),
]);

View File

@ -2,10 +2,10 @@
namespace Webkul\Customer\Database\Factories;
use Webkul\Customer\Models\Customer;
use Illuminate\Support\Arr;
use Webkul\Customer\Models\CustomerAddress;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Arr;
use Webkul\Customer\Models\Customer;
use Webkul\Customer\Models\CustomerAddress;
class CustomerAddressFactory extends Factory
{
@ -20,6 +20,7 @@ class CustomerAddressFactory extends Factory
* Define the model's default state.
*
* @return array
*
* @throws \Exception
*/
public function definition(): array
@ -46,7 +47,3 @@ class CustomerAddressFactory extends Factory
];
}
}

View File

@ -2,10 +2,10 @@
namespace Webkul\Customer\Database\Factories;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Arr;
use Webkul\Customer\Models\Customer;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Hash;
use Webkul\Customer\Models\Customer;
class CustomerFactory extends Factory
{
@ -17,6 +17,8 @@ class CustomerFactory extends Factory
protected $model = Customer::class;
/**
* States.
*
* @var array
*/
protected $states = [
@ -28,32 +30,35 @@ class CustomerFactory extends Factory
* Define the model's default state.
*
* @return array
*
* @throws \Exception
*/
public function definition(): array
{
$now = date("Y-m-d H:i:s");
$password = $this->faker->password;
return [
'first_name' => $this->faker->firstName(),
'last_name' => $this->faker->lastName,
'gender' => Arr::random([
'first_name' => $this->faker->firstName(),
'last_name' => $this->faker->lastName,
'gender' => Arr::random([
'male',
'female',
'other',
]),
'email' => $this->faker->email,
'status' => 1,
'password' => Hash::make($password),
'email' => $this->faker->email,
'status' => 1,
'password' => Hash::make($password = $this->faker->password),
'customer_group_id' => 2,
'is_verified' => 1,
'created_at' => $now,
'updated_at' => $now,
'notes' => json_encode(['plain_password' => $password], JSON_THROW_ON_ERROR),
'is_verified' => 1,
'created_at' => $now = date('Y-m-d H:i:s'),
'updated_at' => $now,
'notes' => json_encode(['plain_password' => $password], JSON_THROW_ON_ERROR),
];
}
/**
* Male.
*
* @return \Webkul\Customer\Database\Factories\CustomerFactory
*/
public function male(): CustomerFactory
{
return $this->state(function (array $attributes) {
@ -63,6 +68,11 @@ class CustomerFactory extends Factory
});
}
/**
* Female.
*
* @return \Webkul\Customer\Database\Factories\CustomerFactory
*/
public function female(): CustomerFactory
{
return $this->state(function (array $attributes) {

View File

@ -0,0 +1,35 @@
<?php
namespace Webkul\Customer\Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Webkul\Core\Models\Channel;
use Webkul\Customer\Models\Customer;
use Webkul\Customer\Models\Wishlist;
use Webkul\Product\Models\Product;
class CustomerWishlistFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Wishlist::class;
/**
* Define the model's default state.
*
* @return array
*
* @throws \Exception
*/
public function definition(): array
{
return [
'channel_id' => Channel::factory(),
'product_id' => Product::factory(),
'customer_id' => Customer::factory(),
];
}
}

View File

@ -14,9 +14,7 @@ class Wishlist
{
$wishlist = false;
$guard = request()->has('token') ? 'api' : 'customer';
if ($customer = auth()->guard($guard)->user()) {
if ($customer = auth()->guard()->user()) {
$wishlist = $customer->wishlist_items->filter(function ($item) use ($product) {
return $item->channel_id == core()->getCurrentChannel()->id && $item->product_id == $product->product_id;
})->first();

View File

@ -7,6 +7,7 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Laravel\Sanctum\HasApiTokens;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
use Webkul\Checkout\Models\CartProxy;
use Webkul\Core\Models\SubscribersListProxy;
@ -18,7 +19,7 @@ use Webkul\Sales\Models\OrderProxy;
class Customer extends Authenticatable implements CustomerContract, JWTSubject
{
use HasFactory, Notifiable;
use HasApiTokens, HasFactory, Notifiable;
/**
* The table associated with the model.

View File

@ -2,12 +2,15 @@
namespace Webkul\Customer\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Webkul\Customer\Contracts\Wishlist as WishlistContract;
use Webkul\Product\Models\ProductProxy;
class Wishlist extends Model implements WishlistContract
{
use HasFactory;
/**
* The table associated with the model.
*
@ -44,4 +47,14 @@ class Wishlist extends Model implements WishlistContract
{
return $this->hasOne(ProductProxy::modelClass(), 'id', 'product_id');
}
/**
* Create a new factory instance for the model
*
* @return Factory
*/
protected static function newFactory()
{
return \Webkul\Customer\Database\Factories\CustomerWishlistFactory::new ();
}
}

View File

@ -2,8 +2,8 @@
namespace Webkul\Product\Database\Factories;
use Webkul\Product\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
use Webkul\Product\Models\Product;
class ProductFactory extends Factory
{
@ -15,6 +15,8 @@ class ProductFactory extends Factory
protected $model = Product::class;
/**
* States.
*
* @var string[]
*/
protected $states = [
@ -32,7 +34,7 @@ class ProductFactory extends Factory
public function definition(): array
{
return [
'sku' => $this->faker->uuid,
'sku' => $this->faker->uuid,
'attribute_family_id' => 1,
];
}
@ -72,4 +74,4 @@ class ProductFactory extends Factory
];
});
}
}
}

View File

@ -256,8 +256,8 @@ class ProductRepository extends Repository
if (count($priceRange) > 0) {
$customerGroupId = null;
if (Cart::getCurrentCustomer()->check()) {
$customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id;
if (auth()->guard()->check()) {
$customerGroupId = auth()->guard()->user()->customer_group_id;
} else {
$customerGuestGroup = app('Webkul\Customer\Repositories\CustomerGroupRepository')->getCustomerGuestGroup();

View File

@ -652,8 +652,8 @@ abstract class AbstractType
$customerGroupId = null;
if (Cart::getCurrentCustomer()->check()) {
$customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id;
if (auth()->guard()->check()) {
$customerGroupId = auth()->guard()->user()->customer_group_id;
} else {
$customerGuestGroup = app(CustomerGroupRepository::class)->getCustomerGuestGroup();
@ -1008,8 +1008,8 @@ abstract class AbstractType
$haveOffers = true;
$customerGroupId = null;
if (Cart::getCurrentCustomer()->check()) {
$customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id;
if (auth()->guard()->check()) {
$customerGroupId = auth()->guard()->user()->customer_group_id;
} else {
$customerGroupRepository = app('Webkul\Customer\Repositories\CustomerGroupRepository');

View File

@ -6,14 +6,15 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
use Webkul\User\Contracts\Admin as AdminContract;
use Webkul\User\Database\Factories\AdminFactory;
use Webkul\User\Notifications\AdminResetPassword;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
class Admin extends Authenticatable implements AdminContract, JWTSubject
{
use HasFactory, Notifiable;
use HasFactory, HasApiTokens, Notifiable;
/**
* The attributes that are mass assignable.
@ -79,11 +80,11 @@ class Admin extends Authenticatable implements AdminContract, JWTSubject
/**
* Create a new factory instance for the model.
*
* @return Factory
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory(): Factory
{
return AdminFactory::new();
return AdminFactory::new ();
}
/**

View File

@ -6,5 +6,4 @@ use Konekt\Concord\Proxies\ModelProxy;
class AdminProxy extends ModelProxy
{
}
}

View File

@ -19,12 +19,19 @@ class Role extends Model implements RoleContract
'permissions',
];
/**
* The attributes that are castable.
*
* @var array
*/
protected $casts = [
'permissions' => 'array',
];
/**
* Get the admins.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function admins()
{

View File

@ -6,5 +6,4 @@ use Konekt\Concord\Proxies\ModelProxy;
class RoleProxy extends ModelProxy
{
}
}

View File

@ -1,37 +0,0 @@
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method void pause()
*
* @SuppressWarnings(PHPMD)
*/
class AcceptanceTester extends \Codeception\Actor
{
use _generated\AcceptanceTesterActions;
/**
* Logging in as an Admin
*/
public function loginAsAdmin()
{
$I = $this;
$I->amOnPage('/admin');
$I->see('Sign In');
$I->fillField('email', 'admin@example.com');
$I->fillField('password', 'admin123');
$I->dontSee('The "Email" field is required.');
$I->dontSee('The "Password" field is required.');
$I->click('Sign In');
$I->see('Dashboard', '//h1');
}
}

View File

@ -0,0 +1,383 @@
<?php
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\Sanctum;
use Webkul\Attribute\Models\Attribute;
use Webkul\Attribute\Models\AttributeOption;
use Webkul\Checkout\Models\Cart;
use Webkul\Checkout\Models\CartItem;
use Webkul\Customer\Models\Customer;
use Webkul\Product\Models\Product;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Models\ProductInventory;
/**
* Inherited methods.
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method void pause()
*
* @SuppressWarnings(PHPMD)
*/
class ApiTester extends \Codeception\Actor
{
use _generated\ApiTesterActions;
/**
* Sanctum authenticated customer.
*
* @return \Webkul\Customer\Models\Customer
*/
public function amSanctumAuthenticatedCustomer()
{
return Sanctum::actingAs(
Customer::factory()->create(),
['*']
);
}
/**
* Create token for sanctum authenticated customer.
*
* @param \Webkul\Customer\Models\Customer $customer
* @return string
*/
public function amCreatingTokenForSanctumAuthenticatedCustomer(Customer $customer)
{
return $this->grabTokenFromSanctumGeneratedString(
$customer->createToken($this->fake()->company)->plainTextToken
);
}
/**
* Set all necessary headers, if token is passed then bearable authentication header
* will pass.
*
* @param optional|string $token
* @return void
*/
public function haveAllNecessaryHeaders($token = null)
{
$this->haveHttpHeader('Accept', 'application/json');
$this->haveHttpHeader('Content-Type', 'application/json');
if ($token) {
$this->amBearerAuthenticated($token);
}
}
/**
* Check all necessary success response.
*
* @return void
*/
public function seeAllNecessarySuccessResponse()
{
$this->seeResponseCodeIsSuccessful();
$this->seeResponseIsJson();
}
/**
* Get JSON decoded response.
*
* @return mixed
*/
public function grabJsonDecodedResponse()
{
return json_decode($this->grabResponse());
}
/**
* Get token from response.
*
* @return string
*/
public function grabTokenFromResponse()
{
$idAndToken = $this->grabDataFromResponseByJsonPath('token')[0];
return $this->grabTokenFromSanctumGeneratedString($idAndToken);
}
/**
* Get token from sanctum generated string.
*
* @return string
*/
public function grabTokenFromSanctumGeneratedString($idAndToken)
{
$idAndToken = explode('|', $idAndToken);
return $idAndToken[1];
}
/**
* Clean all fields.
*
* @param array $fields
* @return array
*/
public function cleanAllFields(array $fields)
{
return collect($fields)->map(function ($field, $key) {
return $this->cleanField($field);
})->toArray();
}
/**
* Clean field.
*
* @param string $field
* @return string
*/
public function cleanField($field)
{
return preg_replace('/[^A-Za-z0-9 ]/', '', $field);
}
/**
* Generate cart.
*
* @param array $attributes
* @return \Webkul\Checkout\Contracts\Cart
*/
public function haveCart($attributes = [])
{
return Cart::factory($attributes)->adjustCustomer()->create();
}
/**
* Generate cart items.
*
* @param array $attributes
* @return \Webkul\Checkout\Contracts\CartItem
*/
public function haveCartItems($attributes = [])
{
return CartItem::factory($attributes)->adjustProduct()->create();
}
/**
* Generate simple product.
*
* @param array $configs
* @param array $productStates
* @return \Webkul\Product\Contracts\Product
*/
public function haveSimpleProduct(array $configs = [], array $productStates = []): Product
{
$I = $this;
if (! in_array('simple', $productStates)) {
$productStates = array_merge($productStates, ['simple']);
}
$product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
$I->createAttributeValues($product, $configs['attributeValues'] ?? []);
$I->createInventory($product->id, $configs['productInventory'] ?? []);
return $product->refresh();
}
/**
* Create product.
*
* @param array $attributes
* @param array $states
* @return \Webkul\Product\Contracts\Product
*/
public function createProduct(array $attributes = [], array $states = []): Product
{
return Product::factory()
->state(function () use ($states) {
return [
'type' => $states[0],
];
})
->create($attributes);
}
/**
* Create product inventory.
*
* @param int $productId
* @param array $inventoryConfig
* @return void
*/
public function createInventory(int $productId, array $inventoryConfig = []): void
{
$I = $this;
$I->have(ProductInventory::class, array_merge($inventoryConfig, [
'product_id' => $productId,
'inventory_source_id' => 1,
]));
}
/**
* Create attribute values.
*
* @param \Webkul\Product\Contracts\Product $product
* @param array $attributeValues
* @return void
*/
public function createAttributeValues(Product $product, array $attributeValues = []): void
{
$I = $this;
$brand = Attribute::query()->where(['code' => 'brand'])->firstOrFail();
if (! AttributeOption::query()->where(['attribute_id' => $brand->id])->exists()) {
AttributeOption::create([
'admin_name' => 'Webkul Demo Brand (c) 2020',
'attribute_id' => $brand->id,
]);
}
/**
* Some defaults that should apply to all generated products.
* By defaults products will be generated as saleable.
* If you do not want this, this defaults can be overriden by $attributeValues.
*/
$defaultAttributeValues = [
'name' => $I->fake()->words(3, true),
'description' => $I->fake()->sentence,
'short_description' => $I->fake()->sentence,
'sku' => $product->sku,
'url_key' => $I->fake()->slug,
'status' => true,
'guest_checkout' => true,
'visible_individually' => true,
'special_price_from' => null,
'special_price_to' => null,
'special_price' => null,
'price' => $I->fake()->randomFloat(2, 1, 1000),
'weight' => '1.00',
'brand' => AttributeOption::query()->firstWhere('attribute_id', $brand->id)->id,
];
$attributeValues = array_merge($defaultAttributeValues, $attributeValues);
$possibleAttributeValues = DB::table('attributes')
->select('id', 'code', 'type')
->get()
->toArray();
foreach ($possibleAttributeValues as $attributeSet) {
$data = [
'product_id' => $product->id,
'attribute_id' => $attributeSet->id,
];
$fieldName = self::getAttributeFieldName($attributeSet->type);
$data[$fieldName] = $attributeValues[$attributeSet->code] ?? null;
$data = $this->appendAttributeDependencies($attributeSet->code, $data);
$I->have(ProductAttributeValue::class, $data);
}
}
/**
* Get attribute field names.
*
* @param string $type
* @return string|void
*/
private static function getAttributeFieldName(string $type): ?string
{
$possibleTypes = [
'text' => 'text_value',
'select' => 'integer_value',
'boolean' => 'boolean_value',
'textarea' => 'text_value',
'price' => 'float_value',
'date' => 'date_value',
'checkbox' => 'text_value',
];
return $possibleTypes[$type];
}
/**
* Append attribute dependencies.
*
* @param string $attributeCode
* @param array $data
* @return array
*/
private function appendAttributeDependencies(string $attributeCode, array $data): array
{
$locale = core()->getCurrentLocale()->code;
$channel = core()->getCurrentChannelCode();
$attributeSetDependencies = [
'name' => [
'locale',
'channel',
],
'tax_category_id' => [
'channel',
],
'short_description' => [
'locale',
'channel',
],
'description' => [
'locale',
'channel',
],
'cost' => [
'channel',
],
'special_price_from' => [
'channel',
],
'special_price_to' => [
'channel',
],
'meta_title' => [
'locale',
'channel',
],
'meta_keywords' => [
'locale',
'channel',
],
'meta_description' => [
'locale',
'channel',
],
'custom_sale_badge' => [
'locale',
],
];
if (array_key_exists($attributeCode, $attributeSetDependencies)) {
foreach ($attributeSetDependencies[$attributeCode] as $key) {
if ($key === 'locale') {
$data['locale'] = $locale;
}
if ($key === 'channel') {
$data['channel'] = $channel;
}
}
}
return $data;
}
}

View File

@ -1,15 +1,14 @@
<?php
use Codeception\Actor;
use Webkul\User\Models\Admin;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Webkul\Customer\Models\Customer;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
use Illuminate\Routing\RouteCollection;
use Webkul\Customer\Models\Customer;
use Webkul\User\Models\Admin;
/**
* Inherited Methods
* Inherited methods.
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
@ -27,17 +26,13 @@ class FunctionalTester extends Actor
{
use _generated\FunctionalTesterActions;
/**
* Define custom actions here
*/
/**
* Set the logged in user to the admin identity.
*
* @param \Webkul\User\Models\Admin|null $admin
* @param \Webkul\User\Models\Admin|null $admin
* @return Admin
*
* @throws \Exception
* @returns Admin
*/
public function loginAsAdmin(Admin $admin = null): Admin
{
@ -49,11 +44,11 @@ class FunctionalTester extends Actor
if (! $admin) {
throw new Exception(
'Admin user not found in database. Please ensure Seeders are executed');
'Admin user not found in database. Please ensure Seeders are executed'
);
}
Auth::guard('admin')
->login($admin);
Auth::guard('admin')->login($admin);
$I->seeAuthentication('admin');
@ -64,9 +59,9 @@ class FunctionalTester extends Actor
* Set the logged in user to the customer identity.
*
* @param \Webkul\User\Models\Customer|null $customer
* @return Customer
*
* @throws \Exception
* @returns Customer
*/
public function loginAsCustomer(Customer $customer = null): Customer
{
@ -76,8 +71,7 @@ class FunctionalTester extends Actor
$customer = $I->have(Customer::class);
}
Auth::guard('customer')
->login($customer);
Auth::guard('customer')->login($customer);
$I->seeAuthentication('customer');
@ -85,9 +79,12 @@ class FunctionalTester extends Actor
}
/**
* @param string $name
* @param array $params
* @param bool $routeCheck set this to false if the action is doing a redirection
* On admin route.
*
* @param string $name
* @param array $params
* @param bool $routeCheck
* @return void
*/
public function amOnAdminRoute(string $name, array $params = [], bool $routeCheck = true)
{
@ -98,19 +95,17 @@ class FunctionalTester extends Actor
$I->seeCurrentRouteIs($name);
}
/** @var RouteCollection $routes */
$routes = Route::getRoutes();
$middlewares = $routes->getByName($name)->middleware();
$I->assertContains('admin', $middlewares, 'check that admin middleware is applied');
}
/**
* Set specific Webkul/Core configuration keys to a given value
* Set specific Webkul/Core configuration keys to a given value.
*
* // TODO: change method as soon as there is a method to set core config data
*
* @param $data array containing 'code => value' pairs
* TODO: Change method as soon as there is a method to set core config data.
*
* @param $data array containing 'code => value' pairs
* @return void
*/
public function setConfigData($data): void
@ -133,6 +128,11 @@ class FunctionalTester extends Actor
}
}
/**
* Use default theme.
*
* @return void.
*/
public function useDefaultTheme(): void
{
$channel = core()->getCurrentChannel();

View File

@ -1,10 +0,0 @@
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class Acceptance extends \Codeception\Module
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace Helper;
class Api extends \Codeception\Module
{
}

View File

@ -1,29 +1,31 @@
<?php
namespace Helper;
use Codeception\Module;
use Faker\Factory;
use Faker\Generator;
class DataMocker extends Module
{
/**
* Faker instance.
*
* @var \Faker\Generator
*/
private static $faker;
/**
* Get an instance of the faker
* Get an instance of the faker.
*
* @return \Faker\Generator
*
* @author florianbosdorff
*/
public function fake(): Generator
{
if (self::$faker === null) {
self::$faker = Factory::create();
}
return self::$faker;
}
}
}

View File

@ -2,15 +2,15 @@
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
use Webkul\Core\Models\Channel;
class Functional extends \Codeception\Module
{
/**
* Apply the given theme by setting the value to the default (or given) channel.
*
* @param string $theme
* @param string $theme
* @return void
*/
public function applyTheme(string $theme, string $channel = 'default'): void
{

View File

@ -1,10 +1,7 @@
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
namespace Helper;
class Trigger extends \Codeception\Module
{
}

View File

@ -1,10 +1,7 @@
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
namespace Helper;
class Unit extends \Codeception\Module
{
}

View File

@ -1,8 +1,7 @@
<?php
/**
* Inherited Methods
* Inherited methods.
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
@ -19,8 +18,4 @@
class TriggerTester extends \Codeception\Actor
{
use _generated\TriggerTesterActions;
/**
* Define custom actions here
*/
}
}

View File

@ -3,7 +3,7 @@
use Codeception\Stub;
/**
* Inherited Methods
* Inherited methods.
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
@ -21,22 +21,16 @@ class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
/**
* execute any function of a class (also private/protected) and return its return
*
* @param string|object $className name of the class (FQCN) or an instance of it
* @param string $functionName name of the function which will be executed
* @param array $methodParams params the function will be executed with
* @param array $constructParams params which will be called in constructor. Will be ignored if $className
* is already an instance of an object.
* @param array $mocks mock/stub overrides of methods and properties. Will be ignored if $className is
* already an instance of an object.
* Execute any function of a class (also private/protected) and return its return.
*
* @param string|object $className
* @param string $functionName
* @param array $methodParams
* @param array $constructParams
* @param array $mocks
* @return mixed
*
* @throws \Exception
*/
public function executeFunction(
@ -47,7 +41,9 @@ class UnitTester extends \Codeception\Actor
array $mocks = []
) {
$I = $this;
$I->comment('I execute function "'
$I->comment(
'I execute function "'
. $functionName
. '" of class "'
. (is_object($className) ? get_class($className) : $className)
@ -59,9 +55,13 @@ class UnitTester extends \Codeception\Actor
. count($mocks)
. ' mocked class-methods/params'
);
$class = new \ReflectionClass($className);
$method = $class->getMethod($functionName);
$method->setAccessible(true);
if (is_object($className)) {
$reflectedClass = $className;
} elseif (empty($constructParams)) {

View File

@ -1,30 +0,0 @@
# Codeception Test Suite Configuration
#
# Suite for acceptance tests.
# Perform tests in browser using the WebDriver or PhpBrowser.
# If you need both WebDriver and PHPBrowser tests - create a separate suite.
actor: AcceptanceTester
modules:
enabled:
- \Helper\Acceptance
- Asserts
- WebDriver:
url: http://nginx/
host: selenium-chrome
browser: chrome
window_size: 1920x1080
restart: true
wait: 20
pageload_timeout: 10
connection_timeout: 60
request_timeout: 60
log_js_errors: true
- Webkul\Core\Helpers\Laravel5Helper:
part: ORM
cleanup: false
environment_file: .env
database_seeder_class: DatabaseSeeder
url: http://nginx
step_decorators: ~

View File

@ -1,54 +0,0 @@
<?php
namespace Tests\Acceptance\BookingProduct;
use Carbon\Carbon;
use Faker\Factory;
use AcceptanceTester;
use Webkul\Product\Models\Product;
use Webkul\Core\Helpers\Laravel5Helper;
use Webkul\BookingProduct\Models\BookingProduct;
use Webkul\BookingProduct\Models\BookingProductEventTicket;
class BookingProductEventTicketCest
{
protected $faker;
public function _before(): void
{
$this->faker = Factory::create();
}
public function testSpecialPricesAreShown(AcceptanceTester $I): void
{
$product = $I->haveProduct(Laravel5Helper::VIRTUAL_PRODUCT);
Product::query()->where('id', $product->id)->update(['type' => 'booking']);
$bookingProduct = $I->have(BookingProduct::class, [
'type' => 'event',
'available_to' => Carbon::now()->addMinutes($this->faker->numberBetween(2, 59))->toDateTimeString(),
'product_id' => $product->id,
]);
$scenario['ticket'] = [
'price' => 10,
'special_price' => 5
];
$ticket = $I->have(
BookingProductEventTicket::class,
array_merge(
['booking_product_id' => $bookingProduct->id],
$scenario['ticket']
)
);
$I->amOnPage($product->url_key);
$I->see(core()->currency($ticket->price), '//span[@class="regular-price"]');
$I->see(
__('bookingproduct::app.shop.products.per-ticket-price', ['price' => core()->currency($ticket->special_price)]),
'//span[@class="special-price"]'
);
}
}

View File

@ -1,60 +0,0 @@
<?php
namespace Tests\Acceptance;
use AcceptanceTester;
use Faker\Factory;
class GuestCheckoutCest
{
private $faker;
public function _before(AcceptanceTester $I)
{
$this->faker = Factory::create();
}
function testToConfigureGlobalGuestCheckout(AcceptanceTester $I)
{
$admin = config('app.admin_url');
$I->loginAsAdmin();
$I->amGoingTo('turn ON the global guest checkout configuration');
$I->amOnPage($admin . '/configuration/catalog/products');
$I->see(__('admin::app.admin.system.allow-guest-checkout'));
$I->selectOption('catalog[products][guest-checkout][allow-guest-checkout]', 1);
$I->click(__('admin::app.configuration.save-btn-title'));
$I->seeRecord('core_config', ['code' => 'catalog.products.guest-checkout.allow-guest-checkout', 'value' => 1]);
$I->amGoingTo('assert that the product guest checkout configuration is shown');
$I->amOnPage($admin . '/catalog/products');
$I->click(__('admin::app.catalog.products.add-product-btn-title'));
$I->selectOption('attribute_family_id', 1);
$I->fillField('sku', $this->faker->uuid);
$I->dontSeeInSource('<span class="control-error">The "SKU" field is required.</span>');
$I->click(__('admin::app.catalog.products.save-btn-title'));
$I->seeInCurrentUrl($admin . '/catalog/products/edit');
$I->scrollTo('#new');
$I->see('Guest Checkout');
$I->seeInSource('<input type="checkbox" id="guest_checkout" name="guest_checkout"');
$I->amGoingTo('turn OFF the global guest checkout configuration');
$I->amOnPage($admin . '/configuration/catalog/products');
$I->see(__('admin::app.admin.system.allow-guest-checkout'));
$I->selectOption('catalog[products][guest-checkout][allow-guest-checkout]', 0);
$I->click(__('admin::app.configuration.save-btn-title'));
$I->seeRecord('core_config', ['code' => 'catalog.products.guest-checkout.allow-guest-checkout', 'value' => 0]);
$I->amGoingTo('assert that the product guest checkout configuration is not shown');
$I->amOnPage($admin . '/catalog/products');
$I->click(__('admin::app.catalog.products.add-product-btn-title'));
$I->selectOption('attribute_family_id', 1);
$I->fillField('sku', $this->faker->uuid);
$I->dontSeeInSource('<span class="control-error">The "SKU" field is required.</span>');
$I->click(__('admin::app.catalog.products.save-btn-title'));
$I->seeInCurrentUrl($admin . '/catalog/products/edit');
$I->scrollTo('#new');
$I->dontSee('Guest Checkout');
$I->dontSeeInSource('<input type="checkbox" id="guest_checkout" name="guest_checkout"');
}
}

16
tests/api.suite.yml Normal file
View File

@ -0,0 +1,16 @@
actor: ApiTester
modules:
enabled:
- Asserts
- \Helper\Api
- \Helper\DataMocker
- Laravel:
cleanup: true
database_seeder_class: DatabaseSeeder
environment_file: .env.testing
parts: ORM
run_database_migrations: false
run_database_seeder: false
- REST:
url: /api/
depends: Laravel

13
tests/api/V1/BaseCest.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace Tests\API\V1;
class BaseCest
{
protected const API_VERSION = 'v1';
protected function getVersionRoute($url)
{
return self::API_VERSION . '/' . $url;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Tests\API\V1\Shop\Catalog;
use ApiTester;
use Webkul\Attribute\Models\Attribute;
class AttributeCest extends CatalogCest
{
public function testForFetchingAllTheAttributes(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('attributes'));
$I->seeAllNecessarySuccessResponse();
}
public function testForFetchingTheAttributeById(ApiTester $I)
{
$attribute = Attribute::find(1);
$I->sendGet($this->getVersionRoute('attributes/' . $attribute->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'id' => $attribute->id,
'code' => $attribute->code,
'type' => $attribute->type,
'name' => $attribute->name,
]);
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Tests\API\V1\Shop\Catalog;
use ApiTester;
use Webkul\Attribute\Models\AttributeFamily;
class AttributeFamilyCest extends CatalogCest
{
public function testForFetchingAllTheAttributeFamilies(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('attribute-families'));
$I->seeAllNecessarySuccessResponse();
}
public function testForFetchingTheAttributeFamilyById(ApiTester $I)
{
$attributeFamily = AttributeFamily::find(1);
$I->sendGet($this->getVersionRoute('attribute-families/' . $attributeFamily->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'id' => $attributeFamily->id,
'code' => $attributeFamily->code,
'name' => $attributeFamily->name,
'groups' => [],
]);
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Tests\API\V1\Shop\Catalog;
use Tests\API\V1\BaseCest;
class CatalogCest extends BaseCest
{
}

View File

@ -0,0 +1,15 @@
<?php
namespace Tests\API\V1\Shop\Catalog;
use ApiTester;
class CategoryCest extends CatalogCest
{
public function testForFetchingAllTheCategories(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('categories'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Tests\API\V1\Shop\Catalog;
use ApiTester;
class ProductCest extends CatalogCest
{
public function testForFetchingAllTheProducts(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('products'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Tests\API\V1\Shop\Core;
use ApiTester;
use Webkul\Core\Models\Channel;
class ChannelCest extends CoreCest
{
public function testForFetchingAllTheChannels(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('channels'));
$I->seeAllNecessarySuccessResponse();
}
public function testForFetchingTheChannelById(ApiTester $I)
{
$channel = Channel::find(1);
$I->sendGet($this->getVersionRoute('channels/' . $channel->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'id' => $channel->id,
'code' => $channel->code,
'name' => $channel->name,
]);
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Tests\API\V1\Shop\Core;
use Tests\API\V1\BaseCest;
class CoreCest extends BaseCest
{
}

View File

@ -0,0 +1,38 @@
<?php
namespace Tests\API\V1\Shop\Core;
use ApiTester;
use Webkul\Core\Models\Country;
class CountryCest extends CoreCest
{
public function testForFetchingAllTheCountries(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('countries'));
$I->seeAllNecessarySuccessResponse();
}
public function testForFetchingTheCountryById(ApiTester $I)
{
$country = Country::find(1);
$I->sendGet($this->getVersionRoute('countries/' . $country->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'id' => $country->id,
'code' => $country->code,
'name' => $country->name,
]);
}
public function testForFetchingStatesGroupByCountries(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('countries/states/groups'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Tests\API\V1\Shop\Core;
use ApiTester;
use Webkul\Core\Models\Currency;
class CurrencyCest extends CoreCest
{
public function testForFetchingAllTheCurrencies(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('currencies'));
$I->seeAllNecessarySuccessResponse();
}
public function testForFetchingTheCurrencyById(ApiTester $I)
{
$currency = Currency::find(1);
$I->sendGet($this->getVersionRoute('currencies/' . $currency->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'id' => $currency->id,
'code' => $currency->code,
'name' => $currency->name,
]);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Tests\API\V1\Shop\Core;
use ApiTester;
use Webkul\Core\Models\Locale;
class LocaleCest extends CoreCest
{
public function testForFetchingAllTheLocales(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('locales'));
$I->seeAllNecessarySuccessResponse();
}
public function testForFetchingTheLocaleById(ApiTester $I)
{
$locale = Locale::find(1);
$I->sendGet($this->getVersionRoute('locales/' . $locale->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'id' => $locale->id,
'code' => $locale->code,
'name' => $locale->name,
]);
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Tests\API\V1\Shop\Core;
use ApiTester;
class SliderCest extends CoreCest
{
public function testForFetchingAllTheSliders(ApiTester $I)
{
$I->sendGet($this->getVersionRoute('sliders'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,177 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Webkul\Customer\Models\CustomerAddress;
class AddressCest extends CustomerCest
{
public function testForFetchingAllTheCustomerAddresses(ApiTester $I)
{
$howManyAddresses = $I->fake()->randomDigitNotZero();
$customer = $I->amSanctumAuthenticatedCustomer();
$I->haveMultiple(CustomerAddress::class, $howManyAddresses, [
'customer_id' => $customer->id,
]);
$I->haveAllNecessaryHeaders();
$I->sendGet($this->getVersionRoute('customer/addresses'));
$I->seeAllNecessarySuccessResponse();
$response = $I->grabJsonDecodedResponse();
$I->assertEquals($howManyAddresses, count($response->data));
}
public function testForStoringTheCustomerAddress(ApiTester $I)
{
$I->amSanctumAuthenticatedCustomer();
$I->haveAllNecessaryHeaders();
$fields = $I->cleanAllFields([
'first_name' => $I->fake()->firstName,
'last_name' => $I->fake()->lastName,
'address1' => [$I->fake()->streetAddress],
'company_name' => $I->fake()->company,
'country' => $I->fake()->countryCode,
'state' => $I->fake()->word,
'city' => $I->fake()->city,
'postcode' => $I->fake()->postcode,
'phone' => $I->fake()->phoneNumber,
]);
$I->sendPost($this->getVersionRoute('customer/addresses'), $fields);
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'first_name' => $fields['first_name'],
'last_name' => $fields['last_name'],
'address1' => $fields['address1'],
'company_name' => $fields['company_name'],
'country' => $fields['country'],
'state' => $fields['state'],
'city' => $fields['city'],
'postcode' => $fields['postcode'],
'phone' => $fields['phone'],
],
]);
}
public function testForFetchingTheCustomerAddress(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$customerAddress = $I->have(CustomerAddress::class, [
'customer_id' => $customer->id,
'first_name' => $I->fake()->firstName,
'last_name' => $I->fake()->lastName,
'address1' => $I->fake()->streetAddress,
'company_name' => $I->fake()->company,
'country' => $I->fake()->countryCode,
'state' => $I->fake()->word,
'city' => $I->fake()->city,
'postcode' => $I->fake()->postcode,
'phone' => $I->fake()->phoneNumber,
]);
$I->haveAllNecessaryHeaders();
$I->sendGet($this->getVersionRoute('customer/addresses/' . $customerAddress->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'first_name' => $customerAddress->first_name,
'last_name' => $customerAddress->last_name,
'address1' => [$customerAddress->address1],
'company_name' => $customerAddress->company_name,
'country' => $customerAddress->country,
'state' => $customerAddress->state,
'city' => $customerAddress->city,
'postcode' => $customerAddress->postcode,
'phone' => $customerAddress->phone,
],
]);
}
public function testForUpdatingTheCustomerAddress(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$customerAddress = $I->have(CustomerAddress::class, [
'customer_id' => $customer->id,
'first_name' => $I->fake()->firstName,
'last_name' => $I->fake()->lastName,
'address1' => $I->fake()->streetAddress,
'company_name' => $I->fake()->company,
'country' => $I->fake()->countryCode,
'state' => $I->fake()->word,
'city' => $I->fake()->city,
'postcode' => $I->fake()->postcode,
'phone' => $I->fake()->phoneNumber,
]);
$I->haveAllNecessaryHeaders();
$fields = $I->cleanAllFields([
'first_name' => $I->fake()->firstName,
'last_name' => $I->fake()->lastName,
'address1' => [$customerAddress->address1],
'company_name' => $customerAddress->company_name,
'country' => $customerAddress->country,
'state' => $customerAddress->state,
'city' => $customerAddress->city,
'postcode' => $customerAddress->postcode,
'phone' => $customerAddress->phone,
]);
$I->sendPut($this->getVersionRoute('customer/addresses/' . $customerAddress->id), $fields);
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'first_name' => $fields['first_name'],
'last_name' => $fields['last_name'],
'address1' => $fields['address1'],
'company_name' => $fields['company_name'],
'country' => $fields['country'],
'state' => $fields['state'],
'city' => $fields['city'],
'postcode' => $fields['postcode'],
'phone' => $fields['phone'],
],
]);
$I->dontSeeResponseContainsJson([
'data' => [
'first_name' => $customerAddress->firstName,
'last_name' => $customerAddress->lastName,
],
]);
}
public function testForDeletingTheCustomerAddress(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$customerAddress = $I->have(CustomerAddress::class, [
'customer_id' => $customer->id,
]);
$I->haveAllNecessaryHeaders();
$I->sendDelete($this->getVersionRoute('customer/addresses/' . $customerAddress->id));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,127 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Illuminate\Support\Facades\Notification;
use Webkul\Customer\Models\Customer;
class AuthCest extends CustomerCest
{
public function testForRegisterTheCustomer(ApiTester $I)
{
$I->haveAllNecessaryHeaders();
$I->sendPost($this->getVersionRoute('customer/register'), [
'first_name' => $I->fake()->firstName(),
'last_name' => $I->fake()->lastName(),
'email' => $I->fake()->email(),
'password' => $password = $I->fake()->password,
'password_confirmation' => $password,
]);
$I->seeAllNecessarySuccessResponse();
}
public function testForLoginTheCustomer(ApiTester $I)
{
$customer = $I->have(Customer::class);
$I->haveAllNecessaryHeaders();
$I->sendPost($this->getVersionRoute('customer/login'), [
'email' => $customer->email,
'password' => json_decode($customer->notes)->plain_password,
'device_name' => $I->fake()->company,
]);
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'first_name' => $customer->first_name,
'last_name' => $customer->last_name,
'gender' => $customer->gender,
'email' => $customer->email,
],
]);
}
public function testForFetchingTheLoggedInCustomer(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$I->haveAllNecessaryHeaders();
$I->sendGet($this->getVersionRoute('customer/get'));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'first_name' => $customer->first_name,
'last_name' => $customer->last_name,
'gender' => $customer->gender,
'email' => $customer->email,
],
]);
}
public function testForUpdatingTheLoggedInCustomer(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$I->haveAllNecessaryHeaders();
$I->sendPut($this->getVersionRoute('customer/profile'), [
'first_name' => $changedFirstName = $I->fake()->firstName(),
'last_name' => $changedLastName = $I->fake()->lastName(),
'gender' => $customer->gender,
'email' => $customer->email,
]);
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'first_name' => $changedFirstName,
'last_name' => $changedLastName,
'gender' => $customer->gender,
'email' => $customer->email,
],
]);
$I->dontSeeResponseContainsJson([
'data' => [
'first_name' => $customer->first_name,
'last_name' => $customer->last_name,
],
]);
}
public function testForLogoutTheCustomer(ApiTester $I)
{
$I->amSanctumAuthenticatedCustomer();
$I->haveAllNecessaryHeaders();
$I->sendPost($this->getVersionRoute('customer/logout'));
$I->seeAllNecessarySuccessResponse();
}
public function testForPasswordResetLink(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$I->haveAllNecessaryHeaders();
Notification::fake();
$I->sendPost($this->getVersionRoute('customer/forgot-password'), [
'email' => $customer->email,
]);
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,282 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Webkul\Customer\Models\Wishlist;
class CartCest extends CustomerCest
{
public function testForFetchingTheCart(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$product = $I->haveSimpleProduct();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$cartItem = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product->id,
]);
$I->haveAllNecessaryHeaders();
$I->sendGet($this->getVersionRoute('customer/cart'));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'id' => $cart->id,
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'items' => [
[
'id' => $cartItem->id,
'product' => [
'id' => $product->id,
],
],
],
],
]);
}
public function testForAddingItemToTheCart(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$I->haveAllNecessaryHeaders();
$product = $I->haveSimpleProduct();
$I->sendPost($this->getVersionRoute('customer/cart/add/' . $product->id), [
'quantity' => 1,
]);
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'items' => [
[
'product' => [
'id' => $product->id,
],
],
],
],
]);
}
public function testForUpdatingTheCart(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$product = $I->haveSimpleProduct();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$cartItem = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product->id,
]);
$I->haveAllNecessaryHeaders();
$I->sendPut($this->getVersionRoute('customer/cart/update'), [
'qty' => [
$cartItem->id => $expectedQuantity = 2,
],
]);
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'id' => $cart->id,
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'items' => [
[
'id' => $cartItem->id,
'quantity' => $expectedQuantity,
'product' => [
'id' => $product->id,
],
],
],
],
]);
}
public function testForRemovingItemFromTheCart(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$product1 = $I->haveSimpleProduct();
$cartItem1 = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product1->id,
]);
$product2 = $I->haveSimpleProduct();
$cartItem2 = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product2->id,
]);
$I->assertEquals(2, \Webkul\Checkout\Facades\Cart::getCart()->items()->count());
$I->haveAllNecessaryHeaders();
$I->sendDelete($this->getVersionRoute('customer/cart/remove/' . $cartItem1->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'id' => $cart->id,
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'items' => [
[
'id' => $cartItem2->id,
'quantity' => $cartItem2->quantity,
'product' => [
'id' => $product2->id,
],
],
],
],
]);
$I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count());
}
public function testForEmptyCart(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$product = $I->haveSimpleProduct();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product->id,
]);
$I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count());
$I->haveAllNecessaryHeaders();
$I->sendDelete($this->getVersionRoute('customer/cart/empty'));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => null,
]);
$I->assertNull(\Webkul\Checkout\Facades\Cart::getCart());
}
public function testForMovingCartItemToWishlist(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$product1 = $I->haveSimpleProduct();
$cartItem1 = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product1->id,
]);
$product2 = $I->haveSimpleProduct();
$cartItem2 = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product2->id,
]);
$I->assertEquals(2, \Webkul\Checkout\Facades\Cart::getCart()->items()->count());
$I->haveAllNecessaryHeaders();
$I->sendPost($this->getVersionRoute('customer/cart/move-to-wishlist/' . $cartItem1->id));
$I->seeAllNecessarySuccessResponse();
$I->seeResponseContainsJson([
'data' => [
'id' => $cart->id,
'customer_email' => $customer->email,
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'items' => [
[
'id' => $cartItem2->id,
'quantity' => $cartItem2->quantity,
'product' => [
'id' => $product2->id,
],
],
],
],
]);
$I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count());
$I->assertCount(1, Wishlist::all());
}
public function testForApplyingInvalidCouponToTheCart(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$product = $I->haveSimpleProduct();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product->id,
]);
$I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count());
$I->haveAllNecessaryHeaders();
$I->sendPost($this->getVersionRoute('customer/cart/coupon'), [
'code' => 'INVALID_CODE',
]);
$I->seeResponseCodeIs(400);
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
class CheckoutCest extends CustomerCest
{
public function testForPlacingOrder(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($customer);
$I->haveAllNecessaryHeaders($token);
$this->generateCartForCustomer($I, $customer);
$this->saveAddress($I);
$this->saveShippingMethod($I);
$this->savePaymentMethod($I);
$this->saveOrder($I);
}
private function generateCartForCustomer(ApiTester $I, $customer)
{
$product = $I->haveSimpleProduct();
$cart = $I->haveCart([
'customer_id' => $customer->id,
]);
$cartItem = $I->haveCartItems([
'cart_id' => $cart->id,
'product_id' => $product->id,
]);
}
private function saveAddress(ApiTester $I)
{
$fields = $I->cleanAllFields([
'first_name' => $I->fake()->firstName,
'last_name' => $I->fake()->lastName,
'email' => $I->fake()->safeEmail(),
'address1' => [$I->fake()->streetAddress],
'company_name' => $I->fake()->company,
'country' => $I->fake()->countryCode,
'state' => $I->fake()->word,
'city' => $I->fake()->city,
'postcode' => $I->fake()->postcode,
'phone' => $I->fake()->phoneNumber,
]);
$I->sendPost($this->getVersionRoute('customer/checkout/save-address'), [
'billing' => array_merge($fields, ['use_for_shipping' => false]),
'shipping' => $fields,
]);
$I->seeAllNecessarySuccessResponse();
}
private function saveShippingMethod(ApiTester $I)
{
$I->haveHttpHeader('X-CSRF-TOKEN', csrf_token());
$I->sendPost($this->getVersionRoute('customer/checkout/save-shipping'), [
'shipping_method' => 'flatrate_flatrate',
]);
$I->seeAllNecessarySuccessResponse();
}
private function savePaymentMethod(ApiTester $I)
{
$I->haveHttpHeader('X-CSRF-TOKEN', csrf_token());
$I->sendPost($this->getVersionRoute('customer/checkout/save-payment'), [
'payment' => [
'method' => 'cashondelivery',
],
]);
$I->seeAllNecessarySuccessResponse();
}
private function saveOrder(ApiTester $I)
{
$I->haveHttpHeader('X-CSRF-TOKEN', csrf_token());
$I->sendPost($this->getVersionRoute('customer/checkout/save-order'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Tests\API\V1\BaseCest;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Sales\Models\OrderItem;
use Webkul\Sales\Models\OrderPayment;
class CustomerCest extends BaseCest
{
protected function generateCashOnDeliveryOrder(ApiTester $I)
{
$product = $product = $I->haveSimpleProduct();
$order = $I->have(OrderItem::class, ['product_id' => $product->id])->order;
$I->have(OrderAddress::class, $this->generateAddressData($I, [
'order_id' => $order->id,
'address_type' => OrderAddress::ADDRESS_TYPE_SHIPPING,
'customer_id' => $order->customer->id,
]));
$I->have(OrderAddress::class, $this->generateAddressData($I, [
'order_id' => $order->id,
'address_type' => OrderAddress::ADDRESS_TYPE_BILLING,
'customer_id' => $order->customer->id,
]));
$I->have(OrderPayment::class, [
'method' => 'cashondelivery',
'method_title' => null,
'order_id' => $order->id,
]);
return $order;
}
protected function generateAddressData(ApiTester $I, array $additionalData): array
{
$faker = $I->fake();
return array_merge([
'city' => $faker->city,
'company_name' => $faker->company,
'country' => $faker->countryCode,
'email' => $faker->email,
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'phone' => $faker->phoneNumber,
'postcode' => $faker->postcode,
'state' => $faker->state,
], $additionalData);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Webkul\Sales\Models\Invoice;
class InvoiceCest extends CustomerCest
{
public function testForFetchingAllTheCustomerInvoices(ApiTester $I)
{
$order = $this->generateCashOnDeliveryOrder($I);
$invoices = $I->have(Invoice::class, [
'order_id' => $order->id,
]);
$token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($order->customer);
$I->haveAllNecessaryHeaders($token);
$I->sendGet($this->getVersionRoute('customer/invoices'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
class OrderCest extends CustomerCest
{
public function testForFetchingAllTheCustomerOrders(ApiTester $I)
{
$order = $this->generateCashOnDeliveryOrder($I);
$token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($order->customer);
$I->haveAllNecessaryHeaders($token);
$I->sendGet($this->getVersionRoute('customer/orders'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Webkul\Sales\Models\Shipment;
class ShipmentCest extends CustomerCest
{
public function testForFetchingAllTheCustomerShipments(ApiTester $I)
{
$order = $this->generateCashOnDeliveryOrder($I);
$shipments = $I->have(Shipment::class);
$token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($order->customer);
$I->haveAllNecessaryHeaders($token);
$I->sendGet($this->getVersionRoute('customer/shipments'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Tests\API\V1\Shop\Customer;
use ApiTester;
use Webkul\Customer\Models\Wishlist;
class WishlistCest extends CustomerCest
{
public function testForFetchingAllTheCustomerWishlists(ApiTester $I)
{
$customer = $I->amSanctumAuthenticatedCustomer();
$product = $I->haveSimpleProduct();
$wishlist = $I->have(Wishlist::class, [
'channel_id' => core()->getCurrentChannel()->id,
'customer_id' => $customer->id,
'product_id' => $product->id,
]);
$I->sendGet($this->getVersionRoute('customer/wishlist'));
$I->seeAllNecessarySuccessResponse();
}
}

View File

@ -1,14 +1,6 @@
# Codeception Test Suite Configuration
#
# Suite for functional tests
# Emulate web requests and make application process them
# Include one of framework modules (Symfony2, Yii2, Laravel5) to use it
# Remove this suite if you don't use frameworks
actor: FunctionalTester
modules:
enabled:
# add a framework module here
- \Helper\Functional
- \Helper\DataMocker
- Asserts
@ -20,4 +12,4 @@ modules:
run_database_seeder: true
database_seeder_class: DatabaseSeeder
step_decorators: ~
step_decorators: ~

View File

@ -1,7 +1,3 @@
# Codeception Test Suite Configuration
#
# Suite for unit or integration tests that test database logic (e.g. triggers).
actor: TriggerTester
modules:
enabled:
@ -15,4 +11,4 @@ modules:
database_seeder_class: DatabaseSeeder
packages: packages
step_decorators: ~
step_decorators: ~

View File

@ -1,7 +1,3 @@
# Codeception Test Suite Configuration
#
# Suite for unit or integration tests.
actor: UnitTester
modules:
enabled:
@ -16,4 +12,4 @@ modules:
database_seeder_class: DatabaseSeeder
packages: packages
step_decorators: ~
step_decorators: ~