@nyaruka/temba-components 0.129.3 → 0.129.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/.eslintrc.js +1 -0
- package/.github/workflows/build.yml +135 -3
- package/CHANGELOG.md +19 -0
- package/demo/data/flows/sample-flow.json +110 -87
- package/demo/field-config-demo.html +135 -0
- package/dist/temba-components.js +1257 -675
- package/dist/temba-components.js.map +1 -1
- package/docs/ActionEditor-Migration.md +118 -0
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/{EditorNode.js → CanvasNode.js} +345 -42
- package/out-tsc/src/flow/CanvasNode.js.map +1 -0
- package/out-tsc/src/flow/Editor.js +107 -3
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +1211 -0
- package/out-tsc/src/flow/NodeEditor.js.map +1 -0
- package/out-tsc/src/flow/Plumber.js +0 -6
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js +40 -0
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -0
- package/out-tsc/src/flow/actions/add_contact_urn.js +16 -0
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -0
- package/out-tsc/src/flow/actions/add_input_labels.js +11 -0
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -0
- package/out-tsc/src/flow/actions/call_classifier.js +11 -0
- package/out-tsc/src/flow/actions/call_classifier.js.map +1 -0
- package/out-tsc/src/flow/actions/call_llm.js +11 -0
- package/out-tsc/src/flow/actions/call_llm.js.map +1 -0
- package/out-tsc/src/flow/actions/call_resthook.js +11 -0
- package/out-tsc/src/flow/actions/call_resthook.js.map +1 -0
- package/out-tsc/src/flow/actions/call_webhook.js +122 -0
- package/out-tsc/src/flow/actions/call_webhook.js.map +1 -0
- package/out-tsc/src/flow/actions/enter_flow.js +14 -0
- package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
- package/out-tsc/src/flow/actions/open_ticket.js +11 -0
- package/out-tsc/src/flow/actions/open_ticket.js.map +1 -0
- package/out-tsc/src/flow/actions/play_audio.js +11 -0
- package/out-tsc/src/flow/actions/play_audio.js.map +1 -0
- package/out-tsc/src/flow/actions/remove_contact_groups.js +62 -0
- package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -0
- package/out-tsc/src/flow/actions/request_optin.js +11 -0
- package/out-tsc/src/flow/actions/request_optin.js.map +1 -0
- package/out-tsc/src/flow/actions/say_msg.js +11 -0
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -0
- package/out-tsc/src/flow/actions/send_broadcast.js +33 -0
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -0
- package/out-tsc/src/flow/actions/send_email.js +56 -0
- package/out-tsc/src/flow/actions/send_email.js.map +1 -0
- package/out-tsc/src/flow/actions/send_msg.js +55 -0
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -0
- package/out-tsc/src/flow/actions/set_contact_channel.js +12 -0
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -0
- package/out-tsc/src/flow/actions/set_contact_field.js +12 -0
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -0
- package/out-tsc/src/flow/actions/set_contact_language.js +10 -0
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -0
- package/out-tsc/src/flow/actions/set_contact_name.js +10 -0
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -0
- package/out-tsc/src/flow/actions/set_contact_status.js +10 -0
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -0
- package/out-tsc/src/flow/actions/set_run_result.js +10 -0
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -0
- package/out-tsc/src/flow/actions/split_by_expression_example.js +77 -0
- package/out-tsc/src/flow/actions/split_by_expression_example.js.map +1 -0
- package/out-tsc/src/flow/actions/start_session.js +11 -0
- package/out-tsc/src/flow/actions/start_session.js.map +1 -0
- package/out-tsc/src/flow/actions/transfer_airtime.js +11 -0
- package/out-tsc/src/flow/actions/transfer_airtime.js.map +1 -0
- package/out-tsc/src/flow/config.js +88 -193
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/execute_actions.js +4 -0
- package/out-tsc/src/flow/nodes/execute_actions.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -0
- package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_contact_field.js +7 -0
- package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_expression.js +7 -0
- package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_groups.js +7 -0
- package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_random.js +10 -0
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_run_result.js +7 -0
- package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_scheme.js +7 -0
- package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_subflow.js +9 -0
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_webhook.js +18 -0
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_audio.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_digits.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_image.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_image.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_location.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_location.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_menu.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_video.js +7 -0
- package/out-tsc/src/flow/nodes/wait_for_video.js.map +1 -0
- package/out-tsc/src/flow/types.js +79 -0
- package/out-tsc/src/flow/types.js.map +1 -0
- package/out-tsc/src/flow/utils.js +65 -0
- package/out-tsc/src/flow/utils.js.map +1 -0
- package/out-tsc/src/form/ArrayEditor.js +199 -0
- package/out-tsc/src/form/ArrayEditor.js.map +1 -0
- package/out-tsc/src/form/BaseListEditor.js +128 -0
- package/out-tsc/src/form/BaseListEditor.js.map +1 -0
- package/out-tsc/src/form/Checkbox.js +17 -2
- package/out-tsc/src/form/Checkbox.js.map +1 -1
- package/out-tsc/src/form/Completion.js +6 -0
- package/out-tsc/src/form/Completion.js.map +1 -1
- package/out-tsc/src/form/FormField.js +110 -11
- package/out-tsc/src/form/FormField.js.map +1 -1
- package/out-tsc/src/form/KeyValueEditor.js +223 -0
- package/out-tsc/src/form/KeyValueEditor.js.map +1 -0
- package/out-tsc/src/form/select/Select.js +92 -32
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/interfaces.js +6 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +2 -76
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/temba-modules.js +9 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/ActionHelper.js +116 -0
- package/out-tsc/test/ActionHelper.js.map +1 -0
- package/out-tsc/test/actions/add_contact_groups.test.js +66 -0
- package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -0
- package/out-tsc/test/actions/remove_contact_groups.test.js +226 -0
- package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -0
- package/out-tsc/test/actions/send_email.test.js +160 -0
- package/out-tsc/test/actions/send_email.test.js.map +1 -0
- package/out-tsc/test/actions/send_msg.test.js +95 -0
- package/out-tsc/test/actions/send_msg.test.js.map +1 -0
- package/out-tsc/test/temba-action-editing-integration.test.js +183 -0
- package/out-tsc/test/temba-action-editing-integration.test.js.map +1 -0
- package/out-tsc/test/temba-checkbox.test.js +1 -1
- package/out-tsc/test/temba-checkbox.test.js.map +1 -1
- package/out-tsc/test/temba-field-config.test.js +133 -0
- package/out-tsc/test/temba-field-config.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor-node.test.js +14 -14
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +283 -0
- package/out-tsc/test/temba-node-editor.test.js.map +1 -0
- package/out-tsc/test/temba-select.test.js +158 -0
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
- 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/remove_contact_groups/editor/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/single-group.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/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.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/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.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/editor/router.png +0 -0
- package/screenshots/truth/editor/send_msg.png +0 -0
- package/screenshots/truth/editor/set_contact_language.png +0 -0
- package/screenshots/truth/editor/set_contact_name.png +0 -0
- package/screenshots/truth/editor/set_run_result.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/formfield/markdown-errors.png +0 -0
- package/screenshots/truth/formfield/plain-text-errors.png +0 -0
- package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
- package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
- package/src/events.ts +1 -40
- package/src/flow/{EditorNode.ts → CanvasNode.ts} +424 -48
- package/src/flow/Editor.ts +140 -4
- package/src/flow/NodeEditor.ts +1454 -0
- package/src/flow/Plumber.ts +0 -9
- package/src/flow/actions/add_contact_groups.ts +42 -0
- package/src/flow/actions/add_contact_urn.ts +17 -0
- package/src/flow/actions/add_input_labels.ts +12 -0
- package/src/flow/actions/call_classifier.ts +12 -0
- package/src/flow/actions/call_llm.ts +12 -0
- package/src/flow/actions/call_resthook.ts +12 -0
- package/src/flow/actions/call_webhook.ts +133 -0
- package/src/flow/actions/enter_flow.ts +15 -0
- package/src/flow/actions/open_ticket.ts +12 -0
- package/src/flow/actions/play_audio.ts +12 -0
- package/src/flow/actions/remove_contact_groups.ts +66 -0
- package/src/flow/actions/request_optin.ts +12 -0
- package/src/flow/actions/say_msg.ts +12 -0
- package/src/flow/actions/send_broadcast.ts +35 -0
- package/src/flow/actions/send_email.ts +60 -0
- package/src/flow/actions/send_msg.ts +58 -0
- package/src/flow/actions/set_contact_channel.ts +13 -0
- package/src/flow/actions/set_contact_field.ts +13 -0
- package/src/flow/actions/set_contact_language.ts +11 -0
- package/src/flow/actions/set_contact_name.ts +11 -0
- package/src/flow/actions/set_contact_status.ts +11 -0
- package/src/flow/actions/set_run_result.ts +11 -0
- package/src/flow/actions/split_by_expression_example.ts +88 -0
- package/src/flow/actions/start_session.ts +12 -0
- package/src/flow/actions/transfer_airtime.ts +12 -0
- package/src/flow/config.ts +93 -232
- package/src/flow/nodes/execute_actions.ts +5 -0
- package/src/flow/nodes/split_by_airtime.ts +9 -0
- package/src/flow/nodes/split_by_contact_field.ts +7 -0
- package/src/flow/nodes/split_by_expression.ts +7 -0
- package/src/flow/nodes/split_by_groups.ts +7 -0
- package/src/flow/nodes/split_by_random.ts +10 -0
- package/src/flow/nodes/split_by_run_result.ts +7 -0
- package/src/flow/nodes/split_by_scheme.ts +7 -0
- package/src/flow/nodes/split_by_subflow.ts +9 -0
- package/src/flow/nodes/split_by_webhook.ts +19 -0
- package/src/flow/nodes/wait_for_audio.ts +7 -0
- package/src/flow/nodes/wait_for_digits.ts +7 -0
- package/src/flow/nodes/wait_for_image.ts +7 -0
- package/src/flow/nodes/wait_for_location.ts +7 -0
- package/src/flow/nodes/wait_for_menu.ts +7 -0
- package/src/flow/nodes/wait_for_response.ts +7 -0
- package/src/flow/nodes/wait_for_video.ts +7 -0
- package/src/flow/types.ts +352 -0
- package/src/flow/utils.ts +76 -0
- package/src/form/ArrayEditor.ts +240 -0
- package/src/form/BaseListEditor.ts +177 -0
- package/src/form/Checkbox.ts +22 -3
- package/src/form/Completion.ts +6 -0
- package/src/form/FormField.ts +115 -11
- package/src/form/KeyValueEditor.ts +251 -0
- package/src/form/select/Select.ts +105 -32
- package/src/interfaces.ts +7 -2
- package/src/live/ContactChat.ts +3 -97
- package/src/store/flow-definition.d.ts +6 -1
- package/static/api/contacts.json +30 -0
- package/static/api/groups.json +4 -426
- package/static/api/locations.json +24 -0
- package/static/api/media.json +5 -0
- package/static/api/optins.json +16 -0
- package/static/api/orgs.json +13 -0
- package/static/api/topics.json +21 -0
- package/static/api/users.json +26 -0
- package/static/css/temba-components.css +3 -6
- package/temba-modules.ts +9 -2
- package/test/ActionHelper.ts +142 -0
- package/test/actions/add_contact_groups.test.ts +89 -0
- package/test/actions/remove_contact_groups.test.ts +265 -0
- package/test/actions/send_email.test.ts +214 -0
- package/test/actions/send_msg.test.ts +130 -0
- package/test/temba-action-editing-integration.test.ts +240 -0
- package/test/temba-checkbox.test.ts +1 -1
- package/test/temba-field-config.test.ts +152 -0
- package/test/temba-flow-editor-node.test.ts +18 -18
- package/test/temba-node-editor.test.ts +353 -0
- package/test/temba-select.test.ts +234 -0
- package/test-assets/contacts/history.json +11 -33
- package/web-dev-server.config.mjs +34 -0
- package/.github/workflows/coverage.yml +0 -80
- package/demo/sticky-note-demo.html +0 -155
- package/out-tsc/src/flow/EditorNode.js.map +0 -1
- package/out-tsc/src/flow/render.js +0 -358
- package/out-tsc/src/flow/render.js.map +0 -1
- package/out-tsc/test/temba-flow-render.test.js +0 -794
- package/out-tsc/test/temba-flow-render.test.js.map +0 -1
- package/src/flow/render.ts +0 -443
- package/test/temba-flow-render.test.ts +0 -1003
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { fixture, expect } from '@open-wc/testing';
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import { Action, Node } from '../src/store/flow-definition';
|
|
4
|
+
import { assertScreenshot, getClip } from './utils.test';
|
|
5
|
+
import { Editor } from '../src/flow/Editor';
|
|
6
|
+
import '../temba-modules';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generic action test framework
|
|
10
|
+
* Tests the complete action lifecycle: render → edit → save → validate
|
|
11
|
+
*/
|
|
12
|
+
export class ActionTest<T extends Action> {
|
|
13
|
+
constructor(private actionConfig: any, private actionName: string) {}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Renders an action in the flow editor and returns the flow node
|
|
17
|
+
*/
|
|
18
|
+
private async renderAction(action: T): Promise<HTMLElement> {
|
|
19
|
+
const node: Node = {
|
|
20
|
+
uuid: 'test-node',
|
|
21
|
+
actions: [action],
|
|
22
|
+
exits: []
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const mockDefinition = {
|
|
26
|
+
nodes: [node],
|
|
27
|
+
_ui: {
|
|
28
|
+
nodes: {
|
|
29
|
+
[node.uuid]: {
|
|
30
|
+
type: 'execute_actions',
|
|
31
|
+
position: { left: 50, top: 50 }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const editor = (await fixture(html`
|
|
38
|
+
<temba-flow-editor>
|
|
39
|
+
<div id="canvas"></div>
|
|
40
|
+
</temba-flow-editor>
|
|
41
|
+
`)) as Editor;
|
|
42
|
+
|
|
43
|
+
(editor as any).definition = mockDefinition;
|
|
44
|
+
(editor as any).canvasSize = { width: 400, height: 300 };
|
|
45
|
+
await editor.updateComplete;
|
|
46
|
+
|
|
47
|
+
const flowNode = editor.querySelector('temba-flow-node') as HTMLElement;
|
|
48
|
+
expect(flowNode).to.exist;
|
|
49
|
+
|
|
50
|
+
return flowNode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Opens the node editor for an action and returns the editor element
|
|
55
|
+
*/
|
|
56
|
+
private async openNodeEditor(action: T): Promise<HTMLElement> {
|
|
57
|
+
const nodeEditor = (await fixture(html`
|
|
58
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
59
|
+
`)) as HTMLElement;
|
|
60
|
+
|
|
61
|
+
await (nodeEditor as any).updateComplete;
|
|
62
|
+
expect(nodeEditor).to.exist;
|
|
63
|
+
|
|
64
|
+
return nodeEditor;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Takes a screenshot of the dialog container within a node editor
|
|
69
|
+
*/
|
|
70
|
+
private async assertDialogScreenshot(
|
|
71
|
+
el: HTMLElement,
|
|
72
|
+
screenshotName: string
|
|
73
|
+
) {
|
|
74
|
+
const dialog = el.shadowRoot
|
|
75
|
+
.querySelector('temba-dialog')
|
|
76
|
+
.shadowRoot.querySelector('.dialog-container') as HTMLElement;
|
|
77
|
+
await assertScreenshot(screenshotName, getClip(dialog));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Complete test for an action configuration
|
|
82
|
+
* 1. Renders the action in a flow node (with screenshot)
|
|
83
|
+
* 2. Opens the node editor (with screenshot)
|
|
84
|
+
* 3. Simulates save and validates round-trip conversion
|
|
85
|
+
*/
|
|
86
|
+
async testAction(action: T, testName: string) {
|
|
87
|
+
it(`${testName}`, async () => {
|
|
88
|
+
// Step 1: Render action in flow node
|
|
89
|
+
const flowNode = await this.renderAction(action);
|
|
90
|
+
expect(flowNode.querySelector('.body')).to.exist;
|
|
91
|
+
await assertScreenshot(
|
|
92
|
+
`actions/${this.actionName}/render/${testName}`,
|
|
93
|
+
getClip(flowNode)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Step 2: Open node editor
|
|
97
|
+
const nodeEditor = await this.openNodeEditor(action);
|
|
98
|
+
await this.assertDialogScreenshot(
|
|
99
|
+
nodeEditor,
|
|
100
|
+
`actions/${this.actionName}/editor/${testName}`
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Step 3: Test round-trip conversion (simulates save workflow)
|
|
104
|
+
if (this.actionConfig.toFormData && this.actionConfig.fromFormData) {
|
|
105
|
+
const formData = this.actionConfig.toFormData(action);
|
|
106
|
+
const convertedAction = this.actionConfig.fromFormData(formData) as T;
|
|
107
|
+
|
|
108
|
+
// Validate the round trip worked
|
|
109
|
+
expect(convertedAction.uuid).to.equal(action.uuid);
|
|
110
|
+
expect(convertedAction.type).to.equal(action.type);
|
|
111
|
+
|
|
112
|
+
// Validate the converted action
|
|
113
|
+
if (this.actionConfig.validate) {
|
|
114
|
+
const validation = this.actionConfig.validate(convertedAction);
|
|
115
|
+
expect(validation.valid).to.be.true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Run basic property tests
|
|
123
|
+
*/
|
|
124
|
+
testBasicProperties() {
|
|
125
|
+
it('has correct basic properties', () => {
|
|
126
|
+
expect(this.actionConfig.name).to.be.a('string');
|
|
127
|
+
expect(this.actionConfig.color).to.exist;
|
|
128
|
+
|
|
129
|
+
// toFormData and fromFormData are optional - only needed for complex data transformations
|
|
130
|
+
if (this.actionConfig.toFormData) {
|
|
131
|
+
expect(this.actionConfig.toFormData).to.be.a('function');
|
|
132
|
+
}
|
|
133
|
+
if (this.actionConfig.fromFormData) {
|
|
134
|
+
expect(this.actionConfig.fromFormData).to.be.a('function');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (this.actionConfig.validate) {
|
|
138
|
+
expect(this.actionConfig.validate).to.be.a('function');
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { add_contact_groups } from '../../src/flow/actions/add_contact_groups';
|
|
3
|
+
import { AddToGroup } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the add_contact_groups action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('add_contact_groups action config', () => {
|
|
10
|
+
const helper = new ActionTest(add_contact_groups, 'add_contact_groups');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(add_contact_groups.name).to.equal('Add to Group');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'add_contact_groups',
|
|
25
|
+
groups: [{ uuid: 'group-1', name: 'VIP Customers' }]
|
|
26
|
+
} as AddToGroup,
|
|
27
|
+
'single-group'
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
helper.testAction(
|
|
31
|
+
{
|
|
32
|
+
uuid: 'test-action-2',
|
|
33
|
+
type: 'add_contact_groups',
|
|
34
|
+
groups: [
|
|
35
|
+
{ uuid: 'group-1', name: 'VIP Customers' },
|
|
36
|
+
{ uuid: 'group-2', name: 'Newsletter Subscribers' },
|
|
37
|
+
{ uuid: 'group-3', name: 'Beta Testers' }
|
|
38
|
+
]
|
|
39
|
+
} as AddToGroup,
|
|
40
|
+
'multiple-groups'
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
helper.testAction(
|
|
44
|
+
{
|
|
45
|
+
uuid: 'test-action-3',
|
|
46
|
+
type: 'add_contact_groups',
|
|
47
|
+
groups: [
|
|
48
|
+
{
|
|
49
|
+
uuid: 'group-1',
|
|
50
|
+
name: 'Very Long Group Name That Might Wrap to Multiple Lines'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
uuid: 'group-2',
|
|
54
|
+
name: 'Another Extremely Long Group Name for Testing Layout'
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
} as AddToGroup,
|
|
58
|
+
'long-group-names'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
helper.testAction(
|
|
62
|
+
{
|
|
63
|
+
uuid: 'test-action-4',
|
|
64
|
+
type: 'add_contact_groups',
|
|
65
|
+
groups: [
|
|
66
|
+
{ uuid: 'group-1', name: 'Sales Team' },
|
|
67
|
+
{ uuid: 'group-2', name: 'Marketing Team' },
|
|
68
|
+
{ uuid: 'group-3', name: 'Support Team' },
|
|
69
|
+
{ uuid: 'group-4', name: 'Development Team' },
|
|
70
|
+
{ uuid: 'group-5', name: 'QA Team' }
|
|
71
|
+
]
|
|
72
|
+
} as AddToGroup,
|
|
73
|
+
'many-groups'
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
helper.testAction(
|
|
77
|
+
{
|
|
78
|
+
uuid: 'test-action-5',
|
|
79
|
+
type: 'add_contact_groups',
|
|
80
|
+
groups: [
|
|
81
|
+
{ uuid: 'group-1', name: 'Customers - Premium Plan (Monthly)' },
|
|
82
|
+
{ uuid: 'group-2', name: 'Customers - Enterprise Plan (Annual)' },
|
|
83
|
+
{ uuid: 'group-3', name: 'Trial Users - 30 Day Free Trial' }
|
|
84
|
+
]
|
|
85
|
+
} as AddToGroup,
|
|
86
|
+
'descriptive-group-names'
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { remove_contact_groups } from '../../src/flow/actions/remove_contact_groups';
|
|
3
|
+
import { RemoveFromGroup } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the remove_contact_groups action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('remove_contact_groups action config', () => {
|
|
10
|
+
const helper = new ActionTest(remove_contact_groups, 'remove_contact_groups');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(remove_contact_groups.name).to.equal('Remove from Group');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'remove_contact_groups',
|
|
25
|
+
groups: [
|
|
26
|
+
{
|
|
27
|
+
uuid: 'group-1',
|
|
28
|
+
name: 'VIP Customers',
|
|
29
|
+
status: 'ready',
|
|
30
|
+
system: false,
|
|
31
|
+
query: '',
|
|
32
|
+
count: 150
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
all_groups: false
|
|
36
|
+
} as RemoveFromGroup,
|
|
37
|
+
'single-group'
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
helper.testAction(
|
|
41
|
+
{
|
|
42
|
+
uuid: 'test-action-2',
|
|
43
|
+
type: 'remove_contact_groups',
|
|
44
|
+
groups: [
|
|
45
|
+
{
|
|
46
|
+
uuid: 'group-1',
|
|
47
|
+
name: 'Newsletter Subscribers',
|
|
48
|
+
status: 'ready',
|
|
49
|
+
system: false,
|
|
50
|
+
query: '',
|
|
51
|
+
count: 1250
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
uuid: 'group-2',
|
|
55
|
+
name: 'Beta Testers',
|
|
56
|
+
status: 'ready',
|
|
57
|
+
system: false,
|
|
58
|
+
query: '',
|
|
59
|
+
count: 45
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
uuid: 'group-3',
|
|
63
|
+
name: 'Inactive Users',
|
|
64
|
+
status: 'ready',
|
|
65
|
+
system: false,
|
|
66
|
+
query: '',
|
|
67
|
+
count: 300
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
all_groups: false
|
|
71
|
+
} as RemoveFromGroup,
|
|
72
|
+
'multiple-groups'
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
helper.testAction(
|
|
76
|
+
{
|
|
77
|
+
uuid: 'test-action-3',
|
|
78
|
+
type: 'remove_contact_groups',
|
|
79
|
+
groups: [],
|
|
80
|
+
all_groups: true
|
|
81
|
+
} as RemoveFromGroup,
|
|
82
|
+
'remove-from-all-groups'
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
helper.testAction(
|
|
86
|
+
{
|
|
87
|
+
uuid: 'test-action-4',
|
|
88
|
+
type: 'remove_contact_groups',
|
|
89
|
+
groups: [
|
|
90
|
+
{
|
|
91
|
+
uuid: 'group-1',
|
|
92
|
+
name: 'Customers - Premium Subscription (Annual Billing)',
|
|
93
|
+
status: 'ready',
|
|
94
|
+
system: false,
|
|
95
|
+
query: '',
|
|
96
|
+
count: 89
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
uuid: 'group-2',
|
|
100
|
+
name: 'Users - Trial Period Expired (30+ Days)',
|
|
101
|
+
status: 'ready',
|
|
102
|
+
system: false,
|
|
103
|
+
query: '',
|
|
104
|
+
count: 234
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
all_groups: false
|
|
108
|
+
} as RemoveFromGroup,
|
|
109
|
+
'long-descriptive-group-names'
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
helper.testAction(
|
|
113
|
+
{
|
|
114
|
+
uuid: 'test-action-5',
|
|
115
|
+
type: 'remove_contact_groups',
|
|
116
|
+
groups: [
|
|
117
|
+
{
|
|
118
|
+
uuid: 'group-1',
|
|
119
|
+
name: 'Sales Team',
|
|
120
|
+
status: 'ready',
|
|
121
|
+
system: false,
|
|
122
|
+
query: '',
|
|
123
|
+
count: 12
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
uuid: 'group-2',
|
|
127
|
+
name: 'Marketing Team',
|
|
128
|
+
status: 'ready',
|
|
129
|
+
system: false,
|
|
130
|
+
query: '',
|
|
131
|
+
count: 8
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
uuid: 'group-3',
|
|
135
|
+
name: 'Support Team',
|
|
136
|
+
status: 'ready',
|
|
137
|
+
system: false,
|
|
138
|
+
query: '',
|
|
139
|
+
count: 15
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
uuid: 'group-4',
|
|
143
|
+
name: 'Development Team',
|
|
144
|
+
status: 'ready',
|
|
145
|
+
system: false,
|
|
146
|
+
query: '',
|
|
147
|
+
count: 25
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
uuid: 'group-5',
|
|
151
|
+
name: 'QA Team',
|
|
152
|
+
status: 'ready',
|
|
153
|
+
system: false,
|
|
154
|
+
query: '',
|
|
155
|
+
count: 6
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
uuid: 'group-6',
|
|
159
|
+
name: 'Management Team',
|
|
160
|
+
status: 'ready',
|
|
161
|
+
system: false,
|
|
162
|
+
query: '',
|
|
163
|
+
count: 4
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
all_groups: false
|
|
167
|
+
} as RemoveFromGroup,
|
|
168
|
+
'many-groups'
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
helper.testAction(
|
|
172
|
+
{
|
|
173
|
+
uuid: 'test-action-6',
|
|
174
|
+
type: 'remove_contact_groups',
|
|
175
|
+
groups: [
|
|
176
|
+
{
|
|
177
|
+
uuid: 'group-1',
|
|
178
|
+
name: 'Unsubscribed Users',
|
|
179
|
+
status: 'ready',
|
|
180
|
+
system: false,
|
|
181
|
+
query: '',
|
|
182
|
+
count: 567
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
uuid: 'group-2',
|
|
186
|
+
name: 'Bounced Email Addresses',
|
|
187
|
+
status: 'ready',
|
|
188
|
+
system: false,
|
|
189
|
+
query: '',
|
|
190
|
+
count: 89
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
all_groups: false
|
|
194
|
+
} as RemoveFromGroup,
|
|
195
|
+
'cleanup-groups'
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('validation edge cases', () => {
|
|
200
|
+
it('fails validation when no groups selected and all_groups is false', () => {
|
|
201
|
+
const action: RemoveFromGroup = {
|
|
202
|
+
uuid: 'test-action',
|
|
203
|
+
type: 'remove_contact_groups',
|
|
204
|
+
groups: [],
|
|
205
|
+
all_groups: false
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const result = remove_contact_groups.validate(action);
|
|
209
|
+
expect(result.valid).to.be.false;
|
|
210
|
+
expect(result.errors.groups).to.equal(
|
|
211
|
+
'At least one group must be selected or check "Remove from All Groups"'
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('fails validation when groups is undefined and all_groups is false', () => {
|
|
216
|
+
const action: RemoveFromGroup = {
|
|
217
|
+
uuid: 'test-action',
|
|
218
|
+
type: 'remove_contact_groups',
|
|
219
|
+
groups: undefined as any,
|
|
220
|
+
all_groups: false
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const result = remove_contact_groups.validate(action);
|
|
224
|
+
expect(result.valid).to.be.false;
|
|
225
|
+
expect(result.errors.groups).to.equal(
|
|
226
|
+
'At least one group must be selected or check "Remove from All Groups"'
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('passes validation when all_groups is true even with empty groups', () => {
|
|
231
|
+
const action: RemoveFromGroup = {
|
|
232
|
+
uuid: 'test-action',
|
|
233
|
+
type: 'remove_contact_groups',
|
|
234
|
+
groups: [],
|
|
235
|
+
all_groups: true
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const result = remove_contact_groups.validate(action);
|
|
239
|
+
expect(result.valid).to.be.true;
|
|
240
|
+
expect(Object.keys(result.errors)).to.have.length(0);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('passes validation when groups are provided and all_groups is false', () => {
|
|
244
|
+
const action: RemoveFromGroup = {
|
|
245
|
+
uuid: 'test-action',
|
|
246
|
+
type: 'remove_contact_groups',
|
|
247
|
+
groups: [
|
|
248
|
+
{
|
|
249
|
+
uuid: 'group-1',
|
|
250
|
+
name: 'Test Group',
|
|
251
|
+
status: 'ready',
|
|
252
|
+
system: false,
|
|
253
|
+
query: '',
|
|
254
|
+
count: 10
|
|
255
|
+
}
|
|
256
|
+
],
|
|
257
|
+
all_groups: false
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const result = remove_contact_groups.validate(action);
|
|
261
|
+
expect(result.valid).to.be.true;
|
|
262
|
+
expect(Object.keys(result.errors)).to.have.length(0);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
});
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { send_email } from '../../src/flow/actions/send_email';
|
|
3
|
+
import { SendEmail } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the send_email action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('send_email action config', () => {
|
|
10
|
+
const helper = new ActionTest(send_email, 'send_email');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(send_email.name).to.equal('Send Email');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'send_email',
|
|
25
|
+
addresses: ['user@example.com'],
|
|
26
|
+
subject: 'Welcome!',
|
|
27
|
+
body: 'Thank you for signing up.'
|
|
28
|
+
} as SendEmail,
|
|
29
|
+
'simple-email'
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
helper.testAction(
|
|
33
|
+
{
|
|
34
|
+
uuid: 'test-action-2',
|
|
35
|
+
type: 'send_email',
|
|
36
|
+
addresses: [
|
|
37
|
+
'user1@example.com',
|
|
38
|
+
'user2@example.com',
|
|
39
|
+
'user3@example.com'
|
|
40
|
+
],
|
|
41
|
+
subject: 'Multiple Recipients',
|
|
42
|
+
body: 'This email is sent to multiple recipients.'
|
|
43
|
+
} as SendEmail,
|
|
44
|
+
'multiple-recipients'
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
helper.testAction(
|
|
48
|
+
{
|
|
49
|
+
uuid: 'test-action-3',
|
|
50
|
+
type: 'send_email',
|
|
51
|
+
addresses: ['admin@company.com'],
|
|
52
|
+
subject: 'Multi-line Email Content',
|
|
53
|
+
body: 'Dear User,\n\nThis is a multi-line email body.\n\nIt contains multiple paragraphs and line breaks.\n\nBest regards,\nThe Team'
|
|
54
|
+
} as SendEmail,
|
|
55
|
+
'multiline-body'
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
helper.testAction(
|
|
59
|
+
{
|
|
60
|
+
uuid: 'test-action-4',
|
|
61
|
+
type: 'send_email',
|
|
62
|
+
addresses: ['support@company.com'],
|
|
63
|
+
subject: 'Email with expressions',
|
|
64
|
+
body: 'Hello @contact.name,\n\nYour order @run.results.order_id has been processed.\n\nThank you!'
|
|
65
|
+
} as SendEmail,
|
|
66
|
+
'with-expressions'
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
helper.testAction(
|
|
70
|
+
{
|
|
71
|
+
uuid: 'test-action-5',
|
|
72
|
+
type: 'send_email',
|
|
73
|
+
addresses: ['notification@company.com'],
|
|
74
|
+
subject:
|
|
75
|
+
'Very Long Subject Line That Could Potentially Exceed Normal Length Limits To Test Subject Field Handling',
|
|
76
|
+
body: 'Short body content.'
|
|
77
|
+
} as SendEmail,
|
|
78
|
+
'long-subject'
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
helper.testAction(
|
|
82
|
+
{
|
|
83
|
+
uuid: 'test-action-6',
|
|
84
|
+
type: 'send_email',
|
|
85
|
+
addresses: [
|
|
86
|
+
'customer.service@department.company.com',
|
|
87
|
+
'technical.support@department.company.com',
|
|
88
|
+
'billing.inquiries@department.company.com'
|
|
89
|
+
],
|
|
90
|
+
subject: 'Customer Support Escalation',
|
|
91
|
+
body: 'Customer Name: @contact.name\nTicket ID: @run.results.ticket_id\n\nIssue Description:\n@run.results.issue_description\n\nPriority: High\nCategory: @run.results.category\n\nPlease respond within 2 hours.'
|
|
92
|
+
} as SendEmail,
|
|
93
|
+
'complex-business-email'
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
helper.testAction(
|
|
97
|
+
{
|
|
98
|
+
uuid: 'test-action-7',
|
|
99
|
+
type: 'send_email',
|
|
100
|
+
addresses: ['alerts@company.com'],
|
|
101
|
+
subject: '',
|
|
102
|
+
body: 'Email with empty subject'
|
|
103
|
+
} as SendEmail,
|
|
104
|
+
'empty-subject'
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
helper.testAction(
|
|
108
|
+
{
|
|
109
|
+
uuid: 'test-action-8',
|
|
110
|
+
type: 'send_email',
|
|
111
|
+
addresses: ['test@company.com'],
|
|
112
|
+
subject: 'Empty body test',
|
|
113
|
+
body: ''
|
|
114
|
+
} as SendEmail,
|
|
115
|
+
'empty-body'
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('validation edge cases', () => {
|
|
120
|
+
it('fails validation for empty addresses array', () => {
|
|
121
|
+
const action: SendEmail = {
|
|
122
|
+
uuid: 'test-action',
|
|
123
|
+
type: 'send_email',
|
|
124
|
+
addresses: [],
|
|
125
|
+
subject: 'Test Subject',
|
|
126
|
+
body: 'Test Body'
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const result = send_email.validate(action);
|
|
130
|
+
expect(result.valid).to.be.false;
|
|
131
|
+
expect(result.errors.addresses).to.equal(
|
|
132
|
+
'At least one recipient email address is required'
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('fails validation for null addresses', () => {
|
|
137
|
+
const action: SendEmail = {
|
|
138
|
+
uuid: 'test-action',
|
|
139
|
+
type: 'send_email',
|
|
140
|
+
addresses: null as any,
|
|
141
|
+
subject: 'Test Subject',
|
|
142
|
+
body: 'Test Body'
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const result = send_email.validate(action);
|
|
146
|
+
expect(result.valid).to.be.false;
|
|
147
|
+
expect(result.errors.addresses).to.equal(
|
|
148
|
+
'At least one recipient email address is required'
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('fails validation for undefined addresses', () => {
|
|
153
|
+
const action: SendEmail = {
|
|
154
|
+
uuid: 'test-action',
|
|
155
|
+
type: 'send_email',
|
|
156
|
+
addresses: undefined as any,
|
|
157
|
+
subject: 'Test Subject',
|
|
158
|
+
body: 'Test Body'
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const result = send_email.validate(action);
|
|
162
|
+
expect(result.valid).to.be.false;
|
|
163
|
+
expect(result.errors.addresses).to.equal(
|
|
164
|
+
'At least one recipient email address is required'
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('passes validation with valid email addresses', () => {
|
|
169
|
+
const action: SendEmail = {
|
|
170
|
+
uuid: 'test-action',
|
|
171
|
+
type: 'send_email',
|
|
172
|
+
addresses: ['valid@example.com'],
|
|
173
|
+
subject: 'Test Subject',
|
|
174
|
+
body: 'Test Body'
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const result = send_email.validate(action);
|
|
178
|
+
expect(result.valid).to.be.true;
|
|
179
|
+
expect(Object.keys(result.errors)).to.have.length(0);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('passes validation with multiple email addresses', () => {
|
|
183
|
+
const action: SendEmail = {
|
|
184
|
+
uuid: 'test-action',
|
|
185
|
+
type: 'send_email',
|
|
186
|
+
addresses: [
|
|
187
|
+
'user1@example.com',
|
|
188
|
+
'user2@example.com',
|
|
189
|
+
'user3@example.com'
|
|
190
|
+
],
|
|
191
|
+
subject: 'Test Subject',
|
|
192
|
+
body: 'Test Body'
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const result = send_email.validate(action);
|
|
196
|
+
expect(result.valid).to.be.true;
|
|
197
|
+
expect(Object.keys(result.errors)).to.have.length(0);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('passes validation with empty subject and body', () => {
|
|
201
|
+
const action: SendEmail = {
|
|
202
|
+
uuid: 'test-action',
|
|
203
|
+
type: 'send_email',
|
|
204
|
+
addresses: ['test@example.com'],
|
|
205
|
+
subject: '',
|
|
206
|
+
body: ''
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const result = send_email.validate(action);
|
|
210
|
+
expect(result.valid).to.be.true;
|
|
211
|
+
expect(Object.keys(result.errors)).to.have.length(0);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|