set('admin_access.secrets_key', 'base64:'.base64_encode(random_bytes(32))); clearMailboxSeed(); }); it('resolves a purpose to the mailbox it points at', function () { Mailbox::factory()->create(['key' => 'support', 'address' => 'support@clupilot.com']); Settings::set('mail.purpose.support', 'support'); expect(app(MailboxResolver::class)->for(MailPurpose::SUPPORT)?->address) ->toBe('support@clupilot.com'); }); it('falls back to system when a purpose has no mailbox', function () { Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com']); Settings::set('mail.purpose.system', 'no-reply'); // billing deliberately unset expect(app(MailboxResolver::class)->for(MailPurpose::BILLING)?->address) ->toBe('no-reply@clupilot.com'); }); it('falls back to system when the named mailbox no longer exists', function () { Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com']); Settings::set('mail.purpose.system', 'no-reply'); Settings::set('mail.purpose.billing', 'geloescht'); expect(app(MailboxResolver::class)->for(MailPurpose::BILLING)?->address) ->toBe('no-reply@clupilot.com'); }); it('falls back to system when the mailbox is deactivated, not deleted', function () { // Deactivating is an explicit operator action. Reaching this mailbox by // its row surviving would silently send from an address the operator // just told the console to stop using. Mailbox::factory()->create(['key' => 'support', 'address' => 'support@clupilot.com', 'active' => false]); Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com']); Settings::set('mail.purpose.support', 'support'); Settings::set('mail.purpose.system', 'no-reply'); expect(app(MailboxResolver::class)->for(MailPurpose::SUPPORT)?->address) ->toBe('no-reply@clupilot.com'); }); it('returns null rather than an inactive mailbox when the fallback is deactivated too', function () { // The fallback lookup is filtered the SAME way as the direct one — an // inactive system mailbox must not be handed out just because it is the // last candidate. Mailbox::factory()->create(['key' => 'support', 'address' => 'support@clupilot.com', 'active' => false]); Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com', 'active' => false]); Settings::set('mail.purpose.support', 'support'); Settings::set('mail.purpose.system', 'no-reply'); expect(app(MailboxResolver::class)->for(MailPurpose::SUPPORT))->toBeNull(); }); it('returns null rather than guessing when even system is unset', function () { expect(app(MailboxResolver::class)->for(MailPurpose::SYSTEM))->toBeNull(); }); it('rejects a purpose that is not in the curated list', function () { expect(fn () => app(MailboxResolver::class)->for('erfunden')) ->toThrow(InvalidArgumentException::class, 'erfunden'); });