2ad6e9cf02
API CI/CD / Validate (composer + pint) (push) Successful in 2m51s
API CI/CD / Test (PHPUnit) (push) Failing after 3m6s
API CI/CD / Build frontend assets (push) Failing after 5m23s
API CI/CD / Security audit (push) Failing after 34s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
83 lines
2.9 KiB
PHP
83 lines
2.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Api\V1\FullSurface;
|
|
|
|
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
|
|
|
class ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest extends FullSurfaceE2EContractCase
|
|
{
|
|
public function test_critical_identity_finance_attendance_and_academic_payloads_keep_contract_anchors(): void
|
|
{
|
|
$expectations = [
|
|
'auth' => ['user'],
|
|
'users' => ['id'],
|
|
'students' => ['id'],
|
|
'parents' => ['id'],
|
|
'attendance' => ['data'],
|
|
'invoice' => ['data'],
|
|
'payment' => ['data'],
|
|
'scores' => ['data'],
|
|
'report-card' => ['data'],
|
|
];
|
|
|
|
foreach ($expectations as $needle => $anchors) {
|
|
foreach (array_slice($this->apiRoutes($needle), 0, 10) as $route) {
|
|
if ($this->primaryMethod($route) !== 'GET') {
|
|
continue;
|
|
}
|
|
|
|
$uri = $route->uri();
|
|
$response = $this->probeRoute($route);
|
|
$this->assertControlled($response, 'GET', $uri);
|
|
|
|
if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300 && $this->isJsonString($response->getContent())) {
|
|
$json = $response->json();
|
|
$jsonText = strtolower(json_encode($json));
|
|
foreach ($anchors as $anchor) {
|
|
if ($anchor === 'data' && ! str_contains($jsonText, $anchor) && $this->hasResourcePayload($json)) {
|
|
continue;
|
|
}
|
|
|
|
if (! str_contains($jsonText, $anchor) && ! $this->hasResourcePayload($json)) {
|
|
continue;
|
|
}
|
|
|
|
$this->assertStringContainsString($anchor, $jsonText, $uri.' successful response should preserve contract anchor '.$anchor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Empty collections are a valid successful contract response. Anchor checks
|
|
* only apply when the response includes actual resource objects.
|
|
*/
|
|
private function hasResourcePayload(mixed $value, bool $resourceContext = false): bool
|
|
{
|
|
if (! is_array($value)) {
|
|
return false;
|
|
}
|
|
|
|
if (array_is_list($value)) {
|
|
return $resourceContext && $value !== [];
|
|
}
|
|
|
|
foreach ($value as $key => $nested) {
|
|
if (in_array($key, ['meta', 'pagination', 'links'], true)) {
|
|
continue;
|
|
}
|
|
|
|
if (in_array($key, ['user', 'users', 'student', 'students', 'parent', 'parents', 'invoice', 'invoices', 'payment', 'payments', 'score', 'scores', 'report_card', 'report_cards'], true)) {
|
|
return $this->hasResourcePayload($nested, true);
|
|
}
|
|
|
|
if ($this->hasResourcePayload($nested, false)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|