feat: lit-site-status, Admin-Tab und Admin-Hinweis zeigen Divi-Fähigkeiten mit Zustand, Quelle, Problemen und betroffenen Werkzeugen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
b92545a8fe
commit
2aef6e1154
@@ -11,6 +11,9 @@ use LIT\MCP\Admin\DiviTab;
|
||||
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
||||
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
||||
use LIT\MCP\Integrations\Divi\Release\CheckStep;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use LIT\MCP\Integrations\Divi\Release\FeatureOverview;
|
||||
use LIT\MCP\Integrations\Divi\Release\FeatureStatus;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
@@ -18,6 +21,8 @@ use LIT\MCP\Integrations\Divi\Release\ReleaseStore;
|
||||
use LIT\MCP\Integrations\Divi\Release\WriteProbe;
|
||||
use LIT\MCP\Plugin;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\FeatureFakeTool;
|
||||
use LIT\MCP\Tests\Support\MatrixFixtures;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -63,8 +68,12 @@ final class DiviTabTest extends TestCase
|
||||
return new CheckReport('r1', '2026-10-01T08:00:00+00:00', 1, $version, Plugin::VERSION, $key, $steps);
|
||||
}
|
||||
|
||||
private function tab(?CheckReport $report, ReleaseStore $releases, ?FakeChangeLog $log = null): DiviTab
|
||||
{
|
||||
private function tab(
|
||||
?CheckReport $report,
|
||||
ReleaseStore $releases,
|
||||
?FakeChangeLog $log = null,
|
||||
?FeatureOverview $overview = null
|
||||
): DiviTab {
|
||||
$reports = Mockery::mock(CheckReportStore::class);
|
||||
$reports->allows('latest')->andReturn($report);
|
||||
|
||||
@@ -75,7 +84,8 @@ final class DiviTabTest extends TestCase
|
||||
new AdminPostAction(static function (): void {
|
||||
}),
|
||||
static fn (): string => '5.3.0',
|
||||
static fn (string $version): string => 'key'
|
||||
static fn (string $version): string => 'key',
|
||||
$overview
|
||||
);
|
||||
}
|
||||
|
||||
@@ -154,6 +164,19 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
/** @return string The rendered tab. */
|
||||
private function rendered(ReleaseStatus $status, ?CheckReport $report, ?DiviTab $tab = null): string
|
||||
{
|
||||
return $this->renderedTab($status, $tab ?? $this->tab($report, Mockery::mock(ReleaseStore::class)));
|
||||
}
|
||||
|
||||
private function renderedWith(ReleaseStatus $status, ?CheckReport $report, FeatureOverview $overview): string
|
||||
{
|
||||
return $this->renderedTab(
|
||||
$status,
|
||||
$this->tab($report, Mockery::mock(ReleaseStore::class), null, $overview)
|
||||
);
|
||||
}
|
||||
|
||||
private function renderedTab(ReleaseStatus $status, DiviTab $tab): string
|
||||
{
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => $status);
|
||||
Functions\when('rest_url')->justReturn('https://k.de/wp-json/lit-mcp/v1/divi-check');
|
||||
@@ -167,7 +190,7 @@ final class DiviTabTest extends TestCase
|
||||
Functions\when('get_option')->justReturn('d.m.Y');
|
||||
|
||||
ob_start();
|
||||
($tab ?? $this->tab($report, Mockery::mock(ReleaseStore::class)))->render();
|
||||
$tab->render();
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
@@ -331,4 +354,191 @@ final class DiviTabTest extends TestCase
|
||||
static fn (): string => ''
|
||||
))->removeOrphans();
|
||||
}
|
||||
|
||||
private static function mixedStatus(): ReleaseStatus
|
||||
{
|
||||
$matrix = MatrixFixtures::released('auto', [
|
||||
new FeatureStatus(
|
||||
DiviFeature::PageWrite,
|
||||
ReleaseState::Incompatible,
|
||||
['Seiten: Signatur von et_pb_x() <geändert>'],
|
||||
null
|
||||
),
|
||||
new FeatureStatus(DiviFeature::Catalog, ReleaseState::Untested, [], null),
|
||||
]);
|
||||
|
||||
return new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, [], null, matrix: $matrix);
|
||||
}
|
||||
|
||||
public function testTheFeatureTableShowsStateSourceProblemsAndTools(): void
|
||||
{
|
||||
$overview = new FeatureOverview(static fn (): array => [
|
||||
new FeatureFakeTool('lit/divi-insert', true, [DiviFeature::PageRead, DiviFeature::PageWrite]),
|
||||
new FeatureFakeTool('lit/divi-presets-assign', false, [DiviFeature::PresetWrite]),
|
||||
]);
|
||||
|
||||
$html = $this->renderedWith(self::mixedStatus(), null, $overview);
|
||||
|
||||
self::assertStringContainsString('<th scope="col">Betroffene Werkzeuge</th>', $html);
|
||||
self::assertStringContainsString(
|
||||
'<td>Seiten schreiben</td><td><strong>inkompatibel</strong></td><td>–</td>',
|
||||
$html
|
||||
);
|
||||
self::assertStringContainsString('<td>Modulkatalog</td><td><strong>ungetestet</strong></td>', $html);
|
||||
self::assertStringContainsString(
|
||||
'<td>Seiten lesen</td><td><strong>freigegeben</strong></td><td>Automatik (auto)</td>',
|
||||
$html
|
||||
);
|
||||
self::assertStringContainsString('<li><code>lit-divi-insert</code></li>', $html);
|
||||
self::assertStringContainsString('<li><code>lit/divi-presets-assign</code></li>', $html);
|
||||
}
|
||||
|
||||
public function testFeatureProblemsAreEscaped(): void
|
||||
{
|
||||
$html = $this->rendered(self::mixedStatus(), null);
|
||||
|
||||
self::assertStringContainsString('Seiten: Signatur von et_pb_x() <geändert>', $html);
|
||||
self::assertStringNotContainsString('<geändert>', $html);
|
||||
}
|
||||
|
||||
public function testTheTableNamesEverySourceInWords(): void
|
||||
{
|
||||
$code = $this->rendered(ReleaseStatus::released('5.3.0'), null);
|
||||
$database = $this->rendered(
|
||||
new ReleaseStatus(ReleaseState::Released, '5.3.0', ReleaseStatus::SOURCE_DATABASE, [], [
|
||||
'released_at' => '2026-10-01T08:00:00+00:00', 'user_id' => 1,
|
||||
], matrix: MatrixFixtures::released('database')),
|
||||
self::report()
|
||||
);
|
||||
|
||||
self::assertStringContainsString('Plugin (code)', $code);
|
||||
self::assertStringContainsString('Freigabe auf dieser Website (database)', $database);
|
||||
}
|
||||
|
||||
public function testTheTabExplainsTheAutomationAndTheFilter(): void
|
||||
{
|
||||
$html = $this->rendered(ReleaseStatus::released('5.3.0'), null);
|
||||
|
||||
self::assertStringContainsString('gibt LIT MCP jede Fähigkeit einzeln frei', $html);
|
||||
self::assertStringContainsString('<code>lit_mcp_divi_auto_release</code>', $html);
|
||||
self::assertStringContainsString('als ungetestet', $html);
|
||||
self::assertStringContainsString('Aufrufe', $html);
|
||||
self::assertStringNotContainsString('Verhalten geprüft', $html);
|
||||
}
|
||||
|
||||
public function testTheTabNoLongerSaysWritingIsLockedAsAWhole(): void
|
||||
{
|
||||
$untested = $this->rendered(
|
||||
new ReleaseStatus(
|
||||
ReleaseState::Untested,
|
||||
'5.3.0',
|
||||
matrix: MatrixFixtures::with(DiviFeature::Catalog, ReleaseState::Untested)
|
||||
),
|
||||
null
|
||||
);
|
||||
$incompatible = $this->rendered(self::mixedStatus(), null);
|
||||
|
||||
foreach ([$untested, $incompatible] as $html) {
|
||||
self::assertStringNotContainsString('Schreiben bleibt gesperrt', $html);
|
||||
self::assertStringNotContainsString('lesen nur', $html);
|
||||
self::assertStringContainsString('alle anderen laufen weiter', $html);
|
||||
}
|
||||
}
|
||||
|
||||
public function testADatabaseReleaseCanBeWithdrawnWhileOneFeatureIsIncompatible(): void
|
||||
{
|
||||
$matrix = MatrixFixtures::released('database', [
|
||||
new FeatureStatus(DiviFeature::PageWrite, ReleaseState::Incompatible, ['Seiten: x() fehlt'], null),
|
||||
]);
|
||||
$status = new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', ReleaseStatus::SOURCE_DATABASE, [], [
|
||||
'released_at' => '2026-10-01T08:00:00+00:00', 'user_id' => 1,
|
||||
], matrix: $matrix);
|
||||
|
||||
self::assertStringContainsString('Freigabe zurückziehen', $this->rendered($status, self::report()));
|
||||
}
|
||||
|
||||
public function testWithoutADatabaseReleaseNothingCanBeWithdrawnWhateverTheState(): void
|
||||
{
|
||||
self::assertStringNotContainsString('Freigabe zurückziehen', $this->rendered(self::mixedStatus(), null));
|
||||
}
|
||||
|
||||
/** @return string The admin notice of this request. */
|
||||
private function notice(ReleaseStatus $status, string $version = '5.3.0'): string
|
||||
{
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => $status);
|
||||
$tab = new DiviTab(
|
||||
Mockery::mock(CheckReportStore::class),
|
||||
Mockery::mock(ReleaseStore::class),
|
||||
FakeChangeLog::forbidden(),
|
||||
new AdminPostAction(static function (): void {
|
||||
}),
|
||||
static fn () => $version,
|
||||
static fn (string $v): string => 'key'
|
||||
);
|
||||
|
||||
ob_start();
|
||||
$tab->renderNotice();
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
|
||||
public function testTheNoticeNamesTheUnusableFeaturesAndLinksToTheTab(): void
|
||||
{
|
||||
$html = $this->notice(self::mixedStatus());
|
||||
|
||||
self::assertStringContainsString('class="notice notice-warning"', $html);
|
||||
self::assertStringContainsString('Mit Divi 5.3.0 sind diese Fähigkeiten nicht nutzbar', $html);
|
||||
self::assertStringContainsString('Seiten schreiben, Modulkatalog', $html);
|
||||
self::assertStringContainsString('alle anderen laufen weiter', $html);
|
||||
self::assertStringContainsString('page=lit-mcp&tab=divi', $html);
|
||||
}
|
||||
|
||||
public function testNoNoticeWhileEveryFeatureIsUsable(): void
|
||||
{
|
||||
self::assertSame('', $this->notice(ReleaseStatus::released('5.3.0')));
|
||||
}
|
||||
|
||||
public function testNoNoticeForUsersWithoutManageOptions(): void
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
|
||||
self::assertSame('', $this->notice(self::mixedStatus()));
|
||||
}
|
||||
|
||||
public function testNoNoticeWithoutDivi(): void
|
||||
{
|
||||
self::assertSame('', $this->notice(self::mixedStatus(), ''));
|
||||
}
|
||||
|
||||
public function testNoNoticeOnTheDiviTabItself(): void
|
||||
{
|
||||
Functions\when('get_current_screen')->justReturn((object) ['id' => 'settings_page_lit-mcp']);
|
||||
$_GET['tab'] = 'divi';
|
||||
|
||||
self::assertSame('', $this->notice(self::mixedStatus()));
|
||||
}
|
||||
|
||||
public function testTheNoticeStillShowsOnOtherTabsOfThePluginPage(): void
|
||||
{
|
||||
Functions\when('get_current_screen')->justReturn((object) ['id' => 'settings_page_lit-mcp']);
|
||||
$_GET['tab'] = 'tools';
|
||||
|
||||
self::assertStringContainsString('nicht nutzbar', $this->notice(self::mixedStatus()));
|
||||
}
|
||||
|
||||
public function testTheNoticeIsRegisteredOnAdminNotices(): void
|
||||
{
|
||||
$tab = $this->tab(null, Mockery::mock(ReleaseStore::class));
|
||||
Actions\expectAdded('admin_notices')->once()->with([$tab, 'renderNotice']);
|
||||
|
||||
$tab->registerNotice();
|
||||
}
|
||||
|
||||
public function testRegisteringTheTabsActionsAlsoRegistersTheNotice(): void
|
||||
{
|
||||
$tab = $this->tab(null, Mockery::mock(ReleaseStore::class));
|
||||
Actions\expectAdded('admin_notices')->once()->with([$tab, 'renderNotice']);
|
||||
|
||||
$tab->registerActions();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user