feat: lit/divi-presets-delete – unbenutzte Presets löschen

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-16 17:50:29 +02:00
co-authored by Claude Sonnet 5.5
parent 25720ad086
commit 2e8f723b01
6 changed files with 300 additions and 2 deletions
@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
use Brain\Monkey\Functions;
use LIT\MCP\Integrations\Divi\Design\DesignChange;
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
use LIT\MCP\Integrations\Divi\Design\DiviPresetsDeleteAbility;
use LIT\MCP\Integrations\Divi\Design\SnapshotStore;
use LIT\MCP\Integrations\Divi\Library\GlobalUsages;
use LIT\MCP\Integrations\Divi\Library\UsageReport;
use LIT\MCP\Tests\Support\FakeChangeLog;
use LIT\MCP\Tests\Unit\TestCase;
use Mockery;
final class DiviPresetsDeleteAbilityTest extends TestCase
{
private function ability(UsageReport $report, ?DesignSystemWriter $writer = null, ?SnapshotStore $snapshots = null): DiviPresetsDeleteAbility
{
Functions\when('current_user_can')->justReturn(true);
if ($writer === null) {
$writer = Mockery::mock(DesignSystemWriter::class);
$writer->allows('presets')->andReturn(PresetBookTest::stored());
$writer->allows('canUseVisualBuilder')->andReturn(true);
}
$usages = Mockery::mock(GlobalUsages::class);
$usages->allows('reportFor')->andReturn($report);
return new DiviPresetsDeleteAbility(
$writer,
new DesignChange($snapshots ?? Mockery::mock(SnapshotStore::class), new FakeChangeLog(3)),
$usages
);
}
private static function unused(): UsageReport
{
return new UsageReport(0, [], 0, 0, [], 0, false);
}
public function testUnusedPresetIsDeletedAfterConfirm(): void
{
$writer = Mockery::mock(DesignSystemWriter::class);
$writer->allows('presets')->andReturn(PresetBookTest::stored());
$writer->allows('canUseVisualBuilder')->andReturn(true);
$writer->expects('savePresets')
->with(Mockery::on(static function (array $rest): bool {
$ids = array_column($rest['module'][0]['items'], 'id');
return $ids === ['aaaaaaaaaa', 'cccccccccc'];
}), true)
->andReturnUsing(static function (): array {
$stored = PresetBookTest::stored();
unset($stored['module']['divi/button']['items']['bbbbbbbbbb']);
return $stored;
});
$snapshots = Mockery::mock(SnapshotStore::class);
$snapshots->expects('save')->andReturn('presets-9');
$snapshots->expects('attachLog');
$ability = $this->ability(self::unused(), $writer, $snapshots);
$input = ['items' => [['module' => 'button', 'preset' => 'bbbbbbbbbb']]];
$dry = self::assertToolError($ability->execute($input), 'confirm_required');
self::assertSame('removed', $dry['diff'][0]['action']);
$result = $ability->execute($input + ['confirm' => true, 'design_rev' => $dry['design_rev']]);
self::assertSame('presets-9', $result['snapshot_id']);
}
public function testPresetInUseIsRefused(): void
{
$used = new UsageReport(2, [['post_id' => 3, 'title' => 'Start', 'status' => 'publish', 'type' => 'page']],
1, 1, [], 0, false);
$error = self::assertToolError(
$this->ability($used)->execute(['items' => [['module' => 'button', 'preset' => 'CTA primär']]]),
'in_use'
);
self::assertSame(3, $error['usages'][0]['post_id']);
self::assertStringContainsString('lit/divi-design-detach', $error['hint']);
}
public function testNestedUseInAnotherPresetCounts(): void
{
$error = self::assertToolError(
$this->ability(self::unused())->execute(['items' => [['group' => 'font-body', 'preset' => 'Lesetext']]]),
'in_use'
);
self::assertSame('preset', $error['usages'][0]['type']);
self::assertSame('dddddddddd', $error['usages'][0]['preset_id']);
}
public function testDeletingTheDefaultClearsIt(): void
{
$dry = self::assertToolError(
$this->ability(self::unused())->execute(['items' => [['module' => 'text', 'preset' => 'Fließtext']]]),
'confirm_required'
);
self::assertSame(['removed', 'default_cleared'], array_column($dry['diff'], 'action'));
}
public function testUnknownPreset(): void
{
self::assertToolError(
$this->ability(self::unused())->execute(['items' => [['module' => 'button', 'preset' => 'Fehlt']]]),
'validation_failed'
);
}
}
@@ -33,6 +33,7 @@ final class DiviIntegrationTest extends TestCase
'lit/divi-dynamic-sources',
'lit/divi-preset-get',
'lit/divi-presets-set',
'lit/divi-presets-delete',
];
public function testProvidesTheDiviAbilitiesOnlyWithDivi5(): void