@elliemae/pui-app-bridge 2.23.6 → 2.24.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 (61) hide show
  1. package/dist/cjs/appBridge.js +31 -1
  2. package/dist/cjs/e2e-host.html +505 -0
  3. package/dist/cjs/e2e-index.html +100 -0
  4. package/dist/cjs/index.html +51 -11
  5. package/dist/cjs/microfeHost.js +5 -1
  6. package/dist/esm/appBridge.js +31 -1
  7. package/dist/esm/e2e-host.html +505 -0
  8. package/dist/esm/e2e-index.html +100 -0
  9. package/dist/esm/index.html +51 -11
  10. package/dist/esm/microfeHost.js +5 -1
  11. package/dist/public/e2e-host.html +4 -0
  12. package/dist/public/e2e-host.js +7 -0
  13. package/dist/public/e2e-host.js.br +0 -0
  14. package/dist/public/e2e-host.js.gz +0 -0
  15. package/dist/public/e2e-host.js.map +1 -0
  16. package/dist/public/e2e-index.html +1 -0
  17. package/dist/public/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js +17 -0
  18. package/dist/public/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js.br +0 -0
  19. package/dist/public/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js.gz +0 -0
  20. package/dist/public/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js.map +1 -0
  21. package/dist/public/e2eIntermediateGuest/latest/manifest.json +3 -0
  22. package/dist/public/e2eTestGuest/latest/e2eTestGuest.checksum.js +48 -0
  23. package/dist/public/e2eTestGuest/latest/e2eTestGuest.checksum.js.br +0 -0
  24. package/dist/public/e2eTestGuest/latest/e2eTestGuest.checksum.js.gz +0 -0
  25. package/dist/public/e2eTestGuest/latest/e2eTestGuest.checksum.js.map +1 -0
  26. package/dist/public/e2eTestGuest/latest/manifest.json +3 -0
  27. package/dist/public/frame.html +1 -1
  28. package/dist/public/index.html +1 -1
  29. package/dist/public/js/{emuiAppBridge.cd5a9c6779f9aab2eec6.js → emuiAppBridge.5a6bc2ea1f03ee954a75.js} +8 -8
  30. package/dist/public/js/emuiAppBridge.5a6bc2ea1f03ee954a75.js.br +0 -0
  31. package/dist/public/js/emuiAppBridge.5a6bc2ea1f03ee954a75.js.gz +0 -0
  32. package/dist/public/js/emuiAppBridge.5a6bc2ea1f03ee954a75.js.map +1 -0
  33. package/dist/public/latest/app.config.json +20 -0
  34. package/dist/types/lib/typings/host.d.ts +7 -0
  35. package/dist/types/tsconfig.tsbuildinfo +1 -1
  36. package/dist/umd/e2e-host.html +4 -0
  37. package/dist/umd/e2e-host.js +7 -0
  38. package/dist/umd/e2e-host.js.br +0 -0
  39. package/dist/umd/e2e-host.js.gz +0 -0
  40. package/dist/umd/e2e-host.js.map +1 -0
  41. package/dist/umd/e2e-index.html +1 -0
  42. package/dist/umd/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js +17 -0
  43. package/dist/umd/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js.br +0 -0
  44. package/dist/umd/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js.gz +0 -0
  45. package/dist/umd/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js.map +1 -0
  46. package/dist/umd/e2eIntermediateGuest/latest/manifest.json +3 -0
  47. package/dist/umd/e2eTestGuest/latest/e2eTestGuest.checksum.js +48 -0
  48. package/dist/umd/e2eTestGuest/latest/e2eTestGuest.checksum.js.br +0 -0
  49. package/dist/umd/e2eTestGuest/latest/e2eTestGuest.checksum.js.gz +0 -0
  50. package/dist/umd/e2eTestGuest/latest/e2eTestGuest.checksum.js.map +1 -0
  51. package/dist/umd/e2eTestGuest/latest/manifest.json +3 -0
  52. package/dist/umd/index.html +1 -1
  53. package/dist/umd/index.js +7 -7
  54. package/dist/umd/index.js.br +0 -0
  55. package/dist/umd/index.js.gz +0 -0
  56. package/dist/umd/index.js.map +1 -1
  57. package/dist/umd/latest/app.config.json +20 -0
  58. package/package.json +4 -4
  59. package/dist/public/js/emuiAppBridge.cd5a9c6779f9aab2eec6.js.br +0 -0
  60. package/dist/public/js/emuiAppBridge.cd5a9c6779f9aab2eec6.js.gz +0 -0
  61. package/dist/public/js/emuiAppBridge.cd5a9c6779f9aab2eec6.js.map +0 -1
@@ -0,0 +1,100 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AppBridge E2E Test Suite</title>
7
+ <script src="https://cdn.tailwindcss.com?plugins=forms"></script>
8
+ </head>
9
+ <body class="bg-gray-50">
10
+ <header class="bg-gray-900 text-white px-6 py-4">
11
+ <h1 class="text-xl font-bold">AppBridge End-to-End Test Suite</h1>
12
+ <p class="text-sm text-gray-400 mt-1">
13
+ Comprehensive blackbox tests for AppBridge (in-process micro-frontend
14
+ framework). Each page includes test steps, expected values, and a
15
+ verification checklist.
16
+ </p>
17
+ </header>
18
+
19
+ <main class="mx-auto max-w-5xl px-6 py-6">
20
+ <section
21
+ class="mb-6 bg-yellow-50 border border-yellow-200 rounded-lg p-4"
22
+ >
23
+ <h2 class="text-sm font-semibold text-yellow-800 mb-2">
24
+ Setup Instructions
25
+ </h2>
26
+ <ol class="text-xs text-yellow-700 list-decimal ml-4 space-y-1">
27
+ <li>
28
+ Install dependencies:
29
+ <code class="bg-yellow-100 px-1 rounded">pnpm install</code>
30
+ </li>
31
+ <li>
32
+ Start AppBridge dev server:
33
+ <code class="bg-yellow-100 px-1 rounded"
34
+ >cd libs/app-bridge && pnpm start</code
35
+ >
36
+ (default port 3000)
37
+ </li>
38
+ <li>
39
+ Open
40
+ <code class="bg-yellow-100 px-1 rounded"
41
+ >http://localhost:3000/e2e-index.html</code
42
+ >
43
+ in the browser
44
+ </li>
45
+ <li>
46
+ Each test page has
47
+ <code class="bg-yellow-100 px-1 rounded">data-testid</code>
48
+ attributes for Playwright/Cypress selectors
49
+ </li>
50
+ </ol>
51
+ </section>
52
+
53
+ <section class="mb-6">
54
+ <h2 class="text-lg font-semibold text-gray-800 border-b pb-1 mb-3">
55
+ 1. Core AppBridge Host Tests
56
+ </h2>
57
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
58
+ <a
59
+ href="./e2e-host.html"
60
+ data-testid="link-e2e-host"
61
+ class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
62
+ >
63
+ <h3 class="font-medium text-indigo-700">Comprehensive E2E Host</h3>
64
+ <p class="text-xs text-gray-500 mt-1">
65
+ All host scenarios: openApp, closeApp, scripting objects, events,
66
+ lifecycle, metadata, callContext.
67
+ </p>
68
+ <p class="text-xs text-gray-400 mt-2">
69
+ <strong>What to verify:</strong> Apps open and mount into
70
+ containers. Scripting objects can be added/removed/invoked with
71
+ correct callContext. Events reach subscribed apps.
72
+ closeApp/closeAllApps cleans up properly.
73
+ </p>
74
+ <div class="mt-2 text-xs text-gray-400">
75
+ <strong>Test Cases:</strong>
76
+ TC-APP-01..04 &bull; TC-SO-01..06 &bull; TC-EVT-01..03 &bull;
77
+ TC-LIFE-01..04 &bull; TC-META-01
78
+ </div>
79
+ </a>
80
+ <a
81
+ href="./index.html"
82
+ data-testid="link-main-demo"
83
+ class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
84
+ >
85
+ <h3 class="font-medium text-indigo-700">Main Demo App</h3>
86
+ <p class="text-xs text-gray-500 mt-1">
87
+ Original Loan Application demo with credit, pricing, and loan
88
+ validation micro-apps.
89
+ </p>
90
+ <p class="text-xs text-gray-400 mt-2">
91
+ <strong>What to verify:</strong> Loan form data flows to guest
92
+ apps. Events (onLoanAmountChanged, etc.) update guest UIs. Credit
93
+ score updates from guest. Save dispatches onPreSave with feedback.
94
+ </p>
95
+ </a>
96
+ </div>
97
+ </section>
98
+ </main>
99
+ </body>
100
+ </html>
@@ -6,43 +6,83 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Host</title>
8
8
  <script src="https://cdn.tailwindcss.com?plugins=forms"></script>
9
- <script src="https://cdn.mortgagetech.q1.ice.com/pui-diagnostics@3" ></script>
9
+ <script src="https://cdn.mortgagetech.q1.ice.com/pui-diagnostics@3"></script>
10
10
  </head>
11
11
  <body>
12
- <header class="bg-indigo-300 h-10 flex place-items-center">
12
+ <header class="bg-indigo-300 h-10 flex place-items-center justify-between">
13
13
  <div class="px-2">ICE Mortgage Product</div>
14
+ <nav class="flex gap-3 px-2 text-sm">
15
+ <a
16
+ href="./e2e-index.html"
17
+ class="text-indigo-800 hover:text-indigo-950 font-medium"
18
+ >E2E Test Suite</a
19
+ >
20
+ <a
21
+ href="./e2e-host.html"
22
+ class="text-indigo-800 hover:text-indigo-950 font-medium"
23
+ >E2E Host</a
24
+ >
25
+ </nav>
14
26
  </header>
15
27
  <main class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
16
28
  <div class="min-w-0 flex-1 mt-4">
17
- <h1 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">Loan Application</h2>
29
+ <h1
30
+ class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight"
31
+ >
32
+ Loan Application
33
+ </h1>
18
34
  </div>
19
35
  <!-- success feedback -->
20
36
  <div id="successFeedback" class="hidden rounded-md bg-green-50 p-4">
21
37
  <div class="flex">
22
38
  <div class="flex-shrink-0">
23
39
  <!-- Heroicon name: mini/check-circle -->
24
- <svg class="h-5 w-5 text-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
25
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
40
+ <svg
41
+ class="h-5 w-5 text-green-400"
42
+ xmlns="http://www.w3.org/2000/svg"
43
+ viewBox="0 0 20 20"
44
+ fill="currentColor"
45
+ aria-hidden="true"
46
+ >
47
+ <path
48
+ fill-rule="evenodd"
49
+ d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
50
+ clip-rule="evenodd"
51
+ />
26
52
  </svg>
