1
0
Files
breadcrumb-the-shire/tests/Architecture/FilterDrawerRuntimeContractTest.php

44 lines
2.2 KiB
PHP
Raw Normal View History

<?php
namespace MintyPHP\Tests\Architecture;
use PHPUnit\Framework\TestCase;
class FilterDrawerRuntimeContractTest extends TestCase
{
use ProjectFileAssertionSupport;
public function testUsersResetKeepsTenantParam(): void
{
$moduleContent = $this->readProjectFile('web/js/pages/admin-users-index.js');
$this->assertStringContainsString("preserveFilterParams: ['tenant']", $moduleContent);
}
public function testFilterDrawerAndExperienceImplementFocusTrapAndDirtyApplyUi(): void
{
$drawerJs = $this->readProjectFile('web/js/components/app-filter-drawer.js');
$this->assertStringContainsString("drawer.setAttribute('role', 'dialog')", $drawerJs);
$this->assertStringContainsString("drawer.setAttribute('aria-modal', 'true')", $drawerJs);
feat(core): detail drawer + address book list redesign Introduces a reusable core detail-drawer primitive that slides in from the right and loads any view via a `*-fragment(none).phtml` endpoint. Bundles the address book list overhaul that is its first consumer. Core additions: - `app-detail-drawer.js` — generic drawer with stepper, focus trap, body scroll-lock, URL-hash deep-linking, session-expiry detection - `app-fragment-init.js` — auto-wires tabs/lookups/confirm/file-upload/ fslightbox inside injected HTML; consumers do not re-initialize components - `app-focus-trap.js` — shared focus-trap + refcounted scroll-lock, used by both filter-drawer and detail-drawer - `getHtml()` in `app-http.js` + `SessionExpiredError`; drawer reloads the page on auth redirect instead of rendering the login form in the panel - `DetailDrawerFragmentContractTest` enforces that every `initDetailDrawer` consumer ships matching `*-fragment($id).php` + `*-fragment(none).phtml` Address book list: - Grid collapses from 9 columns to 4 (identity / context / phone / actions) with a two-line identity cell (avatar + name + email) - Tenant register tabs above the grid using the `app-list-tabs` partial; tenant filter wired via hidden toolbar field so grid.js forwards it on every data fetch - Profile body extracted to a shared partial so the full-page view and the new drawer fragment share the same markup - New i18n keys for the drawer/list labels Also refactors `app-filter-drawer` to reuse the shared focus-trap and scroll-lock instead of maintaining its own copy, and documents the detail-drawer convention in CLAUDE.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:22:26 +02:00
// Focus-trap + focus-return implementation moved to shared utility.
$this->assertStringContainsString("from '../core/app-focus-trap.js'", $drawerJs);
$this->assertStringContainsString('focusTrap.activate(', $drawerJs);
$this->assertStringContainsString('focusTrap.deactivate()', $drawerJs);
$trapJs = $this->readProjectFile('web/js/core/app-focus-trap.js');
$this->assertStringContainsString("if (event.key !== 'Tab')", $trapJs);
$this->assertStringContainsString("lastTrigger && typeof lastTrigger.focus === 'function'", $trapJs);
$experienceJs = $this->readProjectFile('web/js/pages/app-list-filter-experience.js');
$this->assertStringContainsString('countDraftChanges(', $experienceJs);
$this->assertStringContainsString('countActiveDraftFilters(', $experienceJs);
$this->assertStringContainsString('drawerController.setApplyEnabled(changedCount > 0);', $experienceJs);
$this->assertStringContainsString('drawerController.setApplyCount(activeCount);', $experienceJs);
$this->assertStringContainsString('announceLive(', $experienceJs);
$stateJs = $this->readProjectFile('web/js/pages/app-list-filter-state.js');
$this->assertStringContainsString('buildChipsFromMeta', $stateJs);
$this->assertStringContainsString('removeChipFromMetaState', $stateJs);
$this->assertStringContainsString('clearMetaState', $stateJs);
}
}