Integrations DI refactor, remove Sellasist/Baselinker, fix product-edit encoding (0.263)
- New: Domain\Integrations\IntegrationsRepository + admin\Controllers\IntegrationsController (DI) - Cleanup: removed all Sellasist and Baselinker integrations from entire project - Fix: product-edit.php Polish characters (UTF-8/CP1250 double-encoding) - Update: factory\Integrations as facade (Apilo + ShopPRO only) - Tests: 212 tests, 577 assertions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
204
tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php
Normal file
204
tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Domain\Integrations;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Domain\Integrations\IntegrationsRepository;
|
||||
|
||||
class IntegrationsRepositoryTest extends TestCase
|
||||
{
|
||||
private $mockDb;
|
||||
private IntegrationsRepository $repository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->mockDb = $this->createMock(\medoo::class);
|
||||
$this->repository = new IntegrationsRepository($this->mockDb);
|
||||
}
|
||||
|
||||
public function testGetSettingsReturnsArray(): void
|
||||
{
|
||||
$stmt = $this->createMock(\PDOStatement::class);
|
||||
$stmt->expects($this->once())
|
||||
->method('fetchAll')
|
||||
->with(\PDO::FETCH_ASSOC)
|
||||
->willReturn([
|
||||
['name' => 'client-id', 'value' => 'abc123'],
|
||||
['name' => 'client-secret', 'value' => 'secret'],
|
||||
]);
|
||||
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('query')
|
||||
->with('SELECT * FROM pp_shop_apilo_settings')
|
||||
->willReturn($stmt);
|
||||
|
||||
$settings = $this->repository->getSettings('apilo');
|
||||
|
||||
$this->assertIsArray($settings);
|
||||
$this->assertSame('abc123', $settings['client-id']);
|
||||
$this->assertSame('secret', $settings['client-secret']);
|
||||
}
|
||||
|
||||
public function testGetSettingReturnsValue(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_apilo_settings', 'value', ['name' => 'client-id'])
|
||||
->willReturn('abc123');
|
||||
|
||||
$this->assertSame('abc123', $this->repository->getSetting('apilo', 'client-id'));
|
||||
}
|
||||
|
||||
public function testGetSettingReturnsNullWhenNotFound(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_apilo_settings', 'value', ['name' => 'nonexistent'])
|
||||
->willReturn(false);
|
||||
|
||||
$this->assertNull($this->repository->getSetting('apilo', 'nonexistent'));
|
||||
}
|
||||
|
||||
public function testSaveSettingUpdatesExistingValue(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('count')
|
||||
->with('pp_shop_apilo_settings', ['name' => 'client-id'])
|
||||
->willReturn(1);
|
||||
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with('pp_shop_apilo_settings', ['value' => 'new-value'], ['name' => 'client-id']);
|
||||
|
||||
$this->assertTrue($this->repository->saveSetting('apilo', 'client-id', 'new-value'));
|
||||
}
|
||||
|
||||
public function testSaveSettingInsertsNewValue(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('count')
|
||||
->with('pp_shop_shoppro_settings', ['name' => 'domain'])
|
||||
->willReturn(0);
|
||||
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('insert')
|
||||
->with('pp_shop_shoppro_settings', ['name' => 'domain', 'value' => 'example.com']);
|
||||
|
||||
$this->assertTrue($this->repository->saveSetting('shoppro', 'domain', 'example.com'));
|
||||
}
|
||||
|
||||
public function testInvalidProviderThrowsException(): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->repository->getSettings('sellasist');
|
||||
}
|
||||
|
||||
public function testLinkProductUpdatesDatabase(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with(
|
||||
'pp_shop_products',
|
||||
$this->callback(function ($data) {
|
||||
return isset($data['apilo_product_id']) && isset($data['apilo_product_name']);
|
||||
}),
|
||||
['id' => 42]
|
||||
)
|
||||
->willReturn(1);
|
||||
|
||||
$this->assertTrue($this->repository->linkProduct(42, 'ext-123', 'Test Product'));
|
||||
}
|
||||
|
||||
public function testUnlinkProductClearsFields(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with(
|
||||
'pp_shop_products',
|
||||
['apilo_product_id' => null, 'apilo_product_name' => null],
|
||||
['id' => 42]
|
||||
)
|
||||
->willReturn(1);
|
||||
|
||||
$this->assertTrue($this->repository->unlinkProduct(42));
|
||||
}
|
||||
|
||||
public function testGetProductSkuReturnsValue(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_products', 'sku', ['id' => 10])
|
||||
->willReturn('SKU-100');
|
||||
|
||||
$this->assertSame('SKU-100', $this->repository->getProductSku(10));
|
||||
}
|
||||
|
||||
public function testGetProductSkuReturnsNullForMissing(): void
|
||||
{
|
||||
$this->mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_products', 'sku', ['id' => 999])
|
||||
->willReturn(false);
|
||||
|
||||
$this->assertNull($this->repository->getProductSku(999));
|
||||
}
|
||||
|
||||
public function testApiloGetAccessTokenReturnsNullWithoutSettings(): void
|
||||
{
|
||||
$stmt = $this->createMock(\PDOStatement::class);
|
||||
$stmt->method('fetchAll')->willReturn([]);
|
||||
|
||||
$this->mockDb->method('query')->willReturn($stmt);
|
||||
|
||||
$this->assertNull($this->repository->apiloGetAccessToken());
|
||||
}
|
||||
|
||||
public function testApiloFetchListThrowsForInvalidType(): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->repository->apiloFetchList('invalid');
|
||||
}
|
||||
|
||||
public function testAllPublicMethodsExist(): void
|
||||
{
|
||||
$expectedMethods = [
|
||||
'getSettings', 'getSetting', 'saveSetting',
|
||||
'linkProduct', 'unlinkProduct',
|
||||
'apiloAuthorize', 'apiloGetAccessToken',
|
||||
'apiloFetchList', 'apiloProductSearch', 'apiloCreateProduct',
|
||||
'getProductSku', 'shopproImportProduct',
|
||||
];
|
||||
|
||||
foreach ($expectedMethods as $method) {
|
||||
$this->assertTrue(
|
||||
method_exists($this->repository, $method),
|
||||
"Method $method does not exist"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testSettingsTableMapping(): void
|
||||
{
|
||||
// Verify apilo maps correctly
|
||||
$stmt = $this->createMock(\PDOStatement::class);
|
||||
$stmt->method('fetchAll')->willReturn([]);
|
||||
$this->mockDb->method('query')
|
||||
->with($this->stringContains('pp_shop_apilo_settings'))
|
||||
->willReturn($stmt);
|
||||
|
||||
$this->assertIsArray($this->repository->getSettings('apilo'));
|
||||
}
|
||||
|
||||
public function testShopproProviderWorks(): void
|
||||
{
|
||||
$stmt = $this->createMock(\PDOStatement::class);
|
||||
$stmt->method('fetchAll')->willReturn([
|
||||
['name' => 'domain', 'value' => 'test.com'],
|
||||
]);
|
||||
$this->mockDb->method('query')
|
||||
->with($this->stringContains('pp_shop_shoppro_settings'))
|
||||
->willReturn($stmt);
|
||||
|
||||
$settings = $this->repository->getSettings('shoppro');
|
||||
$this->assertSame('test.com', $settings['domain']);
|
||||
}
|
||||
}
|
||||
171
tests/Unit/admin/Controllers/IntegrationsControllerTest.php
Normal file
171
tests/Unit/admin/Controllers/IntegrationsControllerTest.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
namespace Tests\Unit\admin\Controllers;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use admin\Controllers\IntegrationsController;
|
||||
use Domain\Integrations\IntegrationsRepository;
|
||||
|
||||
class IntegrationsControllerTest extends TestCase
|
||||
{
|
||||
private $repository;
|
||||
private IntegrationsController $controller;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->repository = $this->createMock(IntegrationsRepository::class);
|
||||
$this->controller = new IntegrationsController($this->repository);
|
||||
}
|
||||
|
||||
public function testConstructorAcceptsDependencies(): void
|
||||
{
|
||||
$controller = new IntegrationsController($this->repository);
|
||||
$this->assertInstanceOf(IntegrationsController::class, $controller);
|
||||
}
|
||||
|
||||
public function testConstructorRequiresRepository(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass(IntegrationsController::class);
|
||||
$constructor = $reflection->getConstructor();
|
||||
$params = $constructor->getParameters();
|
||||
|
||||
$this->assertCount(1, $params);
|
||||
$this->assertEquals(
|
||||
'Domain\Integrations\IntegrationsRepository',
|
||||
$params[0]->getType()->getName()
|
||||
);
|
||||
}
|
||||
|
||||
public function testHasAllApiloSettingsMethods(): void
|
||||
{
|
||||
$methods = [
|
||||
'apilo_settings',
|
||||
'apilo_settings_save',
|
||||
'apilo_authorization',
|
||||
];
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$this->assertTrue(
|
||||
method_exists($this->controller, $method),
|
||||
"Method $method does not exist"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testHasAllApiloDataFetchMethods(): void
|
||||
{
|
||||
$methods = [
|
||||
'get_platform_list',
|
||||
'get_status_types_list',
|
||||
'get_carrier_account_list',
|
||||
'get_payment_types_list',
|
||||
];
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$this->assertTrue(
|
||||
method_exists($this->controller, $method),
|
||||
"Method $method does not exist"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testHasAllApiloProductMethods(): void
|
||||
{
|
||||
$methods = [
|
||||
'apilo_create_product',
|
||||
'apilo_product_search',
|
||||
'apilo_product_select_save',
|
||||
'apilo_product_select_delete',
|
||||
];
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$this->assertTrue(
|
||||
method_exists($this->controller, $method),
|
||||
"Method $method does not exist"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testHasAllShopproMethods(): void
|
||||
{
|
||||
$methods = [
|
||||
'shoppro_settings',
|
||||
'shoppro_settings_save',
|
||||
'shoppro_product_import',
|
||||
];
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$this->assertTrue(
|
||||
method_exists($this->controller, $method),
|
||||
"Method $method does not exist"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testApiloSettingsReturnsString(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
$this->assertEquals('string', (string) $reflection->getMethod('apilo_settings')->getReturnType());
|
||||
}
|
||||
|
||||
public function testShopproSettingsReturnsString(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
$this->assertEquals('string', (string) $reflection->getMethod('shoppro_settings')->getReturnType());
|
||||
}
|
||||
|
||||
public function testVoidReturnTypes(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
|
||||
$voidMethods = [
|
||||
'apilo_settings_save',
|
||||
'apilo_authorization',
|
||||
'get_platform_list',
|
||||
'get_status_types_list',
|
||||
'get_carrier_account_list',
|
||||
'get_payment_types_list',
|
||||
'apilo_create_product',
|
||||
'apilo_product_search',
|
||||
'apilo_product_select_save',
|
||||
'apilo_product_select_delete',
|
||||
'shoppro_settings_save',
|
||||
'shoppro_product_import',
|
||||
];
|
||||
|
||||
foreach ($voidMethods as $method) {
|
||||
$this->assertEquals(
|
||||
'void',
|
||||
(string) $reflection->getMethod($method)->getReturnType(),
|
||||
"Method $method should return void"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testDoesNotHaveSellasistMethods(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
$methods = array_map(fn($m) => $m->getName(), $reflection->getMethods());
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$this->assertStringNotContainsString(
|
||||
'sellasist',
|
||||
strtolower($method),
|
||||
"Controller should not have sellasist method: $method"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testDoesNotHaveBaselinkerMethods(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
$methods = array_map(fn($m) => $m->getName(), $reflection->getMethods());
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$this->assertStringNotContainsString(
|
||||
'baselinker',
|
||||
strtolower($method),
|
||||
"Controller should not have baselinker method: $method"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ if (!class_exists('S')) {
|
||||
public static function clear_redis_cache() {}
|
||||
public static function clear_product_cache($id) {}
|
||||
public static function send_email($to, $subject, $body) { return true; }
|
||||
public static function remove_special_chars($str) { return str_ireplace(['\'', '"', ',', ';', '<', '>'], ' ', $str); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user