initial project
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use App\Services\CalculateService;
|
||||
use App\Services\PromoService;
|
||||
|
||||
class CalculateServiceTest extends CIUnitTestCase
|
||||
{
|
||||
protected $calculateService;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Mock PromoService for testing
|
||||
/** @var PromoService $promoService */
|
||||
$promoService = $this->createMock(PromoService::class);
|
||||
$this->calculateService = new CalculateService($promoService);
|
||||
}
|
||||
|
||||
public function testCalculateDeliveryFee()
|
||||
{
|
||||
// Test cases for delivery fee calculation
|
||||
$testCases = [
|
||||
['distance' => 0, 'expected' => 0.00],
|
||||
['distance' => 2.5, 'expected' => 5.00], // Below 5 km: RM 5
|
||||
['distance' => 5.0, 'expected' => 7.00], // 5-6.99 km: RM 7
|
||||
['distance' => 6.99, 'expected' => 7.00], // 5-6.99 km: RM 7
|
||||
['distance' => 7.0, 'expected' => 12.00], // 7-12.99 km: RM 12
|
||||
['distance' => 10.5, 'expected' => 12.00], // 7-12.99 km: RM 12
|
||||
['distance' => 12.99, 'expected' => 12.00], // 7-12.99 km: RM 12
|
||||
['distance' => 13.0, 'expected' => 15.00], // 13-20 km: RM 15
|
||||
['distance' => 16.5, 'expected' => 15.00], // 13-20 km: RM 15
|
||||
['distance' => 20.0, 'expected' => 15.00], // 13-20 km: RM 15
|
||||
['distance' => 22.0, 'expected' => 17.00], // Above 20 km: +RM 2 for every 5 km
|
||||
['distance' => 25.0, 'expected' => 17.00], // Above 20 km: +RM 2 for every 5 km
|
||||
['distance' => 27.0, 'expected' => 19.00], // Above 20 km: +RM 2 for every 5 km
|
||||
['distance' => 30.0, 'expected' => 19.00], // Above 20 km: +RM 2 for every 5 km
|
||||
];
|
||||
|
||||
foreach ($testCases as $testCase) {
|
||||
$result = $this->calculateService->calculateDeliveryFee($testCase['distance']);
|
||||
$this->assertEquals(
|
||||
$testCase['expected'],
|
||||
$result,
|
||||
"Distance: {$testCase['distance']} km should cost RM {$testCase['expected']}, but got RM {$result}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCalculateDeliveryFeeWithInvalidInput()
|
||||
{
|
||||
// Test invalid inputs
|
||||
$invalidInputs = [
|
||||
-5.0, // Negative distance
|
||||
'invalid', // String
|
||||
null, // Null
|
||||
[], // Array
|
||||
true, // Boolean
|
||||
];
|
||||
|
||||
foreach ($invalidInputs as $invalidInput) {
|
||||
$result = $this->calculateService->calculateDeliveryFee($invalidInput);
|
||||
$this->assertEquals(0, $result, "Invalid input '{$invalidInput}' should return 0");
|
||||
}
|
||||
}
|
||||
|
||||
public function testCalculateDistanceWithInvalidInput()
|
||||
{
|
||||
// Test invalid outlet ID
|
||||
$result = $this->calculateService->calculateDistance('invalid', 3.123, 101.654);
|
||||
$this->assertEquals(0, $result, 'Invalid outlet ID should return 0');
|
||||
|
||||
// Test invalid coordinates
|
||||
$result = $this->calculateService->calculateDistance(1, 'invalid_lat', 101.654);
|
||||
$this->assertEquals(0, $result, 'Invalid latitude should return 0');
|
||||
|
||||
$result = $this->calculateService->calculateDistance(1, 3.123, 'invalid_lng');
|
||||
$this->assertEquals(0, $result, 'Invalid longitude should return 0');
|
||||
|
||||
// Test out of range coordinates
|
||||
$result = $this->calculateService->calculateDistance(1, 100.0, 101.654); // Latitude > 90
|
||||
$this->assertEquals(0, $result, 'Latitude > 90 should return 0');
|
||||
|
||||
$result = $this->calculateService->calculateDistance(1, 3.123, 200.0); // Longitude > 180
|
||||
$this->assertEquals(0, $result, 'Longitude > 180 should return 0');
|
||||
}
|
||||
|
||||
public function testDeliveryFeeCalculationLogic()
|
||||
{
|
||||
// Test edge cases around the boundaries
|
||||
$this->assertEquals(5.00, $this->calculateService->calculateDeliveryFee(4.99), '4.99 km should be RM 5');
|
||||
$this->assertEquals(7.00, $this->calculateService->calculateDeliveryFee(5.00), '5.00 km should be RM 7');
|
||||
$this->assertEquals(7.00, $this->calculateService->calculateDeliveryFee(6.99), '6.99 km should be RM 7');
|
||||
$this->assertEquals(12.00, $this->calculateService->calculateDeliveryFee(7.00), '7.00 km should be RM 12');
|
||||
$this->assertEquals(12.00, $this->calculateService->calculateDeliveryFee(12.99), '12.99 km should be RM 12');
|
||||
$this->assertEquals(15.00, $this->calculateService->calculateDeliveryFee(13.00), '13.00 km should be RM 15');
|
||||
$this->assertEquals(15.00, $this->calculateService->calculateDeliveryFee(20.00), '20.00 km should be RM 15');
|
||||
$this->assertEquals(17.00, $this->calculateService->calculateDeliveryFee(21.00), '21.00 km should be RM 17');
|
||||
$this->assertEquals(17.00, $this->calculateService->calculateDeliveryFee(24.99), '24.99 km should be RM 17');
|
||||
$this->assertEquals(19.00, $this->calculateService->calculateDeliveryFee(25.00), '25.00 km should be RM 19');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,832 @@
|
||||
<?php
|
||||
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use App\Controllers\CustomerController;
|
||||
use App\Models\Customer;
|
||||
use App\Models\CustomerAddress;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
// use App\Controllers\Backend\CustomerController;
|
||||
|
||||
class CustomerAddressTest extends CIUnitTestCase
|
||||
{
|
||||
protected $controller;
|
||||
protected $request;
|
||||
protected $customerModelMock;
|
||||
protected $customerAddressModelMock;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->controller = new \App\Controllers\Backend\CustomerController();
|
||||
$this->controller->initController(
|
||||
service('request'),
|
||||
service('response'),
|
||||
service('logger')
|
||||
);
|
||||
|
||||
$this->request = $this->createMock(IncomingRequest::class);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request);
|
||||
|
||||
// Create and inject model mocks
|
||||
$this->customerModelMock = $this->createMock(\App\Models\Customer::class);
|
||||
$this->customerAddressModelMock = $this->createMock(\App\Models\CustomerAddress::class);
|
||||
\Config\Services::injectMock('customer', $this->customerModelMock);
|
||||
\Config\Services::injectMock('customeraddress', $this->customerAddressModelMock);
|
||||
|
||||
}
|
||||
|
||||
protected function setProtectedOrPrivateProperty($object, $property, $value)
|
||||
{
|
||||
$reflection = new \ReflectionObject($object);
|
||||
while (!$reflection->hasProperty($property)) {
|
||||
$reflection = $reflection->getParentClass();
|
||||
}
|
||||
$prop = $reflection->getProperty($property);
|
||||
$prop->setAccessible(true);
|
||||
$prop->setValue($object, $value);
|
||||
}
|
||||
|
||||
public function testCreateCustomerAddressReturnsIfCustomerIdMissing()
|
||||
{
|
||||
$response = $this->controller->createCustomerAddress();
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$json = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('error', $json['status']);
|
||||
$this->assertEquals('Customer ID is required.', $json['message']);
|
||||
|
||||
}
|
||||
|
||||
public function testCreateCustomerAddressReturnsIfCustomerNotFound()
|
||||
{
|
||||
$mockCustomerModel = $this->getMockBuilder(Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
|
||||
$response = $this->controller->createCustomerAddress(1);
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('error', $json['status']);
|
||||
$this->assertEquals('Customer with ID 1 not found or not active.', $json['message']);
|
||||
|
||||
}
|
||||
|
||||
public function testCreateCustomerAddressReturnsOnSuccess()
|
||||
{
|
||||
$mockCustomerModel = $this->getMockBuilder(Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn(['id' => 1, 'status' => 'active']);
|
||||
|
||||
$mockCustomerAddressModel = $this->getMockBuilder(CustomerAddress::class)
|
||||
->onlyMethods(['set', 'update', 'insert'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerAddressModel->method('where')->willReturnSelf();
|
||||
$mockCustomerAddressModel->method('set')->willReturnSelf();
|
||||
$mockCustomerAddressModel->method('update')->willReturn(true);
|
||||
$mockCustomerAddressModel->method('insert')->willReturn(true);
|
||||
|
||||
$mockRequest = $this->createMock(IncomingRequest::class);
|
||||
$mockRequest->method('getVar')->willReturnMap([
|
||||
['name', null, 'John'],
|
||||
['phone', null, '123456789'],
|
||||
['address', null, '123 Main St'],
|
||||
['unit', null, 'Unit 5'],
|
||||
['note', null, 'Test note'],
|
||||
]);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $mockRequest);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
|
||||
$response = $this->controller->createCustomerAddress(1);
|
||||
$this->assertEquals(201, $response->getStatusCode());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('success', $json['status']);
|
||||
$this->assertEquals('Customer address created successfully.', $json['message']);
|
||||
}
|
||||
|
||||
public function testCreateCustomerAddressReturnsOnInsertFailure()
|
||||
{
|
||||
$mockCustomerModel = $this->getMockBuilder(Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn(['id' => 1, 'status' => 'active']);
|
||||
|
||||
$mockCustomerAddressModel = $this->getMockBuilder(CustomerAddress::class)
|
||||
->onlyMethods(['set', 'update', 'insert'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerAddressModel->method('where')->willReturnSelf();
|
||||
$mockCustomerAddressModel->method('set')->willReturnSelf();
|
||||
$mockCustomerAddressModel->method('update')->willReturn(true);
|
||||
$mockCustomerAddressModel->method('insert')->willReturn(false);
|
||||
|
||||
$mockRequest = $this->createMock(IncomingRequest::class);
|
||||
$mockRequest->method('getVar')->willReturn('Some value');
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $mockRequest);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
|
||||
|
||||
$response = $this->controller->createCustomerAddress(1);
|
||||
$this->assertEquals(500, $response->getStatusCode());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('error', $json['status']);
|
||||
$this->assertEquals('Failed to create customer address.', $json['message']);
|
||||
}
|
||||
|
||||
public function testCustomerAddressIndexReturnsMultipleAddresses()
|
||||
{
|
||||
// Arrange: Prepare a list of 2 fake addresses
|
||||
$fakeAddresses = [
|
||||
[
|
||||
'id' => 1,
|
||||
'customer_id' => 1,
|
||||
'name' => 'Home',
|
||||
'phone' => '0123456789',
|
||||
'address' => '123 Test Street',
|
||||
'unit' => 'A-1-1',
|
||||
'note' => 'Ring bell twice',
|
||||
'is_default' => 1,
|
||||
'created_at' => '2025-07-30 10:00:00',
|
||||
'updated_at' => '2025-07-30 10:00:00',
|
||||
'deleted_at' => null,
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'customer_id' => 1,
|
||||
'name' => 'Office',
|
||||
'phone' => '0987654321',
|
||||
'address' => '456 Work Avenue',
|
||||
'unit' => 'B-2-2',
|
||||
'note' => 'Reception 3rd floor',
|
||||
'is_default' => 0,
|
||||
'created_at' => '2025-07-30 11:00:00',
|
||||
'updated_at' => '2025-07-30 11:00:00',
|
||||
'deleted_at' => null,
|
||||
],
|
||||
];
|
||||
|
||||
// Create a mock for CustomerAddress model
|
||||
$mockCustomerAddressModel = $this->createMock(\App\Models\CustomerAddress::class);
|
||||
$mockCustomerAddressModel
|
||||
->expects($this->once())
|
||||
->method('findAll')
|
||||
->willReturn($fakeAddresses);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
|
||||
$response = $this->controller->customerAddressIndex();
|
||||
|
||||
|
||||
$this->assertIsObject($response);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
$decoded = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals('success', $decoded['status']);
|
||||
$this->assertEquals('Customer addresses retrieved successfully.', $decoded['message']);
|
||||
$this->assertCount(2, $decoded['data']); // Ensure two addresses
|
||||
$this->assertEquals($fakeAddresses, $decoded['data']);
|
||||
}
|
||||
|
||||
public function testShowCustomerAddressSuccess()
|
||||
{
|
||||
$addressData = [
|
||||
'id' => 1,
|
||||
'customer_id' => 101,
|
||||
'name' => 'Home',
|
||||
'phone' => '0123456789',
|
||||
'address' => '123 Main St',
|
||||
'unit' => 'A-1-1',
|
||||
'note' => 'Main house',
|
||||
'is_default' => 1,
|
||||
];
|
||||
|
||||
$mockCustomerAddressModel = $this->createMock(CustomerAddress::class);
|
||||
$mockCustomerAddressModel->method('find')->with(1)->willReturn($addressData);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
|
||||
$response = $this->controller->showCustomerAddress(1);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Customer address retrieved successfully', $response->getBody());
|
||||
}
|
||||
|
||||
public function testShowCustomerAddressNotFound()
|
||||
{
|
||||
$mockCustomerAddressModel = $this->createMock(CustomerAddress::class);
|
||||
$mockCustomerAddressModel->method('find')->with(999)->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
|
||||
$response = $this->controller->showCustomerAddress(999);
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$this->assertStringContainsString('not found', $response->getBody());
|
||||
}
|
||||
|
||||
public function testShowCustomerAddressMissingId()
|
||||
{
|
||||
$this->controller = new \App\Controllers\Backend\CustomerController();
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'response', \Config\Services::response());
|
||||
|
||||
$response = $this->controller->showCustomerAddress(null);
|
||||
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Address ID is required', $response->getBody());
|
||||
}
|
||||
|
||||
public function testShowAddressesByCustomerSuccess()
|
||||
{
|
||||
$mockModel = $this->getMockBuilder(CustomerAddress::class)
|
||||
->onlyMethods(['findAll'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mockModel->method('where')->with('customer_id', 101)->willReturnSelf();
|
||||
$mockModel->method('findAll')->willReturn([
|
||||
['id' => 1, 'customer_id' => 101, 'address' => '123 Main St'],
|
||||
['id' => 2, 'customer_id' => 101, 'address' => '456 Side St']
|
||||
]);
|
||||
|
||||
// $this->controller = new CustomerController();
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockModel);
|
||||
|
||||
$response = $this->controller->showAddressesByCustomer(101);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Customer addresses retrieved successfully', $response->getBody());
|
||||
}
|
||||
|
||||
public function testShowAddressesByCustomerEmpty()
|
||||
{
|
||||
$mockModel = $this->getMockBuilder(CustomerAddress::class)
|
||||
->onlyMethods(['findAll'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mockModel->method('where')->with('customer_id', 999)->willReturnSelf();
|
||||
$mockModel->method('findAll')->willReturn([]);
|
||||
|
||||
// $this->controller = new CustomerController();
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockModel);
|
||||
|
||||
$response = $this->controller->showAddressesByCustomer(999);
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$this->assertStringContainsString('No addresses found', $response->getBody());
|
||||
}
|
||||
|
||||
public function testShowAddressesByCustomerMissingId()
|
||||
{
|
||||
$this->controller = new \App\Controllers\Backend\CustomerController();
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'response', \Config\Services::response());
|
||||
|
||||
$response = $this->controller->showAddressesByCustomer(null);
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Customer ID is required', $response->getBody());
|
||||
}
|
||||
|
||||
public function testUpdateCustomerAddressMissingId()
|
||||
{
|
||||
$result = $this->controller->updateCustomerAddress(null);
|
||||
$this->assertEquals(422, $result->getStatusCode());
|
||||
$this->assertStringContainsString('Address ID is required', $result->getJSON());
|
||||
}
|
||||
|
||||
public function testUpdateCustomerAddressInvalidId()
|
||||
{
|
||||
// Mock CustomerAddress model where 'find' returns null
|
||||
$mockAddressModel = $this->createMock(CustomerAddress::class);
|
||||
$mockAddressModel->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockAddressModel);
|
||||
|
||||
// Customer model might still be called depending on controller flow — mock it
|
||||
$mockCustomerModel = $this->createMock(Customer::class);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
|
||||
$result = $this->controller->updateCustomerAddress(99);
|
||||
|
||||
$this->assertEquals(404, $result->getStatusCode());
|
||||
$this->assertStringContainsString('not found', $result->getBody());
|
||||
}
|
||||
|
||||
|
||||
public function testUpdateCustomerAddressCustomerNotFound()
|
||||
{
|
||||
$mockAddressModel = $this->getMockBuilder(CustomerAddress::class)
|
||||
->onlyMethods(['find'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockAddressModel->method('find')->willReturn(['customer_id' => 5]);
|
||||
|
||||
$mockCustomerModel = $this->getMockBuilder(Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockAddressModel);
|
||||
|
||||
$result = $this->controller->updateCustomerAddress(1);
|
||||
$this->assertEquals(404, $result->getStatusCode());
|
||||
$this->assertStringContainsString('Customer not found', $result->getJSON());
|
||||
}
|
||||
|
||||
|
||||
public function testUpdateCustomerAddressValidationFail()
|
||||
{
|
||||
$mockAddressModel = $this->createMock(CustomerAddress::class);
|
||||
$mockAddressModel->method('find')->willReturn(['customer_id' => 1]);
|
||||
|
||||
$mockCustomerModel = $this->getMockBuilder(Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn(['id' => 1, 'status' => 'active']);
|
||||
|
||||
// Inject into controller directly
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockAddressModel);
|
||||
|
||||
// Mock request object
|
||||
$request = \Config\Services::request();
|
||||
$request->setGlobal('post', [
|
||||
'name' => '', // validation fail
|
||||
'phone' => '',
|
||||
'address' => '',
|
||||
'is_default' => ''
|
||||
]);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $request);
|
||||
|
||||
$result = $this->controller->updateCustomerAddress(1);
|
||||
$this->assertEquals(422, $result->getStatusCode());
|
||||
$this->assertStringContainsString('Validation failed', $result->getJSON());
|
||||
}
|
||||
|
||||
public function testUpdateCustomerAddressSuccess()
|
||||
{
|
||||
$addressId = 1;
|
||||
|
||||
$existingAddress = [
|
||||
'id' => $addressId,
|
||||
'customer_id' => 1,
|
||||
'name' => 'Old Address Name',
|
||||
'phone' => '0123456789',
|
||||
'address' => 'Old Street',
|
||||
'unit' => 'B-2-3',
|
||||
'note' => 'Old note',
|
||||
'is_default' => 0,
|
||||
];
|
||||
|
||||
$mockCustomerAddressModel = $this->getMockBuilder(\App\Models\CustomerAddress::class)
|
||||
->onlyMethods(['find', 'update', 'set'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerAddressModel->method('find')->with($addressId)->willReturn($existingAddress);
|
||||
$mockCustomerAddressModel->method('update')->willReturn(true);
|
||||
$mockCustomerAddressModel->method('where')->willReturnSelf(); // For setting others to is_default = 0
|
||||
$mockCustomerAddressModel->method('set')->willReturnSelf();
|
||||
|
||||
// Mock Customer model
|
||||
$mockCustomerModel = $this->getMockBuilder(\App\Models\Customer::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn([
|
||||
'id' => 1,
|
||||
'name' => 'Test Customer',
|
||||
'status' => 'active',
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
|
||||
// Simulate POST data
|
||||
$mockRequest = $this->getMockBuilder(IncomingRequest::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getVar', 'getMethod'])
|
||||
->getMock();
|
||||
|
||||
$mockRequest->method('getVar')->willReturnCallback(function ($key = null) {
|
||||
$data = [
|
||||
'name' => 'Updated Address Name',
|
||||
'phone' => '0199999999',
|
||||
'address' => 'New Street',
|
||||
'unit' => 'A-1-1',
|
||||
'note' => 'New note',
|
||||
'is_default' => 1,
|
||||
'customer_id' => 1,
|
||||
];
|
||||
return $key ? ($data[$key] ?? null) : $data;
|
||||
});
|
||||
|
||||
$mockRequest->method('getMethod')->willReturn('post');
|
||||
|
||||
// Validation mock
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
// Create controller and inject dependencies
|
||||
$controller = new \App\Controllers\Backend\CustomerController();
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $mockRequest);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', \Config\Services::response());
|
||||
|
||||
// Run the controller method
|
||||
$response = $controller->updateCustomerAddress($addressId);
|
||||
|
||||
$statusCode = $response->getStatusCode();
|
||||
$body = $response->getBody();
|
||||
|
||||
// var_dump($statusCode);
|
||||
// var_dump($body);
|
||||
|
||||
// Assert the response
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
$decodedBody = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('success', $decodedBody['status']);
|
||||
$this->assertEquals('Customer address updated successfully.', $decodedBody['message']);
|
||||
}
|
||||
|
||||
|
||||
public function testUpdateCustomerAddressFailsToSave()
|
||||
{
|
||||
$addressId = 1;
|
||||
|
||||
$existingAddress = [
|
||||
'id' => $addressId,
|
||||
'customer_id' => 1,
|
||||
'name' => 'Old Address Name',
|
||||
'phone' => '0123456789',
|
||||
'address' => 'Old Street',
|
||||
'unit' => 'B-2-3',
|
||||
'note' => 'Old note',
|
||||
'is_default' => 0,
|
||||
];
|
||||
|
||||
$mockCustomerAddressModel = $this->getMockBuilder(\App\Models\CustomerAddress::class)
|
||||
->onlyMethods(['find', 'update', 'set'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerAddressModel->method('find')->with($addressId)->willReturn($existingAddress);
|
||||
$mockCustomerAddressModel->method('update')->willReturn(false); // Simulate update failure
|
||||
$mockCustomerAddressModel->method('where')->willReturnSelf();
|
||||
$mockCustomerAddressModel->method('set')->willReturnSelf();
|
||||
|
||||
$mockCustomerModel = $this->getMockBuilder(\App\Models\Customer::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['where'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mockCustomerModel->method('where')->willReturnSelf();
|
||||
$mockCustomerModel->method('first')->willReturn([
|
||||
'id' => 1,
|
||||
'name' => 'Test Customer',
|
||||
'status' => 'active',
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
|
||||
$mockRequest = $this->getMockBuilder(IncomingRequest::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getVar', 'getMethod'])
|
||||
->getMock();
|
||||
|
||||
$mockRequest->method('getVar')->willReturnCallback(function ($key = null) {
|
||||
$data = [
|
||||
'name' => 'Updated Address Name',
|
||||
'phone' => '0199999999',
|
||||
'address' => 'New Street',
|
||||
'unit' => 'A-1-1',
|
||||
'note' => 'New note',
|
||||
'is_default' => 1,
|
||||
'customer_id' => 1,
|
||||
];
|
||||
return $key ? ($data[$key] ?? null) : $data;
|
||||
});
|
||||
|
||||
$mockRequest->method('getMethod')->willReturn('post');
|
||||
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
$controller = new \App\Controllers\Backend\CustomerController();
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $mockRequest);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', \Config\Services::response());
|
||||
|
||||
$response = $controller->updateCustomerAddress($addressId);
|
||||
|
||||
$this->assertSame(500, $response->getStatusCode());
|
||||
|
||||
$decoded = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('error', $decoded['status']);
|
||||
$this->assertEquals('Failed to update customer address.', $decoded['message']);
|
||||
|
||||
}
|
||||
|
||||
public function testDeleteCustomerAddressMissingId()
|
||||
{
|
||||
$response = $this->controller->deleteCustomerAddress(null);
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$this->assertStringContainsString('ID is required', $response->getJSON());
|
||||
}
|
||||
|
||||
public function testDeleteCustomerAddressNotFound()
|
||||
{
|
||||
$mockCustomerAddressModel = $this->getMockBuilder(\App\Models\CustomerAddress::class)
|
||||
->onlyMethods(['find'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mockCustomerAddressModel->method('find')->willReturn(null);
|
||||
|
||||
// Inject mock into private property
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mockCustomerAddressModel);
|
||||
|
||||
// Call the method and assert response
|
||||
$response = $this->controller->deleteCustomerAddress(999);
|
||||
|
||||
|
||||
// Assert
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$decodedBody = json_decode($response->getBody(), true);
|
||||
$this->assertEquals('error', $decodedBody['status']);
|
||||
$this->assertEquals('Customer address with ID 999 not found.', $decodedBody['message']);
|
||||
}
|
||||
|
||||
public function testDeleteCustomerAddressSuccessNonDefault()
|
||||
{
|
||||
$addressId = 1;
|
||||
$address = [
|
||||
'id' => $addressId,
|
||||
'customer_id' => 1,
|
||||
'is_default' => 0,
|
||||
];
|
||||
|
||||
$mock = $this->createMock(CustomerAddress::class);
|
||||
$mock->method('find')->with($addressId)->willReturn($address);
|
||||
$mock->method('delete')->with($addressId)->willReturn(true);
|
||||
|
||||
// Inject mock using reflection
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mock);
|
||||
|
||||
$response = $this->controller->deleteCustomerAddress($addressId);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertStringContainsString('deleted successfully', $response->getJSON());
|
||||
}
|
||||
|
||||
public function testDeleteCustomerAddressSuccessDefault()
|
||||
{
|
||||
$addressId = 1;
|
||||
$customerId = 101;
|
||||
$defaultAddress = [
|
||||
'id' => $addressId,
|
||||
'customer_id' => $customerId,
|
||||
'is_default' => 1,
|
||||
];
|
||||
|
||||
$anotherAddress = [
|
||||
'id' => 2,
|
||||
'customer_id' => $customerId,
|
||||
'is_default' => 0,
|
||||
];
|
||||
|
||||
$mock = $this->getMockBuilder(CustomerAddress::class)
|
||||
->onlyMethods(['find', 'delete', 'first', 'update'])
|
||||
->addMethods(['where', 'orderBy'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mock->method('find')->with($addressId)->willReturn($defaultAddress);
|
||||
$mock->method('delete')->with($addressId)->willReturn(true);
|
||||
$mock->method('where')->willReturnSelf();
|
||||
$mock->method('orderBy')->willReturnSelf();
|
||||
$mock->method('first')->willReturn($anotherAddress);
|
||||
$mock->method('update')->with($anotherAddress['id'], ['is_default' => 1])->willReturn(true);
|
||||
|
||||
// Inject mock using reflection
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mock);
|
||||
|
||||
|
||||
$response = $this->controller->deleteCustomerAddress($addressId);
|
||||
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertStringContainsString('deleted successfully', $response->getJSON());
|
||||
}
|
||||
|
||||
|
||||
public function testDeleteCustomerAddressFailsToDelete()
|
||||
{
|
||||
$addressId = 1;
|
||||
$address = [
|
||||
'id' => $addressId,
|
||||
'customer_id' => 1,
|
||||
'is_default' => 0,
|
||||
];
|
||||
|
||||
$mock = $this->createMock(CustomerAddress::class);
|
||||
$mock->method('find')->with($addressId)->willReturn($address);
|
||||
$mock->method('delete')->with($addressId)->willReturn(false);
|
||||
|
||||
// Inject mock using reflection
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $mock);
|
||||
|
||||
$response = $this->controller->deleteCustomerAddress($addressId);
|
||||
$this->assertEquals(500, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Failed to delete', $response->getJSON());
|
||||
}
|
||||
|
||||
|
||||
public function testSetDefaultCustomerAddressSuccess()
|
||||
{
|
||||
$customerId = 123;
|
||||
$addressId = 456;
|
||||
|
||||
// Mock request
|
||||
$this->request->method('getVar')->with('customer_id')->willReturn($customerId);
|
||||
|
||||
$this->customerModelMock = $this->getMockBuilder(\App\Models\Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->customerModelMock->method('where')->willReturnSelf();
|
||||
$this->customerModelMock->method('first')->willReturn([
|
||||
'id' => $customerId,
|
||||
'status' => 'active',
|
||||
]);
|
||||
|
||||
// Mock address model
|
||||
$this->customerAddressModelMock = $this->getMockBuilder(\App\Models\CustomerAddress::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first', 'set', 'update'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->customerAddressModelMock->method('where')->willReturnSelf();
|
||||
$this->customerAddressModelMock->method('first')->willReturn([
|
||||
'id' => $addressId,
|
||||
'customer_id' => $customerId,
|
||||
]);
|
||||
|
||||
$this->customerAddressModelMock->method('set')->willReturnSelf();
|
||||
$this->customerAddressModelMock->method('update')->willReturn(true);
|
||||
|
||||
// Inject mocks into service container
|
||||
\Config\Services::injectMock('customer', $this->customerModelMock);
|
||||
\Config\Services::injectMock('customeraddress', $this->customerAddressModelMock);
|
||||
// Set mocked model into the controller before calling the method
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModelMock);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $this->customerAddressModelMock);
|
||||
|
||||
// Capture response
|
||||
$response = $this->controller->setDefaultCustomerAddress($addressId);
|
||||
|
||||
$responseArray = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertEquals('success', $responseArray['status']);
|
||||
$this->assertEquals("Address ID {$addressId} is now the default for customer ID {$customerId}.", $responseArray['message']);
|
||||
$this->assertEquals($customerId, $responseArray['data']['customer_id']);
|
||||
$this->assertEquals($addressId, $responseArray['data']['address_id']);
|
||||
}
|
||||
|
||||
public function testSetDefaultCustomerAddressMissingCustomerId()
|
||||
{
|
||||
// Arrange
|
||||
$addressId = 456;
|
||||
|
||||
// Simulate request missing 'customer_id'
|
||||
$this->request->method('getVar')->with('customer_id')->willReturn(null);
|
||||
|
||||
// Act
|
||||
$response = $this->controller->setDefaultCustomerAddress($addressId);
|
||||
$responseArray = json_decode($response->getBody(), true);
|
||||
|
||||
// Assert
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$this->assertEquals('error', $responseArray['status']);
|
||||
$this->assertEquals('Customer ID is required.', $responseArray['message']);
|
||||
$this->assertNull($responseArray['data']);
|
||||
}
|
||||
|
||||
public function testSetDefaultCustomerAddressFailsWhenCustomerNotFound()
|
||||
{
|
||||
$customerId = 123;
|
||||
$addressId = 456;
|
||||
|
||||
// Mock request
|
||||
$this->request->method('getVar')->with('customer_id')->willReturn($customerId);
|
||||
|
||||
// Mock customer model to return null
|
||||
$this->customerModelMock = $this->getMockBuilder(\App\Models\Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->customerModelMock->method('where')->willReturnSelf();
|
||||
$this->customerModelMock->method('first')->willReturn(null); // customer not found
|
||||
|
||||
\Config\Services::injectMock('customer', $this->customerModelMock);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModelMock);
|
||||
|
||||
$response = $this->controller->setDefaultCustomerAddress($addressId);
|
||||
$responseArray = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$this->assertEquals('error', $responseArray['status']);
|
||||
$this->assertEquals('Customer not found or inactive.', $responseArray['message']);
|
||||
$this->assertNull($responseArray['data']);
|
||||
}
|
||||
|
||||
public function testSetDefaultCustomerAddressFailsWhenAddressNotFound()
|
||||
{
|
||||
$customerId = 123;
|
||||
$addressId = 456;
|
||||
|
||||
$this->request->method('getVar')->with('customer_id')->willReturn($customerId);
|
||||
|
||||
// Mock valid customer
|
||||
$this->customerModelMock = $this->getMockBuilder(\App\Models\Customer::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->customerModelMock->method('where')->willReturnSelf();
|
||||
$this->customerModelMock->method('first')->willReturn([
|
||||
'id' => $customerId,
|
||||
'status' => 'active',
|
||||
]);
|
||||
|
||||
// Mock address not found
|
||||
$this->customerAddressModelMock = $this->getMockBuilder(\App\Models\CustomerAddress::class)
|
||||
->addMethods(['where'])
|
||||
->onlyMethods(['first'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->customerAddressModelMock->method('where')->willReturnSelf();
|
||||
$this->customerAddressModelMock->method('first')->willReturn(null);
|
||||
|
||||
\Config\Services::injectMock('customer', $this->customerModelMock);
|
||||
\Config\Services::injectMock('customeraddress', $this->customerAddressModelMock);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModelMock);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerAddressModel', $this->customerAddressModelMock);
|
||||
|
||||
$response = $this->controller->setDefaultCustomerAddress($addressId);
|
||||
$responseArray = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$this->assertEquals('error', $responseArray['status']);
|
||||
$this->assertEquals('Address not found or does not belong to the customer.', $responseArray['message']);
|
||||
$this->assertNull($responseArray['data']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,629 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Controllers\Backend;
|
||||
|
||||
use App\Controllers\Backend\CustomerController;
|
||||
use App\Models\Customer;
|
||||
use App\Models\SettingCustomerType;
|
||||
use App\Models\SettingMembershipTier;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use Config\App;
|
||||
use Config\Services;
|
||||
|
||||
class CustomerTest extends CIUnitTestCase
|
||||
{
|
||||
protected $controller;
|
||||
protected $request;
|
||||
protected $response;
|
||||
protected $customerModel;
|
||||
protected $customerTypeModel;
|
||||
protected $tierModel;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Mock models
|
||||
$this->customerModel = $this->getMockBuilder(Customer::class)
|
||||
->onlyMethods(['insert', 'getInsertID', 'update'])
|
||||
->getMock();
|
||||
|
||||
$this->customerTypeModel = $this->getMockBuilder(SettingCustomerType::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
|
||||
$this->tierModel = $this->getMockBuilder(SettingMembershipTier::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
|
||||
// Set global POST input before request is retrieved
|
||||
service('request')->setGlobal('post', [
|
||||
'customer_type' => 'Regular',
|
||||
'customer_tier' => 'Bronze',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
'password_hash' => 'secret1234',
|
||||
'name' => 'John Doe',
|
||||
]);
|
||||
|
||||
// Get request service AFTER setting global input
|
||||
$this->request = service('request');
|
||||
$this->response = service('response');
|
||||
|
||||
// Now init the controller with the correct request/response
|
||||
$this->controller = new \App\Controllers\Backend\CustomerController();
|
||||
$this->controller->initController($this->request, $this->response, service('logger'));
|
||||
|
||||
// Inject mocks
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerTypeModel', $this->customerTypeModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'membershipTierModel', $this->tierModel);
|
||||
}
|
||||
|
||||
//Have an issue
|
||||
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);
|
||||
}
|
||||
|
||||
public function testCreateFailsValidation()
|
||||
{
|
||||
$this->request->setGlobal('post', [
|
||||
'customer_type' => 'Regular',
|
||||
'customer_tier' => 'Bronze',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'invalid-email', // Invalid email format
|
||||
'password_hash' => 'secret1234',
|
||||
// 'name' is missing
|
||||
]);
|
||||
|
||||
$this->customerTypeModel->method('where')->willReturnSelf();
|
||||
$this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']);
|
||||
|
||||
$this->tierModel->method('where')->willReturnSelf();
|
||||
$this->tierModel->method('first')->willReturn(['id' => 2, 'name' => 'Bronze']);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request);
|
||||
|
||||
$response = $this->controller->create();
|
||||
|
||||
$this->assertEquals(400, $response->getStatusCode());
|
||||
|
||||
}
|
||||
|
||||
public function testCreateFailsIfCustomerTypeNotFound()
|
||||
{
|
||||
// Inject mock validation to bypass default validation rules
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
// $this->request = service('request');
|
||||
$this->request->setGlobal('post', [
|
||||
'customer_type' => 'NonexistentType',
|
||||
// 'customer_tier' => 'Bronze',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
'password_hash' => 'secret1234',
|
||||
'name' => 'John Doe',
|
||||
]);
|
||||
|
||||
$this->customerTypeModel->method('where')->willReturnSelf();
|
||||
$this->customerTypeModel->method('first')->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request);
|
||||
|
||||
$response = $this->controller->create();
|
||||
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
|
||||
// $this->assertStringContainsString('Customer type', $response->getBody());
|
||||
}
|
||||
|
||||
public function testCreateFailsIfMembershipTierNotFound()
|
||||
{
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
$this->request->setGlobal('post', [
|
||||
'customer_type' => 'Regular',
|
||||
'customer_tier' => 'NonexistentTier',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
'password_hash' => 'secret1234',
|
||||
'name' => 'John Doe',
|
||||
]);
|
||||
|
||||
|
||||
$this->customerTypeModel->method('where')->willReturnSelf();
|
||||
$this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']);
|
||||
|
||||
$this->tierModel->method('where')->willReturnSelf();
|
||||
$this->tierModel->method('first')->willReturn(null);
|
||||
|
||||
$response = $this->controller->create();
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
|
||||
}
|
||||
|
||||
public function testCreateCustomerSuccess()
|
||||
{
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
$this->request->setGlobal('post', [
|
||||
'customer_type' => 'Regular',
|
||||
'customer_tier' => 'Bronze',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
'password_hash' => 'secret1234',
|
||||
'name' => 'John Doe',
|
||||
]);
|
||||
|
||||
$this->customerTypeModel->method('where')->willReturnSelf();
|
||||
$this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']);
|
||||
|
||||
$this->tierModel->method('where')->willReturnSelf();
|
||||
$this->tierModel->method('first')->willReturn(['id' => 2, 'name' => 'Bronze']);
|
||||
|
||||
$this->customerModel->method('insert')->willReturn(true);
|
||||
$this->customerModel->method('getInsertID')->willReturn(5);
|
||||
$this->customerModel->method('update')->willReturn(true);
|
||||
|
||||
// Inject a real response object
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerTypeModel', $this->customerTypeModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'membershipTierModel', $this->tierModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'response', service('response'));
|
||||
|
||||
$response = $this->controller->create();
|
||||
|
||||
// var_dump($response->getStatusCode());
|
||||
// var_dump($response->getBody());
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Customer created successfully', $response->getBody());
|
||||
|
||||
$_POST = [];
|
||||
}
|
||||
|
||||
|
||||
public function testCreateFailsOnCustomerInsert()
|
||||
{
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
$this->request->setGlobal('post', [
|
||||
'customer_type' => 'Regular',
|
||||
'customer_tier' => 'Bronze',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
'password_hash' => 'secret1234',
|
||||
'name' => 'John Doe',
|
||||
]);
|
||||
|
||||
// Mock success on lookups
|
||||
$this->customerTypeModel->method('where')->willReturnSelf();
|
||||
$this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']);
|
||||
|
||||
$this->tierModel->method('where')->willReturnSelf();
|
||||
$this->tierModel->method('first')->willReturn(['id' => 2, 'name' => 'Bronze']);
|
||||
|
||||
// Simulate failure in DB insert
|
||||
$this->customerModel->method('insert')->willReturn(false);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request);
|
||||
|
||||
$response = $this->controller->create();
|
||||
|
||||
$this->assertEquals(500, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Failed to create customer', $response->getBody());
|
||||
}
|
||||
|
||||
public function testIndexReturnsCustomers()
|
||||
{
|
||||
$mockData = [
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => 'Test Customer',
|
||||
'customer_tier' => 'Gold',
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => 'Second Customer',
|
||||
'customer_tier' => 'Silver',
|
||||
]
|
||||
];
|
||||
|
||||
$this->customerModel = $this->getMockBuilder(Customer::class)
|
||||
->onlyMethods(['findAll'])
|
||||
->addMethods(['select', 'join'])
|
||||
->getMock();
|
||||
|
||||
|
||||
$this->customerModel->method('select')->willReturnSelf();
|
||||
$this->customerModel->method('join')->willReturnSelf();
|
||||
$this->customerModel->method('findAll')->willReturn($mockData);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
|
||||
$response = $this->controller->index();
|
||||
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
|
||||
$output = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals('success', $output['status']);
|
||||
$this->assertEquals('Customer list retrieved successfully.', $output['message']);
|
||||
$this->assertCount(2, $output['data']);
|
||||
$this->assertEquals('Test Customer', $output['data'][0]['name']);
|
||||
}
|
||||
|
||||
|
||||
public function testShowReturnsCustomerSuccess()
|
||||
{
|
||||
$mockCustomer = [
|
||||
'id' => 1,
|
||||
'name' => 'Test Customer',
|
||||
'email' => 'test@example.com',
|
||||
'profile_picture' => null,
|
||||
'customer_tier' => 'Gold',
|
||||
];
|
||||
|
||||
$this->customerModel = $this->getMockBuilder(Customer::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['select', 'join', 'where'])
|
||||
->getMock();
|
||||
|
||||
$this->customerModel->method('select')->willReturnSelf();
|
||||
$this->customerModel->method('join')->willReturnSelf();
|
||||
$this->customerModel->method('where')->willReturnSelf();
|
||||
$this->customerModel->method('first')->willReturn($mockCustomer);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
|
||||
$response = $this->controller->show(1);
|
||||
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
|
||||
$output = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals('success', $output['status']);
|
||||
$this->assertEquals('Customer retrieved successfully.', $output['message']);
|
||||
$this->assertEquals('Test Customer', $output['data']['name']);
|
||||
}
|
||||
|
||||
|
||||
public function testShowReturnsValidationErrorWhenIdMissing()
|
||||
{
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'response', service('response'));
|
||||
|
||||
$response = $this->controller->show(null);
|
||||
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Customer ID is required.', $response->getBody());
|
||||
}
|
||||
|
||||
public function testShowReturnsNotFoundWhenCustomerMissing()
|
||||
{
|
||||
$this->customerModel = $this->getMockBuilder(Customer::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['select', 'join', 'where'])
|
||||
->getMock();
|
||||
|
||||
$this->customerModel->method('select')->willReturnSelf();
|
||||
$this->customerModel->method('join')->willReturnSelf();
|
||||
$this->customerModel->method('where')->willReturnSelf();
|
||||
$this->customerModel->method('first')->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
|
||||
$response = $this->controller->show(99); // non-existing
|
||||
|
||||
$this->assertSame(404, $response->getStatusCode());
|
||||
|
||||
$output = json_decode($response->getBody(), true);
|
||||
|
||||
$this->assertEquals('error', $output['status']);
|
||||
$this->assertEquals('Customer with ID 99 not found.', $output['message']);
|
||||
}
|
||||
|
||||
public function testDeleteCustomerFailsWithoutId()
|
||||
{
|
||||
$this->controller = new CustomerController();
|
||||
$this->controller->initController(service('request'), service('response'), service('logger'));
|
||||
|
||||
$result = $this->controller->delete(null);
|
||||
$output = json_decode($result->getJSON(), true);
|
||||
|
||||
$this->assertEquals(422, $result->getStatusCode());
|
||||
$this->assertEquals('error', $output['status']);
|
||||
$this->assertEquals('Customer ID is required.', $output['message']);
|
||||
$this->assertNull($output['data']);
|
||||
}
|
||||
|
||||
|
||||
public function testDeleteCustomerFailsWhenNotFound()
|
||||
{
|
||||
$this->customerModel = $this->getMockBuilder(Customer::class)
|
||||
->onlyMethods(['find'])
|
||||
->getMock();
|
||||
|
||||
$this->customerModel->method('find')->willReturn(null);
|
||||
|
||||
$this->controller = new CustomerController();
|
||||
$this->controller->initController(service('request'), service('response'), service('logger'));
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
|
||||
$result = $this->controller->delete(999);
|
||||
$output = json_decode($result->getJSON(), true);
|
||||
|
||||
$this->assertEquals(404, $result->getStatusCode());
|
||||
$this->assertEquals('error', $output['status']);
|
||||
$this->assertEquals('Customer with ID 999 not found.', $output['message']);
|
||||
$this->assertNull($output['data']);
|
||||
}
|
||||
|
||||
public function testDeleteCustomerSuccess()
|
||||
{
|
||||
$mockCustomer = ['id' => 1, 'name' => 'Test User'];
|
||||
|
||||
$this->customerModel = $this->getMockBuilder(Customer::class)
|
||||
->onlyMethods(['find', 'delete'])
|
||||
->getMock();
|
||||
|
||||
$this->customerModel->method('find')->with(1)->willReturn($mockCustomer);
|
||||
$this->customerModel->method('delete')->with(1)->willReturn(true);
|
||||
|
||||
$this->controller = new CustomerController();
|
||||
$this->controller->initController(service('request'), service('response'), service('logger'));
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel);
|
||||
|
||||
$result = $this->controller->delete(1);
|
||||
$output = json_decode($result->getJSON(), true);
|
||||
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
$this->assertEquals('success', $output['status']);
|
||||
$this->assertEquals('Customer with ID 1 deleted successfully.', $output['message']);
|
||||
$this->assertNull($output['data']);
|
||||
}
|
||||
|
||||
public function testUpdateFailsOnValidationError()
|
||||
{
|
||||
$id = 1;
|
||||
|
||||
$mockCustomerModel = $this->createMock(\App\Models\Customer::class);
|
||||
$mockCustomerModel->method('find')->willReturn([
|
||||
'id' => $id,
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com'
|
||||
]);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
|
||||
$this->request->setGlobal('post', [
|
||||
'customer_type' => 'Regular',
|
||||
'customer_tier' => 'Bronze',
|
||||
'birthday' => '1990-01-01',
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
'name' => '', // Empty name = fail
|
||||
]);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request);
|
||||
|
||||
$response = $this->controller->update($id);
|
||||
|
||||
$this->assertEquals(422, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Validation failed', $response->getBody());
|
||||
}
|
||||
|
||||
public function testUpdateCustomerSuccess()
|
||||
{
|
||||
// Mock customer ID
|
||||
$customerId = 1;
|
||||
|
||||
// Expected customer data returned by find()
|
||||
$existingCustomer = [
|
||||
'id' => $customerId,
|
||||
'name' => 'Old Name',
|
||||
'phone' => '0111111111',
|
||||
'email' => 'old@example.com',
|
||||
'customer_type' => 'Regular',
|
||||
'membership_tier' => 'Silver',
|
||||
'birthday' => '1990-01-01',
|
||||
];
|
||||
|
||||
// Create mock for Customer model
|
||||
$mockCustomerModel = $this->createMock(Customer::class);
|
||||
$mockCustomerModel->method('find')->with($customerId)->willReturn($existingCustomer);
|
||||
$mockCustomerModel->method('update')->willReturn(true);
|
||||
|
||||
// Mock SettingCustomerType model
|
||||
$mockCustomerTypeModel = $this->getMockBuilder(SettingCustomerType::class)
|
||||
->onlyMethods(['first']) // first() exists — use onlyMethods()
|
||||
->addMethods(['where']) // where() is dynamic — use addMethods()
|
||||
->getMock();
|
||||
$mockCustomerTypeModel->method('where')->willReturnSelf();
|
||||
$mockCustomerTypeModel->method('first')->willReturn(['name' => 'Regular']);
|
||||
|
||||
// Mock SettingMembershipTier model
|
||||
$mockTierModel = $this->getMockBuilder(SettingMembershipTier::class)
|
||||
->onlyMethods(['first']) // first() exists — use onlyMethods()
|
||||
->addMethods(['where']) // where() is dynamic — use addMethods()
|
||||
->getMock();
|
||||
$mockTierModel->method('where')->willReturnSelf();
|
||||
$mockTierModel->method('first')->willReturn([
|
||||
'id' => 1,
|
||||
'name' => 'Gold'
|
||||
]);
|
||||
|
||||
// Mock the IncomingRequest
|
||||
$mockRequest = $this->getMockBuilder(IncomingRequest::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getVar', 'getMethod'])
|
||||
->getMock();
|
||||
|
||||
$mockRequest->method('getVar')->willReturnCallback(function ($key) {
|
||||
$data = [
|
||||
'id' => 1,
|
||||
'phone' => '0123456789',
|
||||
'name' => 'Updated Name',
|
||||
'email' => 'updated@example.com',
|
||||
'customer_type' => 'Regular',
|
||||
'membership_tier' => 'Gold',
|
||||
'birthday' => '1990-01-01',
|
||||
];
|
||||
return $data[$key] ?? null;
|
||||
});
|
||||
|
||||
$mockRequest->method('getMethod')->willReturn('post');
|
||||
|
||||
// Mock validation to return true (skip validation errors)
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
// Create controller and inject mocks
|
||||
$controller = new CustomerController();
|
||||
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $mockRequest);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'customerTypeModel', $mockCustomerTypeModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'membershipTierModel', $mockTierModel);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', \Config\Services::response());
|
||||
|
||||
// Run update
|
||||
$response = $controller->update($customerId);
|
||||
|
||||
// $statusCode = $response->getStatusCode();
|
||||
// $body = $response->getBody();
|
||||
|
||||
// var_dump($statusCode);
|
||||
// var_dump($body);
|
||||
|
||||
// Assert success
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testUpdateFailsWhenCustomerNotFound()
|
||||
{
|
||||
$mockCustomerModel = $this->createMock(\App\Models\Customer::class);
|
||||
$mockCustomerModel->method('find')->willReturn(null);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
|
||||
$response = $this->controller->update(999); // Non-existent ID
|
||||
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Customer with ID 999 not found', $response->getBody());
|
||||
}
|
||||
|
||||
|
||||
public function testUpdateFailsIfTierNotFound()
|
||||
{
|
||||
$id = 1;
|
||||
|
||||
// Mock customerModel
|
||||
$mockCustomerModel = $this->createMock(\App\Models\Customer::class);
|
||||
$mockCustomerModel->method('find')->willReturn([
|
||||
'id' => $id,
|
||||
'phone' => '0123456789',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
|
||||
// Mock membershipTierModel to return null (tier not found)
|
||||
$mockTierModel = $this->getMockBuilder(SettingMembershipTier::class)
|
||||
->onlyMethods(['first'])
|
||||
->addMethods(['where'])
|
||||
->getMock();
|
||||
$mockTierModel->method('where')->willReturnSelf();
|
||||
$mockTierModel->method('first')->willReturn(null);
|
||||
|
||||
// Set mocked models into the controller
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'membershipTierModel', $mockTierModel);
|
||||
|
||||
// Create and mock a request with POST data
|
||||
$mockRequest = $this->getMockBuilder(IncomingRequest::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getVar', 'getMethod'])
|
||||
->getMock();
|
||||
|
||||
$mockRequest->method('getVar')->willReturnMap([
|
||||
['customer_type', null, 'Regular'],
|
||||
['customer_tier', null, 'NonexistentTier'],
|
||||
['birthday', null, '1990-01-01'],
|
||||
['phone', null, '0123456789'],
|
||||
['email', null, 'test@example.com'],
|
||||
['name', null, 'John Doe'],
|
||||
]);
|
||||
|
||||
$mockRequest->method('getMethod')->willReturn('post');
|
||||
|
||||
// Set the mocked request into the controller
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $mockRequest);
|
||||
|
||||
// Mock validation to return true (skip validation errors)
|
||||
$mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['run', 'getErrors'])
|
||||
->getMock();
|
||||
$mockValidation->method('run')->willReturn(true);
|
||||
$mockValidation->method('getErrors')->willReturn([]);
|
||||
\Config\Services::injectMock('validation', $mockValidation);
|
||||
|
||||
// Call the update method
|
||||
$response = $this->controller->update($id);
|
||||
|
||||
// Assertions
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use Config\App;
|
||||
use Tests\Support\Libraries\ConfigReader;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class HealthTest extends CIUnitTestCase
|
||||
{
|
||||
public function testIsDefinedAppPath(): void
|
||||
{
|
||||
$this->assertTrue(defined('APPPATH'));
|
||||
}
|
||||
|
||||
public function testBaseUrlHasBeenSet(): void
|
||||
{
|
||||
$validation = service('validation');
|
||||
|
||||
$env = false;
|
||||
|
||||
// Check the baseURL in .env
|
||||
if (is_file(HOMEPATH . '.env')) {
|
||||
$env = preg_grep('/^app\.baseURL = ./', file(HOMEPATH . '.env')) !== false;
|
||||
}
|
||||
|
||||
if ($env) {
|
||||
// BaseURL in .env is a valid URL?
|
||||
// phpunit.xml.dist sets app.baseURL in $_SERVER
|
||||
// So if you set app.baseURL in .env, it takes precedence
|
||||
$config = new App();
|
||||
$this->assertTrue(
|
||||
$validation->check($config->baseURL, 'valid_url'),
|
||||
'baseURL "' . $config->baseURL . '" in .env is not valid URL',
|
||||
);
|
||||
}
|
||||
|
||||
// Get the baseURL in app/Config/App.php
|
||||
// You can't use Config\App, because phpunit.xml.dist sets app.baseURL
|
||||
$reader = new ConfigReader();
|
||||
|
||||
// BaseURL in app/Config/App.php is a valid URL?
|
||||
$this->assertTrue(
|
||||
$validation->check($reader->baseURL, 'valid_url'),
|
||||
'baseURL "' . $reader->baseURL . '" in app/Config/App.php is not valid URL',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Controllers\Backend;
|
||||
|
||||
use App\Controllers\Backend\UserController;
|
||||
use App\Models\User;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
|
||||
class UserTest extends CIUnitTestCase
|
||||
{
|
||||
protected $mockUser;
|
||||
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 setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->mockUser = $this->createMock(User::class);
|
||||
$this->controller = new UserController();
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'user', $this->mockUser);
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $this->createMock(IncomingRequest::class));
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'response', service('response'));
|
||||
}
|
||||
|
||||
public function testIndexReturnsUsers()
|
||||
{
|
||||
$users = [
|
||||
['id' => 1, 'username' => 'john', 'name' => 'John Doe'],
|
||||
['id' => 2, 'username' => 'jane', 'name' => 'Jane Doe'],
|
||||
];
|
||||
|
||||
$this->mockUser->method('findAll')->willReturn($users);
|
||||
|
||||
$result = $this->controller->index();
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
|
||||
$this->assertEquals('success', $data['status']);
|
||||
$this->assertEquals('User data retrieved successfully.', $data['message']);
|
||||
$this->assertEquals($users, $data['data']);
|
||||
}
|
||||
|
||||
public function testIndexReturnsNoUsers()
|
||||
{
|
||||
$this->mockUser->method('findAll')->willReturn([]);
|
||||
|
||||
$result = $this->controller->index();
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
|
||||
$this->assertEquals('error', $data['status']);
|
||||
$this->assertEquals('No user data found.', $data['message']);
|
||||
$this->assertEquals(null, $data['data']);
|
||||
}
|
||||
|
||||
public function testShowReturnsUser()
|
||||
{
|
||||
$user = ['id' => 1, 'username' => 'john', 'name' => 'John Doe'];
|
||||
$this->mockUser->method('find')->with(1)->willReturn($user);
|
||||
|
||||
$result = $this->controller->show(1);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
|
||||
$this->assertEquals('success', $data['status']);
|
||||
$this->assertEquals('User retrieved successfully.', $data['message']);
|
||||
$this->assertEquals($user, $data['data']);
|
||||
}
|
||||
|
||||
public function testShowReturnsNotFound()
|
||||
{
|
||||
$this->mockUser->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->show(99);
|
||||
$this->assertEquals(404, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
|
||||
$this->assertEquals('error', $data['status']);
|
||||
$this->assertEquals('User not found.', $data['message']);
|
||||
}
|
||||
|
||||
public function testCreateValidationFails()
|
||||
{
|
||||
$controller = $this->getMockBuilder(UserController::class)
|
||||
->onlyMethods(['validate'])
|
||||
->enableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$controller->method('validate')->willReturn(false);
|
||||
|
||||
$validator = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$validator->method('getErrors')->willReturn(['username' => 'Required']);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($controller, 'validator', $validator);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'user', $this->mockUser);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $this->createMock(\CodeIgniter\HTTP\IncomingRequest::class));
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', service('response'));
|
||||
|
||||
$result = $controller->create();
|
||||
$this->assertEquals(422, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
$this->assertArrayHasKey('error', $data);
|
||||
|
||||
$this->assertEquals('errors', $data['status']);
|
||||
$this->assertEquals('Validation failed', $data['message']);
|
||||
$this->assertArrayHasKey('username', $data['errors']);
|
||||
}
|
||||
|
||||
public function testCreateSuccess()
|
||||
{
|
||||
$this->mockUser->method('insert')->willReturn(1);
|
||||
$this->mockUser->method('find')->with(1)->willReturn([
|
||||
'id' => 1, 'username' => 'john', 'name' => 'John Doe'
|
||||
]);
|
||||
|
||||
$request = $this->createMock(IncomingRequest::class);
|
||||
$request->method('getVar')->willReturnMap([
|
||||
['username', 'john'],
|
||||
['name', 'John Doe'],
|
||||
['password_hash', 'password'],
|
||||
['role', 'admin'],
|
||||
['status', 'active'],
|
||||
]);
|
||||
|
||||
$controller = $this->getMockBuilder(UserController::class)
|
||||
->onlyMethods(['validate'])
|
||||
->enableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$controller->method('validate')->willReturn(true);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($controller, 'request', $request);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'user', $this->mockUser);
|
||||
$this->setProtectedOrPrivateProperty($controller, 'response', service('response'));
|
||||
|
||||
$result = $controller->create();
|
||||
$this->assertEquals(201, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
|
||||
$this->assertEquals('success', $data['status']);
|
||||
$this->assertEquals('User created successfully.', $data['message']);
|
||||
$this->assertEquals([
|
||||
'id' => 1, 'username' => 'john', 'name' => 'John Doe'
|
||||
], $data['data']);
|
||||
}
|
||||
|
||||
public function testUpdateUserNotFound()
|
||||
{
|
||||
$this->mockUser->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->update(99);
|
||||
$this->assertEquals(404, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
|
||||
$this->assertEquals('error', $data['status']);
|
||||
$this->assertEquals('User not found.', $data['message']);
|
||||
}
|
||||
|
||||
public function testUpdateNoDataProvided()
|
||||
{
|
||||
$this->mockUser->method('find')->with(1)->willReturn(['id' => 1]);
|
||||
$request = $this->createMock(IncomingRequest::class);
|
||||
$request->method('getRawInput')->willReturn([]);
|
||||
$request->method('getPost')->willReturn([]);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $request);
|
||||
|
||||
$result = $this->controller->update(1);
|
||||
$this->assertEquals(400, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
|
||||
$this->assertEquals('error', $data['status']);
|
||||
$this->assertEquals('No data provided to update.', $data['message']);
|
||||
}
|
||||
|
||||
public function testUpdateSuccess()
|
||||
{
|
||||
$this->mockUser->method('find')->with(1)->willReturn(['id' => 1]);
|
||||
$this->mockUser->expects($this->once())->method('update')->with(1, ['username' => 'john']);
|
||||
$this->mockUser->method('find')->with(1)->willReturn(['id' => 1, 'username' => 'john']);
|
||||
|
||||
$request = $this->createMock(IncomingRequest::class);
|
||||
$request->method('getRawInput')->willReturn(['username' => 'john']);
|
||||
$request->method('getPost')->willReturn([]);
|
||||
|
||||
$this->setProtectedOrPrivateProperty($this->controller, 'request', $request);
|
||||
|
||||
$result = $this->controller->update(1);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
|
||||
$this->assertEquals('success', $data['status']);
|
||||
$this->assertEquals('User updated successfully.', $data['message']);
|
||||
$this->assertEquals(['id' => 1, 'username' => 'john'], $data['data']);
|
||||
}
|
||||
|
||||
public function testDeleteUserNotFound()
|
||||
{
|
||||
$this->mockUser->method('find')->with(99)->willReturn(null);
|
||||
|
||||
$result = $this->controller->delete(99);
|
||||
$this->assertEquals(404, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
|
||||
$this->assertEquals('error', $data['status']);
|
||||
$this->assertEquals('User not found.', $data['message']);
|
||||
}
|
||||
|
||||
public function testDeleteSuccess()
|
||||
{
|
||||
$this->mockUser->method('find')->with(1)->willReturn(['id' => 1]);
|
||||
$this->mockUser->expects($this->once())->method('delete')->with(1);
|
||||
|
||||
$result = $this->controller->delete(1);
|
||||
$this->assertEquals(200, $result->getStatusCode());
|
||||
|
||||
$data = json_decode($result->getBody(), true);
|
||||
$this->assertIsArray($data);
|
||||
$this->assertArrayHasKey('status', $data);
|
||||
$this->assertArrayHasKey('message', $data);
|
||||
|
||||
$this->assertEquals('success', $data['status']);
|
||||
$this->assertEquals('User deleted successfully.', $data['message']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user