@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.
@@ -1,18 +1,17 @@
1
1
  import { expect } from '@storybook/jest';
2
- /* eslint-disable react-hooks/exhaustive-deps */
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 '../../.storybook/preview';
11
- import { FIELDS } from '../../src/components/Form/utils/constants';
12
- import KindlyChatButton from '../../src/features/KindlyChatButton/KindlyChatButton';
13
- import settingsJSON from '../assets/settingsJson';
14
- import withContainer from '../decorators/withContainer';
15
- import withMockProvider from '../decorators/withProvider';
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
- ...defaultParameters,
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 screen.findByTestId('chat-body-container');
281
- await screen.findAllByText('Single-line lonely message');
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 new Promise((resolve) => {
284
- setTimeout(resolve, 50);
285
- });
286
- fireEvent.scroll(chatBody, { target: { scrollTop: 0 } });
311
+ await wait(300);
287
312
 
288
- const chatNewMessage = await screen.findByTestId('chat-new-message');
313
+ // Some screen sizes won't have a scrollbar
314
+ const hasScrollbar = chatBody.scrollTop > 0;
289
315
 
290
- // TODO: We used to use `waitFor`, but it seems to fail in Chromatic.
291
- // Wait for the newMessage button to be visible
292
- await new Promise((resolve) => {
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
- await expect(chatNewMessage).toBeVisible();
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 screen.findByText(defaultBotSettings.text.takeover_queue_text.en);
384
- const leaveQueueButton = await screen.findByText(defaultBotSettings.text.takeover_queue_link.en);
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 screen.findByText(defaultBotSettings.text.leave_queue_text.en);
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 screen.findByText(
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,4 +1,3 @@
1
- /* eslint-disable react/prop-types */
2
1
  import React from 'react';
3
2
  import withMock from 'storybook-addon-mock';
4
3
 
@@ -1,5 +1,3 @@
1
- /* eslint-disable react-hooks/exhaustive-deps */
2
- /* eslint-disable react/prop-types */
3
1
  import React from 'react';
4
2
  import withFetchMock from 'storybook-addon-mock';
5
3
 
@@ -1,4 +1,3 @@
1
- /* eslint-disable react/prop-types */
2
1
  import React from 'react';
3
2
  import withMock from 'storybook-addon-mock';
4
3
 
@@ -1,6 +1,4 @@
1
- /* eslint-disable react-hooks/exhaustive-deps */
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 screen.findByText(defaultBotSettings.text.change_language_button.en);
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 screen.findByText(defaultBotSettings.text.change_language_button.en);
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 screen.findByText(availableLanguages[1].name);
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 screen.findByText(defaultBotSettings.text.delete_button.en);
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 screen.findByText(defaultBotSettings.text.download_button.en);
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 screen.findByTestId('end-chat-button');
221
+ QuitChat.play = async ({ canvasElement }) => {
222
+ const deleteButton = await within(canvasElement).findByTestId('end-chat-button');
225
223
  await userEvent.click(deleteButton);
226
224
  };
@@ -1,5 +1,3 @@
1
- /* eslint-disable react-hooks/exhaustive-deps */
2
- /* eslint-disable react/prop-types */
3
1
  import React from 'react';
4
2
  import withFetchMock from 'storybook-addon-mock';
5
3
 
@@ -1,5 +1,3 @@
1
- /* eslint-disable react-hooks/exhaustive-deps */
2
- /* eslint-disable react/prop-types */
3
1
  import React from 'react';
4
2
 
5
3
  import { chromaticViewports } from '../../.storybook/preview';
@@ -0,0 +1,2 @@
1
+ /* eslint-disable no-promise-executor-return */
2
+ export default (waitTime) => new Promise((resolve) => setTimeout(resolve, waitTime));