Introduce `department_selfserve_studio_layouts` table for department-specific layouts and implement advanced auto-layout functionality in the DepartmentSelfServeStudio module. Added custom node definitions, updated styling, and integrated new logics for sorting and visualizing nodes in the Vue Flow interface.
128 lines
6.2 KiB
PHP
128 lines
6.2 KiB
PHP
<?php
|
|
|
|
function selfserve_openapi_content_or_skip(): string
|
|
{
|
|
$candidates = [
|
|
dirname(__DIR__, 6) . DIRECTORY_SEPARATOR . 'openapi.yaml',
|
|
dirname(__DIR__, 5) . DIRECTORY_SEPARATOR . 'openapi.yaml',
|
|
dirname(__DIR__, 4) . DIRECTORY_SEPARATOR . 'openapi.yaml',
|
|
dirname(__DIR__, 3) . DIRECTORY_SEPARATOR . 'openapi.yaml',
|
|
dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'openapi.yaml',
|
|
];
|
|
|
|
foreach ($candidates as $candidate) {
|
|
if (!is_file($candidate)) {
|
|
continue;
|
|
}
|
|
|
|
$content = file_get_contents($candidate);
|
|
if ($content !== false) {
|
|
return $content;
|
|
}
|
|
}
|
|
|
|
test()->markTestSkipped('openapi.yaml is not available in this runtime environment.');
|
|
}
|
|
|
|
function selfserve_openapi_path_block_or_fail(string $content, string $path): string
|
|
{
|
|
$path_marker = ' ' . $path . ':';
|
|
$start = strpos($content, $path_marker);
|
|
if ($start === false) {
|
|
throw new RuntimeException("OpenAPI path block not found: {$path}");
|
|
}
|
|
|
|
$rest = substr($content, $start + strlen($path_marker));
|
|
$next_path = strpos($rest, "\n /");
|
|
if ($next_path === false) {
|
|
return substr($content, $start);
|
|
}
|
|
|
|
return substr($content, $start, strlen($path_marker) + $next_path);
|
|
}
|
|
|
|
it('documents self-serve machine type, eligibility, summary, and webhook endpoints', function (): void {
|
|
$content = selfserve_openapi_content_or_skip();
|
|
$allowedPathBlock = selfserve_openapi_path_block_or_fail($content, '/department/selfserve/vehicle/allowed');
|
|
$summaryPathBlock = selfserve_openapi_path_block_or_fail($content, '/department/selfserve/washes/summary');
|
|
|
|
expect($content)->toContain('/department/selfserve/machine-types:');
|
|
expect($content)->toContain('/department/selfserve/vehicle/allowed:');
|
|
expect($content)->toContain('/department/selfserve/washes/summary:');
|
|
expect($content)->toContain('/relay/button/press/post:');
|
|
expect($content)->toContain('/modules/self-serve/lane/wash/in-progress:');
|
|
expect($content)->toContain('/modules/self-serve/lane/relay/machine/status:');
|
|
expect($content)->toContain('/modules/self-serve/lane/relay/machine/set:');
|
|
expect($content)->toContain('/modules/self-serve/lane/gate/open:');
|
|
expect($content)->toContain('/modules/self-serve/lane/relay/machine_program_picker/status:');
|
|
expect($content)->toContain('/modules/self-serve/lane/relay/machine_program_picker/set:');
|
|
expect($content)->toContain('/modules/self-serve/lane/relay/machine_cleaner/status:');
|
|
expect($content)->toContain('/modules/self-serve/lane/relay/machine_cleaner/set:');
|
|
expect($allowedPathBlock)->toContain('name: vehicle_type_id');
|
|
expect($allowedPathBlock)->toContain('name: vehicle_type');
|
|
expect($summaryPathBlock)->toContain('name: vehicle_type_id');
|
|
expect($summaryPathBlock)->toContain('name: vehicle_type');
|
|
});
|
|
|
|
it('documents the all-in-one self-serve studio replacement API', function (): void {
|
|
$content = selfserve_openapi_content_or_skip();
|
|
|
|
expect($content)->toContain('/department/selfserve/studio/graph:');
|
|
expect($content)->toContain('/department/selfserve/studio/layout:');
|
|
expect($content)->toContain('/department/selfserve/studio/validate:');
|
|
expect($content)->toContain('/department/selfserve/studio/simulate:');
|
|
expect($content)->toContain('/department/selfserve/studio/publish:');
|
|
expect($content)->toContain('/department/selfserve/studio/rollback:');
|
|
expect($content)->toContain('/department/selfserve/studio/gateway-action:');
|
|
expect($content)->toContain('SelfserveStudioGraph:');
|
|
expect($content)->toContain('SelfserveStudioGraphSaveRequest:');
|
|
expect($content)->toContain('SelfserveStudioLayout:');
|
|
expect($content)->toContain('runSelfserveStudioGatewayAction');
|
|
});
|
|
|
|
it('defines reusable self-serve wash and machine type schemas', function (): void {
|
|
$content = selfserve_openapi_content_or_skip();
|
|
|
|
expect($content)->toContain('SelfserveMachineType:');
|
|
expect($content)->toContain('SelfserveVehicleAllowedResponse:');
|
|
expect($content)->toContain('SelfserveWashSummary:');
|
|
expect($content)->toContain('MachineButtonPressWebhookResponse:');
|
|
expect($content)->toContain('DepartmentSelfserveVehicleConditionMutationResponse:');
|
|
expect($content)->toContain('machine_type_id:');
|
|
expect($content)->toContain('SelfServeLaneMachineRelayStatus:');
|
|
expect($content)->toContain(' wash_started_at:');
|
|
});
|
|
|
|
it('documents in-progress self-serve wash start and machine relay fields', function (): void {
|
|
$content = selfserve_openapi_content_or_skip();
|
|
$inProgressPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/wash/in-progress');
|
|
|
|
expect($inProgressPathBlock)->toContain('included_minutes:');
|
|
expect($inProgressPathBlock)->toContain('machine_relay_enabled:');
|
|
expect($inProgressPathBlock)->toContain('machine_relay_enabled_at:');
|
|
expect($inProgressPathBlock)->toContain('machine_start_triggered_at:');
|
|
expect($inProgressPathBlock)->toContain('wash_started_at:');
|
|
});
|
|
|
|
it('documents self-serve machine wash included minutes in config schemas', function (): void {
|
|
$content = selfserve_openapi_content_or_skip();
|
|
|
|
expect($content)->toContain('SelfServeConfigEntry:');
|
|
expect($content)->toContain('machine_wash_minutes_included');
|
|
expect($content)->toContain('SelfServeConfig:');
|
|
});
|
|
|
|
it('documents property gate lane commands and sanitized gate failure responses', function (): void {
|
|
$content = selfserve_openapi_content_or_skip();
|
|
$commandPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/command');
|
|
$gateOpenPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/gate/open');
|
|
|
|
expect($commandPathBlock)->toContain('OPEN_PROPERTY_ACCESS_GATE');
|
|
expect($commandPathBlock)->toContain('OPEN_PROPERTY_EXIT_GATE');
|
|
expect($commandPathBlock)->toContain('Command execution failed');
|
|
expect($commandPathBlock)->toContain('Failed to execute command: Failed to open property access gate.');
|
|
|
|
expect($gateOpenPathBlock)->toContain('Gate open failed');
|
|
expect($gateOpenPathBlock)->toContain('Failed to open entrance gate.');
|
|
});
|