@servicetitan/titan-chat-ui 3.0.1 → 3.1.1
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.
- package/CHANGELOG.md +12 -0
- package/dist/components/chat/__tests-cy__/chat-error.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-error.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-error.test.js +6 -0
- package/dist/components/chat/__tests-cy__/chat-error.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-input-file.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-input-file.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-input-file.test.js +6 -0
- package/dist/components/chat/__tests-cy__/chat-input-file.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-input.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-input.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-input.test.js +6 -0
- package/dist/components/chat/__tests-cy__/chat-input.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-log.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-log.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-log.test.js +6 -0
- package/dist/components/chat/__tests-cy__/chat-log.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-messages.test.js +2 -91
- package/dist/components/chat/__tests-cy__/chat-messages.test.js.map +1 -1
- package/dist/components/chat/__tests-cy__/chat-notifications.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-notifications.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-notifications.test.js +6 -0
- package/dist/components/chat/__tests-cy__/chat-notifications.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-timer.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-timer.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-timer.test.js +6 -0
- package/dist/components/chat/__tests-cy__/chat-timer.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat.test.js +3 -123
- package/dist/components/chat/__tests-cy__/chat.test.js.map +1 -1
- package/dist/components/chat/chat-error.d.ts +3 -1
- package/dist/components/chat/chat-error.d.ts.map +1 -1
- package/dist/components/chat/chat-error.js +2 -3
- package/dist/components/chat/chat-error.js.map +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-input.js +2 -1
- package/dist/components/chat/chat-input.js.map +1 -1
- package/dist/components/chat/chat-notifications.js +1 -1
- package/dist/components/chat/chat-notifications.js.map +1 -1
- package/dist/components/message-content/__tests-cy__/message-content-file.test.d.ts +2 -0
- package/dist/components/message-content/__tests-cy__/message-content-file.test.d.ts.map +1 -0
- package/dist/components/message-content/__tests-cy__/message-content-file.test.js +6 -0
- package/dist/components/message-content/__tests-cy__/message-content-file.test.js.map +1 -0
- package/dist/components/messages/__tests-cy__/message-agent.test.js +7 -72
- package/dist/components/messages/__tests-cy__/message-agent.test.js.map +1 -1
- package/dist/components/messages/__tests-cy__/message-system.test.js +5 -14
- package/dist/components/messages/__tests-cy__/message-system.test.js.map +1 -1
- package/dist/components/messages/__tests-cy__/message-timeout.test.js +2 -21
- package/dist/components/messages/__tests-cy__/message-timeout.test.js.map +1 -1
- package/dist/components/messages/__tests-cy__/message-typing.test.js +3 -45
- package/dist/components/messages/__tests-cy__/message-typing.test.js.map +1 -1
- package/dist/components/messages/__tests-cy__/message-user.test.js +3 -23
- package/dist/components/messages/__tests-cy__/message-user.test.js.map +1 -1
- package/package.json +4 -4
- package/src/components/chat/__tests-cy__/chat-error.test.tsx +6 -0
- package/src/components/chat/__tests-cy__/chat-input-file.test.tsx +6 -0
- package/src/components/chat/__tests-cy__/chat-input.test.tsx +6 -0
- package/src/components/chat/__tests-cy__/chat-log.test.tsx +6 -0
- package/src/components/chat/__tests-cy__/chat-messages.test.tsx +2 -107
- package/src/components/chat/__tests-cy__/chat-notifications.test.tsx +6 -0
- package/src/components/chat/__tests-cy__/chat-timer.test.tsx +6 -0
- package/src/components/chat/__tests-cy__/chat.test.tsx +3 -156
- package/src/components/chat/chat-error.tsx +2 -3
- package/src/components/chat/chat-input.tsx +25 -21
- package/src/components/chat/chat-notifications.tsx +1 -1
- package/src/components/message-content/__tests-cy__/message-content-file.test.tsx +6 -0
- package/src/components/messages/__tests-cy__/message-agent.test.tsx +7 -129
- package/src/components/messages/__tests-cy__/message-system.test.tsx +5 -27
- package/src/components/messages/__tests-cy__/message-timeout.test.tsx +2 -25
- package/src/components/messages/__tests-cy__/message-typing.test.tsx +3 -54
- package/src/components/messages/__tests-cy__/message-user.test.tsx +3 -37
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/components/chat/chat-error.module.less +0 -6
- package/src/components/chat/chat-error.module.less +0 -6
- package/src/components/chat/chat-error.module.less.d.ts +0 -3
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
1
|
import { BodyText, Stack } from '@servicetitan/design-system';
|
|
3
|
-
import {
|
|
4
|
-
import { mount } from 'cypress/react';
|
|
2
|
+
import { runMessageSystemSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
5
3
|
import { MessageSystem } from '../message-system';
|
|
6
|
-
describe('
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
it('should be properly rendered', () => {
|
|
11
|
-
mount(_jsx(MessageSystem, { className: "custom-class", children: _jsx(Stack, { className: "border", children: _jsx(BodyText, { "data-cy": "content", children: "message system content" }) }) }));
|
|
12
|
-
ChatUiSelectors.chatMessageSystem.should('have.class', 'custom-class').should('be.visible');
|
|
13
|
-
});
|
|
14
|
-
it('should be properly rendered fullwidth', () => {
|
|
15
|
-
mount(_jsx(MessageSystem, { className: "custom-class", fullWidth: true, children: _jsx(Stack, { className: "border", children: _jsx(BodyText, { "data-cy": "content", children: "message system content" }) }) }));
|
|
16
|
-
ChatUiSelectors.chatMessageSystem.should('have.class', 'custom-class').should('be.visible');
|
|
4
|
+
describe('MessageSystem', () => {
|
|
5
|
+
runMessageSystemSharedTests(MessageSystem, {
|
|
6
|
+
TextComponent: BodyText,
|
|
7
|
+
ContainerComponent: Stack,
|
|
17
8
|
});
|
|
18
9
|
});
|
|
19
10
|
//# sourceMappingURL=message-system.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-system.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-system.test.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-system.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-system.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC3B,2BAA2B,CAAC,aAAa,EAAE;QACvC,aAAa,EAAE,QAAQ;QACvB,kBAAkB,EAAE,KAAK;KAC5B,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ChatUiSelectors } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
3
|
-
import { mount } from 'cypress/react';
|
|
1
|
+
import { runMessageTimeoutSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
4
2
|
import { MessageTimeout } from '../message-timeout';
|
|
5
3
|
describe('MessageTimeout', () => {
|
|
6
|
-
|
|
7
|
-
const onResume = cy.spy().as('onResume');
|
|
8
|
-
const onReset = cy.spy().as('onReset');
|
|
9
|
-
mount(_jsx(MessageTimeout, { onResume: onResume, onReset: onReset }));
|
|
10
|
-
ChatUiSelectors.chatMessageTimeout
|
|
11
|
-
.should('be.visible')
|
|
12
|
-
.should('contain.text', [
|
|
13
|
-
'Your session has timed out.',
|
|
14
|
-
'Would you like to resume it or start a new one?',
|
|
15
|
-
'Continue session or Start new session',
|
|
16
|
-
].join(''));
|
|
17
|
-
ChatUiSelectors.chatMessageTimeoutResume.should('be.visible');
|
|
18
|
-
ChatUiSelectors.chatMessageTimeoutReset.should('be.visible');
|
|
19
|
-
ChatUiSelectors.chatMessageTimeoutResume.click();
|
|
20
|
-
cy.get('@onResume').should('have.been.calledOnce');
|
|
21
|
-
ChatUiSelectors.chatMessageTimeoutReset.click();
|
|
22
|
-
cy.get('@onReset').should('have.been.calledOnce');
|
|
23
|
-
});
|
|
4
|
+
runMessageTimeoutSharedTests(MessageTimeout);
|
|
24
5
|
});
|
|
25
6
|
//# sourceMappingURL=message-timeout.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-timeout.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-timeout.test.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-timeout.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-timeout.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC5B,4BAA4B,CAAC,cAAc,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC"}
|
|
@@ -1,48 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ChatParticipantIcon } from '@servicetitan/titan-chat-ui-common';
|
|
3
|
-
import { ChatUiSelectors } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
4
|
-
import { mount } from 'cypress/react';
|
|
1
|
+
import { runMessageTypingSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
5
2
|
import { MessageTyping } from '../message-typing';
|
|
6
|
-
describe('
|
|
7
|
-
|
|
8
|
-
mount(_jsx(MessageTyping, { avatar: {
|
|
9
|
-
name: 'Test User Name',
|
|
10
|
-
icon,
|
|
11
|
-
className: 'custom-class',
|
|
12
|
-
} }));
|
|
13
|
-
ChatUiSelectors.chatMessageTyping.should('be.visible').children().should('have.length', 2);
|
|
14
|
-
ChatUiSelectors.chatMessageTypingDots.should('be.visible');
|
|
15
|
-
}
|
|
16
|
-
it('should render message with bot icon', () => {
|
|
17
|
-
render(ChatParticipantIcon.Bot);
|
|
18
|
-
ChatUiSelectors.chatAvatarBot
|
|
19
|
-
.should('be.visible')
|
|
20
|
-
.should('have.class', 'custom-class')
|
|
21
|
-
.invoke('css', 'background-image')
|
|
22
|
-
.then(bgColor => {
|
|
23
|
-
const isSvg = Boolean(bgColor.indexOf('data:image/svg+xml;base64') >= 0);
|
|
24
|
-
expect(isSvg).to.eq(true);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
it('should render message with empty icon', () => {
|
|
28
|
-
render(ChatParticipantIcon.Empty);
|
|
29
|
-
ChatUiSelectors.chatAvatarEmpty.should('exist').should('not.be.visible');
|
|
30
|
-
});
|
|
31
|
-
it('should render message with initials', () => {
|
|
32
|
-
render(ChatParticipantIcon.Initials);
|
|
33
|
-
ChatUiSelectors.chatAvatarInitials.should('be.visible').should('contain.text', 'T');
|
|
34
|
-
});
|
|
35
|
-
it('should not cancel the dots animation', () => {
|
|
36
|
-
cy.clock();
|
|
37
|
-
render(ChatParticipantIcon.Initials);
|
|
38
|
-
// Verify the rendered component + check the dots animation doesn't change over the time
|
|
39
|
-
ChatUiSelectors.chatMessageTypingDots.should('be.visible');
|
|
40
|
-
cy.tick(10000);
|
|
41
|
-
ChatUiSelectors.chatMessageTypingDots.should('be.visible');
|
|
42
|
-
cy.tick(20000);
|
|
43
|
-
ChatUiSelectors.chatMessageTypingDots.should('be.visible');
|
|
44
|
-
cy.tick(30000);
|
|
45
|
-
ChatUiSelectors.chatMessageTypingDots.should('be.visible');
|
|
46
|
-
});
|
|
3
|
+
describe('MessageTyping', () => {
|
|
4
|
+
runMessageTypingSharedTests(MessageTyping);
|
|
47
5
|
});
|
|
48
6
|
//# sourceMappingURL=message-typing.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-typing.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-typing.test.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-typing.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-typing.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC3B,2BAA2B,CAAC,aAAa,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}
|
|
@@ -1,27 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
1
|
import { BodyText } from '@servicetitan/design-system';
|
|
3
|
-
import {
|
|
4
|
-
import { mount } from 'cypress/react';
|
|
2
|
+
import { runMessageUserSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
5
3
|
import { MessageUser } from '../message-user';
|
|
6
|
-
describe('
|
|
7
|
-
|
|
8
|
-
cy.viewport('macbook-13');
|
|
9
|
-
});
|
|
10
|
-
it('should be properly rendered', () => {
|
|
11
|
-
mount(_jsx(MessageUser, { children: _jsx(BodyText, { "data-cy": "content", children: "message user content" }) }));
|
|
12
|
-
ChatUiSelectors.chatMessageUser.should('be.visible');
|
|
13
|
-
ChatUiSelectors.chatMessageContent
|
|
14
|
-
.should('be.visible')
|
|
15
|
-
.should('contain.text', 'message user content');
|
|
16
|
-
});
|
|
17
|
-
it('should be properly rendered with long text', () => {
|
|
18
|
-
const longText = 'message user content '.repeat(100).trim();
|
|
19
|
-
mount(_jsx(MessageUser, { children: _jsx(BodyText, { "data-cy": "content", children: longText }) }));
|
|
20
|
-
ChatUiSelectors.chatMessageContent.should('be.visible').should('contain.text', longText);
|
|
21
|
-
});
|
|
22
|
-
it('should be rendered with footer', () => {
|
|
23
|
-
mount(_jsx(MessageUser, { messageFooter: _jsx(BodyText, { children: "message user footer" }), children: _jsx(BodyText, { "data-cy": "content", children: "message user content" }) }));
|
|
24
|
-
ChatUiSelectors.chatMessageFooter.should('be.visible');
|
|
25
|
-
});
|
|
4
|
+
describe('MessageUser', () => {
|
|
5
|
+
runMessageUserSharedTests(MessageUser, BodyText);
|
|
26
6
|
});
|
|
27
7
|
//# sourceMappingURL=message-user.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-user.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-user.test.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-user.test.js","sourceRoot":"","sources":["../../../../src/components/messages/__tests-cy__/message-user.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IACzB,yBAAyB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/titan-chat-ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "Chat experience UI package",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"push:local": "yalc push"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@servicetitan/titan-chat-ui-common": "^3.
|
|
20
|
+
"@servicetitan/titan-chat-ui-common": "^3.1.1",
|
|
21
21
|
"lodash": "4.17.21",
|
|
22
22
|
"nanoid": "^5.1.5"
|
|
23
23
|
},
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"react-dom": "^18"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@servicetitan/titan-chatbot-ui-cypress": "^3.
|
|
43
|
+
"@servicetitan/titan-chatbot-ui-cypress": "^3.1.1",
|
|
44
44
|
"cypress": "^14.3.2"
|
|
45
45
|
},
|
|
46
46
|
"keywords": [
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
"cli": {
|
|
54
54
|
"webpack": false
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "83c89de5b42d24ce5d7fcd034810bf596a673a08"
|
|
57
57
|
}
|
|
@@ -1,111 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CHAT_UI_STORE_TOKEN, mockChatMessageModelText } from '@servicetitan/titan-chat-ui-common';
|
|
3
|
-
import { ChatUiSelectors, CypressMocks } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
4
|
-
import { mount } from 'cypress/react';
|
|
1
|
+
import { runChatMessagesSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
5
2
|
import { ChatMessages } from '../chat-messages';
|
|
6
3
|
|
|
7
4
|
describe('[ChatMessages]', () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
cy.viewport(780, 600);
|
|
12
|
-
cy.clock(new Date('2023-10-01T10:10:00Z').getTime());
|
|
13
|
-
storeMock = new CypressMocks.ChatUiStoreMock();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const render = () => {
|
|
17
|
-
return mount(
|
|
18
|
-
<Provider
|
|
19
|
-
singletons={[
|
|
20
|
-
{
|
|
21
|
-
provide: CHAT_UI_STORE_TOKEN,
|
|
22
|
-
useValue: storeMock,
|
|
23
|
-
},
|
|
24
|
-
]}
|
|
25
|
-
>
|
|
26
|
-
<ChatMessages messages={storeMock.messages} />
|
|
27
|
-
</Provider>
|
|
28
|
-
);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
it('should render default chat', () => {
|
|
32
|
-
render();
|
|
33
|
-
|
|
34
|
-
ChatUiSelectors.chatMessages.should('be.visible');
|
|
35
|
-
ChatUiSelectors.chatMessage.should('have.length', 2);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should render several consecutive agent messages without extra avatars', () => {
|
|
39
|
-
storeMock.messages = [
|
|
40
|
-
mockChatMessageModelText(true, {
|
|
41
|
-
id: 'id1',
|
|
42
|
-
timestamp: new Date('2023-01-01T10:10:00Z'),
|
|
43
|
-
message: 'Hello, this is the first message',
|
|
44
|
-
}),
|
|
45
|
-
mockChatMessageModelText(true, {
|
|
46
|
-
id: 'id2',
|
|
47
|
-
message: 'Hello, this is the second message. '.repeat(5).trim(),
|
|
48
|
-
timestamp: new Date('2023-01-01T10:10:59.999Z'),
|
|
49
|
-
}),
|
|
50
|
-
mockChatMessageModelText(true, {
|
|
51
|
-
id: 'id3',
|
|
52
|
-
message: 'Hello, this is the third message',
|
|
53
|
-
timestamp: new Date('2023-01-01T10:11:00Z'),
|
|
54
|
-
}),
|
|
55
|
-
mockChatMessageModelText(true, {
|
|
56
|
-
id: 'id4',
|
|
57
|
-
message: 'Hello, this is the forth message',
|
|
58
|
-
timestamp: new Date('2023-01-01T10:11:01Z'),
|
|
59
|
-
}),
|
|
60
|
-
mockChatMessageModelText(false, {
|
|
61
|
-
id: 'id11',
|
|
62
|
-
timestamp: new Date('2023-01-01T11:10:00Z'),
|
|
63
|
-
message: 'Hello, this is the first message',
|
|
64
|
-
}),
|
|
65
|
-
mockChatMessageModelText(false, {
|
|
66
|
-
id: 'id22',
|
|
67
|
-
message: 'Hello, this is the second message',
|
|
68
|
-
timestamp: new Date('2023-01-01T11:11:00Z'),
|
|
69
|
-
}),
|
|
70
|
-
mockChatMessageModelText(false, {
|
|
71
|
-
id: 'id33',
|
|
72
|
-
message: 'Hello, this is the third message',
|
|
73
|
-
timestamp: new Date('2023-01-01T11:12:00Z'),
|
|
74
|
-
}),
|
|
75
|
-
mockChatMessageModelText(false, {
|
|
76
|
-
id: 'id44',
|
|
77
|
-
message: 'Hello, this is the forth message',
|
|
78
|
-
timestamp: new Date('2023-01-01T11:12:01Z'),
|
|
79
|
-
}),
|
|
80
|
-
];
|
|
81
|
-
render();
|
|
82
|
-
|
|
83
|
-
const getTimestamp = (i: number) =>
|
|
84
|
-
ChatUiSelectors.chatMessage
|
|
85
|
-
.eq(i)
|
|
86
|
-
.find(`[data-cy="${ChatUiSelectors.cy.chatMessageFooter}"]`);
|
|
87
|
-
|
|
88
|
-
ChatUiSelectors.chatMessageAgent.should('have.length', 4);
|
|
89
|
-
ChatUiSelectors.chatMessageUser.should('have.length', 4);
|
|
90
|
-
|
|
91
|
-
// Agent avatar should be visible only for the first message in group
|
|
92
|
-
const getAvatar = (i: number) =>
|
|
93
|
-
ChatUiSelectors.chatMessageAgent
|
|
94
|
-
.find(`[data-cy="${ChatUiSelectors.cy.chatAvatar}"]`)
|
|
95
|
-
.eq(i);
|
|
96
|
-
getAvatar(0).should('be.visible');
|
|
97
|
-
getAvatar(1).should('not.exist');
|
|
98
|
-
getAvatar(2).should('not.exist');
|
|
99
|
-
getAvatar(3).should('not.exist');
|
|
100
|
-
|
|
101
|
-
// Footer with date should be visible only for the different formatted timestamps
|
|
102
|
-
getTimestamp(0).should('not.exist');
|
|
103
|
-
getTimestamp(1).should('be.visible').should('contain.text', 'agent • 10:10 AM');
|
|
104
|
-
getTimestamp(2).should('not.exist');
|
|
105
|
-
getTimestamp(3).should('be.visible').should('contain.text', 'agent • 10:11 AM');
|
|
106
|
-
getTimestamp(4).should('be.visible').should('contain.text', '11:10 AM');
|
|
107
|
-
getTimestamp(5).should('be.visible').should('contain.text', '11:11 AM');
|
|
108
|
-
getTimestamp(6).should('not.exist');
|
|
109
|
-
getTimestamp(7).should('be.visible').should('contain.text', '11:12 AM');
|
|
110
|
-
});
|
|
5
|
+
runChatMessagesSharedTests(ChatMessages);
|
|
111
6
|
});
|
|
@@ -1,159 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
CHAT_UI_BACKEND_STORE_TOKEN,
|
|
4
|
-
CHAT_UI_STORE_TOKEN,
|
|
5
|
-
ChatParticipantIcon,
|
|
6
|
-
ChatUiBackendEchoStore,
|
|
7
|
-
ChatUiStore,
|
|
8
|
-
IChatUiBackendStore,
|
|
9
|
-
IChatUiStore,
|
|
10
|
-
} from '@servicetitan/titan-chat-ui-common';
|
|
11
|
-
import { ChatUiSelectors } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
12
|
-
import { mount } from 'cypress/react';
|
|
13
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { runChatSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
|
|
14
2
|
import { Chat } from '../chat';
|
|
15
3
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const container = new Container();
|
|
19
|
-
container.parent = rootContainer;
|
|
20
|
-
container.bind<IChatUiStore>(CHAT_UI_STORE_TOKEN).to(ChatUiStore).inSingletonScope();
|
|
21
|
-
container
|
|
22
|
-
.bind<IChatUiBackendStore>(CHAT_UI_BACKEND_STORE_TOKEN)
|
|
23
|
-
.to(ChatUiBackendEchoStore)
|
|
24
|
-
.inSingletonScope();
|
|
25
|
-
return container;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
describe('[Chat]', () => {
|
|
29
|
-
let container: Container;
|
|
30
|
-
let chatUiStore: IChatUiStore;
|
|
31
|
-
let chatUiBackendStore: ChatUiBackendEchoStore;
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
container = initContainer();
|
|
35
|
-
chatUiStore = container.get<IChatUiStore>(CHAT_UI_STORE_TOKEN);
|
|
36
|
-
chatUiBackendStore = container.get<ChatUiBackendEchoStore>(CHAT_UI_BACKEND_STORE_TOKEN);
|
|
37
|
-
cy.viewport(780, 800);
|
|
38
|
-
cy.clock(Date.parse('2023-10-01T00:00:00Z'));
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const render = () => {
|
|
42
|
-
const ChatWrapper = provide({
|
|
43
|
-
singletons: [
|
|
44
|
-
{
|
|
45
|
-
provide: CHAT_UI_STORE_TOKEN,
|
|
46
|
-
useValue: chatUiStore,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
provide: CHAT_UI_BACKEND_STORE_TOKEN,
|
|
50
|
-
useValue: chatUiBackendStore,
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
})(() => {
|
|
54
|
-
const [chatUiStore, chatUiBackendStore] = useDependencies(
|
|
55
|
-
CHAT_UI_STORE_TOKEN,
|
|
56
|
-
CHAT_UI_BACKEND_STORE_TOKEN
|
|
57
|
-
);
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
const init = async () => {
|
|
60
|
-
chatUiBackendStore.subscribe();
|
|
61
|
-
await chatUiStore.run({
|
|
62
|
-
agentName: 'EchoBot',
|
|
63
|
-
agentIcon: ChatParticipantIcon.Bot,
|
|
64
|
-
});
|
|
65
|
-
};
|
|
66
|
-
init().then(() => {});
|
|
67
|
-
return () => chatUiBackendStore.unsubscribe();
|
|
68
|
-
}, [chatUiStore, chatUiBackendStore]);
|
|
69
|
-
return <Chat className="h-100vh max-h-100vh" />;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
cy.spy(chatUiStore, 'run').as('runSpy');
|
|
73
|
-
mount(<ChatWrapper />);
|
|
74
|
-
|
|
75
|
-
ChatUiSelectors.chatConnecting.should('be.visible');
|
|
76
|
-
cy.tick(1000);
|
|
77
|
-
return cy.wrap(
|
|
78
|
-
new Promise(resolve => {
|
|
79
|
-
cy.get('@runSpy')
|
|
80
|
-
.should('have.been.calledOnce')
|
|
81
|
-
.then((invocation: any) => {
|
|
82
|
-
const initPromise = invocation.firstCall.returnValue as ReturnType<
|
|
83
|
-
IChatUiStore['run']
|
|
84
|
-
>;
|
|
85
|
-
initPromise.then(resolve);
|
|
86
|
-
});
|
|
87
|
-
})
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const ask = (message: string) => {
|
|
92
|
-
ChatUiSelectors.chatInput.type(`${message}{enter}`);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
it('should render default chat', () => {
|
|
96
|
-
render().then(() => {
|
|
97
|
-
ChatUiSelectors.chatMessages.should('be.visible');
|
|
98
|
-
ChatUiSelectors.chatMessageAgent.should('have.length', 1).should('be.visible');
|
|
99
|
-
ChatUiSelectors.chatMessageContentAgent
|
|
100
|
-
.should('be.visible')
|
|
101
|
-
.should(
|
|
102
|
-
'contain.text',
|
|
103
|
-
"Hello! I'm generic echo bot. I can echo your messages. Try it out!"
|
|
104
|
-
);
|
|
105
|
-
ChatUiSelectors.chatNotifications.should('exist');
|
|
106
|
-
ChatUiSelectors.chatSend.should('be.visible').should('be.disabled');
|
|
107
|
-
ChatUiSelectors.chatInput.should('be.visible').should('not.be.disabled');
|
|
108
|
-
|
|
109
|
-
ChatUiSelectors.chatInput.type('Hello');
|
|
110
|
-
ChatUiSelectors.chatSend.click();
|
|
111
|
-
|
|
112
|
-
ChatUiSelectors.chatMessageUser
|
|
113
|
-
.should('be.visible')
|
|
114
|
-
.should('have.length', 1)
|
|
115
|
-
.should('contain.text', 'Hello');
|
|
116
|
-
ChatUiSelectors.chatMessageTyping.should('be.visible');
|
|
117
|
-
ChatUiSelectors.chatMessageAgent.should('have.length', 1);
|
|
118
|
-
|
|
119
|
-
cy.tick(1000);
|
|
120
|
-
|
|
121
|
-
ChatUiSelectors.chatMessageTyping.should('not.exist');
|
|
122
|
-
ChatUiSelectors.chatMessageAgent.should('have.length', 2);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should render chat error message', () => {
|
|
127
|
-
render().then(() => {
|
|
128
|
-
chatUiStore.setTimer({ secondsTotal: 100, secondsLeft: 10 });
|
|
129
|
-
chatUiStore.setError('error message', {
|
|
130
|
-
title: 'Custom Error',
|
|
131
|
-
recoverStrategy: {
|
|
132
|
-
recoverButtonTitle: 'Recover button title',
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
ChatUiSelectors.chatTimer.should('not.exist');
|
|
137
|
-
ChatUiSelectors.chatError.should('be.visible');
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('should handle send message error and retry', () => {
|
|
142
|
-
render().then(() => {
|
|
143
|
-
ask('[Error]Custom error message');
|
|
144
|
-
cy.tick(1000);
|
|
145
|
-
|
|
146
|
-
// Check error message
|
|
147
|
-
ChatUiSelectors.chatMessageError
|
|
148
|
-
.should('be.visible')
|
|
149
|
-
.should('contain.text', 'Message not delivered. Retry');
|
|
150
|
-
ChatUiSelectors.chatError
|
|
151
|
-
.should('be.visible')
|
|
152
|
-
.should('contain.text', ['Custom Error Title', 'Custom error message'].join(''));
|
|
153
|
-
|
|
154
|
-
// Retry message
|
|
155
|
-
ChatUiSelectors.chatMessageErrorRetry.should('be.visible').click();
|
|
156
|
-
cy.tick(1000);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
4
|
+
describe('Chat', () => {
|
|
5
|
+
runChatSharedTests(Chat);
|
|
159
6
|
});
|
|
@@ -4,9 +4,8 @@ import { CHAT_UI_STORE_TOKEN } from '@servicetitan/titan-chat-ui-common';
|
|
|
4
4
|
import { observer } from 'mobx-react';
|
|
5
5
|
import { FC, useCallback } from 'react';
|
|
6
6
|
import { MultilineText } from '../common/multiline-text';
|
|
7
|
-
import * as Styles from './chat-error.module.less';
|
|
8
7
|
|
|
9
|
-
export const ChatError: FC = observer(() => {
|
|
8
|
+
export const ChatError: FC<{ className?: string }> = observer(({ className }) => {
|
|
10
9
|
const [chatUiStore] = useDependencies(CHAT_UI_STORE_TOKEN);
|
|
11
10
|
const { error } = chatUiStore;
|
|
12
11
|
|
|
@@ -22,7 +21,7 @@ export const ChatError: FC = observer(() => {
|
|
|
22
21
|
status="critical"
|
|
23
22
|
title={error.title}
|
|
24
23
|
icon
|
|
25
|
-
className={
|
|
24
|
+
className={className}
|
|
26
25
|
data-cy="titan-chat-error"
|
|
27
26
|
>
|
|
28
27
|
<MultilineText text={error.message} data-cy="titan-chat-error-text" />
|
|
@@ -3,7 +3,7 @@ import { provide, useDependencies } from '@servicetitan/react-ioc';
|
|
|
3
3
|
import { CHAT_UI_STORE_TOKEN } from '@servicetitan/titan-chat-ui-common';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { observer } from 'mobx-react';
|
|
6
|
-
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
+
import { FC, FormEvent, useCallback, useEffect, useRef, useState } from 'react';
|
|
7
7
|
import { ChatInputStore } from '../../stores/chat-input.store';
|
|
8
8
|
import * as Styles from './chat-input.module.less';
|
|
9
9
|
|
|
@@ -21,26 +21,30 @@ export const ChatInput: FC<{ className?: string }> = provide({
|
|
|
21
21
|
ChatInputStore
|
|
22
22
|
);
|
|
23
23
|
|
|
24
|
-
const handleSendMessage = useCallback(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
24
|
+
const handleSendMessage = useCallback(
|
|
25
|
+
async (event?: FormEvent) => {
|
|
26
|
+
event?.preventDefault();
|
|
27
|
+
const validateResult = await supportChatInputStore.formState.validate();
|
|
28
|
+
if (validateResult.hasError) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const text = supportChatInputStore.formState.$.message.value;
|
|
32
|
+
if (!text.trim() && !chatUiStore.file) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
supportChatInputStore.formState.$.message.onChange('');
|
|
36
|
+
setIsSending(true);
|
|
37
|
+
try {
|
|
38
|
+
await chatUiStore.sendMessageText(text);
|
|
39
|
+
} finally {
|
|
40
|
+
setIsSending(false);
|
|
41
|
+
}
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
textareaRef.current?.focus();
|
|
44
|
+
}, 0);
|
|
45
|
+
},
|
|
46
|
+
[chatUiStore, supportChatInputStore]
|
|
47
|
+
);
|
|
44
48
|
|
|
45
49
|
const clearTimer = useCallback(() => {
|
|
46
50
|
clearTimeout(typingTimeoutRef.current ?? 0);
|
|
@@ -13,7 +13,7 @@ export const ChatNotifications: FC<IChatNotificationsProps> = observer(() => {
|
|
|
13
13
|
return (
|
|
14
14
|
<Stack direction="column" spacing="2" data-cy="titan-chat-notifications">
|
|
15
15
|
{chatUiStore.timer && !chatUiStore.isError && <ChatTimer />}
|
|
16
|
-
{chatUiStore.isError && <ChatError />}
|
|
16
|
+
{chatUiStore.isError && <ChatError className="m-x-3" />}
|
|
17
17
|
</Stack>
|
|
18
18
|
);
|
|
19
19
|
});
|