require 'rails_helper' RSpec.describe ConfiguracaoNotificacao do # Preenchimento mínimo para os toggles passarem nas validações condicionais. def config_smtp(extras = {}) described_class.new({ smtp_ativo: true, smtp_address: 'smtp.gmail.com', smtp_port: 587, smtp_username: 'sistema@reem.com.br', smtp_password: 'segredo123' }.merge(extras)) end def config_whats(extras = {}) described_class.new({ whatsapp_ativo: true, twilio_account_sid: 'AC123', twilio_auth_token: 'tok123', twilio_from: '+14155238886' }.merge(extras)) end describe '.instancia' do it 'devolve sempre a mesma linha' do primeira = described_class.instancia expect(described_class.instancia.id).to eq(primeira.id) expect(described_class.count).to eq(1) end end describe '.normalizar_telefone' do { '11 920051157' => '+5511920051157', '(11) 92005-1157' => '+5511920051157', '011 92005-1157' => '+5511920051157', '+55 11 92005-1157' => '+5511920051157', 'whatsapp:+5511920051157' => '+5511920051157', '1132224444' => '+551132224444', # DDD 55 (Santa Maria/RS): o "55" inicial é o DDD, não o país. '55991234567' => '+5555991234567' }.each do |entrada, esperado| it "converte #{entrada.inspect} em #{esperado}" do expect(described_class.normalizar_telefone(entrada)).to eq(esperado) end end it 'devolve nil para vazio ou número curto demais' do expect(described_class.normalizar_telefone(nil)).to be_nil expect(described_class.normalizar_telefone('')).to be_nil expect(described_class.normalizar_telefone('920051157')).to be_nil end end describe '.canal' do it 'prefixa whatsapp:' do expect(described_class.canal('11 920051157')).to eq('whatsapp:+5511920051157') end it 'devolve nil quando o número é inválido' do expect(described_class.canal('abc')).to be_nil end end describe 'atributos cifrados' do # A tabela é singleton (índice único em singleton_guard) e a migration já # cria a linha — por isso os testes que persistem usam `.instancia`. it 'grava criptografado e lê de volta em claro' do cfg = described_class.instancia cfg.update!(smtp_password: 'minha-senha', twilio_auth_token: 'meu-token') cfg.reload expect(cfg.smtp_password).to eq('minha-senha') expect(cfg.twilio_auth_token).to eq('meu-token') expect(cfg.smtp_password_cifrado).to be_present expect(cfg.smtp_password_cifrado).not_to include('minha-senha') end it 'não marca o registro como alterado ao reatribuir o mesmo valor' do cfg = described_class.instancia cfg.update!(smtp_password: 'igual') cfg.smtp_password = 'igual' expect(cfg).not_to be_changed end it 'trata segredo ilegível como ausente, sem estourar' do cfg = described_class.instancia cfg.update!(smtp_password: 'x') cfg.update_column(:smtp_password_cifrado, 'lixo-que-nao-decifra') expect(cfg.reload.smtp_password).to be_nil expect(cfg.smtp_password?).to be(false) end end describe 'validações' do it 'não exige SMTP enquanto o envio de e-mail está desligado' do expect(described_class.new).to be_valid end it 'exige servidor, usuário e senha quando o e-mail é ativado' do cfg = described_class.new(smtp_ativo: true) expect(cfg).not_to be_valid expect(cfg.errors.attribute_names).to include(:smtp_address, :smtp_username, :smtp_password) end it 'exige credenciais do Twilio quando o WhatsApp é ativado' do cfg = described_class.new(whatsapp_ativo: true) expect(cfg).not_to be_valid expect(cfg.errors.attribute_names).to include(:twilio_account_sid, :twilio_auth_token, :twilio_from) end it 'rejeita e-mail administrativo malformado' do expect(described_class.new(email_admin: 'sem-arroba')).not_to be_valid end it 'rejeita porta fora da faixa' do expect(described_class.new(smtp_port: 0)).not_to be_valid expect(described_class.new(smtp_port: 70_000)).not_to be_valid end it 'normaliza os telefones antes de salvar' do cfg = described_class.instancia cfg.update!(whatsapp_admin: '(11) 92005-1157') expect(cfg.reload.whatsapp_admin).to eq('+5511920051157') end end describe '#smtp_settings' do it 'devolve nil quando não está pronto, para o .env continuar valendo' do expect(described_class.new.smtp_settings).to be_nil expect(config_smtp(smtp_ativo: false).smtp_settings).to be_nil end it 'usa STARTTLS na 587' do settings = config_smtp.smtp_settings expect(settings[:enable_starttls_auto]).to be(true) expect(settings).not_to have_key(:ssl) expect(settings[:password]).to eq('segredo123') expect(settings[:authentication]).to eq(:plain) end it 'usa SSL direto na 465' do settings = config_smtp(smtp_port: 465).smtp_settings expect(settings[:ssl]).to be(true) expect(settings).not_to have_key(:enable_starttls_auto) end it 'deriva o domínio do remetente quando não informado' do expect(config_smtp.smtp_settings[:domain]).to eq('reem.com.br') end end describe '#remetente_formatado' do it 'monta "Nome" quando há nome' do cfg = config_smtp(remetente_email: 'nao-responda@reem.com.br', remetente_nome: 'Reem Transporte') expect(cfg.remetente_formatado).to eq('"Reem Transporte" ') end it 'cai no usuário do SMTP quando não há remetente próprio' do expect(config_smtp.remetente_formatado).to eq('sistema@reem.com.br') end end describe '#credenciais_whatsapp' do it 'usa o banco quando está completo' do creds = config_whats.credenciais_whatsapp expect(creds[:sid]).to eq('AC123') expect(creds[:from]).to eq('whatsapp:+14155238886') end it 'cai no .env quando o banco está incompleto' do allow(ENV).to receive(:[]).and_call_original allow(ENV).to receive(:[]).with('TWILIO_ACCOUNT_SID').and_return('AC_env') allow(ENV).to receive(:[]).with('TWILIO_AUTH_TOKEN').and_return('tok_env') allow(ENV).to receive(:[]).with('TWILIO_WHATSAPP_FROM').and_return('+14155238886') expect(described_class.new.credenciais_whatsapp[:sid]).to eq('AC_env') end it 'não mistura SID do banco com token do .env' do allow(ENV).to receive(:[]).and_call_original allow(ENV).to receive(:[]).with('TWILIO_ACCOUNT_SID').and_return('AC_env') allow(ENV).to receive(:[]).with('TWILIO_AUTH_TOKEN').and_return('tok_env') allow(ENV).to receive(:[]).with('TWILIO_WHATSAPP_FROM').and_return('+14155238886') # SID no banco mas sem token → whatsapp_pronto? é false → vai inteiro pro ENV cfg = described_class.new(whatsapp_ativo: true, twilio_account_sid: 'AC_banco') expect(cfg.credenciais_whatsapp[:sid]).to eq('AC_env') expect(cfg.credenciais_whatsapp[:token]).to eq('tok_env') end end end