[ERP-48] Écrire les tests PHPUnit RG-1.01 à RG-1.17 #20

Merged
malio merged 3 commits from feature/ERP-48-tests-phpunit-rg-1-01-a-1-17 into develop 2026-05-28 09:48:17 +00:00
Owner

Mode stacked PR — DERNIER ticket back du M0

Cible : feature/ERP-47-declarer-module-catalog-rbac (PAS develop).
Quand la MR ERP-47 sera mergée sur develop, repointer la cible de cette MR vers develop.

Résumé

Suite PHPUnit complète qui mappe chaque RG (1.01 → 1.17) de la spec M0 Catalog vers un ou plusieurs tests ciblés. 63 nouveaux tests dans 9 classes sous tests/Module/Catalog/Api/.

Cahier de test

RG Test(s)
RG-1.01 CategoryPermissionsTest::testPersonaWithoutCatalogPermissionGets403* (4 personas × 4 verbes) + testAnonymousGets401* + testAdminGets{200,201,204}* + testUserWithViewPermissionGets200*
RG-1.02 CategoryValidationTest::testNameRequiredReturns422 + testNameEmptyStringReturns422 + testNameWhitespaceOnlyReturns422
RG-1.03 CategoryValidationTest::testNameIsTrimmedOnCreate
RG-1.04 CategoryValidationTest::testNameTooShortReturns422 + testNameTooLongReturns422 + testNameAtMaxLengthIs201
RG-1.05 CategoryValidationTest::testCategoryTypeRequiredReturns422 + testCategoryTypeNullIsRejected
RG-1.06 CategoryValidationTest::testCategoryTypeMustExistReturns4xx
RG-1.07 CategoryUniqueTest::testDuplicateNameSameTypeReturns409 + testDuplicateNameCaseInsensitiveReturns409 + testSameNameDifferentTypeAllowed + testRecreateAfterSoftDeleteAllowed
RG-1.08 CategoryListTest::testListExcludesSoftDeletedByDefault
RG-1.09 CategoryListTest::testIncludeDeletedFlagSurfacesSoftDeleted
RG-1.10 CategoryListTest::testDefaultSortIsNameAsc
RG-1.11 CategoryGetTest::testGetSoftDeletedReturns404 + testGetSoftDeletedWithFlagReturns200 + testGetNonExistentReturns404 + testGetActiveCategoryReturns200
RG-1.12 CategoryDeleteTest::testDeleteReturns204AndPersistsSoftDelete
RG-1.13 CategoryDeleteTest::testPatchCannotSetDeletedAt
RG-1.11 étendue (404 sur soft-deleted) CategoryDeleteTest::testPatchOnSoftDeletedReturns404 + testDeleteOnSoftDeletedReturns404
Audit CategoryAuditTest::testAuditLogOnCreate + testAuditLogOnUpdate + testAuditLogOnSoftDelete + testAuditLogPerformerCarriesAuthenticatedUsername
RG-1.15 CategoryTimestampableBlamableTest::testCreatedByAdminOnPost + testCreatedByNullInConsoleContext
RG-1.16 CategoryTimestampableBlamableTest::testPatchUpdatesUpdatedFieldsOnly + testSoftDeleteAlsoUpdatesUpdatedFields
RG-1.17 EntitiesAreTimestampableBlamableTest::testAllBusinessEntitiesImplementBothInterfaces (déjà livré ERP-52, reste vert avec Category détectée Timestampable/Blamable et CategoryType whitelistée)

Side fixes révélés par la suite

1. Category.phpnormalizer: 'trim' sur Assert\NotBlank + Length

Avant le fix, POST {name: " "} retournait 201 au lieu de 422 : le Processor trim après validation, mais NotBlank ne fait pas de trim natif. La RG-1.02 (whitespace-only → 422) combinée à la RG-1.03 (trim serveur) exige le normalizer: 'trim'. 1 ligne, aligne le contrat sans réordonnancer Validate/Process.

2. makefile — recréer l'index partiel uq_category_name_type_active après schema:update

doctrine:schema:update --env=test --force drop systématiquement l'index partiel uq_category_name_type_active (l'ORM ne sait pas exprimer un index fonctionnel + partiel via attribut Doctrine, donc le voit comme orphelin). Conséquence : POST doublon (name, type) retournait 201 au lieu de 409 (la UniqueConstraintViolation ne se déclenche plus). Fix : dbal:run-sql "CREATE UNIQUE INDEX IF NOT EXISTS ..." ajouté en fin de test-db-setup. Approche chirurgicale validée avec Matthieu, ne touche pas à fake_site_aware_entity (dépend de schema:update pour exister avant le purger fixtures:load).

Helpers livrés

tests/Module/Catalog/Api/AbstractCatalogApiTestCase.php :

  • Factories : createCategory(), createCategoryType()
  • Auth : createAdminClient(), createManageClient(), createViewClient(), createPersonaClient(string \$label) (4 personas MALIO sans permission catalog)
  • Cleanup : purge complète Category + CategoryType (aucune fixture au M0) + users/roles test_*

