|
1 | | -import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; |
| 1 | +import { describe, it, expect, vi, beforeEach, afterEach, Mock } from "vitest"; |
2 | 2 | import { iFrameScriptExecutionHandlerCode } from "./scriptExecutor"; |
| 3 | +import { Procedure } from "@vitest/spy"; |
3 | 4 |
|
4 | 5 | describe("iFrameScriptExecutionHandlerCode", () => { |
5 | 6 | let iframe: HTMLIFrameElement; |
| 7 | + // eslint-disable-next-line @typescript-eslint/no-unused-vars |
6 | 8 | let messageEventListener: (event: MessageEvent) => void; |
7 | 9 |
|
8 | 10 | beforeEach(() => { |
@@ -39,116 +41,177 @@ describe("iFrameScriptExecutionHandlerCode", () => { |
39 | 41 | it("should execute simple dynamic code and return results via postMessage", async () => { |
40 | 42 | const postMessageMock = vi.fn(); |
41 | 43 |
|
42 | | - expect(iframe.contentWindow).not.toBeNull(); |
43 | | - if (iframe.contentWindow) { |
44 | | - // Override the postMessage method on the iframe's parent |
45 | | - Object.defineProperty(iframe.contentWindow, "parent", { |
46 | | - value: { |
47 | | - postMessage: postMessageMock |
48 | | - }, |
49 | | - configurable: true |
50 | | - }); |
51 | | - |
52 | | - const messageData = { |
53 | | - functionCode: "return 40 + 2;", |
54 | | - widget: {}, |
55 | | - PVs: [] |
56 | | - }; |
57 | | - |
58 | | - const messageEvent = new MessageEvent("message", { |
59 | | - data: messageData, |
60 | | - source: null |
61 | | - }); |
62 | | - |
63 | | - // Send the code to the iframe via a message |
64 | | - iframe.contentWindow.dispatchEvent(messageEvent); |
65 | | - |
66 | | - // Short wait for async execution to complete |
67 | | - await new Promise(resolve => setTimeout(resolve, 1000)); |
68 | | - |
69 | | - // Validate that the dynamic script executed as expected |
70 | | - expect(postMessageMock).toHaveBeenCalledWith(42, "*"); |
71 | | - } |
| 44 | + const messageData = { |
| 45 | + functionCode: "return 40 + 2;", |
| 46 | + id: 1234, |
| 47 | + pvs: [] |
| 48 | + }; |
| 49 | + |
| 50 | + await postTestMessageToIframe(iframe, postMessageMock, messageData); |
| 51 | + |
| 52 | + // Validate that the dynamic script executed as expected |
| 53 | + expect(postMessageMock).toHaveBeenCalledWith( |
| 54 | + { id: 1234, functionReturnValue: 42, widgetProps: {} }, |
| 55 | + "*" |
| 56 | + ); |
72 | 57 | }); |
73 | 58 |
|
74 | 59 | it("should execute code containing some Phoebus built ins and return results via postMessage", async () => { |
75 | 60 | const postMessageMock = vi.fn(); |
| 61 | + const testScript = ` |
| 62 | + importClass(org.csstudio.display.builder.runtime.script.PVUtil); |
| 63 | + importClass(org.csstudio.display.builder.runtime.script.ScriptUtil); |
| 64 | + importPackage(Packages.org.csstudio.opibuilder.scriptUtil); |
| 65 | + return PVUtil.getDouble(1+2); |
| 66 | + `; |
| 67 | + |
| 68 | + const messageData = { |
| 69 | + functionCode: testScript, |
| 70 | + id: 3456, |
| 71 | + pvs: [] |
| 72 | + }; |
| 73 | + |
| 74 | + await postTestMessageToIframe(iframe, postMessageMock, messageData); |
| 75 | + |
| 76 | + expect(postMessageMock).toHaveBeenCalledWith( |
| 77 | + { id: 3456, functionReturnValue: 3, widgetProps: {} }, |
| 78 | + "*" |
| 79 | + ); |
| 80 | + }); |
76 | 81 |
|
77 | | - expect(iframe.contentWindow).not.toBeNull(); |
78 | | - if (iframe.contentWindow) { |
79 | | - // Override the postMessage method on the iframe's parent |
80 | | - Object.defineProperty(iframe.contentWindow, "parent", { |
81 | | - value: { |
82 | | - postMessage: postMessageMock |
83 | | - }, |
84 | | - configurable: true |
85 | | - }); |
86 | | - |
87 | | - const script = ` |
88 | | - importClass(org.csstudio.display.builder.runtime.script.PVUtil); |
89 | | - importClass(org.csstudio.display.builder.runtime.script.ScriptUtil); |
90 | | - importPackage(Packages.org.csstudio.opibuilder.scriptUtil); |
91 | | -
|
92 | | - // widget.setPropertyValue("background_color", ColorFontUtil.getColorFromRGB(255, 255, 0)); |
93 | | -
|
94 | | - return PVUtil.getDouble(1+2); |
95 | | - `; |
96 | | - |
97 | | - const messageData = { |
98 | | - functionCode: script, |
99 | | - widget: {}, |
100 | | - PVs: [] |
101 | | - }; |
102 | | - |
103 | | - const messageEvent = new MessageEvent("message", { |
104 | | - data: messageData, |
105 | | - source: null |
106 | | - }); |
107 | | - |
108 | | - // Send the code to the iframe via a message |
109 | | - iframe.contentWindow.dispatchEvent(messageEvent); |
110 | | - |
111 | | - // Short wait for async execution to complete |
112 | | - await new Promise(resolve => setTimeout(resolve, 1000)); |
113 | | - |
114 | | - // Validate that the dynamic script executed as expected |
115 | | - expect(postMessageMock).toHaveBeenCalledWith(3, "*"); |
116 | | - } |
| 82 | + it("should execute code containing widget.setPropertyValue and return results via postMessage in widgetProps", async () => { |
| 83 | + const postMessageMock = vi.fn(); |
| 84 | + const testScript = ` |
| 85 | + widget.setPropertyValue("x", PVUtil.getDouble(1+2)); |
| 86 | + widget.setPropertyValue("background_color", ColorFontUtil.getColorFromRGB(255, 0, 255)); |
| 87 | + widget.setPropertyValue("foreground_color", ColorFontUtil.YELLOW); |
| 88 | + `; |
| 89 | + |
| 90 | + const messageData = { |
| 91 | + functionCode: testScript, |
| 92 | + id: 73734, |
| 93 | + pvs: [] |
| 94 | + }; |
| 95 | + |
| 96 | + await postTestMessageToIframe(iframe, postMessageMock, messageData); |
| 97 | + expect(postMessageMock).toHaveBeenCalledWith( |
| 98 | + { |
| 99 | + id: 73734, |
| 100 | + functionReturnValue: undefined, |
| 101 | + widgetProps: { |
| 102 | + x: 3, |
| 103 | + background_color: { |
| 104 | + text: "rgba(255,0,255,1)", |
| 105 | + type: "rgbaColor" |
| 106 | + }, |
| 107 | + foreground_color: { |
| 108 | + text: "rgba(255,255,0,1)", |
| 109 | + type: "rgbaColor" |
| 110 | + } |
| 111 | + } |
| 112 | + }, |
| 113 | + "*" |
| 114 | + ); |
| 115 | + }); |
| 116 | + |
| 117 | + it("should execute code that uses a pv values and return results via postMessage in widgetProps", async () => { |
| 118 | + const postMessageMock = vi.fn(); |
| 119 | + |
| 120 | + const testScript = ` |
| 121 | + const value = PVUtil.getDouble(pvs[0]); |
| 122 | + if (value > 299) { |
| 123 | + widget.setPropertyValue("background_color", ColorFontUtil.getColorFromRGB(255, 255, 0)); |
| 124 | + } else { |
| 125 | + widget.setPropertyValue("background_color", ColorFontUtil.getColorFromRGB(128, 255, 255)); |
| 126 | + } |
| 127 | + `; |
| 128 | + |
| 129 | + const messageData1 = { |
| 130 | + functionCode: testScript, |
| 131 | + id: 73734, |
| 132 | + pvs: [301] |
| 133 | + }; |
| 134 | + |
| 135 | + const messageData2 = { |
| 136 | + functionCode: testScript, |
| 137 | + id: 9098, |
| 138 | + pvs: [298] |
| 139 | + }; |
| 140 | + |
| 141 | + await postTestMessageToIframe(iframe, postMessageMock, messageData1); |
| 142 | + await postTestMessageToIframe(iframe, postMessageMock, messageData2); |
| 143 | + |
| 144 | + expect(postMessageMock).toHaveBeenCalledWith( |
| 145 | + { |
| 146 | + id: 73734, |
| 147 | + functionReturnValue: undefined, |
| 148 | + widgetProps: { |
| 149 | + background_color: { |
| 150 | + text: "rgba(255,255,0,1)", |
| 151 | + type: "rgbaColor" |
| 152 | + } |
| 153 | + } |
| 154 | + }, |
| 155 | + "*" |
| 156 | + ); |
| 157 | + |
| 158 | + expect(postMessageMock).toHaveBeenCalledWith( |
| 159 | + { |
| 160 | + id: 9098, |
| 161 | + functionReturnValue: undefined, |
| 162 | + widgetProps: { |
| 163 | + background_color: { |
| 164 | + text: "rgba(128,255,255,1)", |
| 165 | + type: "rgbaColor" |
| 166 | + } |
| 167 | + } |
| 168 | + }, |
| 169 | + "*" |
| 170 | + ); |
117 | 171 | }); |
118 | 172 |
|
119 | 173 | it("should handle exception in the dynamic code and send error message via postMessage", async () => { |
120 | 174 | const postMessageMock = vi.fn(); |
121 | 175 |
|
122 | | - expect(iframe.contentWindow).not.toBeNull(); |
123 | | - if (iframe.contentWindow) { |
124 | | - // Override the postMessage method on the iframe's parent |
125 | | - Object.defineProperty(iframe.contentWindow, "parent", { |
126 | | - value: { |
127 | | - postMessage: postMessageMock |
128 | | - }, |
129 | | - configurable: true |
130 | | - }); |
131 | | - |
132 | | - const messageData = { |
133 | | - functionCode: 'throw new Error("Test error");', |
134 | | - widget: {}, |
135 | | - PVs: [] |
136 | | - }; |
137 | | - |
138 | | - // Create a test message event with invalid code |
139 | | - const messageEvent = new MessageEvent("message", { |
140 | | - data: messageData, |
141 | | - source: null |
142 | | - }); |
143 | | - |
144 | | - // Dispatch the event to the iframe's contentWindow |
145 | | - iframe.contentWindow.dispatchEvent(messageEvent); |
146 | | - |
147 | | - // Wait for async operations |
148 | | - await new Promise(resolve => setTimeout(resolve, 1000)); |
149 | | - |
150 | | - // Check if postMessage was called with the expected error message |
151 | | - expect(postMessageMock).toHaveBeenCalledWith("Error: Test error", "*"); |
152 | | - } |
| 176 | + const messageData = { |
| 177 | + functionCode: 'throw new Error("Test error");', |
| 178 | + id: 6789, |
| 179 | + pvs: [] |
| 180 | + }; |
| 181 | + |
| 182 | + await postTestMessageToIframe(iframe, postMessageMock, messageData); |
| 183 | + |
| 184 | + // Check if postMessage was called with the expected error message |
| 185 | + expect(postMessageMock).toHaveBeenCalledWith( |
| 186 | + { id: 6789, error: "Error: Test error" }, |
| 187 | + "*" |
| 188 | + ); |
153 | 189 | }); |
154 | 190 | }); |
| 191 | + |
| 192 | +const postTestMessageToIframe = async ( |
| 193 | + iframe: HTMLIFrameElement, |
| 194 | + postMessageMock: Mock<Procedure>, |
| 195 | + messageData: { functionCode: string; id: number; pvs: any[] } |
| 196 | +) => { |
| 197 | + Object.defineProperty(iframe.contentWindow, "parent", { |
| 198 | + value: { |
| 199 | + postMessage: postMessageMock |
| 200 | + }, |
| 201 | + configurable: true |
| 202 | + }); |
| 203 | + |
| 204 | + const messageEvent = new MessageEvent("message", { |
| 205 | + data: messageData, |
| 206 | + source: null |
| 207 | + }); |
| 208 | + |
| 209 | + expect(iframe.contentWindow).not.toBeNull(); |
| 210 | + if (iframe.contentWindow) { |
| 211 | + // Send the code and pv values to the iframe via a message |
| 212 | + iframe.contentWindow.dispatchEvent(messageEvent); |
| 213 | + } |
| 214 | + |
| 215 | + // Short wait for async execution to complete |
| 216 | + await new Promise(resolve => setTimeout(resolve, 200)); |
| 217 | +}; |
0 commit comments