From b998683762324e9f5831652554ac26d5b636c932 Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Tue, 15 Sep 2026 08:12:01 +0200 Subject: [PATCH] Add fixtures and tests for DesignGuard::missingStylesheets() Plan step 41(ii): exercises the tag-to-stylesheet mapping (plain, prefixed and namespaced spellings), a package stylesheet's own imports counting toward its dependents (split-button.css satisfies button.css and menu.css too), ->links() needing pagination.css, the always-required foundation.css, and a package tag shadowed by the application's own anonymous or class component. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9 --- tests/Feature/DesignGuardTest.php | 106 ++++++++++++++++++ .../Fixtures/design-guard/stylesheets/all.css | 1 + .../stylesheets/foundation-only.css | 1 + .../stylesheets/missing-foundation.css | 1 + .../design-guard/stylesheets/split-button.css | 2 + .../stylesheets/views/dependencies.blade.php | 3 + .../stylesheets/views/namespaced.blade.php | 1 + .../stylesheets/views/pagination.blade.php | 1 + .../stylesheets/views/plain.blade.php | 1 + .../stylesheets/views/prefixed.blade.php | 1 + .../stylesheets/views/shadow-class.blade.php | 1 + .../stylesheets/views/shadow.blade.php | 1 + .../stylesheets/views/split-button.blade.php | 1 + 13 files changed, 121 insertions(+) create mode 100644 tests/Fixtures/design-guard/stylesheets/all.css create mode 100644 tests/Fixtures/design-guard/stylesheets/foundation-only.css create mode 100644 tests/Fixtures/design-guard/stylesheets/missing-foundation.css create mode 100644 tests/Fixtures/design-guard/stylesheets/split-button.css create mode 100644 tests/Fixtures/design-guard/stylesheets/views/dependencies.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/namespaced.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/pagination.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/plain.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/prefixed.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/shadow-class.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/shadow.blade.php create mode 100644 tests/Fixtures/design-guard/stylesheets/views/split-button.blade.php diff --git a/tests/Feature/DesignGuardTest.php b/tests/Feature/DesignGuardTest.php index dbe230e3..b130dd6c 100644 --- a/tests/Feature/DesignGuardTest.php +++ b/tests/Feature/DesignGuardTest.php @@ -1,9 +1,14 @@ Stylesheets::resetCache()); + /** * @param list $violations * @return list @@ -305,6 +310,107 @@ it('bans any further pattern', function () { expect($violations)->toContain('views/page.blade.php:7 a retired utility'); }); +it('names the missing package stylesheet and the exact @import line to add', function () { + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/split-button.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/foundation-only.css')) + ->violations()); + + expect($violations)->toBe([ + "stylesheets/views/split-button.blade.php:1 `` needs `components/split-button.css`, missing from stylesheets/foundation-only.css — add `@import '../../../../resources/css/components/split-button.css';`", + ]); +}); + +it('counts what an imported package stylesheet already brings in, through its own imports', function () { + $violations = DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/dependencies.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/split-button.css')) + ->violations(); + + expect($violations)->toBe([]); +}); + +it('needs nothing more once the entry imports all.css', function () { + $violations = DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/all.css')) + ->violations(); + + expect($violations)->toBe([]); +}); + +it('requires foundation.css whatever the views hold', function () { + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/plain.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/missing-foundation.css')) + ->violations()); + + expect($violations)->toBe([ + "stylesheets/missing-foundation.css:1 the CSS entry never imports `foundation.css`, required by every package stylesheet — add `@import '../../../../resources/css/foundation.css';`", + ]); +}); + +it('recognises a package tag written under the configured prefix', function () { + config(['livewire-material.prefix' => 'm']); + + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/prefixed.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/foundation-only.css')) + ->violations()); + + expect($violations)->toBe([ + "stylesheets/views/prefixed.blade.php:1 `` needs `components/button.css`, missing from stylesheets/foundation-only.css — add `@import '../../../../resources/css/components/button.css';`", + ]); +}); + +it('recognises a package tag written fully qualified', function () { + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/namespaced.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/foundation-only.css')) + ->violations()); + + expect($violations)->toBe([ + "stylesheets/views/namespaced.blade.php:1 `` needs `components/button.css`, missing from stylesheets/foundation-only.css — add `@import '../../../../resources/css/components/button.css';`", + ]); +}); + +it('needs pagination.css when a view calls ->links()', function () { + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/pagination.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/foundation-only.css')) + ->violations()); + + expect($violations)->toBe([ + "stylesheets/views/pagination.blade.php:1 `->links()` needs `components/pagination.css`, missing from stylesheets/foundation-only.css — add `@import '../../../../resources/css/components/pagination.css';`", + ]); +}); + +it('reports a package tag the application shadows with its own anonymous component', function () { + $views = sys_get_temp_dir().'/livewire-material-guard-shadow-'.uniqid(); + File::ensureDirectoryExists($views.'/components'); + File::put($views.'/components/button.blade.php', 'the application\'s button'); + View::getFinder()->prependLocation($views); + + try { + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/shadow.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/all.css')) + ->violations()); + } finally { + File::deleteDirectory($views); + } + + expect($violations)->toBe([ + "stylesheets/views/shadow.blade.php:1 `` is shadowed by the application's own component of the same name — the package's `` never renders here", + ]); +}); + +it('reports a package tag the application shadows with its own component class', function () { + if (! class_exists('App\View\Components\Card', false)) { + eval('namespace App\View\Components; class Card {}'); + } + + $violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/stylesheets/views/shadow-class.blade.php')) + ->missingStylesheets(realpath(GUARD_FIXTURES.'/stylesheets/all.css')) + ->violations()); + + expect($violations)->toBe([ + "stylesheets/views/shadow-class.blade.php:1 `` is shadowed by the application's own component of the same name — the package's `` never renders here", + ]); +}); + it('passes the package\'s own views', function () { $violations = DesignGuard::scan([__DIR__.'/../../resources/views', __DIR__.'/../../resources/js', __DIR__.'/../../src'])->violations(); diff --git a/tests/Fixtures/design-guard/stylesheets/all.css b/tests/Fixtures/design-guard/stylesheets/all.css new file mode 100644 index 00000000..97bfe489 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/all.css @@ -0,0 +1 @@ +@import '../../../../resources/css/all.css'; diff --git a/tests/Fixtures/design-guard/stylesheets/foundation-only.css b/tests/Fixtures/design-guard/stylesheets/foundation-only.css new file mode 100644 index 00000000..e71757d0 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/foundation-only.css @@ -0,0 +1 @@ +@import '../../../../resources/css/foundation.css'; diff --git a/tests/Fixtures/design-guard/stylesheets/missing-foundation.css b/tests/Fixtures/design-guard/stylesheets/missing-foundation.css new file mode 100644 index 00000000..46713f54 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/missing-foundation.css @@ -0,0 +1 @@ +@import '../../../../resources/css/components/button.css'; diff --git a/tests/Fixtures/design-guard/stylesheets/split-button.css b/tests/Fixtures/design-guard/stylesheets/split-button.css new file mode 100644 index 00000000..bb8ed5ad --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/split-button.css @@ -0,0 +1,2 @@ +@import '../../../../resources/css/foundation.css'; +@import '../../../../resources/css/components/split-button.css'; diff --git a/tests/Fixtures/design-guard/stylesheets/views/dependencies.blade.php b/tests/Fixtures/design-guard/stylesheets/views/dependencies.blade.php new file mode 100644 index 00000000..4e4ffd83 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/dependencies.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/tests/Fixtures/design-guard/stylesheets/views/namespaced.blade.php b/tests/Fixtures/design-guard/stylesheets/views/namespaced.blade.php new file mode 100644 index 00000000..9e0d8096 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/namespaced.blade.php @@ -0,0 +1 @@ + diff --git a/tests/Fixtures/design-guard/stylesheets/views/pagination.blade.php b/tests/Fixtures/design-guard/stylesheets/views/pagination.blade.php new file mode 100644 index 00000000..a85e4139 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/pagination.blade.php @@ -0,0 +1 @@ +{{ $items->links() }} diff --git a/tests/Fixtures/design-guard/stylesheets/views/plain.blade.php b/tests/Fixtures/design-guard/stylesheets/views/plain.blade.php new file mode 100644 index 00000000..62001bb4 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/plain.blade.php @@ -0,0 +1 @@ +
Nothing package-specific here.
diff --git a/tests/Fixtures/design-guard/stylesheets/views/prefixed.blade.php b/tests/Fixtures/design-guard/stylesheets/views/prefixed.blade.php new file mode 100644 index 00000000..a81f6db3 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/prefixed.blade.php @@ -0,0 +1 @@ + diff --git a/tests/Fixtures/design-guard/stylesheets/views/shadow-class.blade.php b/tests/Fixtures/design-guard/stylesheets/views/shadow-class.blade.php new file mode 100644 index 00000000..72297ea3 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/shadow-class.blade.php @@ -0,0 +1 @@ + diff --git a/tests/Fixtures/design-guard/stylesheets/views/shadow.blade.php b/tests/Fixtures/design-guard/stylesheets/views/shadow.blade.php new file mode 100644 index 00000000..dfdd8b89 --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/shadow.blade.php @@ -0,0 +1 @@ + diff --git a/tests/Fixtures/design-guard/stylesheets/views/split-button.blade.php b/tests/Fixtures/design-guard/stylesheets/views/split-button.blade.php new file mode 100644 index 00000000..8a2560da --- /dev/null +++ b/tests/Fixtures/design-guard/stylesheets/views/split-button.blade.php @@ -0,0 +1 @@ +