feat: Add Transport module with repository, controller, and views
- Implemented TransportRepository for managing transport data with methods for listing, finding, saving, and retrieving transport costs. - Created ShopTransportController to handle transport-related actions, including listing, editing, and saving transports. - Added views for transport management: transports list and transport edit forms. - Introduced JavaScript for responsive tabs in transport edit view. - Updated testing suite with comprehensive unit tests for TransportRepository and ShopTransportController. - Increased test coverage with new assertions and scenarios for transport functionalities.
This commit is contained in:
334
tests/Unit/Domain/Transport/TransportRepositoryTest.php
Normal file
334
tests/Unit/Domain/Transport/TransportRepositoryTest.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Domain\Transport;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Domain\Transport\TransportRepository;
|
||||
|
||||
class TransportRepositoryTest extends TestCase
|
||||
{
|
||||
public function testFindReturnsNullForInvalidId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->never())->method('get');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$this->assertNull($repository->find(0));
|
||||
$this->assertNull($repository->find(-1));
|
||||
}
|
||||
|
||||
public function testFindReturnsNullWhenNotFound(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_transports', '*', ['id' => 5])
|
||||
->willReturn(null);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$this->assertNull($repository->find(5));
|
||||
}
|
||||
|
||||
public function testFindNormalizesDataAndIncludesPaymentMethods(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_shop_transports', '*', ['id' => 3])
|
||||
->willReturn([
|
||||
'id' => '3',
|
||||
'name' => 'Kurier DPD',
|
||||
'name_visible' => 'DPD',
|
||||
'description' => 'Opis',
|
||||
'status' => '1',
|
||||
'cost' => '15.99',
|
||||
'max_wp' => '30',
|
||||
'default' => '0',
|
||||
'delivery_free' => '1',
|
||||
'apilo_carrier_account_id' => '42',
|
||||
'o' => '2',
|
||||
]);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('select')
|
||||
->with('pp_shop_transport_payment_methods', 'id_payment_method', ['id_transport' => 3])
|
||||
->willReturn([1, 3, 5]);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$result = $repository->find(3);
|
||||
|
||||
$this->assertIsArray($result);
|
||||
$this->assertSame(3, $result['id']);
|
||||
$this->assertSame('Kurier DPD', $result['name']);
|
||||
$this->assertSame(1, $result['status']);
|
||||
$this->assertSame(15.99, $result['cost']);
|
||||
$this->assertSame(30, $result['max_wp']);
|
||||
$this->assertSame(0, $result['default']);
|
||||
$this->assertSame(1, $result['delivery_free']);
|
||||
$this->assertSame(42, $result['apilo_carrier_account_id']);
|
||||
$this->assertSame(2, $result['o']);
|
||||
$this->assertSame([1, 3, 5], $result['payment_methods']);
|
||||
}
|
||||
|
||||
public function testFindHandlesNullMaxWpAndApiloId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->method('get')
|
||||
->willReturn([
|
||||
'id' => '1',
|
||||
'name' => 'Test',
|
||||
'status' => '0',
|
||||
'cost' => '0',
|
||||
'max_wp' => null,
|
||||
'default' => '0',
|
||||
'delivery_free' => '0',
|
||||
'apilo_carrier_account_id' => null,
|
||||
'o' => '0',
|
||||
]);
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$result = $repository->find(1);
|
||||
|
||||
$this->assertNull($result['max_wp']);
|
||||
$this->assertNull($result['apilo_carrier_account_id']);
|
||||
$this->assertSame([], $result['payment_methods']);
|
||||
}
|
||||
|
||||
public function testSaveInsertReturnsNewId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('insert')
|
||||
->with('pp_shop_transports', $this->callback(function ($data) {
|
||||
return $data['name'] === 'Nowy transport'
|
||||
&& $data['status'] === 1
|
||||
&& $data['cost'] === 10.5;
|
||||
}));
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('id')
|
||||
->willReturn('7');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$id = $repository->save([
|
||||
'id' => 0,
|
||||
'name' => 'Nowy transport',
|
||||
'status' => 'on',
|
||||
'cost' => '10.5',
|
||||
'default' => '0',
|
||||
'delivery_free' => 0,
|
||||
]);
|
||||
|
||||
$this->assertSame(7, $id);
|
||||
}
|
||||
|
||||
public function testSaveUpdateReturnsExistingId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with('pp_shop_transports', $this->isType('array'), ['id' => 4]);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('delete')
|
||||
->with('pp_shop_transport_payment_methods', ['id_transport' => 4]);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$id = $repository->save([
|
||||
'id' => 4,
|
||||
'name' => 'Update',
|
||||
'status' => 1,
|
||||
'cost' => 5.0,
|
||||
'default' => 0,
|
||||
'delivery_free' => 'on',
|
||||
]);
|
||||
|
||||
$this->assertSame(4, $id);
|
||||
}
|
||||
|
||||
public function testSaveInsertReturnsNullOnFailure(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->method('insert');
|
||||
$mockDb->method('id')->willReturn(null);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$this->assertNull($repository->save([
|
||||
'id' => 0,
|
||||
'name' => 'Fail',
|
||||
]));
|
||||
}
|
||||
|
||||
public function testSaveResetsDefaultWhenSettingNew(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$updateCalls = [];
|
||||
|
||||
$mockDb->method('update')
|
||||
->willReturnCallback(function ($table, $data, $where = null) use (&$updateCalls) {
|
||||
$updateCalls[] = ['table' => $table, 'data' => $data, 'where' => $where];
|
||||
});
|
||||
|
||||
$mockDb->method('delete');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$repository->save([
|
||||
'id' => 2,
|
||||
'name' => 'X',
|
||||
'default' => 'on',
|
||||
'status' => 0,
|
||||
'delivery_free' => 0,
|
||||
]);
|
||||
|
||||
$this->assertCount(2, $updateCalls);
|
||||
$this->assertSame(['default' => 0], $updateCalls[0]['data']);
|
||||
$this->assertNull($updateCalls[0]['where']);
|
||||
}
|
||||
|
||||
public function testSaveSwitchValuesNormalization(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$savedData = null;
|
||||
|
||||
$mockDb->method('update')
|
||||
->willReturnCallback(function ($table, $data) use (&$savedData) {
|
||||
$savedData = $data;
|
||||
});
|
||||
$mockDb->method('delete');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$repository->save([
|
||||
'id' => 1,
|
||||
'name' => 'T',
|
||||
'status' => 'on',
|
||||
'default' => 'true',
|
||||
'delivery_free' => '1',
|
||||
'cost' => 0,
|
||||
]);
|
||||
|
||||
$this->assertSame(1, $savedData['status']);
|
||||
$this->assertSame(1, $savedData['default']);
|
||||
$this->assertSame(1, $savedData['delivery_free']);
|
||||
}
|
||||
|
||||
public function testListForAdminWhitelistsSortColumn(): 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 [[1]]; }
|
||||
};
|
||||
}
|
||||
|
||||
return new class {
|
||||
public function fetchAll() {
|
||||
return [[
|
||||
'id' => 1, 'name' => 'DPD', 'name_visible' => '',
|
||||
'description' => '', 'status' => 1, 'cost' => 10.0,
|
||||
'max_wp' => null, 'default' => 0,
|
||||
'apilo_carrier_account_id' => null, 'delivery_free' => 0, 'o' => 1,
|
||||
]];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$result = $repository->listForAdmin(
|
||||
[],
|
||||
'name DESC; DROP TABLE pp_shop_transports; --',
|
||||
'DESC; DELETE FROM pp_users; --',
|
||||
1,
|
||||
999
|
||||
);
|
||||
|
||||
$this->assertCount(2, $queries);
|
||||
$dataSql = $queries[1]['sql'];
|
||||
|
||||
$this->assertMatchesRegularExpression('/ORDER BY\s+st\.name\s+ASC,\s+st\.id\s+ASC/i', $dataSql);
|
||||
$this->assertStringNotContainsString('DROP TABLE', $dataSql);
|
||||
$this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);
|
||||
}
|
||||
|
||||
public function testAllActiveReturnsNormalizedRows(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('select')
|
||||
->willReturn([
|
||||
[
|
||||
'id' => '2', 'name' => 'InPost', 'status' => '1',
|
||||
'cost' => '9.99', 'max_wp' => '25', 'default' => '1',
|
||||
'delivery_free' => '0', 'apilo_carrier_account_id' => null, 'o' => '1',
|
||||
],
|
||||
]);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$rows = $repository->allActive();
|
||||
|
||||
$this->assertCount(1, $rows);
|
||||
$this->assertSame(2, $rows[0]['id']);
|
||||
$this->assertSame(9.99, $rows[0]['cost']);
|
||||
$this->assertSame(1, $rows[0]['status']);
|
||||
$this->assertSame(1, $rows[0]['default']);
|
||||
}
|
||||
|
||||
public function testGetApiloCarrierAccountIdReturnsNullForInvalidId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->never())->method('get');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$this->assertNull($repository->getApiloCarrierAccountId(0));
|
||||
}
|
||||
|
||||
public function testGetApiloCarrierAccountIdReturnsIntOrNull(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->willReturnOnConsecutiveCalls(null, '55');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$this->assertNull($repository->getApiloCarrierAccountId(1));
|
||||
$this->assertSame(55, $repository->getApiloCarrierAccountId(2));
|
||||
}
|
||||
|
||||
public function testGetTransportCostReturnsFloatOrNull(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->willReturnOnConsecutiveCalls(null, '12.50');
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$this->assertNull($repository->getTransportCost(99));
|
||||
$this->assertSame(12.5, $repository->getTransportCost(1));
|
||||
}
|
||||
|
||||
public function testAllForAdminReturnsAllTransports(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('select')
|
||||
->willReturn([
|
||||
['id' => '1', 'name' => 'A', 'status' => '1', 'cost' => '5', 'max_wp' => null, 'default' => '0', 'delivery_free' => '0', 'apilo_carrier_account_id' => null, 'o' => '1'],
|
||||
['id' => '2', 'name' => 'B', 'status' => '0', 'cost' => '10', 'max_wp' => '50', 'default' => '1', 'delivery_free' => '1', 'apilo_carrier_account_id' => '3', 'o' => '2'],
|
||||
]);
|
||||
|
||||
$repository = new TransportRepository($mockDb);
|
||||
$rows = $repository->allForAdmin();
|
||||
|
||||
$this->assertCount(2, $rows);
|
||||
$this->assertSame(0, $rows[1]['status']);
|
||||
$this->assertSame(1, $rows[1]['default']);
|
||||
$this->assertSame(50, $rows[1]['max_wp']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user