refactor(shop-statuses): migrate to DI, restructure docs into docs/ folder (0.268)
- Migrate ShopStatuses module to Domain + DI architecture - Add ShopStatusRepository, ShopStatusesController with color picker - Convert front\factory\ShopStatuses to facade - Add FormFieldType::COLOR with HTML5 color picker - Move documentation files to docs/ folder (PROJECT_STRUCTURE, REFACTORING_PLAN, CHANGELOG, FORM_EDIT_SYSTEM, TESTING, DATABASE_STRUCTURE) - Tests: 254 tests, 736 assertions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
253
tests/Unit/Domain/ShopStatus/ShopStatusRepositoryTest.php
Normal file
253
tests/Unit/Domain/ShopStatus/ShopStatusRepositoryTest.php
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Domain\ShopStatus;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Domain\ShopStatus\ShopStatusRepository;
|
||||
|
||||
class ShopStatusRepositoryTest extends TestCase
|
||||
{
|
||||
public function testFindReturnsNullForNegativeId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->never())->method('get');
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertNull($repository->find(-1));
|
||||
}
|
||||
|
||||
public function testFindReturnsNullWhenNotFound(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_statuses', '*', ['id' => 99])
|
||||
->willReturn(null);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertNull($repository->find(99));
|
||||
}
|
||||
|
||||
public function testFindReturnsStatusWithIdZero(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_statuses', '*', ['id' => 0])
|
||||
->willReturn([
|
||||
'id' => '0',
|
||||
'status' => 'zamówienie złożone',
|
||||
'color' => '#ff0000',
|
||||
'o' => '0',
|
||||
'apilo_status_id' => '5',
|
||||
]);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$result = $repository->find(0);
|
||||
|
||||
$this->assertIsArray($result);
|
||||
$this->assertSame(0, $result['id']);
|
||||
$this->assertSame('zamówienie złożone', $result['status']);
|
||||
$this->assertSame('#ff0000', $result['color']);
|
||||
$this->assertSame(0, $result['o']);
|
||||
$this->assertSame(5, $result['apilo_status_id']);
|
||||
}
|
||||
|
||||
public function testFindNormalizesNullApiloStatusId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_statuses', '*', ['id' => 1])
|
||||
->willReturn([
|
||||
'id' => '1',
|
||||
'status' => 'zamówienie opłacone',
|
||||
'color' => '',
|
||||
'o' => '1',
|
||||
'apilo_status_id' => null,
|
||||
]);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$result = $repository->find(1);
|
||||
|
||||
$this->assertIsArray($result);
|
||||
$this->assertSame(1, $result['id']);
|
||||
$this->assertNull($result['apilo_status_id']);
|
||||
}
|
||||
|
||||
public function testSaveUpdatesColorAndApiloStatusId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$updateRow = null;
|
||||
$updateWhere = null;
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->willReturnCallback(function ($table, $row, $where) use (&$updateRow, &$updateWhere) {
|
||||
$this->assertSame('pp_shop_statuses', $table);
|
||||
$updateRow = $row;
|
||||
$updateWhere = $where;
|
||||
return true;
|
||||
});
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$id = $repository->save(3, [
|
||||
'color' => ' #00ff00 ',
|
||||
'apilo_status_id' => '12',
|
||||
]);
|
||||
|
||||
$this->assertSame(3, $id);
|
||||
$this->assertSame('#00ff00', $updateRow['color']);
|
||||
$this->assertSame(12, $updateRow['apilo_status_id']);
|
||||
$this->assertSame(['id' => 3], $updateWhere);
|
||||
}
|
||||
|
||||
public function testSaveWithIdZeroWorks(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with('pp_shop_statuses', $this->anything(), ['id' => 0]);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$id = $repository->save(0, ['color' => '#aabbcc']);
|
||||
|
||||
$this->assertSame(0, $id);
|
||||
}
|
||||
|
||||
public function testSaveWithEmptyApiloStatusIdSetsNull(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$updateRow = null;
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->willReturnCallback(function ($table, $row) use (&$updateRow) {
|
||||
$updateRow = $row;
|
||||
});
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$repository->save(1, ['color' => '#000', 'apilo_status_id' => '']);
|
||||
|
||||
$this->assertNull($updateRow['apilo_status_id']);
|
||||
}
|
||||
|
||||
public function testSaveRejectsNegativeId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->never())->method('update');
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertSame(0, $repository->save(-1, ['color' => '#fff']));
|
||||
}
|
||||
|
||||
public function testGetApiloStatusIdReturnsValue(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_statuses', 'apilo_status_id', ['id' => 4])
|
||||
->willReturn(15);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertSame(15, $repository->getApiloStatusId(4));
|
||||
}
|
||||
|
||||
public function testGetApiloStatusIdReturnsNullWhenNotSet(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->willReturn(null);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertNull($repository->getApiloStatusId(4));
|
||||
}
|
||||
|
||||
public function testGetByIntegrationStatusIdForApilo(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_statuses', 'id', ['apilo_status_id' => 15])
|
||||
->willReturn(4);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertSame(4, $repository->getByIntegrationStatusId('apilo', 15));
|
||||
}
|
||||
|
||||
public function testGetByIntegrationStatusIdReturnsNullForUnknownIntegration(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->never())->method('get');
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$this->assertNull($repository->getByIntegrationStatusId('unknown', 1));
|
||||
}
|
||||
|
||||
public function testAllStatusesReturnsOrderedList(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('select')
|
||||
->with('pp_shop_statuses', ['id', 'status'], ['ORDER' => ['o' => 'ASC']])
|
||||
->willReturn([
|
||||
['id' => 0, 'status' => 'złożone'],
|
||||
['id' => 1, 'status' => 'opłacone'],
|
||||
]);
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$result = $repository->allStatuses();
|
||||
|
||||
$this->assertSame([0 => 'złożone', 1 => 'opłacone'], $result);
|
||||
}
|
||||
|
||||
public function testListForAdminWhitelistsSortAndDirection(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$queries = [];
|
||||
|
||||
$mockDb->method('query')
|
||||
->willReturnCallback(function ($sql, $params = []) use (&$queries) {
|
||||
$queries[] = ['sql' => $sql, 'params' => $params];
|
||||
|
||||
if (strpos($sql, 'COUNT(0)') !== false) {
|
||||
return new class {
|
||||
public function fetchAll()
|
||||
{
|
||||
return [[2]];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new class {
|
||||
public function fetchAll()
|
||||
{
|
||||
return [[
|
||||
'id' => 0,
|
||||
'status' => 'złożone',
|
||||
'color' => '#fff',
|
||||
'o' => 0,
|
||||
'apilo_status_id' => null,
|
||||
]];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
$repository = new ShopStatusRepository($mockDb);
|
||||
$result = $repository->listForAdmin(
|
||||
[],
|
||||
'status DESC; DROP TABLE pp_shop_statuses; --',
|
||||
'DESC; DELETE FROM pp_users; --',
|
||||
1,
|
||||
999
|
||||
);
|
||||
|
||||
$this->assertCount(2, $queries);
|
||||
$dataSql = $queries[1]['sql'];
|
||||
|
||||
$this->assertMatchesRegularExpression('/ORDER BY\s+ss\.o\s+ASC,\s+ss\.id\s+ASC/i', $dataSql);
|
||||
$this->assertStringNotContainsString('DROP TABLE', $dataSql);
|
||||
$this->assertStringNotContainsString('DELETE FROM pp_users', $dataSql);
|
||||
$this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user