name)->toBe('counter'); expect($id->instanceId)->toBe('demo'); expect($id->toString())->toBe('counter:demo'); }); it('generates new component ID with unique instance', function () { $id1 = ComponentId::generate('search'); $id2 = ComponentId::generate('search'); expect($id1->name)->toBe('search'); expect($id2->name)->toBe('search'); expect($id1->instanceId !== $id2->instanceId)->toBeTrue(); }); it('creates with specific instance ID', function () { $id = ComponentId::create('modal', 'main-dialog'); expect($id->name)->toBe('modal'); expect($id->instanceId)->toBe('main-dialog'); expect($id->toString())->toBe('modal:main-dialog'); }); it('converts to string with __toString', function () { $id = ComponentId::fromString('tabs:settings'); expect((string) $id)->toBe('tabs:settings'); }); it('checks equality correctly', function () { $id1 = ComponentId::fromString('counter:demo'); $id2 = ComponentId::fromString('counter:demo'); $id3 = ComponentId::fromString('counter:other'); expect($id1->equals($id2))->toBeTrue(); expect($id1->equals($id3))->toBeFalse(); }); it('checks component name', function () { $id = ComponentId::fromString('search:main-form'); expect($id->hasName('search'))->toBeTrue(); expect($id->hasName('counter'))->toBeFalse(); }); it('throws exception for empty ID', function () { ComponentId::fromString(''); })->throws(InvalidArgumentException::class, 'Component ID cannot be empty'); it('throws exception for invalid format', function () { ComponentId::fromString('invalid-format'); })->throws(InvalidArgumentException::class, 'Invalid component ID format'); it('throws exception for empty name', function () { ComponentId::fromString(':instance'); })->throws(InvalidArgumentException::class, 'Component name cannot be empty'); it('throws exception for empty instance ID', function () { ComponentId::fromString('component:'); })->throws(InvalidArgumentException::class, 'Instance ID cannot be empty'); it('throws exception for invalid name characters', function () { ComponentId::create('invalid/name', 'instance'); })->throws(InvalidArgumentException::class, 'Invalid component name format'); it('accepts valid name formats', function (string $name) { $id = ComponentId::create($name, 'test'); expect($id->name)->toBe($name); })->with([ 'lowercase' => 'counter', 'with-hyphens' => 'search-component', 'with_underscores' => 'data_table', 'with-numbers' => 'tab1', 'mixed' => 'live-component_v2', ]); it('handles complex instance IDs', function () { $instanceId = 'user-123_session-abc.def'; $id = ComponentId::create('profile', $instanceId); expect($id->instanceId)->toBe($instanceId); expect($id->toString())->toBe("profile:{$instanceId}"); }); it('parses component ID with multiple colons correctly', function () { // Should only split on first colon $id = ComponentId::fromString('component:instance:with:colons'); expect($id->name)->toBe('component'); expect($id->instanceId)->toBe('instance:with:colons'); }); });