');
expect($html)->toContain('size-4')->not->toContain('size-5');
});
it('falls back to its own size when the call site names none', function () {
expect(Blade::render(''))->toContain('size-5');
});
it('keeps an icon on the line it was written on', function () {
// Tailwind's preflight makes every svg display:block. Inside an inline
// parent that pushes the following text onto a second line, which is how a
// one-line navigation entry became two lines tall.
expect(Blade::render(''))
->toContain('inline-block')
->toContain('shrink-0');
});
it('keeps a navigation entry on one line whichever slot the icon uses', function () {
// Blade::render leaves a slot's output buffer open when a component is
// rendered outside a request, which PHPUnit reports as a risky test. The
// markup it returns is complete; only the buffer needs tidying.
$render = function (string $template): string {
$level = ob_get_level();
try {
return Blade::render($template);
} finally {
while (ob_get_level() > $level) {
ob_end_clean();
}
}
};
$viaSlot = $render(
'Zugangsdaten'
);
// The mistake that caused the report: the icon handed to the DEFAULT slot
// rather than the icon slot. The layout must not depend on which was used.
$viaDefaultSlot = $render(
'Zugangsdaten'
);
foreach ([$viaSlot, $viaDefaultSlot] as $html) {
expect($html)
->toContain('items-center')
->toContain('Zugangsdaten')
// The label wrapper is a flex row of its own, so a stray icon lands
// next to the text rather than above it.
->toContain('flex min-w-0 items-center gap-3');
}
});
it('puts navigation icons in the icon slot everywhere', function () {
// Belt to the component's braces. The component now survives an icon in the
// wrong slot, but the wrong slot also skips the shrink-0 wrapper and reads
// as an accident to the next person editing the file.
$offenders = [];
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(resource_path('views'), FilesystemIterator::SKIP_DOTS)
);
foreach ($files as $file) {
if (! str_ends_with($file->getFilename(), '.blade.php')) {
continue;
}
$source = (string) file_get_contents($file->getPathname());
// Each nav-item element, from its opening tag to its closing one.
preg_match_all('//s', $source, $matches);
foreach ($matches[0] as $element) {
$withoutIconSlot = preg_replace('/.*?<\/x-slot:icon>/s', '', $element);
if (str_contains((string) $withoutIconSlot, 'getPathname());
}
}
}
expect($offenders)->toBe([]);
});