127 lines
5.4 KiB
PHP
127 lines
5.4 KiB
PHP
<?php
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
/**
|
|
* The public website is one of the three surfaces the token file describes.
|
|
*
|
|
* It was the last one still speaking the old language: a 900-line page with its
|
|
* own design system inside a <style> block — warm paper, a serif headline, 3px
|
|
* corners, its own scale of greys — written before the tokens existed. A
|
|
* visitor who clicked "Anmelden" left one company and arrived at another.
|
|
*
|
|
* These tests are about drift, not about looks. Nothing stops someone pasting a
|
|
* hex value into a marketing page at four in the afternoon; what stops it
|
|
* becoming a second design system is noticing on the first one.
|
|
*/
|
|
|
|
/** Public pages that must draw from the shared stylesheet. */
|
|
function sitePages(): array
|
|
{
|
|
return [
|
|
'landing.blade.php',
|
|
'legal.blade.php',
|
|
'status.blade.php',
|
|
'components/layouts/site.blade.php',
|
|
];
|
|
}
|
|
|
|
it('builds the public site from the shared tokens, not from its own palette', function (string $page) {
|
|
$source = File::get(resource_path('views/'.$page));
|
|
|
|
// Hex literals are the tell. One is a paste; a dozen is a second design
|
|
// system growing quietly beside the first.
|
|
preg_match_all('/#[0-9a-fA-F]{3,8}\b/', $source, $found);
|
|
|
|
expect($found[0])->toBeEmpty()
|
|
// The old page set its own type stack. The token file owns that now,
|
|
// and a serif headline is precisely the impression the redesign
|
|
// removed — every page read as a document.
|
|
->and($source)->not->toContain('font-family')
|
|
->and($source)->not->toContain('Georgia')
|
|
->and($source)->not->toContain('font-serif');
|
|
})->with(sitePages());
|
|
|
|
it('serves the website from the same stylesheet as the portal', function () {
|
|
// Not "a stylesheet exists" — the SAME one. Two builds would drift the
|
|
// moment a token changed in one of them.
|
|
$layout = File::get(resource_path('views/components/layouts/site.blade.php'));
|
|
|
|
expect($layout)->toContain('<x-shell.head');
|
|
|
|
$head = File::get(resource_path('views/components/shell/head.blade.php'));
|
|
|
|
expect($head)->toContain("@vite(['resources/css/app.css'");
|
|
});
|
|
|
|
it('keeps the deliberately self-contained page self-contained', function () {
|
|
// The exception, named rather than forgotten. coming-soon is shown when the
|
|
// application may not be able to serve a built stylesheet at all — mid
|
|
// deploy, or freshly installed — and @vite would throw where the whole
|
|
// point is to render something reassuring.
|
|
//
|
|
// The status page used to be on this list on the same theory and does not
|
|
// belong: if the stylesheet cannot be served, the application serving the
|
|
// status page is already failing, and mid-deployment every route answers
|
|
// with the maintenance page. What the exemption actually bought was a third
|
|
// design nobody maintained.
|
|
$source = File::get(resource_path('views/coming-soon.blade.php'));
|
|
|
|
// The CALL, not the word: the file explains in a comment why it does not
|
|
// use @vite, and a plain substring match reads that explanation as the
|
|
// offence it warns about.
|
|
expect($source)->not->toMatch('/@vite\s*\(/')
|
|
->and($source)->toContain('<style>');
|
|
});
|
|
|
|
it('does not leave the old marketing stylesheet behind anywhere', function () {
|
|
// The tell of the previous edition: warm paper and the 3px radius. Left in
|
|
// a partial nobody opened, it would come back the next time somebody
|
|
// copied a section.
|
|
foreach (File::allFiles(resource_path('views')) as $file) {
|
|
if ($file->getFilename() === 'coming-soon.blade.php') {
|
|
continue;
|
|
}
|
|
|
|
// The mail layout is deliberately inline-styled: an email client has no
|
|
// stylesheet of ours to load.
|
|
if (str_contains($file->getPathname(), '/mail/') || str_contains($file->getPathname(), '/pdf/')) {
|
|
continue;
|
|
}
|
|
|
|
expect(File::get($file->getPathname()))
|
|
->not->toContain('--paper')
|
|
->not->toContain('Plex Serif');
|
|
}
|
|
});
|
|
|
|
it('does not space the wordmark out into separate words', function () {
|
|
// It went out reading "Clu Pilot Cloud". `gap` on a flex container applies
|
|
// between EVERY child, and a bare text node is a child — so an inline-flex
|
|
// row wrapped around "Clu", <i>Pilot</i> and " Cloud" put nine pixels
|
|
// between each of them.
|
|
//
|
|
// The rule that prevents it: the mark and the wordmark are the only two
|
|
// children of the flex row, and the wordmark is one element.
|
|
$source = File::get(resource_path('views/coming-soon.blade.php'));
|
|
|
|
expect($source)->toContain('<span class="word">CluPilot')
|
|
->and($source)->not->toContain('Clu<i>Pilot</i>');
|
|
});
|
|
|
|
it('draws the actual mark on the placeholder, not an empty tile', function () {
|
|
// It was a plain gradient square. A brand tile with nothing in it reads as
|
|
// an image that failed to load — on a "we are still building" page that is
|
|
// the last impression to leave.
|
|
//
|
|
// Inlined rather than pulled from x-ui.logo: this page renders when the
|
|
// asset build may not exist, and a Blade component is fine but the SVG has
|
|
// to be in the file either way.
|
|
$source = File::get(resource_path('views/coming-soon.blade.php'));
|
|
|
|
expect($source)->toContain('viewBox="0 0 64 64"')
|
|
// The ascent triangle — the part that makes it a mark rather than a
|
|
// rounded rectangle.
|
|
->and($source)->toContain('M32 17 44 44l-12-6-12 6z');
|
|
});
|