diff --git a/.gitignore b/.gitignore
index 40db549..4b0fd5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,6 @@ yarn-error.log
###> vincentlanglet/twig-cs-fixer ###
/.twig-cs-fixer.cache
###< vincentlanglet/twig-cs-fixer ###
+
+# Generated by Symfony when the test application boots
+/tests/App/config/reference.php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15db80c..3a46040 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ Latest
------
## Changes
+* [#81](https://github.com/cleverage/ui-process-bundle/issues/81) Add missing tests: functional tests of the UI and the HTTP API on a test application (SQLite, in-memory Messenger), unit tests of every class (DI, command, migrations, entities, managers, message handlers, scheduler, Monolog handlers, forms, EasyAdmin fields and filters, Twig, validators); `memory_limit` set to 512M for the test suite.
* [#83](https://github.com/cleverage/ui-process-bundle/issues/83) Remove `UploadAndExecuteAction` (route `process_upload_and_execute`), `ProcessUploadFileType` and `ProcessConfigurationValueResolver`: the action was broken and unreachable, file uploads are handled by `LaunchAction` (`entrypoint_type: file`).
* [#84](https://github.com/cleverage/ui-process-bundle/issues/84) Add `LogRecord::hasContextInfo()`, deprecate the misnamed `LogRecord::contextIsEmpty()` (it returns `true` when the context is not empty). Add tests.
* [#85](https://github.com/cleverage/ui-process-bundle/issues/85) `ProcessHandler`: default report increment level aligned on the bundle configuration (`Warning`); declare the `symfony/ux-twig-component` dependency. Add tests.
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index c3e7947..56fc4af 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -14,6 +14,10 @@
tests
+
+
+
+
src
diff --git a/tests/Admin/Field/ContextFieldTest.php b/tests/Admin/Field/ContextFieldTest.php
new file mode 100644
index 0000000..d696b85
--- /dev/null
+++ b/tests/Admin/Field/ContextFieldTest.php
@@ -0,0 +1,44 @@
+getAsDto();
+
+ self::assertSame('myProperty', $dto->getProperty());
+ self::assertSame('My label', $dto->getLabel());
+ self::assertSame('@CleverAgeUiProcess/admin/field/array.html.twig', $dto->getTemplatePath());
+ }
+
+ public function testNewWithTranslatableLabel(): void
+ {
+ $label = new TranslatableMessage('my.label');
+
+ self::assertSame($label, ContextField::new('myProperty', $label)->getAsDto()->getLabel());
+ }
+
+ public function testNewWithoutLabel(): void
+ {
+ self::assertNull(ContextField::new('myProperty')->getAsDto()->getLabel());
+ }
+}
diff --git a/tests/Admin/Field/EnumFieldTest.php b/tests/Admin/Field/EnumFieldTest.php
new file mode 100644
index 0000000..828f15b
--- /dev/null
+++ b/tests/Admin/Field/EnumFieldTest.php
@@ -0,0 +1,44 @@
+getAsDto();
+
+ self::assertSame('myProperty', $dto->getProperty());
+ self::assertSame('My label', $dto->getLabel());
+ self::assertSame('@CleverAgeUiProcess/admin/field/enum.html.twig', $dto->getTemplatePath());
+ }
+
+ public function testNewWithTranslatableLabel(): void
+ {
+ $label = new TranslatableMessage('my.label');
+
+ self::assertSame($label, EnumField::new('myProperty', $label)->getAsDto()->getLabel());
+ }
+
+ public function testNewWithoutLabel(): void
+ {
+ self::assertNull(EnumField::new('myProperty')->getAsDto()->getLabel());
+ }
+}
diff --git a/tests/Admin/Field/LogLevelFieldTest.php b/tests/Admin/Field/LogLevelFieldTest.php
new file mode 100644
index 0000000..6bfe06b
--- /dev/null
+++ b/tests/Admin/Field/LogLevelFieldTest.php
@@ -0,0 +1,44 @@
+getAsDto();
+
+ self::assertSame('myProperty', $dto->getProperty());
+ self::assertSame('My label', $dto->getLabel());
+ self::assertSame('@CleverAgeUiProcess/admin/field/log_level.html.twig', $dto->getTemplatePath());
+ }
+
+ public function testNewWithTranslatableLabel(): void
+ {
+ $label = new TranslatableMessage('my.label');
+
+ self::assertSame($label, LogLevelField::new('myProperty', $label)->getAsDto()->getLabel());
+ }
+
+ public function testNewWithoutLabel(): void
+ {
+ self::assertNull(LogLevelField::new('myProperty')->getAsDto()->getLabel());
+ }
+}
diff --git a/tests/Admin/Filter/LogProcessFilterTest.php b/tests/Admin/Filter/LogProcessFilterTest.php
new file mode 100644
index 0000000..09a4f0e
--- /dev/null
+++ b/tests/Admin/Filter/LogProcessFilterTest.php
@@ -0,0 +1,106 @@
+ 'demo.a', 'demo.b' => 'demo.b'])->getAsDto();
+
+ self::assertSame(LogProcessFilter::class, $dto->getFqcn());
+ self::assertSame('process', $dto->getProperty());
+ self::assertSame('Process', $dto->getLabel());
+ self::assertSame(ChoiceFilterType::class, $dto->getFormType());
+ self::assertSame(['choices' => ['demo.a' => 'demo.a', 'demo.b' => 'demo.b']], $dto->getFormTypeOption('value_type_options'));
+ self::assertSame(['comparison' => ComparisonType::EQ, 'value' => null], $dto->getFormTypeOption('data'));
+ }
+
+ public function testNewWithExecutionIdReplacesChoices(): void
+ {
+ $dto = LogProcessFilter::new('Process', ['demo.a' => 'demo.a'], '12')->getAsDto();
+
+ self::assertSame(['choices' => [12 => '12']], $dto->getFormTypeOption('value_type_options'));
+ self::assertSame(['comparison' => ComparisonType::EQ, 'value' => '12'], $dto->getFormTypeOption('data'));
+ }
+
+ public function testNewWithNonNumericExecutionIdKeepsChoices(): void
+ {
+ $dto = LogProcessFilter::new('Process', ['demo.a' => 'demo.a'], 'demo.a')->getAsDto();
+
+ self::assertSame(['choices' => ['demo.a' => 'demo.a']], $dto->getFormTypeOption('value_type_options'));
+ self::assertSame(['comparison' => ComparisonType::EQ, 'value' => 'demo.a'], $dto->getFormTypeOption('data'));
+ }
+
+ public function testApplyWithExecutionId(): void
+ {
+ $queryBuilder = $this->createQueryBuilder();
+
+ $this->apply($queryBuilder, '12');
+
+ self::assertSame(
+ 'SELECT entity FROM '.LogRecord::class.' entity INNER JOIN entity.processExecution pe WHERE pe.id = :id',
+ $queryBuilder->getDQL()
+ );
+ self::assertCount(1, $queryBuilder->getParameters());
+ self::assertSame('12', $queryBuilder->getParameter('id')?->getValue());
+ }
+
+ public function testApplyWithProcessCodes(): void
+ {
+ $queryBuilder = $this->createQueryBuilder();
+
+ $this->apply($queryBuilder, ['demo.a', 'demo.b']);
+
+ self::assertSame(
+ 'SELECT entity FROM '.LogRecord::class.' entity INNER JOIN entity.processExecution pe WHERE pe.code IN (:codes)',
+ $queryBuilder->getDQL()
+ );
+ self::assertCount(1, $queryBuilder->getParameters());
+ self::assertSame(['demo.a', 'demo.b'], $queryBuilder->getParameter('codes')?->getValue());
+ }
+
+ private function createQueryBuilder(): QueryBuilder
+ {
+ $entityManager = $this->createStub(EntityManagerInterface::class);
+ $entityManager->method('getExpressionBuilder')->willReturn(new Expr());
+
+ return (new QueryBuilder($entityManager))->select('entity')->from(LogRecord::class, 'entity');
+ }
+
+ private function apply(QueryBuilder $queryBuilder, mixed $value): void
+ {
+ $filter = LogProcessFilter::new('Process', []);
+ $filterDataDto = FilterDataDto::new(0, $filter->getAsDto(), 'entity', ['comparison' => ComparisonType::EQ, 'value' => $value]);
+
+ /** @var EntityDto