unit tests for ic3 enhancers (#22)
This commit is contained in:
Родитель
b728f68f1f
Коммит
1e5422e087
|
@ -0,0 +1,120 @@
|
|||
import createEgressMessageActivityMiddleware from './../../../../src/ic3/enhancers/egress/createEgressFileAttachmentMiddleware';
|
||||
import { StateKey } from './../../../../src/types/ic3/IC3AdapterState';
|
||||
import { TelemetryEvents } from './../../../../src/types/ic3/TelemetryEvents';
|
||||
import { ActivityType } from './../../../../src/types/DirectLineTypes';
|
||||
|
||||
describe('createEgressFileAttachmentMiddleware test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
let fetchBefore;
|
||||
|
||||
beforeAll(() => {
|
||||
spyOn(Date.prototype, 'toISOString').and.returnValue('dateString');
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
fetchBefore = global.fetch;
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { ERROR: 'ERROR' }
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
global.fetch = fetchBefore;
|
||||
});
|
||||
|
||||
test('should return next', async () => {
|
||||
const activity = { type: ActivityType.Message }
|
||||
const next = 'next'
|
||||
const result = await createEgressMessageActivityMiddleware()({getState: () => {}})(() => next)(activity)
|
||||
expect(result).toBe(next);
|
||||
});
|
||||
|
||||
test('should throw error', async () => {
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
attachments: [{}]
|
||||
}
|
||||
const getState = (key) => key === StateKey.Logger ? { logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent } : null;
|
||||
try {
|
||||
await createEgressMessageActivityMiddleware()({getState})()(activity);
|
||||
} catch(e) {
|
||||
expect(e).toEqual(new Error('IC3: Failed to egress without an active conversation.'));
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('ERROR', {
|
||||
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
|
||||
Description: `Adapter: Failed to egress without an active conversation.`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('should call next with correct individualActivity', async () => {
|
||||
global.fetch = () => ({
|
||||
ok: true,
|
||||
blob: () => 'resBlob'
|
||||
});
|
||||
const next = jest.fn();
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
attachments: [
|
||||
{ contentUrl: 'contentUrl1', name: 'attachmentName1', contentType: 'type1' },
|
||||
{ contentUrl: 'contentUrl2', name: 'attachmentName2', contentType: 'type2' }
|
||||
]
|
||||
}
|
||||
const conversation = { uploadFile: () => 'file uploaded' }
|
||||
const getState = () => conversation;
|
||||
await createEgressMessageActivityMiddleware()({ getState })(next)(activity);
|
||||
const expectedIndividualActivity = {
|
||||
attachments: [
|
||||
{
|
||||
blob: 'resBlob',
|
||||
contentType: activity.attachments[0].contentType,
|
||||
contentUrl: activity.attachments[0].contentUrl,
|
||||
name: activity.attachments[0].name
|
||||
},
|
||||
{
|
||||
blob: 'resBlob',
|
||||
contentType: activity.attachments[1].contentType,
|
||||
contentUrl: activity.attachments[1].contentUrl,
|
||||
name: activity.attachments[1].name
|
||||
}
|
||||
],
|
||||
channelData: {
|
||||
middlewareData: {
|
||||
[activity.attachments[0].name]: activity.attachments[0].contentUrl,
|
||||
[activity.attachments[1].name]: activity.attachments[1].contentUrl
|
||||
},
|
||||
uploadedFileMetadata: 'file uploaded'
|
||||
},
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message
|
||||
};
|
||||
expect(next).toHaveBeenCalledWith(expectedIndividualActivity)
|
||||
});
|
||||
|
||||
test('should throw error on failed attachment fetch', async () => {
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
global.fetch = () => ({ ok: false });
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
attachments: [{ contentUrl: 'contentUrl1', name: 'attachmentName1', contentType: 'type1' }]
|
||||
}
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent});
|
||||
|
||||
try {
|
||||
await createEgressMessageActivityMiddleware()({ getState })(() => {})(activity);
|
||||
} catch(e) {
|
||||
expect(e).toEqual(new Error('IC3: Failed to fetch attachment to send.'));
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('ERROR', {
|
||||
Event: TelemetryEvents.FETCH_ATTACHMENT_FAILED,
|
||||
Description: `Adapter: Failed to fetch attachment to send.`
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,202 @@
|
|||
import createEgressMessageActivityMiddleware from './../../../../src/ic3/enhancers/egress/createEgressMessageActivityMiddleware';
|
||||
import { ActivityType } from './../../../../src/types/DirectLineTypes';
|
||||
import { TelemetryEvents } from './../../../../src/types/ic3/TelemetryEvents';
|
||||
import { StateKey } from './../../../../src/types/ic3/IC3AdapterState';
|
||||
|
||||
describe('test createEgressMessageActivityMiddleware', () => {
|
||||
let globalMicrosoftBefore;
|
||||
const testDateNowValue = 123
|
||||
const textContentType = 'Text';
|
||||
const testActivityId = 'testActivityId';
|
||||
const userPersonType = 0;
|
||||
const userMessageType = 0;
|
||||
const logClientSdkTelemetryEventSpy = jest.fn();
|
||||
const sendMessageMock = jest.fn();
|
||||
const sendFileMessageMock = jest.fn();
|
||||
const next = () => 'next';
|
||||
const mockGetState = (key) => {
|
||||
switch(key) {
|
||||
case StateKey.Conversation: {
|
||||
return {
|
||||
sendMessage: sendMessageMock,
|
||||
sendFileMessage: sendFileMessageMock
|
||||
}
|
||||
}
|
||||
case StateKey.UserDisplayName: return StateKey.UserDisplayName;
|
||||
case StateKey.Logger: return { logClientSdkTelemetryEvent: logClientSdkTelemetryEventSpy};
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
spyOn(Date, 'now').and.returnValue(testDateNowValue);
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { ERROR: 'ERROR', DEBUG: 'DEBUG' },
|
||||
MessageContentType: { Text: textContentType },
|
||||
MessageType: { UserMessage: userMessageType },
|
||||
PersonType: { User: userPersonType },
|
||||
DeliveryMode: { Bridged: 'Bridged' }
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
});
|
||||
|
||||
it('should return next', async () => {
|
||||
const activity = { type: ActivityType.Typing };
|
||||
const result = await createEgressMessageActivityMiddleware()({getState: () => ({})})(next)(activity);
|
||||
expect(result).toEqual(next());
|
||||
});
|
||||
|
||||
it('should throw an error when no conversation', async () => {
|
||||
const activity = { type: ActivityType.Message };
|
||||
try {
|
||||
await createEgressMessageActivityMiddleware()({getState: () => null})(next)(activity);
|
||||
} catch(e) {
|
||||
expect(e).toEqual(new Error('IC3: Failed to egress without an active conversation.'));
|
||||
}
|
||||
});
|
||||
|
||||
it('should send correct text message', async () => {
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
channelData: { deliveryMode: 'testMode' },
|
||||
from: { id: 'testFromId' },
|
||||
timestamp: 123
|
||||
};
|
||||
|
||||
await createEgressMessageActivityMiddleware()({getState: mockGetState})(next)(activity);
|
||||
const expectedMessage = {
|
||||
clientmessageid: `${testDateNowValue}`,
|
||||
content: '',
|
||||
contentType: textContentType,
|
||||
deliveryMode: 'testMode',
|
||||
messageType: 0,
|
||||
properties: activity.channelData,
|
||||
sender: { displayName: StateKey.UserDisplayName, id: activity.from.id, type: 0 },
|
||||
tags: [],
|
||||
timestamp: new Date(activity.timestamp)
|
||||
}
|
||||
expect(logClientSdkTelemetryEventSpy).toHaveBeenCalledWith(
|
||||
'DEBUG',
|
||||
{
|
||||
Event: TelemetryEvents.SEND_MESSAGE_SUCCESS,
|
||||
Description: `Adapter: Successfully sent a message with clientmessageid ${testDateNowValue}`
|
||||
}
|
||||
);
|
||||
expect(sendMessageMock).toHaveBeenCalledWith(expectedMessage);
|
||||
});
|
||||
|
||||
it('should send correct text message without tags', async () => {
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
channelData: { clientActivityID: testActivityId },
|
||||
from: { id: 'testFromId' },
|
||||
timestamp: 123,
|
||||
value: {}
|
||||
};
|
||||
|
||||
await createEgressMessageActivityMiddleware()({getState: mockGetState})(next)(activity);
|
||||
const expectedMessage = {
|
||||
clientmessageid: `${testDateNowValue}`,
|
||||
content: JSON.stringify(activity.value),
|
||||
contentType: textContentType,
|
||||
deliveryMode: 'Bridged',
|
||||
messageType: 0,
|
||||
properties: { deliveryMode: 'Bridged' },
|
||||
sender: { displayName: StateKey.UserDisplayName, id: activity.from.id, type: 0 },
|
||||
tags: ["client_activity_id:testActivityId"],
|
||||
timestamp: new Date(activity.timestamp)
|
||||
}
|
||||
expect(logClientSdkTelemetryEventSpy).toHaveBeenCalledWith(
|
||||
'DEBUG',
|
||||
{
|
||||
Event: TelemetryEvents.SEND_MESSAGE_SUCCESS,
|
||||
Description: `Adapter: Successfully sent a message with clientmessageid ${testDateNowValue}`
|
||||
}
|
||||
);
|
||||
expect(sendMessageMock).toHaveBeenCalledWith(expectedMessage);
|
||||
});
|
||||
|
||||
it('should send correct text message with tags', async () => {
|
||||
const clientActivityId = 'client_activity_id:1'
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
channelData: {
|
||||
clientActivityID: testActivityId,
|
||||
tags: [clientActivityId, 'testTag']
|
||||
},
|
||||
from: { id: 'testFromId' },
|
||||
timestamp: 123,
|
||||
value: {}
|
||||
};
|
||||
|
||||
await createEgressMessageActivityMiddleware()({getState: mockGetState})(next)(activity);
|
||||
const expectedMessage = {
|
||||
clientmessageid: `${testDateNowValue}`,
|
||||
content: JSON.stringify(activity.value),
|
||||
contentType: textContentType,
|
||||
deliveryMode: 'Bridged',
|
||||
messageType: 0,
|
||||
properties: { deliveryMode: 'Bridged' },
|
||||
sender: { displayName: StateKey.UserDisplayName, id: activity.from.id, type: 0 },
|
||||
tags: ["client_activity_id:testActivityId", 'testTag'],
|
||||
timestamp: new Date(activity.timestamp)
|
||||
}
|
||||
expect(logClientSdkTelemetryEventSpy).toHaveBeenCalledWith(
|
||||
'DEBUG',
|
||||
{
|
||||
Event: TelemetryEvents.SEND_MESSAGE_SUCCESS,
|
||||
Description: `Adapter: Successfully sent a message with clientmessageid ${testDateNowValue}`
|
||||
}
|
||||
);
|
||||
expect(sendMessageMock).toHaveBeenCalledWith(expectedMessage);
|
||||
});
|
||||
|
||||
it('should send correct file message', async () => {
|
||||
const clientActivityId = 'client_activity_id:1'
|
||||
const activity = {
|
||||
type: ActivityType.Message,
|
||||
channelData: {
|
||||
clientActivityID: testActivityId,
|
||||
tags: [clientActivityId, 'testTag'],
|
||||
uploadedFileMetadata: 'fileMetaData'
|
||||
},
|
||||
from: { id: 'testFromId' },
|
||||
timestamp: 123,
|
||||
value: {},
|
||||
previousClientActivityID: 'previousActivityId'
|
||||
};
|
||||
|
||||
await createEgressMessageActivityMiddleware()({getState: mockGetState})(next)(activity);
|
||||
const expectedMessage = {
|
||||
clientmessageid: `${testDateNowValue}`,
|
||||
content: JSON.stringify(activity.value),
|
||||
contentType: textContentType,
|
||||
deliveryMode: 'Bridged',
|
||||
messageType: 0,
|
||||
properties: { deliveryMode: 'Bridged' },
|
||||
sender: { displayName: StateKey.UserDisplayName, id: activity.from.id, type: 0 },
|
||||
tags: ["client_activity_id:testActivityId", 'testTag', "previousClientActivityID:previousActivityId"],
|
||||
timestamp: new Date(activity.timestamp)
|
||||
}
|
||||
expect(logClientSdkTelemetryEventSpy).toHaveBeenCalledWith(
|
||||
'DEBUG',
|
||||
{
|
||||
Event: TelemetryEvents.SEND_FILE_SUCCESS,
|
||||
Description: `Adapter: Successfully sent a file with clientmessageid ${testDateNowValue}`
|
||||
}
|
||||
);
|
||||
expect(sendFileMessageMock).toHaveBeenCalledWith(activity.channelData.uploadedFileMetadata, expectedMessage);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
import createEgressTypingActivityMiddleware from './../../../../src/ic3/enhancers/egress/createEgressTypingActivityMiddleware';
|
||||
import { ActivityType } from './../../../../src/types/DirectLineTypes';
|
||||
import { TelemetryEvents } from './../../../../src/types/ic3/TelemetryEvents';
|
||||
import { StateKey } from './../../../../src/types/ic3/IC3AdapterState';
|
||||
|
||||
describe('createEgressTypingActivityMiddleware test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
const logClientSdkTelemetryEventSpy = jest.fn();
|
||||
const indicateTypingStatusMock = jest.fn();
|
||||
const sendMessageToBotMock = jest.fn();
|
||||
const next = () => 'next';
|
||||
const mockGetState = (key) => {
|
||||
switch(key) {
|
||||
case StateKey.Conversation: {
|
||||
return {
|
||||
indicateTypingStatus: indicateTypingStatusMock,
|
||||
sendMessageToBot: sendMessageToBotMock
|
||||
}
|
||||
}
|
||||
case StateKey.UserDisplayName: return StateKey.UserDisplayName;
|
||||
case StateKey.BotId: return StateKey.BotId
|
||||
case StateKey.Logger: return { logClientSdkTelemetryEvent: logClientSdkTelemetryEventSpy};
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { DEBUG: 'DEBUG' },
|
||||
TypingStatus: { Typing: 'Typing' }
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
});
|
||||
|
||||
test('should return next when activity type is not typing', () => {
|
||||
const result = createEgressTypingActivityMiddleware()({getState: mockGetState})(next)({});
|
||||
expect(result).toEqual(next());
|
||||
});
|
||||
|
||||
test('should throw error when no conversationg', () => {
|
||||
const activity = { type: ActivityType.Typing }
|
||||
try {
|
||||
createEgressTypingActivityMiddleware()({getState: () => null})(next)(activity);
|
||||
} catch(e) {
|
||||
expect(e).toEqual(new Error('IC3: Failed to egress without an active conversation.'));
|
||||
}
|
||||
});
|
||||
|
||||
test('should indicate typing status, send message to bot and log correct event', () => {
|
||||
const activity = {
|
||||
type: ActivityType.Typing,
|
||||
channelData: { tags: ['tag'] }
|
||||
}
|
||||
createEgressTypingActivityMiddleware()({getState: mockGetState})(next)(activity);
|
||||
expect(indicateTypingStatusMock).toHaveBeenCalledWith('Typing', {
|
||||
imdisplayname: StateKey.UserDisplayName
|
||||
});
|
||||
expect(sendMessageToBotMock).toHaveBeenCalledWith(StateKey.BotId, {
|
||||
payload: '{"isTyping":true}'
|
||||
});
|
||||
expect(logClientSdkTelemetryEventSpy).toHaveBeenCalledWith('DEBUG', {
|
||||
Event: TelemetryEvents.SEND_TYPING_SUCCESS,
|
||||
Description: `Adapter: Successfully sent a typing indication`
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import createEgressEnhancer from './../../../../src/ic3/enhancers/egress/index';
|
||||
import * as applyEgressMiddleware from './../../../../src/applyEgressMiddleware';
|
||||
import * as createEgressFileAttachmentMiddleware from './../../../../src/ic3/enhancers/egress/createEgressFileAttachmentMiddleware';
|
||||
import * as createEgressMessageActivityMiddleware from './../../../../src/ic3/enhancers/egress/createEgressMessageActivityMiddleware';
|
||||
import * as createEgressTypingActivityMiddleware from './../../../../src/ic3/enhancers/egress/createEgressTypingActivityMiddleware';
|
||||
|
||||
describe('createEgressEnhancer test', () => {
|
||||
test('should call applyEgressMiddleware with correct params', () => {
|
||||
spyOn(applyEgressMiddleware, 'default');
|
||||
createEgressFileAttachmentMiddleware.default = jest.fn().mockReturnValue('mock1');
|
||||
createEgressMessageActivityMiddleware.default = jest.fn().mockReturnValue('mock2');
|
||||
createEgressTypingActivityMiddleware.default = jest.fn().mockReturnValue('mock2');
|
||||
|
||||
createEgressEnhancer();
|
||||
|
||||
expect(applyEgressMiddleware.default).toHaveBeenCalledWith('mock1', 'mock2', 'mock2');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,161 @@
|
|||
import createExtractAdaptiveCardMiddleware from './../../../../src/ic3/enhancers/ingress/createExtractAdaptiveCardMiddleware';
|
||||
import { ActivityType } from './../../../../src/types/DirectLineTypes';
|
||||
import { TelemetryEvents } from './../../../../src/types/ic3/TelemetryEvents';
|
||||
|
||||
describe('createExtractAdaptiveCardMiddleware test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
let globalDecodeURIComponentBefore;
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
const next = 'next';
|
||||
|
||||
beforeAll(() => {
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
globalDecodeURIComponentBefore = global.decodeURIComponent;
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { WARN: 'WARN' }
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
global.decodeURIComponent = globalDecodeURIComponentBefore
|
||||
});
|
||||
|
||||
test('should return next when activity type is not message', () => {
|
||||
const result = createExtractAdaptiveCardMiddleware()({getState: () => {}})(() => next)({});
|
||||
expect(result).toBe(next);
|
||||
});
|
||||
|
||||
test('should return next on wrong activity text', () => {
|
||||
const activity = { text: 'testText', type: ActivityType.Message }
|
||||
const result = createExtractAdaptiveCardMiddleware()({getState: () => {}})(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
});
|
||||
|
||||
test('should return next on TAG_PARSE_ERROR', () => {
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: () => [{}]
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('WARN', {
|
||||
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
|
||||
Description: `Adapter: [AdaptiveCard] Unable to parse XML; ignoring attachment.`
|
||||
});
|
||||
});
|
||||
|
||||
test('should return next when element nodeName is not CONTENT_URI_OBJECT', () => {
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: () => [],
|
||||
documentElement: { nodeName: 'testNodeName' }
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('WARN', {
|
||||
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
|
||||
Description: `Adapter: [AdaptiveCard] Wrong XML schema; ignoring attachment.`
|
||||
});
|
||||
});
|
||||
|
||||
test('should return next when no Swift element', () => {
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: () => [],
|
||||
documentElement: { nodeName: 'URIObject' }
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('WARN', {
|
||||
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
|
||||
Description: `Adapter: [AdaptiveCard] Does not contain <Swift>; ignoring attachment.`
|
||||
});
|
||||
});
|
||||
|
||||
test('should return next when no swiftJSON', () => {
|
||||
const mockdecodeURIComponent = jest.fn().mockReturnValue('');
|
||||
global.decodeURIComponent = mockdecodeURIComponent;
|
||||
const swiftElement = { getAttribute: () => '' }
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: (tag) => tag === 'Swift' ? [swiftElement] : [],
|
||||
documentElement: { nodeName: 'URIObject' }
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('WARN', {
|
||||
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
|
||||
Description: `Adapter: [AdaptiveCard] Data is empty; ignoring attachment.`
|
||||
});
|
||||
});
|
||||
|
||||
test('should return next when swift type does not include TYPE_MESSAGE_CARD', () => {
|
||||
const mockSwift = { type: 'message' }
|
||||
const mockdecodeURIComponent = jest.fn().mockReturnValue(JSON.stringify(mockSwift));
|
||||
global.decodeURIComponent = mockdecodeURIComponent;
|
||||
const swiftElement = { getAttribute: () => '' }
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: (tag) => tag === 'Swift' ? [swiftElement] : [],
|
||||
documentElement: { nodeName: 'URIObject' }
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
});
|
||||
|
||||
test('should return next when no swift attachments', () => {
|
||||
const mockSwift = { type: 'message/card' }
|
||||
const mockdecodeURIComponent = jest.fn().mockReturnValue(JSON.stringify(mockSwift));
|
||||
global.decodeURIComponent = mockdecodeURIComponent;
|
||||
const swiftElement = { getAttribute: () => '' }
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: (tag) => tag === 'Swift' ? [swiftElement] : [],
|
||||
documentElement: { nodeName: 'URIObject' }
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })(() => next)(activity);
|
||||
expect(result).toBe(next);
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('WARN', {
|
||||
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
|
||||
Description: `Adapter: [AdaptiveCard] Key 'attachments' not found; ignoring attachment.`
|
||||
});
|
||||
});
|
||||
|
||||
test('should call next whith correct params', () => {
|
||||
const mockSwift = { type: 'message/card', attachments: [] }
|
||||
const mockdecodeURIComponent = jest.fn().mockReturnValue(JSON.stringify(mockSwift));
|
||||
global.decodeURIComponent = mockdecodeURIComponent;
|
||||
const swiftElement = { getAttribute: () => '' }
|
||||
const mockDomParser = {
|
||||
getElementsByTagName: (tag) => tag === 'Swift' ? [swiftElement] : [],
|
||||
documentElement: { nodeName: 'URIObject' }
|
||||
}
|
||||
spyOn(DOMParser.prototype, 'parseFromString').and.returnValue(mockDomParser);
|
||||
const activity = { text: 'URIObject', type: ActivityType.Message }
|
||||
const getState = () => ({logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent})
|
||||
const result = createExtractAdaptiveCardMiddleware()({ getState })((param) => param)(activity);
|
||||
const expectedResult = { attachments: mockSwift.attachments, text: '', type: 'message' };
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
import createPatchFromRoleAndNameMiddleware from './../../../../src/ic3/enhancers/ingress/createPatchFromRoleAndNameMiddleware';
|
||||
import { StateKey } from './../../../../src/types/ic3/IC3AdapterState';
|
||||
import { Role } from './../../../../src/types/DirectLineTypes';
|
||||
|
||||
describe('createPatchFromRoleAndNameMiddleware test', () => {
|
||||
const next = jest.fn().mockReturnValue('next');
|
||||
test('should call next with correct params', () => {
|
||||
const getState = (key) => key === StateKey.UserId ? 'userId' : key === StateKey.UserDisplayName ? 'userName' : null;
|
||||
const activity = {
|
||||
from: {
|
||||
id: 'activityId',
|
||||
name: 'activityName',
|
||||
role: Role.User
|
||||
}
|
||||
}
|
||||
const result = createPatchFromRoleAndNameMiddleware()({ getState })(next)(activity);
|
||||
expect(result).toBe('next');
|
||||
expect(next).toHaveBeenCalledWith({
|
||||
from: {
|
||||
id: 'activityId',
|
||||
name: 'activityName',
|
||||
role: Role.Bot
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('should call next with correct params', () => {
|
||||
const getState = (key) => key === StateKey.UserId ? 'userId' : key === StateKey.UserDisplayName ? 'userName' : null;
|
||||
const activity = {
|
||||
from: {
|
||||
id: 'userIdActivity',
|
||||
name: 'activityName',
|
||||
role: Role.User
|
||||
}
|
||||
}
|
||||
const result = createPatchFromRoleAndNameMiddleware()({ getState })(next)(activity);
|
||||
expect(result).toBe('next');
|
||||
expect(next).toHaveBeenCalledWith({
|
||||
from: {
|
||||
id: 'userIdActivity',
|
||||
name: 'userName',
|
||||
role: Role.User
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('should call next with correct params', () => {
|
||||
const getState = (key) => key === StateKey.UserId ? 'userId' : key === StateKey.UserDisplayName ? 'userName' : null;
|
||||
const activity = {
|
||||
from: {
|
||||
id: 'userIdActivity',
|
||||
name: 'activityName',
|
||||
role: Role.Channel
|
||||
}
|
||||
}
|
||||
const result = createPatchFromRoleAndNameMiddleware()({ getState })(next)(activity);
|
||||
expect(result).toBe('next');
|
||||
expect(next).toHaveBeenCalledWith({...activity});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
import createIngressEnhancer from './../../../../src/ic3/enhancers/ingress/index';
|
||||
import * as redux from 'redux';
|
||||
import * as createExtractAdaptiveCardMiddleware from './../../../../src/ic3/enhancers/ingress/createExtractAdaptiveCardMiddleware';
|
||||
import * as createPatchFromRoleAndNameMiddleware from './../../../../src/ic3/enhancers/ingress/createPatchFromRoleAndNameMiddleware';
|
||||
import * as createSubscribeNewMessageAndThreadUpdateEnhancer from './../../../../src/ic3/enhancers/ingress/subscribeNewMessageAndThreadUpdate';
|
||||
import * as applyIngressMiddleware from './../../../../src/applyIngressMiddleware';
|
||||
|
||||
describe('createIngressEnhancer test', () => {
|
||||
test('should call compose with correct params', () => {
|
||||
spyOn(redux, 'compose').and.returnValue('compose');
|
||||
applyIngressMiddleware.default = jest.fn().mockReturnValue('mock1');
|
||||
createExtractAdaptiveCardMiddleware.default = jest.fn().mockReturnValue('mock2');
|
||||
createPatchFromRoleAndNameMiddleware.default = jest.fn().mockReturnValue('mock3');
|
||||
createSubscribeNewMessageAndThreadUpdateEnhancer.default = jest.fn().mockReturnValue('mock4');
|
||||
const result = createIngressEnhancer();
|
||||
expect(redux.compose).toHaveBeenCalledWith('mock4', 'mock1');
|
||||
expect(applyIngressMiddleware.default).toHaveBeenCalledWith('mock3', 'mock2');
|
||||
expect(result).toBe('compose')
|
||||
})
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
import createTypingMessageToDirectLineActivityMapper from './../../../../../src/ic3/enhancers/ingress/mappers/createThreadToDirectLineActivityMapper';
|
||||
import { StateKey } from './../../../../../src/types/ic3/IC3AdapterState';
|
||||
import { TelemetryEvents } from './../../../../../src/types/ic3/TelemetryEvents';
|
||||
import { IC3_CHANNEL_ID } from './../../../../../src/ic3/Constants';
|
||||
import { ActivityType, Role } from './../../../../../src/types/DirectLineTypes';
|
||||
import * as uniqueId from './../../../../../src/ic3/utils/uniqueId';
|
||||
|
||||
describe('createTypingMessageToDirectLineActivityMapper test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
|
||||
beforeAll(() => {
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { DEBUG: 'DEBUG', ERROR: 'ERROR' }
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
});
|
||||
|
||||
test('should throw error when no conversation', async () => {
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
const mockGetState = (key) => key === StateKey.Logger
|
||||
? { logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent }
|
||||
: null;
|
||||
try {
|
||||
await createTypingMessageToDirectLineActivityMapper({getState: mockGetState})()();
|
||||
} catch(e) {
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('ERROR', {
|
||||
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
|
||||
Description: `Adapter: Failed to ingress thread update without an active conversation.`
|
||||
});
|
||||
expect(e).toEqual(new Error('IC3: Failed to ingress thread update without an active conversation.'))
|
||||
}
|
||||
});
|
||||
|
||||
test('should return correct ic3 activity', async () => {
|
||||
spyOn(Date.prototype, 'toISOString').and.returnValue('dateString');
|
||||
spyOn(uniqueId, 'default').and.returnValue('uniqueId');
|
||||
|
||||
const conversation = { id: 'convId' };
|
||||
const mockGetState = () => conversation;
|
||||
const thread = {
|
||||
id: 'threadId',
|
||||
members: 'members',
|
||||
properties: 'properties',
|
||||
type: 'type'
|
||||
};
|
||||
const result = await createTypingMessageToDirectLineActivityMapper({getState: mockGetState})()(thread);
|
||||
const expectedResult = {
|
||||
channelData: {
|
||||
members: thread.members,
|
||||
properties: thread.properties,
|
||||
type: thread.type
|
||||
},
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation,
|
||||
from: {
|
||||
id: thread.id,
|
||||
name: '',
|
||||
role: Role.Channel
|
||||
},
|
||||
id: 'uniqueId',
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,73 @@
|
|||
import createTypingMessageToDirectLineActivityMapper from './../../../../../src/ic3/enhancers/ingress/mappers/createTypingMessageToDirectLineActivityMapper';
|
||||
import { StateKey } from './../../../../../src/types/ic3/IC3AdapterState';
|
||||
import { TelemetryEvents } from './../../../../../src/types/ic3/TelemetryEvents';
|
||||
import { IC3_CHANNEL_ID } from './../../../../../src/ic3/Constants';
|
||||
import { ActivityType } from './../../../../../src/types/DirectLineTypes';
|
||||
import * as uniqueId from './../../../../../src/ic3/utils/uniqueId';
|
||||
|
||||
describe('createTypingMessageToDirectLineActivityMapper test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
|
||||
beforeAll(() => {
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { ERROR: 'ERROR' },
|
||||
MessageType: { Typing: 'Typing', ClearTyping: 'ClearTyping'}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
});
|
||||
|
||||
test('should return next', async () => {
|
||||
const next = () => 'next';
|
||||
const result = await createTypingMessageToDirectLineActivityMapper({})(next)({});
|
||||
expect(result).toBe(next());
|
||||
});
|
||||
|
||||
test('should throw error when no conversation', async () => {
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
const getState = (key) => key === StateKey.Logger ? {logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent} : null;
|
||||
const message = { messageType: 'Typing' };
|
||||
try {
|
||||
await createTypingMessageToDirectLineActivityMapper({ getState })()(message);
|
||||
} catch(e) {
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('ERROR', {
|
||||
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
|
||||
Description: `Adapter: Failed to ingress typing without an active conversation.`
|
||||
});
|
||||
expect(e).toEqual(new Error('IC3: Failed to ingress typing without an active conversation.'));
|
||||
}
|
||||
});
|
||||
|
||||
test('should return correct object', async () => {
|
||||
spyOn(Date.prototype, 'toISOString').and.returnValue('dateString');
|
||||
spyOn(uniqueId, 'default').and.returnValue('uniqueId');
|
||||
const conversation = { id: 'tesConvId' };
|
||||
const getState = () => conversation;
|
||||
const message = {
|
||||
messageType: 'Typing',
|
||||
timestamp: new Date(),
|
||||
sender: { displayName: 'displayName', id: 'senderId' }
|
||||
};
|
||||
const result = await createTypingMessageToDirectLineActivityMapper({ getState })()(message);
|
||||
const expectedResult = {
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation,
|
||||
from: { id: message.sender.id, name: message.sender.displayName },
|
||||
id: 'uniqueId',
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Typing
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,286 @@
|
|||
import createUserMessageToDirectLineActivityMapper from './../../../../../src/ic3/enhancers/ingress/mappers/createUserMessageToDirectLineActivityMapper';
|
||||
import { StateKey } from './../../../../../src/types/ic3/IC3AdapterState';
|
||||
import { TelemetryEvents } from './../../../../../src/types/ic3/TelemetryEvents';
|
||||
import { IC3_CHANNEL_ID } from './../../../../../src/ic3/Constants';
|
||||
import { ActivityType } from './../../../../../src/types/DirectLineTypes';
|
||||
|
||||
describe('createUserMessageToDirectLineActivityMapper test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
let globalURLBefore;
|
||||
beforeAll(() => {
|
||||
spyOn(Date.prototype, 'toISOString').and.returnValue('dateString');
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
globalURLBefore = global.URL;
|
||||
global.URL.createObjectURL = jest.fn().mockReturnValue('objectUrl');
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: { ERROR: 'ERROR' },
|
||||
MessageType: { UserMessage: 'UserMessage' }
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
global.URL = globalURLBefore;
|
||||
});
|
||||
|
||||
test('should return next', async () => {
|
||||
const next = 'next';
|
||||
const result = await createUserMessageToDirectLineActivityMapper({getState: () => {}})(() => next)({});
|
||||
expect(result).toBe(next);
|
||||
});
|
||||
|
||||
test('should throw error', async () => {
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
const message = { messageType : 'UserMessage' };
|
||||
const getState = (key) => key === StateKey.Logger ? { logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent } : null;
|
||||
try {
|
||||
await createUserMessageToDirectLineActivityMapper({getState})()(message);
|
||||
} catch(e) {
|
||||
expect(e).toEqual(new Error('IC3: Failed to ingress message without an active conversation.'));
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('ERROR', {
|
||||
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
|
||||
Description: `Adapter: Failed to ingress message without an active conversation.`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('should return correct activity', async () => {
|
||||
const message = {
|
||||
messageType : 'UserMessage',
|
||||
messageid: 'messageid',
|
||||
clientmessageid: 'clientmessageid',
|
||||
content: 'content',
|
||||
properties: { fromUserId: 'fromUserId' },
|
||||
sender: { displayName: 'displayName', id: 'senderId' },
|
||||
timestamp: new Date()
|
||||
};
|
||||
const conversation = { id: 'conversationId' }
|
||||
const getState = () => conversation;
|
||||
const result = await createUserMessageToDirectLineActivityMapper({getState})()(message);
|
||||
const expectedResult = {
|
||||
attachments: undefined,
|
||||
channelData: {
|
||||
clientmessageid: message.clientmessageid,
|
||||
fromUserId: 'fromUserId',
|
||||
tags: undefined
|
||||
},
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation,
|
||||
from: { id: message.sender.id, name: message.sender.displayName },
|
||||
id: message.clientmessageid,
|
||||
messageid: message.messageid,
|
||||
suggestedActions: undefined,
|
||||
text: message.content,
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
test('should return correct activity with attachments', async () => {
|
||||
const message = {
|
||||
messageType : 'UserMessage',
|
||||
messageid: 'messageid',
|
||||
clientmessageid: 'clientmessageid',
|
||||
content: 'content',
|
||||
properties: { fromUserId: 'fromUserId' },
|
||||
sender: { displayName: 'displayName', id: 'senderId' },
|
||||
timestamp: new Date(),
|
||||
fileMetadata: { type: 'fileType' },
|
||||
tags: ['tetTag']
|
||||
};
|
||||
const conversation = {
|
||||
id: 'conversationId',
|
||||
downloadFile: () => 'downloadFile'
|
||||
}
|
||||
const getState = () => conversation;
|
||||
const result = await createUserMessageToDirectLineActivityMapper({getState})()(message);
|
||||
const expectedResult = {
|
||||
attachments: [{
|
||||
blob: 'downloadFile',
|
||||
contentType: 'application/octet-stream',
|
||||
contentUrl: 'objectUrl',
|
||||
tempContentUrl: 'objectUrl',
|
||||
thumbnailUrl: undefined,
|
||||
type: 'fileType'
|
||||
}],
|
||||
channelData: {
|
||||
clientmessageid: message.clientmessageid,
|
||||
fromUserId: message.properties.fromUserId,
|
||||
tags: message.tags
|
||||
},
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation: { id: conversation.id },
|
||||
from: { id: message.sender.id, name: message.sender.displayName },
|
||||
id: message.clientmessageid,
|
||||
messageid: message.messageid,
|
||||
suggestedActions: undefined,
|
||||
text: message.content,
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message,
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
test('should return correct activity with image attachment', async () => {
|
||||
const message = {
|
||||
messageType : 'UserMessage',
|
||||
messageid: 'messageid',
|
||||
clientmessageid: 'clientmessageid',
|
||||
content: 'content',
|
||||
properties: { fromUserId: 'fromUserId' },
|
||||
sender: { displayName: 'displayName', id: 'senderId' },
|
||||
timestamp: new Date(),
|
||||
fileMetadata: { type: 'gif' },
|
||||
tags: ['client_activity_id:']
|
||||
};
|
||||
const conversation = {
|
||||
id: 'conversationId',
|
||||
downloadFile: () => 'downloadFile'
|
||||
}
|
||||
const getState = () => conversation;
|
||||
const result = await createUserMessageToDirectLineActivityMapper({getState})()(message);
|
||||
const expectedResult = {
|
||||
attachments: [{
|
||||
blob: 'downloadFile',
|
||||
contentType: 'image/gif',
|
||||
contentUrl: 'objectUrl',
|
||||
tempContentUrl: 'objectUrl',
|
||||
thumbnailUrl: 'objectUrl',
|
||||
type: 'gif'
|
||||
}],
|
||||
channelData: {
|
||||
clientActivityID: '',
|
||||
clientmessageid: message.clientmessageid,
|
||||
fromUserId: message.properties.fromUserId,
|
||||
tags: message.tags
|
||||
},
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation: { id: conversation.id },
|
||||
from: { id: message.sender.id, name: message.sender.displayName },
|
||||
id: message.clientmessageid,
|
||||
messageid: message.messageid,
|
||||
suggestedActions: undefined,
|
||||
text: message.content,
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message,
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
test('should return correct activity with audio attachment', async () => {
|
||||
const message = {
|
||||
messageType : 'UserMessage',
|
||||
messageid: 'messageid',
|
||||
clientmessageid: 'clientmessageid',
|
||||
content: 'content',
|
||||
properties: { fromUserId: 'fromUserId' },
|
||||
sender: { displayName: 'displayName', id: 'senderId' },
|
||||
timestamp: new Date(),
|
||||
fileMetadata: { type: 'mp3' },
|
||||
tags: ['client_activity_id:']
|
||||
};
|
||||
const conversation = {
|
||||
id: 'conversationId',
|
||||
downloadFile: () => 'downloadFile'
|
||||
}
|
||||
const getState = (key) => {
|
||||
switch(key) {
|
||||
case StateKey.FeatureConfig: return {
|
||||
ShouldEnableInlineAudioPlaying: true,
|
||||
}
|
||||
case StateKey.Conversation: return conversation;
|
||||
default: return null
|
||||
}
|
||||
};
|
||||
const result = await createUserMessageToDirectLineActivityMapper({getState})()(message);
|
||||
const expectedResult = {
|
||||
attachments: [{
|
||||
blob: 'downloadFile',
|
||||
contentType: 'audio/mp3',
|
||||
contentUrl: 'objectUrl',
|
||||
tempContentUrl: 'objectUrl',
|
||||
thumbnailUrl: 'objectUrl',
|
||||
type: 'mp3'
|
||||
}],
|
||||
channelData: {
|
||||
clientActivityID: '',
|
||||
clientmessageid: message.clientmessageid,
|
||||
fromUserId: message.properties.fromUserId,
|
||||
tags: message.tags
|
||||
},
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation: { id: conversation.id },
|
||||
from: { id: message.sender.id, name: message.sender.displayName },
|
||||
id: message.clientmessageid,
|
||||
messageid: message.messageid,
|
||||
suggestedActions: undefined,
|
||||
text: message.content,
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message,
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
test('should return correct activity with video attachment', async () => {
|
||||
const message = {
|
||||
messageType : 'UserMessage',
|
||||
messageid: 'messageid',
|
||||
clientmessageid: 'clientmessageid',
|
||||
content: 'content',
|
||||
properties: { fromUserId: 'fromUserId' },
|
||||
sender: { displayName: 'displayName', id: 'senderId' },
|
||||
timestamp: new Date(),
|
||||
fileMetadata: { type: 'mp4' },
|
||||
tags: ['client_activity_id:']
|
||||
};
|
||||
const conversation = {
|
||||
id: 'conversationId',
|
||||
downloadFile: () => 'downloadFile'
|
||||
}
|
||||
const getState = (key) => {
|
||||
switch(key) {
|
||||
case StateKey.FeatureConfig: return {
|
||||
ShouldEnableInlineVideoPlaying: true
|
||||
}
|
||||
case StateKey.Conversation: return conversation;
|
||||
default: return null
|
||||
}
|
||||
};
|
||||
const result = await createUserMessageToDirectLineActivityMapper({getState})()(message);
|
||||
const expectedResult = {
|
||||
attachments: [{
|
||||
blob: 'downloadFile',
|
||||
contentType: 'video/mp4',
|
||||
contentUrl: 'objectUrl',
|
||||
tempContentUrl: 'objectUrl',
|
||||
thumbnailUrl: 'objectUrl',
|
||||
type: 'mp4'
|
||||
}],
|
||||
channelData: {
|
||||
clientActivityID: '',
|
||||
clientmessageid: message.clientmessageid,
|
||||
fromUserId: message.properties.fromUserId,
|
||||
tags: message.tags
|
||||
},
|
||||
channelId: IC3_CHANNEL_ID,
|
||||
conversation: { id: conversation.id },
|
||||
from: { id: message.sender.id, name: message.sender.displayName },
|
||||
id: message.clientmessageid,
|
||||
messageid: message.messageid,
|
||||
suggestedActions: undefined,
|
||||
text: message.content,
|
||||
timestamp: 'dateString',
|
||||
type: ActivityType.Message,
|
||||
}
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,115 @@
|
|||
import createSubscribeNewMessageAndThreadUpdateEnhancer from './../../../../src/ic3/enhancers/ingress/subscribeNewMessageAndThreadUpdate';
|
||||
import * as redux from 'redux';
|
||||
import * as applySetStateMiddleware from './../../../../src/applySetStateMiddleware';
|
||||
import * as createThreadToDirectLineActivityMapper from './../../../../src/ic3/enhancers/ingress/mappers/createThreadToDirectLineActivityMapper';
|
||||
import { StateKey } from './../../../../src/types/ic3/IC3AdapterState';
|
||||
import { TelemetryEvents } from './../../../../src/types/ic3/TelemetryEvents';
|
||||
import { ReadyState } from './../../../../src/types/AdapterTypes';
|
||||
import ConnectivityManager from './../../../../src/ic3/utils/ConnectivityManager';
|
||||
|
||||
describe('createSubscribeNewMessageAndThreadUpdateEnhancer test', () => {
|
||||
let globalMicrosoftBefore;
|
||||
let windowAddEventListenerBefore;
|
||||
const mockLogClientSdkTelemetryEvent = jest.fn();
|
||||
const subscribe = subscriber => { subscriber.subscribe()}
|
||||
applySetStateMiddleware.default = (param) => param;
|
||||
const next = jest.fn();
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
windowAddEventListenerBefore = window.addEventListener;
|
||||
globalMicrosoftBefore = global.Microsoft;
|
||||
window.addEventListener = jest.fn((param1, param2) => param2());
|
||||
redux.compose = () => param => { param() }
|
||||
createThreadToDirectLineActivityMapper.default = () => param => { param() }
|
||||
spyOn(redux, 'compose').and.callThrough();
|
||||
spyOn(createThreadToDirectLineActivityMapper, 'default').and.callThrough();
|
||||
global.Microsoft = {
|
||||
CRM: {
|
||||
Omnichannel: {
|
||||
IC3Client: {
|
||||
Model: {
|
||||
LogLevel: {
|
||||
WARN: 'WARN',
|
||||
DEBUG: 'DEBUG',
|
||||
INFO: 'INFO',
|
||||
ERROR: 'ERROR'
|
||||
},
|
||||
IConversation: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.Microsoft = globalMicrosoftBefore;
|
||||
window.addEventListener = windowAddEventListenerBefore;
|
||||
});
|
||||
|
||||
test('should make correct calls when isInternetConnected is true, getReadyState is open', async () => {
|
||||
spyOn(ConnectivityManager, 'isInternetConnected').and.returnValue(true);
|
||||
const conversation = {
|
||||
getMessages: () => ['message1', 'mmesage2'],
|
||||
registerOnNewMessage: (param) => { param() },
|
||||
registerOnThreadUpdate: (param) => { param() }
|
||||
}
|
||||
const getState = (key) => {
|
||||
switch(key) {
|
||||
case StateKey.Logger: return {
|
||||
logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent
|
||||
}
|
||||
case StateKey.ConnectionStatusObserverReady: return 'ConnectionStatusObserverReady';
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
await createSubscribeNewMessageAndThreadUpdateEnhancer()({
|
||||
getState,
|
||||
subscribe,
|
||||
getReadyState: () => ReadyState.OPEN
|
||||
})(next)(StateKey.Conversation, conversation);
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('DEBUG', {
|
||||
Event: TelemetryEvents.REHYDRATE_MESSAGES,
|
||||
Description: `Adapter: Re-hydrating received messages`
|
||||
});
|
||||
expect(window.addEventListener).toHaveBeenCalledWith('reinitialize', expect.any(Function));
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('DEBUG', {
|
||||
Event: TelemetryEvents.REGISTER_ON_NEW_MESSAGE,
|
||||
Description: `Adapter: Registering on new message success`
|
||||
});
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('DEBUG', {
|
||||
Event: TelemetryEvents.GET_MESSAGES_SUCCESS,
|
||||
Description: `Adapter: Getting messages success`
|
||||
});
|
||||
expect(redux.compose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should make correct calls when isInternetConnected is false, getReadyState is not open', async () => {
|
||||
spyOn(ConnectivityManager, 'isInternetConnected').and.returnValue(false);
|
||||
const conversation = {
|
||||
getMessages: () => ['message1', 'mmesage2'],
|
||||
registerOnNewMessage: (param) => { param() },
|
||||
registerOnThreadUpdate: (param) => { param() }
|
||||
}
|
||||
const getState = (key) => {
|
||||
switch(key) {
|
||||
case StateKey.Logger: return {
|
||||
logClientSdkTelemetryEvent: mockLogClientSdkTelemetryEvent
|
||||
}
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
await createSubscribeNewMessageAndThreadUpdateEnhancer()({
|
||||
getState,
|
||||
subscribe,
|
||||
getReadyState: () => {}
|
||||
})(next)(StateKey.Conversation, conversation);
|
||||
jest.runAllTimers();
|
||||
expect(mockLogClientSdkTelemetryEvent).toHaveBeenCalledWith('DEBUG', {
|
||||
Event: TelemetryEvents.REHYDRATE_MESSAGES,
|
||||
Description: `Adapter: Re-hydrating received messages`
|
||||
});
|
||||
expect(window.addEventListener).toHaveBeenCalledWith('reinitialize', expect.any(Function));
|
||||
expect(redux.compose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
Загрузка…
Ссылка в новой задаче