feat: lit/divi-variables-set prüft Schrift-Variablen gegen Divis Schriftliste (mit Vorschlägen)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 17:56:58 +02:00
co-authored by Claude Sonnet 5.5
parent dab4a9ba2e
commit 449ec5c33f
4 changed files with 71 additions and 8 deletions
@@ -10,6 +10,7 @@ use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\Integrations\Divi\Design\DesignChange;
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
use LIT\MCP\Integrations\Divi\Design\DiviVariablesSetAbility;
use LIT\MCP\Integrations\Divi\Design\FontCatalog;
use LIT\MCP\Integrations\Divi\Design\GlobalVariablesAdapter;
use LIT\MCP\Integrations\Divi\Design\ReferenceUsageQuery;
use LIT\MCP\Integrations\Divi\Design\SnapshotStore;
@@ -48,7 +49,8 @@ final class DiviVariablesSetAbilityTest extends TestCase
?SnapshotStore $snapshots = null,
array $presets = [],
?GlobalVariablesAdapter $variables = null,
bool $manage = true
bool $manage = true,
?FontCatalog $fonts = null
): DiviVariablesSetAbility {
$writer = Mockery::mock(DesignSystemWriter::class);
$writer->allows('canUseVisualBuilder')->andReturn(true);
@@ -60,6 +62,7 @@ final class DiviVariablesSetAbilityTest extends TestCase
$variables ?? VariableAreaTest::adapter($this->stored, $this->saves, $manage),
new DesignChange($snapshots ?? Mockery::mock(SnapshotStore::class), new FakeChangeLog(3)),
$usages ?? self::usages(self::unused()),
$fonts ?? FontCheckTest::catalog(),
static function (int $length) use (&$counter): string {
return str_pad((string) ++$counter, $length, '0', STR_PAD_LEFT);
}
@@ -377,4 +380,56 @@ final class DiviVariablesSetAbilityTest extends TestCase
self::assertSame([], $dry['warnings']);
}
/** Ruling W12: a font variable names a font Divi knows exactly; unknown names get suggestions. */
public function testFontVariablesNeedAFontDiviKnows(): void
{
$error = $this->ability()
->execute(['items' => [['type' => 'fonts', 'label' => 'Marke', 'value' => 'robotto']]]);
self::assertToolError($error, 'validation_failed');
$fields = self::errorFields($error);
self::assertSame(['items[0].value'], array_keys($fields));
self::assertStringStartsWith('unbekannte Schrift „robotto“; ähnlich: ', $fields['items[0].value']);
self::assertStringContainsString('Roboto', $fields['items[0].value']);
self::assertSame([], $this->saves);
}
public function testAFontVariableWithAKnownFontIsPlanned(): void
{
$dry = self::assertToolError(
$this->ability()->execute(['items' => [['type' => 'fonts', 'label' => 'Marke', 'value' => 'Roboto Slab']]]),
'confirm_required'
);
self::assertSame(['added'], array_column($dry['diff'], 'action'));
}
/** The font list is loaded only for font variables (it costs 1.3 MB, ruling W5). */
public function testOtherTypesDoNotLoadTheFontList(): void
{
$fonts = Mockery::mock(FontCatalog::class);
$fonts->shouldNotReceive('has', 'names');
self::assertToolError(
$this->ability(fonts: $fonts)->execute(['items' => [
['type' => 'strings', 'label' => 'Gruß', 'value' => 'Hallo'],
['id' => 'Eckenradius', 'value' => '12px'],
]]),
'confirm_required'
);
}
/** VariableValue checks first: a malformed name never reaches the font list. */
public function testAMalformedFontNameFailsBeforeTheFontList(): void
{
$fonts = Mockery::mock(FontCatalog::class);
$fonts->shouldNotReceive('has', 'names');
$error = $this->ability(fonts: $fonts)
->execute(['items' => [['type' => 'fonts', 'label' => 'Marke', 'value' => 'Roboto; x']]]);
self::assertToolError($error, 'validation_failed');
self::assertStringStartsWith('Schrift:', self::errorFields($error)['items[0].value']);
}
}