added unit tests

This commit is contained in:
2026-06-04 21:40:59 +02:00
parent d80a8de559
commit 48a619ee4b
64 changed files with 3807 additions and 33 deletions

View File

@ -0,0 +1,183 @@
<?php
declare(strict_types=1);
namespace Tests\Integration;
use Tests\Support\DatabaseSeeder;
use Tests\Support\QdbTestCase;
final class AppSubmitExtendedTest extends QdbTestCase
{
public function testResubmitCreatesSecondSubmissionVersion(): void
{
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::COACH_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$this->assertApiOk($this->submitFixtureQuestionnaire());
$this->assertSame(1, $this->submissionVersionCount($f->clientCode, $f->questionnaireId));
$res = $this->submitQuestionnaireAs($login['token'], $f->questionnaireId, $f->clientCode, [
['questionID' => $f->questionShortId, 'answerOptionKey' => 'yes'],
]);
$this->assertApiOk($res);
$this->assertTrue($res['data']['submitted'] ?? false);
$this->assertSame(2, $this->submissionVersionCount($f->clientCode, $f->questionnaireId));
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
$stmt = $pdo->prepare(
'SELECT COUNT(*) FROM client_answer_submission cas
INNER JOIN questionnaire_submission qs ON qs.submissionID = cas.submissionID
WHERE qs.clientCode = :cc AND qs.questionnaireID = :qn'
);
$stmt->execute([':cc' => $f->clientCode, ':qn' => $f->questionnaireId]);
$this->assertGreaterThanOrEqual(2, (int)$stmt->fetchColumn());
qdb_discard($tmpDb, $lockFp);
}
public function testSupervisorCanSubmitForClient(): void
{
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::SUPERVISOR_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$res = $this->submitQuestionnaireAs($login['token'], $f->questionnaireId, $f->clientCode, [
['questionID' => $f->questionShortId, 'answerOptionKey' => 'yes'],
]);
$this->assertApiOk($res);
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
$stmt = $pdo->prepare(
'SELECT submittedByRole FROM questionnaire_submission
WHERE clientCode = :cc AND questionnaireID = :qn ORDER BY version DESC LIMIT 1'
);
$stmt->execute([':cc' => $f->clientCode, ':qn' => $f->questionnaireId]);
$this->assertSame('supervisor', $stmt->fetchColumn());
qdb_discard($tmpDb, $lockFp);
}
public function testSubmitWithFreeTextAndGlassSymptom(): void
{
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::COACH_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$res = $this->submitQuestionnaireAs($login['token'], $f->questionnaireId, $f->clientCode, [
['questionID' => $f->questionShortId, 'answerOptionKey' => 'yes'],
['questionID' => $f->freeTextShortId, 'freeTextValue' => 'Feeling better'],
['questionID' => $f->glassSymptomKey, 'freeTextValue' => 'moderate'],
]);
$this->assertApiOk($res);
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
$ft = $pdo->prepare(
'SELECT freeTextValue FROM client_answer WHERE clientCode = :cc AND questionID = :qid'
);
$ft->execute([':cc' => $f->clientCode, ':qid' => $f->freeTextQuestionId]);
$this->assertSame('Feeling better', $ft->fetchColumn());
$glass = $pdo->prepare(
'SELECT freeTextValue FROM client_answer WHERE clientCode = :cc AND questionID = :qid'
);
$glass->execute([':cc' => $f->clientCode, ':qid' => $f->glassQuestionId]);
$json = (string)$glass->fetchColumn();
$decoded = json_decode($json, true);
$this->assertIsArray($decoded);
$this->assertSame('moderate', $decoded[$f->glassSymptomKey] ?? null);
qdb_discard($tmpDb, $lockFp);
}
public function testCoachLoadsEncryptedAnswersBundle(): void
{
$this->submitFixtureQuestionnaire();
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::COACH_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$res = $this->api()->withMobileToken($login['token'], 'GET', 'app_questionnaires', null, [
'clientCode' => $f->clientCode,
'answers' => '1',
]);
$this->assertApiOk($res);
$this->assertTrue($res['data']['encrypted'] ?? false);
$plain = qdb_decrypt_sensitive_envelope($res['data'], $login['token']);
$payload = json_decode($plain, true, 512, JSON_THROW_ON_ERROR);
$this->assertSame($f->clientCode, $payload['clientCode']);
$this->assertNotEmpty($payload['questionnaires']);
}
public function testMultiCheckSubmitAccumulatesPoints(): void
{
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::COACH_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$res = $this->submitQuestionnaireAs($login['token'], $f->questionnaireId, $f->clientCode, [
['questionID' => $f->questionShortId, 'answerOptionKey' => 'yes'],
['questionID' => $f->multiCheckShortId, 'answerOptionKey' => 'opt_a'],
['questionID' => $f->multiCheckShortId, 'answerOptionKey' => 'opt_b'],
]);
$this->assertApiOk($res);
$this->assertSame(3, $res['data']['sumPoints'] ?? 0);
}
public function testRequiredQuestionMissingFailsValidation(): void
{
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::COACH_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$res = $this->submitQuestionnaireAs($login['token'], $f->questionnaireId, $f->clientCode, [
['questionID' => $f->freeTextShortId, 'freeTextValue' => 'skipped consent'],
]);
$this->assertApiError($res, 'VALIDATION_FAILED', 400);
$codes = array_column($res['error']['details']['errors'] ?? [], 'code');
$this->assertContains('MISSING_ANSWER', $codes);
}
public function testActiveListExcludesDraftQuestionnaire(): void
{
$login = $this->api()->loginMobileAndGetToken(
DatabaseSeeder::COACH_USERNAME,
DatabaseSeeder::PASSWORD
);
$f = $this->fixture();
$res = $this->api()->withMobileToken($login['token'], 'GET', 'app_questionnaires');
$this->assertApiOk($res);
$ids = array_column($res['data'], 'id');
$this->assertContains($f->questionnaireId, $ids);
$this->assertNotContains($f->draftQuestionnaireId, $ids);
}
public function testTempTokenCannotSubmitQuestionnaire(): void
{
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
$f = $this->fixture();
$pdo->prepare('UPDATE users SET mustChangePassword = 1 WHERE userID = :uid')
->execute([':uid' => $f->supervisorUserId]);
qdb_save($tmpDb, $lockFp);
$login = $this->api()->loginMobile(
DatabaseSeeder::SUPERVISOR_USERNAME,
DatabaseSeeder::PASSWORD
);
$this->assertApiOk($login);
$tempToken = $login['data']['token'];
$res = $this->api()->encryptedPost($tempToken, 'app_questionnaires', [
'questionnaireID' => $f->questionnaireId,
'clientCode' => $f->clientCode,
'answers' => [
['questionID' => $f->questionShortId, 'answerOptionKey' => 'yes'],
],
]);
$this->assertApiError($res, 'PASSWORD_CHANGE_REQUIRED', 403);
}
}