@nyaruka/temba-components 0.140.0 → 0.141.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/.lintstagedrc.js +10 -0
- package/CHANGELOG.md +22 -0
- package/dist/locales/es.js +5 -5
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fr.js +5 -5
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/locale-codes.js +11 -2
- package/dist/locales/locale-codes.js.map +1 -1
- package/dist/locales/pt.js +5 -5
- package/dist/locales/pt.js.map +1 -1
- package/dist/temba-components.js +263 -156
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +1 -1
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +1 -1
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +239 -43
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +61 -14
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js +4 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +4 -1
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js +6 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +6 -2
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +13 -0
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +7 -5
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +10 -3
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_contact_field.js +18 -5
- package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_expression.js +1 -1
- package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +0 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_random.js +0 -1
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_run_result.js +10 -4
- package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +7 -0
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +0 -1
- package/out-tsc/src/layout/Dialog.js.map +1 -1
- package/out-tsc/src/layout/Modax.js +20 -2
- package/out-tsc/src/layout/Modax.js.map +1 -1
- package/out-tsc/src/list/ContentMenu.js +14 -1
- package/out-tsc/src/list/ContentMenu.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +10 -1
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/live/TembaChart.js.map +1 -1
- package/out-tsc/src/locales/es.js +5 -5
- package/out-tsc/src/locales/es.js.map +1 -1
- package/out-tsc/src/locales/fr.js +5 -5
- package/out-tsc/src/locales/fr.js.map +1 -1
- package/out-tsc/src/locales/locale-codes.js +11 -2
- package/out-tsc/src/locales/locale-codes.js.map +1 -1
- package/out-tsc/src/locales/pt.js +5 -5
- package/out-tsc/src/locales/pt.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +11 -0
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +13 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/src/version.js +9 -0
- package/out-tsc/src/version.js.map +1 -0
- package/out-tsc/test/actions/add_contact_groups.test.js +35 -0
- package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -1
- package/out-tsc/test/actions/add_input_labels.test.js +53 -0
- package/out-tsc/test/actions/add_input_labels.test.js.map +1 -0
- package/out-tsc/test/actions/enter_flow.test.js +71 -0
- package/out-tsc/test/actions/enter_flow.test.js.map +1 -0
- package/out-tsc/test/actions/remove_contact_groups.test.js +24 -0
- package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -1
- package/out-tsc/test/actions/send_broadcast.test.js +41 -0
- package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
- package/out-tsc/test/actions/set_contact_channel.test.js +67 -0
- package/out-tsc/test/actions/set_contact_channel.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_field.test.js +52 -0
- package/out-tsc/test/actions/set_contact_field.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_language.test.js +39 -0
- package/out-tsc/test/actions/set_contact_language.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_name.test.js +28 -0
- package/out-tsc/test/actions/set_contact_name.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_status.test.js +44 -0
- package/out-tsc/test/actions/set_contact_status.test.js.map +1 -0
- package/out-tsc/test/actions/set_run_result.test.js +47 -0
- package/out-tsc/test/actions/set_run_result.test.js.map +1 -0
- package/out-tsc/test/actions/start_session.test.js +76 -0
- package/out-tsc/test/actions/start_session.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_contact_field.test.js +50 -0
- package/out-tsc/test/nodes/split_by_contact_field.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_run_result.test.js +82 -0
- package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_ticket.test.js +139 -0
- package/out-tsc/test/nodes/split_by_ticket.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_webhook.test.js +111 -0
- package/out-tsc/test/nodes/split_by_webhook.test.js.map +1 -0
- package/out-tsc/test/temba-contact-chat.test.js +12 -0
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +206 -0
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +19 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +4 -1
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +4 -2
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +3 -9
- package/rollup.components.mjs +7 -1
- package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
- package/screenshots/truth/actions/add_input_labels/editor/multiple-labels.png +0 -0
- package/screenshots/truth/actions/add_input_labels/editor/single-label.png +0 -0
- package/screenshots/truth/actions/add_input_labels/render/multiple-labels.png +0 -0
- package/screenshots/truth/actions/add_input_labels/render/single-label.png +0 -0
- package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
- package/screenshots/truth/actions/play_audio/render/expression-url.png +0 -0
- package/screenshots/truth/actions/play_audio/render/static-url.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/say_msg/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/say_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/say_msg/render/text-with-audio-url.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/editor/sms-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/render/sms-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/render/whatsapp-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/render/clear-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/render/set-value.png +0 -0
- package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
- package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
- package/screenshots/truth/actions/set_contact_language/render/english.png +0 -0
- package/screenshots/truth/actions/set_contact_language/render/french.png +0 -0
- package/screenshots/truth/actions/set_contact_name/editor/expression-name.png +0 -0
- package/screenshots/truth/actions/set_contact_name/editor/static-name.png +0 -0
- package/screenshots/truth/actions/set_contact_name/render/expression-name.png +0 -0
- package/screenshots/truth/actions/set_contact_name/render/static-name.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
- package/screenshots/truth/actions/set_contact_status/render/active.png +0 -0
- package/screenshots/truth/actions/set_contact_status/render/archived.png +0 -0
- package/screenshots/truth/actions/set_contact_status/render/blocked.png +0 -0
- package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
- package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
- package/screenshots/truth/actions/set_run_result/render/expression-value.png +0 -0
- package/screenshots/truth/actions/set_run_result/render/with-category.png +0 -0
- package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_audio/render/basic-audio-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/render/basic-dial.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/render/dial-with-limits.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/digits-with-rules.png +0 -0
- package/screenshots/truth/nodes/wait_for_menu/render/menu-with-digits.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
- package/src/display/FloatingTab.ts +1 -1
- package/src/flow/CanvasNode.ts +1 -1
- package/src/flow/Editor.ts +299 -88
- package/src/flow/Plumber.ts +89 -14
- package/src/flow/actions/add_contact_groups.ts +4 -1
- package/src/flow/actions/add_input_labels.ts +4 -1
- package/src/flow/actions/remove_contact_groups.ts +6 -1
- package/src/flow/actions/send_broadcast.ts +6 -2
- package/src/flow/actions/set_contact_channel.ts +13 -1
- package/src/flow/actions/set_contact_status.ts +7 -5
- package/src/flow/actions/start_session.ts +10 -3
- package/src/flow/nodes/split_by_contact_field.ts +16 -5
- package/src/flow/nodes/split_by_expression.ts +1 -1
- package/src/flow/nodes/split_by_llm_categorize.ts +0 -1
- package/src/flow/nodes/split_by_random.ts +0 -1
- package/src/flow/nodes/split_by_run_result.ts +10 -4
- package/src/flow/nodes/wait_for_digits.ts +2 -1
- package/src/flow/nodes/wait_for_response.ts +1 -1
- package/src/form/FieldRenderer.ts +7 -0
- package/src/layout/Dialog.ts +0 -1
- package/src/layout/Modax.ts +19 -2
- package/src/list/ContentMenu.ts +15 -1
- package/src/live/ContactChat.ts +10 -1
- package/src/live/TembaChart.ts +1 -1
- package/src/locales/es.ts +18 -13
- package/src/locales/fr.ts +18 -13
- package/src/locales/locale-codes.ts +11 -2
- package/src/locales/pt.ts +18 -13
- package/src/simulator/Simulator.ts +12 -0
- package/src/store/AppState.ts +15 -0
- package/src/store/flow-definition.d.ts +1 -0
- package/src/version.ts +10 -0
- package/test/actions/add_contact_groups.test.ts +38 -0
- package/test/actions/add_input_labels.test.ts +67 -0
- package/test/actions/enter_flow.test.ts +88 -0
- package/test/actions/remove_contact_groups.test.ts +29 -0
- package/test/actions/send_broadcast.test.ts +44 -0
- package/test/actions/set_contact_channel.test.ts +88 -0
- package/test/actions/set_contact_field.test.ts +68 -0
- package/test/actions/set_contact_language.test.ts +55 -0
- package/test/actions/set_contact_name.test.ts +39 -0
- package/test/actions/set_contact_status.test.ts +64 -0
- package/test/actions/set_run_result.test.ts +61 -0
- package/test/actions/start_session.test.ts +82 -0
- package/test/nodes/split_by_contact_field.test.ts +59 -0
- package/test/nodes/split_by_run_result.test.ts +100 -0
- package/test/nodes/split_by_ticket.test.ts +157 -0
- package/test/nodes/split_by_webhook.test.ts +131 -0
- package/test/temba-contact-chat.test.ts +17 -0
- package/test/temba-flow-editor.test.ts +264 -0
- package/test/temba-flow-plumber.test.ts +62 -0
- package/test/temba-select.test.ts +6 -1
- package/test/utils.test.ts +4 -2
- package/web-dev-server.config.mjs +5 -1
- package/web-test-runner.config.mjs +4 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { set_contact_status } from '../../src/flow/actions/set_contact_status';
|
|
3
|
+
import { SetContactStatus } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the set_contact_status action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('set_contact_status action config', () => {
|
|
10
|
+
const helper = new ActionTest(set_contact_status, 'set_contact_status');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(set_contact_status.name).to.equal('Update Status');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'set_contact_status',
|
|
25
|
+
status: 'active'
|
|
26
|
+
} as SetContactStatus,
|
|
27
|
+
'active'
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
helper.testAction(
|
|
31
|
+
{
|
|
32
|
+
uuid: 'test-action-2',
|
|
33
|
+
type: 'set_contact_status',
|
|
34
|
+
status: 'blocked'
|
|
35
|
+
} as SetContactStatus,
|
|
36
|
+
'blocked'
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
helper.testAction(
|
|
40
|
+
{
|
|
41
|
+
uuid: 'test-action-3',
|
|
42
|
+
type: 'set_contact_status',
|
|
43
|
+
status: 'archived'
|
|
44
|
+
} as SetContactStatus,
|
|
45
|
+
'archived'
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('round-trip', () => {
|
|
50
|
+
it('should extract status value from select option', () => {
|
|
51
|
+
const formData = {
|
|
52
|
+
uuid: 'test-uuid',
|
|
53
|
+
status: [{ value: 'stopped', name: 'Stopped' }]
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const action = set_contact_status.fromFormData(
|
|
57
|
+
formData
|
|
58
|
+
) as SetContactStatus;
|
|
59
|
+
|
|
60
|
+
expect(action.status).to.equal('stopped');
|
|
61
|
+
expect(action.type).to.equal('set_contact_status');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { set_run_result } from '../../src/flow/actions/set_run_result';
|
|
3
|
+
import { SetRunResult } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the set_run_result action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('set_run_result action config', () => {
|
|
10
|
+
const helper = new ActionTest(set_run_result, 'set_run_result');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(set_run_result.name).to.equal('Save Flow Result');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'set_run_result',
|
|
25
|
+
name: 'Score',
|
|
26
|
+
value: '100',
|
|
27
|
+
category: 'High'
|
|
28
|
+
} as SetRunResult,
|
|
29
|
+
'with-category'
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
helper.testAction(
|
|
33
|
+
{
|
|
34
|
+
uuid: 'test-action-2',
|
|
35
|
+
type: 'set_run_result',
|
|
36
|
+
name: 'Response',
|
|
37
|
+
value: '@input.text',
|
|
38
|
+
category: ''
|
|
39
|
+
} as SetRunResult,
|
|
40
|
+
'expression-value'
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('round-trip', () => {
|
|
45
|
+
it('should extract name from select option array', () => {
|
|
46
|
+
const formData = {
|
|
47
|
+
uuid: 'test-uuid',
|
|
48
|
+
name: [{ value: 'Score', name: 'Score' }],
|
|
49
|
+
value: '42',
|
|
50
|
+
category: 'Medium'
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const action = set_run_result.fromFormData(formData) as SetRunResult;
|
|
54
|
+
|
|
55
|
+
expect(action.name).to.equal('Score');
|
|
56
|
+
expect(action.value).to.equal('42');
|
|
57
|
+
expect(action.category).to.equal('Medium');
|
|
58
|
+
expect(action.type).to.equal('set_run_result');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -148,4 +148,86 @@ describe('start_session action config', () => {
|
|
|
148
148
|
expect(result.valid).to.be.true;
|
|
149
149
|
expect(Object.keys(result.errors).length).to.equal(0);
|
|
150
150
|
});
|
|
151
|
+
|
|
152
|
+
describe('metadata stripping', () => {
|
|
153
|
+
it('should strip superfluous API metadata from flow', () => {
|
|
154
|
+
const formData = {
|
|
155
|
+
uuid: 'test-uuid',
|
|
156
|
+
flow: [
|
|
157
|
+
{
|
|
158
|
+
uuid: 'flow-1',
|
|
159
|
+
name: 'Registration Flow',
|
|
160
|
+
type: 'message',
|
|
161
|
+
archived: false,
|
|
162
|
+
labels: [],
|
|
163
|
+
expires: 720,
|
|
164
|
+
runs: {
|
|
165
|
+
active: 0,
|
|
166
|
+
waiting: 5,
|
|
167
|
+
completed: 100,
|
|
168
|
+
interrupted: 2,
|
|
169
|
+
expired: 1,
|
|
170
|
+
failed: 0
|
|
171
|
+
},
|
|
172
|
+
results: [],
|
|
173
|
+
parent_refs: [],
|
|
174
|
+
created_on: '2024-01-01T00:00:00.000Z',
|
|
175
|
+
modified_on: '2024-06-15T12:00:00.000Z'
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
startType: [{ value: 'create', name: 'Create a new contact' }]
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const action = start_session.fromFormData(formData) as StartSession;
|
|
182
|
+
|
|
183
|
+
expect(action.flow).to.deep.equal({
|
|
184
|
+
uuid: 'flow-1',
|
|
185
|
+
name: 'Registration Flow'
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should strip superfluous API metadata from contacts and groups', () => {
|
|
190
|
+
const formData = {
|
|
191
|
+
uuid: 'test-uuid',
|
|
192
|
+
flow: [{ uuid: 'flow-1', name: 'Test Flow' }],
|
|
193
|
+
startType: [{ value: 'manual', name: 'Select recipients manually' }],
|
|
194
|
+
recipients: [
|
|
195
|
+
{
|
|
196
|
+
uuid: 'contact-1',
|
|
197
|
+
name: 'Alice',
|
|
198
|
+
status: 'active',
|
|
199
|
+
language: 'eng',
|
|
200
|
+
urns: ['tel:+250788123456'],
|
|
201
|
+
groups: [{ uuid: 'g-1', name: 'G1' }],
|
|
202
|
+
fields: { age: '30' },
|
|
203
|
+
created_on: '2024-01-01T00:00:00.000Z',
|
|
204
|
+
modified_on: '2024-06-15T12:00:00.000Z',
|
|
205
|
+
last_seen_on: '2024-06-14T10:00:00.000Z'
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
uuid: 'group-1',
|
|
209
|
+
name: 'VIP',
|
|
210
|
+
group: true,
|
|
211
|
+
query: 'status = vip',
|
|
212
|
+
status: 'ready',
|
|
213
|
+
count: 42,
|
|
214
|
+
system: false
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const action = start_session.fromFormData(formData) as StartSession;
|
|
220
|
+
|
|
221
|
+
expect(action.contacts).to.have.lengthOf(1);
|
|
222
|
+
expect(action.contacts[0]).to.deep.equal({
|
|
223
|
+
uuid: 'contact-1',
|
|
224
|
+
name: 'Alice'
|
|
225
|
+
});
|
|
226
|
+
expect(action.groups).to.have.lengthOf(1);
|
|
227
|
+
expect(action.groups[0]).to.deep.equal({
|
|
228
|
+
uuid: 'group-1',
|
|
229
|
+
name: 'VIP'
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
151
233
|
});
|
|
@@ -448,4 +448,63 @@ describe('split_by_contact_field', () => {
|
|
|
448
448
|
expect(uiConfig.operand.name).to.equal('Facebook');
|
|
449
449
|
expect(uiConfig.operand.type).to.equal('scheme');
|
|
450
450
|
});
|
|
451
|
+
|
|
452
|
+
it('should handle round-trip for custom field without re-selecting', () => {
|
|
453
|
+
// Reproduces the bug: toUIConfig saves { id, name, type } without 'key',
|
|
454
|
+
// then toFormData loads it, and fromFormData must still produce a valid operand.
|
|
455
|
+
const originalNode: Node = {
|
|
456
|
+
uuid: 'test-node-uuid',
|
|
457
|
+
actions: [],
|
|
458
|
+
router: {
|
|
459
|
+
type: 'switch',
|
|
460
|
+
cases: [
|
|
461
|
+
{
|
|
462
|
+
uuid: 'case-1',
|
|
463
|
+
type: 'has_text',
|
|
464
|
+
arguments: ['red'],
|
|
465
|
+
category_uuid: 'cat-1'
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
categories: [
|
|
469
|
+
{ uuid: 'cat-1', name: 'Red', exit_uuid: 'exit-1' },
|
|
470
|
+
{ uuid: 'cat-other', name: 'Other', exit_uuid: 'exit-other' }
|
|
471
|
+
],
|
|
472
|
+
default_category_uuid: 'cat-other',
|
|
473
|
+
operand: '@fields.favorite_color',
|
|
474
|
+
result_name: ''
|
|
475
|
+
},
|
|
476
|
+
exits: [
|
|
477
|
+
{ uuid: 'exit-1', destination_uuid: null },
|
|
478
|
+
{ uuid: 'exit-other', destination_uuid: null }
|
|
479
|
+
]
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// nodeUI as saved by toUIConfig - note: NO 'key' property, only 'id'
|
|
483
|
+
const nodeUI = {
|
|
484
|
+
type: 'split_by_contact_field',
|
|
485
|
+
position: { left: 0, top: 0 },
|
|
486
|
+
config: {
|
|
487
|
+
operand: {
|
|
488
|
+
id: 'favorite_color',
|
|
489
|
+
name: 'Favorite Color',
|
|
490
|
+
type: 'field'
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
// Step 1: toFormData (opening the editor)
|
|
496
|
+
const formData = split_by_contact_field.toFormData!(originalNode, nodeUI);
|
|
497
|
+
|
|
498
|
+
// The field should have 'key' normalized from 'id'
|
|
499
|
+
expect(formData.field[0].key).to.equal('favorite_color');
|
|
500
|
+
|
|
501
|
+
// Step 2: fromFormData (saving without re-selecting the field)
|
|
502
|
+
const updatedNode = split_by_contact_field.fromFormData!(
|
|
503
|
+
formData,
|
|
504
|
+
originalNode
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
// The operand must NOT be @fields.undefined
|
|
508
|
+
expect(updatedNode.router!.operand).to.equal('@fields.favorite_color');
|
|
509
|
+
});
|
|
451
510
|
});
|
|
@@ -1136,6 +1136,106 @@ describe('split_by_run_result node config', () => {
|
|
|
1136
1136
|
});
|
|
1137
1137
|
});
|
|
1138
1138
|
|
|
1139
|
+
describe('toFormData normalizes operand from toUIConfig', () => {
|
|
1140
|
+
it('should handle round-trip when operand has only id (no value)', () => {
|
|
1141
|
+
// Reproduces the bug: toUIConfig saves { id, name, type } without 'value',
|
|
1142
|
+
// then toFormData loads it, and fromFormData must still produce a valid operand.
|
|
1143
|
+
const originalNode: Node = {
|
|
1144
|
+
uuid: 'test-node-uuid',
|
|
1145
|
+
actions: [],
|
|
1146
|
+
router: {
|
|
1147
|
+
type: 'switch',
|
|
1148
|
+
operand: '@results.favorite_color',
|
|
1149
|
+
cases: [
|
|
1150
|
+
{
|
|
1151
|
+
uuid: 'case-1',
|
|
1152
|
+
type: 'has_phrase',
|
|
1153
|
+
arguments: ['red'],
|
|
1154
|
+
category_uuid: 'cat-1'
|
|
1155
|
+
}
|
|
1156
|
+
],
|
|
1157
|
+
categories: [
|
|
1158
|
+
{ uuid: 'cat-1', name: 'Red', exit_uuid: 'exit-1' },
|
|
1159
|
+
{ uuid: 'cat-other', name: 'Other', exit_uuid: 'exit-other' }
|
|
1160
|
+
],
|
|
1161
|
+
default_category_uuid: 'cat-other',
|
|
1162
|
+
result_name: ''
|
|
1163
|
+
},
|
|
1164
|
+
exits: [
|
|
1165
|
+
{ uuid: 'exit-1', destination_uuid: null },
|
|
1166
|
+
{ uuid: 'exit-other', destination_uuid: null }
|
|
1167
|
+
]
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
// nodeUI as saved by toUIConfig - note: NO 'value' property, only 'id'
|
|
1171
|
+
const nodeUI = {
|
|
1172
|
+
config: {
|
|
1173
|
+
operand: {
|
|
1174
|
+
id: 'favorite_color',
|
|
1175
|
+
name: 'Favorite Color',
|
|
1176
|
+
type: 'result'
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
// Step 1: toFormData (opening the editor)
|
|
1182
|
+
const formData = split_by_run_result.toFormData!(originalNode, nodeUI);
|
|
1183
|
+
|
|
1184
|
+
// The result should have 'value' normalized from 'id'
|
|
1185
|
+
expect(formData.result[0].value).to.equal('favorite_color');
|
|
1186
|
+
|
|
1187
|
+
// Step 2: fromFormData (saving without re-selecting the result)
|
|
1188
|
+
const updatedNode = split_by_run_result.fromFormData!(
|
|
1189
|
+
formData,
|
|
1190
|
+
originalNode
|
|
1191
|
+
);
|
|
1192
|
+
|
|
1193
|
+
// The operand must NOT be @results.undefined
|
|
1194
|
+
expect(updatedNode.router!.operand).to.equal('@results.favorite_color');
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
it('should handle round-trip with delimiter when operand has only id', () => {
|
|
1198
|
+
const originalNode: Node = {
|
|
1199
|
+
uuid: 'test-node-uuid',
|
|
1200
|
+
actions: [],
|
|
1201
|
+
router: {
|
|
1202
|
+
type: 'switch',
|
|
1203
|
+
operand: '@(field(results.favorite_color, 2, "."))',
|
|
1204
|
+
cases: [],
|
|
1205
|
+
categories: [
|
|
1206
|
+
{ uuid: 'cat-other', name: 'Other', exit_uuid: 'exit-other' }
|
|
1207
|
+
],
|
|
1208
|
+
default_category_uuid: 'cat-other',
|
|
1209
|
+
result_name: ''
|
|
1210
|
+
},
|
|
1211
|
+
exits: [{ uuid: 'exit-other', destination_uuid: null }]
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
const nodeUI = {
|
|
1215
|
+
config: {
|
|
1216
|
+
operand: {
|
|
1217
|
+
id: 'favorite_color',
|
|
1218
|
+
name: 'Favorite Color',
|
|
1219
|
+
type: 'result'
|
|
1220
|
+
},
|
|
1221
|
+
index: 2,
|
|
1222
|
+
delimiter: '.'
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
const formData = split_by_run_result.toFormData!(originalNode, nodeUI);
|
|
1227
|
+
expect(formData.result[0].value).to.equal('favorite_color');
|
|
1228
|
+
|
|
1229
|
+
const updatedNode = split_by_run_result.fromFormData!(
|
|
1230
|
+
formData,
|
|
1231
|
+
originalNode
|
|
1232
|
+
);
|
|
1233
|
+
expect(updatedNode.router!.operand).to.equal(
|
|
1234
|
+
'@(field(results.favorite_color, 2, "."))'
|
|
1235
|
+
);
|
|
1236
|
+
});
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1139
1239
|
describe('backwards compatibility', () => {
|
|
1140
1240
|
it('should support split_by_run_result_delimited type from old flows', () => {
|
|
1141
1241
|
// Verify that split_by_run_result_delimited points to the same config as split_by_run_result
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { split_by_ticket } from '../../src/flow/nodes/split_by_ticket';
|
|
3
|
+
import { Node, OpenTicket } from '../../src/store/flow-definition';
|
|
4
|
+
import { NodeTest } from '../NodeHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the split_by_ticket node configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('split_by_ticket node config', () => {
|
|
10
|
+
const helper = new NodeTest(split_by_ticket, 'split_by_ticket');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct type and name', () => {
|
|
16
|
+
expect(split_by_ticket.type).to.equal('split_by_ticket');
|
|
17
|
+
expect(split_by_ticket.name).to.equal('Open Ticket');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('round-trip transformation', () => {
|
|
22
|
+
it('should transform from flow definition to form data', () => {
|
|
23
|
+
const node: Node = {
|
|
24
|
+
uuid: 'test-node',
|
|
25
|
+
actions: [
|
|
26
|
+
{
|
|
27
|
+
type: 'open_ticket',
|
|
28
|
+
uuid: 'action-1',
|
|
29
|
+
topic: { uuid: 'topic-1', name: 'General' },
|
|
30
|
+
assignee: { uuid: 'user-1', name: 'Alice' },
|
|
31
|
+
note: 'Test note'
|
|
32
|
+
} as OpenTicket
|
|
33
|
+
],
|
|
34
|
+
exits: []
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const formData = split_by_ticket.toFormData!(node);
|
|
38
|
+
|
|
39
|
+
expect(formData.uuid).to.equal('test-node');
|
|
40
|
+
expect(formData.topic).to.have.lengthOf(1);
|
|
41
|
+
expect(formData.topic[0]).to.deep.equal({
|
|
42
|
+
uuid: 'topic-1',
|
|
43
|
+
name: 'General'
|
|
44
|
+
});
|
|
45
|
+
expect(formData.assignee).to.have.lengthOf(1);
|
|
46
|
+
expect(formData.assignee[0]).to.deep.equal({
|
|
47
|
+
uuid: 'user-1',
|
|
48
|
+
name: 'Alice'
|
|
49
|
+
});
|
|
50
|
+
expect(formData.note).to.equal('Test note');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should transform from form data to flow definition', () => {
|
|
54
|
+
const originalNode: Node = {
|
|
55
|
+
uuid: 'test-node',
|
|
56
|
+
actions: [],
|
|
57
|
+
exits: []
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const formData = {
|
|
61
|
+
uuid: 'test-node',
|
|
62
|
+
topic: [{ uuid: 'topic-1', name: 'General' }],
|
|
63
|
+
assignee: [{ uuid: 'user-1', name: 'Alice' }],
|
|
64
|
+
note: 'Test note'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const resultNode = split_by_ticket.fromFormData!(formData, originalNode);
|
|
68
|
+
|
|
69
|
+
expect(resultNode.uuid).to.equal('test-node');
|
|
70
|
+
expect(resultNode.actions).to.have.lengthOf(1);
|
|
71
|
+
expect(resultNode.actions![0].type).to.equal('open_ticket');
|
|
72
|
+
expect((resultNode.actions![0] as any).topic).to.deep.equal({
|
|
73
|
+
uuid: 'topic-1',
|
|
74
|
+
name: 'General'
|
|
75
|
+
});
|
|
76
|
+
expect((resultNode.actions![0] as any).assignee).to.deep.equal({
|
|
77
|
+
uuid: 'user-1',
|
|
78
|
+
name: 'Alice'
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should strip superfluous API metadata from topic and assignee', () => {
|
|
83
|
+
const originalNode: Node = {
|
|
84
|
+
uuid: 'test-node',
|
|
85
|
+
actions: [],
|
|
86
|
+
exits: []
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const formData = {
|
|
90
|
+
uuid: 'test-node',
|
|
91
|
+
topic: [
|
|
92
|
+
{
|
|
93
|
+
uuid: 'topic-1',
|
|
94
|
+
name: 'General',
|
|
95
|
+
created_on: '2024-01-01T00:00:00.000Z',
|
|
96
|
+
modified_on: '2024-06-15T12:00:00.000Z'
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
assignee: [
|
|
100
|
+
{
|
|
101
|
+
uuid: 'user-1',
|
|
102
|
+
name: 'Alice Johnson',
|
|
103
|
+
email: 'alice@example.com',
|
|
104
|
+
first_name: 'Alice',
|
|
105
|
+
last_name: 'Johnson',
|
|
106
|
+
role: 'agent',
|
|
107
|
+
created_on: '2024-01-01T00:00:00.000Z'
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
note: ''
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const resultNode = split_by_ticket.fromFormData!(formData, originalNode);
|
|
114
|
+
|
|
115
|
+
const action = resultNode.actions![0] as any;
|
|
116
|
+
expect(action.topic).to.deep.equal({
|
|
117
|
+
uuid: 'topic-1',
|
|
118
|
+
name: 'General'
|
|
119
|
+
});
|
|
120
|
+
expect(action.assignee).to.deep.equal({
|
|
121
|
+
uuid: 'user-1',
|
|
122
|
+
name: 'Alice Johnson'
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should handle assignee with only first_name/last_name (no name)', () => {
|
|
127
|
+
const originalNode: Node = {
|
|
128
|
+
uuid: 'test-node',
|
|
129
|
+
actions: [],
|
|
130
|
+
exits: []
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const formData = {
|
|
134
|
+
uuid: 'test-node',
|
|
135
|
+
topic: [{ uuid: 'topic-1', name: 'General' }],
|
|
136
|
+
assignee: [
|
|
137
|
+
{
|
|
138
|
+
uuid: 'user-1',
|
|
139
|
+
first_name: 'Bob',
|
|
140
|
+
last_name: 'Smith',
|
|
141
|
+
email: 'bob@example.com',
|
|
142
|
+
role: 'agent'
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
note: ''
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const resultNode = split_by_ticket.fromFormData!(formData, originalNode);
|
|
149
|
+
|
|
150
|
+
const action = resultNode.actions![0] as any;
|
|
151
|
+
expect(action.assignee).to.deep.equal({
|
|
152
|
+
uuid: 'user-1',
|
|
153
|
+
name: 'Bob Smith'
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { split_by_webhook } from '../../src/flow/nodes/split_by_webhook';
|
|
3
|
+
import { Node, CallWebhook } from '../../src/store/flow-definition';
|
|
4
|
+
import { NodeTest } from '../NodeHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the split_by_webhook node configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('split_by_webhook node config', () => {
|
|
10
|
+
const helper = new NodeTest(split_by_webhook, 'split_by_webhook');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct type and name', () => {
|
|
16
|
+
expect(split_by_webhook.type).to.equal('split_by_webhook');
|
|
17
|
+
expect(split_by_webhook.name).to.equal('Call Webhook');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('round-trip transformation', () => {
|
|
22
|
+
it('should transform from flow definition to form data', () => {
|
|
23
|
+
const node: Node = {
|
|
24
|
+
uuid: 'test-node',
|
|
25
|
+
actions: [
|
|
26
|
+
{
|
|
27
|
+
type: 'call_webhook',
|
|
28
|
+
uuid: 'action-1',
|
|
29
|
+
method: 'POST',
|
|
30
|
+
url: 'https://example.com/webhook',
|
|
31
|
+
headers: { Authorization: 'Bearer token123' },
|
|
32
|
+
body: '{"key": "value"}'
|
|
33
|
+
} as CallWebhook
|
|
34
|
+
],
|
|
35
|
+
exits: []
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const formData = split_by_webhook.toFormData!(node);
|
|
39
|
+
|
|
40
|
+
expect(formData.uuid).to.equal('test-node');
|
|
41
|
+
expect(formData.method).to.equal('POST');
|
|
42
|
+
expect(formData.url).to.equal('https://example.com/webhook');
|
|
43
|
+
expect(formData.headers).to.deep.equal({
|
|
44
|
+
Authorization: 'Bearer token123'
|
|
45
|
+
});
|
|
46
|
+
expect(formData.body).to.equal('{"key": "value"}');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should transform from form data to flow definition (GET)', () => {
|
|
50
|
+
const originalNode: Node = {
|
|
51
|
+
uuid: 'test-node',
|
|
52
|
+
actions: [],
|
|
53
|
+
exits: []
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const formData = {
|
|
57
|
+
uuid: 'test-node',
|
|
58
|
+
method: [{ value: 'GET', name: 'GET' }],
|
|
59
|
+
url: 'https://example.com/api',
|
|
60
|
+
headers: [],
|
|
61
|
+
body: ''
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const resultNode = split_by_webhook.fromFormData!(formData, originalNode);
|
|
65
|
+
|
|
66
|
+
expect(resultNode.uuid).to.equal('test-node');
|
|
67
|
+
expect(resultNode.actions).to.have.lengthOf(1);
|
|
68
|
+
expect(resultNode.actions![0].type).to.equal('call_webhook');
|
|
69
|
+
|
|
70
|
+
const action = resultNode.actions![0] as any;
|
|
71
|
+
expect(action.method).to.equal('GET');
|
|
72
|
+
expect(action.url).to.equal('https://example.com/api');
|
|
73
|
+
|
|
74
|
+
// Should have Success/Failure router
|
|
75
|
+
expect(resultNode.router).to.exist;
|
|
76
|
+
expect(resultNode.router!.type).to.equal('switch');
|
|
77
|
+
expect(resultNode.exits).to.have.lengthOf(2);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should transform from form data to flow definition (POST)', () => {
|
|
81
|
+
const originalNode: Node = {
|
|
82
|
+
uuid: 'test-node',
|
|
83
|
+
actions: [],
|
|
84
|
+
exits: []
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const formData = {
|
|
88
|
+
uuid: 'test-node',
|
|
89
|
+
method: [{ value: 'POST', name: 'POST' }],
|
|
90
|
+
url: 'https://example.com/webhook',
|
|
91
|
+
headers: [{ name: 'Content-Type', value: 'application/json' }],
|
|
92
|
+
body: '{"data": "@contact.name"}'
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const resultNode = split_by_webhook.fromFormData!(formData, originalNode);
|
|
96
|
+
|
|
97
|
+
const action = resultNode.actions![0] as any;
|
|
98
|
+
expect(action.method).to.equal('POST');
|
|
99
|
+
expect(action.url).to.equal('https://example.com/webhook');
|
|
100
|
+
expect(action.headers).to.have.lengthOf(1);
|
|
101
|
+
expect(action.body).to.equal('{"data": "@contact.name"}');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should preserve action UUID on re-save', () => {
|
|
105
|
+
const originalNode: Node = {
|
|
106
|
+
uuid: 'test-node',
|
|
107
|
+
actions: [
|
|
108
|
+
{
|
|
109
|
+
type: 'call_webhook',
|
|
110
|
+
uuid: 'existing-action-uuid',
|
|
111
|
+
method: 'GET',
|
|
112
|
+
url: 'https://example.com/old'
|
|
113
|
+
} as CallWebhook
|
|
114
|
+
],
|
|
115
|
+
exits: []
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const formData = {
|
|
119
|
+
uuid: 'test-node',
|
|
120
|
+
method: [{ value: 'GET', name: 'GET' }],
|
|
121
|
+
url: 'https://example.com/new',
|
|
122
|
+
headers: [],
|
|
123
|
+
body: ''
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const resultNode = split_by_webhook.fromFormData!(formData, originalNode);
|
|
127
|
+
|
|
128
|
+
expect(resultNode.actions![0].uuid).to.equal('existing-action-uuid');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -116,6 +116,23 @@ describe('temba-contact-chat', () => {
|
|
|
116
116
|
await assertScreenshot('contacts/chat-for-stopped-contact', getClip(chat));
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
+
it('keeps flow footer from blocking scrollbar drag interactions', async () => {
|
|
120
|
+
await loadStore();
|
|
121
|
+
const chat: ContactChat = await getContactChat({
|
|
122
|
+
contact: 'contact-dave-active'
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const flowFooter = chat.shadowRoot.querySelector(
|
|
126
|
+
'.flow-footer'
|
|
127
|
+
) as HTMLElement;
|
|
128
|
+
const inFlow = flowFooter.querySelector('.in-flow') as HTMLElement;
|
|
129
|
+
|
|
130
|
+
expect(flowFooter).to.exist;
|
|
131
|
+
expect(inFlow).to.exist;
|
|
132
|
+
expect(getComputedStyle(flowFooter).pointerEvents).to.equal('none');
|
|
133
|
+
expect(getComputedStyle(inFlow).pointerEvents).to.equal('auto');
|
|
134
|
+
});
|
|
135
|
+
|
|
119
136
|
it('sends text without attachments', async () => {
|
|
120
137
|
// we are a StoreElement, so load a store first
|
|
121
138
|
await loadStore();
|