fix: TB dry runs hide uneditable live templates, off-switch despite draft (rulings Q20, Q21)
- ThemeBuilderAccess::editableLiveTemplates() shared by tb-list and the tb-assign/tb-activate dry runs; uneditable live templates only as a count (hidden_overlaps, hidden_live) - tb-activate enabled:false works while the Theme Builder has a draft, with a warning - possible_overlaps skips identical conditions; reattach records the previous enabled state; exclude_from must be a list; tb-activate live from the read-back Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,26 @@ final class TbActivateAbilityTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/** A store with $template on the live list whose read-back follows one setEnabled() call. */
|
||||
private static function switchable(Template $template): DiviThemeBuilder
|
||||
{
|
||||
$current = $template;
|
||||
$store = ThemeBuilderFixtures::store([$template]);
|
||||
$store->shouldReceive('template')->andReturnUsing(static function () use (&$current): Template {
|
||||
return $current;
|
||||
});
|
||||
$store->shouldReceive('setEnabled')->once()->with($template->id, ! $template->enabled)->andReturnUsing(
|
||||
static function (int $id, bool $enabled) use (&$current, $template): void {
|
||||
$current = ThemeBuilderFixtures::template($id, [
|
||||
'enabled' => $enabled,
|
||||
'use_on' => $template->useOn,
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
return $store;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private static function input(Template $template, bool $enabled, bool $confirm = false): array
|
||||
{
|
||||
@@ -91,8 +111,7 @@ final class TbActivateAbilityTest extends TestCase
|
||||
public function testConfirmedActivationSwitchesOnlyTheFlag(): void
|
||||
{
|
||||
$template = ThemeBuilderFixtures::template(1066);
|
||||
$store = ThemeBuilderFixtures::store([$template]);
|
||||
$store->shouldReceive('setEnabled')->once()->with(1066, true);
|
||||
$store = self::switchable($template);
|
||||
$store->shouldReceive('clearCaches')->once();
|
||||
$store->shouldReceive('setConditions')->never();
|
||||
$store->shouldReceive('attach')->never();
|
||||
@@ -112,8 +131,7 @@ final class TbActivateAbilityTest extends TestCase
|
||||
public function testDeactivationAlsoNeedsConfirm(): void
|
||||
{
|
||||
$template = ThemeBuilderFixtures::template(1066, ['enabled' => true]);
|
||||
$store = ThemeBuilderFixtures::store([$template]);
|
||||
$store->shouldReceive('setEnabled')->once()->with(1066, false);
|
||||
$store = self::switchable($template);
|
||||
$store->shouldReceive('clearCaches')->once();
|
||||
|
||||
$dry = self::ability($store)->execute(self::input($template, false));
|
||||
@@ -243,4 +261,75 @@ final class TbActivateAbilityTest extends TestCase
|
||||
}
|
||||
$log->assertPartials(['ability' => 'lit/tb-activate', 'object_type' => 'et_template', 'object_id' => '1066']);
|
||||
}
|
||||
|
||||
/** Fix round 1: live is what the read-back shows, not what was asked for. */
|
||||
public function testLiveComesFromTheReadBack(): void
|
||||
{
|
||||
$template = ThemeBuilderFixtures::template(1066);
|
||||
$store = ThemeBuilderFixtures::store([$template]);
|
||||
$store->shouldReceive('setEnabled')->once()->with(1066, true);
|
||||
$store->shouldReceive('clearCaches')->once();
|
||||
|
||||
$result = self::ability($store)->execute(self::input($template, true, true));
|
||||
|
||||
self::assertTrue($result['enabled']);
|
||||
self::assertFalse($result['live'], 'the read-back still shows the template disabled');
|
||||
}
|
||||
|
||||
/** Ruling Q21: live templates the user may not edit appear in the dry run only as a number. */
|
||||
public function testDryRunHidesLiveTemplatesTheUserMayNotEdit(): void
|
||||
{
|
||||
Functions\when('current_user_can')->alias(
|
||||
static fn (string $cap, mixed ...$args): bool => ! ($cap === 'edit_post' && ($args[0] ?? 0) === 1071)
|
||||
);
|
||||
$template = ThemeBuilderFixtures::template(1066, ['use_on' => ['singular:post_type:page:all']]);
|
||||
$mine = ThemeBuilderFixtures::template(1070, ['enabled' => true, 'title' => 'Meine', 'use_on' => ['homepage']]);
|
||||
$secret = ThemeBuilderFixtures::template(1071, [
|
||||
'enabled' => true,
|
||||
'title' => 'Geheim',
|
||||
'use_on' => ['singular:post_type:page:all'],
|
||||
]);
|
||||
$store = ThemeBuilderFixtures::store([$template, $mine, $secret]);
|
||||
$store->shouldReceive('setEnabled')->never();
|
||||
|
||||
$dry = self::ability($store, FakeChangeLog::forbidden())->execute(self::input($template, true));
|
||||
|
||||
self::assertToolError($dry, 'confirm_required');
|
||||
self::assertSame([], $dry->get_error_data()['overlaps']);
|
||||
self::assertSame([1070], array_column($dry->get_error_data()['possible_overlaps'], 'id'));
|
||||
self::assertSame(1, $dry->get_error_data()['hidden_overlaps']);
|
||||
self::assertStringContainsString('ohne Berechtigung, die sich überschneiden können: 1', self::clientError($dry)['message']);
|
||||
$all = (string) json_encode([$dry->get_error_data(), self::clientError($dry)], JSON_UNESCAPED_UNICODE);
|
||||
self::assertStringNotContainsString('1071', $all);
|
||||
self::assertStringNotContainsString('Geheim', $all);
|
||||
}
|
||||
|
||||
/** Ruling Q20: switching off works while the Theme Builder has unsaved changes – with a warning. */
|
||||
public function testTheOffSwitchWorksWithADraftAndWarns(): void
|
||||
{
|
||||
$template = ThemeBuilderFixtures::template(1066, ['enabled' => true]);
|
||||
$store = ThemeBuilderFixtures::store([$template], 999);
|
||||
$store->shouldReceive('setEnabled')->once()->with(1066, false);
|
||||
$store->shouldReceive('clearCaches')->once();
|
||||
|
||||
self::assertTrue(self::ability($store)->permission(self::input($template, false)));
|
||||
$dry = self::ability($store)->execute(self::input($template, false));
|
||||
self::assertToolError($dry, 'confirm_required');
|
||||
self::assertStringContainsString('ungespeicherte Änderungen', self::clientError($dry)['message']);
|
||||
|
||||
$result = self::ability($store)->execute(self::input($template, false, true));
|
||||
self::assertTrue($result['ok']);
|
||||
self::assertStringContainsString('ungespeicherte Änderungen', implode(' ', $result['warnings']));
|
||||
}
|
||||
|
||||
/** Ruling Q20: the draft exemption is for switching off only. */
|
||||
public function testTheOnSwitchIsRefusedWithADraft(): void
|
||||
{
|
||||
$template = ThemeBuilderFixtures::template(1066);
|
||||
$store = ThemeBuilderFixtures::store([$template], 999);
|
||||
$store->shouldReceive('setEnabled')->never();
|
||||
|
||||
self::assertToolError(self::ability($store)->permission(self::input($template, true)), 'unsupported');
|
||||
self::assertToolError(self::ability($store)->execute(self::input($template, true, true)), 'unsupported');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user