Conversation
Project doesn't use Stimulus or Turbo (no controllers.json, no <turbo-frame>, no data-controller — frontend is React/Mantine + Twig/Bootstrap). Both bundles were Flex-recipe leftovers that Dependabot kept churning major-bump PRs against (#488, #489 closed). Drops the composer packages, the four orphaned npm deps (@hotwired/{stimulus,turbo}, @symfony/{stimulus-bridge,ux-turbo}), config/packages/ux_turbo.yaml, the bundles.php entries, and the turbo-track comment boilerplate in webpack_encore.yaml. The subsequent `composer update` also picked up routine patch bumps: Symfony 8.0.8 -> 8.0.9 across components, doctrine/persistence 4.1.1 -> 4.2.0, async-aws/sqs 2.8.1 -> 2.9.0, phpstan 2.1.54, phpunit 13.1.8, aws-sdk-php 3.379.11, polyfills 1.37. No majors, no security advisories.
All MESSENGER_TRANSPORT_*_DSN values default to doctrine:// in .env, sync:// in .env.test, and docs/installation.md documents Doctrine as the only supported transport. No sqs:// DSN, no AsyncAws/AmazonSqs imports anywhere — the package was a Flex-recipe leftover. Drops symfony/amazon-sqs-messenger and its only transitive deps (async-aws/sqs, async-aws/core). aws/aws-sdk-php stays — it's pulled by league/flysystem-aws-s3-v3 and used in EditorUploadStorageFactory and MosaicStorageFactory for Scaleway S3.
Closes #467. Adds vincentlanglet/twig-cs-fixer ^3.14 as a dev dep with the default TwigCsFixer standard. New `.twig-cs-fixer.php` finder targets templates/, gitignores the cache, and exposes two Make targets next to the existing PHP fixers: make twig-cs-fix # auto-fix template style make twig-cs-check # dry-run for CI Both wired into `lint-all`. CLAUDE.md pre-commit checklist + commands table updated. CI workflow gains a "Twig-CS-Fixer (dry-run)" step right after PHP-CS-Fixer in the lint+unit job. Initial fix pass on 26 of the 103 templates: trailing commas in multi-line arrays/hashes, unnecessary quotes on hash keys (`{'_target_path': ...}` -> `{_target_path: ...}`), and `{% include %}` tag converted to the `{{ include(...) }}` function (preferred since Twig 2.x; same rendered HTML, cleaner scope handling). Functional tests (982/982) confirm template rendering is unchanged.
…es.php Flex rewrote config/bundles.php when unconfiguring the stimulus and ux-turbo recipes, dropping the project's standard PHP header. CI's PHP-CS-Fixer step caught it.
🔧 Chore: drop unused deps + add Twig-CS-Fixer + refresh deps
…nedCardController tests + sync service extensions Refs #498. First batch of the F6.14 banned-card coverage backfill: - BannedCardImageResolverTest (14 tests): all four URL-resolution branches — direct image URL, TCGdex CDN from TcgdexCard / parsed TcgdexId, PokemonTCG.io fallback, upstream-set-code fallback via TcgdexSet, plus rarity-tier sort, normalize-CDN dot-strip, all guessSerieIdFromSetId prefixes. - BannedCardEnricherTest (11 tests): no-op when already linked, local hit, TCGdex API hit (with imageUrl-fill protection), alias fallback, all-null path; force-mode reset; reparent identity cache regression for two consecutive printings sharing one identity (placeholder removal verified); empty-name fill on existing canonical parent. - AdminBannedCardControllerTest (12 tests): auth + role gates, active / history tabs, garbage view fallback, edit save round-trip, soft-delete + restore happy paths, CSRF rejection on delete and restore. - BannedCardsSyncServiceTest extensions: empty-printings skip during soft-delete pass and the in-loop parentsByIdentityId cache that prevents duplicate parents across two same-identity entries in one sync run.
Refs #498. Second batch of the F6.14 banned-card coverage backfill, finishing the priority list: - BannedCardSeedDataTest (7 tests): applyTo fills nulls / preserves existing values / no-ops on unknown name; per-printing seeds for Unown LOT 90 vs LOT 91 (distinct ban dates); applyAll counts filled+skipped, single flush, skips when seed exists but all fields already filled. - BannedCardsEnrichCommandTest (3 tests): linked / unresolved reporting, empty result, --force flag wired through. - BannedCardsSeedCommandTest (2 tests): success and empty repo. - AdminTechnicalControllerTest extension (4 tests): banned-cards-enrich auth + CSRF + happy path + force flag. - BannedCardPrintingRepositoryTest (4 tests): findOneBySetCodeAndCardNumber hit/miss, findAllOrderedBySetAndNumber lex order + empty. - CardPrintingRepositoryTest (3 tests): findFirstBySetCodeAndCardNumber prefers Expanded-legal then lowest rarity tier; null on miss. - BannedCardFormTypeTest (4 tests): form binds to BannedCard, exposes all fields, valid payload round-trip, empty optional fields clear existing values. Final and unit/functional totals: 1101 unit / 1005 functional tests pass locally (was 1062 / 982 before this branch).
✅ Tests: backfill banned-card coverage (#498)
…ry suites
Two coverage fixes in one branch:
1. **Test suite registration**
- Adds tests/Form and tests/Sentry to the unit suite in
phpunit.xml.dist. Without them, BannedCardFormTypeTest (added in
#509) and BeforeSendCallbackTest weren't running in CI.
2. **Sprite subsystem coverage** (F2.26 — was 0% before this PR)
- SpriteResolverTest (10 tests): cache-hit short-circuit, CDN-then-
PokeAPI fallback, no-CDN-config skip, exception swallow, data-URI
encoding, isCached, in-memory pokedex-id memoization.
- SpriteMappingSyncServiceTest (5 tests): inserts new + applies
SLUG_ALIASES; updates pokedex id when changed; skips unchanged
rows; throws on non-200 CSV fetch; CSV parser rejects empty,
malformed, and zero-id lines.
- SpritesSyncMappingCommandTest (2 tests): success path with counts,
RuntimeException -> Command::FAILURE.
- SpriteProxyControllerTest (3 tests): 404 on resolver miss, 200
with image/png + content on cache hit, /api/sprites/slugs returns
alphabetically-ordered JSON list.
- PokemonSpriteMappingRepositoryTest (4 tests): findPokedexIdBySlug
hit/miss, findAllSlugs ordering + empty.
3. **Source fix surfaced by the tests**
- SpriteMappingSyncService.php: pass empty $escape to str_getcsv() —
PHP 8.4+ deprecates the implicit default. Was hidden at 0%
coverage; the new tests trigger the deprecation, which the
project's failOnDeprecation=true would fail in CI.
Test totals: 1129 unit (was 1112), 1012 functional (was 1005).
✅ Tests: cover sprite subsystem + register Form & Sentry test suites
Two new functional test files extending the headline tests in the same
namespace (which only covered auth + a couple of happy paths).
AdminPageControllerCoverageTest (13 tests + 1 skip):
- list with q, category, channel filters; pagination beyond page 1
- reorder accepts JSON id list, rejects non-array payload (400)
- new page prefilled from channel + category query params
- new page submit creates row + redirects with success flash
- saveTranslation: existing locale update on welcome (en),
new-locale creation on a freshly-persisted app-channel page (fr),
rejects locale not in channel (404)
- delete + duplicate reject invalid CSRF (flash danger)
- duplicate clones every translation, sets isPublished=false, preserves
noIndex + ogImage + menuCategory
AdminMenuCategoryControllerCoverageTest (14 tests):
- list with view=footer, view=garbage (falls back to menu),
channel=app filter
- reorder accepts category-id array, returns {ok:true}
- new submit creates category + redirects to edit
- new with view=footer flags category as footer
- new with channel=app attaches the channel
- edit GET renders form; edit POST saves + redirects with flash
- saveTranslation: existing-locale update, new-locale creation on
a fresh app-channel category, rejects locale not in channel (404)
- delete with valid CSRF removes the row, with invalid CSRF rejects
with danger flash and keeps the row
Test totals: 1040 functional (was 1012), 1129 unit unchanged. Both
controllers were 28-46 % covered before this PR.
✅ Tests: backfill AdminPage and AdminMenuCategory controllers
…t 0%) The naive "PDF generation is hard to test" framing missed the obvious seam: both generators run a Twig render to produce HTML, then call Dompdf on it. Stubbing Twig::render with willReturnCallback to capture the template context lets us assert on every data-prep branch (grouping, sorting, font-size auto-fit, name localization, set-symbol fetch, sprite embedding) without booting the real templates. Dompdf still runs against the captured-then-passed-through tiny HTML so renderPdf() is exercised too; on a 6-line body it's effectively free (~5ms per test). PdfDecklistGeneratorTest (15 tests): - generateAnonymous / generatePersonal happy paths produce %PDF-* output - mode flag, playerName, trigram, gravatar URI propagation - gravatar 404 keeps gravatarDataUri null (graceful degradation) - deck without current version still renders with empty groups - card grouping + qty-desc-then-name-asc sort across all sections - trainer fallback bucket when subtype is null - font size shrinks under load, clamps to 9pt ceiling for tiny decks - localized card name preferred when deck has a single language - English subtitle added when display name differs from English name - set-symbol .png fetch with content-type normalization - HTTP exception during symbol fetch swallowed gracefully - TcgdexCardRepository fallback path with in-memory caching - multi-language deck falls back to English locale PdfLabelGeneratorTest (9 tests): - generate produces %PDF-* using the simple-label template - QR code data URI + base URL extraction (scheme + host) - sprite resolution + slug title-case (incl. dash → space conversion) - sprite resolver returning null skips that sprite - generateFoldable uses the foldable template - foldable handles deck without current version (default 6pt size) - foldable card grouping by subtype with fixed section ordering - foldable font size shrinks for large decks, clamps to 7pt ceiling Test totals: 1153 unit (was 1129).
…handler branches
Three coverage targets from the medium-tier list:
AdminTechnicalControllerCoverageTest (16 tests):
- enrich-retry / flush-reenrich auth + CSRF reject branches
- mosaic-generate CSRF reject + happy path (info/success flash)
- sprite-mapping-rebuild CSRF reject branch
- tcgdex-sync-insert / tcgdex-sync-update CSRF reject branches
- banned-cards-sync CSRF reject branch
- clear-cache CSRF reject + happy path
- clear-app-cache CSRF reject + happy path (cache->clear)
- clear-cache-key CSRF reject + empty-key warning + valid delete
Note: dispatch happy paths for Messenger-backed actions (set-mappings,
tcgdex-sync, flush-reenrich, banned-cards-sync, sprite-mapping-rebuild)
are not asserted because the test env runs sync transports and the
handlers reach external services (TCGdex / pokemon.com / PokeAPI)
without try/catch in the controller. The CSRF + auth branches are the
testable surface; the controller code beyond them is one-line dispatch.
DeckShowPdfRoutesTest (9 tests):
- /deck/{tag}/label.pdf returns application/pdf for owner; 403 otherwise
- /deck/{tag}/label-foldable.pdf same access pattern + valid PDF body
- /deck/{tag}/decklist.pdf personal mode for owner, ?anonymous=1 variant,
403 for non-owner
- /deck/{tag}/re-enrich requires ROLE_TECHNICAL_ADMIN; invalid CSRF -> 403
GenerateMinifiedMosaicHandlerTest extensions (4 tests):
- Catch branch: exception inside the pipeline is logged at error level
and rethrown
- MINIFIED_PRINTING_OVERRIDES static map short-circuits resolveMinifiedImage
(GEN|73 -> XY 129 with no CardPrinting reference)
- Two cards with the same name + image collapse into one tile via the
buildMergedTiles dedup keyed on `name|imageUrl`
- Tile sort order pokemon -> trainer -> energy with qty-desc + name-asc
within each type
Test totals: 1133 unit (+4) / 1065 functional (+25).
✅ Tests: cover PDF decklist + label generators (319 LOC at 0%)
✅ Tests: AdminTechnical + DeckShow PDF + mosaic handler branches
Both fields were missing from the explicit form_row calls in the deck new and edit templates, so form_end was emitting them at the bottom of the form (after the submit button area in some layouts). - new.html.twig: format goes right after name; latestSet sits between the languages island and the public checkbox (matching edit.html.twig). - edit.html.twig: format added right after name. latestSet was already in place.
🐛 Fix: render format + latestSet at the right spot in deck forms
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
🤖 Generated with Claude Code