Skip to content

Commit

Permalink
Hide answers; show created ticket directly
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienClairembault authored Feb 18, 2025
1 parent 24d2922 commit 1b461cb
Show file tree
Hide file tree
Showing 25 changed files with 416 additions and 709 deletions.
12 changes: 0 additions & 12 deletions .phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -2401,12 +2401,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Form/AnswersHandler/AnswersHandler.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Form\\\\AnswersSet\\:\\:getTabNameForItem\\(\\) never returns array\\<string\\> so it can be removed from the return type\\.$#',
'identifier' => 'return.unusedType',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Form/AnswersSet.php',
];
$ignoreErrors[] = [
'message' => '#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#',
'identifier' => 'function.alreadyNarrowedType',
Expand All @@ -2419,12 +2413,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Form/Comment.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Form\\\\Destination\\\\AbstractFormDestinationType\\:\\:getTabNameForItem\\(\\) never returns array\\<string\\> so it can be removed from the return type\\.$#',
'identifier' => 'return.unusedType',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Form/Destination/AbstractFormDestinationType.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Form\\\\Destination\\\\CommonITILField\\\\LocationFieldConfig\\:\\:getSpecificLocationID\\(\\) never returns null so it can be removed from the return type\\.$#',
'identifier' => 'return.unusedType',
Expand Down
38 changes: 38 additions & 0 deletions phpunit/functional/Glpi/Form/AnswersHandler/AnswersHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@

namespace tests\units\Glpi\Form\AnswersHandler;

use CommonITILObject;
use DbTestCase;
use Glpi\Form\Answer;
use Glpi\Form\AnswersHandler\AnswersHandler;
use Glpi\Form\Destination\FormDestinationChange;
use Glpi\Form\Destination\FormDestinationProblem;
use Glpi\Form\Destination\FormDestinationTicket;
use Glpi\Form\Question;
use Glpi\Tests\FormBuilder;
use Glpi\Form\Form;
Expand Down Expand Up @@ -175,4 +179,38 @@ private function validateAnswers(
// The `createDestinations` part of the `saveAnswers` method is tested
// by each possible destinations type in their own test file
}

public function testDestinationItemsAreLinkedToForm(): void
{
// Arrange: create a form with its default mandatory destination
$builder = new FormBuilder("My test form");
$builder->addQuestion("Name", QuestionTypeShortText::class);
$builder->addDestination(FormDestinationTicket::class, "Second ticket");
$builder->addDestination(FormDestinationChange::class, "First change");
$builder->addDestination(FormDestinationProblem::class, "First problem");
$form = $this->createForm($builder);

// Act: submit an answer for this form
$answers = $this->sendFormAndGetAnswerSet($form, [
'Name' => 'My test answer',
]);
$created_items = $answers->getCreatedItems();

// Assert: the created ticket should be linked to the form
$this->assertCount(4, $created_items);

foreach ($created_items as $item) {
$this->assertInstanceOf(CommonITILObject::class, $item);

$linked_items = $item->getLinkedItems();
$this->assertCount(1, $linked_items);
$this->assertArrayHasKey(Form::class, $linked_items);

$linked_forms_ids = $linked_items[Form::class];
$this->assertCount(1, $linked_forms_ids);

$linked_forms_id = current($linked_forms_ids);
$this->assertEquals($form->getID(), $linked_forms_id);
}
}
}
230 changes: 0 additions & 230 deletions phpunit/functional/Glpi/Form/AnswersSetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,96 +43,16 @@
use Glpi\Form\Destination\FormDestinationProblem;
use Glpi\Form\Form;
use Glpi\Form\Question;
use Glpi\Form\QuestionType\QuestionTypeAssignee;
use Glpi\Form\QuestionType\QuestionTypeObserver;
use Glpi\Form\QuestionType\QuestionTypeRequester;
use Glpi\Form\Destination\FormDestinationTicket;
use Glpi\Form\QuestionType\QuestionTypeActorsExtraDataConfig;
use Glpi\Form\QuestionType\QuestionTypeCheckbox;
use Glpi\Form\QuestionType\QuestionTypeDateTime;
use Glpi\Form\QuestionType\QuestionTypeDropdown;
use Glpi\Form\QuestionType\QuestionTypeEmail;
use Glpi\Form\QuestionType\QuestionTypeFile;
use Glpi\Form\QuestionType\QuestionTypeItem;
use Glpi\Form\QuestionType\QuestionTypeItemDropdown;
use Glpi\Form\QuestionType\QuestionTypeLongText;
use Glpi\Form\QuestionType\QuestionTypeNumber;
use Glpi\Form\QuestionType\QuestionTypeRequestType;
use Glpi\Form\QuestionType\QuestionTypeRadio;
use Glpi\Form\QuestionType\QuestionTypeShortText;
use Glpi\Form\QuestionType\QuestionTypesManager;
use Glpi\Form\QuestionType\QuestionTypeUrgency;
use Glpi\Form\QuestionType\QuestionTypeUserDevice;
use Glpi\Tests\FormBuilder;
use Glpi\Tests\FormTesterTrait;
use Group;
use Impact;
use PHPUnit\Framework\Attributes\DataProvider;
use Supplier;
use Ticket;
use User;

