- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
213 lines
6.7 KiB
PHP
213 lines
6.7 KiB
PHP
<?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();
|
|
});
|
|
});
|