Vérifications

  • make php-cs-fixer-allow-risky (auto-applied via pre-commit)
  • make db-reset (index partiel restauré, vérifié \d category)
  • make test311 tests, 1071 assertions, 0 failure, 0 risky
    (248 existants + 63 nouveaux, dont 6 deprecations + 6 notices héritées des tests Core RBAC pré-existants — pas de régression introduite par ce ticket)

Suite

DERNIER ticket back du M0. ERP-52, ERP-43, ERP-44, ERP-45, ERP-46, ERP-47, ERP-48 sont tous en review.
Quand la MR ERP-47 sera mergée sur develop, Matthieu repointera la cible de cette MR vers develop. Tristan reviewe la stack en série.

## Mode stacked PR — DERNIER ticket back du M0 **Cible : `feature/ERP-47-declarer-module-catalog-rbac`** (PAS develop). Quand la MR ERP-47 sera mergée sur develop, repointer la cible de cette MR vers develop. ## Résumé Suite PHPUnit complète qui mappe chaque RG (1.01 → 1.17) de la spec M0 Catalog vers un ou plusieurs tests ciblés. **63 nouveaux tests** dans 9 classes sous `tests/Module/Catalog/Api/`. ## Cahier de test | RG | Test(s) | |---|---| | **RG-1.01** | `CategoryPermissionsTest::testPersonaWithoutCatalogPermissionGets403*` (4 personas × 4 verbes) + `testAnonymousGets401*` + `testAdminGets{200,201,204}*` + `testUserWithViewPermissionGets200*` | | **RG-1.02** | `CategoryValidationTest::testNameRequiredReturns422` + `testNameEmptyStringReturns422` + `testNameWhitespaceOnlyReturns422` | | **RG-1.03** | `CategoryValidationTest::testNameIsTrimmedOnCreate` | | **RG-1.04** | `CategoryValidationTest::testNameTooShortReturns422` + `testNameTooLongReturns422` + `testNameAtMaxLengthIs201` | | **RG-1.05** | `CategoryValidationTest::testCategoryTypeRequiredReturns422` + `testCategoryTypeNullIsRejected` | | **RG-1.06** | `CategoryValidationTest::testCategoryTypeMustExistReturns4xx` | | **RG-1.07** | `CategoryUniqueTest::testDuplicateNameSameTypeReturns409` + `testDuplicateNameCaseInsensitiveReturns409` + `testSameNameDifferentTypeAllowed` + `testRecreateAfterSoftDeleteAllowed` | | **RG-1.08** | `CategoryListTest::testListExcludesSoftDeletedByDefault` | | **RG-1.09** | `CategoryListTest::testIncludeDeletedFlagSurfacesSoftDeleted` | | **RG-1.10** | `CategoryListTest::testDefaultSortIsNameAsc` | | **RG-1.11** | `CategoryGetTest::testGetSoftDeletedReturns404` + `testGetSoftDeletedWithFlagReturns200` + `testGetNonExistentReturns404` + `testGetActiveCategoryReturns200` | | **RG-1.12** | `CategoryDeleteTest::testDeleteReturns204AndPersistsSoftDelete` | | **RG-1.13** | `CategoryDeleteTest::testPatchCannotSetDeletedAt` | | **RG-1.11 étendue (404 sur soft-deleted)** | `CategoryDeleteTest::testPatchOnSoftDeletedReturns404` + `testDeleteOnSoftDeletedReturns404` | | **Audit** | `CategoryAuditTest::testAuditLogOnCreate` + `testAuditLogOnUpdate` + `testAuditLogOnSoftDelete` + `testAuditLogPerformerCarriesAuthenticatedUsername` | | **RG-1.15** | `CategoryTimestampableBlamableTest::testCreatedByAdminOnPost` + `testCreatedByNullInConsoleContext` | | **RG-1.16** | `CategoryTimestampableBlamableTest::testPatchUpdatesUpdatedFieldsOnly` + `testSoftDeleteAlsoUpdatesUpdatedFields` | | **RG-1.17** | `EntitiesAreTimestampableBlamableTest::testAllBusinessEntitiesImplementBothInterfaces` (déjà livré ERP-52, reste vert avec `Category` détectée Timestampable/Blamable et `CategoryType` whitelistée) | ## Side fixes révélés par la suite ### 1. `Category.php` — `normalizer: 'trim'` sur Assert\NotBlank + Length Avant le fix, POST `{name: " "}` retournait **201** au lieu de **422** : le Processor trim après validation, mais NotBlank ne fait pas de trim natif. La RG-1.02 (whitespace-only → 422) combinée à la RG-1.03 (trim serveur) exige le `normalizer: 'trim'`. 1 ligne, aligne le contrat sans réordonnancer Validate/Process. ### 2. `makefile` — recréer l'index partiel `uq_category_name_type_active` après `schema:update` `doctrine:schema:update --env=test --force` drop systématiquement l'index partiel `uq_category_name_type_active` (l'ORM ne sait pas exprimer un index fonctionnel + partiel via attribut Doctrine, donc le voit comme orphelin). Conséquence : POST doublon `(name, type)` retournait **201** au lieu de **409** (la `UniqueConstraintViolation` ne se déclenche plus). Fix : `dbal:run-sql "CREATE UNIQUE INDEX IF NOT EXISTS ..."` ajouté en fin de `test-db-setup`. Approche chirurgicale validée avec Matthieu, ne touche pas à `fake_site_aware_entity` (dépend de schema:update pour exister avant le purger fixtures:load). ## Helpers livrés `tests/Module/Catalog/Api/AbstractCatalogApiTestCase.php` : - Factories : `createCategory()`, `createCategoryType()` - Auth : `createAdminClient()`, `createManageClient()`, `createViewClient()`, `createPersonaClient(string \$label)` (4 personas MALIO sans permission catalog) - Cleanup : purge complète Category + CategoryType (aucune fixture au M0) + users/roles `test_*` ## Vérifications - ✅ `make php-cs-fixer-allow-risky` (auto-applied via pre-commit) - ✅ `make db-reset` (index partiel restauré, vérifié `\d category`) - ✅ `make test` → **311 tests, 1071 assertions, 0 failure, 0 risky** (248 existants + 63 nouveaux, dont 6 deprecations + 6 notices héritées des tests Core RBAC pré-existants — pas de régression introduite par ce ticket) ## Suite DERNIER ticket back du M0. ERP-52, ERP-43, ERP-44, ERP-45, ERP-46, ERP-47, ERP-48 sont tous en review. Quand la MR ERP-47 sera mergée sur develop, Matthieu repointera la cible de cette MR vers develop. Tristan reviewe la stack en série.
malio changed target branch from feature/ERP-47-declarer-module-catalog-rbac to develop 2026-05-28 09:45:36 +00:00
matthieu added 3 commits 2026-05-28 09:48:05 +00:00
- remplace build:dist (nuxt generate + prerender inutile en SPA) par nuxt build
- cache node_modules sur hash du lockfile, npm ci uniquement en cache miss
- regenere les types Nuxt (postinstall) en cache hit
- cache des artefacts .nuxt / Vite avec restore-keys pour eviter le build a froid
Les logs montrent que chaque operation actions/cache attend ~4m30 avant
ETIMEDOUT sur le serveur de cache du runner Gitea (51.91.78.99:39531) :
- cache: npm de setup-node = tout le 'Setup Node 22' (271s)
- cache node_modules et cache .nuxt : timeouts additionnels
- cache Composer cote backend : meme risque

