'Relation Test', 'title' => 'Relation Test', 'active' => true, ]); $ingredient = Ingredient::create([ 'name' => 'Test INCI', 'trans_name' => '', 'inci' => '', 'trans_inci' => '', 'effect' => '', 'trans_effect' => '', 'active' => true, 'pos' => 0, ]); ProductIngredient::create([ 'product_id' => $product->id, 'ingredient_id' => $ingredient->id, ]); $product->refresh(); expect($product->product_ingredients)->toHaveCount(1); expect($product->product_ingredients->first()->ingredient_id)->toBe($ingredient->id); }); test('ingredient product_ingredients relation uses ingredient_id foreign key', function () { $product = Product::create([ 'name' => 'Relation Test 2', 'title' => 'Relation Test 2', 'active' => true, ]); $ingredient = Ingredient::create([ 'name' => 'Test INCI 2', 'trans_name' => '', 'inci' => '', 'trans_inci' => '', 'effect' => '', 'trans_effect' => '', 'active' => true, 'pos' => 0, ]); ProductIngredient::create([ 'product_id' => $product->id, 'ingredient_id' => $ingredient->id, ]); $ingredient->refresh(); expect($ingredient->product_ingredients)->toHaveCount(1); expect($ingredient->product_ingredients->first()->product_id)->toBe($product->id); }); test('updateIngredients removes deselected ingredients', function () { $product = Product::create([ 'name' => 'Sync Test', 'title' => 'Sync Test', 'active' => true, ]); $a = Ingredient::create([ 'name' => 'Alpha', 'trans_name' => '', 'inci' => '', 'trans_inci' => '', 'effect' => '', 'trans_effect' => '', 'active' => true, 'pos' => 0, ]); $b = Ingredient::create([ 'name' => 'Beta', 'trans_name' => '', 'inci' => '', 'trans_inci' => '', 'effect' => '', 'trans_effect' => '', 'active' => true, 'pos' => 0, ]); $repo = new ProductRepository($product); $repo->updateIngredients(['product_ingredients' => [(string) $a->id, (string) $b->id]]); expect($product->fresh()->p_ingredients)->toHaveCount(2); $repo->updateIngredients(['product_ingredients' => [(string) $a->id]]); expect($product->fresh()->p_ingredients)->toHaveCount(1); expect($product->fresh()->p_ingredients->first()->id)->toBe($a->id); }); test('getProductIngredientsOptions lists ingredients alphabetically by name', function () { Ingredient::create([ 'name' => 'Zebra', 'trans_name' => '', 'inci' => '', 'trans_inci' => '', 'effect' => '', 'trans_effect' => '', 'active' => true, 'pos' => 0, ]); Ingredient::create([ 'name' => 'Alpha', 'trans_name' => '', 'inci' => '', 'trans_inci' => '', 'effect' => '', 'trans_effect' => '', 'active' => true, 'pos' => 0, ]); $html = HTMLHelper::getProductIngredientsOptions([], false); expect(strpos($html, 'Alpha'))->toBeLessThan(strpos($html, 'Zebra')); }); test('copy preserves product attribute type_id', function () { $type = AttributeType::create([ 'name' => 'Type A', 'slug' => 'type-a-'.uniqid(), 'pos' => 0, 'active' => true, ]); $typeB = AttributeType::create([ 'name' => 'Type B', 'slug' => 'type-b-'.uniqid(), 'pos' => 1, 'active' => true, ]); $attr = Attribute::create([ 'attribute_type_id' => $type->id, 'name' => 'Attr', 'trans_name' => '', 'pos' => 0, 'active' => true, 'slug' => 'attr-'.uniqid(), ]); $source = Product::create([ 'name' => 'Source', 'title' => 'Source', 'active' => true, ]); ProductAttribute::create([ 'product_id' => $source->id, 'type_id' => $typeB->id, 'attribute_id' => $attr->id, ]); $repo = new ProductRepository(new Product); $copy = $repo->copy($source->fresh()); $copied = $copy->attributes()->first(); expect($copied)->not->toBeNull(); expect($copied->type_id)->toBe($typeB->id); expect($copied->attribute_id)->toBe($attr->id); });