@webex/contact-center 3.10.0-next.7 → 3.10.0-next.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/cc.js +11 -0
  2. package/dist/cc.js.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/services/config/types.js +2 -2
  5. package/dist/services/config/types.js.map +1 -1
  6. package/dist/services/core/Utils.js +90 -71
  7. package/dist/services/core/Utils.js.map +1 -1
  8. package/dist/services/core/constants.js +17 -1
  9. package/dist/services/core/constants.js.map +1 -1
  10. package/dist/services/task/TaskManager.js +61 -36
  11. package/dist/services/task/TaskManager.js.map +1 -1
  12. package/dist/services/task/TaskUtils.js +33 -5
  13. package/dist/services/task/TaskUtils.js.map +1 -1
  14. package/dist/services/task/index.js +49 -58
  15. package/dist/services/task/index.js.map +1 -1
  16. package/dist/services/task/types.js +2 -4
  17. package/dist/services/task/types.js.map +1 -1
  18. package/dist/types/cc.d.ts +6 -0
  19. package/dist/types/index.d.ts +1 -1
  20. package/dist/types/services/config/types.d.ts +4 -4
  21. package/dist/types/services/core/Utils.d.ts +32 -17
  22. package/dist/types/services/core/constants.d.ts +14 -0
  23. package/dist/types/services/task/TaskUtils.d.ts +17 -3
  24. package/dist/types/services/task/types.d.ts +25 -13
  25. package/dist/webex.js +1 -1
  26. package/package.json +8 -8
  27. package/src/cc.ts +11 -0
  28. package/src/index.ts +1 -0
  29. package/src/services/config/types.ts +2 -2
  30. package/src/services/core/Utils.ts +101 -85
  31. package/src/services/core/constants.ts +16 -0
  32. package/src/services/task/TaskManager.ts +75 -28
  33. package/src/services/task/TaskUtils.ts +37 -5
  34. package/src/services/task/index.ts +54 -89
  35. package/src/services/task/types.ts +26 -13
  36. package/test/unit/spec/services/core/Utils.ts +262 -31
  37. package/test/unit/spec/services/task/TaskManager.ts +224 -1
  38. package/test/unit/spec/services/task/TaskUtils.ts +6 -6
  39. package/test/unit/spec/services/task/index.ts +283 -86
  40. package/umd/contact-center.min.js +2 -2
  41. package/umd/contact-center.min.js.map +1 -1
@@ -1495,6 +1495,18 @@ describe('TaskManager', () => {
1495
1495
  interactionId: taskId,
1496
1496
  participantId: 'new-participant-123',
1497
1497
  participantType: 'agent',
1498
+ interaction: {
1499
+ participants: {
1500
+ [agentId]: { pType: 'Agent', hasLeft: false },
1501
+ 'new-participant-123': { pType: 'Agent', hasLeft: false },
1502
+ },
1503
+ media: {
1504
+ [taskId]: {
1505
+ mType: 'mainCall',
1506
+ participants: [agentId, 'new-participant-123'],
1507
+ },
1508
+ },
1509
+ },
1498
1510
  },
1499
1511
  };
1500
1512
 
@@ -1881,6 +1893,217 @@ describe('TaskManager', () => {
1881
1893
  expect(otherTask.data.isConferencing).toBeUndefined();
1882
1894
  expect(otherTask.emit).not.toHaveBeenCalled();
1883
1895
  });
