diff --git a/Helper/Product.php b/Helper/Product.php index 721155c3..f44b3449 100644 --- a/Helper/Product.php +++ b/Helper/Product.php @@ -233,7 +233,7 @@ public function validateProduct($product, $parent, $config) } } - $visibilityFilter = $filters['visibility'] ?? []; + $visibilityFilter = array_map('intval', $filters['visibility'] ?? []); if (!empty($visibilityFilter) && in_array($product->getVisibility(), $visibilityFilter, true)) { return true; } @@ -972,7 +972,11 @@ public function addAttributeData($attributes, $filters) } } catch (\Exception $e) { $this->logger->addErrorLog('addAttributeData', $e->getMessage()); - unset($attributes[$key]); + if (!empty($value['label'])) { + $attributes[$key]['type'] = null; + } else { + unset($attributes[$key]); + } } } diff --git a/Model/Item.php b/Model/Item.php index 226bb7ce..1b2bb209 100644 --- a/Model/Item.php +++ b/Model/Item.php @@ -131,6 +131,10 @@ public function __construct( */ public function add($row, $storeId) { + if (empty($row['id'])) { + return; + } + $data = []; $data['item_id'] = $storeId . sprintf('%08d', $row['id']); $data['store_id'] = $storeId; diff --git a/Test/End-2-end/tests/feed/feed-generation.spec.ts b/Test/End-2-end/tests/feed/feed-generation.spec.ts new file mode 100644 index 00000000..0f959ae2 --- /dev/null +++ b/Test/End-2-end/tests/feed/feed-generation.spec.ts @@ -0,0 +1,118 @@ +/* + * Copyright Magmodules.eu. All rights reserved. + * See COPYING.txt for license details. + */ + +import { test, expect } from '@playwright/test'; +import ChannableApi from 'Services/ChannableApi'; + +const api = new ChannableApi(); + +const FEED_TOKEN = process.env.CHANNABLE_TOKEN || 'e2e-test-token'; +const STORE_ID = 1; + +const CONFIG = { + 'magmodules_channable/general/enable': '1', +}; + +test.describe('Feed Generation', () => { + test.beforeAll(async ({}, testInfo) => { + const baseURL = testInfo.project.use.baseURL!; + await api.setMagentoConfig(baseURL, CONFIG); + }); + + test('feed endpoint returns valid JSON without errors', async ({ request }) => { + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=${FEED_TOKEN}&page=1`); + + expect(response.status()).toBe(200); + + const body = await response.json(); + expect(body).not.toHaveProperty('error'); + }); + + test('feed endpoint returns products array', async ({ request }) => { + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=${FEED_TOKEN}&page=1`); + + const body = await response.json(); + expect(body).toHaveProperty('products'); + expect(Array.isArray(body.products)).toBe(true); + }); + + test('feed products contain required id and title fields', async ({ request }) => { + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=${FEED_TOKEN}&page=1`); + + const body = await response.json(); + const products = body.products ?? []; + + // Skip if no products in feed (empty catalog) + if (products.length === 0) return; + + for (const product of products) { + // Every product row must have an id and title + expect(product).toHaveProperty('id'); + expect(product).toHaveProperty('title'); + expect(product.id).toBeTruthy(); + } + }); + + test('feed does not crash with visibility filter enabled', async ({ request }, testInfo) => { + const baseURL = testInfo.project.use.baseURL!; + + // Enable visibility filter and include "Not Visible Individually" (value 1) + await api.setMagentoConfig(baseURL, { + ...CONFIG, + 'magmodules_channable/filter/visbility_enabled': '1', + 'magmodules_channable/filter/visbility': '1', + }); + + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=${FEED_TOKEN}&page=1`); + + expect(response.status()).toBe(200); + + const body = await response.json(); + expect(body).not.toHaveProperty('error'); + + // Reset visibility filter + await api.setMagentoConfig(baseURL, { + ...CONFIG, + 'magmodules_channable/filter/visbility_enabled': '0', + }); + }); + + test('feed returns empty for invalid token', async ({ request }) => { + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=wrong-token&page=1`); + + expect(response.status()).toBe(200); + + const body = await response.json(); + // Should return empty array, not an error page + expect(Array.isArray(body) || (typeof body === 'object' && Object.keys(body).length === 0)).toBe(true); + }); + + test('feed returns empty when module is disabled', async ({ request }, testInfo) => { + const baseURL = testInfo.project.use.baseURL!; + + await api.setMagentoConfig(baseURL, { + 'magmodules_channable/general/enable': '0', + }); + + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=${FEED_TOKEN}&page=1`); + + expect(response.status()).toBe(200); + + const body = await response.json(); + expect(Array.isArray(body) || (typeof body === 'object' && Object.keys(body).length === 0)).toBe(true); + + // Re-enable + await api.setMagentoConfig(baseURL, CONFIG); + }); + + test('single product feed via pid parameter', async ({ request }) => { + const response = await request.get(`/channable/feed/json?id=${STORE_ID}&token=${FEED_TOKEN}&pid=1`); + + expect(response.status()).toBe(200); + + const body = await response.json(); + expect(body).not.toHaveProperty('error'); + }); +});