diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5777b0..e5b4d8b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Implement `Field` question type for new GLPI forms +- Bind the answers to the `Field` question type to the corresponding additional fields ## [1.22.2] - 2025-10-24 diff --git a/inc/destinationfield.class.php b/inc/destinationfield.class.php new file mode 100644 index 00000000..96348fbd --- /dev/null +++ b/inc/destinationfield.class.php @@ -0,0 +1,162 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2013-2023 by Fields plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/fields + * ------------------------------------------------------------------------- + */ + +use Glpi\Application\View\TemplateRenderer; +use Glpi\DBAL\JsonFieldInterface; +use Glpi\Form\AnswersSet; +use Glpi\Form\Destination\AbstractCommonITILFormDestination; +use Glpi\Form\Destination\AbstractConfigField; +use Glpi\Form\Destination\CommonITILField\Category; +use Glpi\Form\Destination\CommonITILField\SimpleValueConfig; +use Glpi\Form\Destination\FormDestination; +use Glpi\Form\Form; +use Glpi\Form\Question; +use Glpi\Form\QuestionType\QuestionTypeItemDropdown; + +class PluginFieldsDestinationField extends AbstractConfigField +{ + public function __construct(private AbstractCommonITILFormDestination $itil_destination) {} + + #[Override] + public function getLabel(): string + { + return __('Additional fields', 'fields'); + } + + #[Override] + public function getConfigClass(): string + { + return SimpleValueConfig::class; + } + + #[Override] + public function renderConfigForm( + Form $form, + FormDestination $destination, + JsonFieldInterface $config, + string $input_name, + array $display_options + ): string { + if (!$config instanceof SimpleValueConfig) { + throw new InvalidArgumentException("Unexpected config class"); + } + + $twig = TemplateRenderer::getInstance(); + return $twig->render('@fields/destinationfield.html.twig', [ + 'value' => $config->getValue(), + 'input_name' => $input_name . "[" . SimpleValueConfig::VALUE . "]", + 'options' => $display_options, + ]); + } + + #[Override] + public function applyConfiguratedValueToInputUsingAnswers( + JsonFieldInterface $config, + array $input, + AnswersSet $answers_set + ): array { + if (!$config instanceof SimpleValueConfig) { + throw new InvalidArgumentException("Unexpected config class"); + } + + if ((bool) $config->getValue()) { + $answers = $answers_set->getAnswersByTypes([ + PluginFieldsQuestionType::class, + QuestionTypeItemDropdown::class, + ]); + + foreach ($answers as $answer) { + $question = Question::getById($answer->getQuestionId()); + $block_id = PluginFieldsContainer::findContainer($this->itil_destination->getTarget()::class, 'dom'); + if (!$block_id) { + continue; + } + + if ($question->getQuestionType() instanceof QuestionTypeItemDropdown) { + $itemtype = (new QuestionTypeItemDropdown())->getDefaultValueItemtype($question); + $field_name = $itemtype::getForeignKeyField(); + if (!str_starts_with($field_name, 'plugin_fields_')) { + continue; + } + + /** @var object{field_name: string} $item */ + $item = getItemForItemtype($itemtype); + $field = new PluginFieldsField(); + if (!$field->getFromDBByCrit(['name' => $item->field_name])) { + continue; + } + + $value = $answer->getRawAnswer()['items_id']; + } else { + $field_id = (new PluginFieldsQuestionType())->getDefaultValueFieldId($question); + $field = PluginFieldsField::getById($field_id); + } + + // Check that the field belongs to the correct block + if ($block_id != $field->fields[PluginFieldsContainer::getForeignKeyField()]) { + continue; + } + + $input['c_id'] = $block_id; + if ($field->fields['type'] == 'dropdown') { + $field_name = 'plugin_fields_' . $field->fields['name'] . 'dropdowns_id'; + } else { + $field_name = $field->fields['name']; + } + + if ($field->fields['type'] == 'glpi_item') { + $input[sprintf('itemtype_%s', $field_name)] = $answer->getRawAnswer()['itemtype']; + $input[sprintf('items_id_%s', $field_name)] = $answer->getRawAnswer()['items_id']; + } else { + $input[$field_name] = $value ?? $answer->getRawAnswer(); + } + } + } + return $input; + } + + #[Override] + public function getDefaultConfig(Form $form): SimpleValueConfig + { + return new SimpleValueConfig("1"); + } + + #[Override] + public function getWeight(): int + { + return 1000; + } + + #[Override] + public function getCategory(): Category + { + return Category::PROPERTIES; + } +} diff --git a/inc/questiontype.class.php b/inc/questiontype.class.php index 13427ec1..2d2df5bd 100644 --- a/inc/questiontype.class.php +++ b/inc/questiontype.class.php @@ -205,6 +205,11 @@ public function formatRawAnswer(mixed $answer, Question $question): string case 'datetime': return (new DateTime($answer))->format('Y-m-d H:i'); case 'glpi_item': + $itemtype = $answer['itemtype']; + if (!is_a($itemtype, CommonDBTM::class, true)) { + return ''; + } + $item = $answer['itemtype']::getById($answer['items_id']); if (!$item) { return ''; @@ -219,10 +224,17 @@ public function formatRawAnswer(mixed $answer, Question $question): string return ''; } - if (is_string($answer)) { + if (!is_array($answer)) { $answer = [$answer]; } - return implode(', ', array_map(fn($items_id) => $itemtype::getById($items_id)->fields['name'], $answer)); + $names = []; + foreach ($answer as $items_id) { + $item = $itemtype::getById($items_id); + if ($item) { + $names[] = $item->fields['name']; + } + } + return implode(', ', $names); } return (string) $answer; diff --git a/public/css/fields.scss b/public/css/fields.scss index 15c09b06..f0314940 100644 --- a/public/css/fields.scss +++ b/public/css/fields.scss @@ -89,3 +89,9 @@ div.fields_clear { } } } + +.glpi-fields-plugin-question-type-glpi-destination-toggle { + .field-container > label { + margin-top: 0 !important; + } +} diff --git a/setup.php b/setup.php index 88004591..9ea1cc2c 100644 --- a/setup.php +++ b/setup.php @@ -65,7 +65,10 @@ if (!file_exists(PLUGINFIELDS_FRONT_PATH)) { mkdir(PLUGINFIELDS_FRONT_PATH); } - +use Glpi\Form\Destination\FormDestinationChange; +use Glpi\Form\Destination\FormDestinationManager; +use Glpi\Form\Destination\FormDestinationProblem; +use Glpi\Form\Destination\FormDestinationTicket; use Glpi\Form\Migration\TypesConversionMapper; use Glpi\Form\QuestionType\QuestionTypesManager; use Symfony\Component\Yaml\Yaml; @@ -399,11 +402,29 @@ function plugin_fields_register_plugin_types(): void { $types = QuestionTypesManager::getInstance(); $type_mapper = TypesConversionMapper::getInstance(); + $destination_manager = FormDestinationManager::getInstance(); // Register question category, type and converter if valid fields are defined if (PluginFieldsQuestionType::hasAvailableFields()) { + // Register question category $types->registerPluginCategory(new PluginFieldsQuestionTypeCategory()); + + // Register question type $types->registerPluginQuestionType(new PluginFieldsQuestionType()); + + // Register common ITIL field for tickets, changes and problems + foreach ([ + new FormDestinationTicket(), + new FormDestinationChange(), + new FormDestinationProblem(), + ] as $itil_destination) { + $destination_manager->registerPluginCommonITILConfigField( + $itil_destination::class, + new PluginFieldsDestinationField($itil_destination), + ); + } + + // Register converter for migration $type_mapper->registerPluginQuestionTypeConverter('fields', new PluginFieldsQuestionType()); } } diff --git a/templates/destinationfield.html.twig b/templates/destinationfield.html.twig new file mode 100644 index 00000000..f3daf6ad --- /dev/null +++ b/templates/destinationfield.html.twig @@ -0,0 +1,42 @@ +{# + # ------------------------------------------------------------------------- + # Fields plugin for GLPI + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of Fields. + # + # Fields is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation; either version 2 of the License, or + # (at your option) any later version. + # + # Fields is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with Fields. If not, see . + # ------------------------------------------------------------------------- + # @copyright Copyright (C) 2013-2023 by Fields plugin team. + # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + # @link https://github.com/pluginsGLPI/fields + # ------------------------------------------------------------------------- + #} + +{% import 'components/form/fields_macros.html.twig' as fields %} + +{{ fields.sliderField( + input_name, + value, + __('Bind additional fields to the destination', 'fields'), + options|merge({ + 'field_class': 'glpi-fields-plugin-question-type-glpi-destination-toggle', + 'label_class': 'col fw-normal pt-0', + 'input_class': 'col-auto', + 'label_align': 'start', + 'mb' : '', + }) +) }} diff --git a/tests/FieldTestCase.php b/tests/FieldTestCase.php index 5322a600..d9c067f1 100644 --- a/tests/FieldTestCase.php +++ b/tests/FieldTestCase.php @@ -31,15 +31,21 @@ namespace GlpiPlugin\Field\Tests; use DBmysql; -use DbTestCase; use PluginFieldsContainer; +use PluginFieldsField; -abstract class FieldTestCase extends DbTestCase +trait FieldTestTrait { + /** @var PluginFieldsContainer[] */ private static array $createdContainers = []; + /** @var PluginFieldsField[] */ + private static array $createdFields = []; - public function tearDown(): void + public function tearDownFieldTest(): void { + // Re-login to ensure we are logged in + $this->login(); + // Clean created containers array_map( fn(PluginFieldsContainer $container) => $container->delete($container->fields, true), @@ -47,18 +53,53 @@ public function tearDown(): void ); self::$createdContainers = []; + // Clean created fields + array_map( + fn(PluginFieldsField $field) => $field->delete($field->fields, true), + self::$createdFields, + ); + self::$createdFields = []; + /** @var DBmysql $DB */ global $DB; $DB->clearSchemaCache(); - - parent::tearDown(); } public function createFieldContainer(array $inputs): PluginFieldsContainer { + // Re-login to ensure we are logged in + $this->login(); + $container = $this->createItem(PluginFieldsContainer::class, $inputs, ['itemtypes']); self::$createdContainers[] = $container; + // Re-initialize fields plugin to register new container logic + plugin_init_fields(); + + // Clear DB schema cache to avoid issues with new container + /** @var DBmysql $DB */ + global $DB; + $DB->clearSchemaCache(); + return $container; } + + public function createField(array $inputs): PluginFieldsField + { + // Re-login to ensure we are logged in + $this->login(); + + $field = $this->createItem(PluginFieldsField::class, $inputs, ['allowed_values', 'question_types']); + self::$createdFields[] = $field; + + // Re-initialize fields plugin to register new field logic + plugin_init_fields(); + + // Clear DB schema cache to avoid issues with new field + /** @var DBmysql $DB */ + global $DB; + $DB->clearSchemaCache(); + + return $field; + } } diff --git a/tests/QuestionTypeTestCase.php b/tests/QuestionTypeTestCase.php index 5cb76d20..1e3a1609 100644 --- a/tests/QuestionTypeTestCase.php +++ b/tests/QuestionTypeTestCase.php @@ -30,10 +30,9 @@ namespace GlpiPlugin\Field\Tests; +use DbTestCase; use Glpi\Controller\Form\RendererController; use Glpi\Form\Form; -use Glpi\Form\Migration\TypesConversionMapper; -use Glpi\Form\QuestionType\QuestionTypesManager; use Glpi\Tests\FormTesterTrait; use PluginFieldsContainer; use PluginFieldsField; @@ -42,9 +41,10 @@ use Symfony\Component\HttpFoundation\Request; use Ticket; -abstract class QuestionTypeTestCase extends FieldTestCase +abstract class QuestionTypeTestCase extends DbTestCase { use FormTesterTrait; + use FieldTestTrait; protected ?PluginFieldsContainer $block = null; protected ?PluginFieldsField $field = null; @@ -60,30 +60,25 @@ public function createFieldAndContainer(): void 'entities_id' => $this->getTestRootEntity(true), ]); - $this->field = $this->createItem(PluginFieldsField::class, [ + $this->field = $this->createField([ 'label' => 'GLPI Item', 'type' => 'glpi_item', PluginFieldsContainer::getForeignKeyField() => $this->block->getID(), - 'ranking' => 2, + 'ranking' => 1, 'is_active' => 1, ]); - - // Register plugin question types - plugin_fields_register_plugin_types(); } public function setUp(): void { + $this->createFieldAndContainer(); parent::setUp(); + } - // Delete form related single instances - $this->deleteSingletonInstance([ - QuestionTypesManager::class, - TypesConversionMapper::class, - ]); - - // Login - $this->login(); + public function tearDown(): void + { + parent::tearDown(); + $this->tearDownFieldTest(); } protected function renderFormEditor(Form $form): Crawler @@ -110,7 +105,7 @@ protected function renderHelpdeskForm(Form $form): Crawler return new Crawler($response->getContent()); } - private function deleteSingletonInstance(array $classes) + protected function deleteSingletonInstance(array $classes) { foreach ($classes as $class) { $reflection_class = new ReflectionClass($class); diff --git a/tests/Units/FieldDestinationFieldTest.php b/tests/Units/FieldDestinationFieldTest.php new file mode 100644 index 00000000..603dae98 --- /dev/null +++ b/tests/Units/FieldDestinationFieldTest.php @@ -0,0 +1,349 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2013-2023 by Fields plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/fields + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Field\Tests\Units; + +use CommonITILObject; +use Glpi\Form\AnswersHandler\AnswersHandler; +use Glpi\Form\Destination\CommonITILField\SimpleValueConfig; +use Glpi\Form\Destination\FormDestinationProblem; +use Glpi\Form\Form; +use Glpi\Form\QuestionType\QuestionTypeShortText; +use Glpi\Tests\FormBuilder; +use Glpi\Tests\FormTesterTrait; +use GlpiPlugin\Field\Tests\FieldTestTrait; +use Group; +use Location; +use Override; +use PluginFieldsContainer; +use PluginFieldsDestinationField; +use PluginFieldsQuestionType; +use Problem; +use tests\units\Glpi\Form\Destination\CommonITILField\AbstractDestinationFieldTest; +use Ticket; +use User; + +include_once __DIR__ . '/../../../../tests/abstracts/AbstractDestinationFieldTest.php'; + +final class FieldDestinationFieldTest extends AbstractDestinationFieldTest +{ + use FormTesterTrait; + use FieldTestTrait; + + private array $blocks = []; + private array $fields = []; + + private function initFieldTest(): void + { + $this->blocks[Ticket::class] = $this->createFieldContainer([ + 'label' => 'Ticket additional fields', + 'type' => 'dom', + 'itemtypes' => [Ticket::class], + 'is_active' => 1, + 'entities_id' => $this->getTestRootEntity(true), + ]); + $this->blocks[Problem::class] = $this->createFieldContainer([ + 'label' => 'Problem additional fields', + 'type' => 'dom', + 'itemtypes' => [Problem::class], + 'is_active' => 1, + 'entities_id' => $this->getTestRootEntity(true), + ]); + + $this->fields[] = $this->createField([ + 'label' => 'Short text', + 'type' => 'text', + PluginFieldsContainer::getForeignKeyField() => $this->blocks[Ticket::class]->getID(), + 'ranking' => 1, + 'is_active' => 1, + 'is_readonly' => 0, + ]); + $this->fields[] = $this->createField([ + 'label' => 'GLPI Item', + 'type' => 'glpi_item', + PluginFieldsContainer::getForeignKeyField() => $this->blocks[Ticket::class]->getID(), + 'ranking' => 2, + 'is_active' => 1, + 'is_readonly' => 0, + 'allowed_values' => [User::class, Group::class], + ], ['allowed_values']); + $this->fields[] = $this->createField([ + 'label' => 'Short text', + 'type' => 'text', + PluginFieldsContainer::getForeignKeyField() => $this->blocks[Problem::class]->getID(), + 'ranking' => 1, + 'is_active' => 1, + 'is_readonly' => 0, + ]); + $this->fields[] = $this->createField([ + 'label' => 'GLPI Item', + 'type' => 'glpi_item', + PluginFieldsContainer::getForeignKeyField() => $this->blocks[Problem::class]->getID(), + 'ranking' => 2, + 'is_active' => 1, + 'is_readonly' => 0, + 'allowed_values' => [User::class, Group::class], + ], ['allowed_values']); + $this->fields[] = $this->createField([ + 'label' => 'Location Field', + 'type' => 'dropdown-Location', + PluginFieldsContainer::getForeignKeyField() => $this->blocks[Ticket::class]->getID(), + 'ranking' => 3, + 'is_active' => 1, + 'is_readonly' => 0, + ]); + } + + public function setUp(): void + { + $this->initFieldTest(); + parent::setUp(); + } + + public function tearDown(): void + { + parent::tearDown(); + $this->tearDownFieldTest(); + } + + public function testDestinationWithNoAdditionalFields(): void + { + $builder = (new FormBuilder())->addQuestion("Short text", QuestionTypeShortText::class); + $form = $this->createForm($builder); + + $this->sendFormAndAssertITILObjectAdditionalFields( + form: $form, + config: new SimpleValueConfig(1), + answers: [ + "Short text" => "Test value", + ], + expected_field_values: [Ticket::class => []], + ); + } + + public function testDestinationWithAdditionalFields(): void + { + $this->login(); + $form = $this->createAndGetFormWithMultipleFieldQuestions(); + + $this->sendFormAndAssertITILObjectAdditionalFields( + form: $form, + config: new SimpleValueConfig(1), + answers: [ + "Field 1" => "Text value", + "Field 2" => [ + 'itemtype' => User::class, + 'items_id' => getItemByTypeName(User::class, TU_USER, true), + ], + "Field 3" => "Problem text", + "Field 4" => [ + 'itemtype' => User::class, + 'items_id' => getItemByTypeName(User::class, TU_USER, true), + ], + ], + expected_field_values: [ + Ticket::class => [ + $this->fields[0]->fields['name'] => 'Text value', + 'itemtype_' . $this->fields[1]->fields['name'] => User::class, + 'items_id_' . $this->fields[1]->fields['name'] => getItemByTypeName(User::class, TU_USER, true), + ], + Problem::class => [ + $this->fields[2]->fields['name'] => 'Problem text', + 'itemtype_' . $this->fields[3]->fields['name'] => User::class, + 'items_id_' . $this->fields[3]->fields['name'] => getItemByTypeName(User::class, TU_USER, true), + ], + ], + ); + } + + public function testDestinationWithAdditionalFieldsButDisabledInConfig(): void + { + $this->login(); + $form = $this->createAndGetFormWithMultipleFieldQuestions(); + + $this->sendFormAndAssertITILObjectAdditionalFields( + form: $form, + config: new SimpleValueConfig(false), + answers: [ + "Field 1" => "Text value", + "Field 2" => [ + 'itemtype' => User::class, + 'items_id' => getItemByTypeName(User::class, TU_USER, true), + ], + "Field 3" => "Problem text", + "Field 4" => [ + 'itemtype' => User::class, + 'items_id' => getItemByTypeName(User::class, TU_USER, true), + ], + ], + expected_field_values: [Ticket::class => [], Problem::class => []], + ); + } + + public function testDestinationWithLocationAdditonalFields(): void + { + $this->login(); + $form = $this->createForm((new FormBuilder())->addQuestion( + "Location Field", + PluginFieldsQuestionType::class, + extra_data: json_encode([ + 'block_id' => $this->blocks[Ticket::class]->getID(), + 'field_id' => $this->fields[4]->getID(), + ]), + )); + + // Arrange: Create a location to select + $location = $this->createItem(Location::class, [ + 'name' => 'Test Location', + 'entities_id' => $this->getTestRootEntity(true), + ]); + + $this->sendFormAndAssertITILObjectAdditionalFields( + form: $form, + config: new SimpleValueConfig(1), + answers: [ + "Location Field" => $location->getID(), + ], + expected_field_values: [ + Ticket::class => [ + $this->fields[4]->fields['name'] => $location->getID(), + ], + ], + ); + } + + #[Override] + public static function provideConvertFieldConfigFromFormCreator(): iterable + { + yield 'No destination field config related to Field question in FormCreator - Default configuration must be applied' => [ + 'field_key' => PluginFieldsDestinationField::getKey(), + 'fields_to_set' => [], + 'field_config' => new SimpleValueConfig(1), + ]; + } + + private function sendFormAndAssertITILObjectAdditionalFields( + Form $form, + SimpleValueConfig $config, + array $answers, + array $expected_field_values, + ): void { + // Insert config + $destinations = $form->getDestinations(); + foreach ($destinations as $destination) { + $this->updateItem( + $destination::getType(), + $destination->getId(), + ['config' => [PluginFieldsDestinationField::getKey() => $config->jsonSerialize()]], + ["config"], + ); + } + + // The provider use a simplified answer format to be more readable. + // Rewrite answers into expected format. + $formatted_answers = []; + foreach ($answers as $question => $answer) { + $key = $this->getQuestionId($form, $question); + $formatted_answers[$key] = $answer; + } + + // Submit form + $answers_handler = AnswersHandler::getInstance(); + $answers = $answers_handler->saveAnswers( + $form, + $formatted_answers, + getItemByTypeName(User::class, TU_USER, true), + ); + + // Get created itil object + $created_items = $answers->getCreatedItems(); + $this->assertCount(count($expected_field_values), $created_items); + + // Check field values for each created item + foreach ($expected_field_values as $itil_class => $expected_fields) { + /** @var ?CommonITILObject $itil_object */ + $itil_object = array_reduce( + $created_items, + fn(?CommonITILObject $carry, CommonITILObject $item) => $carry ?? ($item instanceof $itil_class ? $item : null), + null, + ); + $this->assertNotNull($itil_object, "No created item of type $itil_class found."); + + // Check field values + $classname = PluginFieldsContainer::getClassname($itil_class, $this->blocks[$itil_class]->fields['name']); + $obj = getItemForItemtype($classname); + $values = current($obj->find([ + PluginFieldsContainer::getForeignKeyField() => $this->blocks[$itil_class]->getID(), + 'items_id' => $itil_object->getID(), + ])); + + if ($values === false) { + $this->assertEmpty($expected_fields); + return; + } + + foreach ($expected_fields as $field_name => $expected_value) { + $this->assertArrayHasKey($field_name, $values); + $this->assertEquals( + $expected_value, + $values[$field_name], + "Field '$field_name' does not have the expected value.", + ); + } + } + } + + private function createAndGetFormWithMultipleFieldQuestions(): Form + { + $builder = new FormBuilder(); + + // Add Problem destination + $builder->addDestination(FormDestinationProblem::class, 'Problem'); + + // Add Field questions + $builder->addQuestion("Field 1", PluginFieldsQuestionType::class, extra_data: json_encode([ + 'block_id' => $this->blocks[Ticket::class]->getID(), + 'field_id' => $this->fields[0]->getID(), + ])); + $builder->addQuestion("Field 2", PluginFieldsQuestionType::class, extra_data: json_encode([ + 'block_id' => $this->blocks[Ticket::class]->getID(), + 'field_id' => $this->fields[1]->getID(), + ])); + $builder->addQuestion("Field 3", PluginFieldsQuestionType::class, extra_data: json_encode([ + 'block_id' => $this->blocks[Problem::class]->getID(), + 'field_id' => $this->fields[2]->getID(), + ])); + $builder->addQuestion("Field 4", PluginFieldsQuestionType::class, extra_data: json_encode([ + 'block_id' => $this->blocks[Problem::class]->getID(), + 'field_id' => $this->fields[3]->getID(), + ])); + return $this->createForm($builder); + } +} diff --git a/tests/Units/FieldQuestionTypeMigrationTest.php b/tests/Units/FieldQuestionTypeMigrationTest.php index 3732b0e0..959ee4ba 100644 --- a/tests/Units/FieldQuestionTypeMigrationTest.php +++ b/tests/Units/FieldQuestionTypeMigrationTest.php @@ -75,10 +75,9 @@ public function testFieldsQuestionIsMigrated(): void { global $DB; - $question_name = 'GLPI item fields question'; + $this->login(); - // Arrange: create block and field - $this->createFieldAndContainer(); + $question_name = 'GLPI item fields question'; // Create a form $this->assertTrue($DB->insert( @@ -125,9 +124,5 @@ public function testFieldsQuestionIsMigrated(): void $question = getItemByTypeName(Question::class, $question_name); $question_type = $question->getQuestionType(); $this->assertInstanceOf(PluginFieldsQuestionType::class, $question_type); - - // Delete created items - $form = $question->getForm(); - $form->delete($form->fields, true); } } diff --git a/tests/Units/FieldQuestionTypeTest.php b/tests/Units/FieldQuestionTypeTest.php index 20f1fc26..2217d3c4 100644 --- a/tests/Units/FieldQuestionTypeTest.php +++ b/tests/Units/FieldQuestionTypeTest.php @@ -43,9 +43,6 @@ final class FieldQuestionTypeTest extends QuestionTypeTestCase { public function testFieldsQuestionCategoryIsAvailableWhenValidFieldExists(): void { - // Arrange: create block and field - $this->createFieldAndContainer(); - // Act: get enabled question type categories $manager = QuestionTypesManager::getInstance(); $categories = $manager->getCategories(); @@ -59,6 +56,12 @@ public function testFieldsQuestionCategoryIsAvailableWhenValidFieldExists(): voi public function testFieldsQuestionCategoryIsNotAvailableWhenNoValidFieldExists(): void { + // Arrange: clean created field and container + $this->tearDownFieldTest(); + $this->deleteSingletonInstance([ + QuestionTypesManager::class, + ]); + // Act: get enabled question type categories $manager = QuestionTypesManager::getInstance(); $categories = $manager->getCategories(); @@ -72,9 +75,6 @@ public function testFieldsQuestionCategoryIsNotAvailableWhenNoValidFieldExists() public function testFieldsQuestionIsAvailableWhenValidFieldExists(): void { - // Arrange: create block and field - $this->createFieldAndContainer(); - // Act: get enabled question types $manager = QuestionTypesManager::getInstance(); $types = $manager->getQuestionTypes(); @@ -88,6 +88,12 @@ public function testFieldsQuestionIsAvailableWhenValidFieldExists(): void public function testFieldsQuestionIsNotAvailableWhenNoValidFieldExists(): void { + // Arrange: clean created field and container + $this->tearDownFieldTest(); + $this->deleteSingletonInstance([ + QuestionTypesManager::class, + ]); + // Act: get enabled question types $manager = QuestionTypesManager::getInstance(); $types = $manager->getQuestionTypes(); @@ -101,8 +107,7 @@ public function testFieldsQuestionIsNotAvailableWhenNoValidFieldExists(): void public function testFieldsQuestionEditorRendering(): void { - // Arrange: create field and container - $this->createFieldAndContainer(); + $this->login(); // Arrange: create form with Field question $builder = new FormBuilder("My form"); @@ -118,15 +123,11 @@ public function testFieldsQuestionEditorRendering(): void // Assert: item was rendered $this->assertNotEmpty($crawler->filter('.form-editor-container [data-glpi-form-editor-question] .glpi-fields-plugin-question-type-glpi-item-field')); - - // Cleanup - $form->delete($form->fields, true); } public function testFieldsQuestionHelpdeskRendering(): void { - // Arrange: create field and container - $this->createFieldAndContainer(); + $this->login(); // Arrange: create form with Field question $builder = new FormBuilder("My form"); @@ -142,9 +143,6 @@ public function testFieldsQuestionHelpdeskRendering(): void // Assert: item was rendered $this->assertNotEmpty($crawler->filter('[data-glpi-form-renderer-fields-question-type-specific-container]')); - - // Cleanup - $form->delete($form->fields, true); } private function getFieldExtraDataConfig(): PluginFieldsQuestionTypeExtraDataConfig