1884
- });
1896
+ });
1897
+
1898
+ describe('CONTACT_MERGED event handling', () => {
1899
+ let task;
1900
+ let taskEmitSpy;
1901
+ let managerEmitSpy;
1902
+
1903
+ beforeEach(() => {
1904
+ // Create initial task
1905
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1906
+ task = taskManager.getTask(taskId);
1907
+ taskEmitSpy = jest.spyOn(task, 'emit');
1908
+ managerEmitSpy = jest.spyOn(taskManager, 'emit');
1909
+ });
1910
+
1911
+ it('should update existing task data and emit TASK_MERGED event when CONTACT_MERGED is received', () => {
1912
+ const mergedPayload = {
1913
+ data: {
1914
+ type: CC_EVENTS.CONTACT_MERGED,
1915
+ interactionId: taskId,
1916
+ agentId: taskDataMock.agentId,
1917
+ interaction: {
1918
+ ...taskDataMock.interaction,
1919
+ state: 'merged',
1920
+ customField: 'updated-value',
1921
+ },
1922
+ },
1923
+ };
1924
+
1925
+ webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
1926
+
1927
+ const updatedTask = taskManager.getTask(taskId);
1928
+ expect(updatedTask).toBeDefined();
1929
+ expect(updatedTask.data.interaction.customField).toBe('updated-value');
1930
+ expect(updatedTask.data.interaction.state).toBe('merged');
1931
+ expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, updatedTask);
1932
+ });
1933
+
1934
+ it('should create new task when CONTACT_MERGED is received for non-existing task', () => {
1935
+ const newMergedTaskId = 'new-merged-task-id';
1936
+ const mergedPayload = {
1937
+ data: {
1938
+ type: CC_EVENTS.CONTACT_MERGED,
1939
+ interactionId: newMergedTaskId,
1940
+ agentId: taskDataMock.agentId,
1941
+ interaction: {
1942
+ mediaType: 'telephony',
1943
+ state: 'merged',
1944
+ participants: {
1945
+ [taskDataMock.agentId]: {
1946
+ isWrapUp: false,
1947
+ hasJoined: true,
1948
+ },
1949
+ },
1950
+ },
1951
+ },
1952
+ };
1953
+
1954
+ // Verify task doesn't exist before
1955
+ expect(taskManager.getTask(newMergedTaskId)).toBeUndefined();
1956
+
1957
+ webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
1958
+
1959
+ // Verify task was created
1960
+ const newTask = taskManager.getTask(newMergedTaskId);
1961
+ expect(newTask).toBeDefined();
1962
+ expect(newTask.data.interactionId).toBe(newMergedTaskId);
1963
+ expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, newTask);
1964
+ });
1965
+
1966
+ it('should remove child task when childInteractionId is present in CONTACT_MERGED', () => {
1967
+ const childTaskId = 'child-task-id';
1968
+ const parentTaskId = 'parent-task-id';
1969
+
1970
+ // Create child task
1971
+ const childPayload = {
1972
+ data: {
1973
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
1974
+ interactionId: childTaskId,
1975
+ agentId: taskDataMock.agentId,
1976
+ interaction: {mediaType: 'telephony'},
1977
+ },
1978
+ };
1979
+ webSocketManagerMock.emit('message', JSON.stringify(childPayload));
1980
+
1981
+ // Verify child task exists
1982
+ expect(taskManager.getTask(childTaskId)).toBeDefined();
1983
+
1984
+ // Create parent task
1985
+ const parentPayload = {
1986
+ data: {
1987
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
1988
+ interactionId: parentTaskId,
1989
+ agentId: taskDataMock.agentId,
1990
+ interaction: {mediaType: 'telephony'},
1991
+ },
1992
+ };
1993
+ webSocketManagerMock.emit('message', JSON.stringify(parentPayload));
1994
+
1995
+ // Send CONTACT_MERGED with childInteractionId
1996
+ const mergedPayload = {
1997
+ data: {
1998
+ type: CC_EVENTS.CONTACT_MERGED,
1999
+ interactionId: parentTaskId,
2000
+ childInteractionId: childTaskId,
2001
+ agentId: taskDataMock.agentId,
2002
+ interaction: {
2003
+ mediaType: 'telephony',
2004
+ state: 'merged',
2005
+ },
2006
+ },
2007
+ };
2008
+
2009
+ webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
2010
+
2011
+ // Verify child task was removed
2012
+ expect(taskManager.getTask(childTaskId)).toBeUndefined();
2013
+
2014
+ // Verify parent task still exists
2015
+ expect(taskManager.getTask(parentTaskId)).toBeDefined();
2016
+
2017
+ // Verify TASK_MERGED event was emitted
2018
+ expect(managerEmitSpy).toHaveBeenCalledWith(
2019
+ TASK_EVENTS.TASK_MERGED,
2020
+ expect.objectContaining({
2021
+ data: expect.objectContaining({
2022
+ interactionId: parentTaskId,
2023
+ }),
2024
+ })
2025
+ );
2026
+ });
2027
+
2028
+ it('should handle CONTACT_MERGED with EP-DN participant correctly', () => {
2029
+ const epdnTaskId = 'epdn-merged-task';
2030
+ const mergedPayload = {
2031
+ data: {
2032
+ type: CC_EVENTS.CONTACT_MERGED,
2033
+ interactionId: epdnTaskId,
2034
+ agentId: taskDataMock.agentId,
2035
+ interaction: {
2036
+ mediaType: 'telephony',
2037
+ state: 'merged',
2038
+ participants: {
2039
+ [taskDataMock.agentId]: {
2040
+ type: 'Agent',
2041
+ isWrapUp: false,
2042
+ hasJoined: true,
2043
+ },
2044
+ 'epdn-participant': {
2045
+ type: 'EpDn',
2046
+ epId: 'entry-point-123',
2047
+ isWrapUp: false,
2048
+ },
2049
+ },
2050
+ },
2051
+ },
2052
+ };
2053
+
2054
+ webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
2055
+
2056
+ const mergedTask = taskManager.getTask(epdnTaskId);
2057
+ expect(mergedTask).toBeDefined();
2058
+ expect(mergedTask.data.interaction.participants['epdn-participant']).toBeDefined();
2059
+ expect(mergedTask.data.interaction.participants['epdn-participant'].type).toBe('EpDn');
2060
+ expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, mergedTask);
2061
+ });
2062
+
2063
+ it('should not affect other tasks when CONTACT_MERGED is received', () => {
2064
+ const otherTaskId = 'other-unrelated-task';
2065
+ const otherPayload = {
2066
+ data: {
2067
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
2068
+ interactionId: otherTaskId,
2069
+ agentId: taskDataMock.agentId,
2070
+ interaction: {mediaType: 'chat'},
2071
+ },
2072
+ };
2073
+ webSocketManagerMock.emit('message', JSON.stringify(otherPayload));
2074
+
2075
+ const otherTask = taskManager.getTask(otherTaskId);
2076
+ const otherTaskEmitSpy = jest.spyOn(otherTask, 'emit');
2077
+
2078
+ // Send CONTACT_MERGED for the original task
2079
+ const mergedPayload = {
2080
+ data: {
2081
+ type: CC_EVENTS.CONTACT_MERGED,
2082
+ interactionId: taskId,
2083
+ agentId: taskDataMock.agentId,
2084
+ interaction: {
2085
+ mediaType: 'telephony',
2086
+ state: 'merged',
2087
+ },
2088
+ },
2089
+ };
2090
+
2091
+ webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
2092
+
2093
+ // Verify other task was not affected
2094
+ expect(otherTaskEmitSpy).not.toHaveBeenCalled();
2095
+ expect(otherTask.data.interaction.mediaType).toBe('chat');
2096
+
2097
+ // Verify original task was updated
2098
+ expect(managerEmitSpy).toHaveBeenCalledWith(
2099
+ TASK_EVENTS.TASK_MERGED,
2100
+ expect.objectContaining({
2101
+ data: expect.objectContaining({
2102
+ interactionId: taskId,
2103
+ }),
2104
+ })
2105
+ );
2106
+ });
2107
+ });
1885
2108
  });
