mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-30 18:47:51 +00:00 
			
		
		
		
	feat: Add campaigns in web widget (#2227)
* add campaign store(getter, actions and mutations) * add campaign store module * add get campaigns api * add fetch campaign action widget load * add specs * code cleanup * trigger campaig api fixes * integrate campaign trigger action * code cleanup * revert changes * trigger api fixes * review fixes * code beautification * chore: Fix multiple campaigns being send because of race condition * chore: rubocop * chore: Fix specs * disable campaigns Co-authored-by: Nithin David Thomas <webofnithin@gmail.com> Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
		| @@ -5,10 +5,12 @@ class Campaigns::CampaignConversationBuilder | |||||||
|     @contact_inbox = ContactInbox.find(@contact_inbox_id) |     @contact_inbox = ContactInbox.find(@contact_inbox_id) | ||||||
|     @campaign = @contact_inbox.inbox.campaigns.find_by!(display_id: campaign_display_id) |     @campaign = @contact_inbox.inbox.campaigns.find_by!(display_id: campaign_display_id) | ||||||
|  |  | ||||||
|     # We won't send campaigns if a conversation is already present |  | ||||||
|     return if @contact_inbox.conversations.present? |  | ||||||
|  |  | ||||||
|     ActiveRecord::Base.transaction do |     ActiveRecord::Base.transaction do | ||||||
|  |       @contact_inbox.lock! | ||||||
|  |  | ||||||
|  |       # We won't send campaigns if a conversation is already present | ||||||
|  |       return if @contact_inbox.reload.conversations.present? | ||||||
|  |  | ||||||
|       @conversation = ::Conversation.create!(conversation_params) |       @conversation = ::Conversation.create!(conversation_params) | ||||||
|       Messages::MessageBuilder.new(@campaign.sender, @conversation, message_params).perform |       Messages::MessageBuilder.new(@campaign.sender, @conversation, message_params).perform | ||||||
|     end |     end | ||||||
|   | |||||||
| @@ -73,6 +73,7 @@ export default { | |||||||
|   methods: { |   methods: { | ||||||
|     ...mapActions('appConfig', ['setWidgetColor']), |     ...mapActions('appConfig', ['setWidgetColor']), | ||||||
|     ...mapActions('conversation', ['fetchOldConversations', 'setUserLastSeen']), |     ...mapActions('conversation', ['fetchOldConversations', 'setUserLastSeen']), | ||||||
|  |     ...mapActions('campaign', ['fetchCampaigns']), | ||||||
|     ...mapActions('agent', ['fetchAvailableAgents']), |     ...mapActions('agent', ['fetchAvailableAgents']), | ||||||
|     scrollConversationToBottom() { |     scrollConversationToBottom() { | ||||||
|       const container = this.$el.querySelector('.conversation-wrap'); |       const container = this.$el.querySelector('.conversation-wrap'); | ||||||
| @@ -149,6 +150,7 @@ export default { | |||||||
|           this.fetchOldConversations().then(() => this.setUnreadView()); |           this.fetchOldConversations().then(() => this.setUnreadView()); | ||||||
|           this.setPopoutDisplay(message.showPopoutButton); |           this.setPopoutDisplay(message.showPopoutButton); | ||||||
|           this.fetchAvailableAgents(websiteToken); |           this.fetchAvailableAgents(websiteToken); | ||||||
|  |           this.fetchCampaigns(websiteToken); | ||||||
|           this.setHideMessageBubble(message.hideMessageBubble); |           this.setHideMessageBubble(message.hideMessageBubble); | ||||||
|           this.$store.dispatch('contacts/get'); |           this.$store.dispatch('contacts/get'); | ||||||
|         } else if (message.event === 'widget-visible') { |         } else if (message.event === 'widget-visible') { | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								app/javascript/widget/api/campaign.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/javascript/widget/api/campaign.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import endPoints from 'widget/api/endPoints'; | ||||||
|  | import { API } from 'widget/helpers/axios'; | ||||||
|  |  | ||||||
|  | const getCampaigns = async websiteToken => { | ||||||
|  |   const urlData = endPoints.getCampaigns(websiteToken); | ||||||
|  |   const result = await API.get(urlData.url, { params: urlData.params }); | ||||||
|  |   return result; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const triggerCampaign = async ({ campaignId }) => { | ||||||
|  |   const { websiteToken } = window.chatwootWebChannel; | ||||||
|  |   const urlData = endPoints.triggerCampaign(websiteToken, campaignId); | ||||||
|  |  | ||||||
|  |   await API.post( | ||||||
|  |     urlData.url, | ||||||
|  |     { ...urlData.data }, | ||||||
|  |     { | ||||||
|  |       params: urlData.params, | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export { getCampaigns, triggerCampaign }; | ||||||
| @@ -64,6 +64,24 @@ const getAvailableAgents = token => ({ | |||||||
|     website_token: token, |     website_token: token, | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|  | const getCampaigns = token => ({ | ||||||
|  |   url: '/api/v1/widget/campaigns', | ||||||
|  |   params: { | ||||||
|  |     website_token: token, | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | const triggerCampaign = (token, campaignId) => ({ | ||||||
|  |   url: '/api/v1/widget/events', | ||||||
|  |   data: { | ||||||
|  |     name: 'campaign.triggered', | ||||||
|  |     event_info: { | ||||||
|  |       campaign_id: campaignId, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   params: { | ||||||
|  |     website_token: token, | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   createConversation, |   createConversation, | ||||||
| @@ -72,4 +90,6 @@ export default { | |||||||
|   getConversation, |   getConversation, | ||||||
|   updateMessage, |   updateMessage, | ||||||
|   getAvailableAgents, |   getAvailableAgents, | ||||||
|  |   getCampaigns, | ||||||
|  |   triggerCampaign, | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								app/javascript/widget/helpers/campaignTimer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/javascript/widget/helpers/campaignTimer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | import { triggerCampaign } from 'widget/api/campaign'; | ||||||
|  | const startTimer = async ({ allCampaigns }) => { | ||||||
|  |   allCampaigns.forEach(campaign => { | ||||||
|  |     const { | ||||||
|  |       trigger_rules: { time_on_page: timeOnPage }, | ||||||
|  |       id: campaignId, | ||||||
|  |     } = campaign; | ||||||
|  |     setTimeout(async () => { | ||||||
|  |       await triggerCampaign({ campaignId }); | ||||||
|  |     }, timeOnPage * 1000); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export { startTimer }; | ||||||
| @@ -9,9 +9,9 @@ import conversationLabels from 'widget/store/modules/conversationLabels'; | |||||||
| import events from 'widget/store/modules/events'; | import events from 'widget/store/modules/events'; | ||||||
| import globalConfig from 'shared/store/globalConfig'; | import globalConfig from 'shared/store/globalConfig'; | ||||||
| import message from 'widget/store/modules/message'; | import message from 'widget/store/modules/message'; | ||||||
|  | import campaign from 'widget/store/modules/campaign'; | ||||||
|  |  | ||||||
| Vue.use(Vuex); | Vue.use(Vuex); | ||||||
|  |  | ||||||
| export default new Vuex.Store({ | export default new Vuex.Store({ | ||||||
|   modules: { |   modules: { | ||||||
|     agent, |     agent, | ||||||
| @@ -23,5 +23,6 @@ export default new Vuex.Store({ | |||||||
|     events, |     events, | ||||||
|     globalConfig, |     globalConfig, | ||||||
|     message, |     message, | ||||||
|  |     campaign, | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								app/javascript/widget/store/modules/campaign.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/javascript/widget/store/modules/campaign.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | import Vue from 'vue'; | ||||||
|  | import { getCampaigns } from 'widget/api/campaign'; | ||||||
|  | import { startTimer } from 'widget/helpers/campaignTimer'; | ||||||
|  |  | ||||||
|  | const state = { | ||||||
|  |   records: [], | ||||||
|  |   uiFlags: { | ||||||
|  |     isError: false, | ||||||
|  |     hasFetched: false, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const getters = { | ||||||
|  |   getHasFetched: $state => $state.uiFlags.hasFetched, | ||||||
|  |   fetchCampaigns: $state => $state.records, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const actions = { | ||||||
|  |   fetchCampaigns: async ({ commit }, websiteToken) => { | ||||||
|  |     try { | ||||||
|  |       const { data } = await getCampaigns(websiteToken); | ||||||
|  |       startTimer({ allCampaigns: data }); | ||||||
|  |       commit('setCampaigns', data); | ||||||
|  |       commit('setError', false); | ||||||
|  |       commit('setHasFetched', true); | ||||||
|  |     } catch (error) { | ||||||
|  |       commit('setError', true); | ||||||
|  |       commit('setHasFetched', true); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const mutations = { | ||||||
|  |   setCampaigns($state, data) { | ||||||
|  |     Vue.set($state, 'records', data); | ||||||
|  |   }, | ||||||
|  |   setError($state, value) { | ||||||
|  |     Vue.set($state.uiFlags, 'isError', value); | ||||||
|  |   }, | ||||||
|  |   setHasFetched($state, value) { | ||||||
|  |     Vue.set($state.uiFlags, 'hasFetched', value); | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   namespaced: true, | ||||||
|  |   state, | ||||||
|  |   getters, | ||||||
|  |   actions, | ||||||
|  |   mutations, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | import { API } from 'widget/helpers/axios'; | ||||||
|  | import { actions } from '../../campaign'; | ||||||
|  | import { campaigns } from './data'; | ||||||
|  |  | ||||||
|  | const commit = jest.fn(); | ||||||
|  | jest.mock('widget/helpers/axios'); | ||||||
|  |  | ||||||
|  | describe('#actions', () => { | ||||||
|  |   describe('#fetchCampaigns', () => { | ||||||
|  |     it('sends correct actions if API is success', async () => { | ||||||
|  |       API.get.mockResolvedValue({ data: campaigns }); | ||||||
|  |       await actions.fetchCampaigns({ commit }, 'XDsafmADasd'); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         ['setCampaigns', campaigns], | ||||||
|  |         ['setError', false], | ||||||
|  |         ['setHasFetched', true], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |     it('sends correct actions if API is error', async () => { | ||||||
|  |       API.get.mockRejectedValue({ message: 'Authentication required' }); | ||||||
|  |       await actions.fetchCampaigns({ commit }, 'XDsafmADasd'); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         ['setError', true], | ||||||
|  |         ['setHasFetched', true], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										86
									
								
								app/javascript/widget/store/modules/specs/campaign/data.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								app/javascript/widget/store/modules/specs/campaign/data.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | |||||||
|  | export const campaigns = [ | ||||||
|  |   { | ||||||
|  |     id: 1, | ||||||
|  |     title: 'Welcome', | ||||||
|  |     description: null, | ||||||
|  |     account_id: 1, | ||||||
|  |     inbox: { | ||||||
|  |       id: 37, | ||||||
|  |       channel_id: 1, | ||||||
|  |       name: 'Chatwoot', | ||||||
|  |       channel_type: 'Channel::WebWidget', | ||||||
|  |     }, | ||||||
|  |     sender: { | ||||||
|  |       account_id: 1, | ||||||
|  |       availability_status: 'offline', | ||||||
|  |       confirmed: true, | ||||||
|  |       email: 'sojan@chatwoot.com', | ||||||
|  |       available_name: 'Sojan', | ||||||
|  |       id: 10, | ||||||
|  |       name: 'Sojan', | ||||||
|  |     }, | ||||||
|  |     message: 'Hey, What brings you today', | ||||||
|  |     enabled: true, | ||||||
|  |     trigger_rules: { | ||||||
|  |       url: 'https://github.com', | ||||||
|  |       time_on_page: 10, | ||||||
|  |     }, | ||||||
|  |     created_at: '2021-05-03T04:53:36.354Z', | ||||||
|  |     updated_at: '2021-05-03T04:53:36.354Z', | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: 11, | ||||||
|  |     title: 'Onboarding Campaign', | ||||||
|  |     description: null, | ||||||
|  |     account_id: 1, | ||||||
|  |     inbox: { | ||||||
|  |       id: 37, | ||||||
|  |       channel_id: 1, | ||||||
|  |       name: 'GitX', | ||||||
|  |       channel_type: 'Channel::WebWidget', | ||||||
|  |     }, | ||||||
|  |     sender: { | ||||||
|  |       account_id: 1, | ||||||
|  |       availability_status: 'offline', | ||||||
|  |       confirmed: true, | ||||||
|  |       email: 'sojan@chatwoot.com', | ||||||
|  |       available_name: 'Sojan', | ||||||
|  |       id: 10, | ||||||
|  |     }, | ||||||
|  |     message: 'Begin your onboarding campaign with a welcome message', | ||||||
|  |     enabled: true, | ||||||
|  |     trigger_rules: { | ||||||
|  |       url: 'https://chatwoot.com', | ||||||
|  |       time_on_page: '20', | ||||||
|  |     }, | ||||||
|  |     created_at: '2021-05-03T08:15:35.828Z', | ||||||
|  |     updated_at: '2021-05-03T08:15:35.828Z', | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: 12, | ||||||
|  |     title: 'Thanks', | ||||||
|  |     description: null, | ||||||
|  |     account_id: 1, | ||||||
|  |     inbox: { | ||||||
|  |       id: 37, | ||||||
|  |       channel_id: 1, | ||||||
|  |       name: 'Chatwoot', | ||||||
|  |       channel_type: 'Channel::WebWidget', | ||||||
|  |     }, | ||||||
|  |     sender: { | ||||||
|  |       account_id: 1, | ||||||
|  |       availability_status: 'offline', | ||||||
|  |       confirmed: true, | ||||||
|  |       email: 'nithin@chatwoot.com', | ||||||
|  |       available_name: 'Nithin', | ||||||
|  |     }, | ||||||
|  |     message: 'Thanks for coming to the show. How may I help you?', | ||||||
|  |     enabled: false, | ||||||
|  |     trigger_rules: { | ||||||
|  |       url: 'https://noshow.com', | ||||||
|  |       time_on_page: 10, | ||||||
|  |     }, | ||||||
|  |     created_at: '2021-05-03T10:22:51.025Z', | ||||||
|  |     updated_at: '2021-05-03T10:22:51.025Z', | ||||||
|  |   }, | ||||||
|  | ]; | ||||||
| @@ -0,0 +1,96 @@ | |||||||
|  | import { getters } from '../../campaign'; | ||||||
|  | import { campaigns } from './data'; | ||||||
|  |  | ||||||
|  | describe('#getters', () => { | ||||||
|  |   it('fetchCampaigns', () => { | ||||||
|  |     const state = { | ||||||
|  |       records: campaigns, | ||||||
|  |     }; | ||||||
|  |     expect(getters.fetchCampaigns(state)).toEqual([ | ||||||
|  |       { | ||||||
|  |         id: 1, | ||||||
|  |         title: 'Welcome', | ||||||
|  |         description: null, | ||||||
|  |         account_id: 1, | ||||||
|  |         inbox: { | ||||||
|  |           id: 37, | ||||||
|  |           channel_id: 1, | ||||||
|  |           name: 'Chatwoot', | ||||||
|  |           channel_type: 'Channel::WebWidget', | ||||||
|  |         }, | ||||||
|  |         sender: { | ||||||
|  |           account_id: 1, | ||||||
|  |           availability_status: 'offline', | ||||||
|  |           confirmed: true, | ||||||
|  |           email: 'sojan@chatwoot.com', | ||||||
|  |           available_name: 'Sojan', | ||||||
|  |           id: 10, | ||||||
|  |           name: 'Sojan', | ||||||
|  |         }, | ||||||
|  |         message: 'Hey, What brings you today', | ||||||
|  |         enabled: true, | ||||||
|  |         trigger_rules: { | ||||||
|  |           url: 'https://github.com', | ||||||
|  |           time_on_page: 10, | ||||||
|  |         }, | ||||||
|  |         created_at: '2021-05-03T04:53:36.354Z', | ||||||
|  |         updated_at: '2021-05-03T04:53:36.354Z', | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         id: 11, | ||||||
|  |         title: 'Onboarding Campaign', | ||||||
|  |         description: null, | ||||||
|  |         account_id: 1, | ||||||
|  |         inbox: { | ||||||
|  |           id: 37, | ||||||
|  |           channel_id: 1, | ||||||
|  |           name: 'GitX', | ||||||
|  |           channel_type: 'Channel::WebWidget', | ||||||
|  |         }, | ||||||
|  |         sender: { | ||||||
|  |           account_id: 1, | ||||||
|  |           availability_status: 'offline', | ||||||
|  |           confirmed: true, | ||||||
|  |           email: 'sojan@chatwoot.com', | ||||||
|  |           available_name: 'Sojan', | ||||||
|  |           id: 10, | ||||||
|  |         }, | ||||||
|  |         message: 'Begin your onboarding campaign with a welcome message', | ||||||
|  |         enabled: true, | ||||||
|  |         trigger_rules: { | ||||||
|  |           url: 'https://chatwoot.com', | ||||||
|  |           time_on_page: '20', | ||||||
|  |         }, | ||||||
|  |         created_at: '2021-05-03T08:15:35.828Z', | ||||||
|  |         updated_at: '2021-05-03T08:15:35.828Z', | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         id: 12, | ||||||
|  |         title: 'Thanks', | ||||||
|  |         description: null, | ||||||
|  |         account_id: 1, | ||||||
|  |         inbox: { | ||||||
|  |           id: 37, | ||||||
|  |           channel_id: 1, | ||||||
|  |           name: 'Chatwoot', | ||||||
|  |           channel_type: 'Channel::WebWidget', | ||||||
|  |         }, | ||||||
|  |         sender: { | ||||||
|  |           account_id: 1, | ||||||
|  |           availability_status: 'offline', | ||||||
|  |           confirmed: true, | ||||||
|  |           email: 'nithin@chatwoot.com', | ||||||
|  |           available_name: 'Nithin', | ||||||
|  |         }, | ||||||
|  |         message: 'Thanks for coming to the show. How may I help you?', | ||||||
|  |         enabled: false, | ||||||
|  |         trigger_rules: { | ||||||
|  |           url: 'https://noshow.com', | ||||||
|  |           time_on_page: 10, | ||||||
|  |         }, | ||||||
|  |         created_at: '2021-05-03T10:22:51.025Z', | ||||||
|  |         updated_at: '2021-05-03T10:22:51.025Z', | ||||||
|  |       }, | ||||||
|  |     ]); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | import { mutations } from '../../campaign'; | ||||||
|  | import { campaigns } from './data'; | ||||||
|  |  | ||||||
|  | describe('#mutations', () => { | ||||||
|  |   describe('#setCampagins', () => { | ||||||
|  |     it('set campaign records', () => { | ||||||
|  |       const state = { records: [] }; | ||||||
|  |       mutations.setCampaigns(state, campaigns); | ||||||
|  |       expect(state.records).toEqual(campaigns); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('#setError', () => { | ||||||
|  |     it('set error flag', () => { | ||||||
|  |       const state = { records: [], uiFlags: {} }; | ||||||
|  |       mutations.setError(state, true); | ||||||
|  |       expect(state.uiFlags.isError).toEqual(true); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('#setHasFetched', () => { | ||||||
|  |     it('set fetched flag', () => { | ||||||
|  |       const state = { records: [], uiFlags: {} }; | ||||||
|  |       mutations.setHasFetched(state, true); | ||||||
|  |       expect(state.uiFlags.hasFetched).toEqual(true); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -6,7 +6,7 @@ class CampaignListener < BaseListener | |||||||
|     return if campaign_display_id.blank? |     return if campaign_display_id.blank? | ||||||
|  |  | ||||||
|     ::Campaigns::CampaignConversationBuilder.new( |     ::Campaigns::CampaignConversationBuilder.new( | ||||||
|       contact_inbox: contact_inbox.id, |       contact_inbox_id: contact_inbox.id, | ||||||
|       campaign_display_id: campaign_display_id, |       campaign_display_id: campaign_display_id, | ||||||
|       conversation_additional_attributes: event.data[:event_info].except(:campaign_id) |       conversation_additional_attributes: event.data[:event_info].except(:campaign_id) | ||||||
|     ).perform |     ).perform | ||||||
|   | |||||||
| @@ -3,9 +3,11 @@ class MessageTemplates::HookExecutionService | |||||||
|  |  | ||||||
|   def perform |   def perform | ||||||
|     return if inbox.agent_bot_inbox&.active? |     return if inbox.agent_bot_inbox&.active? | ||||||
|  |     return if conversation.campaign.present? | ||||||
|  |  | ||||||
|     # TODO: let's see whether this is needed and remove this and related logic if not |     # TODO: let's see whether this is needed and remove this and related logic if not | ||||||
|     # ::MessageTemplates::Template::OutOfOffice.new(conversation: conversation).perform if should_send_out_of_office_message? |     # ::MessageTemplates::Template::OutOfOffice.new(conversation: conversation).perform if should_send_out_of_office_message? | ||||||
|  |  | ||||||
|     ::MessageTemplates::Template::Greeting.new(conversation: conversation).perform if should_send_greeting? |     ::MessageTemplates::Template::Greeting.new(conversation: conversation).perform if should_send_greeting? | ||||||
|     ::MessageTemplates::Template::EmailCollect.new(conversation: conversation).perform if should_send_email_collect? |     ::MessageTemplates::Template::EmailCollect.new(conversation: conversation).perform if should_send_email_collect? | ||||||
|   end |   end | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ describe CampaignListener do | |||||||
|     context 'when params contain campaign id' do |     context 'when params contain campaign id' do | ||||||
|       it 'triggers campaign conversation builder' do |       it 'triggers campaign conversation builder' do | ||||||
|         expect(Campaigns::CampaignConversationBuilder).to receive(:new) |         expect(Campaigns::CampaignConversationBuilder).to receive(:new) | ||||||
|           .with({ contact_inbox: contact_inbox.id, campaign_display_id: campaign.display_id, conversation_additional_attributes: {} }).once |           .with({ contact_inbox_id: contact_inbox.id, campaign_display_id: campaign.display_id, conversation_additional_attributes: {} }).once | ||||||
|         listener.campaign_triggered(event) |         listener.campaign_triggered(event) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   | |||||||
| @@ -39,6 +39,18 @@ describe ::MessageTemplates::HookExecutionService do | |||||||
|       expect(::MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation) |       expect(::MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     it 'doesnot calls ::MessageTemplates::Template::EmailCollect on campaign conversations' do | ||||||
|  |       contact = create(:contact, email: nil) | ||||||
|  |       conversation = create(:conversation, contact: contact, campaign: create(:campaign)) | ||||||
|  |  | ||||||
|  |       allow(::MessageTemplates::Template::EmailCollect).to receive(:new).and_return(true) | ||||||
|  |  | ||||||
|  |       # described class gets called in message after commit | ||||||
|  |       message = create(:message, conversation: conversation) | ||||||
|  |  | ||||||
|  |       expect(::MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation) | ||||||
|  |     end | ||||||
|  |  | ||||||
|     it 'doesnot calls ::MessageTemplates::Template::Greeting if greeting_message is empty' do |     it 'doesnot calls ::MessageTemplates::Template::Greeting if greeting_message is empty' do | ||||||
|       contact = create(:contact, email: nil) |       contact = create(:contact, email: nil) | ||||||
|       conversation = create(:conversation, contact: contact) |       conversation = create(:conversation, contact: contact) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Muhsin Keloth
					Muhsin Keloth