session cylces and adjustments
Some checks failed
PHPUnit / test (push) Has been cancelled

This commit is contained in:
tom.hempel
2026-06-29 13:26:08 +02:00
parent f1caa9e681
commit 7fefc264f4
12 changed files with 1256 additions and 3 deletions

View File

@ -0,0 +1,194 @@
<?php
declare(strict_types=1);
namespace Tests\Integration;
use Tests\Support\DatabaseSeeder;
use Tests\Support\QdbTestCase;
final class ProgramSessionsTest extends QdbTestCase
{
public function testAdminCrudAndMobileFetch(): void
{
$token = $this->adminToken();
$qnId = $this->fixture()->questionnaireId;
$create = $this->api()->request('POST', 'program_sessions', [
'name' => 'Baseline',
'description' => 'First visit',
'sessionNumber' => 1,
'orderIndex' => 0,
'isActive' => true,
'questionnaires' => [
['questionnaireID' => $qnId, 'orderIndex' => 0],
],
], ['Authorization' => 'Bearer ' . $token]);
$this->assertApiOk($create);
$sessionID = $create['data']['session']['sessionID'] ?? '';
$this->assertNotSame('', $sessionID);
$this->assertSame('Baseline', $create['data']['session']['name']);
$this->assertCount(1, $create['data']['session']['questionnaires']);
$list = $this->api()->request('GET', 'program_sessions', null, [
'Authorization' => 'Bearer ' . $token,
]);
$this->assertApiOk($list);
$this->assertCount(1, $list['data']['sessions']);
$this->assertFalse($list['data']['settings']['autoRepeatSessions'] ?? true);
$update = $this->api()->request('PUT', 'program_sessions', [
'sessionID' => $sessionID,
'name' => 'Baseline updated',
'sessionNumber' => 2,
'questionnaires' => [],
], ['Authorization' => 'Bearer ' . $token]);
$this->assertApiOk($update);
$this->assertSame('Baseline updated', $update['data']['session']['name']);
$this->assertSame([], $update['data']['session']['questionnaires']);
$mobile = $this->coachMobileLogin();
$appRes = $this->api()->request('GET', 'app_questionnaires', null, [
'Authorization' => 'Bearer ' . $mobile['token'],
], ['sessions' => '1']);
$this->assertApiOk($appRes);
$this->assertCount(1, $appRes['data']['sessions']);
$this->assertSame($sessionID, $appRes['data']['sessions'][0]['sessionID']);
$this->assertArrayHasKey('settings', $appRes['data']);
$delete = $this->api()->request('DELETE', 'program_sessions', [
'sessionID' => $sessionID,
], ['Authorization' => 'Bearer ' . $token]);
$this->assertApiOk($delete);
$empty = $this->api()->request('GET', 'program_sessions', null, [
'Authorization' => 'Bearer ' . $token,
]);
$this->assertApiOk($empty);
$this->assertSame([], $empty['data']['sessions']);
}
public function testAutoRepeatAdvancesCycleAfterLastSessionCompleted(): void
{
$adminToken = $this->adminToken();
$qnId = $this->fixture()->questionnaireId;
$clientCode = $this->fixture()->clientCode;
$this->assertApiOk($this->api()->request('PATCH', 'program_sessions', [
'autoRepeatSessions' => true,
], ['Authorization' => 'Bearer ' . $adminToken]));
$session1 = $this->api()->request('POST', 'program_sessions', [
'name' => 'Session 1',
'sessionNumber' => 1,
'orderIndex' => 0,
'isActive' => true,
'questionnaires' => [['questionnaireID' => $qnId, 'orderIndex' => 0]],
], ['Authorization' => 'Bearer ' . $adminToken]);
$this->assertApiOk($session1);
$session2 = $this->api()->request('POST', 'program_sessions', [
'name' => 'Session 2',
'sessionNumber' => 2,
'orderIndex' => 1,
'isActive' => true,
'questionnaires' => [['questionnaireID' => $qnId, 'orderIndex' => 0]],
], ['Authorization' => 'Bearer ' . $adminToken]);
$this->assertApiOk($session2);
$login = $this->coachMobileLogin();
$submit = $this->submitQuestionnaireAs(
$login['token'],
$qnId,
$clientCode,
[['questionID' => $this->fixture()->questionShortId, 'answerOptionKey' => 'yes']],
);
$this->assertApiOk($submit);
$this->assertTrue($submit['data']['cycleAdvanced'] ?? false);
$this->assertSame(2, $submit['data']['cycleNumber'] ?? 0);
$clientsRes = $this->api()->withMobileToken($login['token'], 'GET', 'app_questionnaires', null, [
'clients' => '1',
]);
$this->assertApiOk($clientsRes);
$plain = qdb_decrypt_sensitive_envelope($clientsRes['data'], $login['token']);
$payload = json_decode($plain, true, 512, JSON_THROW_ON_ERROR);
$client = null;
foreach ($payload['clients'] as $row) {
if (($row['clientCode'] ?? '') === $clientCode) {
$client = $row;
break;
}
}
$this->assertNotNull($client);
$progress = $client['programProgress'];
$this->assertSame(2, $progress['cycleNumber']);
$this->assertSame(2, $progress['totalSessions']);
$this->assertSame(0, $progress['sessionsCompletedInCycle']);
$this->assertTrue($progress['autoRepeatSessions']);
$this->assertFalse($progress['programComplete']);
}
public function testAutoRepeatDisabledKeepsProgramComplete(): void
{
$adminToken = $this->adminToken();
$qnId = $this->fixture()->questionnaireId;
$clientCode = $this->fixture()->clientCode;
$this->assertApiOk($this->api()->request('PATCH', 'program_sessions', [
'autoRepeatSessions' => false,
], ['Authorization' => 'Bearer ' . $adminToken]));
$this->assertApiOk($this->api()->request('POST', 'program_sessions', [
'name' => 'Only session',
'sessionNumber' => 1,
'orderIndex' => 0,
'isActive' => true,
'questionnaires' => [['questionnaireID' => $qnId, 'orderIndex' => 0]],
], ['Authorization' => 'Bearer ' . $adminToken]));
$login = $this->coachMobileLogin();
$submit = $this->submitQuestionnaireAs(
$login['token'],
$qnId,
$clientCode,
[['questionID' => $this->fixture()->questionShortId, 'answerOptionKey' => 'yes']],
);
$this->assertApiOk($submit);
$this->assertFalse($submit['data']['cycleAdvanced'] ?? true);
$this->assertSame(1, $submit['data']['cycleNumber'] ?? 0);
$clientsRes = $this->api()->withMobileToken($login['token'], 'GET', 'app_questionnaires', null, [
'clients' => '1',
]);
$this->assertApiOk($clientsRes);
$plain = qdb_decrypt_sensitive_envelope($clientsRes['data'], $login['token']);
$payload = json_decode($plain, true, 512, JSON_THROW_ON_ERROR);
$progress = $payload['clients'][0]['programProgress'];
$this->assertTrue($progress['cycleComplete']);
$this->assertTrue($progress['programComplete']);
$this->assertFalse($progress['autoRepeatSessions']);
}
public function testRejectUnknownQuestionnaire(): void
{
$token = $this->adminToken();
$res = $this->api()->request('POST', 'program_sessions', [
'name' => 'Invalid',
'questionnaires' => [
['questionnaireID' => 'does-not-exist'],
],
], ['Authorization' => 'Bearer ' . $token]);
$this->assertApiError($res, 'INVALID_FIELD', 400);
}
public function testCoachCannotCreateSession(): void
{
$mobile = $this->coachMobileLogin();
$res = $this->api()->request('POST', 'program_sessions', [
'name' => 'Blocked',
], ['Authorization' => 'Bearer ' . $mobile['token']]);
$this->assertApiError($res, 'FORBIDDEN', 403);
}
}