@kindly/react-chat 2.40.3 → 2.40.5
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/.storybook/main.js +3 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/stories/.eslintrc +11 -0
- package/stories/screens.stories/Chat/FormStates.stories.jsx +407 -0
- package/stories/screens.stories/{Chat.stories.jsx → Chat/index.stories.jsx} +63 -224
- package/stories/screens.stories/ClosedButton.stories.jsx +0 -1
- package/stories/screens.stories/Feedback.stories.jsx +0 -2
- package/stories/screens.stories/Nudge.stories.jsx +0 -1
- package/stories/screens.stories/Options.stories.jsx +12 -14
- package/stories/screens.stories/PushGreeting.stories.jsx +0 -2
- package/stories/screens.stories/StartChat.stories.jsx +0 -2
- package/stories/utils/wait.js +2 -0
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { expect } from '@storybook/jest';
|
|
2
|
-
|
|
3
|
-
/* eslint-disable react/prop-types */
|
|
4
|
-
import { fireEvent, screen, userEvent } from '@storybook/testing-library';
|
|
2
|
+
import { fireEvent, userEvent, waitFor, within } from '@storybook/testing-library';
|
|
5
3
|
import React from 'react';
|
|
6
4
|
import withFetchMock from 'storybook-addon-mock';
|
|
7
5
|
|
|
8
6
|
import { IMAGE_WIDTH } from 'app/constants';
|
|
9
7
|
|
|
10
|
-
import { chromaticViewports } from '
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import settingsJSON from '
|
|
14
|
-
import withContainer from '
|
|
15
|
-
import withMockProvider from '
|
|
8
|
+
import { chromaticViewports } from '../../../.storybook/preview';
|
|
9
|
+
import KindlyChatButton from '../../../src/features/KindlyChatButton/KindlyChatButton';
|
|
10
|
+
import mockMessage from '../../../testing/mockMessage';
|
|
11
|
+
import settingsJSON from '../../assets/settingsJson';
|
|
12
|
+
import withContainer from '../../decorators/withContainer';
|
|
13
|
+
import withMockProvider from '../../decorators/withProvider';
|
|
14
|
+
import wait from '../../utils/wait';
|
|
16
15
|
|
|
17
16
|
const defaultBotSettings = {
|
|
18
17
|
welcomePage: settingsJSON.welcome_page,
|
|
@@ -225,7 +224,11 @@ const MESSAGES = {
|
|
|
225
224
|
};
|
|
226
225
|
MultilineBotMessage.storyName = 'Multiline Bot & User Messages';
|
|
227
226
|
MultilineBotMessage.parameters = {
|
|
228
|
-
...
|
|
227
|
+
...Regular.parameters,
|
|
228
|
+
botSettings: {
|
|
229
|
+
...defaultBotSettings,
|
|
230
|
+
typing_duration: 0,
|
|
231
|
+
},
|
|
229
232
|
initialStateModifier: {
|
|
230
233
|
...defaultParameters.initialStateModifier,
|
|
231
234
|
messages: {
|
|
@@ -276,24 +279,54 @@ MultilineBotMessage.parameters = {
|
|
|
276
279
|
},
|
|
277
280
|
},
|
|
278
281
|
};
|
|
279
|
-
MultilineBotMessage.play = async () => {
|
|
280
|
-
const chatBody = await
|
|
281
|
-
await
|
|
282
|
+
MultilineBotMessage.play = async ({ canvasElement }) => {
|
|
283
|
+
const chatBody = await within(canvasElement).findByTestId('chat-body-container');
|
|
284
|
+
await within(canvasElement).findAllByText('Single-line lonely message');
|
|
285
|
+
// wait for the auto-scroll to execute
|
|
286
|
+
await wait(300);
|
|
287
|
+
|
|
288
|
+
// Some screen sizes won't have a scrollbar
|
|
289
|
+
const hasScrollbar = chatBody.scrollTop > 0;
|
|
290
|
+
|
|
291
|
+
if (hasScrollbar) {
|
|
292
|
+
fireEvent.scroll(chatBody, { target: { scrollTop: 0 } });
|
|
293
|
+
|
|
294
|
+
const chatNewMessage = await within(canvasElement).findByTestId('chat-new-message');
|
|
295
|
+
expect(chatNewMessage).not.toBeVisible();
|
|
296
|
+
|
|
297
|
+
await waitFor(
|
|
298
|
+
async () => {
|
|
299
|
+
await expect(chatNewMessage).toBeVisible();
|
|
300
|
+
},
|
|
301
|
+
{ timeout: 5000 },
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
export const NewUnreadMessages = Template.bind({});
|
|
307
|
+
NewUnreadMessages.parameters = MultilineBotMessage.parameters;
|
|
308
|
+
NewUnreadMessages.play = async ({ canvasElement }) => {
|
|
309
|
+
const chatBody = await within(canvasElement).findByTestId('chat-body-container');
|
|
282
310
|
// wait for the auto-scroll to execute
|
|
283
|
-
await
|
|
284
|
-
setTimeout(resolve, 50);
|
|
285
|
-
});
|
|
286
|
-
fireEvent.scroll(chatBody, { target: { scrollTop: 0 } });
|
|
311
|
+
await wait(300);
|
|
287
312
|
|
|
288
|
-
|
|
313
|
+
// Some screen sizes won't have a scrollbar
|
|
314
|
+
const hasScrollbar = chatBody.scrollTop > 0;
|
|
289
315
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
setTimeout(resolve, 1400);
|
|
294
|
-
});
|
|
316
|
+
if (hasScrollbar) {
|
|
317
|
+
fireEvent.scroll(chatBody, { target: { scrollTop: 0 } });
|
|
318
|
+
const chatNewMessage = await within(canvasElement).findByTestId('chat-new-message');
|
|
295
319
|
|
|
296
|
-
|
|
320
|
+
await waitFor(
|
|
321
|
+
async () => {
|
|
322
|
+
await expect(chatNewMessage).toBeVisible();
|
|
323
|
+
},
|
|
324
|
+
{ timeout: 5000 },
|
|
325
|
+
);
|
|
326
|
+
mockMessage(window.store, 'This is a new message');
|
|
327
|
+
await wait(50);
|
|
328
|
+
await expect(chatNewMessage).toHaveTextContent('This is a new message');
|
|
329
|
+
}
|
|
297
330
|
};
|
|
298
331
|
|
|
299
332
|
export const GroupsOfMessages = Template.bind({});
|
|
@@ -379,11 +412,11 @@ HandoverRequested.parameters = {
|
|
|
379
412
|
|
|
380
413
|
export const HandoverCancelled = Template.bind({});
|
|
381
414
|
HandoverCancelled.parameters = HandoverRequested.parameters;
|
|
382
|
-
HandoverCancelled.play = async () => {
|
|
383
|
-
await
|
|
384
|
-
const leaveQueueButton = await
|
|
415
|
+
HandoverCancelled.play = async ({ canvasElement }) => {
|
|
416
|
+
await within(canvasElement).findByText(defaultBotSettings.text.takeover_queue_text.en);
|
|
417
|
+
const leaveQueueButton = await within(canvasElement).findByText(defaultBotSettings.text.takeover_queue_link.en);
|
|
385
418
|
await userEvent.click(leaveQueueButton);
|
|
386
|
-
await
|
|
419
|
+
await within(canvasElement).findByText(defaultBotSettings.text.leave_queue_text.en);
|
|
387
420
|
};
|
|
388
421
|
|
|
389
422
|
export const Checkbox = Template.bind({});
|
|
@@ -698,200 +731,6 @@ Slider.parameters = {
|
|
|
698
731
|
},
|
|
699
732
|
};
|
|
700
733
|
|
|
701
|
-
export const Form = Template.bind({});
|
|
702
|
-
Form.parameters = {
|
|
703
|
-
...defaultParameters,
|
|
704
|
-
initialStateModifier: {
|
|
705
|
-
...defaultParameters.initialStateModifier,
|
|
706
|
-
messages: {
|
|
707
|
-
chatMessages: [
|
|
708
|
-
{
|
|
709
|
-
chat_source: 'web',
|
|
710
|
-
chat_language_code: 'en',
|
|
711
|
-
from_bot: true,
|
|
712
|
-
sender: 'BOT',
|
|
713
|
-
message: '',
|
|
714
|
-
message_format: 'txt',
|
|
715
|
-
buttons: [],
|
|
716
|
-
created: '2022-06-15T19:03:46.186495Z',
|
|
717
|
-
id: '1',
|
|
718
|
-
form: {
|
|
719
|
-
submission_id: '1',
|
|
720
|
-
id: '2',
|
|
721
|
-
dialogue_id: '2',
|
|
722
|
-
slug: 'this-is-a-form',
|
|
723
|
-
submit_dialogue_id: 'c0d685d3-3f11-41b8-9cfd-e35d54df2c95',
|
|
724
|
-
abandon_dialogue_id: 'b1cde0f3-0715-48eb-8482-a9355fa11ba8',
|
|
725
|
-
languageCode: 'en',
|
|
726
|
-
texts: {
|
|
727
|
-
title: 'This is a form',
|
|
728
|
-
error_text: 'There was an error around here',
|
|
729
|
-
submit_button_text: 'Submit',
|
|
730
|
-
cancel_button_text: 'Exit',
|
|
731
|
-
unanswered_text: 'You failed to answer this form',
|
|
732
|
-
cancel_text: 'You have cancelled/exited this form',
|
|
733
|
-
},
|
|
734
|
-
fields: [
|
|
735
|
-
{
|
|
736
|
-
input_type: FIELDS.TEXT,
|
|
737
|
-
order: 0,
|
|
738
|
-
slug: 'first-name-field',
|
|
739
|
-
texts: {
|
|
740
|
-
label: 'First name',
|
|
741
|
-
help_text: 'Please input your name here',
|
|
742
|
-
placeholder_text: 'First name',
|
|
743
|
-
required_text: 'This field is absolutely required',
|
|
744
|
-
},
|
|
745
|
-
required: true,
|
|
746
|
-
validators: [
|
|
747
|
-
{
|
|
748
|
-
max_length: 30,
|
|
749
|
-
text: 'Maximum number of length is 30',
|
|
750
|
-
},
|
|
751
|
-
],
|
|
752
|
-
},
|
|
753
|
-
{
|
|
754
|
-
input_type: FIELDS.TEXT,
|
|
755
|
-
order: 1,
|
|
756
|
-
slug: 'text-field',
|
|
757
|
-
texts: {
|
|
758
|
-
label: 'Text field',
|
|
759
|
-
placeholder_text: 'Free text',
|
|
760
|
-
required_text: 'This field is required',
|
|
761
|
-
},
|
|
762
|
-
required: true,
|
|
763
|
-
validators: [
|
|
764
|
-
{
|
|
765
|
-
min_length: 5,
|
|
766
|
-
text: 'This field should be at least 5 characters long',
|
|
767
|
-
},
|
|
768
|
-
{
|
|
769
|
-
max_length: 15,
|
|
770
|
-
},
|
|
771
|
-
],
|
|
772
|
-
},
|
|
773
|
-
{
|
|
774
|
-
input_type: FIELDS.EMAIL,
|
|
775
|
-
order: 2,
|
|
776
|
-
slug: 'email-field',
|
|
777
|
-
texts: {
|
|
778
|
-
label: 'Email',
|
|
779
|
-
placeholder_text: 'Email',
|
|
780
|
-
},
|
|
781
|
-
},
|
|
782
|
-
{
|
|
783
|
-
input_type: FIELDS.NUMBER,
|
|
784
|
-
order: 3,
|
|
785
|
-
affix: 'PREFIX',
|
|
786
|
-
slug: 'number-field',
|
|
787
|
-
texts: {
|
|
788
|
-
label: 'Number',
|
|
789
|
-
affix_value: 'NOK',
|
|
790
|
-
placeholder_text: 'Number',
|
|
791
|
-
},
|
|
792
|
-
validators: [
|
|
793
|
-
{
|
|
794
|
-
minimum: 1,
|
|
795
|
-
},
|
|
796
|
-
{
|
|
797
|
-
maximum: 12,
|
|
798
|
-
},
|
|
799
|
-
],
|
|
800
|
-
},
|
|
801
|
-
{
|
|
802
|
-
input_type: FIELDS.RANGE,
|
|
803
|
-
order: 4,
|
|
804
|
-
affix: 'SUFFIX',
|
|
805
|
-
slug: 'range-field',
|
|
806
|
-
attributes: {
|
|
807
|
-
default_value: '50',
|
|
808
|
-
step: 10,
|
|
809
|
-
},
|
|
810
|
-
texts: {
|
|
811
|
-
label: 'Slider',
|
|
812
|
-
affix_value: 'NOK',
|
|
813
|
-
placeholder_text: 'Slider',
|
|
814
|
-
},
|
|
815
|
-
validators: [
|
|
816
|
-
{
|
|
817
|
-
minimum: 1,
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
maximum: 100,
|
|
821
|
-
},
|
|
822
|
-
],
|
|
823
|
-
},
|
|
824
|
-
{
|
|
825
|
-
input_type: FIELDS.SELECT,
|
|
826
|
-
order: 5,
|
|
827
|
-
affix: '',
|
|
828
|
-
required: true,
|
|
829
|
-
slug: 'select-field',
|
|
830
|
-
attributes: {
|
|
831
|
-
default_value: '5',
|
|
832
|
-
options: [
|
|
833
|
-
{
|
|
834
|
-
value: 1,
|
|
835
|
-
label: 1,
|
|
836
|
-
},
|
|
837
|
-
{
|
|
838
|
-
value: 2,
|
|
839
|
-
label: 2,
|
|
840
|
-
},
|
|
841
|
-
{
|
|
842
|
-
value: 3,
|
|
843
|
-
label: 3,
|
|
844
|
-
},
|
|
845
|
-
{
|
|
846
|
-
value: 4,
|
|
847
|
-
label: 4,
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
value: 5,
|
|
851
|
-
label: 5,
|
|
852
|
-
},
|
|
853
|
-
],
|
|
854
|
-
},
|
|
855
|
-
texts: {
|
|
856
|
-
label: 'Select',
|
|
857
|
-
affix_value: '',
|
|
858
|
-
placeholder_text: 'Please select option',
|
|
859
|
-
},
|
|
860
|
-
validators: [],
|
|
861
|
-
},
|
|
862
|
-
],
|
|
863
|
-
},
|
|
864
|
-
},
|
|
865
|
-
],
|
|
866
|
-
},
|
|
867
|
-
},
|
|
868
|
-
};
|
|
869
|
-
Form.play = async () => {
|
|
870
|
-
await screen.findByText('Please input your name here');
|
|
871
|
-
const textPlaceholderValue = 'Free text';
|
|
872
|
-
const textInput = await screen.findByPlaceholderText(textPlaceholderValue);
|
|
873
|
-
await userEvent.type(textInput, 'This');
|
|
874
|
-
await expect(textInput.value).toBe('This');
|
|
875
|
-
await fireEvent(await screen.getByRole('button', { name: /submit/i }), new MouseEvent('click'));
|
|
876
|
-
await screen.findByText('This field is absolutely required');
|
|
877
|
-
await screen.findByText('This field should be at least 5 characters long');
|
|
878
|
-
const textInputStyle = window.getComputedStyle(textInput);
|
|
879
|
-
expect(textInputStyle.border).not.toContain('#00000000');
|
|
880
|
-
expect(textInputStyle.border).not.toContain('transparent');
|
|
881
|
-
await userEvent.type(textInput, ' is too long');
|
|
882
|
-
await expect(textInput.value).toBe('This is too lon');
|
|
883
|
-
const emailPlaceholderValue = 'Email';
|
|
884
|
-
const emailInput = await screen.findByPlaceholderText(emailPlaceholderValue);
|
|
885
|
-
await userEvent.type(emailInput, 'this@is@not@an@email');
|
|
886
|
-
const selectPlaceholderValue = 'Please select option';
|
|
887
|
-
const selectInput = await screen.findByPlaceholderText(selectPlaceholderValue);
|
|
888
|
-
const selectInputStyle = window.getComputedStyle(selectInput);
|
|
889
|
-
expect(selectInputStyle.border).not.toContain('#00000000');
|
|
890
|
-
expect(selectInputStyle.border).not.toContain('transparent');
|
|
891
|
-
await userEvent.selectOptions(selectInput, '2');
|
|
892
|
-
await expect(selectInputStyle.border).toContain('rgba(0, 0, 0, 0)');
|
|
893
|
-
};
|
|
894
|
-
|
|
895
734
|
export const LeaveContactDetails = Template.bind({});
|
|
896
735
|
LeaveContactDetails.parameters = {
|
|
897
736
|
...defaultParameters,
|
|
@@ -956,8 +795,8 @@ LeaveContactDetails.parameters = {
|
|
|
956
795
|
},
|
|
957
796
|
},
|
|
958
797
|
};
|
|
959
|
-
LeaveContactDetails.play = async () => {
|
|
960
|
-
const LeaveContactButton = await
|
|
798
|
+
LeaveContactDetails.play = async ({ canvasElement }) => {
|
|
799
|
+
const LeaveContactButton = await within(canvasElement).findByText(
|
|
961
800
|
LeaveContactDetails.parameters.initialStateModifier.messages.chatMessages[0].buttons[2].label,
|
|
962
801
|
);
|
|
963
802
|
await userEvent.click(LeaveContactButton);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable react/prop-types */
|
|
3
|
-
import { screen, userEvent } from '@storybook/testing-library';
|
|
1
|
+
import { userEvent, within } from '@storybook/testing-library';
|
|
4
2
|
import React from 'react';
|
|
5
3
|
import withFetchMock from 'storybook-addon-mock';
|
|
6
4
|
|
|
@@ -165,8 +163,8 @@ LanguageChoice.parameters = {
|
|
|
165
163
|
...defaultBotSettings,
|
|
166
164
|
},
|
|
167
165
|
};
|
|
168
|
-
LanguageChoice.play = async () => {
|
|
169
|
-
const languageButton = await
|
|
166
|
+
LanguageChoice.play = async ({ canvasElement }) => {
|
|
167
|
+
const languageButton = await within(canvasElement).findByText(defaultBotSettings.text.change_language_button.en);
|
|
170
168
|
await userEvent.click(languageButton);
|
|
171
169
|
};
|
|
172
170
|
|
|
@@ -177,17 +175,17 @@ LanguageChoiceConfirm.args = {
|
|
|
177
175
|
};
|
|
178
176
|
LanguageChoiceConfirm.argTypes = LanguageChoice.argTypes;
|
|
179
177
|
LanguageChoiceConfirm.parameters = LanguageChoice.parameters;
|
|
180
|
-
LanguageChoiceConfirm.play = async () => {
|
|
181
|
-
const languageButton = await
|
|
178
|
+
LanguageChoiceConfirm.play = async ({ canvasElement }) => {
|
|
179
|
+
const languageButton = await within(canvasElement).findByText(defaultBotSettings.text.change_language_button.en);
|
|
182
180
|
await userEvent.click(languageButton);
|
|
183
|
-
const norskButton = await
|
|
181
|
+
const norskButton = await within(canvasElement).findByText(availableLanguages[1].name);
|
|
184
182
|
await userEvent.click(norskButton);
|
|
185
183
|
};
|
|
186
184
|
|
|
187
185
|
export const DeleteConfirmation = Template.bind({});
|
|
188
186
|
DeleteConfirmation.parameters = defaultParameters;
|
|
189
|
-
DeleteConfirmation.play = async () => {
|
|
190
|
-
const deleteButton = await
|
|
187
|
+
DeleteConfirmation.play = async ({ canvasElement }) => {
|
|
188
|
+
const deleteButton = await within(canvasElement).findByText(defaultBotSettings.text.delete_button.en);
|
|
191
189
|
await userEvent.click(deleteButton);
|
|
192
190
|
};
|
|
193
191
|
|
|
@@ -204,8 +202,8 @@ DeleteSuccess.parameters = {
|
|
|
204
202
|
|
|
205
203
|
export const DownloadChat = Template.bind({});
|
|
206
204
|
DownloadChat.parameters = defaultParameters;
|
|
207
|
-
DownloadChat.play = async () => {
|
|
208
|
-
const downloadButton = await
|
|
205
|
+
DownloadChat.play = async ({ canvasElement }) => {
|
|
206
|
+
const downloadButton = await within(canvasElement).findByText(defaultBotSettings.text.download_button.en);
|
|
209
207
|
await userEvent.click(downloadButton);
|
|
210
208
|
};
|
|
211
209
|
|
|
@@ -220,7 +218,7 @@ QuitChat.parameters = {
|
|
|
220
218
|
},
|
|
221
219
|
},
|
|
222
220
|
};
|
|
223
|
-
QuitChat.play = async () => {
|
|
224
|
-
const deleteButton = await
|
|
221
|
+
QuitChat.play = async ({ canvasElement }) => {
|
|
222
|
+
const deleteButton = await within(canvasElement).findByTestId('end-chat-button');
|
|
225
223
|
await userEvent.click(deleteButton);
|
|
226
224
|
};
|