Files
WP-LIT-MCP/tests/Unit/Integrations/Divi/Pages/DynamicFieldsTest.php
T
janniclas.loosenandClaude Opus 5.5 6288acf0e6 perf: DynamicFields reads each post type's fields once per check (review M-12 b)
reason() and note() run per key and type of a body check; they now share one
offered() result per post type, so the default storage callback loads each
pod once instead of per call.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-27 23:12:14 +02:00

133 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
use LIT\MCP\Integrations\Divi\Pages\DynamicFields;
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
use LIT\MCP\Integrations\WordPress\Schema\FieldDefinition;
use LIT\MCP\Tests\Support\DiviFixtures;
use LIT\MCP\Tests\Unit\TestCase;
use Mockery;
final class DynamicFieldsTest extends TestCase
{
private static function fields(): DynamicFields
{
$schema = Mockery::mock(ContentSchema::class);
$schema->allows('fields')->with('lit_person')->andReturn([
new FieldDefinition('role', 'Funktion', 'string', 'pods', FieldDefinition::WRITABLE),
new FieldDefinition('level', 'Stufe', 'choice', 'pods', FieldDefinition::WRITABLE),
new FieldDefinition('mentor', 'Mentor', 'relation', 'pods', FieldDefinition::WRITABLE),
]);
return new DynamicFields($schema, static fn (string $type): ?string => 'meta');
}
public function testTextLikeFieldsAreOfferedOthersOmittedWithTheirReason(): void
{
[$offered, $omitted] = self::fields()->offered('lit_person');
self::assertSame(['role', 'level'], array_column($offered, 'key'));
self::assertSame('{{field:role}}', $offered[0]['placeholder']);
self::assertSame(['mentor'], array_column($omitted, 'key'));
}
public function testReasonForOneKey(): void
{
self::assertNull(self::fields()->reason('lit_person', 'role'));
self::assertStringContainsString('nur IDs', (string) self::fields()->reason('lit_person', 'mentor'));
self::assertSame('kein bekanntes Feld dieses Inhaltstyps', self::fields()->reason('lit_person', 'telefon'));
}
/** Answer F4 / stage3b render: a choice field shows its stored value ("senior"), not the label. */
public function testChoiceFieldsGetANoteAboutTheStoredValue(): void
{
self::assertStringContainsString('gespeicherten Wert', (string) self::fields()->note('lit_person', 'level'));
self::assertNull(self::fields()->note('lit_person', 'role'));
self::assertNull(self::fields()->note('lit_person', 'mentor'));
self::assertNull(self::fields()->note('lit_person', 'telefon'));
}
/** Review M-12 (b): reason() and note() read a type's fields (and its Pods storage) once per instance. */
public function testReasonAndNoteReadEachTypeOnce(): void
{
$schema = Mockery::mock(ContentSchema::class);
$schema->shouldReceive('fields')->with('lit_person')->once()->andReturn([
new FieldDefinition('role', 'Funktion', 'string', 'pods', FieldDefinition::WRITABLE),
]);
$storage = 0;
$fields = new DynamicFields($schema, static function (string $type) use (&$storage): ?string {
++$storage;
return 'meta';
});
foreach (['role', 'telefon', 'role'] as $key) {
$fields->reason('lit_person', $key);
$fields->note('lit_person', $key);
}
self::assertSame(1, $storage);
}
private static function content(string $name, array $settings): string
{
return VariableRef::serialize('content', $name, $settings);
}
/** Ruling Q11 / stage3b finding 12: both forms Divi resolves (DynamicContentOptionPostMetaKey.php:222-262). */
public function testMetaKeyOfReadsBothFormsDiviWrites(): void
{
self::assertSame('role', DynamicFields::metaKeyOf(self::content('custom_meta_role', ['before' => ''])));
self::assertSame('role', DynamicFields::metaKeyOf(self::content('post_meta_key', [
'before' => '',
'after' => '',
'select_meta_key' => 'custom_meta_role',
'meta_key' => '',
'date_format' => 'default',
'custom_date_format' => '',
'enable_html' => 'off',
])));
self::assertSame('telefon', DynamicFields::metaKeyOf(self::content('post_meta_key', ['meta_key' => 'telefon'])));
self::assertSame('telefon', DynamicFields::metaKeyOf(self::content('post_meta_key', [
'select_meta_key' => 'custom_meta_manual_custom_field_value',
'meta_key' => 'telefon',
])));
self::assertSame('telefon', DynamicFields::metaKeyOf(self::content(
'custom_meta_manual_custom_field_value',
['meta_key' => 'telefon']
)));
}
public function testMetaKeyOfIgnoresEverythingElse(): void
{
self::assertNull(DynamicFields::metaKeyOf(self::content('post_title', ['before' => ''])));
self::assertNull(DynamicFields::metaKeyOf(self::content('post_meta_key', ['meta_key' => ''])));
self::assertNull(DynamicFields::metaKeyOf(self::content('post_meta_key', ['select_meta_key' => 'role'])));
self::assertNull(DynamicFields::metaKeyOf(self::content('custom_meta_', [])));
self::assertNull(DynamicFields::metaKeyOf(
'$variable({"type":"color","value":{"name":"custom_meta_role","settings":{}}})$'
));
self::assertNull(DynamicFields::metaKeyOf('custom_meta_role'));
}
/** The real builder output (stage3b body 2391) names role, level and mentor. */
public function testMetaKeysOfTheRealBuilderBody(): void
{
$content = DiviFixtures::markup('stage3b/tb-body--person-body.html');
preg_match_all('/"value":"(\$variable\(.*?\)\$)"/', $content, $matches);
$keys = [];
foreach ($matches[1] as $value) {
$key = DynamicFields::metaKeyOf((string) json_decode('"' . $value . '"'));
if ($key !== null) {
$keys[] = $key;
}
}
self::assertSame(['role', 'level', 'mentor'], $keys);
}
}