@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,353 @@
|
|
|
1
|
+
import '../temba-modules';
|
|
2
|
+
import { html, fixture, expect } from '@open-wc/testing';
|
|
3
|
+
import { assertScreenshot, getClip } from './utils.test';
|
|
4
|
+
|
|
5
|
+
// Define interface for NodeEditor component
|
|
6
|
+
interface NodeEditorElement extends HTMLElement {
|
|
7
|
+
action?: any;
|
|
8
|
+
node?: any;
|
|
9
|
+
nodeUI?: any;
|
|
10
|
+
isOpen?: boolean;
|
|
11
|
+
updateComplete: Promise<boolean>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const assertDialogScreenshot = async (
|
|
15
|
+
el: NodeEditorElement,
|
|
16
|
+
screenshotName: string
|
|
17
|
+
) => {
|
|
18
|
+
const dialog = el.shadowRoot
|
|
19
|
+
.querySelector('temba-dialog')
|
|
20
|
+
.shadowRoot.querySelector('.dialog-container') as HTMLElement;
|
|
21
|
+
await assertScreenshot(screenshotName, getClip(dialog));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('temba-node-editor', () => {
|
|
25
|
+
it('can be created', async () => {
|
|
26
|
+
const el = (await fixture(html`
|
|
27
|
+
<temba-node-editor .isOpen=${true}></temba-node-editor>
|
|
28
|
+
`)) as NodeEditorElement;
|
|
29
|
+
|
|
30
|
+
expect(el).to.exist;
|
|
31
|
+
expect(el.tagName).to.equal('TEMBA-NODE-EDITOR');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renders send_msg action', async () => {
|
|
35
|
+
const action = {
|
|
36
|
+
uuid: 'test-action-uuid',
|
|
37
|
+
type: 'send_msg',
|
|
38
|
+
text: 'Hello world',
|
|
39
|
+
quick_replies: []
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const el = (await fixture(html`
|
|
43
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
44
|
+
`)) as NodeEditorElement;
|
|
45
|
+
|
|
46
|
+
await el.updateComplete;
|
|
47
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
48
|
+
expect(el.action).to.equal(action);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('renders set_run_result action', async () => {
|
|
52
|
+
const action = {
|
|
53
|
+
uuid: 'test-action-uuid',
|
|
54
|
+
type: 'set_run_result',
|
|
55
|
+
name: 'result_name',
|
|
56
|
+
value: 'result_value'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const el = (await fixture(html`
|
|
60
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
61
|
+
`)) as NodeEditorElement;
|
|
62
|
+
|
|
63
|
+
await el.updateComplete;
|
|
64
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
65
|
+
expect(el.action).to.equal(action);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('renders set_contact_field action', async () => {
|
|
69
|
+
const action = {
|
|
70
|
+
uuid: 'test-action-uuid',
|
|
71
|
+
type: 'set_contact_field',
|
|
72
|
+
field: { key: 'age', name: 'Age' },
|
|
73
|
+
value: '25'
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const el = (await fixture(html`
|
|
77
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
78
|
+
`)) as NodeEditorElement;
|
|
79
|
+
|
|
80
|
+
await el.updateComplete;
|
|
81
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
82
|
+
expect(el.action).to.equal(action);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('renders add_contact_groups action', async () => {
|
|
86
|
+
const action = {
|
|
87
|
+
uuid: 'test-action-uuid',
|
|
88
|
+
type: 'add_contact_groups',
|
|
89
|
+
groups: [{ uuid: 'group-1', name: 'Test Group' }]
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const el = (await fixture(html`
|
|
93
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
94
|
+
`)) as NodeEditorElement;
|
|
95
|
+
|
|
96
|
+
await el.updateComplete;
|
|
97
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
98
|
+
expect(el.action).to.equal(action);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('renders enter_flow action', async () => {
|
|
102
|
+
const action = {
|
|
103
|
+
uuid: 'test-action-uuid',
|
|
104
|
+
type: 'enter_flow',
|
|
105
|
+
flow: { uuid: 'flow-1', name: 'Sub Flow' }
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const el = (await fixture(html`
|
|
109
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
110
|
+
`)) as NodeEditorElement;
|
|
111
|
+
|
|
112
|
+
await el.updateComplete;
|
|
113
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
114
|
+
expect(el.action).to.equal(action);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('renders node with router configuration', async () => {
|
|
118
|
+
const node = {
|
|
119
|
+
uuid: 'test-node-uuid',
|
|
120
|
+
actions: [],
|
|
121
|
+
exits: [{ uuid: 'exit-1', name: 'Default' }],
|
|
122
|
+
router: {
|
|
123
|
+
type: 'switch',
|
|
124
|
+
result_name: 'result',
|
|
125
|
+
categories: [{ uuid: 'cat-1', name: 'Category 1', exit_uuid: 'exit-1' }]
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const nodeUI = {
|
|
130
|
+
type: 'split_by_expression',
|
|
131
|
+
position: { left: 100, top: 100 }
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const el = (await fixture(html`
|
|
135
|
+
<temba-node-editor
|
|
136
|
+
.node=${node}
|
|
137
|
+
.nodeUI=${nodeUI}
|
|
138
|
+
.isOpen=${true}
|
|
139
|
+
></temba-node-editor>
|
|
140
|
+
`)) as NodeEditorElement;
|
|
141
|
+
|
|
142
|
+
await el.updateComplete;
|
|
143
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
144
|
+
expect(el.node).to.equal(node);
|
|
145
|
+
expect(el.nodeUI).to.equal(nodeUI);
|
|
146
|
+
|
|
147
|
+
await assertDialogScreenshot(el, 'editor/router');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('renders node with wait configuration', async () => {
|
|
151
|
+
const node = {
|
|
152
|
+
uuid: 'test-node-uuid',
|
|
153
|
+
actions: [],
|
|
154
|
+
exits: [{ uuid: 'exit-1', name: 'Default' }],
|
|
155
|
+
wait: {
|
|
156
|
+
type: 'msg'
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const nodeUI = {
|
|
161
|
+
type: 'wait_for_response',
|
|
162
|
+
position: { left: 100, top: 100 }
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const el = (await fixture(html`
|
|
166
|
+
<temba-node-editor
|
|
167
|
+
.node=${node}
|
|
168
|
+
.nodeUI=${nodeUI}
|
|
169
|
+
.isOpen=${true}
|
|
170
|
+
></temba-node-editor>
|
|
171
|
+
`)) as NodeEditorElement;
|
|
172
|
+
|
|
173
|
+
await el.updateComplete;
|
|
174
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
175
|
+
expect(el.node).to.equal(node);
|
|
176
|
+
expect(el.nodeUI).to.equal(nodeUI);
|
|
177
|
+
|
|
178
|
+
await assertDialogScreenshot(el, 'editor/wait');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('handles different button actions', async () => {
|
|
182
|
+
const action = {
|
|
183
|
+
uuid: 'test-action-uuid',
|
|
184
|
+
type: 'send_msg',
|
|
185
|
+
text: 'Hello world',
|
|
186
|
+
quick_replies: []
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const el = (await fixture(html`
|
|
190
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
191
|
+
`)) as NodeEditorElement;
|
|
192
|
+
|
|
193
|
+
await el.updateComplete;
|
|
194
|
+
|
|
195
|
+
let saveEventFired = false;
|
|
196
|
+
let cancelEventFired = false;
|
|
197
|
+
|
|
198
|
+
el.addEventListener('temba-action-saved', () => {
|
|
199
|
+
saveEventFired = true;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
el.addEventListener('temba-node-edit-cancelled', () => {
|
|
203
|
+
cancelEventFired = true;
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Get the dialog element inside the node editor
|
|
207
|
+
const dialog = el.shadowRoot!.querySelector('temba-dialog');
|
|
208
|
+
expect(dialog).to.not.be.null;
|
|
209
|
+
|
|
210
|
+
// Test Save button by dispatching event on the dialog
|
|
211
|
+
const saveEvent = new CustomEvent('temba-button-clicked', {
|
|
212
|
+
detail: { button: { name: 'Save' } },
|
|
213
|
+
bubbles: true
|
|
214
|
+
});
|
|
215
|
+
dialog!.dispatchEvent(saveEvent);
|
|
216
|
+
expect(saveEventFired).to.equal(true);
|
|
217
|
+
|
|
218
|
+
// Reset for cancel test
|
|
219
|
+
saveEventFired = false;
|
|
220
|
+
|
|
221
|
+
// Test Cancel button
|
|
222
|
+
const cancelEvent = new CustomEvent('temba-button-clicked', {
|
|
223
|
+
detail: { button: { name: 'Cancel' } },
|
|
224
|
+
bubbles: true
|
|
225
|
+
});
|
|
226
|
+
dialog!.dispatchEvent(cancelEvent);
|
|
227
|
+
expect(cancelEventFired).to.equal(true);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('handles property updates', async () => {
|
|
231
|
+
const el = (await fixture(html`
|
|
232
|
+
<temba-node-editor .isOpen=${true}></temba-node-editor>
|
|
233
|
+
`)) as NodeEditorElement;
|
|
234
|
+
|
|
235
|
+
// Test action property update
|
|
236
|
+
const action = {
|
|
237
|
+
uuid: 'test-action-uuid',
|
|
238
|
+
type: 'send_msg',
|
|
239
|
+
text: 'Hello world',
|
|
240
|
+
quick_replies: []
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
el.action = action;
|
|
244
|
+
await el.updateComplete;
|
|
245
|
+
expect(el.action).to.equal(action);
|
|
246
|
+
|
|
247
|
+
// Test node property update
|
|
248
|
+
const node = {
|
|
249
|
+
uuid: 'test-node-uuid',
|
|
250
|
+
actions: [],
|
|
251
|
+
exits: []
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
el.node = node;
|
|
255
|
+
await el.updateComplete;
|
|
256
|
+
expect(el.node).to.equal(node);
|
|
257
|
+
|
|
258
|
+
// Test nodeUI property update
|
|
259
|
+
const nodeUI = {
|
|
260
|
+
type: 'execute_actions',
|
|
261
|
+
position: { left: 100, top: 100 }
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
el.nodeUI = nodeUI;
|
|
265
|
+
await el.updateComplete;
|
|
266
|
+
expect(el.nodeUI).to.equal(nodeUI);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('handles form submission events', async () => {
|
|
270
|
+
const action = {
|
|
271
|
+
uuid: 'test-action-uuid',
|
|
272
|
+
type: 'send_msg',
|
|
273
|
+
text: 'Hello world',
|
|
274
|
+
quick_replies: []
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const el = (await fixture(html`
|
|
278
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
279
|
+
`)) as NodeEditorElement;
|
|
280
|
+
|
|
281
|
+
await el.updateComplete;
|
|
282
|
+
|
|
283
|
+
// Since the form submission handling is complex and involves internal components,
|
|
284
|
+
// we'll just verify the component renders without errors and has the expected structure
|
|
285
|
+
const shadowRoot = el.shadowRoot;
|
|
286
|
+
expect(shadowRoot).to.not.be.null;
|
|
287
|
+
|
|
288
|
+
// Verify dialog is present
|
|
289
|
+
const dialog = shadowRoot!.querySelector('temba-dialog');
|
|
290
|
+
expect(dialog).to.not.be.null;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('handles form validation', async () => {
|
|
294
|
+
const action = {
|
|
295
|
+
uuid: 'test-action-uuid',
|
|
296
|
+
type: 'send_msg',
|
|
297
|
+
text: 'Hello world',
|
|
298
|
+
quick_replies: []
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const el = (await fixture(html`
|
|
302
|
+
<temba-node-editor .action=${action} .isOpen=${true}></temba-node-editor>
|
|
303
|
+
`)) as NodeEditorElement;
|
|
304
|
+
|
|
305
|
+
await el.updateComplete;
|
|
306
|
+
|
|
307
|
+
// Test that the component renders form elements
|
|
308
|
+
const shadowRoot = el.shadowRoot;
|
|
309
|
+
expect(shadowRoot).to.not.be.null;
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('renders different action types correctly', async () => {
|
|
313
|
+
const actionTypes = [
|
|
314
|
+
{
|
|
315
|
+
type: 'send_msg',
|
|
316
|
+
data: { text: 'Message', quick_replies: [] }
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
type: 'set_run_result',
|
|
320
|
+
data: { name: 'result', value: 'value' }
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
type: 'set_contact_name',
|
|
324
|
+
data: { name: 'John Doe' }
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
type: 'set_contact_language',
|
|
328
|
+
data: { language: 'eng' }
|
|
329
|
+
}
|
|
330
|
+
];
|
|
331
|
+
|
|
332
|
+
for (const actionType of actionTypes) {
|
|
333
|
+
const action = {
|
|
334
|
+
uuid: `test-${actionType.type}`,
|
|
335
|
+
type: actionType.type,
|
|
336
|
+
...actionType.data
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const el = (await fixture(html`
|
|
340
|
+
<temba-node-editor
|
|
341
|
+
.action=${action}
|
|
342
|
+
.isOpen=${true}
|
|
343
|
+
></temba-node-editor>
|
|
344
|
+
`)) as NodeEditorElement;
|
|
345
|
+
|
|
346
|
+
await el.updateComplete;
|
|
347
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
348
|
+
expect(el.action.type).to.equal(actionType.type);
|
|
349
|
+
|
|
350
|
+
await assertDialogScreenshot(el, `editor/${actionType.type}`);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
});
|
|
@@ -573,6 +573,133 @@ describe('temba-select', () => {
|
|
|
573
573
|
});
|
|
574
574
|
});
|
|
575
575
|
|
|
576
|
+
describe('emails functionality', () => {
|
|
577
|
+
it('only allows valid email addresses as options', async () => {
|
|
578
|
+
const select = await createSelect(
|
|
579
|
+
clock,
|
|
580
|
+
getSelectHTML([], {
|
|
581
|
+
placeholder: 'Enter email addresses',
|
|
582
|
+
searchable: true,
|
|
583
|
+
emails: true
|
|
584
|
+
})
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
// Try typing an invalid email - should not show as option
|
|
588
|
+
await typeInto('temba-select', 'invalid-email', false, false);
|
|
589
|
+
await clock.runAll();
|
|
590
|
+
await select.updateComplete;
|
|
591
|
+
|
|
592
|
+
let visibleOptions = select.shadowRoot.querySelectorAll(
|
|
593
|
+
'.option:not(.header)'
|
|
594
|
+
);
|
|
595
|
+
expect(visibleOptions.length).to.equal(0);
|
|
596
|
+
|
|
597
|
+
// Clear input
|
|
598
|
+
select.input = '';
|
|
599
|
+
await select.updateComplete;
|
|
600
|
+
|
|
601
|
+
// Try typing a valid email - should show as option
|
|
602
|
+
await typeInto('temba-select', 'test@example.com', false, false);
|
|
603
|
+
await clock.runAll();
|
|
604
|
+
await select.updateComplete;
|
|
605
|
+
await openSelect(clock, select);
|
|
606
|
+
|
|
607
|
+
const optionsComponent = select.shadowRoot.querySelector(
|
|
608
|
+
'temba-options'
|
|
609
|
+
) as any;
|
|
610
|
+
visibleOptions = optionsComponent.shadowRoot.querySelectorAll(
|
|
611
|
+
'.option:not(.header)'
|
|
612
|
+
);
|
|
613
|
+
expect(visibleOptions.length).to.equal(1);
|
|
614
|
+
expect(visibleOptions[0].textContent).to.contain('test@example.com');
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('behaves as multi-select when emails is true', async () => {
|
|
618
|
+
const select = await createSelect(
|
|
619
|
+
clock,
|
|
620
|
+
getSelectHTML([], {
|
|
621
|
+
placeholder: 'Enter email addresses',
|
|
622
|
+
searchable: true,
|
|
623
|
+
emails: true
|
|
624
|
+
})
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
// Add first email
|
|
628
|
+
await typeInto('temba-select', 'first@example.com', false, false);
|
|
629
|
+
await clock.runAll();
|
|
630
|
+
await select.updateComplete;
|
|
631
|
+
|
|
632
|
+
// Click on the first option to select it using the standard helper
|
|
633
|
+
await openAndClick(clock, select, 0);
|
|
634
|
+
|
|
635
|
+
expect(select.values.length).to.equal(1);
|
|
636
|
+
expect(select.values[0].value).to.equal('first@example.com');
|
|
637
|
+
|
|
638
|
+
// Add second email
|
|
639
|
+
await typeInto('temba-select', 'second@example.com', false, false);
|
|
640
|
+
await clock.runAll();
|
|
641
|
+
await select.updateComplete;
|
|
642
|
+
|
|
643
|
+
// Click on the second option to select it using the standard helper
|
|
644
|
+
await openAndClick(clock, select, 0);
|
|
645
|
+
|
|
646
|
+
// Should have both emails selected (multi-select behavior)
|
|
647
|
+
expect(select.values.length).to.equal(2);
|
|
648
|
+
expect(select.values[0].value).to.equal('first@example.com');
|
|
649
|
+
expect(select.values[1].value).to.equal('second@example.com');
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
it('validates email format correctly', async () => {
|
|
653
|
+
const select = await createSelect(
|
|
654
|
+
clock,
|
|
655
|
+
getSelectHTML([], {
|
|
656
|
+
placeholder: 'Enter email addresses',
|
|
657
|
+
searchable: true,
|
|
658
|
+
emails: true
|
|
659
|
+
})
|
|
660
|
+
);
|
|
661
|
+
|
|
662
|
+
// Test various email formats
|
|
663
|
+
const testCases = [
|
|
664
|
+
{ email: 'valid@example.com', shouldBeValid: true },
|
|
665
|
+
{ email: 'user.name+tag@example.co.uk', shouldBeValid: true },
|
|
666
|
+
{ email: 'invalid-email', shouldBeValid: false },
|
|
667
|
+
{ email: '@example.com', shouldBeValid: false },
|
|
668
|
+
{ email: 'user@', shouldBeValid: false },
|
|
669
|
+
{ email: 'user name@example.com', shouldBeValid: false }, // space not allowed
|
|
670
|
+
{ email: 'user@example', shouldBeValid: false } // no domain extension
|
|
671
|
+
];
|
|
672
|
+
|
|
673
|
+
for (const testCase of testCases) {
|
|
674
|
+
select.input = '';
|
|
675
|
+
await select.updateComplete;
|
|
676
|
+
|
|
677
|
+
await typeInto('temba-select', testCase.email, false, false);
|
|
678
|
+
await clock.runAll();
|
|
679
|
+
await select.updateComplete;
|
|
680
|
+
await openSelect(clock, select);
|
|
681
|
+
|
|
682
|
+
const optionsComponent = select.shadowRoot.querySelector(
|
|
683
|
+
'temba-options'
|
|
684
|
+
) as any;
|
|
685
|
+
const visibleOptions = optionsComponent.shadowRoot.querySelectorAll(
|
|
686
|
+
'.option:not(.header)'
|
|
687
|
+
);
|
|
688
|
+
if (testCase.shouldBeValid) {
|
|
689
|
+
expect(
|
|
690
|
+
visibleOptions.length,
|
|
691
|
+
`${testCase.email} should be valid`
|
|
692
|
+
).to.equal(1);
|
|
693
|
+
} else {
|
|
694
|
+
expect(
|
|
695
|
+
visibleOptions.length,
|
|
696
|
+
`${testCase.email} should be invalid`
|
|
697
|
+
).to.equal(0);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
|
|
576
703
|
describe('static options', () => {
|
|
577
704
|
it('accepts an initial value', async () => {
|
|
578
705
|
const select = await createSelect(
|
|
@@ -591,6 +718,113 @@ describe('temba-select', () => {
|
|
|
591
718
|
getClip(select)
|
|
592
719
|
);
|
|
593
720
|
});
|
|
721
|
+
|
|
722
|
+
it('fires change event when static option sets initial value', async () => {
|
|
723
|
+
const changeEvent = sinon.spy();
|
|
724
|
+
|
|
725
|
+
// Create a basic select element with manual HTML
|
|
726
|
+
const parentNode = document.createElement('div');
|
|
727
|
+
parentNode.innerHTML = `<temba-select name="test">
|
|
728
|
+
<temba-option name="Red" value="0"></temba-option>
|
|
729
|
+
<temba-option name="Green" value="1" selected></temba-option>
|
|
730
|
+
<temba-option name="Blue" value="2"></temba-option>
|
|
731
|
+
</temba-select>`;
|
|
732
|
+
|
|
733
|
+
const select = parentNode.querySelector(
|
|
734
|
+
'temba-select'
|
|
735
|
+
) as Select<SelectOption>;
|
|
736
|
+
document.body.appendChild(parentNode);
|
|
737
|
+
|
|
738
|
+
// Add event listener before triggering initialization
|
|
739
|
+
select.addEventListener('change', changeEvent);
|
|
740
|
+
|
|
741
|
+
// Manually trigger slot change to process the selected attribute
|
|
742
|
+
select.handleSlotChange();
|
|
743
|
+
clock.runAll();
|
|
744
|
+
await select.updateComplete;
|
|
745
|
+
|
|
746
|
+
// The change event should have been fired when the initial value was set
|
|
747
|
+
assert(
|
|
748
|
+
changeEvent.called,
|
|
749
|
+
'change event should fire when static option sets initial value'
|
|
750
|
+
);
|
|
751
|
+
expect(select.values[0].name).to.equal('Green');
|
|
752
|
+
|
|
753
|
+
document.body.removeChild(parentNode);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
it('fires change event when static option sets initial value via value attribute', async () => {
|
|
757
|
+
const changeEvent = sinon.spy();
|
|
758
|
+
|
|
759
|
+
// Create a basic select element with value attribute
|
|
760
|
+
const parentNode = document.createElement('div');
|
|
761
|
+
parentNode.innerHTML = `<temba-select name="test" value="1">
|
|
762
|
+
<temba-option name="Red" value="0"></temba-option>
|
|
763
|
+
<temba-option name="Green" value="1"></temba-option>
|
|
764
|
+
<temba-option name="Blue" value="2"></temba-option>
|
|
765
|
+
</temba-select>`;
|
|
766
|
+
|
|
767
|
+
const select = parentNode.querySelector(
|
|
768
|
+
'temba-select'
|
|
769
|
+
) as Select<SelectOption>;
|
|
770
|
+
document.body.appendChild(parentNode);
|
|
771
|
+
|
|
772
|
+
// Add event listener before triggering initialization
|
|
773
|
+
select.addEventListener('change', changeEvent);
|
|
774
|
+
|
|
775
|
+
// First process the static options
|
|
776
|
+
select.handleSlotChange();
|
|
777
|
+
// Then check for selected option based on value attribute
|
|
778
|
+
select.setSelectedValue(select.getAttribute('value'));
|
|
779
|
+
|
|
780
|
+
clock.runAll();
|
|
781
|
+
await select.updateComplete;
|
|
782
|
+
|
|
783
|
+
// The change event should have been fired when the initial value was set
|
|
784
|
+
assert(
|
|
785
|
+
changeEvent.called,
|
|
786
|
+
'change event should fire when value attribute sets initial value'
|
|
787
|
+
);
|
|
788
|
+
expect(select.values[0].name).to.equal('Green');
|
|
789
|
+
|
|
790
|
+
document.body.removeChild(parentNode);
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
it('creates proper form inputs for static options', async () => {
|
|
794
|
+
// Create a form with a select that has static options
|
|
795
|
+
const form = document.createElement('form');
|
|
796
|
+
form.innerHTML = `<temba-select name="color" value="1">
|
|
797
|
+
<temba-option name="Red" value="0"></temba-option>
|
|
798
|
+
<temba-option name="Green" value="1"></temba-option>
|
|
799
|
+
<temba-option name="Blue" value="2"></temba-option>
|
|
800
|
+
</temba-select>`;
|
|
801
|
+
|
|
802
|
+
document.body.appendChild(form);
|
|
803
|
+
const select = form.querySelector('temba-select') as Select<SelectOption>;
|
|
804
|
+
|
|
805
|
+
// Wait for component to be ready
|
|
806
|
+
await select.updateComplete;
|
|
807
|
+
|
|
808
|
+
// Process the static options and set initial value
|
|
809
|
+
select.handleSlotChange();
|
|
810
|
+
select.setSelectedValue(select.getAttribute('value'));
|
|
811
|
+
|
|
812
|
+
clock.runAll();
|
|
813
|
+
await select.updateComplete;
|
|
814
|
+
|
|
815
|
+
// Check that the select has the correct value
|
|
816
|
+
expect(select.values[0].name).to.equal('Green');
|
|
817
|
+
expect(select.values[0].value).to.equal('1');
|
|
818
|
+
|
|
819
|
+
// For single-mode selects, check the value property
|
|
820
|
+
expect(select.value).to.equal('1');
|
|
821
|
+
|
|
822
|
+
// Test FormData - it should include the select's value
|
|
823
|
+
const formData = new FormData(form);
|
|
824
|
+
expect(formData.get('color')).to.equal('1');
|
|
825
|
+
|
|
826
|
+
document.body.removeChild(form);
|
|
827
|
+
});
|
|
594
828
|
});
|
|
595
829
|
|
|
596
830
|
describe('endpoints', () => {
|