mockDb = $this->createMock(\medoo::class); $this->repository = new IntegrationsRepository($this->mockDb); } public function testGetSettingsReturnsArray(): void { $this->mockDb->expects($this->once()) ->method('select') ->with('pp_shop_apilo_settings', ['name', 'value']) ->willReturn([ ['name' => 'client-id', 'value' => 'abc123'], ['name' => 'client-secret', 'value' => 'secret'], ]); $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 { $this->mockDb->method('select')->willReturn([]); $this->assertNull($this->repository->apiloGetAccessToken()); } public function testShouldRefreshAccessTokenReturnsFalseForFarFutureDate(): void { $reflection = new \ReflectionClass($this->repository); $method = $reflection->getMethod('shouldRefreshAccessToken'); $method->setAccessible(true); $future = date('Y-m-d H:i:s', time() + 3600); $result = $method->invoke($this->repository, $future, 300); $this->assertFalse($result); } public function testShouldRefreshAccessTokenReturnsTrueForNearExpiryDate(): void { $reflection = new \ReflectionClass($this->repository); $method = $reflection->getMethod('shouldRefreshAccessToken'); $method->setAccessible(true); $near = date('Y-m-d H:i:s', time() + 120); $result = $method->invoke($this->repository, $near, 300); $this->assertTrue($result); } public function testApiloFetchListThrowsForInvalidType(): void { $this->expectException(\InvalidArgumentException::class); $this->repository->apiloFetchList('invalid'); } public function testApiloFetchListResultReturnsDetailedErrorWhenConfigMissing(): void { $this->mockDb->expects($this->once()) ->method('select') ->with('pp_shop_apilo_settings', ['name', 'value']) ->willReturn([]); $result = $this->repository->apiloFetchListResult('payment'); $this->assertIsArray($result); $this->assertFalse((bool)($result['success'] ?? true)); $this->assertStringContainsString('Brakuje konfiguracji Apilo', (string)($result['message'] ?? '')); } public function testApiloIntegrationStatusReturnsMissingConfigMessage(): void { $this->mockDb->expects($this->once()) ->method('select') ->with('pp_shop_apilo_settings', ['name', 'value']) ->willReturn([]); $status = $this->repository->apiloIntegrationStatus(); $this->assertIsArray($status); $this->assertFalse((bool)($status['is_valid'] ?? true)); $this->assertStringContainsString('Brakuje konfiguracji Apilo', (string)($status['message'] ?? '')); } public function testAllPublicMethodsExist(): void { $expectedMethods = [ 'getSettings', 'getSetting', 'saveSetting', 'linkProduct', 'unlinkProduct', 'apiloAuthorize', 'apiloGetAccessToken', 'apiloKeepalive', 'apiloIntegrationStatus', 'apiloFetchList', 'apiloFetchListResult', 'apiloProductSearch', 'apiloCreateProduct', 'getProductSku', 'shopproImportProduct', ]; foreach ($expectedMethods as $method) { $this->assertTrue( method_exists($this->repository, $method), "Method $method does not exist" ); } } public function testSettingsTableMapping(): void { $this->mockDb->method('select') ->with('pp_shop_apilo_settings', ['name', 'value']) ->willReturn([]); $this->assertIsArray($this->repository->getSettings('apilo')); } public function testShopproProviderWorks(): void { $this->mockDb->method('select') ->with('pp_shop_shoppro_settings', ['name', 'value']) ->willReturn([ ['name' => 'domain', 'value' => 'test.com'], ]); $settings = $this->repository->getSettings('shoppro'); $this->assertSame('test.com', $settings['domain']); } public function testNormalizeApiloMapListRejectsErrorPayload(): void { $reflection = new \ReflectionClass($this->repository); $method = $reflection->getMethod('normalizeApiloMapList'); $method->setAccessible(true); $result = $method->invoke($this->repository, [ 'message' => 'Missing JWT token', 'code' => 401, ]); $this->assertNull($result); } public function testNormalizeApiloMapListAcceptsIdNameList(): void { $reflection = new \ReflectionClass($this->repository); $method = $reflection->getMethod('normalizeApiloMapList'); $method->setAccessible(true); $payload = [ ['id' => '1', 'name' => 'Przelew'], ['id' => '2', 'name' => 'Karta'], ]; $result = $method->invoke($this->repository, $payload); $this->assertIsArray($result); $this->assertCount(2, $result); $this->assertSame('1', (string)$result[0]['id']); $this->assertSame('Przelew', (string)$result[0]['name']); } // ── Logs ──────────────────────────────────────────────────── public function testGetLogsReturnsItemsAndTotal(): void { $this->mockDb->expects($this->once()) ->method('count') ->with('pp_log', $this->anything()) ->willReturn(2); $this->mockDb->expects($this->once()) ->method('select') ->with('pp_log', '*', $this->anything()) ->willReturn([ ['id' => 1, 'action' => 'send_order', 'message' => 'OK', 'date' => '2026-01-01 12:00:00'], ['id' => 2, 'action' => 'status_sync', 'message' => 'Synced', 'date' => '2026-01-02 12:00:00'], ]); $result = $this->repository->getLogs([], 'id', 'DESC', 1, 15); $this->assertIsArray($result); $this->assertArrayHasKey('items', $result); $this->assertArrayHasKey('total', $result); $this->assertCount(2, $result['items']); $this->assertSame(2, $result['total']); } public function testGetLogsReturnsEmptyWhenNoResults(): void { $this->mockDb->method('count')->willReturn(0); $this->mockDb->method('select')->willReturn([]); $result = $this->repository->getLogs([], 'id', 'DESC', 1, 15); $this->assertSame(0, $result['total']); $this->assertEmpty($result['items']); } public function testGetLogsHandlesNullFromSelect(): void { $this->mockDb->method('count')->willReturn(0); $this->mockDb->method('select')->willReturn(null); $result = $this->repository->getLogs([], 'id', 'DESC', 1, 15); $this->assertSame([], $result['items']); } public function testDeleteLogCallsDelete(): void { $this->mockDb->expects($this->once()) ->method('delete') ->with('pp_log', ['id' => 42]); $this->assertTrue($this->repository->deleteLog(42)); } public function testClearLogsDeletesAll(): void { $this->mockDb->expects($this->once()) ->method('delete') ->with('pp_log', []); $this->assertTrue($this->repository->clearLogs()); } }