markTestSkipped('EBAY_* env vars not set'); } $http = HttpClient::create(); $cache = new ArrayAdapter(); $this->oauth = new EbayOAuthClient( $http, $cache, (string) $clientId, (string) $clientSecret, (string) $oauthBaseUrl, ); $this->taxonomy = new EbayTaxonomyService( $http, $this->oauth, $cache, (string) $apiBaseUrl, (string) $marketplaceId, ); } public function testFetchesApplicationToken(): void { $token = $this->oauth->getAccessToken(); $this->assertNotEmpty($token); $this->assertStringStartsWith('v^1.1', $token); } public function testFetchesAspectsForNotebooksCategory(): void { // 177 = Notebooks & Netbooks in EBAY_DE $aspects = $this->taxonomy->getCategoryAspects('177'); $this->assertNotEmpty($aspects, 'Category 177 should have aspects'); foreach ($aspects as $aspect) { $this->assertArrayHasKey('name', $aspect); $this->assertArrayHasKey('required', $aspect); $this->assertArrayHasKey('usage', $aspect); $this->assertArrayHasKey('values', $aspect); $this->assertIsString($aspect['name']); $this->assertIsBool($aspect['required']); $this->assertContains($aspect['usage'], ['RECOMMENDED', 'OPTIONAL'], 'usage must be a known eBay tier'); $this->assertIsArray($aspect['values']); } $names = array_column($aspects, 'name'); $this->assertNotEmpty( array_filter($names, static fn (string $n) => str_contains(strtolower($n), 'prozes') || str_contains(strtolower($n), 'cpu') || str_contains(strtolower($n), 'speicher')), 'Expected at least one hardware aspect (CPU/RAM)', ); } public function testThreeTierAspectClassification(): void { // eBay has three effective tiers: // required=true + usage=RECOMMENDED → hard gate, eBay blocks listing without it // required=false + usage=RECOMMENDED → "you should have this", search ranking signal // required=false + usage=OPTIONAL → truly optional, low impact $aspects = $this->taxonomy->getCategoryAspects('177'); $hardRequired = array_filter($aspects, static fn (array $a) => $a['required']); $recommended = array_filter($aspects, static fn (array $a) => !$a['required'] && 'RECOMMENDED' === $a['usage']); $optional = array_filter($aspects, static fn (array $a) => !$a['required'] && 'OPTIONAL' === $a['usage']); $this->assertNotEmpty($hardRequired, 'Should have hard-required aspects'); $this->assertNotEmpty($recommended, 'Should have recommended (ranking-signal) aspects'); $this->assertNotEmpty($optional, 'Should have truly optional aspects'); } public function testAspectsWithPredefinedValuesHaveOptions(): void { $aspects = $this->taxonomy->getCategoryAspects('177'); $withOptions = array_filter($aspects, static fn (array $a) => [] !== $a['values']); $this->assertNotEmpty($withOptions, 'Some aspects should have predefined selectable values'); } public function testCachesAspectsOnSecondCall(): void { // First call hits the API $first = $this->taxonomy->getCategoryAspects('177'); // Second call should return from cache (same ArrayAdapter instance) $second = $this->taxonomy->getCategoryAspects('177'); $this->assertSame($first, $second); } public function testFetchesAspectsForRamCategory(): void { // 170083 = RAM/Speicher in EBAY_DE — useful for our memory article types $aspects = $this->taxonomy->getCategoryAspects('170083'); $this->assertNotEmpty($aspects); $names = array_map(static fn (array $a) => $a['name'], $aspects); $this->assertNotEmpty($names); } public function testCategorySuggestionsReturnsResults(): void { $results = $this->taxonomy->getCategorySuggestions('Notebook'); $this->assertNotEmpty($results, 'Sandbox must return at least one suggestion for "Notebook"'); foreach ($results as $result) { $this->assertArrayHasKey('id', $result); $this->assertArrayHasKey('name', $result); $this->assertArrayHasKey('path', $result); $this->assertIsString($result['id']); $this->assertNotEmpty($result['id']); $this->assertIsString($result['name']); } } }