Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
212
tests/Framework/Design/Parser/CssParserTest.php
Normal file
212
tests/Framework/Design/Parser/CssParserTest.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\Design\Parser\ClassNameParser;
|
||||
use App\Framework\Design\Parser\CssParser;
|
||||
use App\Framework\Design\Parser\CustomPropertyParser;
|
||||
use App\Framework\Design\ValueObjects\ColorFormat;
|
||||
use App\Framework\Design\ValueObjects\CssColor;
|
||||
use App\Framework\Filesystem\FilePath;
|
||||
|
||||
describe('CssParser', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
$this->customPropertyParser = new CustomPropertyParser();
|
||||
$this->classNameParser = new ClassNameParser();
|
||||
$this->parser = new CssParser($this->customPropertyParser, $this->classNameParser);
|
||||
});
|
||||
|
||||
it('parses simple CSS content', function () {
|
||||
$css = '
|
||||
:root {
|
||||
--primary-color: #3b82f6;
|
||||
--text-size: 16px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: var(--primary-color);
|
||||
padding: 0.5rem 1rem;
|
||||
color: white;
|
||||
}
|
||||
';
|
||||
|
||||
$result = $this->parser->parseContent($css);
|
||||
|
||||
expect($result->rules)->toHaveCount(2);
|
||||
expect($result->customProperties)->toHaveCount(2);
|
||||
expect($result->classNames)->toHaveCount(1);
|
||||
|
||||
// Test custom properties
|
||||
$primaryColor = $result->customProperties[0];
|
||||
expect($primaryColor->name)->toBe('primary-color');
|
||||
expect($primaryColor->value)->toBe('#3b82f6');
|
||||
|
||||
// Test class names
|
||||
$buttonClass = $result->classNames[0];
|
||||
expect($buttonClass->name)->toBe('button');
|
||||
expect($buttonClass->isBemBlock())->toBeTrue();
|
||||
});
|
||||
|
||||
it('parses BEM classes correctly', function () {
|
||||
$css = '
|
||||
.card { }
|
||||
.card__header { }
|
||||
.card__body { }
|
||||
.card--featured { }
|
||||
.card__header--large { }
|
||||
';
|
||||
|
||||
$result = $this->parser->parseContent($css);
|
||||
|
||||
expect($result->classNames)->toHaveCount(5);
|
||||
|
||||
$classes = array_map(fn ($c) => $c->name, $result->classNames);
|
||||
expect($classes)->toContain('card');
|
||||
expect($classes)->toContain('card__header');
|
||||
expect($classes)->toContain('card__body');
|
||||
expect($classes)->toContain('card--featured');
|
||||
expect($classes)->toContain('card__header--large');
|
||||
|
||||
// Test BEM detection
|
||||
$cardClass = $result->classNames[0];
|
||||
expect($cardClass->isBemBlock())->toBeTrue();
|
||||
|
||||
$headerClass = $result->classNames[1];
|
||||
expect($headerClass->isBemElement())->toBeTrue();
|
||||
|
||||
$featuredClass = $result->classNames[3];
|
||||
expect($featuredClass->isBemModifier())->toBeTrue();
|
||||
});
|
||||
|
||||
it('handles OKLCH colors', function () {
|
||||
$css = '
|
||||
:root {
|
||||
--modern-blue: oklch(0.7 0.15 260);
|
||||
--vibrant-red: oklch(65% 0.2 20deg);
|
||||
}
|
||||
';
|
||||
|
||||
$result = $this->parser->parseContent($css);
|
||||
|
||||
expect($result->customProperties)->toHaveCount(2);
|
||||
|
||||
$blueToken = $result->customProperties[0];
|
||||
expect($blueToken->name)->toBe('modern-blue');
|
||||
expect($blueToken->hasValueType('color'))->toBeTrue();
|
||||
|
||||
$color = $blueToken->getValueAs('color');
|
||||
expect($color)->toBeInstanceOf(CssColor::class);
|
||||
expect($color->format)->toBe(ColorFormat::OKLCH);
|
||||
});
|
||||
|
||||
it('parses complex selectors', function () {
|
||||
$css = '
|
||||
.nav-menu > .nav-item:hover .nav-link {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
$result = $this->parser->parseContent($css);
|
||||
|
||||
expect($result->rules)->toHaveCount(2);
|
||||
|
||||
// Complex selector
|
||||
$complexRule = $result->rules[0];
|
||||
expect($complexRule->selectors)->toHaveCount(1);
|
||||
expect($complexRule->selectors[0]->value)->toContain('nav-menu');
|
||||
expect($complexRule->selectors[0]->extractClasses())->toContain('nav-menu');
|
||||
expect($complexRule->selectors[0]->extractClasses())->toContain('nav-item');
|
||||
expect($complexRule->selectors[0]->extractClasses())->toContain('nav-link');
|
||||
});
|
||||
|
||||
it('calculates selector specificity correctly', function () {
|
||||
$css = '
|
||||
.simple { }
|
||||
#unique { }
|
||||
div.class { }
|
||||
.parent > .child:hover { }
|
||||
#main .sidebar .widget { }
|
||||
';
|
||||
|
||||
$result = $this->parser->parseContent($css);
|
||||
|
||||
expect($result->rules)->toHaveCount(5);
|
||||
|
||||
// .simple = 10
|
||||
expect($result->rules[0]->selectors[0]->calculateSpecificity())->toBe(10);
|
||||
|
||||
// #unique = 100
|
||||
expect($result->rules[1]->selectors[0]->calculateSpecificity())->toBe(100);
|
||||
|
||||
// div.class = 11 (1 element + 10 class)
|
||||
expect($result->rules[2]->selectors[0]->calculateSpecificity())->toBe(11);
|
||||
|
||||
// .parent > .child:hover = 30 (20 classes + 10 pseudo-class)
|
||||
expect($result->rules[3]->selectors[0]->calculateSpecificity())->toBe(30);
|
||||
|
||||
// #main .sidebar .widget = 120 (100 ID + 20 classes)
|
||||
expect($result->rules[4]->selectors[0]->calculateSpecificity())->toBe(120);
|
||||
});
|
||||
|
||||
it('parses file from filesystem', function () {
|
||||
// Create temporary CSS file
|
||||
$tempFile = sys_get_temp_dir() . '/test-' . uniqid() . '.css';
|
||||
file_put_contents($tempFile, '
|
||||
:root {
|
||||
--test-color: #ff0000;
|
||||
}
|
||||
.test-class {
|
||||
color: var(--test-color);
|
||||
}
|
||||
');
|
||||
|
||||
$filePath = new FilePath($tempFile);
|
||||
$result = $this->parser->parseFile($filePath);
|
||||
|
||||
expect($result->customProperties)->toHaveCount(1);
|
||||
expect($result->classNames)->toHaveCount(1);
|
||||
expect($result->rules)->toHaveCount(2);
|
||||
|
||||
// Cleanup
|
||||
unlink($tempFile);
|
||||
});
|
||||
|
||||
it('handles empty CSS gracefully', function () {
|
||||
$result = $this->parser->parseContent('');
|
||||
|
||||
expect($result->rules)->toHaveCount(0);
|
||||
expect($result->customProperties)->toHaveCount(0);
|
||||
expect($result->classNames)->toHaveCount(0);
|
||||
expect($result->statistics['total_rules'])->toBe(0);
|
||||
});
|
||||
|
||||
it('parses utility classes', function () {
|
||||
$css = '
|
||||
.text-center { text-align: center; }
|
||||
.p-4 { padding: 1rem; }
|
||||
.bg-red-500 { background-color: #ef4444; }
|
||||
.hover\\:bg-blue-500:hover { background-color: #3b82f6; }
|
||||
';
|
||||
|
||||
$result = $this->parser->parseContent($css);
|
||||
|
||||
expect($result->classNames)->toHaveCount(4);
|
||||
|
||||
$classes = array_map(fn ($c) => $c->name, $result->classNames);
|
||||
expect($classes)->toContain('text-center');
|
||||
expect($classes)->toContain('p-4');
|
||||
expect($classes)->toContain('bg-red-500');
|
||||
expect($classes)->toContain('hover:bg-blue-500');
|
||||
|
||||
// Test utility detection
|
||||
$utilityClass = $result->classNames[1]; // p-4
|
||||
expect($utilityClass->isUtilityClass())->toBeTrue();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user