diff --git a/src/Testing/DesignGuard.php b/src/Testing/DesignGuard.php index 7247dd3b..d26cc0ba 100644 --- a/src/Testing/DesignGuard.php +++ b/src/Testing/DesignGuard.php @@ -325,6 +325,10 @@ class DesignGuard } foreach ($this->files() as $file) { + if (str_ends_with($file->getFilename(), '.css')) { + continue; // A directly-scanned CSS file is check (iii)'s alone; these checks read Blade, PHP and JS. + } + $contents = (string) file_get_contents($file->getPathname()); $where = $this->relative($file->getPathname()); $isBlade = str_ends_with($file->getFilename(), '.blade.php'); @@ -671,7 +675,7 @@ class DesignGuard */ protected function literalColours(string $css): array { - $pattern = '/(?violations()); + + expect($violations)->toBe([ + 'app-css/app.css:3 literal colour `#ff0000` — use `var(--md-sys-color-*)`', + 'app-css/app.css:4 literal colour `rgb(0, 0, 0)` — use `var(--md-sys-color-*)`', + 'app-css/app.css:6 literal colour `rgba(0, 0, 0, 0.2)` — use `var(--md-sys-color-*)`', + 'app-css/app.css:5 literal radius `border-radius: 12px` — use `var(--md-sys-shape-corner-*)`', + 'app-css/app.css:6 literal shadow `box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)` — use `var(--md-sys-elevation-*)`', + 'app-css/app.css:7 literal font size `font-size: 14px` — use `var(--md-sys-typescale-*)`, which sets size, line height and weight together', + 'app-css/app.css:8 literal font weight `font-weight: 600` — use `var(--md-sys-typescale-*)` or `var(--md-sys-typescale-emphasized-*)`', + 'app-css/app.css:9 literal line height `line-height: 1.4` — use `var(--md-sys-typescale-*)`, which sets it with the size', + 'app-css/app.css:10 literal letter spacing `letter-spacing: 0.02em` — use `var(--md-sys-typescale-*-tracking)`', + 'app-css/app.css:11 literal easing in `transition: opacity 200ms ease-in-out` — use `var(--md-sys-motion-spatial-*)`/`var(--md-sys-motion-effects-*)`, paired with its `-duration`', + 'app-css/app.css:11 literal duration in `transition: opacity 200ms ease-in-out` — use `var(--md-sys-motion-…-duration)`, paired with its easing', + "app-css/app.css:21 media query width `700px` is not one of M3's breakpoints — use 600, 840, 1200 or 1600px (medium, expanded, large, extra-large)", + ]); +}); + +it('ignores the generated material-scheme.css, by name and by its generated header, wherever it sits among the scanned paths', function () { + $withScheme = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/app-css'))->violations()); + $withoutScheme = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/app-css/app.css'))->violations()); + + expect($withScheme)->toBe($withoutScheme); +}); + +it('never reads a Tailwind-shaped word out of running text', function () { + $violations = DesignGuard::scan(realpath(GUARD_FIXTURES.'/running-text.blade.php'))->violations(); + + expect($violations)->toBe([]); +}); + 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/app-css/app.css b/tests/Fixtures/design-guard/app-css/app.css new file mode 100644 index 00000000..a832ac0b --- /dev/null +++ b/tests/Fixtures/design-guard/app-css/app.css @@ -0,0 +1,25 @@ +/* comments are ignored */ +.card { + color: #ff0000; + background: rgb(0, 0, 0); + border-radius: 12px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + font-size: 14px; + font-weight: 600; + line-height: 1.4; + letter-spacing: 0.02em; + transition: opacity 200ms ease-in-out; +} + +.fine { + border-radius: var(--md-sys-shape-corner-lg); + color: var(--md-sys-color-primary); + padding: calc(var(--md-sys-measurement-space100) * 2); + border: 0; +} + +@media (min-width: 700px) { + .card { + display: flex; + } +} diff --git a/tests/Fixtures/design-guard/app-css/generated-scheme.css b/tests/Fixtures/design-guard/app-css/generated-scheme.css new file mode 100644 index 00000000..7719e826 --- /dev/null +++ b/tests/Fixtures/design-guard/app-css/generated-scheme.css @@ -0,0 +1,7 @@ +/* + * Material 3 colour roles, generated by Google's material-color-utilities (spec 2025). + */ + +:root { + --md-sys-color-primary: #6750a4; +} diff --git a/tests/Fixtures/design-guard/app-css/material-scheme.css b/tests/Fixtures/design-guard/app-css/material-scheme.css new file mode 100644 index 00000000..fcfd48e2 --- /dev/null +++ b/tests/Fixtures/design-guard/app-css/material-scheme.css @@ -0,0 +1,3 @@ +:root { + --md-sys-color-primary: #6750a4; +} diff --git a/tests/Fixtures/design-guard/running-text.blade.php b/tests/Fixtures/design-guard/running-text.blade.php new file mode 100644 index 00000000..d0d16065 --- /dev/null +++ b/tests/Fixtures/design-guard/running-text.blade.php @@ -0,0 +1,4 @@ +{{-- Running text is not a class list: none of Tailwind's bare-word utilities should be read out + of prose just because they share a spelling with one. --}} +
This creates a grid of cards, in a flex layout that stays hidden below medium and stacks into a + block once the pane narrows. Nothing here truncates or grows, and the sample is not a table.