Files
shopPRO/tests/Unit/api/Controllers/OrdersApiControllerTest.php
Jacek Pyziak 9cac0d1eeb ver. 0.296: REST API for ordersPRO — orders management, dictionaries, API key auth
- New API layer: ApiRouter, OrdersApiController, DictionariesApiController
- Orders API: list (with filters/pagination/updated_since), details, change status, set paid/unpaid
- Dictionaries API: order statuses, transport methods, payment methods
- X-Api-Key authentication via pp_settings.api_key
- OrderRepository: listForApi(), findForApi(), touchUpdatedAt()
- updated_at column on pp_shop_orders for polling support
- api.php: skip session for API requests, route to ApiRouter
- SettingsController: api_key field in system tab
- 30 new tests (666 total, 1930 assertions)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:25:07 +01:00

291 lines
7.8 KiB
PHP

<?php
namespace Tests\Unit\api\Controllers;
use PHPUnit\Framework\TestCase;
use api\Controllers\OrdersApiController;
use Domain\Order\OrderAdminService;
use Domain\Order\OrderRepository;
class OrdersApiControllerTest extends TestCase
{
private $mockService;
private $mockOrderRepo;
private $controller;
protected function setUp(): void
{
$this->mockService = $this->createMock(OrderAdminService::class);
$this->mockOrderRepo = $this->createMock(OrderRepository::class);
$this->controller = new OrdersApiController($this->mockService, $this->mockOrderRepo);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET = [];
}
protected function tearDown(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET = [];
http_response_code(200);
}
// --- list ---
public function testListReturnsOrders(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$this->mockOrderRepo->method('listForApi')
->willReturn([
'items' => [
['id' => 1, 'number' => '2026/01/001', 'status' => 0, 'paid' => 0, 'summary' => 99.99],
],
'total' => 1,
'page' => 1,
'per_page' => 50,
]);
ob_start();
$this->controller->list();
$output = ob_get_clean();
$json = json_decode($output, true);
$this->assertSame('ok', $json['status']);
$this->assertCount(1, $json['data']['items']);
$this->assertSame(1, $json['data']['total']);
}
public function testListRejectsPostMethod(): void
{
$_SERVER['REQUEST_METHOD'] = 'POST';
ob_start();
$this->controller->list();
$output = ob_get_clean();
$this->assertSame(405, http_response_code());
}
public function testListPassesFiltersToRepository(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET['status'] = '4';
$_GET['paid'] = '1';
$_GET['page'] = '2';
$_GET['per_page'] = '25';
$this->mockOrderRepo->expects($this->once())
->method('listForApi')
->with(
$this->callback(function ($filters) {
return $filters['status'] === '4' && $filters['paid'] === '1';
}),
2,
25
)
->willReturn(['items' => [], 'total' => 0, 'page' => 2, 'per_page' => 25]);
ob_start();
$this->controller->list();
ob_get_clean();
}
// --- get ---
public function testGetReturnsOrder(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET['id'] = '42';
$this->mockOrderRepo->method('findForApi')
->with(42)
->willReturn([
'id' => 42,
'number' => '2026/01/001',
'status' => 4,
'paid' => 1,
'summary' => 150.00,
'products' => [],
'statuses' => [],
]);
ob_start();
$this->controller->get();
$output = ob_get_clean();
$json = json_decode($output, true);
$this->assertSame('ok', $json['status']);
$this->assertSame(42, $json['data']['id']);
}
public function testGetReturns404WhenOrderNotFound(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET['id'] = '999';
$this->mockOrderRepo->method('findForApi')
->with(999)
->willReturn(null);
ob_start();
$this->controller->get();
$output = ob_get_clean();
$this->assertSame(404, http_response_code());
$json = json_decode($output, true);
$this->assertSame('NOT_FOUND', $json['code']);
}
public function testGetReturns400WhenMissingId(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
ob_start();
$this->controller->get();
$output = ob_get_clean();
$this->assertSame(400, http_response_code());
}
// --- change_status ---
public function testChangeStatusUpdatesOrder(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_GET['id'] = '10';
$this->mockOrderRepo->method('findRawById')
->with(10)
->willReturn(['id' => 10, 'status' => 0]);
$this->mockService->method('changeStatus')
->with(10, 5, false)
->willReturn(['result' => true]);
// Simulate JSON body via php://input override is not possible in unit tests,
// so we test the controller logic path via mock expectations
ob_start();
$this->controller->change_status();
$output = ob_get_clean();
// Without a real php://input body, getJsonBody returns null → BAD_REQUEST
$json = json_decode($output, true);
$this->assertSame('error', $json['status']);
$this->assertSame('BAD_REQUEST', $json['code']);
}
public function testChangeStatusReturns400WhenMissingId(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
ob_start();
$this->controller->change_status();
$output = ob_get_clean();
$this->assertSame(400, http_response_code());
}
public function testChangeStatusRejectsGetMethod(): void
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET['id'] = '10';
ob_start();
$this->controller->change_status();
$output = ob_get_clean();
$this->assertSame(405, http_response_code());
}
// --- set_paid ---
public function testSetPaidReturns404WhenOrderNotFound(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_GET['id'] = '999';
$this->mockOrderRepo->method('findRawById')
->with(999)
->willReturn(null);
ob_start();
$this->controller->set_paid();
$output = ob_get_clean();
$this->assertSame(404, http_response_code());
}
public function testSetPaidReturns400WhenMissingId(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
ob_start();
$this->controller->set_paid();
$output = ob_get_clean();
$this->assertSame(400, http_response_code());
}
public function testSetPaidCallsServiceWhenOrderExists(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_GET['id'] = '10';
$this->mockOrderRepo->method('findRawById')
->with(10)
->willReturn(['id' => 10, 'paid' => 0]);
$this->mockService->expects($this->once())
->method('setOrderAsPaid')
->with(10, false);
ob_start();
$this->controller->set_paid();
$output = ob_get_clean();
$json = json_decode($output, true);
$this->assertSame('ok', $json['status']);
$this->assertSame(1, $json['data']['paid']);
}
// --- set_unpaid ---
public function testSetUnpaidReturns404WhenOrderNotFound(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_GET['id'] = '999';
$this->mockOrderRepo->method('findRawById')
->with(999)
->willReturn(null);
ob_start();
$this->controller->set_unpaid();
$output = ob_get_clean();
$this->assertSame(404, http_response_code());
}
public function testSetUnpaidCallsServiceWhenOrderExists(): void
{
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_GET['id'] = '10';
$this->mockOrderRepo->method('findRawById')
->with(10)
->willReturn(['id' => 10, 'paid' => 1]);
$this->mockService->expects($this->once())
->method('setOrderAsUnpaid')
->with(10);
ob_start();
$this->controller->set_unpaid();
$output = ob_get_clean();
$json = json_decode($output, true);
$this->assertSame('ok', $json['status']);
$this->assertSame(0, $json['data']['paid']);
}
}