Adição da função de configuração de email e whatts

This commit is contained in:
2026-08-11 13:31:22 -03:00
parent e8f470f878
commit e530815377
27 changed files with 1461 additions and 92 deletions

View File

@@ -0,0 +1,189 @@
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" <email> 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" <nao-responda@reem.com.br>')
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