Compare commits

...
Author SHA1 Message Date
Shivam Mishra 164b4df679 feat: implement handleReplyTo
* save to localstorage
* trigger a event on the bus
2023-10-05 14:38:55 +05:30
Shivam Mishra 2014a82ff8 test: localstorage utils 2023-10-05 14:35:11 +05:30
Shivam Mishra f60ab0eb1d feat: add json store utils 2023-10-05 14:28:21 +05:30
Shivam Mishra dc6757df3d refactor: use feature flag to toggle reply to 2023-10-05 11:30:32 +05:30
Shivam Mishra cfeddcbec2 feat: setup message_reply_to feature flag 2023-10-05 11:30:32 +05:30
Shivam MishraandGitHub 3aa79dffef fix: event name 2023-10-04 18:13:52 +05:30
Shivam MishraandGitHub 758b7bf061 Merge branch 'develop' into feature/cw-2594 2023-10-04 16:00:29 +05:30
Shivam Mishra 93d126af7b chore: add comment for INBOX_FEATURE_MAP 2023-10-04 15:55:54 +05:30
Shivam Mishra 3c6c57ca0e refactor: better variable name 2023-10-04 15:54:48 +05:30
Shivam Mishra b952608eeb feat: disable reply to for all 2023-10-04 15:52:17 +05:30
Shivam Mishra eb6f1e4031 feat: allow reply to for outgoing messages too 2023-10-04 15:51:48 +05:30
Shivam Mishra 94909255a8 test: cover all inboxMixin functions 2023-10-04 15:50:01 +05:30
Shivam Mishra 91788255f2 test: missing tests for line and telegram 2023-10-04 15:30:15 +05:30
Shivam Mishra 515b9ba0b5 refactor: use common config generator 2023-10-04 15:26:34 +05:30
Shivam Mishra e5c5ebc398 test: inboxHasFeature 2023-10-04 15:20:11 +05:30
Shivam Mishra 21212d9bc3 chore: add dummy handler 2023-10-04 12:13:57 +05:30
Shivam Mishra 0af9e974bd feat: add feature flag map for inbox specific features 2023-10-04 12:12:15 +05:30
Shivam Mishra b3141de50b feat: add context menu option for reply to 2023-10-04 12:01:09 +05:30
Shivam Mishra 1da6962467 feat: add copy for reply to 2023-10-04 12:00:43 +05:30
12 changed files with 432 additions and 153 deletions
@@ -124,6 +124,7 @@
:message="data"
@open="openContextMenu"
@close="closeContextMenu"
@replyTo="handleReplyTo"
/>
</div>
</li>
@@ -149,6 +150,8 @@ import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
import { generateBotMessageContent } from './helpers/botMessageContentHelper';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import { ACCOUNT_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
import { LocalStorage } from 'shared/helpers/localStorage';
export default {
components: {
@@ -188,6 +191,10 @@ export default {
type: Boolean,
default: false,
},
inboxSupportsReplyTo: {
type: Boolean,
default: false,
},
},
data() {
return {
@@ -269,6 +276,7 @@ export default {
copy: this.hasText,
delete: this.hasText || this.hasAttachments,
cannedResponse: this.isOutgoing && this.hasText,
replyTo: !this.data.private && this.inboxSupportsReplyTo,
};
},
contentAttributes() {
@@ -494,6 +502,13 @@ export default {
this.showContextMenu = false;
this.contextMenuPosition = { x: null, y: null };
},
handleReplyTo() {
const replyStorageKey = LOCAL_STORAGE_KEYS.MESSAGE_REPLY_TO;
const { conversation_id: conversationId, id: replyTo } = this.data;
LocalStorage.updateJsonStore(replyStorageKey, conversationId, replyTo);
bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.data);
},
setupHighlightTimer() {
if (Number(this.$route.query.messageId) !== Number(this.data.id)) {
return;
@@ -42,6 +42,7 @@
:is-a-whatsapp-channel="isAWhatsAppChannel"
:has-instagram-story="hasInstagramStory"
:is-web-widget-inbox="isAWebWidgetInbox"
:inbox-supports-reply-to="inboxSupportsReplyTo"
/>
<li v-show="unreadMessageCount != 0" class="unread--toast">
<span>
@@ -110,7 +111,7 @@ import { mapGetters } from 'vuex';
import conversationMixin, {
filterDuplicateSourceMessages,
} from '../../../mixins/conversations';
import inboxMixin from 'shared/mixins/inboxMixin';
import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin';
import configMixin from 'shared/mixins/configMixin';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import aiMixin from 'dashboard/mixins/aiMixin';
@@ -123,6 +124,7 @@ import { LocalStorage } from 'shared/helpers/localStorage';
// constants
import { BUS_EVENTS } from 'shared/constants/busEvents';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { REPLY_POLICY } from 'shared/constants/links';
import wootConstants from 'dashboard/constants/globals';
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
@@ -164,12 +166,14 @@ export default {
computed: {
...mapGetters({
accountId: 'getCurrentAccountId',
currentChat: 'getSelectedChat',
allConversations: 'getAllConversations',
inboxesList: 'inboxes/getInboxes',
listLoadingStatus: 'getAllMessagesLoaded',
loadingChatList: 'getChatListLoadingStatus',
appIntegrations: 'integrations/getAppIntegrations',
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
currentAccountId: 'getCurrentAccountId',
}),
isOpen() {
@@ -316,6 +320,15 @@ export default {
unreadMessageCount() {
return this.currentChat.unread_count || 0;
},
inboxSupportsReplyTo() {
return (
this.inboxHasFeature(INBOX_FEATURES.REPLY_TO) &&
this.isFeatureEnabledonAccount(
this.accountId,
FEATURE_FLAGS.MESSAGE_REPLY_TO
)
);
},
},
watch: {
@@ -4,4 +4,5 @@ export const LOCAL_STORAGE_KEYS = {
DRAFT_MESSAGES: 'draftMessages',
COLOR_SCHEME: 'color_scheme',
DISMISSED_LABEL_SUGGESTIONS: 'labelSuggestionsDismissed',
MESSAGE_REPLY_TO: 'messageReplyTo',
};
+1
View File
@@ -16,4 +16,5 @@ export const FEATURE_FLAGS = {
TEAM_MANAGEMENT: 'team_management',
VOICE_RECORDER: 'voice_recorder',
AUDIT_LOGS: 'audit_logs',
MESSAGE_REPLY_TO: 'message_reply_to',
};
@@ -194,6 +194,7 @@
},
"CONTEXT_MENU": {
"COPY": "Copy",
"REPLY_TO": "Reply to this message",
"DELETE": "Delete",
"CREATE_A_CANNED_RESPONSE": "Add to canned responses",
"TRANSLATE": "Translate",
@@ -44,6 +44,15 @@
@close="handleClose"
>
<div class="menu-container">
<menu-item
v-if="enabledOptions['replyTo']"
:option="{
icon: 'arrow-reply',
label: $t('CONVERSATION.CONTEXT_MENU.REPLY_TO'),
}"
variant="icon"
@click="handleReplyTo"
/>
<menu-item
v-if="enabledOptions['copy']"
:option="{
@@ -204,10 +213,13 @@ export default {
this.handleClose();
this.showTranslateModal = true;
},
handleReplyTo() {
this.$emit('replyTo', this.message);
this.handleClose();
},
onCloseTranslateModal() {
this.showTranslateModal = false;
},
openDeleteModal() {
this.handleClose();
this.showDeleteModal = true;
@@ -9,5 +9,6 @@ export const BUS_EVENTS = {
TOGGLE_SIDEMENU: 'TOGGLE_SIDEMENU',
ON_MESSAGE_LIST_SCROLL: 'ON_MESSAGE_LIST_SCROLL',
WEBSOCKET_DISCONNECT: 'WEBSOCKET_DISCONNECT',
TOGGLE_REPLY_TO_MESSAGE: 'TOGGLE_REPLY_TO_MESSAGE',
SHOW_TOAST: 'newToastMessage',
};
+36 -1
View File
@@ -19,7 +19,7 @@ export const LocalStorage = {
} else {
window.localStorage.setItem(key, value);
}
window.localStorage.setItem(key + ':ts', Date.now());
window.localStorage.setItem(key + ':ts', Date.now().toString());
},
setFlag(store, accountId, key, expiry = 24 * 60 * 60 * 1000) {
@@ -46,4 +46,39 @@ export const LocalStorage = {
window.localStorage.removeItem(key);
window.localStorage.removeItem(key + ':ts');
},
updateJsonStore(storeName, key, value) {
try {
const storedValue = this.get(storeName) || {};
storedValue[key] = value;
this.set(storeName, storedValue);
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error updating JSON store in localStorage', e);
}
},
getFromJsonStore(storeName, key) {
try {
const storedValue = this.get(storeName) || {};
return storedValue[key] || null;
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error getting value from JSON store in localStorage', e);
return null;
}
},
deleteFromJsonStore(storeName, key) {
try {
const storedValue = this.get(storeName);
if (storedValue && key in storedValue) {
delete storedValue[key];
this.set(storeName, storedValue);
}
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error deleting entry from JSON store in localStorage', e);
}
},
};
@@ -0,0 +1,107 @@
import { LocalStorage } from '../localStorage';
// Mocking localStorage
const localStorageMock = (() => {
let store = {};
return {
getItem: key => store[key] || null,
setItem: (key, value) => {
store[key] = String(value);
},
removeItem: key => delete store[key],
clear: () => {
store = {};
},
};
})();
Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
});
describe('LocalStorage utility', () => {
beforeEach(() => {
localStorage.clear();
});
it('set and get methods', () => {
LocalStorage.set('testKey', { a: 1 });
expect(LocalStorage.get('testKey')).toEqual({ a: 1 });
});
it('remove method', () => {
LocalStorage.set('testKey', 'testValue');
LocalStorage.remove('testKey');
expect(LocalStorage.get('testKey')).toBeNull();
});
it('updateJsonStore method', () => {
LocalStorage.updateJsonStore('testStore', 'testKey', 'testValue');
expect(LocalStorage.get('testStore')).toEqual({ testKey: 'testValue' });
});
it('getFromJsonStore method', () => {
LocalStorage.set('testStore', { testKey: 'testValue' });
expect(LocalStorage.getFromJsonStore('testStore', 'testKey')).toBe(
'testValue'
);
});
it('deleteFromJsonStore method', () => {
LocalStorage.set('testStore', { testKey: 'testValue' });
LocalStorage.deleteFromJsonStore('testStore', 'testKey');
expect(LocalStorage.getFromJsonStore('testStore', 'testKey')).toBeNull();
});
it('setFlag and getFlag methods', () => {
const store = 'testStore';
const accountId = '123';
const key = 'flagKey';
const expiry = 1000; // 1 second
// Set flag and verify it's set
LocalStorage.setFlag(store, accountId, key, expiry);
expect(LocalStorage.getFlag(store, accountId, key)).toBe(true);
// Wait for expiry and verify flag is not set
return new Promise(resolve => {
setTimeout(() => {
expect(LocalStorage.getFlag(store, accountId, key)).toBe(false);
resolve();
}, expiry + 100); // wait a bit more than expiry time to ensure the flag has expired
});
});
it('clearAll method', () => {
LocalStorage.set('testKey1', 'testValue1');
LocalStorage.set('testKey2', 'testValue2');
LocalStorage.clearAll();
expect(LocalStorage.get('testKey1')).toBeNull();
expect(LocalStorage.get('testKey2')).toBeNull();
});
it('set method with non-object value', () => {
LocalStorage.set('testKey', 'testValue');
expect(LocalStorage.get('testKey')).toBe('testValue');
});
it('set and get methods with null value', () => {
LocalStorage.set('testKey', null);
expect(LocalStorage.get('testKey')).toBeNull();
});
it('set and get methods with undefined value', () => {
LocalStorage.set('testKey', undefined);
expect(LocalStorage.get('testKey')).toBe('undefined');
});
it('set and get methods with boolean value', () => {
LocalStorage.set('testKey', true);
expect(LocalStorage.get('testKey')).toBe(true);
});
it('set and get methods with number value', () => {
LocalStorage.set('testKey', 42);
expect(LocalStorage.get('testKey')).toBe(42);
});
});
@@ -11,6 +11,24 @@ export const INBOX_TYPES = {
SMS: 'Channel::Sms',
};
export const INBOX_FEATURES = {
REPLY_TO: 'replyTo',
};
// This is a single source of truth for inbox features
// This is used to check if a feature is available for a particular inbox or not
export const INBOX_FEATURE_MAP = {
[INBOX_FEATURES.REPLY_TO]: [
INBOX_TYPES.WEB,
INBOX_TYPES.FB,
INBOX_TYPES.TWITTER,
INBOX_TYPES.WHATSAPP,
INBOX_TYPES.LINE,
INBOX_TYPES.TELEGRAM,
INBOX_TYPES.API,
],
};
export default {
computed: {
channelType() {
@@ -102,4 +120,9 @@ export default {
);
},
},
methods: {
inboxHasFeature(feature) {
return INBOX_FEATURE_MAP[feature]?.includes(this.channelType) ?? false;
},
},
};
@@ -1,218 +1,286 @@
import { shallowMount } from '@vue/test-utils';
import inboxMixin from '../inboxMixin';
function getComponentConfigForInbox(channelType, additionalConfig = {}) {
return {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: {
channel_type: channelType,
...additionalConfig,
},
};
},
};
}
function getComponentConfigForChat(chat) {
return {
render() {},
mixins: [inboxMixin],
data() {
return {
chat,
};
},
};
}
describe('inboxMixin', () => {
it('returns the correct channel type', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return { inbox: { channel_type: 'Channel::WebWidget' } };
},
};
const Component = getComponentConfigForInbox('Channel::WebWidget');
const wrapper = shallowMount(Component);
expect(wrapper.vm.channelType).toBe('Channel::WebWidget');
});
it('isAPIInbox returns true if channel type is API', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return { inbox: { channel_type: 'Channel::Api' } };
},
};
const Component = getComponentConfigForInbox('Channel::Api');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAPIInbox).toBe(true);
});
it('isATwitterInbox returns true if channel type is twitter', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return { inbox: { channel_type: 'Channel::TwitterProfile' } };
},
};
const Component = getComponentConfigForInbox('Channel::TwitterProfile');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwitterInbox).toBe(true);
});
it('isAFacebookInbox returns true if channel type is Facebook', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return { inbox: { channel_type: 'Channel::FacebookPage' } };
},
};
const Component = getComponentConfigForInbox('Channel::FacebookPage');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAFacebookInbox).toBe(true);
});
it('isAWebWidgetInbox returns true if channel type is Facebook', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return { inbox: { channel_type: 'Channel::WebWidget' } };
},
};
const Component = getComponentConfigForInbox('Channel::WebWidget');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAWebWidgetInbox).toBe(true);
});
it('isASmsInbox returns true if channel type is sms', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return { inbox: { channel_type: 'Channel::Sms' } };
},
};
const Component = getComponentConfigForInbox('Channel::Sms');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isASmsInbox).toBe(true);
});
it('isASmsInbox returns true if channel type is twilio sms', () => {
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: 'sms',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isASmsInbox).toBe(true);
});
it('isALineChannel returns true if channel type is Line', () => {
const Component = getComponentConfigForInbox('Channel::Line');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isALineChannel).toBe(true);
});
it('isATelegramChannel returns true if channel type is Telegram', () => {
const Component = getComponentConfigForInbox('Channel::Telegram');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATelegramChannel).toBe(true);
});
it('isATwilioChannel returns true if channel type is Twilio', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: {
channel_type: 'Channel::TwilioSms',
},
};
},
};
const Component = getComponentConfigForInbox('Channel::TwilioSms');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioChannel).toBe(true);
});
it('isATwilioSMSChannel returns true if channel type is Twilio and medium is SMS', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: {
channel_type: 'Channel::TwilioSms',
medium: 'sms',
},
};
},
};
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioChannel).toBe(true);
expect(wrapper.vm.isATwilioSMSChannel).toBe(true);
expect(wrapper.vm.isASmsInbox).toBe(true);
});
describe('isATwilioSMSChannel', () => {
it('returns true if channel type is Twilio and medium is SMS', () => {
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: 'sms',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioSMSChannel).toBe(true);
});
it('isATwilioWhatsAppChannel returns true if channel type is Twilio and medium is WhatsApp', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: {
channel_type: 'Channel::TwilioSms',
medium: 'whatsapp',
},
};
},
};
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioChannel).toBe(true);
expect(wrapper.vm.isATwilioWhatsAppChannel).toBe(true);
it('returns false if channel type is Twilio but medium is not SMS', () => {
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: 'whatsapp',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioSMSChannel).toBe(false);
});
it('returns false if channel type is not Twilio but medium is SMS', () => {
const Component = getComponentConfigForInbox('Channel::NotTwilio', {
medium: 'sms',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioSMSChannel).toBe(false);
});
it('returns false if neither channel type is Twilio nor medium is SMS', () => {
const Component = getComponentConfigForInbox('Channel::NotTwilio', {
medium: 'not_sms',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioSMSChannel).toBe(false);
});
it('returns false if channel type is Twilio but medium is empty', () => {
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: undefined,
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioSMSChannel).toBe(false);
});
});
it('isAnEmailChannel returns true if channel type is email', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: { channel_type: 'Channel::Email' },
};
},
};
const Component = getComponentConfigForInbox('Channel::Email');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAnEmailChannel).toBe(true);
});
it('isTwitterInboxTweet returns true if Twitter channel type is tweet', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
chat: {
channel_type: 'Channel::TwitterProfile',
additional_attributes: {
type: 'tweet',
},
},
};
const Component = getComponentConfigForChat({
channel_type: 'Channel::TwitterProfile',
additional_attributes: {
type: 'tweet',
},
};
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isTwitterInboxTweet).toBe(true);
});
it('twilioBadge returns string sms if channel type is Twilio and medium is sms', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: {
channel_type: 'Channel::TwilioSms',
medium: 'sms',
},
};
},
};
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: 'sms',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioSMSChannel).toBe(true);
expect(wrapper.vm.twilioBadge).toBe('sms');
});
it('twitterBadge returns string twitter-tweet if Twitter channel type is tweet', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
chat: {
id: 1,
additional_attributes: {
type: 'tweet',
},
},
};
const Component = getComponentConfigForChat({
id: 1,
additional_attributes: {
type: 'tweet',
},
};
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isTwitterInboxTweet).toBe(true);
expect(wrapper.vm.twitterBadge).toBe('twitter-tweet');
});
it('inboxBadge returns string Channel::Telegram if isATwilioChannel and isATwitterInbox is false', () => {
const Component = {
render() {},
mixins: [inboxMixin],
data() {
return {
inbox: {
channel_type: 'Channel::Telegram',
},
};
},
};
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioChannel).toBe(false);
expect(wrapper.vm.isATwitterInbox).toBe(false);
expect(wrapper.vm.channelType).toBe('Channel::Telegram');
describe('Badges', () => {
it('inboxBadge returns string Channel::Telegram if isATwilioChannel and isATwitterInbox is false', () => {
const Component = getComponentConfigForInbox('Channel::Telegram');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isATwilioChannel).toBe(false);
expect(wrapper.vm.isATwitterInbox).toBe(false);
expect(wrapper.vm.channelType).toBe('Channel::Telegram');
});
it('inboxBadge returns correct badge for WhatsApp channel', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxBadge).toBe('whatsapp');
});
it('inboxBadge returns the twitterBadge when isATwitterInbox is true', () => {
const Component = getComponentConfigForInbox('Channel::TwitterProfile');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxBadge).toBe('twitter-dm');
});
it('inboxBadge returns the facebookBadge when isAFacebookInbox is true', () => {
const Component = getComponentConfigForInbox('Channel::FacebookPage');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxBadge).toBe('facebook');
});
it('inboxBadge returns the twilioBadge when isATwilioChannel is true', () => {
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: 'sms',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxBadge).toBe('sms');
});
it('inboxBadge returns "whatsapp" when isAWhatsAppChannel is true', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxBadge).toBe('whatsapp');
});
it('inboxBadge returns the channelType when no specific condition is true', () => {
const Component = getComponentConfigForInbox('Channel::Email');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxBadge).toBe('Channel::Email');
});
});
describe('#inboxHasFeature', () => {
it('detects the correct feature', () => {
const Component = getComponentConfigForInbox('Channel::Telegram');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxHasFeature('replyTo')).toBe(true);
expect(wrapper.vm.inboxHasFeature('feature-does-not-exist')).toBe(false);
});
it('returns false for feature not included', () => {
const Component = getComponentConfigForInbox('Channel::Sms');
const wrapper = shallowMount(Component);
expect(wrapper.vm.inboxHasFeature('replyTo')).toBe(false);
expect(wrapper.vm.inboxHasFeature('feature-does-not-exist')).toBe(false);
});
});
describe('WhatsApp channel', () => {
it('returns correct whatsAppAPIProvider', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp', {
provider: 'whatsapp_cloud',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.whatsAppAPIProvider).toBe('whatsapp_cloud');
});
it('returns empty whatsAppAPIProvider if nothing is present', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp', {
provider: undefined,
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.whatsAppAPIProvider).toBe('');
});
it('isAWhatsAppCloudChannel returns true if channel type is WhatsApp and provider is whatsapp_cloud', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp', {
provider: 'whatsapp_cloud',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAWhatsAppCloudChannel).toBe(true);
});
it('is360DialogWhatsAppChannel returns true if channel type is WhatsApp and provider is default', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp', {
provider: 'default',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.is360DialogWhatsAppChannel).toBe(true);
});
it('isAWhatsAppChannel returns true if channel type is WhatsApp', () => {
const Component = getComponentConfigForInbox('Channel::Whatsapp');
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAWhatsAppChannel).toBe(true);
});
it('isAWhatsAppChannel returns true if channel type is Twilio and medium is WhatsApp', () => {
const Component = getComponentConfigForInbox('Channel::TwilioSms', {
medium: 'whatsapp',
});
const wrapper = shallowMount(Component);
expect(wrapper.vm.isAWhatsAppChannel).toBe(true);
});
});
});
+2
View File
@@ -57,3 +57,5 @@
enabled: false
- name: response_bot
enabled: false
- name: message_reply_to
enabled: false