require 'rails_helper' RSpec.describe Notificacao::Despachante do let(:evento) { create(:evento_notificacao) } let(:diretoria) { create(:grupo_contato) } let(:config) { ConfiguracaoNotificacao.instancia } before do config.update_columns(whatsapp_ativo: true, whatsapp_provedor: 'baileys', email_notificacoes_ativo: true, whatsapp_intervalo_segundos: 0) # Nunca tocar a ponte de verdade no teste. allow(Notificacao::Whatsapp).to receive(:enviar) .and_return(Notificacao::ClienteWhatsapp::Resposta.new(ok: true)) allow(ConfiguracaoNotificacao).to receive(:instancia).and_return(config) end def despachar(envolvido: nil, dados: {}) described_class.new(evento.reload, dados: dados, assunto: 'Assunto', corpo: 'Corpo', envolvido: envolvido).executar end it 'envia para os contatos dos grupos assinantes e registra cada envio' do contato = create(:contato, grupo_contato: diretoria, telefone: '11 92005-1157', email: 'dir@reem.com') create(:grupo_evento_assinatura, grupo_contato: diretoria, evento_notificacao: evento) expect { despachar }.to change(NotificacaoEnvio, :count).by(2) # whatsapp + email expect(Notificacao::Whatsapp).to have_received(:enviar) .with(hash_including(para: contato.telefone)) expect(NotificacaoEnvio.where(canal: 'whatsapp').first).to be_enviado end # A mesma pessoa pode ser contato de um grupo E a envolvida no fato — sem # dedup ela receberia a mensagem duas vezes. it 'não manda duas vezes para o mesmo número' do create(:contato, grupo_contato: diretoria, telefone: '11 92005-1157', email: nil) create(:grupo_evento_assinatura, grupo_contato: diretoria, evento_notificacao: evento, canal: 'whatsapp') motorista = create(:motorista, telefone: '(11) 92005-1157') despachar(envolvido: motorista) expect(NotificacaoEnvio.where(canal: 'whatsapp').count).to eq(1) end it 'inclui o envolvido que não é contato de nenhum grupo' do create(:grupo_evento_assinatura, grupo_contato: diretoria, evento_notificacao: evento) motorista = create(:motorista, telefone: '(11) 98888-7777') despachar(envolvido: motorista) expect(NotificacaoEnvio.where(canal: 'whatsapp').pluck(:destino)).to eq(['+5511988887777']) end it 'não avisa o envolvido quando o evento diz para não avisar' do evento.update!(notificar_envolvido: false) motorista = create(:motorista, telefone: '(11) 98888-7777') despachar(envolvido: motorista) expect(NotificacaoEnvio.where(canal: 'whatsapp')).to be_empty end it 'registra a falha em vez de levantar — envio não pode travar um fechamento' do create(:contato, grupo_contato: diretoria, telefone: '11 92005-1157', email: nil) create(:grupo_evento_assinatura, grupo_contato: diretoria, evento_notificacao: evento, canal: 'whatsapp') allow(Notificacao::Whatsapp).to receive(:enviar) .and_return(Notificacao::ClienteWhatsapp::Resposta.new(ok: false, erro: 'whatsapp desconectado')) expect { despachar }.not_to raise_error envio = NotificacaoEnvio.last expect(envio).to be_falhou expect(envio.erro).to include('desconectado') end # O editor de blocos vence o texto padrão — e o fallback existe para que ligar # o editor não apague as notificações dos eventos que já funcionavam. describe 'template de blocos' do before do create(:contato, grupo_contato: diretoria, telefone: '11 92005-1157', email: 'dir@reem.com') create(:grupo_evento_assinatura, grupo_contato: diretoria, evento_notificacao: evento) end it 'sem template, usa o corpo passado pelo chamador' do despachar expect(NotificacaoEnvio.find_by(canal: 'whatsapp').corpo).to eq('Corpo') end it 'com template, o corpo sai renderizado por canal' do MensagemTemplate.create!(evento_notificacao: evento, canal: 'whatsapp', ativo: true, blocos: [{ 'tipo' => 'texto', 'texto' => 'Oi {{contato}}, {{valor}}' }]) MensagemTemplate.create!(evento_notificacao: evento, canal: 'email', ativo: true, assunto: 'Fechamento de {{contato}}', blocos: [{ 'tipo' => 'texto', 'texto' => 'Corpo do e-mail' }]) despachar(dados: { 'valor' => 'R$ 10,00' }) zap = NotificacaoEnvio.find_by(canal: 'whatsapp') expect(zap.corpo).to include('R$ 10,00') email = NotificacaoEnvio.find_by(canal: 'email') expect(email.corpo).to include('
'texto', 'texto' => 'Olá {{contato}}' }]) despachar corpos = NotificacaoEnvio.where(canal: 'whatsapp').pluck(:corpo) expect(corpos).to include(a_string_including('Ana')) expect(corpos.uniq.size).to eq(corpos.size) end it 'template ativo mas vazio não substitui o texto padrão' do MensagemTemplate.create!(evento_notificacao: evento, canal: 'whatsapp', ativo: true, blocos: []) despachar expect(NotificacaoEnvio.find_by(canal: 'whatsapp').corpo).to eq('Corpo') end end it 'não envia nada quando o canal está desligado na configuração' do create(:contato, grupo_contato: diretoria, telefone: '11 92005-1157', email: 'dir@reem.com') create(:grupo_evento_assinatura, grupo_contato: diretoria, evento_notificacao: evento) config.update_columns(whatsapp_ativo: false, email_notificacoes_ativo: false) expect { despachar }.not_to change(NotificacaoEnvio, :count) end end # Buscar o evento pela `chave` fazia só o de SISTEMA disparar: um evento criado # pelo ADM com o mesmo gatilho ficava mudo para sempre, sem erro nenhum — a tela # oferecia o gatilho e nada acontecia. RSpec.describe Notificacao::Despachante, '.disparar_gatilho' do it 'agenda TODOS os eventos ativos do gatilho, não só o de sistema' do sistema = create(:evento_notificacao, gatilho: 'valor_alterado', chave: 'valor_alterado', sistema: true) do_adm = create(:evento_notificacao, gatilho: 'valor_alterado', chave: 'aviso_extra') create(:evento_notificacao, gatilho: 'pagamento_efetuado', chave: 'outro') agendados = [] allow(NotificacaoJob).to receive(:perform_later) { |id, *| agendados << id } described_class.disparar_gatilho(gatilho: 'valor_alterado', corpo: 'x') expect(agendados).to contain_exactly(sistema.id, do_adm.id) end it 'ignora evento desativado' do create(:evento_notificacao, gatilho: 'valor_alterado', chave: 'desligado', ativo: false) allow(NotificacaoJob).to receive(:perform_later) described_class.disparar_gatilho(gatilho: 'valor_alterado', corpo: 'x') expect(NotificacaoJob).not_to have_received(:perform_later) end # O botão "disparar agora" mira UM evento — ali a chave é o identificador certo. it '.disparar continua agendando só o evento da chave' do alvo = create(:evento_notificacao, gatilho: 'manual', chave: 'so_este') create(:evento_notificacao, gatilho: 'manual', chave: 'outro_manual') agendados = [] allow(NotificacaoJob).to receive(:perform_later) { |id, *| agendados << id } described_class.disparar(chave: 'so_este', corpo: 'x') expect(agendados).to eq([alvo.id]) end end