Node 22 est deja dans le tool-cache (install instantane), npm ci a froid
~30s, build ~20s : le caching n'apportait rien ici. A re-activer si le
serveur de cache du runner est repare.
test(catalog) : cover RG-1.01 to RG-1.17 with 9 test classes (63 tests)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Failing after 1m23s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m6s
c777ca057b
PHPUnit suite for the M0 Catalog module covering the 17 business rules of
the spec :
- CategoryPermissionsTest (RG-1.01) — 4 personas + admin + anonymous on GET / POST / PATCH / DELETE
- CategoryValidationTest (RG-1.02 to RG-1.06) — name NotBlank + trim + length + categoryType required / must exist
- CategoryUniqueTest (RG-1.07) — 409 case-insensitive, multi-type allowed, recreate after soft delete
- CategoryListTest (RG-1.08 to RG-1.10) — soft-delete filter, includeDeleted flag, name ASC sort
- CategoryGetTest (RG-1.11) — 404 on soft-deleted, 200 with flag, 404 on not found
- CategoryDeleteTest (RG-1.12 / RG-1.13) — soft delete, deletedAt unwriteable via PATCH, 404 on already deleted
- CategoryAuditTest — audit_log written on create / update / soft delete with correct performed_by
- CategoryTimestampableBlamableTest (RG-1.15 / RG-1.16) — blame admin on POST, null in console context, frozen createdBy on PATCH, updated_* on soft delete
- EntitiesAreTimestampableBlamableTest (RG-1.17) — stays green (already shipped in ERP-52)

Side fixes uncovered by the suite :
- Category.php : add normalizer 'trim' to NotBlank + Length so a whitespace-only
  name returns 422 (RG-1.02 + RG-1.03 alignment, the Processor trim was running
  after validation).
- makefile : recreate the partial index uq_category_name_type_active in
  test-db-setup. doctrine:schema:update drops the unexpressable index after
  migrations, which made RG-1.07 silently pass (duplicate POST -> 201 instead
  of 409). The DDL is now restored after schema:update via dbal:run-sql.

Tests : 311 total (248 + 63 new), 1071 assertions, 0 failure, 0 risky.
matthieu force-pushed feature/ERP-48-tests-phpunit-rg-1-01-a-1-17 from 8c3c0b58ed to c777ca057b 2026-05-28 09:48:05 +00:00 Compare
malio merged commit 4824690923 into develop 2026-05-28 09:48:17 +00:00
malio deleted branch feature/ERP-48-tests-phpunit-rg-1-01-a-1-17 2026-05-28 09:48:17 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: MALIO-DEV/Starseed#20