@nyaruka/temba-components 0.129.7 → 0.129.9
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/.devcontainer/Dockerfile +11 -4
- package/.devcontainer/devcontainer.json +3 -2
- package/.github/workflows/build.yml +4 -14
- package/CHANGELOG.md +29 -0
- package/demo/components/flow/example.html +1 -1
- package/demo/components/message-editor/example.html +125 -0
- package/demo/components/textinput/completion.html +1 -0
- package/demo/data/flows/food-order.json +12 -21
- package/demo/data/flows/sample-flow.json +210 -104
- package/dist/temba-components.js +715 -364
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Thumbnail.js +2 -1
- package/out-tsc/src/display/Thumbnail.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/excellent/helpers.js +2 -2
- package/out-tsc/src/excellent/helpers.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +25 -7
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +11 -1
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +342 -276
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +40 -0
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/call_llm.js +56 -3
- package/out-tsc/src/flow/actions/call_llm.js.map +1 -1
- package/out-tsc/src/flow/actions/call_webhook.js +26 -17
- package/out-tsc/src/flow/actions/call_webhook.js.map +1 -1
- package/out-tsc/src/flow/actions/open_ticket.js +65 -3
- package/out-tsc/src/flow/actions/open_ticket.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +147 -6
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +75 -0
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/config.js +4 -0
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +227 -0
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_ticket.js +18 -0
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js +27 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js +0 -65
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +87 -57
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/BaseListEditor.js +19 -4
- package/out-tsc/src/form/BaseListEditor.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +305 -0
- package/out-tsc/src/form/FieldRenderer.js.map +1 -0
- package/out-tsc/src/form/FormField.js +4 -4
- package/out-tsc/src/form/FormField.js.map +1 -1
- package/out-tsc/src/form/KeyValueEditor.js +1 -1
- package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
- package/out-tsc/src/form/MediaPicker.js +13 -1
- package/out-tsc/src/form/MediaPicker.js.map +1 -1
- package/out-tsc/src/form/MessageEditor.js +422 -0
- package/out-tsc/src/form/MessageEditor.js.map +1 -0
- package/out-tsc/src/form/TextInput.js +13 -6
- package/out-tsc/src/form/TextInput.js.map +1 -1
- package/out-tsc/src/form/select/Select.js +52 -24
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +66 -15
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/markdown.js +13 -11
- package/out-tsc/src/markdown.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/ActionHelper.js +2 -0
- package/out-tsc/test/ActionHelper.js.map +1 -1
- package/out-tsc/test/NodeHelper.js +148 -0
- package/out-tsc/test/NodeHelper.js.map +1 -0
- package/out-tsc/test/actions/call_llm.test.js +103 -0
- package/out-tsc/test/actions/call_llm.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js +532 -0
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_random.test.js +150 -0
- package/out-tsc/test/nodes/split_by_random.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js +150 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_response.test.js +171 -0
- package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -0
- package/out-tsc/test/temba-add-input-labels.test.js +70 -0
- package/out-tsc/test/temba-add-input-labels.test.js.map +1 -0
- package/out-tsc/test/temba-field-config.test.js +4 -2
- package/out-tsc/test/temba-field-config.test.js.map +1 -1
- package/out-tsc/test/temba-field-renderer.test.js +296 -0
- package/out-tsc/test/temba-field-renderer.test.js.map +1 -0
- package/out-tsc/test/temba-markdown.test.js +1 -1
- package/out-tsc/test/temba-markdown.test.js.map +1 -1
- package/out-tsc/test/temba-message-editor.test.js +194 -0
- package/out-tsc/test/temba-message-editor.test.js.map +1 -0
- package/out-tsc/test/temba-node-editor.test.js +471 -0
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +7 -4
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/temba-textinput.test.js +16 -0
- package/out-tsc/test/temba-textinput.test.js.map +1 -1
- package/out-tsc/test/temba-webchat.test.js +5 -1
- package/out-tsc/test/temba-webchat.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +2 -8
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +7 -4
- 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/call_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/render/translation-task.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/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_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/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/field-renderer/checkbox-checked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/context-comparison.png +0 -0
- package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
- package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
- package/screenshots/truth/field-renderer/select-multi.png +0 -0
- package/screenshots/truth/field-renderer/select-no-label.png +0 -0
- package/screenshots/truth/field-renderer/select-with-label.png +0 -0
- package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/text-no-label.png +0 -0
- package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/text-with-label.png +0 -0
- package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
- package/screenshots/truth/formfield/markdown-errors.png +0 -0
- package/screenshots/truth/formfield/no-errors.png +0 -0
- package/screenshots/truth/formfield/plain-text-errors.png +0 -0
- package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
- package/screenshots/truth/message-editor/default.png +0 -0
- package/screenshots/truth/message-editor/drag-highlight.png +0 -0
- package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
- package/screenshots/truth/message-editor/with-completion.png +0 -0
- package/screenshots/truth/message-editor/with-properties.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_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.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/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.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/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/screenshots/truth/textinput/autogrow-initial.png +0 -0
- package/screenshots/truth/textinput/input-form.png +0 -0
- package/src/display/Thumbnail.ts +2 -1
- package/src/events.ts +13 -1
- package/src/excellent/helpers.ts +2 -2
- package/src/flow/CanvasNode.ts +22 -1
- package/src/flow/Editor.ts +12 -1
- package/src/flow/NodeEditor.ts +412 -354
- package/src/flow/actions/add_input_labels.ts +45 -0
- package/src/flow/actions/call_llm.ts +57 -3
- package/src/flow/actions/call_webhook.ts +28 -18
- package/src/flow/actions/open_ticket.ts +74 -3
- package/src/flow/actions/send_msg.ts +170 -6
- package/src/flow/actions/set_run_result.ts +83 -0
- package/src/flow/config.ts +4 -0
- package/src/flow/nodes/split_by_llm_categorize.ts +277 -0
- package/src/flow/nodes/split_by_ticket.ts +19 -0
- package/src/flow/nodes/wait_for_response.ts +28 -1
- package/src/flow/types.ts +46 -128
- package/src/form/ArrayEditor.ts +96 -66
- package/src/form/BaseListEditor.ts +22 -6
- package/src/form/FieldRenderer.ts +465 -0
- package/src/form/FormField.ts +4 -4
- package/src/form/KeyValueEditor.ts +1 -1
- package/src/form/MediaPicker.ts +13 -1
- package/src/form/MessageEditor.ts +449 -0
- package/src/form/TextInput.ts +16 -8
- package/src/form/select/Select.ts +55 -24
- package/src/live/ContactChat.ts +69 -19
- package/src/markdown.ts +19 -11
- package/src/store/flow-definition.d.ts +5 -2
- package/static/api/labels.json +31 -0
- package/static/api/topics.json +24 -9
- package/static/api/users.json +35 -16
- package/static/css/temba-components.css +5 -3
- package/static/mr/docs/en-us/editor.json +2588 -0
- package/stress-test.js +143 -0
- package/temba-modules.ts +2 -0
- package/test/ActionHelper.ts +2 -0
- package/test/NodeHelper.ts +184 -0
- package/test/actions/call_llm.test.ts +137 -0
- package/test/nodes/README.md +78 -0
- package/test/nodes/split_by_llm_categorize.test.ts +698 -0
- package/test/nodes/split_by_random.test.ts +177 -0
- package/test/nodes/wait_for_digits.test.ts +176 -0
- package/test/nodes/wait_for_response.test.ts +206 -0
- package/test/temba-add-input-labels.test.ts +87 -0
- package/test/temba-field-config.test.ts +4 -2
- package/test/temba-field-renderer.test.ts +482 -0
- package/test/temba-markdown.test.ts +1 -1
- package/test/temba-message-editor.test.ts +300 -0
- package/test/temba-node-editor.test.ts +590 -0
- package/test/temba-select.test.ts +7 -7
- package/test/temba-textinput.test.ts +26 -0
- package/test/temba-webchat.test.ts +6 -1
- package/test/utils.test.ts +2 -13
- package/test-assets/contacts/history.json +19 -0
- package/test-assets/select/llms.json +18 -0
- package/test-assets/style.css +2 -0
- package/web-dev-mock.mjs +523 -0
- package/web-dev-server.config.mjs +74 -6
- package/web-test-runner.config.mjs +9 -4
- package/test/temba-flow-editor.test.ts.backup +0 -563
- package/test/temba-utils-index.test.ts.backup +0 -1737
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temba-field-config.test.js","sourceRoot":"","sources":["../../test/temba-field-config.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, fixture, expect } from '@open-wc/testing';\nimport '../src/form/KeyValueEditor';\nimport '../src/form/ArrayEditor';\n\ndescribe('Field Configuration System', () => {\n describe('KeyValueEditor', () => {\n it('should render with empty value and always show one empty row', async () => {\n const el = await fixture(html`\n <temba-key-value-editor></temba-key-value-editor>\n `);\n\n expect(el).to.exist;\n // Should always have at least one row (empty row)\n const rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(1);\n // Should not have add button anymore\n expect(el.shadowRoot?.querySelector('.add-btn')).to.not.exist;\n });\n\n it('should render with initial values and maintain empty row', async () => {\n const initialValue = {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer token123'\n };\n\n const el = await fixture(html`\n <temba-key-value-editor .value=${initialValue}></temba-key-value-editor>\n `);\n\n expect(el).to.exist;\n // Should have 2 data rows + 1 empty row = 3 total\n const rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(3);\n });\n\n it('should emit clean values without empty rows', async () => {\n const el = await fixture(html`\n <temba-key-value-editor></temba-key-value-editor>\n `);\n\n let changeEvent: any = null;\n el.addEventListener('change', (e) => {\n changeEvent = e;\n });\n\n // Trigger a field change that should cause an update\n const keyInput = el.shadowRoot?.querySelector('temba-textinput') as any;\n if (keyInput) {\n keyInput.value = 'test-key';\n keyInput.dispatchEvent(new Event('change'));\n }\n\n await (el as any).updateComplete;\n\n expect(changeEvent).to.exist;\n // Should emit the array format with key-value pairs\n expect(changeEvent.detail.value).to.be.an('array');\n expect(changeEvent.detail.value).to.deep.include({\n key: 'test-key',\n value: ''\n });\n });\n\n it('should hide remove button for empty rows', async () => {\n const initialValue = {\n 'Content-Type': 'application/json'\n };\n\n const el = await fixture(html`\n <temba-key-value-editor .value=${initialValue}></temba-key-value-editor>\n `);\n\n expect(el).to.exist;\n const rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(2); // 1 data row + 1 empty row\n\n // First row (with data) should have remove button\n const firstRowRemoveBtn = rows?.[0]?.querySelector('.remove-btn');\n expect(firstRowRemoveBtn).to.exist;\n\n // Second row (empty) should have spacer instead of remove button\n const secondRowRemoveBtn = rows?.[1]?.querySelector('.remove-btn');\n const secondRowSpacer = rows?.[1]?.querySelector('.remove-btn-spacer');\n expect(secondRowRemoveBtn).to.not.exist;\n expect(secondRowSpacer).to.exist;\n });\n\n it('should show remove button when empty row gets content', async () => {\n const el = await fixture(html`\n <temba-key-value-editor></temba-key-value-editor>\n `);\n\n // Initially should have no remove button (empty row)\n let rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.[0]?.querySelector('.remove-btn')).to.not.exist;\n expect(rows?.[0]?.querySelector('.remove-btn-spacer')).to.exist;\n\n // Simulate adding content by setting value and triggering update\n (el as any).value = { 'test-key': '' };\n (el as any).requestUpdate();\n await (el as any).updateComplete;\n\n // Now should have remove button for the row with content\n rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(2); // row with content + empty row\n expect(rows?.[0]?.querySelector('.remove-btn')).to.exist;\n expect(rows?.[1]?.querySelector('.remove-btn-spacer')).to.exist;\n });\n });\n\n describe('ArrayEditor', () => {\n it('should render with empty array', async () => {\n const itemConfig = {\n name: { type: 'text', label: 'Name', required: true },\n value: { type: 'text', label: 'Value' }\n };\n\n const el = await fixture(html`\n <temba-array-editor .itemConfig=${itemConfig}></temba-array-editor>\n `);\n\n await (el as any).updateComplete;\n\n expect(el).to.exist;\n expect(el.shadowRoot?.querySelector('.add-btn')).to.exist;\n });\n\n it('should render with initial items', async () => {\n const itemConfig = {\n operator: { type: 'text', label: 'Operator' },\n value: { type: 'text', label: 'Value' }\n };\n\n const initialValue = [\n { operator: 'equals', value: 'test' },\n { operator: 'contains', value: 'example' }\n ];\n\n const el = await fixture(html`\n <temba-array-editor\n .value=${initialValue}\n .itemConfig=${itemConfig}\n itemLabel=\"Rule\"\n ></temba-array-editor>\n `);\n\n expect(el).to.exist;\n const items = el.shadowRoot?.querySelectorAll('.array-item');\n expect(items?.length).to.equal(2);\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"temba-field-config.test.js","sourceRoot":"","sources":["../../test/temba-field-config.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, fixture, expect } from '@open-wc/testing';\nimport '../src/form/KeyValueEditor';\nimport '../src/form/ArrayEditor';\n\ndescribe('Field Configuration System', () => {\n describe('KeyValueEditor', () => {\n it('should render with empty value and always show one empty row', async () => {\n const el = await fixture(html`\n <temba-key-value-editor></temba-key-value-editor>\n `);\n\n expect(el).to.exist;\n // Should always have at least one row (empty row)\n const rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(1);\n // Should not have add button anymore\n expect(el.shadowRoot?.querySelector('.add-btn')).to.not.exist;\n });\n\n it('should render with initial values and maintain empty row', async () => {\n const initialValue = {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer token123'\n };\n\n const el = await fixture(html`\n <temba-key-value-editor .value=${initialValue}></temba-key-value-editor>\n `);\n\n expect(el).to.exist;\n // Should have 2 data rows + 1 empty row = 3 total\n const rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(3);\n });\n\n it('should emit clean values without empty rows', async () => {\n const el = await fixture(html`\n <temba-key-value-editor></temba-key-value-editor>\n `);\n\n let changeEvent: any = null;\n el.addEventListener('change', (e) => {\n changeEvent = e;\n });\n\n // Trigger a field change that should cause an update\n const keyInput = el.shadowRoot?.querySelector('temba-textinput') as any;\n if (keyInput) {\n keyInput.value = 'test-key';\n keyInput.dispatchEvent(new Event('change'));\n }\n\n await (el as any).updateComplete;\n\n expect(changeEvent).to.exist;\n // Should emit the array format with key-value pairs\n expect(changeEvent.detail.value).to.be.an('array');\n expect(changeEvent.detail.value).to.deep.include({\n key: 'test-key',\n value: ''\n });\n });\n\n it('should hide remove button for empty rows', async () => {\n const initialValue = {\n 'Content-Type': 'application/json'\n };\n\n const el = await fixture(html`\n <temba-key-value-editor .value=${initialValue}></temba-key-value-editor>\n `);\n\n expect(el).to.exist;\n const rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(2); // 1 data row + 1 empty row\n\n // First row (with data) should have remove button\n const firstRowRemoveBtn = rows?.[0]?.querySelector('.remove-btn');\n expect(firstRowRemoveBtn).to.exist;\n\n // Second row (empty) should have spacer instead of remove button\n const secondRowRemoveBtn = rows?.[1]?.querySelector('.remove-btn');\n const secondRowSpacer = rows?.[1]?.querySelector('.remove-btn-spacer');\n expect(secondRowRemoveBtn).to.not.exist;\n expect(secondRowSpacer).to.exist;\n });\n\n it('should show remove button when empty row gets content', async () => {\n const el = await fixture(html`\n <temba-key-value-editor></temba-key-value-editor>\n `);\n\n // Initially should have no remove button (empty row)\n let rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.[0]?.querySelector('.remove-btn')).to.not.exist;\n expect(rows?.[0]?.querySelector('.remove-btn-spacer')).to.exist;\n\n // Simulate adding content by setting value and triggering update\n (el as any).value = { 'test-key': '' };\n (el as any).requestUpdate();\n await (el as any).updateComplete;\n\n // Now should have remove button for the row with content\n rows = el.shadowRoot?.querySelectorAll('.row');\n expect(rows?.length).to.equal(2); // row with content + empty row\n expect(rows?.[0]?.querySelector('.remove-btn')).to.exist;\n expect(rows?.[1]?.querySelector('.remove-btn-spacer')).to.exist;\n });\n });\n\n describe('ArrayEditor', () => {\n it('should render with empty array', async () => {\n const itemConfig = {\n name: { type: 'text', label: 'Name', required: true },\n value: { type: 'text', label: 'Value' }\n };\n\n const el = await fixture(html`\n <temba-array-editor .itemConfig=${itemConfig}></temba-array-editor>\n `);\n\n await (el as any).updateComplete;\n\n expect(el).to.exist;\n // ArrayEditor with maintainEmptyItem=true doesn't show add button\n expect(el.shadowRoot?.querySelector('.add-btn')).to.not.exist;\n });\n\n it('should render with initial items', async () => {\n const itemConfig = {\n operator: { type: 'text', label: 'Operator' },\n value: { type: 'text', label: 'Value' }\n };\n\n const initialValue = [\n { operator: 'equals', value: 'test' },\n { operator: 'contains', value: 'example' }\n ];\n\n const el = await fixture(html`\n <temba-array-editor\n .value=${initialValue}\n .itemConfig=${itemConfig}\n itemLabel=\"Rule\"\n ></temba-array-editor>\n `);\n\n expect(el).to.exist;\n const items = el.shadowRoot?.querySelectorAll('.array-item');\n // Expects 3 items: 2 initial items + 1 auto-generated empty item\n expect(items?.length).to.equal(3);\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
|
2
|
+
import { FieldRenderer } from '../src/form/FieldRenderer';
|
|
3
|
+
import { assertScreenshot, getClip } from './utils.test';
|
|
4
|
+
describe('FieldRenderer', () => {
|
|
5
|
+
describe('text fields', () => {
|
|
6
|
+
it('should render text field with label', async () => {
|
|
7
|
+
const config = {
|
|
8
|
+
type: 'text',
|
|
9
|
+
label: 'Website URL',
|
|
10
|
+
placeholder: 'Enter URL'
|
|
11
|
+
};
|
|
12
|
+
const template = FieldRenderer.renderField('url', config, 'https://example.com', {
|
|
13
|
+
errors: [],
|
|
14
|
+
showLabel: true,
|
|
15
|
+
onChange: () => { }
|
|
16
|
+
});
|
|
17
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
18
|
+
await assertScreenshot('field-renderer/text-with-label', getClip(container));
|
|
19
|
+
});
|
|
20
|
+
it('should render evaluated text field with completion', async () => {
|
|
21
|
+
const config = {
|
|
22
|
+
type: 'text',
|
|
23
|
+
label: 'Dynamic URL',
|
|
24
|
+
evaluated: true,
|
|
25
|
+
placeholder: 'Enter URL with expressions'
|
|
26
|
+
};
|
|
27
|
+
const template = FieldRenderer.renderField('url', config, 'https://api.com/@contact.name', {
|
|
28
|
+
errors: [],
|
|
29
|
+
showLabel: true,
|
|
30
|
+
onChange: () => { }
|
|
31
|
+
});
|
|
32
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
33
|
+
await assertScreenshot('field-renderer/text-evaluated', getClip(container));
|
|
34
|
+
});
|
|
35
|
+
it('should render text field without label for ArrayEditor context', async () => {
|
|
36
|
+
const config = {
|
|
37
|
+
type: 'text',
|
|
38
|
+
label: 'Item Name',
|
|
39
|
+
placeholder: 'Enter name'
|
|
40
|
+
};
|
|
41
|
+
const template = FieldRenderer.renderField('name', config, 'Sample Item', {
|
|
42
|
+
errors: [],
|
|
43
|
+
showLabel: false,
|
|
44
|
+
flavor: 'small',
|
|
45
|
+
extraClasses: 'form-control',
|
|
46
|
+
onChange: () => { }
|
|
47
|
+
});
|
|
48
|
+
const container = await fixture(html `<div style="width: 300px; padding: 10px;">${template}</div>`);
|
|
49
|
+
await assertScreenshot('field-renderer/text-no-label', getClip(container));
|
|
50
|
+
});
|
|
51
|
+
it('should render text field with errors', async () => {
|
|
52
|
+
const config = {
|
|
53
|
+
type: 'text',
|
|
54
|
+
label: 'Email Address',
|
|
55
|
+
placeholder: 'Enter email'
|
|
56
|
+
};
|
|
57
|
+
const template = FieldRenderer.renderField('email', config, 'invalid-email', {
|
|
58
|
+
errors: ['Invalid email format', 'Email is required'],
|
|
59
|
+
showLabel: true,
|
|
60
|
+
onChange: () => { }
|
|
61
|
+
});
|
|
62
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
63
|
+
await assertScreenshot('field-renderer/text-with-errors', getClip(container));
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('textarea fields', () => {
|
|
67
|
+
it('should render textarea with label', async () => {
|
|
68
|
+
const config = {
|
|
69
|
+
type: 'textarea',
|
|
70
|
+
label: 'Description',
|
|
71
|
+
placeholder: 'Enter description',
|
|
72
|
+
rows: 4
|
|
73
|
+
};
|
|
74
|
+
const template = FieldRenderer.renderField('description', config, 'This is a sample description\nwith multiple lines', {
|
|
75
|
+
errors: [],
|
|
76
|
+
showLabel: true,
|
|
77
|
+
onChange: () => { }
|
|
78
|
+
});
|
|
79
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
80
|
+
await assertScreenshot('field-renderer/textarea-with-label', getClip(container));
|
|
81
|
+
});
|
|
82
|
+
it('should render evaluated textarea with completion', async () => {
|
|
83
|
+
const config = {
|
|
84
|
+
type: 'textarea',
|
|
85
|
+
label: 'Message Template',
|
|
86
|
+
evaluated: true,
|
|
87
|
+
placeholder: 'Enter message with expressions',
|
|
88
|
+
rows: 3
|
|
89
|
+
};
|
|
90
|
+
const template = FieldRenderer.renderField('message', config, 'Hello @contact.name,\nYour order is ready!', {
|
|
91
|
+
errors: [],
|
|
92
|
+
showLabel: true,
|
|
93
|
+
onChange: () => { }
|
|
94
|
+
});
|
|
95
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
96
|
+
await assertScreenshot('field-renderer/textarea-evaluated', getClip(container));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('select fields', () => {
|
|
100
|
+
it('should render select field with label', async () => {
|
|
101
|
+
const config = {
|
|
102
|
+
type: 'select',
|
|
103
|
+
label: 'Country',
|
|
104
|
+
options: ['United States', 'Canada', 'United Kingdom', 'Australia'],
|
|
105
|
+
searchable: true
|
|
106
|
+
};
|
|
107
|
+
const template = FieldRenderer.renderField('country', config, 'Canada', {
|
|
108
|
+
errors: [],
|
|
109
|
+
showLabel: true,
|
|
110
|
+
onChange: () => { }
|
|
111
|
+
});
|
|
112
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
113
|
+
await assertScreenshot('field-renderer/select-with-label', getClip(container));
|
|
114
|
+
});
|
|
115
|
+
it('should render multi-select field', async () => {
|
|
116
|
+
const config = {
|
|
117
|
+
type: 'select',
|
|
118
|
+
label: 'Skills',
|
|
119
|
+
options: ['JavaScript', 'Python', 'TypeScript', 'React', 'Node.js'],
|
|
120
|
+
multi: true,
|
|
121
|
+
tags: true
|
|
122
|
+
};
|
|
123
|
+
const template = FieldRenderer.renderField('skills', config, ['JavaScript', 'TypeScript'], {
|
|
124
|
+
errors: [],
|
|
125
|
+
showLabel: true,
|
|
126
|
+
onChange: () => { }
|
|
127
|
+
});
|
|
128
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
129
|
+
await assertScreenshot('field-renderer/select-multi', getClip(container));
|
|
130
|
+
});
|
|
131
|
+
it('should render select field without label for ArrayEditor context', async () => {
|
|
132
|
+
const config = {
|
|
133
|
+
type: 'select',
|
|
134
|
+
label: 'Status',
|
|
135
|
+
options: ['Active', 'Inactive', 'Pending']
|
|
136
|
+
};
|
|
137
|
+
const template = FieldRenderer.renderField('status', config, 'Active', {
|
|
138
|
+
errors: [],
|
|
139
|
+
showLabel: false,
|
|
140
|
+
flavor: 'small',
|
|
141
|
+
extraClasses: 'form-control',
|
|
142
|
+
onChange: () => { }
|
|
143
|
+
});
|
|
144
|
+
const container = await fixture(html `<div style="width: 200px; padding: 10px;">${template}</div>`);
|
|
145
|
+
await assertScreenshot('field-renderer/select-no-label', getClip(container));
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('checkbox fields', () => {
|
|
149
|
+
it('should render checkbox with label', async () => {
|
|
150
|
+
const config = {
|
|
151
|
+
type: 'checkbox',
|
|
152
|
+
label: 'Accept Terms and Conditions'
|
|
153
|
+
};
|
|
154
|
+
const template = FieldRenderer.renderField('accept', config, true, {
|
|
155
|
+
errors: [],
|
|
156
|
+
showLabel: true,
|
|
157
|
+
onChange: () => { }
|
|
158
|
+
});
|
|
159
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
160
|
+
await assertScreenshot('field-renderer/checkbox-checked', getClip(container));
|
|
161
|
+
});
|
|
162
|
+
it('should render unchecked checkbox', async () => {
|
|
163
|
+
const config = {
|
|
164
|
+
type: 'checkbox',
|
|
165
|
+
label: 'Subscribe to newsletter'
|
|
166
|
+
};
|
|
167
|
+
const template = FieldRenderer.renderField('subscribe', config, false, {
|
|
168
|
+
errors: [],
|
|
169
|
+
showLabel: true,
|
|
170
|
+
onChange: () => { }
|
|
171
|
+
});
|
|
172
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
173
|
+
await assertScreenshot('field-renderer/checkbox-unchecked', getClip(container));
|
|
174
|
+
});
|
|
175
|
+
it('should render checkbox with errors', async () => {
|
|
176
|
+
const config = {
|
|
177
|
+
type: 'checkbox',
|
|
178
|
+
label: 'Agree to terms',
|
|
179
|
+
required: true
|
|
180
|
+
};
|
|
181
|
+
const template = FieldRenderer.renderField('terms', config, false, {
|
|
182
|
+
errors: ['You must accept the terms to continue'],
|
|
183
|
+
showLabel: true,
|
|
184
|
+
onChange: () => { }
|
|
185
|
+
});
|
|
186
|
+
const container = await fixture(html `<div style="width: 400px; padding: 20px;">${template}</div>`);
|
|
187
|
+
await assertScreenshot('field-renderer/checkbox-with-errors', getClip(container));
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe('key-value fields', () => {
|
|
191
|
+
it('should render key-value field with label', async () => {
|
|
192
|
+
const config = {
|
|
193
|
+
type: 'key-value',
|
|
194
|
+
label: 'HTTP Headers',
|
|
195
|
+
keyPlaceholder: 'Header name',
|
|
196
|
+
valuePlaceholder: 'Header value'
|
|
197
|
+
};
|
|
198
|
+
const template = FieldRenderer.renderField('headers', config, [
|
|
199
|
+
{ key: 'Content-Type', value: 'application/json' },
|
|
200
|
+
{ key: 'Authorization', value: 'Bearer token123' }
|
|
201
|
+
], {
|
|
202
|
+
errors: [],
|
|
203
|
+
showLabel: true,
|
|
204
|
+
onChange: () => { }
|
|
205
|
+
});
|
|
206
|
+
const container = await fixture(html `<div style="width: 500px; padding: 20px;">${template}</div>`);
|
|
207
|
+
await assertScreenshot('field-renderer/key-value-with-label', getClip(container));
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
describe('message-editor fields', () => {
|
|
211
|
+
it('should render message-editor with label', async () => {
|
|
212
|
+
const config = {
|
|
213
|
+
type: 'message-editor',
|
|
214
|
+
label: 'Email Message',
|
|
215
|
+
placeholder: 'Enter your message...',
|
|
216
|
+
minHeight: 120
|
|
217
|
+
};
|
|
218
|
+
const template = FieldRenderer.renderField('message', config, 'Hello! This is a test message.', {
|
|
219
|
+
errors: [],
|
|
220
|
+
showLabel: true,
|
|
221
|
+
onChange: () => { },
|
|
222
|
+
additionalData: { attachments: [] }
|
|
223
|
+
});
|
|
224
|
+
const container = await fixture(html `<div style="width: 500px; padding: 20px;">${template}</div>`);
|
|
225
|
+
await assertScreenshot('field-renderer/message-editor-with-label', getClip(container));
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
describe('field consistency', () => {
|
|
229
|
+
it('should render the same field type consistently between contexts', async () => {
|
|
230
|
+
const config = {
|
|
231
|
+
type: 'text',
|
|
232
|
+
label: 'Product Name',
|
|
233
|
+
placeholder: 'Enter product name'
|
|
234
|
+
};
|
|
235
|
+
// NodeEditor context (with label)
|
|
236
|
+
const nodeEditorTemplate = FieldRenderer.renderField('product', config, 'iPhone 15', {
|
|
237
|
+
errors: [],
|
|
238
|
+
showLabel: true,
|
|
239
|
+
onChange: () => { }
|
|
240
|
+
});
|
|
241
|
+
// ArrayEditor context (without label)
|
|
242
|
+
const arrayEditorTemplate = FieldRenderer.renderField('product', config, 'iPhone 15', {
|
|
243
|
+
errors: [],
|
|
244
|
+
showLabel: false,
|
|
245
|
+
flavor: 'small',
|
|
246
|
+
extraClasses: 'form-control',
|
|
247
|
+
onChange: () => { }
|
|
248
|
+
});
|
|
249
|
+
const nodeContainer = await fixture(html `<div
|
|
250
|
+
style="width: 400px; padding: 20px; border: 1px solid #ddd; margin: 10px;"
|
|
251
|
+
>
|
|
252
|
+
<h3 style="margin: 0 0 10px 0; font-size: 14px; color: #666;">
|
|
253
|
+
NodeEditor Context
|
|
254
|
+
</h3>
|
|
255
|
+
${nodeEditorTemplate}
|
|
256
|
+
</div>`);
|
|
257
|
+
const arrayContainer = await fixture(html `<div
|
|
258
|
+
style="width: 400px; padding: 20px; border: 1px solid #ddd; margin: 10px;"
|
|
259
|
+
>
|
|
260
|
+
<h3 style="margin: 0 0 10px 0; font-size: 14px; color: #666;">
|
|
261
|
+
ArrayEditor Context
|
|
262
|
+
</h3>
|
|
263
|
+
${arrayEditorTemplate}
|
|
264
|
+
</div>`);
|
|
265
|
+
const combinedContainer = await fixture(html `<div
|
|
266
|
+
style="display: flex; flex-direction: column; width: 420px;"
|
|
267
|
+
>
|
|
268
|
+
${nodeContainer} ${arrayContainer}
|
|
269
|
+
</div>`);
|
|
270
|
+
await assertScreenshot('field-renderer/context-comparison', getClip(combinedContainer));
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
describe('error handling', () => {
|
|
274
|
+
it('should handle all field types without throwing errors', () => {
|
|
275
|
+
const configs = [
|
|
276
|
+
{ type: 'text', label: 'Text' },
|
|
277
|
+
{ type: 'textarea', label: 'Textarea' },
|
|
278
|
+
{ type: 'select', label: 'Select', options: [] },
|
|
279
|
+
{ type: 'checkbox', label: 'Checkbox' },
|
|
280
|
+
{ type: 'key-value', label: 'KeyValue' },
|
|
281
|
+
{ type: 'array', label: 'Array', itemConfig: {} },
|
|
282
|
+
{ type: 'message-editor', label: 'MessageEditor' }
|
|
283
|
+
];
|
|
284
|
+
configs.forEach((config, index) => {
|
|
285
|
+
expect(() => {
|
|
286
|
+
FieldRenderer.renderField(`field${index}`, config, null, {
|
|
287
|
+
errors: [],
|
|
288
|
+
showLabel: true,
|
|
289
|
+
onChange: () => { }
|
|
290
|
+
});
|
|
291
|
+
}).to.not.throw;
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
//# sourceMappingURL=temba-field-renderer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temba-field-renderer.test.js","sourceRoot":"","sources":["../../test/temba-field-renderer.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing';\nimport { FieldRenderer } from '../src/form/FieldRenderer';\nimport {\n TextFieldConfig,\n TextareaFieldConfig,\n SelectFieldConfig,\n CheckboxFieldConfig,\n KeyValueFieldConfig,\n MessageEditorFieldConfig\n} from '../src/flow/types';\nimport { assertScreenshot, getClip } from './utils.test';\n\ndescribe('FieldRenderer', () => {\n describe('text fields', () => {\n it('should render text field with label', async () => {\n const config: TextFieldConfig = {\n type: 'text',\n label: 'Website URL',\n placeholder: 'Enter URL'\n };\n\n const template = FieldRenderer.renderField(\n 'url',\n config,\n 'https://example.com',\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/text-with-label',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render evaluated text field with completion', async () => {\n const config: TextFieldConfig = {\n type: 'text',\n label: 'Dynamic URL',\n evaluated: true,\n placeholder: 'Enter URL with expressions'\n };\n\n const template = FieldRenderer.renderField(\n 'url',\n config,\n 'https://api.com/@contact.name',\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/text-evaluated',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render text field without label for ArrayEditor context', async () => {\n const config: TextFieldConfig = {\n type: 'text',\n label: 'Item Name',\n placeholder: 'Enter name'\n };\n\n const template = FieldRenderer.renderField(\n 'name',\n config,\n 'Sample Item',\n {\n errors: [],\n showLabel: false,\n flavor: 'small',\n extraClasses: 'form-control',\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 300px; padding: 10px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/text-no-label',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render text field with errors', async () => {\n const config: TextFieldConfig = {\n type: 'text',\n label: 'Email Address',\n placeholder: 'Enter email'\n };\n\n const template = FieldRenderer.renderField(\n 'email',\n config,\n 'invalid-email',\n {\n errors: ['Invalid email format', 'Email is required'],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/text-with-errors',\n getClip(container as HTMLElement)\n );\n });\n });\n\n describe('textarea fields', () => {\n it('should render textarea with label', async () => {\n const config: TextareaFieldConfig = {\n type: 'textarea',\n label: 'Description',\n placeholder: 'Enter description',\n rows: 4\n };\n\n const template = FieldRenderer.renderField(\n 'description',\n config,\n 'This is a sample description\\nwith multiple lines',\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/textarea-with-label',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render evaluated textarea with completion', async () => {\n const config: TextareaFieldConfig = {\n type: 'textarea',\n label: 'Message Template',\n evaluated: true,\n placeholder: 'Enter message with expressions',\n rows: 3\n };\n\n const template = FieldRenderer.renderField(\n 'message',\n config,\n 'Hello @contact.name,\\nYour order is ready!',\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/textarea-evaluated',\n getClip(container as HTMLElement)\n );\n });\n });\n\n describe('select fields', () => {\n it('should render select field with label', async () => {\n const config: SelectFieldConfig = {\n type: 'select',\n label: 'Country',\n options: ['United States', 'Canada', 'United Kingdom', 'Australia'],\n searchable: true\n };\n\n const template = FieldRenderer.renderField('country', config, 'Canada', {\n errors: [],\n showLabel: true,\n onChange: () => {}\n });\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/select-with-label',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render multi-select field', async () => {\n const config: SelectFieldConfig = {\n type: 'select',\n label: 'Skills',\n options: ['JavaScript', 'Python', 'TypeScript', 'React', 'Node.js'],\n multi: true,\n tags: true\n };\n\n const template = FieldRenderer.renderField(\n 'skills',\n config,\n ['JavaScript', 'TypeScript'],\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/select-multi',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render select field without label for ArrayEditor context', async () => {\n const config: SelectFieldConfig = {\n type: 'select',\n label: 'Status',\n options: ['Active', 'Inactive', 'Pending']\n };\n\n const template = FieldRenderer.renderField('status', config, 'Active', {\n errors: [],\n showLabel: false,\n flavor: 'small',\n extraClasses: 'form-control',\n onChange: () => {}\n });\n\n const container = await fixture(\n html`<div style=\"width: 200px; padding: 10px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/select-no-label',\n getClip(container as HTMLElement)\n );\n });\n });\n\n describe('checkbox fields', () => {\n it('should render checkbox with label', async () => {\n const config: CheckboxFieldConfig = {\n type: 'checkbox',\n label: 'Accept Terms and Conditions'\n };\n\n const template = FieldRenderer.renderField('accept', config, true, {\n errors: [],\n showLabel: true,\n onChange: () => {}\n });\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/checkbox-checked',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render unchecked checkbox', async () => {\n const config: CheckboxFieldConfig = {\n type: 'checkbox',\n label: 'Subscribe to newsletter'\n };\n\n const template = FieldRenderer.renderField('subscribe', config, false, {\n errors: [],\n showLabel: true,\n onChange: () => {}\n });\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/checkbox-unchecked',\n getClip(container as HTMLElement)\n );\n });\n\n it('should render checkbox with errors', async () => {\n const config: CheckboxFieldConfig = {\n type: 'checkbox',\n label: 'Agree to terms',\n required: true\n };\n\n const template = FieldRenderer.renderField('terms', config, false, {\n errors: ['You must accept the terms to continue'],\n showLabel: true,\n onChange: () => {}\n });\n\n const container = await fixture(\n html`<div style=\"width: 400px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/checkbox-with-errors',\n getClip(container as HTMLElement)\n );\n });\n });\n\n describe('key-value fields', () => {\n it('should render key-value field with label', async () => {\n const config: KeyValueFieldConfig = {\n type: 'key-value',\n label: 'HTTP Headers',\n keyPlaceholder: 'Header name',\n valuePlaceholder: 'Header value'\n };\n\n const template = FieldRenderer.renderField(\n 'headers',\n config,\n [\n { key: 'Content-Type', value: 'application/json' },\n { key: 'Authorization', value: 'Bearer token123' }\n ],\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 500px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/key-value-with-label',\n getClip(container as HTMLElement)\n );\n });\n });\n\n describe('message-editor fields', () => {\n it('should render message-editor with label', async () => {\n const config: MessageEditorFieldConfig = {\n type: 'message-editor',\n label: 'Email Message',\n placeholder: 'Enter your message...',\n minHeight: 120\n };\n\n const template = FieldRenderer.renderField(\n 'message',\n config,\n 'Hello! This is a test message.',\n {\n errors: [],\n showLabel: true,\n onChange: () => {},\n additionalData: { attachments: [] }\n }\n );\n\n const container = await fixture(\n html`<div style=\"width: 500px; padding: 20px;\">${template}</div>`\n );\n await assertScreenshot(\n 'field-renderer/message-editor-with-label',\n getClip(container as HTMLElement)\n );\n });\n });\n\n describe('field consistency', () => {\n it('should render the same field type consistently between contexts', async () => {\n const config: TextFieldConfig = {\n type: 'text',\n label: 'Product Name',\n placeholder: 'Enter product name'\n };\n\n // NodeEditor context (with label)\n const nodeEditorTemplate = FieldRenderer.renderField(\n 'product',\n config,\n 'iPhone 15',\n {\n errors: [],\n showLabel: true,\n onChange: () => {}\n }\n );\n\n // ArrayEditor context (without label)\n const arrayEditorTemplate = FieldRenderer.renderField(\n 'product',\n config,\n 'iPhone 15',\n {\n errors: [],\n showLabel: false,\n flavor: 'small',\n extraClasses: 'form-control',\n onChange: () => {}\n }\n );\n\n const nodeContainer = await fixture(html`<div\n style=\"width: 400px; padding: 20px; border: 1px solid #ddd; margin: 10px;\"\n >\n <h3 style=\"margin: 0 0 10px 0; font-size: 14px; color: #666;\">\n NodeEditor Context\n </h3>\n ${nodeEditorTemplate}\n </div>`);\n\n const arrayContainer = await fixture(html`<div\n style=\"width: 400px; padding: 20px; border: 1px solid #ddd; margin: 10px;\"\n >\n <h3 style=\"margin: 0 0 10px 0; font-size: 14px; color: #666;\">\n ArrayEditor Context\n </h3>\n ${arrayEditorTemplate}\n </div>`);\n\n const combinedContainer = await fixture(html`<div\n style=\"display: flex; flex-direction: column; width: 420px;\"\n >\n ${nodeContainer} ${arrayContainer}\n </div>`);\n\n await assertScreenshot(\n 'field-renderer/context-comparison',\n getClip(combinedContainer as HTMLElement)\n );\n });\n });\n\n describe('error handling', () => {\n it('should handle all field types without throwing errors', () => {\n const configs = [\n { type: 'text', label: 'Text' } as TextFieldConfig,\n { type: 'textarea', label: 'Textarea' } as TextareaFieldConfig,\n { type: 'select', label: 'Select', options: [] } as SelectFieldConfig,\n { type: 'checkbox', label: 'Checkbox' },\n { type: 'key-value', label: 'KeyValue' },\n { type: 'array', label: 'Array', itemConfig: {} },\n { type: 'message-editor', label: 'MessageEditor' }\n ];\n\n configs.forEach((config, index) => {\n expect(() => {\n FieldRenderer.renderField(`field${index}`, config as any, null, {\n errors: [],\n showLabel: true,\n onChange: () => {}\n });\n }).to.not.throw;\n });\n });\n });\n});\n"]}
|
|
@@ -33,7 +33,7 @@ describe('markdown', () => {
|
|
|
33
33
|
const invalidPartInfo = {
|
|
34
34
|
type: PartType.ATTRIBUTE
|
|
35
35
|
};
|
|
36
|
-
expect(() => new RenderMarkdown(invalidPartInfo)).to.throw('
|
|
36
|
+
expect(() => new RenderMarkdown(invalidPartInfo)).to.throw('markdown directives only support child expressions');
|
|
37
37
|
});
|
|
38
38
|
it('creates directive for child part type', () => {
|
|
39
39
|
const validPartInfo = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temba-markdown.test.js","sourceRoot":"","sources":["../../test/temba-markdown.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport { html, render } from 'lit';\nimport { markdown, renderMarkdown, RenderMarkdown } from '../src/markdown';\nimport { PartType } from 'lit/directive.js';\n\ndescribe('markdown', () => {\n describe('markdown instance', () => {\n it('exports a Remarkable instance', () => {\n expect(markdown).to.exist;\n expect(typeof markdown.render).to.equal('function');\n });\n\n it('renders basic markdown', () => {\n const result = markdown.render('# Hello World');\n expect(result).to.include('<h1>Hello World</h1>');\n });\n\n it('renders markdown with emphasis', () => {\n const result = markdown.render('**bold** and *italic*');\n expect(result).to.include('<strong>bold</strong>');\n expect(result).to.include('<em>italic</em>');\n });\n\n it('renders markdown lists', () => {\n const result = markdown.render('- Item 1\\n- Item 2');\n expect(result).to.include('<ul>');\n expect(result).to.include('<li>Item 1</li>');\n expect(result).to.include('<li>Item 2</li>');\n });\n\n it('renders markdown links', () => {\n const result = markdown.render('[Link](https://example.com)');\n expect(result).to.include('<a href=\"https://example.com\">Link</a>');\n });\n });\n\n describe('RenderMarkdown directive', () => {\n it('throws error for non-child part types', () => {\n const invalidPartInfo = {\n type: PartType.ATTRIBUTE\n };\n\n expect(() => new RenderMarkdown(invalidPartInfo as any)).to.throw(\n 'renderMarkdown only supports child expressions'\n );\n });\n\n it('creates directive for child part type', () => {\n const validPartInfo = {\n type: PartType.CHILD\n };\n\n expect(() => new RenderMarkdown(validPartInfo as any)).to.not.throw;\n });\n\n it('renders markdown content', () => {\n const validPartInfo = {\n type: PartType.CHILD\n };\n\n const directive = new RenderMarkdown(validPartInfo as any);\n const result = directive.render('# Test Header');\n\n // The result should be a TemplateResult\n expect(result).to.exist;\n expect(result.strings).to.exist;\n });\n\n it('updates correctly', () => {\n const validPartInfo = {\n type: PartType.CHILD\n };\n\n const directive = new RenderMarkdown(validPartInfo as any);\n const mockPart = {} as any;\n\n const result = directive.update(mockPart, ['# Updated Content']);\n\n // Should return the same as render\n expect(result).to.exist;\n expect(result.strings).to.exist;\n });\n });\n\n describe('renderMarkdown function', () => {\n it('creates a directive that can be used in templates', () => {\n const template = html`${renderMarkdown('# Test')}`;\n\n // Should create a valid template\n expect(template).to.exist;\n expect(template.strings).to.exist;\n });\n\n it('renders markdown when used in a template', () => {\n const container = document.createElement('div');\n const template = html`${renderMarkdown('# Hello World')}`;\n\n render(template, container);\n\n // Check that the markdown was rendered to HTML\n expect(container.innerHTML).to.include('<h1>Hello World</h1>');\n });\n\n it('handles empty markdown', () => {\n const container = document.createElement('div');\n const template = html`${renderMarkdown('')}`;\n\n render(template, container);\n\n // Should not throw - Lit may add HTML comments for template placeholders\n expect(() => render(template, container)).to.not.throw;\n });\n\n it('handles markdown with special characters', () => {\n const container = document.createElement('div');\n const markdownWithSpecialChars =\n '**Bold** text with <script>alert(\"xss\")</script>';\n const template = html`${renderMarkdown(markdownWithSpecialChars)}`;\n\n render(template, container);\n\n // Should render the markdown but the script tag should be escaped/handled\n expect(container.innerHTML).to.include('<strong>Bold</strong>');\n // The script tag should be rendered as text or escaped\n expect(container.innerHTML).to.include('script');\n });\n\n it('renders complex markdown structures', () => {\n const complexMarkdown = `\n# Main Header\n\n## Sub Header\n\nThis is a paragraph with **bold** and *italic* text.\n\n- List item 1\n- List item 2\n - Nested item\n\n[A link](https://example.com)\n\n\\`\\`\\`\ncode block\n\\`\\`\\`\n`;\n\n const container = document.createElement('div');\n const template = html`${renderMarkdown(complexMarkdown)}`;\n\n render(template, container);\n\n expect(container.innerHTML).to.include('<h1>Main Header</h1>');\n expect(container.innerHTML).to.include('<h2>Sub Header</h2>');\n expect(container.innerHTML).to.include('<strong>bold</strong>');\n expect(container.innerHTML).to.include('<em>italic</em>');\n expect(container.innerHTML).to.include('<ul>');\n expect(container.innerHTML).to.include(\n '<a href=\"https://example.com\">A link</a>'\n );\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"temba-markdown.test.js","sourceRoot":"","sources":["../../test/temba-markdown.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport { html, render } from 'lit';\nimport { markdown, renderMarkdown, RenderMarkdown } from '../src/markdown';\nimport { PartType } from 'lit/directive.js';\n\ndescribe('markdown', () => {\n describe('markdown instance', () => {\n it('exports a Remarkable instance', () => {\n expect(markdown).to.exist;\n expect(typeof markdown.render).to.equal('function');\n });\n\n it('renders basic markdown', () => {\n const result = markdown.render('# Hello World');\n expect(result).to.include('<h1>Hello World</h1>');\n });\n\n it('renders markdown with emphasis', () => {\n const result = markdown.render('**bold** and *italic*');\n expect(result).to.include('<strong>bold</strong>');\n expect(result).to.include('<em>italic</em>');\n });\n\n it('renders markdown lists', () => {\n const result = markdown.render('- Item 1\\n- Item 2');\n expect(result).to.include('<ul>');\n expect(result).to.include('<li>Item 1</li>');\n expect(result).to.include('<li>Item 2</li>');\n });\n\n it('renders markdown links', () => {\n const result = markdown.render('[Link](https://example.com)');\n expect(result).to.include('<a href=\"https://example.com\">Link</a>');\n });\n });\n\n describe('RenderMarkdown directive', () => {\n it('throws error for non-child part types', () => {\n const invalidPartInfo = {\n type: PartType.ATTRIBUTE\n };\n\n expect(() => new RenderMarkdown(invalidPartInfo as any)).to.throw(\n 'markdown directives only support child expressions'\n );\n });\n\n it('creates directive for child part type', () => {\n const validPartInfo = {\n type: PartType.CHILD\n };\n\n expect(() => new RenderMarkdown(validPartInfo as any)).to.not.throw;\n });\n\n it('renders markdown content', () => {\n const validPartInfo = {\n type: PartType.CHILD\n };\n\n const directive = new RenderMarkdown(validPartInfo as any);\n const result = directive.render('# Test Header');\n\n // The result should be a TemplateResult\n expect(result).to.exist;\n expect(result.strings).to.exist;\n });\n\n it('updates correctly', () => {\n const validPartInfo = {\n type: PartType.CHILD\n };\n\n const directive = new RenderMarkdown(validPartInfo as any);\n const mockPart = {} as any;\n\n const result = directive.update(mockPart, ['# Updated Content']);\n\n // Should return the same as render\n expect(result).to.exist;\n expect(result.strings).to.exist;\n });\n });\n\n describe('renderMarkdown function', () => {\n it('creates a directive that can be used in templates', () => {\n const template = html`${renderMarkdown('# Test')}`;\n\n // Should create a valid template\n expect(template).to.exist;\n expect(template.strings).to.exist;\n });\n\n it('renders markdown when used in a template', () => {\n const container = document.createElement('div');\n const template = html`${renderMarkdown('# Hello World')}`;\n\n render(template, container);\n\n // Check that the markdown was rendered to HTML\n expect(container.innerHTML).to.include('<h1>Hello World</h1>');\n });\n\n it('handles empty markdown', () => {\n const container = document.createElement('div');\n const template = html`${renderMarkdown('')}`;\n\n render(template, container);\n\n // Should not throw - Lit may add HTML comments for template placeholders\n expect(() => render(template, container)).to.not.throw;\n });\n\n it('handles markdown with special characters', () => {\n const container = document.createElement('div');\n const markdownWithSpecialChars =\n '**Bold** text with <script>alert(\"xss\")</script>';\n const template = html`${renderMarkdown(markdownWithSpecialChars)}`;\n\n render(template, container);\n\n // Should render the markdown but the script tag should be escaped/handled\n expect(container.innerHTML).to.include('<strong>Bold</strong>');\n // The script tag should be rendered as text or escaped\n expect(container.innerHTML).to.include('script');\n });\n\n it('renders complex markdown structures', () => {\n const complexMarkdown = `\n# Main Header\n\n## Sub Header\n\nThis is a paragraph with **bold** and *italic* text.\n\n- List item 1\n- List item 2\n - Nested item\n\n[A link](https://example.com)\n\n\\`\\`\\`\ncode block\n\\`\\`\\`\n`;\n\n const container = document.createElement('div');\n const template = html`${renderMarkdown(complexMarkdown)}`;\n\n render(template, container);\n\n expect(container.innerHTML).to.include('<h1>Main Header</h1>');\n expect(container.innerHTML).to.include('<h2>Sub Header</h2>');\n expect(container.innerHTML).to.include('<strong>bold</strong>');\n expect(container.innerHTML).to.include('<em>italic</em>');\n expect(container.innerHTML).to.include('<ul>');\n expect(container.innerHTML).to.include(\n '<a href=\"https://example.com\">A link</a>'\n );\n });\n });\n});\n"]}
|