From d1eaffb2d93b8b6f7720003bd43f1ce285c7fa2f Mon Sep 17 00:00:00 2001 From: chylex <contact@chylex.com> Date: Fri, 25 Sep 2020 05:33:01 +0200 Subject: [PATCH] Add tests for pagination settings, issue assignees, and issue tasks --- .../acceptance/T004_RegisterAccounts_Cest.php | 1 + .../T051_AccountSettingsAppearance_Cest.php | 13 +- tests/acceptance/T143_IssueEditing_Cest.php | 53 +++++ .../T144_IssueDescriptionTasks_Cest.php | 178 ++++++++++++++++ .../T145_IssueCheckboxTasks_Cest.php | 198 ++++++++++++++++++ ...n_Cest.php => T146_IssueDeletion_Cest.php} | 2 +- 6 files changed, 443 insertions(+), 2 deletions(-) create mode 100644 tests/acceptance/T144_IssueDescriptionTasks_Cest.php create mode 100644 tests/acceptance/T145_IssueCheckboxTasks_Cest.php rename tests/acceptance/{T144_IssueDeletion_Cest.php => T146_IssueDeletion_Cest.php} (98%) diff --git a/tests/acceptance/T004_RegisterAccounts_Cest.php b/tests/acceptance/T004_RegisterAccounts_Cest.php index e0cc8e4..301c6df 100644 --- a/tests/acceptance/T004_RegisterAccounts_Cest.php +++ b/tests/acceptance/T004_RegisterAccounts_Cest.php @@ -132,6 +132,7 @@ class T004_RegisterAccounts_Cest{ $db->exec('UPDATE users SET date_registered = DATE_SUB(NOW(), INTERVAL 2 SECOND) WHERE name = \'User2\''); $db->exec('UPDATE users SET date_registered = DATE_SUB(NOW(), INTERVAL 1 SECOND) WHERE name = \'RoleLess\''); + $db->exec('UPDATE users SET id = \'admintest\' WHERE name = \'Admin\''); $db->exec('UPDATE users SET id = \'user1test\' WHERE name = \'User1\''); $db->exec('UPDATE users SET id = \'user2test\' WHERE name = \'User2\''); $db->exec('UPDATE users SET id = \'user3test\' WHERE name = \'User3\''); diff --git a/tests/acceptance/T051_AccountSettingsAppearance_Cest.php b/tests/acceptance/T051_AccountSettingsAppearance_Cest.php index b20f1ae..6934ccf 100644 --- a/tests/acceptance/T051_AccountSettingsAppearance_Cest.php +++ b/tests/acceptance/T051_AccountSettingsAppearance_Cest.php @@ -7,7 +7,7 @@ use AcceptanceTester; class T051_AccountSettingsAppearance_Cest{ public function _before(AcceptanceTester $I): void{ - $I->amLoggedIn('User3'); + $I->amLoggedIn('Manager2'); $I->amOnPage('/account/appearance'); } @@ -28,6 +28,17 @@ class T051_AccountSettingsAppearance_Cest{ $I->seeElement('#ChangeAppearance-1-TablePaginationElements + .error'); $I->seeInField('#ChangeAppearance-1-TablePaginationElements', 50); } + + public function changeTablePagination(AcceptanceTester $I): void{ + $I->fillField('#ChangeAppearance-1-TablePaginationElements', 6); + $I->click('button[type="submit"]'); + $I->seeElement('form .success'); + $I->seeCookie('pagination_elements'); + $I->assertEquals(6, $I->grabCookie('pagination_elements')); + + $I->amOnPage('/users'); + $I->see('1 to 6 out of 8', 'tfoot .element-info'); + } } ?> diff --git a/tests/acceptance/T143_IssueEditing_Cest.php b/tests/acceptance/T143_IssueEditing_Cest.php index 8ad1ee9..6d119b4 100644 --- a/tests/acceptance/T143_IssueEditing_Cest.php +++ b/tests/acceptance/T143_IssueEditing_Cest.php @@ -99,6 +99,59 @@ class T143_IssueEditing_Cest{ $I->dontSee('RoleLess', '#Confirm-1-Assignee option'); } + public function assigneeDoesNotExist(AcceptanceTester $I): void{ + $I->amLoggedIn('User1'); + $I->amOnPage('/project/p1/issues/1/edit'); + + $I->submitForm('#Confirm-1', [ + 'Assignee' => '000000000' + ]); + + $I->seeElement('#Confirm-1-Assignee + .error'); + } + + public function assigneeIsNotAMember(AcceptanceTester $I): void{ + $I->amLoggedIn('User1'); + $I->amOnPage('/project/p1/issues/1/edit'); + $I->dontSee('Admin', '#Confirm-1-Assignee option'); + + $I->submitForm('#Confirm-1', [ + 'Assignee' => 'admintest' + ]); + + $I->seeElement('#Confirm-1-Assignee + .error'); + } + + public function assigneeIsAFormerMember(AcceptanceTester $I): void{ + Acceptance::getDB()->exec('UPDATE issues SET assignee_id = \'admintest\' WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + + $I->amLoggedIn('User1'); + $I->amOnPage('/project/p1/issues/1/edit'); + $I->see('Admin', '#Confirm-1-Assignee option'); + $I->click('button[type="submit"]'); + + $I->seeCurrentUrlEquals('/project/p1/issues/1'); + $I->see('Admin', '[data-title="Assignee"]'); + + Acceptance::getDB()->exec('UPDATE issues SET assignee_id = NULL WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + } + + public function assigneeIsAFormerMemberAndGetsReassigned(AcceptanceTester $I): void{ + Acceptance::getDB()->exec('UPDATE issues SET assignee_id = \'admintest\' WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + + $I->amLoggedIn('User1'); + $I->amOnPage('/project/p1/issues/1/edit'); + $I->see('Admin', '#Confirm-1-Assignee option'); + $I->selectOption('Assignee', '(None)'); + $I->click('button[type="submit"]'); + + $I->seeCurrentUrlEquals('/project/p1/issues/1'); + $I->see('Nobody', '[data-title="Assignee"]'); + + $I->amOnPage('/project/p1/issues/1/edit'); + $I->dontSee('Admin', '#Confirm-1-Assignee option'); + } + /** * @example ["#MarkReadyToTest", "Ready to Test"] * @example ["#MarkFinished", "Finished"] diff --git a/tests/acceptance/T144_IssueDescriptionTasks_Cest.php b/tests/acceptance/T144_IssueDescriptionTasks_Cest.php new file mode 100644 index 0000000..cb535a7 --- /dev/null +++ b/tests/acceptance/T144_IssueDescriptionTasks_Cest.php @@ -0,0 +1,178 @@ +<?php +declare(strict_types = 1); + +namespace acceptance; + +use AcceptanceTester; +use Codeception\Example; +use Helper\Acceptance; + +class T144_IssueDescriptionTasks_Cest{ + public function _after(AcceptanceTester $I): void{ + Acceptance::getDB()->exec('UPDATE issues SET author_id = \'user1test\', description = \'\', status = \'open\', progress = 0 WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + } + + private function editDescriptionAs(AcceptanceTester $I, string $user, string $desc, ?string $status = null): void{ + $I->amLoggedIn($user); + $I->amOnPage('/project/p1/issues/1/edit'); + $I->fillField('Description', $desc); + + if ($status !== null){ + $I->selectOption('Status', $status); + } + + $I->click('button[type="submit"]'); + $I->seeCurrentUrlEquals('/project/p1/issues/1'); + } + + private function checkIssueDetailStatus(AcceptanceTester $I, string $status, int $progress): void{ + $I->see($status, '[data-title="Status"]'); + $I->see((string)$progress, '[data-title="Progress"] .progress-bar'); + } + + private function generateDescription(array $tasks): string{ + return implode("\n", array_map(fn($v, $k): string => ($v ? '[x]' : '[]').' Task '.$k, $tasks, range(1, count($tasks)))); + } + + /** + * @example [[false, false, false], "Open", 0] + * @example [[true, false, false], "In Progress", 33] + * @example [[false, true, false], "In Progress", 33] + * @example [[false, false, true], "In Progress", 33] + * @example [[true, true, false], "In Progress", 66] + * @example [[false, true, true], "In Progress", 66] + * @example [[true, false, true], "In Progress", 66] + * @example [[true, true, true], "Ready To Test", 100] + */ + public function goingFromNoTasksToMultipleTasksUpdatesStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, $example[1], $example[2]); + } + + /** + * @example [[false, false, false], "In Progress", 0] + * @example [[true, true, false], "In Progress", 66] + * @example [[true, true, true], "Ready To Test", 100] + * @example [[true, true, true, false], "In Progress", 75] + * @example [[true, true], "Ready To Test", 100] + */ + public function updatingInProgressTasksUpdatesStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, false, true])); + $this->checkIssueDetailStatus($I, 'In Progress', 66); + + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, $example[1], $example[2]); + } + + /** + * @example [[false, false, false], "In Progress", 0] + * @example [[true, true, false], "In Progress", 66] + * @example [[true, true, true], "Ready To Test", 100] + * @example [[true, true, true, false], "In Progress", 75] + * @example [[true, true], "Ready To Test", 100] + */ + public function updatingReadyToTestTasksUpdatesStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, true])); + $this->checkIssueDetailStatus($I, 'Ready To Test', 100); + + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, $example[1], $example[2]); + } + + /** + * @example [[false, false, false], 0] + * @example [[true, true, false], 66] + * @example [[true, true, true], 100] + * @example [[true, true, true, false], 75] + * @example [[true, true], 100] + */ + public function updatingBlockedTasksUpdatesOnlyProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, false, true]), 'Blocked'); + $this->checkIssueDetailStatus($I, 'Blocked', 66); + + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, 'Blocked', $example[1]); + } + + /** + * @example [[false, false, false], 0] + * @example [[true, true, false], 66] + * @example [[true, true, true], 100] + * @example [[true, true, true, false], 75] + * @example [[true, true], 100] + */ + public function updatingFinishedTasksUpdatesOnlyProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, true]), 'Finished'); + $this->checkIssueDetailStatus($I, 'Finished', 100); + + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, 'Finished', $example[1]); + } + + /** + * @example [[false, false, false], 0] + * @example [[true, true, false], 66] + * @example [[true, true, true], 100] + * @example [[true, true, true, false], 75] + * @example [[true, true], 100] + */ + public function updatingRejectedTasksUpdatesOnlyProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, true]), 'Rejected'); + $this->checkIssueDetailStatus($I, 'Rejected', 100); + + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, 'Rejected', $example[1]); + } + + /** + * @example [[true, false], "Open"] + * @example [[true, false], "In Progress"] + * @example [[true, false], "Ready To Test"] + * @example [[true, false], "Finished"] + * @example [[true, false], "Rejected"] + * @example [[true, false], "Blocked"] + */ + public function removingTasksDoesNotUpdateStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0]), $example[1]); + + if ($example[1] === 'Open'){ + // counts as unchanged status so it's automatically set to in-progress unlike other statuses + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0]), $example[1]); + } + + $this->checkIssueDetailStatus($I, $example[1], 50); + + $this->editDescriptionAs($I, 'User1', ''); + $this->checkIssueDetailStatus($I, $example[1], 50); + } + + /** + * @example [[true]] + * @example [[false]] + * @example [[true, true, false]] + * @example [[true, true, true]] + */ + public function memberWithReporterRoleCannotUpdateStatusAndProgressByCreatingTasks(AcceptanceTester $I, Example $example): void{ + Acceptance::getDB()->exec('UPDATE issues SET author_id = \'user3test\' WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + $this->editDescriptionAs($I, 'User3', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, 'Open', 0); + } + + /** + * @example [[]] + * @example [[true]] + * @example [[false]] + * @example [[true, true, false]] + * @example [[true, true, true]] + */ + public function memberWithReporterRoleCannotUpdateStatusAndProgressByChangingTasks(AcceptanceTester $I, Example $example): void{ + Acceptance::getDB()->exec('UPDATE issues SET author_id = \'user3test\' WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, false])); + $this->checkIssueDetailStatus($I, 'In Progress', 66); + + $this->editDescriptionAs($I, 'User3', $this->generateDescription($example[0])); + $this->checkIssueDetailStatus($I, 'In Progress', 66); + } +} + +?> diff --git a/tests/acceptance/T145_IssueCheckboxTasks_Cest.php b/tests/acceptance/T145_IssueCheckboxTasks_Cest.php new file mode 100644 index 0000000..fe68987 --- /dev/null +++ b/tests/acceptance/T145_IssueCheckboxTasks_Cest.php @@ -0,0 +1,198 @@ +<?php +declare(strict_types = 1); + +namespace acceptance; + +use AcceptanceTester; +use Codeception\Example; +use Helper\Acceptance; + +class T145_IssueCheckboxTasks_Cest{ + public function _after(AcceptanceTester $I): void{ + Acceptance::getDB()->exec('UPDATE issues SET milestone_id = NULL, description = \'\', status = \'open\', progress = 0 WHERE project_id = '.Acceptance::getProjectId($I, 'p1').' AND issue_id = 1'); + } + + private function editDescriptionAs(AcceptanceTester $I, string $user, string $desc, ?string $status = null): void{ + $I->amLoggedIn($user); + $I->amOnPage('/project/p1/issues/1/edit'); + $I->fillField('Description', $desc); + + if ($status !== null){ + $I->selectOption('Status', $status); + } + + $I->click('button[type="submit"]'); + $I->seeCurrentUrlEquals('/project/p1/issues/1'); + } + + private function submitCheckBoxes(AcceptanceTester $I, array $task_status){ + foreach($task_status as $task => $checked){ + if ($checked){ + $I->checkOption('#Tasks-'.($task + 1)); + } + else{ + $I->uncheckOption('#Tasks-'.($task + 1)); + } + } + + $I->click('article[data-task-submit] button[type="submit"]'); + } + + private function validateCheckBoxes(AcceptanceTester $I, array $task_status){ + foreach($task_status as $task => $checked){ + if ($checked){ + $I->seeCheckboxIsChecked('#Tasks-'.($task + 1)); + } + else{ + $I->dontSeeCheckboxIsChecked('#Tasks-'.($task + 1)); + } + } + } + + private function checkIssueDetailStatus(AcceptanceTester $I, string $status, int $progress): void{ + $I->see($status, '[data-title="Status"]'); + $I->see((string)$progress, '[data-title="Progress"] .progress-bar'); + } + + private function postAjaxTasks(AcceptanceTester $I, array $tasks): void{ + $I->sendAjaxPostRequest('/project/p1/issues/1', [ + '_Action' => 'Update', + 'Tasks' => array_values(array_filter(array_map(fn($v, $id) => $v ? $id : null, $tasks, range(1, count($tasks))), fn($v): bool => $v !== null)), + ]); + } + + private function generateDescription(array $tasks): string{ + return implode("\n", array_map(fn($v, $k): string => ($v ? '[x]' : '[]').' Task '.$k, $tasks, range(1, count($tasks)))); + } + + /** + * @example [[false, false, false], "Open", 0] + * @example [[true, false, false], "In Progress", 33] + * @example [[false, true, false], "In Progress", 33] + * @example [[false, false, true], "In Progress", 33] + * @example [[true, true, false], "In Progress", 66] + * @example [[false, true, true], "In Progress", 66] + * @example [[true, false, true], "In Progress", 66] + * @example [[true, true, true], "Ready To Test", 100] + */ + public function checkingTasksUpdatesStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([false, false, false])); + $this->submitCheckBoxes($I, $example[0]); + $this->checkIssueDetailStatus($I, $example[1], $example[2]); + $this->validateCheckBoxes($I, $example[0]); + } + + /** + * @example [[false, false, false], "In Progress", 0] + * @example [[true, true, false], "In Progress", 66] + * @example [[true, true, true], "Ready To Test", 100] + */ + public function updatingInProgressTasksUpdatesStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, false, true])); + $this->checkIssueDetailStatus($I, 'In Progress', 66); + $this->submitCheckBoxes($I, $example[0]); + $this->checkIssueDetailStatus($I, $example[1], $example[2]); + $this->validateCheckBoxes($I, $example[0]); + } + + /** + * @example [[false, false, false], "In Progress", 0] + * @example [[true, true, false], "In Progress", 66] + * @example [[true, true, true], "Ready To Test", 100] + */ + public function updatingReadyToTestTasksUpdatesStatusAndProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, true])); + $this->checkIssueDetailStatus($I, 'Ready To Test', 100); + $this->submitCheckBoxes($I, $example[0]); + $this->checkIssueDetailStatus($I, $example[1], $example[2]); + $this->validateCheckBoxes($I, $example[0]); + } + + /** + * @example [[false, false, false], 0] + * @example [[true, true, false], 66] + * @example [[true, true, true], 100] + */ + public function updatingBlockedTasksUpdatesOnlyProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, false, true]), 'Blocked'); + $this->checkIssueDetailStatus($I, 'Blocked', 66); + $this->submitCheckBoxes($I, $example[0]); + $this->checkIssueDetailStatus($I, 'Blocked', $example[1]); + $this->validateCheckBoxes($I, $example[0]); + } + + /** + * @example [[false, false, false], 0] + * @example [[true, true, false], 66] + * @example [[true, true, true], 100] + */ + public function updatingFinishedTasksUpdatesOnlyProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, true]), 'Finished'); + $this->checkIssueDetailStatus($I, 'Finished', 100); + $this->submitCheckBoxes($I, $example[0]); + $this->checkIssueDetailStatus($I, 'Finished', $example[1]); + $this->validateCheckBoxes($I, $example[0]); + } + + /** + * @example [[false, false, false], 0] + * @example [[true, true, false], 66] + * @example [[true, true, true], 100] + */ + public function updatingRejectedTasksUpdatesOnlyProgress(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription([true, true, true]), 'Rejected'); + $this->checkIssueDetailStatus($I, 'Rejected', 100); + $this->submitCheckBoxes($I, $example[0]); + $this->checkIssueDetailStatus($I, 'Rejected', $example[1]); + $this->validateCheckBoxes($I, $example[0]); + } + + /** + * @example [[false, false, false], [false, false, false], "Open", 0] + * @example [[false, false, false], [true, true, false], "In Progress", 66] + * @example [[false, false, false], [true, true, true], "Ready To Test", 100] + * @example [[false, false, true], [false, true, true], "In Progress", 66] + * @example [[true, true, true], [false, false, false], "In Progress", 0] + * @example [[true, true, true], [true, false, false], "In Progress", 33] + * @example [[true, true, true], [true, true, true], "Ready To Test", 100] + */ + public function updateCheckboxesViaAjax(AcceptanceTester $I, Example $example): void{ + $this->editDescriptionAs($I, 'User1', $this->generateDescription($example[0])); + + $I->haveHttpHeader('Accept', 'application/json'); + $this->postAjaxTasks($I, $example[1]); + $I->seeResponseCodeIsSuccessful(); + $response = json_decode($I->grabPageSource(), true); + + $I->assertStringContainsString($example[2], $response['issue_status']); + $I->assertEquals($example[3], $response['issue_progress']); + $I->assertNull($response['active_milestone']); + } + + /** + * @example [[false, false, false], "Open", 0, 68] + * @example [[true, false, false], "In Progress", 33, 78] + * @example [[true, true, false], "In Progress", 66, 89] + * @example [[true, true, true], "Ready To Test", 100, 100] + */ + public function updateCheckboxesViaAjaxWithActiveMilestone(AcceptanceTester $I, Example $example): void{ + $project_id = Acceptance::getProjectId($I, 'p1'); + $db = Acceptance::getDB(); + $db->exec('UPDATE issues SET milestone_id = 2 WHERE project_id = '.$project_id.' AND issue_id = 1'); + $db->exec('INSERT INTO project_user_settings (project_id, user_id, active_milestone) VALUES ('.$project_id.', \'user1test\', 2) ON DUPLICATE KEY UPDATE active_milestone = VALUES(active_milestone)'); + $this->editDescriptionAs($I, 'User1', $this->generateDescription([false, false, false])); + + $I->haveHttpHeader('Accept', 'application/json'); + $this->postAjaxTasks($I, $example[0]); + $I->seeResponseCodeIsSuccessful(); + $response = json_decode($I->grabPageSource(), true); + + $I->assertStringContainsString($example[1], $response['issue_status']); + $I->assertEquals($example[2], $response['issue_progress']); + $I->assertEquals($example[3], $response['active_milestone']); + + $db->exec('UPDATE project_user_settings SET active_milestone = NULL WHERE user_id = \'user1test\' AND project_id = '.$project_id); + } +} + +?> diff --git a/tests/acceptance/T144_IssueDeletion_Cest.php b/tests/acceptance/T146_IssueDeletion_Cest.php similarity index 98% rename from tests/acceptance/T144_IssueDeletion_Cest.php rename to tests/acceptance/T146_IssueDeletion_Cest.php index 7450805..8d61317 100644 --- a/tests/acceptance/T144_IssueDeletion_Cest.php +++ b/tests/acceptance/T146_IssueDeletion_Cest.php @@ -6,7 +6,7 @@ namespace acceptance; use AcceptanceTester; use Helper\Acceptance; -class T144_IssueDeletion_Cest{ +class T146_IssueDeletion_Cest{ public function _before(AcceptanceTester $I): void{ $I->amLoggedIn('User1'); }