Files
shopPRO/tests/Unit/Domain/Product/ProductFeedLinkTest.php
Jacek Pyziak fba215b372 fix: linki produktow z permutacja atrybutow w feedzie Google (v0.350)
Separator URL miedzy parami attr-val zmieniony z "/" na "_" w generatorze
feedu (ProductRepository::appendCombinationToXml). Wzorzec routingu
pp_routes rozszerzony do [0-9_-]+ w Helpers::htacces (oba warianty:
seo_link i fallback p-id-name). LayoutEngine konwertuje "_" -> "|"
przed wywolaniem ProductRepository::findCached — format DB pozostaje "|".
Partial product-attribute.php preselectuje wartosc z permutation_hash
URL (forced_value_id), co poprawia UX wejscia z linka feedu.

Suita: 834 -> 841 testow (+7), 2330 assertions.

Wymagane akcje na produkcji po deployu: regeneracja pp_routes
(Helpers::htacces), wyczyszczenie klucza pp_routes:all w Redis,
regeneracja google-feed.xml, resubmit feedu w GMC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-30 01:58:29 +02:00

152 lines
5.5 KiB
PHP

<?php
namespace Tests\Unit\Domain\Product;
use PHPUnit\Framework\TestCase;
use Domain\Product\ProductRepository;
/**
* Phase 18 — testy generatora linku do feedu Google.
*
* ProductRepository::appendCombinationToXml buduje <link> dla pozycji
* feedu Google. permutation_hash w bazie ma format "attr-val|attr-val".
* W URL feedu separator między parami to "_" (nie "/"), żeby URL był
* jednym segmentem dopasowywalnym przez routing pp_routes.
*
* Test wywołuje prywatną metodę przez ReflectionMethod z minimalnymi
* danymi produktu i sprawdza zawartość wynikowego DOMDocument.
*/
class ProductFeedLinkTest extends TestCase
{
private function buildRepoWithMocks(): ProductRepository
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->method('select')->willReturn([]);
$mockDb->method('get')->willReturn(null);
$repo = new ProductRepository($mockDb);
// appendShippingToXml wywołuje $this->transportRepoForXml->lowestTransportPrice().
// Inicjalizacja w generateGoogleXmlFeed(); dla unit testu wstrzykujemy mock dynamicznie.
$transportMock = $this->getMockBuilder(\Domain\Transport\TransportRepository::class)
->disableOriginalConstructor()
->getMock();
$transportMock->method('lowestTransportPrice')->willReturn(0.0);
$repo->transportRepoForXml = $transportMock;
return $repo;
}
private function invokeAppendCombination(ProductRepository $repo, array $product, array $combination): string
{
$doc = new \DOMDocument('1.0', 'UTF-8');
$channelNode = $doc->appendChild($doc->createElement('channel'));
$method = new \ReflectionMethod(ProductRepository::class, 'appendCombinationToXml');
$method->setAccessible(true);
$method->invoke($repo, $doc, $channelNode, $product, $combination, 'https', 'shop.example.com');
return $doc->saveXML();
}
private function baseProduct(array $overrides = []): array
{
return array_merge([
'id' => 123,
'ean' => '5901234567890',
'language' => [
'name' => 'Produkt testowy',
'xml_name' => '',
'short_description' => 'Opis',
'meta_title' => '',
'seo_link' => 'sukienka-czerwona',
],
'price_brutto' => 100,
'price_brutto_promo' => 0,
'quantity' => 10,
'stock_0_buy' => 0,
'wp' => 1,
'images' => [],
], $overrides);
}
public function testCombinationLinkUsesUnderscoreInSeoLinkBranch()
{
$repo = $this->buildRepoWithMocks();
$product = $this->baseProduct();
$combination = [
'id' => 555,
'permutation_hash' => '20-170|21-175',
'price_brutto' => 120,
'price_brutto_promo' => 0,
'quantity' => 5,
'stock_0_buy' => 0,
];
$xml = $this->invokeAppendCombination($repo, $product, $combination);
$this->assertStringContainsString(
'<link>https://shop.example.com/sukienka-czerwona/20-170_21-175</link>',
$xml,
'Link feedu z seo_link musi używać "_" jako separatora par attr-val'
);
$this->assertStringNotContainsString(
'20-170/21-175',
$xml,
'Link feedu nie może zawierać starego separatora "/" między parami atrybutów'
);
}
public function testCombinationLinkUsesUnderscoreInFallbackBranch()
{
$repo = $this->buildRepoWithMocks();
$product = $this->baseProduct([
'language' => [
'name' => 'Sukienka czerwona',
'xml_name' => '',
'short_description' => 'Opis',
'meta_title' => '',
'seo_link' => '',
],
]);
$combination = [
'id' => 555,
'permutation_hash' => '20-170|21-175',
'price_brutto' => 120,
'price_brutto_promo' => 0,
'quantity' => 5,
'stock_0_buy' => 0,
];
$xml = $this->invokeAppendCombination($repo, $product, $combination);
// Fallback uses "p-{id}-{seo(name)}/...". Helpers::seo stub returns input unchanged.
$this->assertStringContainsString(
'<link>https://shop.example.com/p-123-Sukienka czerwona/20-170_21-175</link>',
$xml,
'Link fallback (bez seo_link) musi używać "_" jako separatora par attr-val'
);
}
public function testCombinationLinkWithSinglePair()
{
$repo = $this->buildRepoWithMocks();
$product = $this->baseProduct();
$combination = [
'id' => 555,
'permutation_hash' => '20-170',
'price_brutto' => 120,
'price_brutto_promo' => 0,
'quantity' => 5,
'stock_0_buy' => 0,
];
$xml = $this->invokeAppendCombination($repo, $product, $combination);
$this->assertStringContainsString(
'<link>https://shop.example.com/sukienka-czerwona/20-170</link>',
$xml,
'Pojedyncza para attr-val pozostaje bez zmian (str_replace nie ma co podmieniać)'
);
}
}