Files
breadcrumb-the-shire/tests/Architecture/FrontendRuntimeHostContractTest.php
fs 811588290c 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

61 lines
3.4 KiB
PHP

<?php
namespace MintyPHP\Tests\Architecture;
use PHPUnit\Framework\TestCase;
class FrontendRuntimeHostContractTest extends TestCase
{
use ProjectFileAssertionSupport;
public function testHostBoundComponentsExposeDataAppComponentMarkupHosts(): void
{
$defaultTemplate = $this->readProjectFile('templates/default.phtml');
$loginTemplate = $this->readProjectFile('templates/login.phtml');
$flashPartial = $this->readProjectFile('templates/partials/app-flash.phtml');
$topbarPartial = $this->readProjectFile('templates/partials/app-topbar.phtml');
$asideIconBar = $this->readProjectFile('templates/partials/app-main-aside-icon-bar.phtml');
$asidePartial = $this->readProjectFile('templates/partials/app-main-aside.phtml');
$bookmarkDialog = $this->readProjectFile('modules/bookmarks/templates/bookmark-dialogs.phtml');
$bookmarkPanelTemplate = $this->readProjectFile('modules/bookmarks/templates/aside-bookmarks-panel.phtml');
$sessionWarningDialog = $this->readProjectFile('templates/partials/app-session-warning-dialog.phtml');
$this->assertStringContainsString('id="page-config-app-components"', $defaultTemplate);
$this->assertStringContainsString('id="page-config-login-components"', $loginTemplate);
$this->assertStringNotContainsString("assetVersion('js/components/app-bookmark-init.js')", $defaultTemplate);
$this->assertStringContainsString('data-app-component="flash-auto-dismiss"', $flashPartial);
$this->assertStringContainsString('data-app-component="tenant-switcher"', $topbarPartial);
$this->assertStringContainsString('data-app-component="theme-controls"', $topbarPartial);
$this->assertStringContainsString('data-app-component="contrast-toggle"', $topbarPartial);
$this->assertStringContainsString('data-app-component="details-aside-toggle"', $topbarPartial);
$this->assertStringContainsString('data-app-component="aside-panels"', $asideIconBar);
$this->assertStringContainsString('data-app-component="sidebar-toggle"', $asidePartial);
$searchDialog = $this->readProjectFile('templates/partials/app-search-dialog.phtml');
$this->assertStringContainsString('data-app-component="global-search"', $searchDialog);
$this->assertStringContainsString('data-app-component="bookmark-panel"', $bookmarkPanelTemplate);
$this->assertStringContainsString('data-app-component="bookmark-save"', $bookmarkDialog);
$this->assertStringContainsString('data-app-component="session-warning"', $sessionWarningDialog);
}
public function testTabsHostsUseDataAppComponentContract(): void
{
$files = [
'modules/addressbook/templates/address-book-profile.phtml',
'pages/admin/departments/_form.phtml',
'pages/admin/permissions/_form.phtml',
'pages/admin/roles/_form.phtml',
'pages/admin/settings/index(default).phtml',
'pages/admin/stats/index(default).phtml',
'pages/admin/tenants/_form.phtml',
'pages/admin/users/_form.phtml',
];
foreach ($files as $file) {
$content = $this->readProjectFile($file);
$this->assertStringContainsString('data-tabs', $content, $file);
$this->assertStringContainsString('data-app-component="tabs"', $content, $file);
}
}
}