seed(AuthorizationSeeder::class); WebsiteType::query()->create([ 'codigo' => 'onticket', 'nombre' => 'OnTicket', ]); WebsiteType::query()->create([ 'codigo' => 'shopit', 'nombre' => 'Shopit', ]); } public function test_authentication_is_required(): void { $this->getJson('/api/v1/adminapp/tenant/featured-groups')->assertUnauthorized(); $this->postJson('/api/v1/adminapp/tenant/featured-groups', $this->payload()) ->assertUnauthorized(); $this->putJson('/api/v1/adminapp/tenant/featured-groups/1', $this->payload()) ->assertUnauthorized(); } public function test_index_returns_only_category_groups_for_the_onticket_tenant(): void { $tenant = $this->createTenant('acme'); $otherTenant = $this->createTenant('other'); $first = $this->createCategoryGroup($tenant, 'Food', order: 2); $second = $this->createCategoryGroup($tenant, 'Tickets', order: 1); $this->createCategoryGroup($otherTenant, 'Other tenant'); FeaturedGroup::query()->create([ 'tenant_code' => $tenant->codigo, 'source_type' => FeaturedGroupSource::All, 'product_layout' => ProductLayout::Row, 'group_layout' => GroupLayout::Paginated, 'group_name' => 'All products', 'group_order' => 0, ]); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->getJson('/api/v1/adminapp/tenant/featured-groups') ->assertOk() ->assertJsonCount(2, 'data') ->assertJsonPath('data.0.id', $second->id) ->assertJsonPath('data.0.category_name', 'Tickets') ->assertJsonPath('data.1.id', $first->id) ->assertJsonMissing(['category_name' => 'Other tenant']) ->assertJsonMissing(['group_name' => 'All products']); } public function test_store_creates_a_category_and_a_featured_horizontal_group(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $response = $this->postJson('/api/v1/adminapp/tenant/featured-groups', [ 'category_name' => 'Food', 'is_featured' => true, ]) ->assertCreated() ->assertJsonPath('data.category_name', 'Food') ->assertJsonPath('data.group_name', 'Food') ->assertJsonPath('data.is_featured', true) ->assertJsonPath('data.type', 'category') ->assertJsonPath('data.product_layout', 'row') ->assertJsonPath('data.group_layout', 'paginated'); $categoryId = $response->json('data.category_id'); $this->assertDatabaseHas('categorias', [ 'id' => $categoryId, 'tenant_code' => $tenant->codigo, 'nombre' => 'Food', ]); $this->assertDatabaseHas('featured_groups', [ 'tenant_code' => $tenant->codigo, 'source_type' => 'category', 'category_id' => $categoryId, 'product_layout' => 'row', 'group_layout' => 'paginated', 'group_name' => 'Food', ]); } public function test_store_uses_column_with_cart_when_the_category_is_not_featured(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->postJson('/api/v1/adminapp/tenant/featured-groups', [ 'category_name' => 'Parking', 'is_featured' => false, ]) ->assertCreated() ->assertJsonPath('data.is_featured', false) ->assertJsonPath('data.product_layout', 'column_with_cart') ->assertJsonPath('data.group_layout', 'paginated'); } public function test_update_changes_the_category_and_group_together(): void { $tenant = $this->createTenant('acme'); $group = $this->createCategoryGroup($tenant, 'Old name', ProductLayout::ColumnWithCart); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->putJson("/api/v1/adminapp/tenant/featured-groups/{$group->id}", [ 'category_name' => 'New name', 'is_featured' => true, ]) ->assertOk() ->assertJsonPath('data.category_name', 'New name') ->assertJsonPath('data.group_name', 'New name') ->assertJsonPath('data.is_featured', true) ->assertJsonPath('data.product_layout', 'row') ->assertJsonPath('data.group_layout', 'paginated'); $this->assertDatabaseHas('categorias', [ 'id' => $group->category_id, 'nombre' => 'New name', ]); $this->assertDatabaseHas('featured_groups', [ 'id' => $group->id, 'group_name' => 'New name', 'product_layout' => 'row', 'group_layout' => 'paginated', ]); } public function test_update_rejects_groups_from_another_tenant_or_source(): void { $tenant = $this->createTenant('acme'); $otherTenant = $this->createTenant('other'); $otherGroup = $this->createCategoryGroup($otherTenant, 'Other'); $allGroup = FeaturedGroup::query()->create([ 'tenant_code' => $tenant->codigo, 'source_type' => FeaturedGroupSource::All, 'product_layout' => ProductLayout::Row, 'group_layout' => GroupLayout::Paginated, 'group_name' => 'All products', 'group_order' => 0, ]); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->putJson( "/api/v1/adminapp/tenant/featured-groups/{$otherGroup->id}", $this->payload(), )->assertNotFound(); $this->putJson( "/api/v1/adminapp/tenant/featured-groups/{$allGroup->id}", $this->payload(), )->assertNotFound(); } public function test_name_and_featured_flag_are_required(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->postJson('/api/v1/adminapp/tenant/featured-groups', [ 'category_name' => '', 'is_featured' => 'yes', ]) ->assertUnprocessable() ->assertJsonValidationErrors(['category_name', 'is_featured']); $this->assertDatabaseCount('categorias', 0); $this->assertDatabaseCount('featured_groups', 0); } public function test_the_controller_is_not_available_for_non_onticket_tenants(): void { $tenant = $this->createTenant('store', 'shopit'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->getJson('/api/v1/adminapp/tenant/featured-groups')->assertNotFound(); $this->postJson('/api/v1/adminapp/tenant/featured-groups', $this->payload()) ->assertNotFound(); } public function test_a_customer_cannot_manage_onticket_featured_groups(): void { Sanctum::actingAs(User::factory()->create([ 'rol_codigo' => RoleCode::User->value, 'tenant_codigo' => null, ])); $this->getJson('/api/v1/adminapp/tenant/featured-groups')->assertForbidden(); $this->postJson('/api/v1/adminapp/tenant/featured-groups', $this->payload()) ->assertForbidden(); } /** @return array{category_name: string, is_featured: bool} */ private function payload(): array { return [ 'category_name' => 'Food', 'is_featured' => true, ]; } private function createTenant(string $code, string $websiteType = 'onticket'): Tenant { return Tenant::query()->create([ 'codigo' => $code, 'nombre' => ucfirst($code), 'dominio' => "{$code}.test", 'website_type_code' => $websiteType, ]); } private function createAdminAppUser(Tenant $tenant): User { return User::factory()->create([ 'rol_codigo' => RoleCode::AdminApp->value, 'tenant_codigo' => $tenant->codigo, ]); } private function createCategoryGroup( Tenant $tenant, string $name, ProductLayout $productLayout = ProductLayout::Row, int $order = 0, ): FeaturedGroup { $category = Category::query()->create([ 'tenant_code' => $tenant->codigo, 'nombre' => $name, ]); return FeaturedGroup::query()->create([ 'tenant_code' => $tenant->codigo, 'source_type' => FeaturedGroupSource::Category, 'category_id' => $category->id, 'product_layout' => $productLayout, 'group_layout' => GroupLayout::Paginated, 'group_name' => $name, 'group_order' => $order, ]); } }