27
53
  </div>
28
54
  <div class="ml-3">
29
- <p class="text-sm font-medium text-green-800">Loan Saved Successfully</p>
30
- </div>
55
+ <p class="text-sm font-medium text-green-800">
56
+ Loan Saved Successfully
57
+ </p>
58
+ </div>
31
59
  </div>
32
60
  </div>
33
61
  <!-- error feedback -->
34
62
  <div id="errorFeedback" class="hidden rounded-md bg-red-50 p-4">
35
63
  <div class="flex">
36
64
  <div class="flex-shrink-0">
37
- <svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
38
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
65
+ <svg
66
+ class="h-5 w-5 text-red-400"
67
+ xmlns="http://www.w3.org/2000/svg"
68
+ viewBox="0 0 20 20"
69
+ fill="currentColor"
70
+ aria-hidden="true"
71
+ >
72
+ <path
73
+ fill-rule="evenodd"
74
+ d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
75
+ clip-rule="evenodd"
76
+ />
39
77
  </svg>
40
78
  </div>
41
79
  <div class="ml-3">
42
- <h3 class="text-sm font-medium text-red-800">Credit Score is not meeting the requirement</h3>
80
+ <h3 class="text-sm font-medium text-red-800">
81
+ Credit Score is not meeting the requirement
82
+ </h3>
43
83
  </div>
44
84
  </div>
45
- </div>
85
+ </div>
46
86
  <div class="mt-2 sm:grid sm:grid-cols-2 sm:gap-2">
47
87
  <form class="px-2 py-2 space-y-8 divide-y divide-gray-200 bg-gray-50">
48
88
  <div class="space-y-8 divide-y divide-gray-200 sm:space-y-5">
