@nyaruka/temba-components 0.134.6 → 0.136.0

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.
Files changed (76) hide show
  1. package/.github/workflows/publish.yml +16 -8
  2. package/CHANGELOG.md +84 -0
  3. package/demo/components/webchat/example.html +4 -2
  4. package/dist/static/svg/index.svg +1 -1
  5. package/dist/temba-components.js +1346 -334
  6. package/dist/temba-components.js.map +1 -1
  7. package/out-tsc/src/Icons.js +2 -1
  8. package/out-tsc/src/Icons.js.map +1 -1
  9. package/out-tsc/src/display/Chat.js +7 -2
  10. package/out-tsc/src/display/Chat.js.map +1 -1
  11. package/out-tsc/src/display/Thumbnail.js +65 -8
  12. package/out-tsc/src/display/Thumbnail.js.map +1 -1
  13. package/out-tsc/src/flow/CanvasNode.js +11 -0
  14. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  15. package/out-tsc/src/flow/Editor.js +224 -2
  16. package/out-tsc/src/flow/Editor.js.map +1 -1
  17. package/out-tsc/src/flow/Plumber.js +320 -1
  18. package/out-tsc/src/flow/Plumber.js.map +1 -1
  19. package/out-tsc/src/interfaces.js +1 -0
  20. package/out-tsc/src/interfaces.js.map +1 -1
  21. package/out-tsc/src/layout/FloatingWindow.js +30 -8
  22. package/out-tsc/src/layout/FloatingWindow.js.map +1 -1
  23. package/out-tsc/src/simulator/Simulator.js +1827 -0
  24. package/out-tsc/src/simulator/Simulator.js.map +1 -0
  25. package/out-tsc/src/store/AppState.js +33 -0
  26. package/out-tsc/src/store/AppState.js.map +1 -1
  27. package/out-tsc/src/utils.js +55 -6
  28. package/out-tsc/src/utils.js.map +1 -1
  29. package/out-tsc/temba-modules.js +2 -0
  30. package/out-tsc/temba-modules.js.map +1 -1
  31. package/out-tsc/test/temba-flow-editor.test.js +1 -1
  32. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  33. package/out-tsc/test/temba-flow-plumber-connections.test.js +3 -1
  34. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
  35. package/out-tsc/test/temba-flow-plumber.test.js +3 -1
  36. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  37. package/out-tsc/test/temba-simulator.test.js +642 -0
  38. package/out-tsc/test/temba-simulator.test.js.map +1 -0
  39. package/out-tsc/test/temba-thumbnail.test.js +120 -0
  40. package/out-tsc/test/temba-thumbnail.test.js.map +1 -0
  41. package/out-tsc/test/temba-utils-index.test.js +12 -6
  42. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  43. package/out-tsc/test/utils.test.js +1 -1
  44. package/out-tsc/test/utils.test.js.map +1 -1
  45. package/package.json +1 -1
  46. package/screenshots/truth/simulator/after-message-sent.png +0 -0
  47. package/screenshots/truth/simulator/after-reset.png +0 -0
  48. package/screenshots/truth/simulator/attachment-menu.png +0 -0
  49. package/screenshots/truth/simulator/context-expanded.png +0 -0
  50. package/screenshots/truth/simulator/context-explorer-open.png +0 -0
  51. package/screenshots/truth/simulator/event-info.png +0 -0
  52. package/screenshots/truth/simulator/image-attachment.png +0 -0
  53. package/screenshots/truth/simulator/open-initial.png +0 -0
  54. package/screenshots/truth/simulator/quick-replies.png +0 -0
  55. package/src/Icons.ts +2 -1
  56. package/src/display/Chat.ts +10 -1
  57. package/src/display/Thumbnail.ts +67 -8
  58. package/src/flow/CanvasNode.ts +12 -0
  59. package/src/flow/Editor.ts +240 -1
  60. package/src/flow/Plumber.ts +371 -2
  61. package/src/interfaces.ts +2 -1
  62. package/src/layout/FloatingWindow.ts +36 -11
  63. package/src/simulator/Simulator.ts +2008 -0
  64. package/src/store/AppState.ts +53 -0
  65. package/src/utils.ts +59 -6
  66. package/static/svg/index.svg +1 -1
  67. package/static/svg/work/traced/route.svg +1 -0
  68. package/static/svg/work/used/route.svg +3 -0
  69. package/temba-modules.ts +2 -0
  70. package/test/temba-flow-editor.test.ts +1 -1
  71. package/test/temba-flow-plumber-connections.test.ts +4 -1
  72. package/test/temba-flow-plumber.test.ts +4 -1
  73. package/test/temba-simulator.test.ts +866 -0
  74. package/test/temba-thumbnail.test.ts +150 -0
  75. package/test/temba-utils-index.test.ts +14 -6
  76. package/test/utils.test.ts +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temba-simulator.test.js","sourceRoot":"","sources":["../../test/temba-simulator.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { fixture, expect, assert } from '@open-wc/testing';\nimport { Simulator } from '../src/simulator/Simulator';\nimport {\n assertScreenshot,\n getClip,\n mockPOST,\n clearMockPosts,\n delay,\n waitForCondition,\n loadStore\n} from './utils.test';\n\nconst FLOW_UUID = 'test-flow-123';\n\nconst createSimulator = async (attrs: any = {}) => {\n // load store first since simulator depends on it\n await loadStore();\n\n const defaults = {\n flow: FLOW_UUID,\n animationTime: '0' // disable animations for deterministic tests\n };\n const mergedAttrs = { ...defaults, ...attrs };\n\n const attrString = Object.entries(mergedAttrs)\n .map(([key, value]) => `${key}=\"${value}\"`)\n .join(' ');\n\n const simulator: Simulator = await fixture(\n `<temba-simulator ${attrString}></temba-simulator>`\n );\n\n // reset cookie-based properties for deterministic tests\n simulator.size = 'medium';\n (simulator as any).following = true;\n (simulator as any).contextExplorerOpen = false;\n await simulator.updateComplete;\n\n return simulator;\n};\n\n// helper to open the simulator\nconst openSimulator = async (simulator: Simulator) => {\n const tab = simulator.shadowRoot.querySelector('temba-floating-tab') as any;\n expect(tab).to.exist;\n\n // trigger the button clicked event on the tab\n tab.dispatchEvent(new CustomEvent('temba-button-clicked', { bubbles: true }));\n\n await simulator.updateComplete;\n // brief delay for async API mock processing\n await delay(50);\n};\n\n// helper to get clip for the simulator window (fixed positioning)\nconst getSimulatorClip = (\n simulator: Simulator,\n includeContext: boolean = false\n) => {\n const phoneWindow = simulator.shadowRoot.querySelector(\n 'temba-floating-window'\n ) as any;\n\n if (!phoneWindow) {\n // if window not open, use default clip\n return getClip(simulator);\n }\n\n const windowElement = phoneWindow.shadowRoot?.querySelector(\n '.window'\n ) as HTMLElement;\n if (!windowElement) {\n return getClip(simulator);\n }\n\n const windowBounds = windowElement.getBoundingClientRect();\n\n if (includeContext) {\n // get the context explorer and phone to clip just those areas\n const phoneSimulator = phoneWindow.querySelector(\n '.phone-simulator'\n ) as HTMLElement;\n if (!phoneSimulator) {\n return getClip(simulator);\n }\n\n const contextExplorer = phoneSimulator.querySelector(\n '.context-explorer'\n ) as HTMLElement;\n const phoneFrame = phoneSimulator.querySelector(\n '.phone-frame'\n ) as HTMLElement;\n\n if (!contextExplorer || !phoneFrame) {\n return {\n x: windowBounds.x,\n y: windowBounds.y,\n width: windowBounds.width,\n height: windowBounds.height\n };\n }\n\n const contextBounds = contextExplorer.getBoundingClientRect();\n const phoneBounds = phoneFrame.getBoundingClientRect();\n\n // clip from the left edge of context explorer to the right edge of phone frame only\n // do not include the option-pane which is to the right of the phone\n // keep padding within the phone bounds to avoid capturing the gap to the option pane\n const padding = 10;\n const leftX = contextBounds.x - padding;\n\n // don't extend past the phone frame right edge - the option pane is close by\n const rightX = phoneBounds.right;\n\n const topY = Math.min(contextBounds.y, phoneBounds.y) - padding;\n const bottomY =\n Math.max(contextBounds.bottom, phoneBounds.bottom) + padding;\n\n return {\n x: leftX,\n y: topY,\n width: rightX - leftX,\n height: bottomY - topY\n };\n }\n\n // the phone-simulator is in the light DOM of the phoneWindow (slotted content)\n const phoneSimulator = phoneWindow.querySelector(\n '.phone-simulator'\n ) as HTMLElement;\n if (!phoneSimulator) {\n return getClip(simulator);\n }\n\n // get the phone-frame from within the phone-simulator\n const phoneFrame = phoneSimulator.querySelector(\n '.phone-frame'\n ) as HTMLElement;\n if (!phoneFrame) {\n // fallback to window bounds if phone-frame not found\n return {\n x: windowBounds.x,\n y: windowBounds.y,\n width: windowBounds.width,\n height: windowBounds.height\n };\n }\n\n const frameBounds = phoneFrame.getBoundingClientRect();\n\n // add padding around the phone frame\n const padding = 10;\n return {\n x: frameBounds.x - padding,\n y: frameBounds.y - padding,\n width: frameBounds.width + padding * 2,\n height: frameBounds.height + padding * 2\n };\n};\n\n// mock responses for simulation endpoints\nconst mockSimulatorStart = () => {\n const response = {\n session: {\n status: 'waiting',\n trigger: {\n type: 'manual',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' }\n },\n runs: [\n {\n uuid: 'run-1',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' },\n status: 'waiting',\n path: [\n {\n uuid: 'step-1',\n node_uuid: 'node-1',\n arrived_on: new Date().toISOString(),\n exit_uuid: null\n }\n ]\n }\n ],\n environment: {\n date_format: 'YYYY-MM-DD',\n time_format: 'HH:mm',\n timezone: 'America/New_York',\n allowed_languages: ['eng'],\n default_country: 'US'\n }\n },\n events: [\n {\n type: 'msg_created',\n created_on: new Date().toISOString(),\n msg: {\n uuid: 'msg-1',\n text: 'Hello! How can I help you today?',\n urn: 'tel:+12065551212'\n }\n }\n ],\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {},\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n },\n context: {\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n name: 'Test User',\n urns: {\n tel: ['+12065551212'],\n __default__: '+12065551212'\n },\n fields: {\n age: '25',\n city: 'Seattle'\n }\n },\n trigger: {\n type: 'manual',\n __default__: 'manual'\n }\n }\n };\n\n mockPOST(/\\/flow\\/simulate\\/.*\\//, response);\n};\n\nconst mockSimulatorResume = (responseText: string, quickReplies?: string[]) => {\n const msg: any = {\n uuid: 'msg-response',\n text: responseText,\n urn: 'tel:+12065551212'\n };\n\n if (quickReplies) {\n msg.quick_replies = quickReplies.map((text) => ({ text }));\n }\n\n const response = {\n session: {\n status: 'waiting',\n trigger: {\n type: 'manual',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' }\n },\n runs: [\n {\n uuid: 'run-1',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' },\n status: 'waiting',\n path: [\n {\n uuid: 'step-1',\n node_uuid: 'node-1',\n arrived_on: new Date().toISOString(),\n exit_uuid: 'exit-1'\n },\n {\n uuid: 'step-2',\n node_uuid: 'node-2',\n arrived_on: new Date().toISOString(),\n exit_uuid: null\n }\n ]\n }\n ],\n environment: {\n date_format: 'YYYY-MM-DD',\n time_format: 'HH:mm',\n timezone: 'America/New_York',\n allowed_languages: ['eng'],\n default_country: 'US'\n }\n },\n events: [\n {\n type: 'msg_created',\n created_on: new Date().toISOString(),\n msg\n }\n ],\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {\n age: '25',\n city: 'Seattle'\n },\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n },\n context: {\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n name: 'Test User',\n urns: {\n tel: ['+12065551212'],\n __default__: '+12065551212'\n },\n fields: {\n age: '25',\n city: 'Seattle'\n }\n },\n results: {\n user_response: {\n value: responseText,\n __default__: responseText\n }\n }\n }\n };\n\n mockPOST(/\\/flow\\/simulate\\/.*\\//, response);\n};\n\ndescribe('temba-simulator', () => {\n beforeEach(() => {\n clearMockPosts();\n });\n\n it('can be created', async () => {\n const simulator: Simulator = await createSimulator();\n assert.instanceOf(simulator, Simulator);\n expect(simulator.flow).to.equal(FLOW_UUID);\n expect(simulator.endpoint).to.equal(`/flow/simulate/${FLOW_UUID}/`);\n });\n\n it('opens simulator window and starts flow', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n // ensure consistent size for screenshot\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n const phoneWindow = simulator.shadowRoot.querySelector(\n 'temba-floating-window'\n ) as any;\n expect(phoneWindow).to.exist;\n\n // verify phone screen is visible\n const phoneScreen = simulator.shadowRoot.querySelector('.phone-screen');\n expect(phoneScreen).to.exist;\n\n // verify initial message is displayed\n const messages = simulator.shadowRoot.querySelectorAll('.message');\n expect(messages.length).to.be.greaterThan(0);\n\n await assertScreenshot(\n 'simulator/open-initial',\n getSimulatorClip(simulator)\n );\n });\n\n it('sends a text message', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // count initial messages\n let messages = simulator.shadowRoot.querySelectorAll('.message');\n const initialCount = messages.length;\n\n // mock the resume response\n mockSimulatorResume('Thanks for your message!');\n\n // type a message\n const input = simulator.shadowRoot.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n expect(input).to.exist;\n\n input.value = 'Hello from test';\n input.dispatchEvent(new Event('input'));\n await simulator.updateComplete;\n\n // press enter to send\n const enterEvent = new KeyboardEvent('keyup', {\n key: 'Enter',\n bubbles: true\n });\n input.dispatchEvent(enterEvent);\n\n await simulator.updateComplete;\n // brief delay for async API mock processing\n await delay(100);\n\n // verify we have more messages than before\n messages = simulator.shadowRoot.querySelectorAll('.message');\n expect(messages.length).to.be.greaterThan(initialCount);\n\n // ensure DOM is settled\n await simulator.updateComplete;\n\n await assertScreenshot(\n 'simulator/after-message-sent',\n getSimulatorClip(simulator)\n );\n });\n\n it('tests message flow and takes screenshot', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // clear previous mocks and set up new mock for a response\n clearMockPosts();\n mockSimulatorResume('Thank you for your message!', ['Yes', 'No', 'Maybe']);\n\n // send a message\n const input = simulator.shadowRoot.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n input.value = 'Test message';\n input.dispatchEvent(new Event('input'));\n\n const enterEvent = new KeyboardEvent('keyup', {\n key: 'Enter',\n bubbles: true\n });\n input.dispatchEvent(enterEvent);\n\n // wait for quick replies to appear\n await waitForCondition(\n () =>\n simulator.shadowRoot.querySelectorAll('.quick-reply-btn').length > 0,\n 2000\n );\n await simulator.updateComplete;\n\n // take screenshot with quick replies\n await assertScreenshot(\n 'simulator/quick-replies',\n getSimulatorClip(simulator)\n );\n });\n\n it('opens attachment menu', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // click the attachment button\n const attachmentButton = simulator.shadowRoot.querySelector(\n '.attachment-button'\n ) as HTMLElement;\n expect(attachmentButton).to.exist;\n attachmentButton.click();\n\n await simulator.updateComplete;\n\n // verify attachment menu is displayed\n const attachmentMenu =\n simulator.shadowRoot.querySelector('.attachment-menu');\n expect(attachmentMenu).to.exist;\n expect(attachmentMenu.classList.contains('open')).to.be.true;\n\n await assertScreenshot(\n 'simulator/attachment-menu',\n getSimulatorClip(simulator)\n );\n });\n\n it('sends an image attachment', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n // reset attachment indices for deterministic testing\n simulator.resetAttachmentIndices();\n await openSimulator(simulator);\n\n // mock the response for image attachment\n mockSimulatorResume('Nice picture!');\n\n // open attachment menu and click image option\n const attachmentButton = simulator.shadowRoot.querySelector(\n '.attachment-button'\n ) as HTMLElement;\n attachmentButton.click();\n await simulator.updateComplete;\n await delay(200);\n\n const imageMenuItem = Array.from(\n simulator.shadowRoot.querySelectorAll('.attachment-menu-item')\n ).find((el) => el.textContent?.includes('Image')) as HTMLElement;\n expect(imageMenuItem).to.exist;\n imageMenuItem.click();\n\n await delay(100);\n await simulator.updateComplete;\n\n // verify attachment wrapper is displayed (image attachments show in attachments not messages)\n const attachmentWrappers = simulator.shadowRoot.querySelectorAll(\n '.attachment-wrapper'\n );\n expect(attachmentWrappers.length).to.be.greaterThan(0);\n\n await assertScreenshot(\n 'simulator/image-attachment',\n getSimulatorClip(simulator)\n );\n });\n\n it('opens context explorer', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // find and click the context explorer button (has expressions icon)\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const contextButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"expressions\"]')\n ) as HTMLElement;\n expect(contextButton).to.exist;\n contextButton.click();\n\n await simulator.updateComplete;\n await delay(100);\n\n // verify context explorer is displayed\n const contextExplorer =\n simulator.shadowRoot.querySelector('.context-explorer');\n expect(contextExplorer).to.exist;\n expect(contextExplorer.classList.contains('open')).to.be.true;\n\n // delay for context explorer to fully render\n await delay(300);\n await simulator.updateComplete;\n await document.fonts.ready;\n\n await assertScreenshot(\n 'simulator/context-explorer-open',\n getSimulatorClip(simulator, true)\n );\n });\n\n it('expands context tree items', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // ensure context explorer starts closed\n if ((simulator as any).contextExplorerOpen) {\n // click to close it first\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const contextButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"expressions\"]')\n ) as HTMLElement;\n contextButton.click();\n await simulator.updateComplete;\n await delay(100);\n }\n\n // now open context explorer\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const contextButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"expressions\"]')\n ) as HTMLElement;\n expect(contextButton).to.exist;\n contextButton.click();\n\n await simulator.updateComplete;\n await delay(100);\n\n // verify context explorer is now open\n expect((simulator as any).contextExplorerOpen).to.be.true;\n const contextExplorer =\n simulator.shadowRoot.querySelector('.context-explorer');\n expect(contextExplorer).to.exist;\n expect(contextExplorer.classList.contains('open')).to.be.true;\n\n // find and click on an expandable item (should have context-item-expandable class)\n const expandableItems = simulator.shadowRoot.querySelectorAll(\n '.context-item-expandable'\n );\n expect(expandableItems.length).to.be.greaterThan(0);\n\n const firstExpandable = expandableItems[0] as HTMLElement;\n firstExpandable.click();\n\n // wait for children to be displayed with specific content\n await waitForCondition(() => {\n const children =\n simulator.shadowRoot.querySelectorAll('.context-children');\n if (children.length === 0) return false;\n // also check that the children have rendered content\n const items = simulator.shadowRoot.querySelectorAll('.context-item');\n return items.length > expandableItems.length;\n }, 2000);\n\n // verify children are displayed\n const contextChildren =\n simulator.shadowRoot.querySelectorAll('.context-children');\n expect(contextChildren.length).to.be.greaterThan(0);\n\n await simulator.updateComplete;\n // delay for DOM to fully render expanded content (context rendering is complex)\n await delay(300);\n await simulator.updateComplete;\n\n // ensure fonts are loaded and give extra time for rendering\n await document.fonts.ready;\n\n // wait for any pending animation frames\n await new Promise((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(resolve))\n );\n await delay(200);\n\n await assertScreenshot(\n 'simulator/context-expanded',\n getSimulatorClip(simulator, true)\n );\n });\n\n it('cycles simulator size', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // initially should be medium (set in createSimulator)\n expect(simulator.size).to.equal('medium');\n\n // find and click the size button (shows current size as text)\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const sizeButton = optionButtons.find((btn) => {\n const text = btn.textContent?.trim();\n return text === 'S' || text === 'M' || text === 'L';\n }) as HTMLElement;\n expect(sizeButton).to.exist;\n sizeButton.click();\n\n await simulator.updateComplete;\n\n // should now be large (medium -> large)\n expect(simulator.size).to.equal('large');\n });\n\n it('resets simulation', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // send a message first\n mockSimulatorResume('Response to test message');\n const input = simulator.shadowRoot.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n input.value = 'Test message';\n input.dispatchEvent(new Event('input'));\n\n const enterEvent = new KeyboardEvent('keyup', {\n key: 'Enter',\n bubbles: true\n });\n input.dispatchEvent(enterEvent);\n\n await delay(1000);\n await simulator.updateComplete;\n\n // verify we have multiple messages\n let messages = simulator.shadowRoot.querySelectorAll('.message');\n const messageCountBefore = messages.length;\n expect(messageCountBefore).to.be.greaterThan(1);\n\n // mock the start response for reset\n mockSimulatorStart();\n\n // click the reset button (has delete icon)\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const resetButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"delete\"]')\n ) as HTMLElement;\n expect(resetButton).to.exist;\n resetButton.click();\n\n await delay(100);\n await simulator.updateComplete;\n\n // verify messages are reset - should go back to just initial message\n messages = simulator.shadowRoot.querySelectorAll('.message');\n expect(messages.length).to.be.lessThan(messageCountBefore);\n\n await assertScreenshot(\n 'simulator/after-reset',\n getSimulatorClip(simulator)\n );\n });\n\n it('displays event info messages', async () => {\n const responseWithEvents = {\n session: {\n status: 'waiting',\n trigger: {\n type: 'manual',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' }\n },\n runs: [\n {\n uuid: 'run-1',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' },\n status: 'waiting',\n path: [\n {\n uuid: 'step-1',\n node_uuid: 'node-1',\n arrived_on: new Date().toISOString(),\n exit_uuid: null\n }\n ]\n }\n ],\n environment: {\n date_format: 'YYYY-MM-DD',\n time_format: 'HH:mm',\n timezone: 'America/New_York',\n allowed_languages: ['eng'],\n default_country: 'US'\n }\n },\n events: [\n {\n type: 'contact_field_changed',\n created_on: new Date().toISOString(),\n field: { key: 'name', name: 'Name' },\n value: { text: 'John Doe' }\n },\n {\n type: 'msg_created',\n created_on: new Date().toISOString(),\n msg: {\n uuid: 'msg-1',\n text: 'Your name has been updated!',\n urn: 'tel:+12065551212'\n }\n }\n ],\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {\n name: 'John Doe'\n },\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n },\n context: {\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n name: 'John Doe',\n fields: {\n name: 'John Doe'\n }\n }\n }\n };\n\n mockPOST(/\\/flow\\/simulate\\/.*\\//, responseWithEvents);\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // verify event info is displayed\n const eventInfo = simulator.shadowRoot.querySelectorAll('.event-info');\n expect(eventInfo.length).to.be.greaterThan(0);\n\n await assertScreenshot('simulator/event-info', getSimulatorClip(simulator));\n });\n\n it('displays different simulator sizes', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // get size button - find it by checking if textContent is a size indicator\n let optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n let sizeButton = optionButtons.find((btn) => {\n const text = btn.textContent?.trim();\n return text === 'S' || text === 'M' || text === 'L';\n }) as HTMLElement;\n expect(sizeButton).to.exist;\n\n // cycle to next size\n sizeButton.click();\n await simulator.updateComplete;\n await delay(200);\n\n // verify size changed\n expect(simulator.size).to.equal('large');\n\n // re-query the button after it updated\n optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n sizeButton = optionButtons.find((btn) => {\n const text = btn.textContent?.trim();\n return text === 'S' || text === 'M' || text === 'L';\n }) as HTMLElement;\n\n // cycle to next size\n sizeButton.click();\n await simulator.updateComplete;\n await delay(200);\n\n expect(simulator.size).to.equal('small');\n });\n\n it('verifies simulator endpoint configuration', async () => {\n const simulator: Simulator = await createSimulator();\n\n // verify endpoint is set correctly from flow prop\n expect(simulator.endpoint).to.equal(`/flow/simulate/${FLOW_UUID}/`);\n\n // change flow prop and verify endpoint updates\n simulator.flow = 'different-flow-456';\n await simulator.updateComplete;\n\n expect(simulator.endpoint).to.equal('/flow/simulate/different-flow-456/');\n });\n});\n"]}
@@ -0,0 +1,120 @@
1
+ import { assert, expect } from '@open-wc/testing';
2
+ import { Thumbnail } from '../src/display/Thumbnail';
3
+ import { getComponent } from './utils.test';
4
+ const TAG = 'temba-thumbnail';
5
+ const getThumbnail = async (attrs = {}) => {
6
+ return (await getComponent(TAG, attrs));
7
+ };
8
+ describe('temba-thumbnail', () => {
9
+ it('can be created', async () => {
10
+ const thumbnail = await getThumbnail();
11
+ assert.instanceOf(thumbnail, Thumbnail);
12
+ });
13
+ it('renders location thumbnail with map tile', async () => {
14
+ // test that a location attachment properly uses latLngToTile in render
15
+ const thumbnail = await getThumbnail({
16
+ attachment: 'geo:40.7128,-74.0060'
17
+ });
18
+ await thumbnail.updateComplete;
19
+ expect(thumbnail.latitude).to.equal(40.7128);
20
+ expect(thumbnail.longitude).to.equal(-74.006);
21
+ expect(thumbnail.contentType).to.equal('location');
22
+ // verify the rendered image contains the correct tile URL
23
+ const img = thumbnail.shadowRoot.querySelector('img');
24
+ expect(img).to.exist;
25
+ expect(img.src).to.include('tile.openstreetmap.org');
26
+ expect(img.src).to.include('/13/'); // zoom level
27
+ });
28
+ describe('latLngToTile', () => {
29
+ it('converts coordinates at 0,0', async () => {
30
+ const thumbnail = await getThumbnail();
31
+ // test at zoom level 0
32
+ const tile0 = thumbnail.latLngToTile(0, 0, 0);
33
+ expect(tile0.x).to.equal(0);
34
+ expect(tile0.y).to.equal(0);
35
+ expect(tile0.z).to.equal(0);
36
+ // test at zoom level 10
37
+ const tile10 = thumbnail.latLngToTile(0, 0, 10);
38
+ expect(tile10.x).to.equal(512);
39
+ expect(tile10.y).to.equal(512);
40
+ expect(tile10.z).to.equal(10);
41
+ });
42
+ it('converts positive coordinates', async () => {
43
+ const thumbnail = await getThumbnail();
44
+ // test London coordinates at zoom 13
45
+ const londonTile = thumbnail.latLngToTile(51.5074, -0.1278, 13);
46
+ expect(londonTile.x).to.equal(4093);
47
+ expect(londonTile.y).to.equal(2724);
48
+ expect(londonTile.z).to.equal(13);
49
+ });
50
+ it('converts negative coordinates', async () => {
51
+ const thumbnail = await getThumbnail();
52
+ // test Sydney coordinates (negative latitude) at zoom 13
53
+ const sydneyTile = thumbnail.latLngToTile(-33.8688, 151.2093, 13);
54
+ expect(sydneyTile.x).to.equal(7536);
55
+ expect(sydneyTile.y).to.equal(4915);
56
+ expect(sydneyTile.z).to.equal(13);
57
+ });
58
+ it('converts coordinates near the North Pole', async () => {
59
+ const thumbnail = await getThumbnail();
60
+ // test near North Pole (85.05 is practical limit for Web Mercator)
61
+ const northPoleTile = thumbnail.latLngToTile(85, 0, 5);
62
+ expect(northPoleTile.x).to.equal(16);
63
+ expect(northPoleTile.y).to.equal(0);
64
+ expect(northPoleTile.z).to.equal(5);
65
+ });
66
+ it('converts coordinates near the South Pole', async () => {
67
+ const thumbnail = await getThumbnail();
68
+ // test near South Pole (-85.05 is practical limit for Web Mercator)
69
+ const southPoleTile = thumbnail.latLngToTile(-85, 0, 5);
70
+ expect(southPoleTile.x).to.equal(16);
71
+ expect(southPoleTile.y).to.equal(31);
72
+ expect(southPoleTile.z).to.equal(5);
73
+ });
74
+ it('converts coordinates near the Date Line (positive)', async () => {
75
+ const thumbnail = await getThumbnail();
76
+ // test near Date Line (179.9 longitude)
77
+ const dateLineTile = thumbnail.latLngToTile(0, 179.9, 10);
78
+ expect(dateLineTile.x).to.equal(1023);
79
+ expect(dateLineTile.y).to.equal(512);
80
+ expect(dateLineTile.z).to.equal(10);
81
+ });
82
+ it('converts coordinates near the Date Line (negative)', async () => {
83
+ const thumbnail = await getThumbnail();
84
+ // test near Date Line (-179.9 longitude)
85
+ const dateLineTile = thumbnail.latLngToTile(0, -179.9, 10);
86
+ expect(dateLineTile.x).to.equal(0);
87
+ expect(dateLineTile.y).to.equal(512);
88
+ expect(dateLineTile.z).to.equal(10);
89
+ });
90
+ it('works correctly with zoom level 1', async () => {
91
+ const thumbnail = await getThumbnail();
92
+ const tile = thumbnail.latLngToTile(40.7128, -74.006, 1);
93
+ expect(tile.x).to.equal(0);
94
+ expect(tile.y).to.equal(0);
95
+ expect(tile.z).to.equal(1);
96
+ });
97
+ it('works correctly with zoom level 5', async () => {
98
+ const thumbnail = await getThumbnail();
99
+ const tile = thumbnail.latLngToTile(40.7128, -74.006, 5);
100
+ expect(tile.x).to.equal(9);
101
+ expect(tile.y).to.equal(12);
102
+ expect(tile.z).to.equal(5);
103
+ });
104
+ it('works correctly with zoom level 15', async () => {
105
+ const thumbnail = await getThumbnail();
106
+ const tile = thumbnail.latLngToTile(40.7128, -74.006, 15);
107
+ expect(tile.x).to.equal(9647);
108
+ expect(tile.y).to.equal(12320);
109
+ expect(tile.z).to.equal(15);
110
+ });
111
+ it('works correctly with zoom level 18 (maximum)', async () => {
112
+ const thumbnail = await getThumbnail();
113
+ const tile = thumbnail.latLngToTile(40.7128, -74.006, 18);
114
+ expect(tile.x).to.equal(77182);
115
+ expect(tile.y).to.equal(98561);
116
+ expect(tile.z).to.equal(18);
117
+ });
118
+ });
119
+ });
120
+ //# sourceMappingURL=temba-thumbnail.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temba-thumbnail.test.js","sourceRoot":"","sources":["../../test/temba-thumbnail.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, expect } from '@open-wc/testing';\nimport { Thumbnail } from '../src/display/Thumbnail';\nimport { getComponent } from './utils.test';\n\nconst TAG = 'temba-thumbnail';\nconst getThumbnail = async (attrs: any = {}) => {\n return (await getComponent(TAG, attrs)) as Thumbnail;\n};\n\ndescribe('temba-thumbnail', () => {\n it('can be created', async () => {\n const thumbnail = await getThumbnail();\n assert.instanceOf(thumbnail, Thumbnail);\n });\n\n it('renders location thumbnail with map tile', async () => {\n // test that a location attachment properly uses latLngToTile in render\n const thumbnail = await getThumbnail({\n attachment: 'geo:40.7128,-74.0060'\n });\n await thumbnail.updateComplete;\n expect(thumbnail.latitude).to.equal(40.7128);\n expect(thumbnail.longitude).to.equal(-74.006);\n expect(thumbnail.contentType).to.equal('location');\n\n // verify the rendered image contains the correct tile URL\n const img = thumbnail.shadowRoot.querySelector('img');\n expect(img).to.exist;\n expect(img.src).to.include('tile.openstreetmap.org');\n expect(img.src).to.include('/13/'); // zoom level\n });\n\n describe('latLngToTile', () => {\n it('converts coordinates at 0,0', async () => {\n const thumbnail = await getThumbnail();\n\n // test at zoom level 0\n const tile0 = (thumbnail as any).latLngToTile(0, 0, 0);\n expect(tile0.x).to.equal(0);\n expect(tile0.y).to.equal(0);\n expect(tile0.z).to.equal(0);\n\n // test at zoom level 10\n const tile10 = (thumbnail as any).latLngToTile(0, 0, 10);\n expect(tile10.x).to.equal(512);\n expect(tile10.y).to.equal(512);\n expect(tile10.z).to.equal(10);\n });\n\n it('converts positive coordinates', async () => {\n const thumbnail = await getThumbnail();\n\n // test London coordinates at zoom 13\n const londonTile = (thumbnail as any).latLngToTile(51.5074, -0.1278, 13);\n expect(londonTile.x).to.equal(4093);\n expect(londonTile.y).to.equal(2724);\n expect(londonTile.z).to.equal(13);\n });\n\n it('converts negative coordinates', async () => {\n const thumbnail = await getThumbnail();\n\n // test Sydney coordinates (negative latitude) at zoom 13\n const sydneyTile = (thumbnail as any).latLngToTile(\n -33.8688,\n 151.2093,\n 13\n );\n expect(sydneyTile.x).to.equal(7536);\n expect(sydneyTile.y).to.equal(4915);\n expect(sydneyTile.z).to.equal(13);\n });\n\n it('converts coordinates near the North Pole', async () => {\n const thumbnail = await getThumbnail();\n\n // test near North Pole (85.05 is practical limit for Web Mercator)\n const northPoleTile = (thumbnail as any).latLngToTile(85, 0, 5);\n expect(northPoleTile.x).to.equal(16);\n expect(northPoleTile.y).to.equal(0);\n expect(northPoleTile.z).to.equal(5);\n });\n\n it('converts coordinates near the South Pole', async () => {\n const thumbnail = await getThumbnail();\n\n // test near South Pole (-85.05 is practical limit for Web Mercator)\n const southPoleTile = (thumbnail as any).latLngToTile(-85, 0, 5);\n expect(southPoleTile.x).to.equal(16);\n expect(southPoleTile.y).to.equal(31);\n expect(southPoleTile.z).to.equal(5);\n });\n\n it('converts coordinates near the Date Line (positive)', async () => {\n const thumbnail = await getThumbnail();\n\n // test near Date Line (179.9 longitude)\n const dateLineTile = (thumbnail as any).latLngToTile(0, 179.9, 10);\n expect(dateLineTile.x).to.equal(1023);\n expect(dateLineTile.y).to.equal(512);\n expect(dateLineTile.z).to.equal(10);\n });\n\n it('converts coordinates near the Date Line (negative)', async () => {\n const thumbnail = await getThumbnail();\n\n // test near Date Line (-179.9 longitude)\n const dateLineTile = (thumbnail as any).latLngToTile(0, -179.9, 10);\n expect(dateLineTile.x).to.equal(0);\n expect(dateLineTile.y).to.equal(512);\n expect(dateLineTile.z).to.equal(10);\n });\n\n it('works correctly with zoom level 1', async () => {\n const thumbnail = await getThumbnail();\n\n const tile = (thumbnail as any).latLngToTile(40.7128, -74.006, 1);\n expect(tile.x).to.equal(0);\n expect(tile.y).to.equal(0);\n expect(tile.z).to.equal(1);\n });\n\n it('works correctly with zoom level 5', async () => {\n const thumbnail = await getThumbnail();\n\n const tile = (thumbnail as any).latLngToTile(40.7128, -74.006, 5);\n expect(tile.x).to.equal(9);\n expect(tile.y).to.equal(12);\n expect(tile.z).to.equal(5);\n });\n\n it('works correctly with zoom level 15', async () => {\n const thumbnail = await getThumbnail();\n\n const tile = (thumbnail as any).latLngToTile(40.7128, -74.006, 15);\n expect(tile.x).to.equal(9647);\n expect(tile.y).to.equal(12320);\n expect(tile.z).to.equal(15);\n });\n\n it('works correctly with zoom level 18 (maximum)', async () => {\n const thumbnail = await getThumbnail();\n\n const tile = (thumbnail as any).latLngToTile(40.7128, -74.006, 18);\n expect(tile.x).to.equal(77182);\n expect(tile.y).to.equal(98561);\n expect(tile.z).to.equal(18);\n });\n });\n});\n"]}
@@ -106,20 +106,26 @@ describe('utils/index', () => {
106
106
  const headers = getHeaders();
107
107
  expect(headers['X-CSRFToken']).to.equal('form-csrf-token');
108
108
  });
109
- it('includes org id when available', () => {
110
- window.org_id = '123';
109
+ it('includes org uuid when available', () => {
110
+ window.workspace = {
111
+ uuid: '3a7e2f10-b0b3-413d-bd84-626e147d5ed2',
112
+ anon: false
113
+ };
111
114
  const headers = getHeaders();
112
- expect(headers['X-Temba-Org']).to.equal('123');
115
+ expect(headers['X-Temba-Workspace']).to.equal('3a7e2f10-b0b3-413d-bd84-626e147d5ed2');
113
116
  });
114
117
  it('merges provided headers', () => {
115
118
  const headers = getHeaders({ 'Custom-Header': 'custom-value' });
116
119
  expect(headers['Custom-Header']).to.equal('custom-value');
117
120
  expect(headers['X-Requested-With']).to.equal('XMLHttpRequest');
118
121
  });
119
- it('removes X-Temba-Org when X-Temba-Service-Org is provided', () => {
120
- window.org_id = '123';
122
+ it('removes X-Temba-Workspace when X-Temba-Service-Org is provided', () => {
123
+ window.workspace = {
124
+ uuid: '3a7e2f10-b0b3-413d-bd84-626e147d5ed2',
125
+ anon: false
126
+ };
121
127
  const headers = getHeaders({ 'X-Temba-Service-Org': 'service-org' });
122
- expect(headers['X-Temba-Org']).to.be.undefined;
128
+ expect(headers['X-Temba-Workspace']).to.be.undefined;
123
129
  expect(headers['X-Temba-Service-Org']).to.equal('service-org');
124
130
  });
125
131
  });