create([ 'platform' => 'B1', 'signal_type' => 'site', 'unique_key' => 'example.com', ]); $resolver = new SupplierProjectResolver; $resolved = $resolver->resolveOrStub('B1', 'site', 'example.com'); expect($resolved->id)->toBe($existing->id); }); test('resolveOrStub creates pending stub when no existing project', function () { $resolver = new SupplierProjectResolver; $resolved = $resolver->resolveOrStub('B2', 'call', '79991234567'); expect($resolved->exists)->toBeTrue(); expect($resolved->platform)->toBe('B2'); expect($resolved->signal_type)->toBe('call'); expect($resolved->unique_key)->toBe('79991234567'); expect($resolved->sync_status)->toBe('pending'); expect($resolved->current_limit)->toBe(0); expect($resolved->current_workdays)->toBe([1, 2, 3, 4, 5, 6, 7]); }); test('resolveOrStub returns same row on second call (no duplicates)', function () { $resolver = new SupplierProjectResolver; $first = $resolver->resolveOrStub('B3', 'sms', 'TINKOFF'); $second = $resolver->resolveOrStub('B3', 'sms', 'TINKOFF'); expect($first->id)->toBe($second->id); expect(SupplierProject::where('unique_key', 'TINKOFF')->count())->toBe(1); }); test('resolveOrStub throws DomainException for B1+sms (forbidden combo)', function () { $resolver = new SupplierProjectResolver; expect(fn () => $resolver->resolveOrStub('B1', 'sms', 'TINKOFF')) ->toThrow(DomainException::class); }); test('resolveOrStub throws InvalidArgumentException for invalid platform', function () { $resolver = new SupplierProjectResolver; expect(fn () => $resolver->resolveOrStub('B9', 'site', 'a.com')) ->toThrow(InvalidArgumentException::class); }); test('resolveOrStub throws InvalidArgumentException for invalid signal_type', function () { $resolver = new SupplierProjectResolver; expect(fn () => $resolver->resolveOrStub('B1', 'unknown_type', 'a.com')) ->toThrow(InvalidArgumentException::class); }); test('resolveOrStub throws DomainException when unique_key collides across signal_types', function () { SupplierProject::factory()->create([ 'platform' => 'B2', 'signal_type' => 'sms', 'unique_key' => 'TINKOFF', ]); $resolver = new SupplierProjectResolver; expect(fn () => $resolver->resolveOrStub('B2', 'site', 'TINKOFF')) ->toThrow(DomainException::class); });