@@ -55,8 +55,12 @@ class CMicroFEHost {
55
55
  } else if (isPublicFunction(propValue, propName)) {
56
56
  Object.defineProperty(proxy, propName, {
57
57
  value: (...args) => {
58
+ const existingCallChain = proxy[propName]?.callContext?.callChain;
58
59
  Object.defineProperty(propValue, "callContext", {
59
- value: { guest: this.#guest },
60
+ value: {
61
+ guest: this.#guest,
62
+ ...existingCallChain?.length ? { callChain: existingCallChain } : {}
63
+ },
60
64
  configurable: true,
61
65
  enumerable: true,
62
66
  writable: true
@@ -0,0 +1,4 @@
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>AppBridge E2E — Comprehensive Host Test</title><script src="https://cdn.tailwindcss.com?plugins=forms"></script><script src="https://cdn.mortgagetech.q1.ice.com/pui-diagnostics@3"></script><script defer="defer" src="js/emuiAppBridge.5a6bc2ea1f03ee954a75.js"></script></head><body class="bg-gray-50"><header class="bg-indigo-600 text-white px-4 py-3 flex items-center justify-between"><h1 class="text-lg font-semibold">AppBridge E2E — Comprehensive Host Test</h1><a href="./e2e-index.html" class="text-indigo-200 hover:text-white text-sm">&larr; Back to dashboard</a></header><main class="mx-auto max-w-7xl px-4 py-4"><div class="bg-blue-50 border border-blue-200 rounded-md p-3 mb-4"><h2 class="text-sm font-bold text-blue-900 mb-1">How to Use This Page</h2><ol class="text-xs text-blue-800 list-decimal ml-4 space-y-1"><li>Wait for <strong>"E2E Host ready"</strong> in the Event Log.</li><li>Use buttons in each section to test AppBridge features.</li><li>Check Event Log and result panels for expected output.</li><li>Work through the Verification Checklist at the bottom.</li></ol></div><div class="grid grid-cols-3 gap-4"><div class="col-span-2 space-y-4"><div class="bg-white rounded-lg shadow p-4"><h2 class="text-sm font-semibold text-gray-700 mb-2">App Loading</h2><div class="flex flex-wrap gap-2"><button data-testid="btn-open-app" id="btnOpenApp" class="rounded bg-indigo-600 px-3 py-1 text-xs text-white hover:bg-indigo-700">Open App (pricingservice)</button> <button data-testid="btn-open-credit" id="btnOpenCredit" class="rounded bg-indigo-600 px-3 py-1 text-xs text-white hover:bg-indigo-700">Open App (creditservice)</button> <button data-testid="btn-open-validation" id="btnOpenValidation" class="rounded bg-indigo-600 px-3 py-1 text-xs text-white hover:bg-indigo-700">Open App (loanvalidation)</button> <button data-testid="btn-open-with-metadata" id="btnOpenWithMetadata" class="rounded bg-purple-600 px-3 py-1 text-xs text-white hover:bg-purple-700">Open App with Metadata</button> <button data-testid="btn-open-e2e-guest" id="btnOpenE2EGuest" class="rounded bg-teal-600 px-3 py-1 text-xs text-white hover:bg-teal-700">Open E2E Test Guest</button> <button data-testid="btn-open-nested-chain" id="btnOpenNestedChain" class="rounded bg-orange-600 px-3 py-1 text-xs text-white hover:bg-orange-700">Open Nested Chain (A→B→C)</button></div><p class="text-xs text-gray-400 mt-1"><strong>Expected:</strong> App loads into the container below. Log shows "openApp" succeeded. The E2E Test Guest provides interactive buttons to test guest→host communication. The Nested Chain (A→B→C) opens an intermediate that clones Loan and re-exposes it to a grandchild — use C's buttons to verify callChain propagation on Host A.</p></div><div class="bg-white rounded-lg shadow p-4"><h2 class="text-sm font-semibold text-gray-700 mb-2">Scripting Object Management</h2><div class="flex flex-wrap gap-2"><button data-testid="btn-add-so" id="btnAddSO" class="rounded bg-green-600 px-3 py-1 text-xs text-white hover:bg-green-700">Add "Inventory" Object</button> <button data-testid="btn-remove-so" id="btnRemoveSO" class="rounded bg-red-600 px-3 py-1 text-xs text-white hover:bg-red-700">Remove "Inventory" Object</button> <button data-testid="btn-remove-all-so" id="btnRemoveAllSO" class="rounded bg-red-600 px-3 py-1 text-xs text-white hover:bg-red-700">Remove All Objects</button></div><p class="text-xs text-gray-400 mt-1"><strong>Expected:</strong> Add succeeds. Remove succeeds. Guest apps can/cannot call removed objects.</p></div><div class="bg-white rounded-lg shadow p-4"><h2 class="text-sm font-semibold text-gray-700 mb-2">Event Dispatching</h2><div class="flex flex-wrap gap-2"><button data-testid="btn-dispatch-presave" id="btnDispatchPreSave" class="rounded bg-yellow-600 px-3 py-1 text-xs text-white hover:bg-yellow-700">Dispatch onPreSave (all apps)</button> <button data-testid="btn-dispatch-amount" id="btnDispatchAmount" class="rounded bg-yellow-600 px-3 py-1 text-xs text-white hover:bg-yellow-700">Dispatch onLoanAmountChanged</button> <button data-testid="btn-dispatch-term" id="btnDispatchTerm" class="rounded bg-yellow-600 px-3 py-1 text-xs text-white hover:bg-yellow-700">Dispatch onLoanTermChanged</button></div><div data-testid="dispatch-result" id="dispatchResult" class="mt-2 text-xs bg-gray-100 rounded p-2 min-h-[40px]">Dispatch results appear here...</div></div><div class="bg-white rounded-lg shadow p-4"><h2 class="text-sm font-semibold text-gray-700 mb-2">callContext (from last scripting object invocation)</h2><div class="grid grid-cols-2 gap-2"><div><h3 class="text-xs font-medium text-gray-500 mb-1">callContext.guest</h3><pre data-testid="call-context-guest" id="callContextGuest" class="text-xs bg-gray-100 rounded p-2 min-h-[30px] whitespace-pre-wrap">
2
+ Waiting for invocation...</pre></div><div><h3 class="text-xs font-medium text-gray-500 mb-1">callContext.callChain</h3><pre data-testid="call-context-chain" id="callContextChain" class="text-xs bg-gray-100 rounded p-2 min-h-[30px] whitespace-pre-wrap">
3
+ Waiting for invocation...</pre></div></div></div><div class="bg-white rounded-lg shadow p-4"><h2 class="text-sm font-semibold text-gray-700 mb-2">App Lifecycle</h2><div class="flex flex-wrap gap-2"><button data-testid="btn-close-app" id="btnCloseApp" class="rounded bg-red-600 px-3 py-1 text-xs text-white hover:bg-red-700">Close First App</button> <button data-testid="btn-close-all" id="btnCloseAll" class="rounded bg-red-800 px-3 py-1 text-xs text-white hover:bg-red-900">Close All Apps</button> <button data-testid="btn-list-apps" id="btnListApps" class="rounded bg-gray-600 px-3 py-1 text-xs text-white hover:bg-gray-700">List Apps</button></div><pre data-testid="app-list" id="appList" class="mt-2 text-xs bg-gray-100 rounded p-2 min-h-[30px] whitespace-pre-wrap">
4
+ (no apps)</pre></div></div><div class="space-y-4"><div class="bg-white rounded-lg shadow p-3"><h2 class="text-sm font-semibold text-gray-700 mb-2">Guest App Container</h2><div data-testid="app-container" id="appContainer" class="border-2 border-dashed border-indigo-300 rounded-lg" style="height:700px;overflow:auto"></div></div><div class="bg-white rounded-lg shadow p-3"><div class="flex justify-between items-center mb-2"><h2 class="text-sm font-semibold text-gray-700">Event Log</h2><button data-testid="btn-clear-log" id="btnClearLog" class="rounded bg-gray-200 px-2 py-0.5 text-xs text-gray-600 hover:bg-gray-300">Clear</button></div><div data-testid="event-log" id="eventLog" class="text-xs bg-gray-100 rounded p-2 min-h-[200px] max-h-[400px] overflow-y-auto"></div></div></div></div><div class="bg-gray-100 border border-gray-300 rounded-md p-3 mt-4"><h2 class="text-sm font-bold text-gray-800 mb-2">Verification Checklist</h2><div class="grid grid-cols-2 gap-2 text-xs"><label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-APP-01:</strong> openApp loads pricingservice into container, log shows mounted</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-APP-02:</strong> openApp loads creditservice into container</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-APP-03:</strong> openApp loads loanvalidation into container</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-APP-04:</strong> openApp with metadata — metadata stored for callChain</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-SO-01:</strong> Loan object registered on init (guest apps can call getLoanDetails)</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-SO-02:</strong> Add Inventory object succeeds</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-SO-03:</strong> Remove Inventory object succeeds</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-SO-04:</strong> removeAllScriptingObjects clears everything</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-SO-05:</strong> callContext.guest populated when guest invokes scripting object method</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-SO-06:</strong> Loan.getLoanDetails returns expected loan data</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-EVT-01:</strong> Dispatch onPreSave reaches all subscribed apps, results returned</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-EVT-02:</strong> Dispatch onLoanAmountChanged reaches subscribed apps</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-EVT-03:</strong> Dispatch onLoanTermChanged reaches subscribed apps</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-LIFE-01:</strong> closeApp removes first app from list</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-LIFE-02:</strong> List Apps shows all active apps with instanceIds</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-LIFE-03:</strong> closeAllApps removes all apps</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-LIFE-04:</strong> No console errors during any operation</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-META-01:</strong> openApp with metadata — callContext.callChain contains metadata when guest invokes cloned object</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-01:</strong> Guest getObject("Loan") returns proxy with expected methods (getLoanDetails, setCreditScore)</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-02:</strong> Guest Loan.getLoanDetails() returns loan data, host callContext.guest shows e2etestguest</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-03:</strong> Guest Loan.setCreditScore(800) returns {updated: true}, host callContext updates</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-04:</strong> Guest getObject("Inventory") returns proxy after host adds it; null before</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-05:</strong> Guest Inventory.getItems() returns item array</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-06:</strong> Guest getObject("NonExistent") returns null</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-07:</strong> Guest subscribes to onPreSave — receives event when host dispatches</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-08:</strong> Guest subscribes to onLoanAmountChanged — receives event when host dispatches</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-GUEST-09:</strong> Guest unsubscribe all — no more events received after unsubscribe</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-CHAIN-01:</strong> Open Nested Chain — Intermediate B loads, shows "CAppBridge B initialized"</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-CHAIN-02:</strong> Grandchild C (E2E Test Guest) appears inside Intermediate B</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-CHAIN-03:</strong> In C: getObject("Loan") → Loan.getLoanDetails() → Host A shows callContext.guest = e2eintermediateguest, callChain = [{id: "e2etestguest", metadata: {role: "grandchild", ...}}]</span></label> <label class="flex items-start gap-2"><input type="checkbox" class="mt-0.5"/> <span><strong>TC-CHAIN-04:</strong> In C: Loan.setCreditScore(800) → Host A callChain includes e2etestguest with metadata from B</span></label></div></div></main><script src="./e2e-host.js" type="module"></script></body></html>
@@ -0,0 +1,7 @@
1
+ import{getAppBridge as m}from"./utils.js";let n=null,i=[];const o=document.getElementById("eventLog"),t=(e,a="info")=>{const d=new Date().toLocaleTimeString(),p=a==="error"?"text-red-600":a==="success"?"text-green-600":a==="warn"?"text-yellow-600":"text-gray-700";o.innerHTML+=`<div class="${p}">[${d}] ${e}</div>`,o.scrollTop=o.scrollHeight};document.getElementById("btnClearLog").addEventListener("click",()=>{o.innerHTML=""});const l=e=>{document.getElementById("callContextGuest").textContent=e?.guest?JSON.stringify(e.guest,null,2):"(none \u2014 internal call)",document.getElementById("callContextChain").textContent=e?.callChain?JSON.stringify(e.callChain,null,2):"(empty \u2014 direct call)"},s=()=>{const e=n?.getApps()||[];document.getElementById("appList").textContent=e.length?e.map(a=>`${a.uuid}`).join(`
2
+ `):"(no apps)"};class g extends ice.ScriptingObject{constructor(){super("Loan"),this.loanId="E2E-001",this.onSaved=new ice.Event({name:"onSaved",objectId:"Loan"}),this.onPreSave=new ice.Event({name:"onPreSave",objectId:"Loan"}),this.onLoanAmountChanged=new ice.Event({name:"onLoanAmountChanged",objectId:"Loan"}),this.onLoanTermChanged=new ice.Event({name:"onLoanTermChanged",objectId:"Loan"}),this.onDownPaymentChanged=new ice.Event({name:"onDownPaymentChanged",objectId:"Loan"})}getLoanDetails=()=>{const a=this.getLoanDetails.callContext;return t("Loan.getLoanDetails() invoked"),l(a),{id:this.loanId,firstName:"Jane",lastName:"Doe",ssn:"123456789",amount:5e5,term:30,downPayment:5e4,creditScore:750}};setCreditScore=a=>{const d=this.setCreditScore.callContext;return t(`Loan.setCreditScore(${a}) invoked`),l(d),{updated:!0,creditScore:a}}}class u extends ice.ScriptingObject{constructor(){super("Inventory")}getItems=()=>{const a=this.getItems.callContext;return t("Inventory.getItems() invoked"),l(a),[{id:1,name:"Widget A"},{id:2,name:"Widget B"}]}}let c=null,r=!1;const v=async()=>{t("Initializing E2E Host...");try{n=await m()}catch(e){t(`ERROR: Failed to create AppBridge \u2014 ${e.message}`,"error");return}c=new g,n.addScriptingObject(c),t("Registered: Loan scripting object"),document.getElementById("btnOpenApp").addEventListener("click",async()=>{try{const e=await n.openApp({id:"pricingservice",frameOptions:{containerId:"appContainer",title:"Pricing Service"}});i.push(e),t(`openApp("pricingservice") \u2192 instanceId=${e}`,"success")}catch(e){t(`openApp("pricingservice") failed: ${e.message}`,"error")}s()}),document.getElementById("btnOpenCredit").addEventListener("click",async()=>{try{const e=await n.openApp({id:"creditservice",frameOptions:{containerId:"appContainer",title:"Credit Service"}});i.push(e),t(`openApp("creditservice") \u2192 instanceId=${e}`,"success")}catch(e){t(`openApp("creditservice") failed: ${e.message}`,"error")}s()}),document.getElementById("btnOpenValidation").addEventListener("click",async()=>{try{const e=await n.openApp({id:"loanvalidation",frameOptions:{containerId:"appContainer",title:"Loan Validation"}});i.push(e),t(`openApp("loanvalidation") \u2192 instanceId=${e}`,"success")}catch(e){t(`openApp("loanvalidation") failed: ${e.message}`,"error")}s()}),document.getElementById("btnOpenE2EGuest").addEventListener("click",async()=>{try{const e=await n.openApp({id:"e2etestguest",frameOptions:{containerId:"appContainer",title:"E2E Test Guest"}});i.push(e),t(`openApp("e2etestguest") \u2192 instanceId=${e}`,"success")}catch(e){t(`openApp("e2etestguest") failed: ${e.message}`,"error")}s()}),document.getElementById("btnOpenNestedChain").addEventListener("click",async()=>{try{const e=await n.openApp({id:"e2eintermediateguest",frameOptions:{containerId:"appContainer",title:"Intermediate Guest B"},metadata:{vendor:"Acme Credit Corp",tier:"premium"}});i.push(e),t(`openApp("e2eintermediateguest" + metadata) \u2192 instanceId=${e}`,"success"),t("Chain: Host A \u2192 Intermediate B \u2192 Grandchild C. Use C's buttons to test callChain.")}catch(e){t(`openApp("e2eintermediateguest") failed: ${e.message}`,"error")}s()}),document.getElementById("btnOpenWithMetadata").addEventListener("click",async()=>{try{const e=await n.openApp({id:"pricingservice",frameOptions:{containerId:"appContainer",title:"Pricing (with metadata)"},metadata:{vendor:"AcmeCorp",tier:"premium",region:"US-East"}});i.push(e),t(`openApp("pricingservice" + metadata) \u2192 instanceId=${e}`,"success")}catch(e){t(`openApp with metadata failed: ${e.message}`,"error")}s()}),document.getElementById("btnAddSO").addEventListener("click",()=>{if(r){t("Inventory already added","warn");return}n.addScriptingObject(new u),r=!0,t('Added "Inventory" scripting object',"success")}),document.getElementById("btnRemoveSO").addEventListener("click",()=>{try{n.removeScriptingObject("Inventory"),r=!1,t('Removed "Inventory" scripting object',"success")}catch(e){t(`removeScriptingObject failed: ${e.message}`,"error")}}),document.getElementById("btnRemoveAllSO").addEventListener("click",()=>{n.removeAllScriptingObjects(),r=!1,t("Removed all scripting objects","success")}),document.getElementById("btnDispatchPreSave").addEventListener("click",async()=>{t("Dispatching onPreSave to all apps...");try{const e=await n.dispatchEvent({event:c.onPreSave,eventParams:{id:c.loanId,firstName:"Jane",lastName:"Doe",amount:5e5,creditScore:750},eventOptions:{timeout:5e3}}),a=Array.isArray(e)?JSON.stringify(e,null,2):"(no results)";document.getElementById("dispatchResult").textContent=`onPreSave results:
3
+ ${a}`,t(`onPreSave dispatched, ${Array.isArray(e)?e.length:0} responses`,"success")}catch(e){t(`Dispatch failed: ${e.message}`,"error")}}),document.getElementById("btnDispatchAmount").addEventListener("click",async()=>{t("Dispatching onLoanAmountChanged...");try{const e=await n.dispatchEvent({event:c.onLoanAmountChanged,eventParams:{amount:75e4}});document.getElementById("dispatchResult").textContent=`onLoanAmountChanged results:
4
+ ${JSON.stringify(e,null,2)}`,t("onLoanAmountChanged dispatched","success")}catch(e){t(`Dispatch failed: ${e.message}`,"error")}}),document.getElementById("btnDispatchTerm").addEventListener("click",async()=>{t("Dispatching onLoanTermChanged...");try{const e=await n.dispatchEvent({event:c.onLoanTermChanged,eventParams:{term:15}});document.getElementById("dispatchResult").textContent=`onLoanTermChanged results:
5
+ ${JSON.stringify(e,null,2)}`,t("onLoanTermChanged dispatched","success")}catch(e){t(`Dispatch failed: ${e.message}`,"error")}}),document.getElementById("btnCloseApp").addEventListener("click",async()=>{if(!i.length){t("No apps to close","warn");return}const e=i.shift();t(`Closing app instanceId=${e}...`);try{await n.closeApp(e),t(`closeApp("${e}") succeeded`,"success")}catch(a){t(`closeApp failed: ${a.message}`,"error")}s()}),document.getElementById("btnCloseAll").addEventListener("click",async()=>{t("Closing all apps...");try{await n.closeAllApps(),i=[],t("closeAllApps() succeeded","success")}catch(e){t(`closeAllApps failed: ${e.message}`,"error")}s()}),document.getElementById("btnListApps").addEventListener("click",()=>{s();const e=n.getApps();t(`Listed ${e.length} active app(s)`)}),setInterval(s,3e3),t("E2E Host ready","success")};window.addEventListener("DOMContentLoaded",v);
6
+
7
+ //# sourceMappingURL=e2e-host.js.map
Binary file
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["webpack://ice/e2e-host.js"],"sourcesContent":["import { getAppBridge } from './utils.js';\n\nlet appBridge = null;\nlet instanceIds = [];\n\nconst logEl = document.getElementById('eventLog');\nconst log = (msg, type = 'info') => {\n const ts = new Date().toLocaleTimeString();\n const color =\n type === 'error'\n ? 'text-red-600'\n : type === 'success'\n ? 'text-green-600'\n : type === 'warn'\n ? 'text-yellow-600'\n : 'text-gray-700';\n logEl.innerHTML += `<div class=\"${color}\">[${ts}] ${msg}</div>`;\n logEl.scrollTop = logEl.scrollHeight;\n};\n\ndocument.getElementById('btnClearLog').addEventListener('click', () => {\n logEl.innerHTML = '';\n});\n\nconst displayCallContext = (ctx) => {\n document.getElementById('callContextGuest').textContent = ctx?.guest\n ? JSON.stringify(ctx.guest, null, 2)\n : '(none — internal call)';\n document.getElementById('callContextChain').textContent = ctx?.callChain\n ? JSON.stringify(ctx.callChain, null, 2)\n : '(empty — direct call)';\n};\n\nconst refreshAppList = () => {\n const apps = appBridge?.getApps() || [];\n document.getElementById('appList').textContent = apps.length\n ? apps.map((a) => `${a.uuid}`).join('\\n')\n : '(no apps)';\n};\n\nclass Loan extends ice.ScriptingObject {\n constructor() {\n super('Loan');\n this.loanId = 'E2E-001';\n this.onSaved = new ice.Event({\n name: 'onSaved',\n objectId: 'Loan',\n });\n this.onPreSave = new ice.Event({\n name: 'onPreSave',\n objectId: 'Loan',\n });\n this.onLoanAmountChanged = new ice.Event({\n name: 'onLoanAmountChanged',\n objectId: 'Loan',\n });\n this.onLoanTermChanged = new ice.Event({\n name: 'onLoanTermChanged',\n objectId: 'Loan',\n });\n this.onDownPaymentChanged = new ice.Event({\n name: 'onDownPaymentChanged',\n objectId: 'Loan',\n });\n }\n\n getLoanDetails = () => {\n const ctx = this.getLoanDetails.callContext;\n log('Loan.getLoanDetails() invoked');\n displayCallContext(ctx);\n return {\n id: this.loanId,\n firstName: 'Jane',\n lastName: 'Doe',\n ssn: '123456789',\n amount: 500000,\n term: 30,\n downPayment: 50000,\n creditScore: 750,\n };\n };\n\n setCreditScore = (creditScore) => {\n const ctx = this.setCreditScore.callContext;\n log(`Loan.setCreditScore(${creditScore}) invoked`);\n displayCallContext(ctx);\n return { updated: true, creditScore };\n };\n}\n\nclass Inventory extends ice.ScriptingObject {\n constructor() {\n super('Inventory');\n }\n getItems = () => {\n const ctx = this.getItems.callContext;\n log('Inventory.getItems() invoked');\n displayCallContext(ctx);\n return [\n { id: 1, name: 'Widget A' },\n { id: 2, name: 'Widget B' },\n ];\n };\n}\n\nlet loanObj = null;\nlet inventoryAdded = false;\n\nconst init = async () => {\n log('Initializing E2E Host...');\n\n try {\n appBridge = await getAppBridge();\n } catch (e) {\n log(`ERROR: Failed to create AppBridge — ${e.message}`, 'error');\n return;\n }\n\n loanObj = new Loan();\n appBridge.addScriptingObject(loanObj);\n log('Registered: Loan scripting object');\n\n // --- App Loading ---\n\n document.getElementById('btnOpenApp').addEventListener('click', async () => {\n try {\n const instanceId = await appBridge.openApp({\n id: 'pricingservice',\n frameOptions: {\n containerId: 'appContainer',\n title: 'Pricing Service',\n },\n });\n instanceIds.push(instanceId);\n log(`openApp(\"pricingservice\") → instanceId=${instanceId}`, 'success');\n } catch (e) {\n log(`openApp(\"pricingservice\") failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document\n .getElementById('btnOpenCredit')\n .addEventListener('click', async () => {\n try {\n const instanceId = await appBridge.openApp({\n id: 'creditservice',\n frameOptions: {\n containerId: 'appContainer',\n title: 'Credit Service',\n },\n });\n instanceIds.push(instanceId);\n log(`openApp(\"creditservice\") → instanceId=${instanceId}`, 'success');\n } catch (e) {\n log(`openApp(\"creditservice\") failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document\n .getElementById('btnOpenValidation')\n .addEventListener('click', async () => {\n try {\n const instanceId = await appBridge.openApp({\n id: 'loanvalidation',\n frameOptions: {\n containerId: 'appContainer',\n title: 'Loan Validation',\n },\n });\n instanceIds.push(instanceId);\n log(`openApp(\"loanvalidation\") → instanceId=${instanceId}`, 'success');\n } catch (e) {\n log(`openApp(\"loanvalidation\") failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document\n .getElementById('btnOpenE2EGuest')\n .addEventListener('click', async () => {\n try {\n const instanceId = await appBridge.openApp({\n id: 'e2etestguest',\n frameOptions: {\n containerId: 'appContainer',\n title: 'E2E Test Guest',\n },\n });\n instanceIds.push(instanceId);\n log(`openApp(\"e2etestguest\") → instanceId=${instanceId}`, 'success');\n } catch (e) {\n log(`openApp(\"e2etestguest\") failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document\n .getElementById('btnOpenNestedChain')\n .addEventListener('click', async () => {\n try {\n const instanceId = await appBridge.openApp({\n id: 'e2eintermediateguest',\n frameOptions: {\n containerId: 'appContainer',\n title: 'Intermediate Guest B',\n },\n metadata: { vendor: 'Acme Credit Corp', tier: 'premium' },\n });\n instanceIds.push(instanceId);\n log(\n `openApp(\"e2eintermediateguest\" + metadata) → instanceId=${instanceId}`,\n 'success',\n );\n log(\n \"Chain: Host A → Intermediate B → Grandchild C. Use C's buttons to test callChain.\",\n );\n } catch (e) {\n log(`openApp(\"e2eintermediateguest\") failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document\n .getElementById('btnOpenWithMetadata')\n .addEventListener('click', async () => {\n try {\n const instanceId = await appBridge.openApp({\n id: 'pricingservice',\n frameOptions: {\n containerId: 'appContainer',\n title: 'Pricing (with metadata)',\n },\n metadata: { vendor: 'AcmeCorp', tier: 'premium', region: 'US-East' },\n });\n instanceIds.push(instanceId);\n log(\n `openApp(\"pricingservice\" + metadata) → instanceId=${instanceId}`,\n 'success',\n );\n } catch (e) {\n log(`openApp with metadata failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n // --- Scripting Object Management ---\n\n document.getElementById('btnAddSO').addEventListener('click', () => {\n if (inventoryAdded) {\n log('Inventory already added', 'warn');\n return;\n }\n appBridge.addScriptingObject(new Inventory());\n inventoryAdded = true;\n log('Added \"Inventory\" scripting object', 'success');\n });\n\n document.getElementById('btnRemoveSO').addEventListener('click', () => {\n try {\n appBridge.removeScriptingObject('Inventory');\n inventoryAdded = false;\n log('Removed \"Inventory\" scripting object', 'success');\n } catch (e) {\n log(`removeScriptingObject failed: ${e.message}`, 'error');\n }\n });\n\n document.getElementById('btnRemoveAllSO').addEventListener('click', () => {\n appBridge.removeAllScriptingObjects();\n inventoryAdded = false;\n log('Removed all scripting objects', 'success');\n });\n\n // --- Event Dispatching ---\n\n document\n .getElementById('btnDispatchPreSave')\n .addEventListener('click', async () => {\n log('Dispatching onPreSave to all apps...');\n try {\n const results = await appBridge.dispatchEvent({\n event: loanObj.onPreSave,\n eventParams: {\n id: loanObj.loanId,\n firstName: 'Jane',\n lastName: 'Doe',\n amount: 500000,\n creditScore: 750,\n },\n eventOptions: { timeout: 5000 },\n });\n const resultDisplay = Array.isArray(results)\n ? JSON.stringify(results, null, 2)\n : '(no results)';\n document.getElementById(\n 'dispatchResult',\n ).textContent = `onPreSave results:\\n${resultDisplay}`;\n log(\n `onPreSave dispatched, ${\n Array.isArray(results) ? results.length : 0\n } responses`,\n 'success',\n );\n } catch (e) {\n log(`Dispatch failed: ${e.message}`, 'error');\n }\n });\n\n document\n .getElementById('btnDispatchAmount')\n .addEventListener('click', async () => {\n log('Dispatching onLoanAmountChanged...');\n try {\n const results = await appBridge.dispatchEvent({\n event: loanObj.onLoanAmountChanged,\n eventParams: { amount: 750000 },\n });\n document.getElementById(\n 'dispatchResult',\n ).textContent = `onLoanAmountChanged results:\\n${JSON.stringify(\n results,\n null,\n 2,\n )}`;\n log('onLoanAmountChanged dispatched', 'success');\n } catch (e) {\n log(`Dispatch failed: ${e.message}`, 'error');\n }\n });\n\n document\n .getElementById('btnDispatchTerm')\n .addEventListener('click', async () => {\n log('Dispatching onLoanTermChanged...');\n try {\n const results = await appBridge.dispatchEvent({\n event: loanObj.onLoanTermChanged,\n eventParams: { term: 15 },\n });\n document.getElementById(\n 'dispatchResult',\n ).textContent = `onLoanTermChanged results:\\n${JSON.stringify(\n results,\n null,\n 2,\n )}`;\n log('onLoanTermChanged dispatched', 'success');\n } catch (e) {\n log(`Dispatch failed: ${e.message}`, 'error');\n }\n });\n\n // --- App Lifecycle ---\n\n document.getElementById('btnCloseApp').addEventListener('click', async () => {\n if (!instanceIds.length) {\n log('No apps to close', 'warn');\n return;\n }\n const instanceId = instanceIds.shift();\n log(`Closing app instanceId=${instanceId}...`);\n try {\n await appBridge.closeApp(instanceId);\n log(`closeApp(\"${instanceId}\") succeeded`, 'success');\n } catch (e) {\n log(`closeApp failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document.getElementById('btnCloseAll').addEventListener('click', async () => {\n log('Closing all apps...');\n try {\n await appBridge.closeAllApps();\n instanceIds = [];\n log('closeAllApps() succeeded', 'success');\n } catch (e) {\n log(`closeAllApps failed: ${e.message}`, 'error');\n }\n refreshAppList();\n });\n\n document.getElementById('btnListApps').addEventListener('click', () => {\n refreshAppList();\n const apps = appBridge.getApps();\n log(`Listed ${apps.length} active app(s)`);\n });\n\n setInterval(refreshAppList, 3000);\n\n log('E2E Host ready', 'success');\n};\n\nwindow.addEventListener('DOMContentLoaded', init);\n"],"mappings":"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","names":["getAppBridge","appBridge","instanceIds","logEl","log","msg","type","ts","color","displayCallContext","ctx","refreshAppList","apps","Loan","creditScore","Inventory","loanObj","inventoryAdded","init","instanceId","results","resultDisplay","e"],"sourceRoot":"","file":"e2e-host.js"}
@@ -0,0 +1 @@
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>AppBridge E2E Test Suite</title><script src="https://cdn.tailwindcss.com?plugins=forms"></script><script defer="defer" src="js/emuiAppBridge.5a6bc2ea1f03ee954a75.js"></script></head><body class="bg-gray-50"><header class="bg-gray-900 text-white px-6 py-4"><h1 class="text-xl font-bold">AppBridge End-to-End Test Suite</h1><p class="text-sm text-gray-400 mt-1">Comprehensive blackbox tests for AppBridge (in-process micro-frontend framework). Each page includes test steps, expected values, and a verification checklist.</p></header><main class="mx-auto max-w-5xl px-6 py-6"><section class="mb-6 bg-yellow-50 border border-yellow-200 rounded-lg p-4"><h2 class="text-sm font-semibold text-yellow-800 mb-2">Setup Instructions</h2><ol class="text-xs text-yellow-700 list-decimal ml-4 space-y-1"><li>Install dependencies: <code class="bg-yellow-100 px-1 rounded">pnpm install</code></li><li>Start AppBridge dev server: <code class="bg-yellow-100 px-1 rounded">cd libs/app-bridge && pnpm start</code> (default port 3000)</li><li>Open <code class="bg-yellow-100 px-1 rounded">http://localhost:3000/e2e-index.html</code> in the browser</li><li>Each test page has <code class="bg-yellow-100 px-1 rounded">data-testid</code> attributes for Playwright/Cypress selectors</li></ol></section><section class="mb-6"><h2 class="text-lg font-semibold text-gray-800 border-b pb-1 mb-3">1. Core AppBridge Host Tests</h2><div class="grid grid-cols-1 md:grid-cols-2 gap-3"><a href="./e2e-host.html" data-testid="link-e2e-host" class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"><h3 class="font-medium text-indigo-700">Comprehensive E2E Host</h3><p class="text-xs text-gray-500 mt-1">All host scenarios: openApp, closeApp, scripting objects, events, lifecycle, metadata, callContext.</p><p class="text-xs text-gray-400 mt-2"><strong>What to verify:</strong> Apps open and mount into containers. Scripting objects can be added/removed/invoked with correct callContext. Events reach subscribed apps. closeApp/closeAllApps cleans up properly.</p><div class="mt-2 text-xs text-gray-400"><strong>Test Cases:</strong> TC-APP-01..04 &bull; TC-SO-01..06 &bull; TC-EVT-01..03 &bull; TC-LIFE-01..04 &bull; TC-META-01</div></a><a href="./index.html" data-testid="link-main-demo" class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"><h3 class="font-medium text-indigo-700">Main Demo App</h3><p class="text-xs text-gray-500 mt-1">Original Loan Application demo with credit, pricing, and loan validation micro-apps.</p><p class="text-xs text-gray-400 mt-2"><strong>What to verify:</strong> Loan form data flows to guest apps. Events (onLoanAmountChanged, etc.) update guest UIs. Credit score updates from guest. Save dispatches onPreSave with feedback.</p></a></div></section></main></body></html>
@@ -0,0 +1,17 @@
1
+ import{registerApp as s,getWindow as p}from"../../utils.js";const r="e2eintermediateguest";let a=null;const c=p(r);window.emui=window.emui||{uuid:crypto.randomUUID()};const t=e=>{const o=document.getElementById("intermediateLog");if(!o)return;const n=new Date().toLocaleTimeString();o.innerHTML+=`<div>[${n}] ${e}</div>`,o.scrollTop=o.scrollHeight},l=e=>new Promise((o,n)=>{const i=document.createElement("script");i.src=e,i.onload=o,i.onerror=()=>n(new Error(`Failed to load ${e}`)),document.head.appendChild(i)}),g={debug:()=>{},info:()=>{},warn:(...e)=>console.warn("[Intermediate]",...e),error:(...e)=>console.error("[Intermediate]",...e),audit:()=>{}},m=()=>{document.body.innerHTML=`
2
+ <div style="font-family:system-ui;font-size:13px;padding:8px;">
3
+ <h3 style="margin:0 0 6px;font-size:14px;color:#0d9488;">
4
+ Intermediate Guest B (also a host)
5
+ </h3>
6
+ <p style="font-size:11px;color:#6b7280;margin:0 0 6px;">
7
+ This guest clones the parent's Loan object and re-exposes it to a grandchild.
8
+ When the grandchild calls Loan methods, callChain propagation is exercised.
9
+ </p>
10
+ <div id="intermediateLog" data-testid="intermediate-log"
11
+ style="background:#f3f4f6;padding:6px;border-radius:4px;min-height:40px;max-height:80px;font-size:11px;overflow:auto;margin-bottom:8px;"></div>
12
+ <div id="grandchildContainer" data-testid="grandchild-container"
13
+ style="border:2px dashed #0d9488;border-radius:6px;height:450px;"></div>
14
+ </div>
15
+ `};window.emui.app={uuid:window.emui.uuid,init:async e=>(a=e.host,Promise.resolve()),mount:async()=>{m(),t("Intermediate B mounted");try{const e=window.parent.location.origin;t(`Loading AppBridge UMD from ${e}/index.js ...`),await l(`${e}/index.js`),t("AppBridge UMD loaded")}catch(e){t(`ERROR loading UMD: ${e.message}`);return}try{const e=window.parent.location.origin,o=document.querySelector("base");o&&(o.href=`${e}/`);const n=new ice.CAppBridge({logger:g,appConfigBaseUrl:`${e}/`});await n.init(),t("CAppBridge B initialized");const i=await a.getObject("Loan");if(!i){t("ERROR: Loan proxy not found from parent");return}t("Got Loan proxy from parent host"),n.addScriptingObject(i),t("Cloned Loan proxy into B's CAppBridge");const d=await n.openApp({id:"e2etestguest",frameOptions:{containerId:"grandchildContainer",title:"Grandchild Guest C"},metadata:{role:"grandchild",vendor:"Intermediate Corp"}});t(`Opened grandchild e2etestguest (${d})`)}catch(e){t(`ERROR: ${e.message}`),console.error("[Intermediate]",e)}},unmount:async()=>Promise.resolve()},s({browserWindow:c,appId:r,app:window.emui.app});
16
+
17
+ //# sourceMappingURL=e2eIntermediateGuest.checksum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["webpack://ice/e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js"],"sourcesContent":["import { registerApp, getWindow } from '../../utils.js';\n\nconst appId = 'e2eintermediateguest';\nlet parentHost = null;\n\nconst browserWindow = getWindow(appId);\nwindow.emui = window.emui || { uuid: crypto.randomUUID() };\n\nconst log = (msg) => {\n const el = document.getElementById('intermediateLog');\n if (!el) return;\n const ts = new Date().toLocaleTimeString();\n el.innerHTML += `<div>[${ts}] ${msg}</div>`;\n el.scrollTop = el.scrollHeight;\n};\n\nconst loadScript = (src) =>\n new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = src;\n script.onload = resolve;\n script.onerror = () => reject(new Error(`Failed to load ${src}`));\n document.head.appendChild(script);\n });\n\nconst mockLogger = {\n debug: () => {},\n info: () => {},\n warn: (...args) => console.warn('[Intermediate]', ...args),\n error: (...args) => console.error('[Intermediate]', ...args),\n audit: () => {},\n};\n\nconst createUI = () => {\n document.body.innerHTML = `\n <div style=\"font-family:system-ui;font-size:13px;padding:8px;\">\n <h3 style=\"margin:0 0 6px;font-size:14px;color:#0d9488;\">\n Intermediate Guest B (also a host)\n </h3>\n <p style=\"font-size:11px;color:#6b7280;margin:0 0 6px;\">\n This guest clones the parent's Loan object and re-exposes it to a grandchild.\n When the grandchild calls Loan methods, callChain propagation is exercised.\n </p>\n <div id=\"intermediateLog\" data-testid=\"intermediate-log\"\n style=\"background:#f3f4f6;padding:6px;border-radius:4px;min-height:40px;max-height:80px;font-size:11px;overflow:auto;margin-bottom:8px;\"></div>\n <div id=\"grandchildContainer\" data-testid=\"grandchild-container\"\n style=\"border:2px dashed #0d9488;border-radius:6px;height:450px;\"></div>\n </div>\n `;\n};\n\nwindow.emui.app = {\n uuid: window.emui.uuid,\n init: async (options) => {\n parentHost = options.host;\n return Promise.resolve();\n },\n mount: async () => {\n createUI();\n log('Intermediate B mounted');\n\n try {\n const origin = window.parent.location.origin;\n log(`Loading AppBridge UMD from ${origin}/index.js ...`);\n await loadScript(`${origin}/index.js`);\n log('AppBridge UMD loaded');\n } catch (e) {\n log(`ERROR loading UMD: ${e.message}`);\n return;\n }\n\n try {\n const origin = window.parent.location.origin;\n\n // Reset iframe <base> to root so CAppBridge resolves hostUrls correctly\n const baseTag = document.querySelector('base');\n if (baseTag) baseTag.href = `${origin}/`;\n\n const appBridgeB = new ice.CAppBridge({\n logger: mockLogger,\n appConfigBaseUrl: `${origin}/`,\n });\n await appBridgeB.init();\n log('CAppBridge B initialized');\n\n const loanProxy = await parentHost.getObject('Loan');\n if (!loanProxy) {\n log('ERROR: Loan proxy not found from parent');\n return;\n }\n log('Got Loan proxy from parent host');\n\n appBridgeB.addScriptingObject(loanProxy);\n log(\"Cloned Loan proxy into B's CAppBridge\");\n\n const instanceId = await appBridgeB.openApp({\n id: 'e2etestguest',\n frameOptions: {\n containerId: 'grandchildContainer',\n title: 'Grandchild Guest C',\n },\n metadata: { role: 'grandchild', vendor: 'Intermediate Corp' },\n });\n log(`Opened grandchild e2etestguest (${instanceId})`);\n } catch (e) {\n log(`ERROR: ${e.message}`);\n console.error('[Intermediate]', e);\n }\n },\n unmount: async () => Promise.resolve(),\n};\n\nregisterApp({ browserWindow, appId, app: window.emui.app });\n"],"mappings":"AAAA,OAAS,eAAAA,EAAa,aAAAC,MAAiB,iBAEvC,MAAMC,EAAQ,uBACd,IAAIC,EAAa,KAEjB,MAAMC,EAAgBH,EAAUC,CAAK,EACrC,OAAO,KAAO,OAAO,MAAQ,CAAE,KAAM,OAAO,WAAW,CAAE,EAEzD,MAAMG,EAAOC,GAAQ,CACnB,MAAMC,EAAK,SAAS,eAAe,iBAAiB,EACpD,GAAI,CAACA,EAAI,OACT,MAAMC,EAAK,IAAI,KAAK,EAAE,mBAAmB,EACzCD,EAAG,WAAa,SAASC,CAAE,KAAKF,CAAG,SACnCC,EAAG,UAAYA,EAAG,YACpB,EAEME,EAAcC,GAClB,IAAI,QAAQ,CAACC,EAASC,IAAW,CAC/B,MAAMC,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,IAAMH,EACbG,EAAO,OAASF,EAChBE,EAAO,QAAU,IAAMD,EAAO,IAAI,MAAM,kBAAkBF,CAAG,EAAE,CAAC,EAChE,SAAS,KAAK,YAAYG,CAAM,CAClC,CAAC,EAEGC,EAAa,CACjB,MAAO,IAAM,CAAC,EACd,KAAM,IAAM,CAAC,EACb,KAAM,IAAIC,IAAS,QAAQ,KAAK,iBAAkB,GAAGA,CAAI,EACzD,MAAO,IAAIA,IAAS,QAAQ,MAAM,iBAAkB,GAAGA,CAAI,EAC3D,MAAO,IAAM,CAAC,CAChB,EAEMC,EAAW,IAAM,CACrB,SAAS,KAAK,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAe5B,EAEA,OAAO,KAAK,IAAM,CAChB,KAAM,OAAO,KAAK,KAClB,KAAM,MAAOC,IACXd,EAAac,EAAQ,KACd,QAAQ,QAAQ,GAEzB,MAAO,SAAY,CACjBD,EAAS,EACTX,EAAI,wBAAwB,EAE5B,GAAI,CACF,MAAMa,EAAS,OAAO,OAAO,SAAS,OACtCb,EAAI,8BAA8Ba,CAAM,eAAe,EACvD,MAAMT,EAAW,GAAGS,CAAM,WAAW,EACrCb,EAAI,sBAAsB,CAC5B,OAAS,EAAG,CACVA,EAAI,sBAAsB,EAAE,OAAO,EAAE,EACrC,MACF,CAEA,GAAI,CACF,MAAMa,EAAS,OAAO,OAAO,SAAS,OAGhCC,EAAU,SAAS,cAAc,MAAM,EACzCA,IAASA,EAAQ,KAAO,GAAGD,CAAM,KAErC,MAAME,EAAa,IAAI,IAAI,WAAW,CACpC,OAAQN,EACR,iBAAkB,GAAGI,CAAM,GAC7B,CAAC,EACD,MAAME,EAAW,KAAK,EACtBf,EAAI,0BAA0B,EAE9B,MAAMgB,EAAY,MAAMlB,EAAW,UAAU,MAAM,EACnD,GAAI,CAACkB,EAAW,CACdhB,EAAI,yCAAyC,EAC7C,MACF,CACAA,EAAI,iCAAiC,EAErCe,EAAW,mBAAmBC,CAAS,EACvChB,EAAI,uCAAuC,EAE3C,MAAMiB,EAAa,MAAMF,EAAW,QAAQ,CAC1C,GAAI,eACJ,aAAc,CACZ,YAAa,sBACb,MAAO,oBACT,EACA,SAAU,CAAE,KAAM,aAAc,OAAQ,mBAAoB,CAC9D,CAAC,EACDf,EAAI,mCAAmCiB,CAAU,GAAG,CACtD,OAAS,EAAG,CACVjB,EAAI,UAAU,EAAE,OAAO,EAAE,EACzB,QAAQ,MAAM,iBAAkB,CAAC,CACnC,CACF,EACA,QAAS,SAAY,QAAQ,QAAQ,CACvC,EAEAL,EAAY,CAAE,cAAAI,EAAe,MAAAF,EAAO,IAAK,OAAO,KAAK,GAAI,CAAC","names":["registerApp","getWindow","appId","parentHost","browserWindow","log","msg","el","ts","loadScript","src","resolve","reject","script","mockLogger","args","createUI","options","origin","baseTag","appBridgeB","loanProxy","instanceId"],"sourceRoot":"","file":"e2eIntermediateGuest/latest/e2eIntermediateGuest.checksum.js"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "e2eIntermediateGuest.js": "latest/e2eIntermediateGuest.checksum.js"
3
+ }
@@ -0,0 +1,48 @@
1
+ import{registerApp as l,getWindow as b}from"../../utils.js";const c="e2etestguest";let r=null,s=null,i=null,a=[];const p=b(c);window.emui=window.emui||{uuid:crypto.randomUUID()};const t=(e,o="info")=>{const d=document.getElementById("guestLog");if(!d)return;const u=new Date().toLocaleTimeString(),g=o==="error"?"#dc2626":o==="success"?"#16a34a":o==="warn"?"#ca8a04":"#374151";d.innerHTML+=`<div style="color:${g}">[${u}] ${e}</div>`,d.scrollTop=d.scrollHeight},n=e=>{const o=document.getElementById("resultPanel");o&&(o.textContent=JSON.stringify(e,null,2))},m=()=>{document.body.innerHTML=`
2
+ <div style="font-family:system-ui;font-size:13px;padding:8px;">
3
+ <h3 style="margin:0 0 8px;font-size:14px;color:#4338ca;">E2E Test Guest</h3>
4
+
5
+ <div style="margin-bottom:8px;">
6
+ <strong>Scripting Object Access</strong><br/>
7
+ <button id="btnGetLoan" data-testid="guest-get-loan"
8
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">getObject("Loan")</button>
9
+ <button id="btnGetInventory" data-testid="guest-get-inventory"
10
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">getObject("Inventory")</button>
11
+ <button id="btnGetMissing" data-testid="guest-get-missing"
12
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">getObject("NonExistent")</button>
13
+ </div>
14
+
15
+ <div style="margin-bottom:8px;">
16
+ <strong>Method Invocation</strong><br/>
17
+ <button id="btnGetDetails" data-testid="guest-get-details"
18
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">Loan.getLoanDetails()</button>
19
+ <button id="btnSetCredit" data-testid="guest-set-credit"
20
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">Loan.setCreditScore(800)</button>
21
+ <button id="btnGetItems" data-testid="guest-get-items"
22
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">Inventory.getItems()</button>
23
+ </div>
24
+
25
+ <div style="margin-bottom:8px;">
26
+ <strong>Event Subscription</strong><br/>
27
+ <button id="btnSubPreSave" data-testid="guest-sub-presave"
28
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">Subscribe onPreSave</button>
29
+ <button id="btnSubAmount" data-testid="guest-sub-amount"
30
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">Subscribe onLoanAmountChanged</button>
31
+ <button id="btnUnsubAll" data-testid="guest-unsub-all"
32
+ style="margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;">Unsubscribe All</button>
33
+ </div>
34
+
35
+ <div style="margin-bottom:4px;"><strong>Result</strong></div>
36
+ <pre id="resultPanel" data-testid="guest-result"
37
+ style="background:#f3f4f6;padding:6px;border-radius:4px;min-height:40px;font-size:11px;white-space:pre-wrap;overflow:auto;max-height:120px;">Waiting...</pre>
38
+
39
+ <div style="margin-bottom:4px;margin-top:6px;">
40
+ <strong>Guest Log</strong>
41
+ <button id="btnClearGuestLog" style="margin-left:8px;font-size:11px;cursor:pointer;">Clear</button>
42
+ </div>
43
+ <div id="guestLog" data-testid="guest-log"
44
+ style="background:#f3f4f6;padding:6px;border-radius:4px;min-height:60px;max-height:120px;font-size:11px;overflow:auto;"></div>
45
+ </div>
46
+ `},y=()=>{document.getElementById("btnGetLoan").addEventListener("click",async()=>{try{s=await r.getObject("Loan"),s?(t('getObject("Loan") \u2192 OK',"success"),n({status:"found",objectId:"Loan",methods:Object.keys(s).filter(e=>typeof s[e]=="function")})):(t('getObject("Loan") \u2192 null (not registered)',"warn"),n({status:"null"}))}catch(e){t(`getObject("Loan") failed: ${e.message}`,"error"),n({error:e.message})}}),document.getElementById("btnGetInventory").addEventListener("click",async()=>{try{i=await r.getObject("Inventory"),i?(t('getObject("Inventory") \u2192 OK',"success"),n({status:"found",objectId:"Inventory",methods:Object.keys(i).filter(e=>typeof i[e]=="function")})):(t('getObject("Inventory") \u2192 null (not registered)',"warn"),n({status:"null"}))}catch(e){t(`getObject("Inventory") failed: ${e.message}`,"error"),n({error:e.message})}}),document.getElementById("btnGetMissing").addEventListener("click",async()=>{try{await r.getObject("NonExistent")?(t('getObject("NonExistent") \u2192 unexpectedly found',"warn"),n({status:"found (unexpected)"})):(t('getObject("NonExistent") \u2192 null (expected)',"success"),n({status:"null",expected:!0}))}catch(e){t(`getObject("NonExistent") error: ${e.message}`,"error"),n({error:e.message})}}),document.getElementById("btnGetDetails").addEventListener("click",async()=>{if(!s){t('Loan not loaded \u2014 click getObject("Loan") first',"warn");return}try{const e=await s.getLoanDetails();t("Loan.getLoanDetails() \u2192 OK","success"),n(e)}catch(e){t(`getLoanDetails() failed: ${e.message}`,"error"),n({error:e.message})}}),document.getElementById("btnSetCredit").addEventListener("click",async()=>{if(!s){t('Loan not loaded \u2014 click getObject("Loan") first',"warn");return}try{const e=await s.setCreditScore(800);t("Loan.setCreditScore(800) \u2192 OK","success"),n(e)}catch(e){t(`setCreditScore() failed: ${e.message}`,"error"),n({error:e.message})}}),document.getElementById("btnGetItems").addEventListener("click",async()=>{if(!i){t('Inventory not loaded \u2014 click getObject("Inventory") first',"warn");return}try{const e=await i.getItems();t("Inventory.getItems() \u2192 OK","success"),n(e)}catch(e){t(`getItems() failed: ${e.message}`,"error"),n({error:e.message})}}),document.getElementById("btnSubPreSave").addEventListener("click",async()=>{if(!s){t('Loan not loaded \u2014 click getObject("Loan") first',"warn");return}try{const e=r.subscribe({eventId:s.onPreSave.id,callback:({eventParams:o})=>(t(`EVENT onPreSave received: ${JSON.stringify(o)}`,"success"),n({event:"onPreSave",eventParams:o}),!0)});a.push({eventId:s.onPreSave.id,token:e}),t(`Subscribed to onPreSave (token=${e})`,"success"),n({subscribed:"onPreSave",token:e})}catch(e){t(`Subscribe onPreSave failed: ${e.message}`,"error")}}),document.getElementById("btnSubAmount").addEventListener("click",async()=>{if(!s){t('Loan not loaded \u2014 click getObject("Loan") first',"warn");return}try{const e=r.subscribe({eventId:s.onLoanAmountChanged.id,callback:({eventParams:o})=>{t(`EVENT onLoanAmountChanged received: ${JSON.stringify(o)}`,"success"),n({event:"onLoanAmountChanged",eventParams:o})}});a.push({eventId:s.onLoanAmountChanged.id,token:e}),t(`Subscribed to onLoanAmountChanged (token=${e})`,"success"),n({subscribed:"onLoanAmountChanged",token:e})}catch(e){t(`Subscribe onLoanAmountChanged failed: ${e.message}`,"error")}}),document.getElementById("btnUnsubAll").addEventListener("click",()=>{a.forEach(({eventId:e,token:o})=>{try{r.unsubscribe({eventId:e,token:o})}catch{}}),t(`Unsubscribed ${a.length} listener(s)`,"success"),a=[],n({unsubscribed:"all"})}),document.getElementById("btnClearGuestLog").addEventListener("click",()=>{document.getElementById("guestLog").innerHTML=""})};window.emui.app={uuid:window.emui.uuid,init:async e=>(r=e.host,Promise.resolve()),mount:async()=>(m(),y(),t("E2E Test Guest mounted","success"),Promise.resolve()),unmount:async()=>(a=[],s=null,i=null,Promise.resolve())},l({browserWindow:p,appId:c,app:window.emui.app});
47
+
48
+ //# sourceMappingURL=e2eTestGuest.checksum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["webpack://ice/e2eTestGuest/latest/e2eTestGuest.checksum.js"],"sourcesContent":["import { registerApp, getWindow } from '../../utils.js';\n\nconst appId = 'e2etestguest';\nlet host = null;\nlet loanObj = null;\nlet inventoryObj = null;\nlet subscriptions = [];\n\nconst browserWindow = getWindow(appId);\nwindow.emui = window.emui || { uuid: crypto.randomUUID() };\n\nconst log = (msg, type = 'info') => {\n const el = document.getElementById('guestLog');\n if (!el) return;\n const ts = new Date().toLocaleTimeString();\n const color =\n type === 'error'\n ? '#dc2626'\n : type === 'success'\n ? '#16a34a'\n : type === 'warn'\n ? '#ca8a04'\n : '#374151';\n el.innerHTML += `<div style=\"color:${color}\">[${ts}] ${msg}</div>`;\n el.scrollTop = el.scrollHeight;\n};\n\nconst showResult = (data) => {\n const el = document.getElementById('resultPanel');\n if (el) el.textContent = JSON.stringify(data, null, 2);\n};\n\nconst createUI = () => {\n document.body.innerHTML = `\n <div style=\"font-family:system-ui;font-size:13px;padding:8px;\">\n <h3 style=\"margin:0 0 8px;font-size:14px;color:#4338ca;\">E2E Test Guest</h3>\n\n <div style=\"margin-bottom:8px;\">\n <strong>Scripting Object Access</strong><br/>\n <button id=\"btnGetLoan\" data-testid=\"guest-get-loan\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">getObject(\"Loan\")</button>\n <button id=\"btnGetInventory\" data-testid=\"guest-get-inventory\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">getObject(\"Inventory\")</button>\n <button id=\"btnGetMissing\" data-testid=\"guest-get-missing\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">getObject(\"NonExistent\")</button>\n </div>\n\n <div style=\"margin-bottom:8px;\">\n <strong>Method Invocation</strong><br/>\n <button id=\"btnGetDetails\" data-testid=\"guest-get-details\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">Loan.getLoanDetails()</button>\n <button id=\"btnSetCredit\" data-testid=\"guest-set-credit\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">Loan.setCreditScore(800)</button>\n <button id=\"btnGetItems\" data-testid=\"guest-get-items\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">Inventory.getItems()</button>\n </div>\n\n <div style=\"margin-bottom:8px;\">\n <strong>Event Subscription</strong><br/>\n <button id=\"btnSubPreSave\" data-testid=\"guest-sub-presave\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">Subscribe onPreSave</button>\n <button id=\"btnSubAmount\" data-testid=\"guest-sub-amount\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">Subscribe onLoanAmountChanged</button>\n <button id=\"btnUnsubAll\" data-testid=\"guest-unsub-all\"\n style=\"margin:2px;padding:2px 8px;font-size:12px;cursor:pointer;\">Unsubscribe All</button>\n </div>\n\n <div style=\"margin-bottom:4px;\"><strong>Result</strong></div>\n <pre id=\"resultPanel\" data-testid=\"guest-result\"\n style=\"background:#f3f4f6;padding:6px;border-radius:4px;min-height:40px;font-size:11px;white-space:pre-wrap;overflow:auto;max-height:120px;\">Waiting...</pre>\n\n <div style=\"margin-bottom:4px;margin-top:6px;\">\n <strong>Guest Log</strong>\n <button id=\"btnClearGuestLog\" style=\"margin-left:8px;font-size:11px;cursor:pointer;\">Clear</button>\n </div>\n <div id=\"guestLog\" data-testid=\"guest-log\"\n style=\"background:#f3f4f6;padding:6px;border-radius:4px;min-height:60px;max-height:120px;font-size:11px;overflow:auto;\"></div>\n </div>\n `;\n};\n\nconst wireButtons = () => {\n // --- getObject ---\n document.getElementById('btnGetLoan').addEventListener('click', async () => {\n try {\n loanObj = await host.getObject('Loan');\n if (loanObj) {\n log('getObject(\"Loan\") → OK', 'success');\n showResult({\n status: 'found',\n objectId: 'Loan',\n methods: Object.keys(loanObj).filter(\n (k) => typeof loanObj[k] === 'function',\n ),\n });\n } else {\n log('getObject(\"Loan\") → null (not registered)', 'warn');\n showResult({ status: 'null' });\n }\n } catch (e) {\n log(`getObject(\"Loan\") failed: ${e.message}`, 'error');\n showResult({ error: e.message });\n }\n });\n\n document\n .getElementById('btnGetInventory')\n .addEventListener('click', async () => {\n try {\n inventoryObj = await host.getObject('Inventory');\n if (inventoryObj) {\n log('getObject(\"Inventory\") → OK', 'success');\n showResult({\n status: 'found',\n objectId: 'Inventory',\n methods: Object.keys(inventoryObj).filter(\n (k) => typeof inventoryObj[k] === 'function',\n ),\n });\n } else {\n log('getObject(\"Inventory\") → null (not registered)', 'warn');\n showResult({ status: 'null' });\n }\n } catch (e) {\n log(`getObject(\"Inventory\") failed: ${e.message}`, 'error');\n showResult({ error: e.message });\n }\n });\n\n document\n .getElementById('btnGetMissing')\n .addEventListener('click', async () => {\n try {\n const obj = await host.getObject('NonExistent');\n if (obj) {\n log('getObject(\"NonExistent\") → unexpectedly found', 'warn');\n showResult({ status: 'found (unexpected)' });\n } else {\n log('getObject(\"NonExistent\") → null (expected)', 'success');\n showResult({ status: 'null', expected: true });\n }\n } catch (e) {\n log(`getObject(\"NonExistent\") error: ${e.message}`, 'error');\n showResult({ error: e.message });\n }\n });\n\n // --- Method invocation ---\n document\n .getElementById('btnGetDetails')\n .addEventListener('click', async () => {\n if (!loanObj) {\n log('Loan not loaded — click getObject(\"Loan\") first', 'warn');\n return;\n }\n try {\n const details = await loanObj.getLoanDetails();\n log('Loan.getLoanDetails() → OK', 'success');\n showResult(details);\n } catch (e) {\n log(`getLoanDetails() failed: ${e.message}`, 'error');\n showResult({ error: e.message });\n }\n });\n\n document\n .getElementById('btnSetCredit')\n .addEventListener('click', async () => {\n if (!loanObj) {\n log('Loan not loaded — click getObject(\"Loan\") first', 'warn');\n return;\n }\n try {\n const result = await loanObj.setCreditScore(800);\n log('Loan.setCreditScore(800) → OK', 'success');\n showResult(result);\n } catch (e) {\n log(`setCreditScore() failed: ${e.message}`, 'error');\n showResult({ error: e.message });\n }\n });\n\n document.getElementById('btnGetItems').addEventListener('click', async () => {\n if (!inventoryObj) {\n log('Inventory not loaded — click getObject(\"Inventory\") first', 'warn');\n return;\n }\n try {\n const items = await inventoryObj.getItems();\n log('Inventory.getItems() → OK', 'success');\n showResult(items);\n } catch (e) {\n log(`getItems() failed: ${e.message}`, 'error');\n showResult({ error: e.message });\n }\n });\n\n // --- Event subscription ---\n document\n .getElementById('btnSubPreSave')\n .addEventListener('click', async () => {\n if (!loanObj) {\n log('Loan not loaded — click getObject(\"Loan\") first', 'warn');\n return;\n }\n try {\n const token = host.subscribe({\n eventId: loanObj.onPreSave.id,\n callback: ({ eventParams }) => {\n log(\n `EVENT onPreSave received: ${JSON.stringify(eventParams)}`,\n 'success',\n );\n showResult({ event: 'onPreSave', eventParams });\n return true;\n },\n });\n subscriptions.push({ eventId: loanObj.onPreSave.id, token });\n log(`Subscribed to onPreSave (token=${token})`, 'success');\n showResult({ subscribed: 'onPreSave', token });\n } catch (e) {\n log(`Subscribe onPreSave failed: ${e.message}`, 'error');\n }\n });\n\n document\n .getElementById('btnSubAmount')\n .addEventListener('click', async () => {\n if (!loanObj) {\n log('Loan not loaded — click getObject(\"Loan\") first', 'warn');\n return;\n }\n try {\n const token = host.subscribe({\n eventId: loanObj.onLoanAmountChanged.id,\n callback: ({ eventParams }) => {\n log(\n `EVENT onLoanAmountChanged received: ${JSON.stringify(\n eventParams,\n )}`,\n 'success',\n );\n showResult({ event: 'onLoanAmountChanged', eventParams });\n },\n });\n subscriptions.push({ eventId: loanObj.onLoanAmountChanged.id, token });\n log(`Subscribed to onLoanAmountChanged (token=${token})`, 'success');\n showResult({ subscribed: 'onLoanAmountChanged', token });\n } catch (e) {\n log(`Subscribe onLoanAmountChanged failed: ${e.message}`, 'error');\n }\n });\n\n document.getElementById('btnUnsubAll').addEventListener('click', () => {\n subscriptions.forEach(({ eventId, token }) => {\n try {\n host.unsubscribe({ eventId, token });\n } catch (e) {\n /* ignore */\n }\n });\n log(`Unsubscribed ${subscriptions.length} listener(s)`, 'success');\n subscriptions = [];\n showResult({ unsubscribed: 'all' });\n });\n\n document.getElementById('btnClearGuestLog').addEventListener('click', () => {\n document.getElementById('guestLog').innerHTML = '';\n });\n};\n\nwindow.emui.app = {\n uuid: window.emui.uuid,\n init: async (options) => {\n host = options.host;\n return Promise.resolve();\n },\n mount: async () => {\n createUI();\n wireButtons();\n log('E2E Test Guest mounted', 'success');\n return Promise.resolve();\n },\n unmount: async () => {\n subscriptions = [];\n loanObj = null;\n inventoryObj = null;\n return Promise.resolve();\n },\n};\n\nregisterApp({ browserWindow, appId, app: window.emui.app });\n"],"mappings":"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","names":["registerApp","getWindow","appId","host","loanObj","inventoryObj","subscriptions","browserWindow","log","msg","type","el","ts","color","showResult","data","createUI","wireButtons","k","details","result","items","token","eventParams","eventId","options"],"sourceRoot":"","file":"e2eTestGuest/latest/e2eTestGuest.checksum.js"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "e2eTestGuest.js": "latest/e2eTestGuest.checksum.js"
3
+ }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="mobile-web-app-capable" content="yes"/><link rel="icon" href="/favicon.ico"/><title>Application</title><script nonce="__CSP_NONCE__">!function(e,t,n,a,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=t.createElement(n),s=t.getElementsByTagName(n)[0],o.async=1,o.src="https://www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga")</script><style nonce="__CSP_NONCE__">.full-width{width:100%}.full-height{height:100%}</style><script defer="defer" src="js/emuiAppBridge.cd5a9c6779f9aab2eec6.js"></script></head><body class="full-width full-height"><noscript>If you're seeing this message, that means <strong>JavaScript has been disabled on your browser</strong>, please <strong>enable JS</strong> to make this app work.</noscript><div id="pui-app-container-" class="full-width full-height"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="mobile-web-app-capable" content="yes"/><link rel="icon" href="/favicon.ico"/><title>Application</title><script nonce="__CSP_NONCE__">!function(e,t,n,a,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=t.createElement(n),s=t.getElementsByTagName(n)[0],o.async=1,o.src="https://www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga")</script><style nonce="__CSP_NONCE__">.full-width{width:100%}.full-height{height:100%}</style><script defer="defer" src="js/emuiAppBridge.5a6bc2ea1f03ee954a75.js"></script></head><body class="full-width full-height"><noscript>If you're seeing this message, that means <strong>JavaScript has been disabled on your browser</strong>, please <strong>enable JS</strong> to make this app work.</noscript><div id="pui-app-container-" class="full-width full-height"></div></body></html>
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Host</title><script src="https://cdn.tailwindcss.com?plugins=forms"></script><script src="https://cdn.mortgagetech.q1.ice.com/pui-diagnostics@3"></script><script defer="defer" src="js/emuiAppBridge.cd5a9c6779f9aab2eec6.js"></script></head><body><header class="bg-indigo-300 h-10 flex place-items-center"><div class="px-2">ICE Mortgage Product</div></header><main class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8"><div class="min-w-0 flex-1 mt-4"><h1 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">Loan Application</h1></div><div id="successFeedback" class="hidden rounded-md bg-green-50 p-4"><div class="flex"><div class="flex-shrink-0"><svg class="h-5 w-5 text-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd"/></svg></div><div class="ml-3"><p class="text-sm font-medium text-green-800">Loan Saved Successfully</p></div></div></div><div id="errorFeedback" class="hidden rounded-md bg-red-50 p-4"><div class="flex"><div class="flex-shrink-0"><svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd"/></svg></div><div class="ml-3"><h3 class="text-sm font-medium text-red-800">Credit Score is not meeting the requirement</h3></div></div></div><div class="mt-2 sm:grid sm:grid-cols-2 sm:gap-2"><form class="px-2 py-2 space-y-8 divide-y divide-gray-200 bg-gray-50"><div class="space-y-8 divide-y divide-gray-200 sm:space-y-5"><div class="space-y-6 sm:space-y-5"><div><h3 class="text-lg font-medium leading-6 text-gray-900">Personal Information</h3></div><div class="space-y-6 sm:space-y-5"><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="firstName" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">First name</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input name="firstName" id="firstName" autocomplete="given-name" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="John" placeholder="John"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="lastName" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Last name</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input name="lastName" id="lastName" autocomplete="family-name" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="Doe" placeholder="Doe"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="ssn" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">SSN</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="ssn" id="ssn" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="123456789" placeholder="123456789"/></div></div></div><div><h3 class="text-lg font-medium leading-6 text-gray-900">Loan Information</h3></div><div class="space-y-6 sm:space-y-5"><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="amount" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Amount</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="amount" id="amount" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="500000" placeholder="500000"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="Term" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Term (years)</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="term" id="term" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="30" placeholder="30"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="downPayment" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Down Payment</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="downPayment" id="downPayment" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="50000" placeholder="50000"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="creditScore" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Credit Score</label><div class="mt-1 sm:mt-0"><output id="creditScore" class="block w-full max-w-lg pl-2 pt-2 sm:max-w-xs sm:text-sm">NA</output></div><div class="mt-1 sm:mt-0"><button id="getCreditScore" type="button" class="inline-flex items-center rounded-full border border-transparent bg-indigo-600 p-1 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"/></svg></button></div></div></div></div></div><button id="saveLoan" type="button" class="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">Save</button></form><div id="aside-container" class="flex flex-col gap-4 items-start mt-4 border-2 p-2 rounded-lg border-dashed border-cyan-300 sm:mt-0"></div></div><div id="bottom-container" class="flex flex-col gap-4 items-start mt-4 p-2 sm:mt-0"></div></main><script src="./init.js" type="module"></script></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Host</title><script src="https://cdn.tailwindcss.com?plugins=forms"></script><script src="https://cdn.mortgagetech.q1.ice.com/pui-diagnostics@3"></script><script defer="defer" src="js/emuiAppBridge.5a6bc2ea1f03ee954a75.js"></script></head><body><header class="bg-indigo-300 h-10 flex place-items-center justify-between"><div class="px-2">ICE Mortgage Product</div><nav class="flex gap-3 px-2 text-sm"><a href="./e2e-index.html" class="text-indigo-800 hover:text-indigo-950 font-medium">E2E Test Suite</a> <a href="./e2e-host.html" class="text-indigo-800 hover:text-indigo-950 font-medium">E2E Host</a></nav></header><main class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8"><div class="min-w-0 flex-1 mt-4"><h1 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">Loan Application</h1></div><div id="successFeedback" class="hidden rounded-md bg-green-50 p-4"><div class="flex"><div class="flex-shrink-0"><svg class="h-5 w-5 text-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd"/></svg></div><div class="ml-3"><p class="text-sm font-medium text-green-800">Loan Saved Successfully</p></div></div></div><div id="errorFeedback" class="hidden rounded-md bg-red-50 p-4"><div class="flex"><div class="flex-shrink-0"><svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd"/></svg></div><div class="ml-3"><h3 class="text-sm font-medium text-red-800">Credit Score is not meeting the requirement</h3></div></div></div><div class="mt-2 sm:grid sm:grid-cols-2 sm:gap-2"><form class="px-2 py-2 space-y-8 divide-y divide-gray-200 bg-gray-50"><div class="space-y-8 divide-y divide-gray-200 sm:space-y-5"><div class="space-y-6 sm:space-y-5"><div><h3 class="text-lg font-medium leading-6 text-gray-900">Personal Information</h3></div><div class="space-y-6 sm:space-y-5"><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="firstName" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">First name</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input name="firstName" id="firstName" autocomplete="given-name" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="John" placeholder="John"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="lastName" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Last name</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input name="lastName" id="lastName" autocomplete="family-name" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="Doe" placeholder="Doe"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="ssn" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">SSN</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="ssn" id="ssn" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="123456789" placeholder="123456789"/></div></div></div><div><h3 class="text-lg font-medium leading-6 text-gray-900">Loan Information</h3></div><div class="space-y-6 sm:space-y-5"><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="amount" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Amount</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="amount" id="amount" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="500000" placeholder="500000"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="Term" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Term (years)</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="term" id="term" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="30" placeholder="30"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="downPayment" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Down Payment</label><div class="mt-1 sm:col-span-2 sm:mt-0"><input type="number" name="downPayment" id="downPayment" class="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:max-w-xs sm:text-sm" value="50000" placeholder="50000"/></div></div><div class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-gray-200"><label for="creditScore" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">Credit Score</label><div class="mt-1 sm:mt-0"><output id="creditScore" class="block w-full max-w-lg pl-2 pt-2 sm:max-w-xs sm:text-sm">NA</output></div><div class="mt-1 sm:mt-0"><button id="getCreditScore" type="button" class="inline-flex items-center rounded-full border border-transparent bg-indigo-600 p-1 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"/></svg></button></div></div></div></div></div><button id="saveLoan" type="button" class="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">Save</button></form><div id="aside-container" class="flex flex-col gap-4 items-start mt-4 border-2 p-2 rounded-lg border-dashed border-cyan-300 sm:mt-0"></div></div><div id="bottom-container" class="flex flex-col gap-4 items-start mt-4 p-2 sm:mt-0"></div></main><script src="./init.js" type="module"></script></body></html>