initial project
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Controllers\Backend;
|
||||
|
||||
use App\Controllers\Backend\OutletController;
|
||||
use App\Models\Outlet;
|
||||
use App\Models\OutletTax;
|
||||
use App\Models\OutletImage;
|
||||
use App\Models\OutletOperatingDay;
|
||||
use App\Models\OutletOperatingHour;
|
||||
use App\Models\OutletOperatingHoursException;
|
||||
use App\Models\SettingTax;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
use CodeIgniter\Database\QueryBuilder;
|
||||
use Mockery;
|
||||
use Config\Database as CI4Database;
|
||||
|
||||
|
||||
class OutletTest extends CIUnitTestCase
|
||||
{
|
||||
protected $mockOutlet;
|
||||
protected $mockOutletTax;
|
||||
protected $mockOutletImage;
|
||||
protected $mockOutletOperatingDay;
|
||||
protected $mockOutletOperatingHour;
|
||||
protected $mockOutletOperatingHoursException;
|
||||
protected $mockSettingTax;
|
||||
protected $controller;
|
||||
|
||||
protected function setProtectedOrPrivateProperty($object, $property, $value)
|
||||
{
|
||||
$reflection = new \ReflectionObject($object);
|
||||
while (!$reflection->hasProperty($property)) {
|
||||
$reflection = $reflection->getParentClass();
|
||||
if (!$reflection) {
|
||||
throw new \Exception("Property {$property} does not exist");
|
||||
}
|
||||
}
|
||||
$prop = $reflection->getProperty($property);
|
||||
$prop->setAccessible(true);
|
||||
$prop->setValue($object, $value);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Mockery::close();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->mockOutlet = $this->createMock(Outlet::class);
|
||||
|
||||
$this->mockOutletTax = $this->getMockBuilder(OutletTax::class)
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
|
||||
$this->mockOutletImage = $this->createMock(OutletImage::class);
|
||||
|
||||
$this->mockOutletOperatingDay = $this->getMockBuilder(OutletOperatingDay::class)
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
|
||||
$this->mockOutletOperatingHour = $this->getMockBuilder(OutletOperatingHour::class)
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
|
||||
$this->mockOutletOperatingHoursException = $this->getMockBuilder(OutletOperatingHoursException::class)
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
|
||||
$this->mockSettingTax = $this->createMock(SettingTax::class);
|
||||
|
||||
$this->controller = new OutletController();
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'outlet', $this->mockOutlet);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'outletTax', $this->mockOutletTax);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'outletImage', $this->mockOutletImage);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'outletOperatingDays', $this->mockOutletOperatingDay);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'outletOperatingHours', $this->mockOutletOperatingHour);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'outletOperatingHoursExceptions', $this->mockOutletOperatingHoursException);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'settingTax', $this->mockSettingTax);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->createMock(IncomingRequest::class));
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'response', service('response'));
|
||||
}
|
||||
|
||||
public function testIndexReturnsOutlets()
|
||||
{
|
||||
$outlets = [
|
||||
['id' => 1, 'title' => 'Outlet 1'],
|
||||
['id' => 2, 'title' => 'Outlet 2'],
|
||||
];
|
||||
|
||||
$this->mockOutlet->method('getOperatingHoursWithDaysList')->willReturn($outlets);
|
||||
|
||||
$result = $this->controller->index();
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(200, $data['status']);
|
||||
$this->assertEquals($outlets, $data['result']);
|
||||
}
|
||||
|
||||
public function testIndexReturnsNoOutlets()
|
||||
{
|
||||
$this->mockOutlet->method('getOperatingHoursWithDaysList')->willReturn([]);
|
||||
|
||||
$result = $this->controller->index();
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(400, $data['status']);
|
||||
$this->assertEquals('No outlet data found.', $data['result']);
|
||||
}
|
||||
|
||||
public function testShowReturnsOutlet()
|
||||
{
|
||||
$outlet = ['id' => 1, 'title' => 'Outlet 1'];
|
||||
$this->mockOutlet->method('getOperatingHoursWithDays')->with(1)->willReturn($outlet);
|
||||
|
||||
$result = $this->controller->show(1);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(200, $data['status']);
|
||||
$this->assertEquals($outlet, $data['result']);
|
||||
}
|
||||
|
||||
public function testShowReturnsNotFound()
|
||||
{
|
||||
$this->mockOutlet->method('getOperatingHoursWithDays')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->show(99);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(400, $data['status']);
|
||||
$this->assertEquals('No outlet data found.', $data['result']);
|
||||
}
|
||||
|
||||
public function testDeleteOutletNotFound()
|
||||
{
|
||||
$this->mockOutlet->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->delete(99);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(400, $data['status']);
|
||||
$this->assertEquals('No outlet data found.', $data['result']);
|
||||
}
|
||||
|
||||
public function testDeleteSuccess()
|
||||
{
|
||||
// Create mock builder objects for chainable methods
|
||||
$mockTaxBuilder = $this->getMockBuilder(\CodeIgniter\Database\BaseBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['delete'])
|
||||
->getMock();
|
||||
$mockDayBuilder = $this->getMockBuilder(\CodeIgniter\Database\BaseBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['delete'])
|
||||
->getMock();
|
||||
$mockHourBuilder = $this->getMockBuilder(\CodeIgniter\Database\BaseBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['delete'])
|
||||
->getMock();
|
||||
$mockExceptionBuilder = $this->getMockBuilder(\CodeIgniter\Database\BaseBuilder::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['delete'])
|
||||
->getMock();
|
||||
|
||||
|
||||
$this->mockOutlet->method('find')->with(1)->willReturn(['id' => 1]);
|
||||
$this->mockOutlet->expects($this->once())->method('delete')->with(1);
|
||||
|
||||
// Setup chainable method expectations
|
||||
$this->mockOutletTax->method('where')->with('outlet_id', 1)->willReturn($mockTaxBuilder);
|
||||
$mockTaxBuilder->expects($this->once())->method('delete')->willReturn(true);
|
||||
|
||||
$this->mockOutletOperatingDay->method('where')->with('outlet_id', 1)->willReturn($mockDayBuilder);
|
||||
$mockDayBuilder->expects($this->once())->method('delete')->willReturn(true);
|
||||
|
||||
$this->mockOutletOperatingHour->method('where')->with('outlet_id', 1)->willReturn($mockHourBuilder);
|
||||
$mockHourBuilder->expects($this->once())->method('delete')->willReturn(true);
|
||||
|
||||
$this->mockOutletOperatingHoursException->method('where')->with('outlet_id', 1)->willReturn($mockExceptionBuilder);
|
||||
$mockExceptionBuilder->expects($this->once())->method('delete')->willReturn(true);
|
||||
|
||||
$result = $this->controller->delete(1);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(200, $data['status']);
|
||||
$this->assertEquals('Outlet deleted successfully.', $data['result']);
|
||||
}
|
||||
|
||||
public function testUpdatePasswordOutletNotFound()
|
||||
{
|
||||
$this->mockOutlet->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->updatePassword(99);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(400, $data['status']);
|
||||
$this->assertEquals('No outlet data found.', $data['result']);
|
||||
}
|
||||
|
||||
public function testCreateValidationFails()
|
||||
{
|
||||
$controller = $this->getMockBuilder(OutletController::class)
|
||||
->onlyMethods(['validate'])
|
||||
->enableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$controller->method('validate')->willReturn(false);
|
||||
|
||||
$validator = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$validator->method('getErrors')->willReturn(['title' => 'Required']);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($controller, 'validator', $validator);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outlet', $this->mockOutlet);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletTax', $this->mockOutletTax);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletImage', $this->mockOutletImage);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingDays', $this->mockOutletOperatingDay);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingHours', $this->mockOutletOperatingHour);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingHoursExceptions', $this->mockOutletOperatingHoursException);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'settingTax', $this->mockSettingTax);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $this->createMock(IncomingRequest::class));
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', service('response'));
|
||||
|
||||
$result = $controller->create();
|
||||
$this->assertEquals(400, $result->getStatusCode()); // 400 is CodeIgniter's default
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('messages', $data);
|
||||
$this->assertArrayHasKey('title', $data['messages']);
|
||||
|
||||
}
|
||||
|
||||
public function testCreateSuccess()
|
||||
{
|
||||
// 1. Mock IncomingRequest
|
||||
$request = $this->createMock(\CodeIgniter\HTTP\IncomingRequest::class);
|
||||
$request->method('getVar')->willReturnMap([
|
||||
['title', 'Outlet 1'],
|
||||
['email', 'outlet1@example.com'],
|
||||
['phone', '123456789'],
|
||||
['address', '123 Street'],
|
||||
['state', 'State'],
|
||||
['postal_code', '12345'],
|
||||
['country', 'Country'],
|
||||
['latitude', '1.234'],
|
||||
['longitude', '5.678'],
|
||||
['password', 'password'],
|
||||
['outlet_delivery_coverage', '10'],
|
||||
['outlet_tax', json_encode([1, 2])],
|
||||
['outlet_operating_days', json_encode([['0' => ['is_operated' => 1]]])],
|
||||
['outlet_operating_hours', json_encode([['0' => [['start_time' => '09:00', 'end_time' => '18:00']]]])],
|
||||
['outlet_operating_hours_exceptions', json_encode([])],
|
||||
]);
|
||||
$request->method('getFiles')->willReturn([]);
|
||||
|
||||
// 2. Mock Controller with validate() overridden
|
||||
$controller = $this->getMockBuilder(\App\Controllers\Backend\OutletController::class)
|
||||
->onlyMethods(['validate'])
|
||||
->getMock();
|
||||
|
||||
$controller->method('validate')->willReturn(true);
|
||||
|
||||
// 3. Mock all Models and insert returns
|
||||
$mockOutlet = $this->createMock(\App\Models\Outlet::class);
|
||||
$mockOutlet->method('insert')->willReturn(1);
|
||||
$mockOutlet->method('find')->willReturn(['id' => 1, 'title' => 'Outlet 1']);
|
||||
|
||||
$mockOutletTax = $this->createMock(\App\Models\OutletTax::class);
|
||||
$mockOutletTax->method('insert')->willReturn(true);
|
||||
|
||||
$mockOutletOperatingDay = $this->createMock(\App\Models\OutletOperatingDay::class);
|
||||
$mockOutletOperatingDay->method('insert')->willReturn(true);
|
||||
|
||||
$mockOutletOperatingHour = $this->createMock(\App\Models\OutletOperatingHour::class);
|
||||
$mockOutletOperatingHour->method('insert')->willReturn(true);
|
||||
|
||||
$mockOutletOperatingHoursException = $this->createMock(\App\Models\OutletOperatingHoursException::class);
|
||||
$mockOutletOperatingHoursException->method('insert')->willReturn(true);
|
||||
|
||||
$mockOutletImage = $this->createMock(\App\Models\OutletImage::class);
|
||||
$mockSettingTax = $this->createMock(\App\Models\SettingTax::class);
|
||||
|
||||
// 4. Mock DB transaction flow
|
||||
// Mock global DB connection
|
||||
$mockDB = Mockery::mock(\CodeIgniter\Database\BaseConnection::class);
|
||||
$mockDB->shouldReceive('transBegin')->andReturn(true);
|
||||
$mockDB->shouldReceive('transCommit')->andReturn(true);
|
||||
$mockDB->shouldReceive('transRollback')->andReturn(true);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($controller, 'db', $mockDB);
|
||||
|
||||
// 5. Inject all mocked dependencies
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $request);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outlet', $mockOutlet);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletTax', $mockOutletTax);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletImage', $mockOutletImage);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingDays', $mockOutletOperatingDay);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingHours', $mockOutletOperatingHour);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingHoursExceptions', $mockOutletOperatingHoursException);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'settingTax', $mockSettingTax);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', service('response'));
|
||||
$this->setProtectedOrPrivateProperty($controller, 'db', $mockDB);
|
||||
|
||||
// 6. Call the method
|
||||
$response = $controller->create();
|
||||
|
||||
// 7. Assert response
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$data = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('success', $data['status']);
|
||||
$this->assertArrayHasKey('result', $data);
|
||||
$this->assertEquals('Outlet 1', $data['result']['title']);
|
||||
}
|
||||
|
||||
|
||||
public function testUpdateValidationFails()
|
||||
{
|
||||
// Create controller mock that allows original validateData method to be called
|
||||
$controller = $this->getMockBuilder(OutletController::class)
|
||||
->onlyMethods([]) // Don't mock any methods - we want real validateData behavior
|
||||
->enableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
// Create a proper validator mock
|
||||
$validator = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$validator->method('getErrors')->willReturn([
|
||||
'title' => 'The title field is required.',
|
||||
'email' => 'The email field is required.',
|
||||
'phone' => 'The phone field is required.',
|
||||
'address' => 'The address field is required.',
|
||||
'state' => 'The state field is required.',
|
||||
'postal_code' => 'The postal_code field is required.',
|
||||
'country' => 'The country field is required.',
|
||||
'latitude' => 'The latitude field is required.',
|
||||
'longitude' => 'The longitude field is required.',
|
||||
'outlet_delivery_coverage' => 'The outlet_delivery_coverage field is required.',
|
||||
'outlet_tax' => 'The outlet_tax field is required.',
|
||||
'outlet_operating_days' => 'The outlet_operating_days field is required.',
|
||||
'outlet_operating_hours' => 'The outlet_operating_hours field is required.',
|
||||
]);
|
||||
|
||||
// Create request mock with invalid data
|
||||
$mockRequest = $this->getMockBuilder(IncomingRequest::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$invalidData = [
|
||||
'title' => '',
|
||||
'email' => 'invalid-email',
|
||||
'phone' => '3o4i234234',
|
||||
'address' => 'dfdgdgdgerfsd',
|
||||
'state' => 'Fkdfnskf',
|
||||
'postal_code' => 'fsdf',
|
||||
'country' => 'fsdfsd',
|
||||
'latitude' => 'not-number',
|
||||
'longitude' => 'not-number',
|
||||
'outlet_delivery_coverage' => 'not-number',
|
||||
'outlet_tax' => 'sdfsdfs',
|
||||
'outlet_operating_days' => 'sfsfsd',
|
||||
'outlet_operating_hours' => 'dsfsdfds',
|
||||
'outlet_operating_hours_exceptions' => null,
|
||||
'outlet_images' => null
|
||||
];
|
||||
|
||||
// Fix: getVar() must return full array when called with no argument
|
||||
$mockRequest->method('getVar')
|
||||
->willReturnCallback(function ($key = null) use ($invalidData) {
|
||||
if ($key === null) {
|
||||
return $invalidData; // full array for validateData()
|
||||
}
|
||||
return $invalidData[$key] ?? null; // or specific key
|
||||
});
|
||||
|
||||
// getJSON fallback (optional - may not be used in controller)
|
||||
$mockRequest->method('getJSON')
|
||||
->willReturn($invalidData);
|
||||
|
||||
// Inject our mocks
|
||||
$this->setProtectedOrPrivateProperty($controller, 'validator', $validator);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outlet', $this->mockOutlet);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletTax', $this->mockOutletTax);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletImage', $this->mockOutletImage);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingDays', $this->mockOutletOperatingDay);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingHours', $this->mockOutletOperatingHour);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'outletOperatingHoursExceptions', $this->mockOutletOperatingHoursException);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'settingTax', $this->mockSettingTax);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $mockRequest);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', service('response'));
|
||||
|
||||
// Mock outlet exists
|
||||
$this->mockOutlet->method('find')->with(1)->willReturn(['id' => 1]);
|
||||
|
||||
// Call the update method
|
||||
$result = $controller->update(1);
|
||||
|
||||
// Assertions
|
||||
$this->assertEquals(400, $result->getStatusCode());
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertEquals('400', $data['status']);
|
||||
// $this->assertArrayHasKey('message', $data);
|
||||
// $this->assertEquals('The title field is required.', $data['message']);
|
||||
}
|
||||
|
||||
|
||||
public function testUpdateOutletNotFound()
|
||||
{
|
||||
$this->mockOutlet->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->update(99);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertEquals(400, $data['status']);
|
||||
$this->assertEquals('No outlet data found.', $data['result']);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user