1886
2109
 
@@ -98,34 +98,34 @@ describe('TaskUtils', () => {
98
98
  });
99
99
 
100
100
  it('should return true when there are 2 or more active agents', () => {
101
- expect(getIsConferenceInProgress(mockTask)).toBe(true);
101
+ expect(getIsConferenceInProgress(mockTask.data)).toBe(true);
102
102
  });
103
103
 
104
104
  it('should return false when there is only 1 active agent', () => {
105
105
  mockTask.data.interaction.participants[mockOtherAgentId].hasLeft = true;
106
- expect(getIsConferenceInProgress(mockTask)).toBe(false);
106
+ expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
107
107
  });
108
108
 
109
109
  it('should exclude customers from agent count', () => {
110
110
  // Remove one agent, should still be false with only 1 agent + customer
111
111
  delete mockTask.data.interaction.participants[mockOtherAgentId];
112
112
  mockTask.data.interaction.media[mockTask.data.interactionId].participants = [mockAgentId, 'customer-123'];
113
- expect(getIsConferenceInProgress(mockTask)).toBe(false);
113
+ expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
114
114
  });
115
115
 
116
116
  it('should exclude supervisors from agent count', () => {
117
117
  mockTask.data.interaction.participants[mockOtherAgentId].pType = 'Supervisor';
118
- expect(getIsConferenceInProgress(mockTask)).toBe(false);
118
+ expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
119
119
  });
120
120
 
121
121
  it('should exclude VVA from agent count', () => {
122
122
  mockTask.data.interaction.participants[mockOtherAgentId].pType = 'VVA';
123
- expect(getIsConferenceInProgress(mockTask)).toBe(false);
123
+ expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
124
124
  });
125
125
 
126
126
  it('should return false when no main call media exists', () => {
127
127
  mockTask.data.interaction.media = {};
128
- expect(getIsConferenceInProgress(mockTask)).toBe(false);
128
+ expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
129
129
  });
130
130
  });
131
131
  });