class AnswersSetTest extends DbTestCase
{
use FormTesterTrait;

public function testGetTabNameForFormWithoutQuestion(): void
{
$this->login();

$_SESSION['glpishow_count_on_tabs'] = true;
$form = $this->createForm(new FormBuilder());

$this->checkGetTabNameForItem($form, "Form answers");
}

public function testGetTabNameForFormWithQuestionsWithCountEnabled(): void
{
$this->login();

$_SESSION['glpishow_count_on_tabs'] = true;
$form = $this->createAndGetFormWithTwoAnswers();

$this->checkGetTabNameForItem($form, "Form answers 2");
}

public function testGetTabNameForFormWithQuestionsWithCountDisabled(): void
{
$this->login();

$_SESSION['glpishow_count_on_tabs'] = false;
$form = $this->createAndGetFormWithTwoAnswers();

$this->checkGetTabNameForItem($form, "Form answers");
}

private function checkGetTabNameForItem(
CommonGLPI $item,
string|false $expected_tab_name,
): void {
$answers_set = new AnswersSet();

$tab_name = $answers_set->getTabNameForItem($item);

// Strip tags to keep only the relevant data
$tab_name = strip_tags($tab_name);

$this->assertEquals($expected_tab_name, $tab_name);
}

public function testDisplayTabContentForItem(): void
{
$this->login();
$answers_set = new AnswersSet();
$form = $this->createAndGetFormWithTwoAnswers();

ob_start();
$return = $answers_set->displayTabContentForItem($form);
ob_end_clean();

$this->assertTrue($return);
}

/**
* Test the "getAnswers" method
*
Expand Down Expand Up @@ -160,156 +80,6 @@ public function testGetAnswer(): void
$this->assertEquals($expected_answer, $answers_set->getAnswers());
}

/**
* Test the "showForm" method
*
* Note: the HTML content itself is not verified here as it would be too
* complex.
* It should be verified using a separate E2E test instead.
* Any error while rendering the tab will still be caught by this tests so
* we must try to send the most complex answers set possible.
*
* @return void
*/
public function testShowForm(): void
{
$this->login();
$answers_handler = AnswersHandler::getInstance();
$types_manager = QuestionTypesManager::getInstance();

// Create a form with each possible types of questions and multiple sections
$form = $this->createForm(
(new FormBuilder())
->addQuestion("Name", QuestionTypeShortText::class)
->addQuestion("Age", QuestionTypeNumber::class)
->addSection("Second section")
->addQuestion("Email", QuestionTypeEmail::class)
->addQuestion("Address", QuestionTypeLongText::class)
->addSection("Third section")
->addQuestion("Date", QuestionTypeDateTime::class)
->addQuestion("Time", QuestionTypeDateTime::class, '', json_encode(['is_time_enabled' => 1]))
->addQuestion("DateTime", QuestionTypeDateTime::class, '', json_encode([
'is_date_enabled' => 1,
'is_time_enabled' => 1
]))
->addQuestion(
"Requester",
QuestionTypeRequester::class,
'',
json_encode((new QuestionTypeActorsExtraDataConfig(true))->jsonSerialize())
)
->addQuestion(
"Observer",
QuestionTypeObserver::class,
'',
json_encode((new QuestionTypeActorsExtraDataConfig(true))->jsonSerialize())
)
->addQuestion(
"Assignee",
QuestionTypeAssignee::class,
'',
json_encode((new QuestionTypeActorsExtraDataConfig(true))->jsonSerialize())
)
->addQuestion("Urgency", QuestionTypeUrgency::class)
->addQuestion("Request type", QuestionTypeRequestType::class)
->addQuestion("Radio", QuestionTypeRadio::class, '123', json_encode([
'options' => [
123 => 'Radio 1'
]
]))
->addQuestion("Checkbox", QuestionTypeCheckbox::class, '123', json_encode([
'options' => [
123 => 'Checkbox 1'
]
]))
->addQuestion("File", QuestionTypeFile::class)
->addQuestion("Dropdown", QuestionTypeDropdown::class, '123', json_encode([
'options' => [
123 => 'Dropdown 1'
]
]))
->addQuestion("GLPI Objects", QuestionTypeItem::class, 0, json_encode(['itemtype' => 'User']))
->addQuestion("User Devices", QuestionTypeUserDevice::class)
->addQuestion("Dropdowns", QuestionTypeItemDropdown::class, 0, json_encode(['itemtype' => 'Location']))
);

// File question type requires an uploaded file
$unique_id = uniqid();
$filename = $unique_id . '-test-show-form-question-type-file.txt';
copy(FIXTURE_DIR . '/uploads/bar.txt', GLPI_TMP_DIR . '/' . $filename);
$question = Question::getById($this->getQuestionId($form, "File"));
$_POST['_prefix_' . $question->getEndUserInputName()] = $unique_id;

// Create a group and a supplier to test the assignee question type
$group = $this->createItem(Group::class, ['name' => 'Group']);
$supplier = $this->createItem(Supplier::class, [
'name' => 'Supplier',
'entities_id' => $this->getTestRootEntity(true)
]);

$answers_set = $answers_handler->saveAnswers($form, [
$this->getQuestionId($form, "Name") => "Pierre Paul Jacques",
$this->getQuestionId($form, "Age") => 20,
$this->getQuestionId($form, "Email") => "[email protected]",
$this->getQuestionId($form, "Address") => "France",
$this->getQuestionId($form, "Date") => "2021-01-01",
$this->getQuestionId($form, "Time") => "12:00",
$this->getQuestionId($form, "DateTime") => "2021-01-01 12:00:00",
$this->getQuestionId($form, "Requester") => [
sprintf('%s-%d', User::getForeignKeyField(), getItemByTypeName(User::class, 'glpi', true)),
sprintf('%s-%d', Group::getForeignKeyField(), $group->getID())
],
$this->getQuestionId($form, "Observer") => [
sprintf('%s-%d', User::getForeignKeyField(), getItemByTypeName(User::class, 'glpi', true)),
sprintf('%s-%d', Group::getForeignKeyField(), $group->getID()),
],
$this->getQuestionId($form, "Assignee") => [
sprintf('%s-%d', User::getForeignKeyField(), getItemByTypeName(User::class, 'glpi', true)),
sprintf('%s-%d', Group::getForeignKeyField(), $group->getID()),
sprintf('%s-%d', Supplier::getForeignKeyField(), $supplier->getID())
],
$this->getQuestionId($form, "Urgency") => 2,
$this->getQuestionId($form, "Request type") => 1,
$this->getQuestionId($form, "File") => [$filename],
$this->getQuestionId($form, "Radio") => 'Radio 1',
$this->getQuestionId($form, "Checkbox") => 'Checkbox 1',
$this->getQuestionId($form, "Dropdown") => 'Dropdown 1',
$this->getQuestionId($form, "GLPI Objects") => [
'itemtype' => 'User',
'items_id' => 0
],
$this->getQuestionId($form, "User Devices") => 'Computer_0',
$this->getQuestionId($form, "Dropdowns") => [
'itemtype' => 'Location',
'items_id' => 0
],
], \Session::getLoginUserID());

// Ensure we used every possible questions types
// Questions types can have multiple questions in the form
// so we need to check the count of unique types
$possible_types = $types_manager->getQuestionTypes();
$current_questions_types = array_reduce(
$form->getQuestions(),
function ($carry, $question) {
$type = $question->getQuestionType();
if (!in_array($type, $carry)) {
$carry[] = $type;
}

return $carry;
},
[]
);
$this->assertCount(count($possible_types), $current_questions_types);
$this->assertCount(count($form->getQuestions()), $answers_set->getAnswers());

// Render content
ob_start();
$this->assertTrue($answers_set->showForm($answers_set->getID()));
ob_end_clean();
}

/**
* Test the "getCreatedItems" method
*
Expand Down
Loading

0 comments on commit 1b461cb

Please sign in to comment.