@osdk/widget.client-react 3.5.0-beta.14 → 3.5.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/package.json +7 -7
- package/build/browser/client.test.js +0 -348
- package/build/browser/client.test.js.map +0 -1
- package/build/browser/utils/extendParametersWithObjectSets.test.js +0 -372
- package/build/browser/utils/extendParametersWithObjectSets.test.js.map +0 -1
- package/build/browser/utils/transformEmitEventPayload.test.js +0 -210
- package/build/browser/utils/transformEmitEventPayload.test.js.map +0 -1
- package/build/esm/client.test.js +0 -348
- package/build/esm/client.test.js.map +0 -1
- package/build/esm/utils/extendParametersWithObjectSets.test.js +0 -372
- package/build/esm/utils/extendParametersWithObjectSets.test.js.map +0 -1
- package/build/esm/utils/transformEmitEventPayload.test.js +0 -210
- package/build/esm/utils/transformEmitEventPayload.test.js.map +0 -1
- package/build/types/client.test.d.ts +0 -3
- package/build/types/client.test.d.ts.map +0 -1
- package/build/types/utils/extendParametersWithObjectSets.test.d.ts +0 -1
- package/build/types/utils/extendParametersWithObjectSets.test.d.ts.map +0 -1
- package/build/types/utils/transformEmitEventPayload.test.d.ts +0 -1
- package/build/types/utils/transformEmitEventPayload.test.d.ts.map +0 -1
package/build/esm/client.test.js
DELETED
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
18
|
-
import { defineConfig, FoundryHostEventTarget } from "@osdk/widget.client";
|
|
19
|
-
import { act } from "react";
|
|
20
|
-
import { createRoot } from "react-dom/client";
|
|
21
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
22
|
-
import { FoundryWidget } from "./client.js";
|
|
23
|
-
import { useFoundryWidgetContext } from "./context.js";
|
|
24
|
-
import { transformEmitEventPayload } from "./utils/transformEmitEventPayload.js";
|
|
25
|
-
|
|
26
|
-
// Mocks
|
|
27
|
-
const mockEmitEvent = vi.fn();
|
|
28
|
-
const mockWidgetClient = {
|
|
29
|
-
subscribe: vi.fn(),
|
|
30
|
-
unsubscribe: vi.fn(),
|
|
31
|
-
ready: vi.fn(),
|
|
32
|
-
resize: vi.fn(),
|
|
33
|
-
emitEvent: mockEmitEvent,
|
|
34
|
-
hostEventTarget: new FoundryHostEventTarget()
|
|
35
|
-
};
|
|
36
|
-
vi.mock("./utils/transformEmitEventPayload.js", () => ({
|
|
37
|
-
transformEmitEventPayload: vi.fn()
|
|
38
|
-
}));
|
|
39
|
-
vi.mock("@osdk/widget.client", async () => {
|
|
40
|
-
const actual = await vi.importActual("@osdk/widget.client");
|
|
41
|
-
return {
|
|
42
|
-
...actual,
|
|
43
|
-
createFoundryWidgetClient: vi.fn(() => mockWidgetClient)
|
|
44
|
-
};
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Test config
|
|
48
|
-
const config = defineConfig({
|
|
49
|
-
id: "testWidget",
|
|
50
|
-
name: "Test Widget",
|
|
51
|
-
type: "workshop",
|
|
52
|
-
parameters: {
|
|
53
|
-
myParam: {
|
|
54
|
-
displayName: "My Param",
|
|
55
|
-
type: "string"
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
events: {
|
|
59
|
-
eventA: {
|
|
60
|
-
displayName: "Event A",
|
|
61
|
-
parameterUpdateIds: ["myParam"]
|
|
62
|
-
},
|
|
63
|
-
eventB: {
|
|
64
|
-
displayName: "Event B",
|
|
65
|
-
parameterUpdateIds: ["myParam"]
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
describe("FoundryWidget emitEvent race condition handling", () => {
|
|
70
|
-
const client = vi.fn();
|
|
71
|
-
let container;
|
|
72
|
-
let root;
|
|
73
|
-
function EmitEventCapture({
|
|
74
|
-
emitEventRef
|
|
75
|
-
}) {
|
|
76
|
-
const context = useFoundryWidgetContext();
|
|
77
|
-
emitEventRef.current = context.emitEvent;
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
const mountWidget = async () => {
|
|
81
|
-
container = document.createElement("div");
|
|
82
|
-
document.body.appendChild(container);
|
|
83
|
-
root = createRoot(container);
|
|
84
|
-
const emitEventRef = {
|
|
85
|
-
current: null
|
|
86
|
-
};
|
|
87
|
-
act(() => {
|
|
88
|
-
root.render(/*#__PURE__*/React.createElement(FoundryWidget, {
|
|
89
|
-
config: config,
|
|
90
|
-
client: client
|
|
91
|
-
}, /*#__PURE__*/React.createElement(EmitEventCapture, {
|
|
92
|
-
emitEventRef: emitEventRef
|
|
93
|
-
})));
|
|
94
|
-
});
|
|
95
|
-
await act(async () => {
|
|
96
|
-
await vi.runAllTimersAsync();
|
|
97
|
-
});
|
|
98
|
-
return emitEventRef.current;
|
|
99
|
-
};
|
|
100
|
-
const unmountWidget = () => {
|
|
101
|
-
act(() => {
|
|
102
|
-
root.unmount();
|
|
103
|
-
});
|
|
104
|
-
document.body.removeChild(container);
|
|
105
|
-
};
|
|
106
|
-
const createDeferredTransformMock = () => {
|
|
107
|
-
const pending = [];
|
|
108
|
-
vi.mocked(transformEmitEventPayload).mockImplementation((_config, _eventId, payload) => ({
|
|
109
|
-
type: "async",
|
|
110
|
-
payload: new Promise(resolve => {
|
|
111
|
-
pending.push({
|
|
112
|
-
payload: payload,
|
|
113
|
-
resolve: resolve
|
|
114
|
-
});
|
|
115
|
-
})
|
|
116
|
-
}));
|
|
117
|
-
return {
|
|
118
|
-
get pendingCount() {
|
|
119
|
-
return pending.length;
|
|
120
|
-
},
|
|
121
|
-
resolveAll() {
|
|
122
|
-
pending.forEach(({
|
|
123
|
-
payload,
|
|
124
|
-
resolve
|
|
125
|
-
}) => resolve(payload));
|
|
126
|
-
},
|
|
127
|
-
resolveNext() {
|
|
128
|
-
const next = pending.shift();
|
|
129
|
-
if (next) next.resolve(next.payload);
|
|
130
|
-
},
|
|
131
|
-
resolveAtIndex(index) {
|
|
132
|
-
const item = pending[index];
|
|
133
|
-
if (item) {
|
|
134
|
-
pending.splice(index, 1);
|
|
135
|
-
item.resolve(item.payload);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
beforeEach(() => {
|
|
141
|
-
vi.clearAllMocks();
|
|
142
|
-
vi.useFakeTimers();
|
|
143
|
-
mockWidgetClient.hostEventTarget = new FoundryHostEventTarget();
|
|
144
|
-
});
|
|
145
|
-
afterEach(() => {
|
|
146
|
-
unmountWidget();
|
|
147
|
-
vi.useRealTimers();
|
|
148
|
-
});
|
|
149
|
-
it("should emit both events when different events are called", async () => {
|
|
150
|
-
const deferred = createDeferredTransformMock();
|
|
151
|
-
const emit = await mountWidget();
|
|
152
|
-
act(() => {
|
|
153
|
-
emit("eventA", {
|
|
154
|
-
parameterUpdates: {
|
|
155
|
-
myParam: "valueA"
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
emit("eventB", {
|
|
159
|
-
parameterUpdates: {
|
|
160
|
-
myParam: "valueB"
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
expect(deferred.pendingCount).toBe(2);
|
|
165
|
-
await act(async () => {
|
|
166
|
-
deferred.resolveAll();
|
|
167
|
-
await vi.runAllTimersAsync();
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// Both events should be emitted
|
|
171
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(2);
|
|
172
|
-
expect(mockEmitEvent).toHaveBeenCalledWith("eventA", {
|
|
173
|
-
parameterUpdates: {
|
|
174
|
-
myParam: "valueA"
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
expect(mockEmitEvent).toHaveBeenCalledWith("eventB", {
|
|
178
|
-
parameterUpdates: {
|
|
179
|
-
myParam: "valueB"
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
it("should only emit the last call even when transforms resolve out of order", async () => {
|
|
184
|
-
const deferred = createDeferredTransformMock();
|
|
185
|
-
const emit = await mountWidget();
|
|
186
|
-
|
|
187
|
-
// Call emitEvent 3 times rapidly
|
|
188
|
-
act(() => {
|
|
189
|
-
emit("eventA", {
|
|
190
|
-
parameterUpdates: {
|
|
191
|
-
myParam: "first"
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
emit("eventA", {
|
|
195
|
-
parameterUpdates: {
|
|
196
|
-
myParam: "second"
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
emit("eventA", {
|
|
200
|
-
parameterUpdates: {
|
|
201
|
-
myParam: "third"
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
expect(deferred.pendingCount).toBe(3);
|
|
206
|
-
|
|
207
|
-
// Resolve in different order: second first, then third, then first
|
|
208
|
-
// This proves only the last *call* emits, not just the last to resolve
|
|
209
|
-
await act(async () => {
|
|
210
|
-
deferred.resolveAtIndex(1); // "second" resolves first - should not emit
|
|
211
|
-
await vi.runAllTimersAsync();
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// No emit yet since "second" wasn't the last call
|
|
215
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(0);
|
|
216
|
-
await act(async () => {
|
|
217
|
-
deferred.resolveAtIndex(1); // "third" resolves second (now at index 1)
|
|
218
|
-
await vi.runAllTimersAsync();
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// Now "third" should emit because it was the last call
|
|
222
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(1);
|
|
223
|
-
expect(mockEmitEvent).toHaveBeenCalledWith("eventA", {
|
|
224
|
-
parameterUpdates: {
|
|
225
|
-
myParam: "third"
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
await act(async () => {
|
|
229
|
-
deferred.resolveAtIndex(0); // "first" resolves last - should not emit
|
|
230
|
-
await vi.runAllTimersAsync();
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Still only one emit - all stale calls are ignored
|
|
234
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(1);
|
|
235
|
-
});
|
|
236
|
-
it("should emit all calls when they complete sequentially", async () => {
|
|
237
|
-
const deferred = createDeferredTransformMock();
|
|
238
|
-
const emit = await mountWidget();
|
|
239
|
-
|
|
240
|
-
// First call
|
|
241
|
-
act(() => {
|
|
242
|
-
emit("eventA", {
|
|
243
|
-
parameterUpdates: {
|
|
244
|
-
myParam: "first"
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// Complete first call before making second
|
|
250
|
-
await act(async () => {
|
|
251
|
-
deferred.resolveNext();
|
|
252
|
-
await vi.runAllTimersAsync();
|
|
253
|
-
});
|
|
254
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(1);
|
|
255
|
-
expect(mockEmitEvent).toHaveBeenLastCalledWith("eventA", {
|
|
256
|
-
parameterUpdates: {
|
|
257
|
-
myParam: "first"
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Second call after first completed
|
|
262
|
-
act(() => {
|
|
263
|
-
emit("eventA", {
|
|
264
|
-
parameterUpdates: {
|
|
265
|
-
myParam: "second"
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
await act(async () => {
|
|
270
|
-
deferred.resolveNext();
|
|
271
|
-
await vi.runAllTimersAsync();
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// Both sequential calls should be emitted
|
|
275
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(2);
|
|
276
|
-
expect(mockEmitEvent).toHaveBeenLastCalledWith("eventA", {
|
|
277
|
-
parameterUpdates: {
|
|
278
|
-
myParam: "second"
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
it("should emit all rapid calls synchronously when passThrough type is returned", async () => {
|
|
283
|
-
// Mock transformEmitEventPayload to return passThrough (synchronous) results
|
|
284
|
-
vi.mocked(transformEmitEventPayload).mockImplementation((_config, _eventId, payload) => ({
|
|
285
|
-
type: "passThrough",
|
|
286
|
-
payload: payload
|
|
287
|
-
}));
|
|
288
|
-
const emit = await mountWidget();
|
|
289
|
-
|
|
290
|
-
// Emit 5 events rapidly - all should go through synchronously
|
|
291
|
-
act(() => {
|
|
292
|
-
emit("eventA", {
|
|
293
|
-
parameterUpdates: {
|
|
294
|
-
myParam: "first"
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
emit("eventA", {
|
|
298
|
-
parameterUpdates: {
|
|
299
|
-
myParam: "second"
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
emit("eventA", {
|
|
303
|
-
parameterUpdates: {
|
|
304
|
-
myParam: "third"
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
emit("eventA", {
|
|
308
|
-
parameterUpdates: {
|
|
309
|
-
myParam: "fourth"
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
emit("eventA", {
|
|
313
|
-
parameterUpdates: {
|
|
314
|
-
myParam: "fifth"
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
// All 5 should be emitted immediately without waiting for any async operations
|
|
320
|
-
expect(mockEmitEvent).toHaveBeenCalledTimes(5);
|
|
321
|
-
expect(mockEmitEvent).toHaveBeenNthCalledWith(1, "eventA", {
|
|
322
|
-
parameterUpdates: {
|
|
323
|
-
myParam: "first"
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
expect(mockEmitEvent).toHaveBeenNthCalledWith(2, "eventA", {
|
|
327
|
-
parameterUpdates: {
|
|
328
|
-
myParam: "second"
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
expect(mockEmitEvent).toHaveBeenNthCalledWith(3, "eventA", {
|
|
332
|
-
parameterUpdates: {
|
|
333
|
-
myParam: "third"
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
expect(mockEmitEvent).toHaveBeenNthCalledWith(4, "eventA", {
|
|
337
|
-
parameterUpdates: {
|
|
338
|
-
myParam: "fourth"
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
expect(mockEmitEvent).toHaveBeenNthCalledWith(5, "eventA", {
|
|
342
|
-
parameterUpdates: {
|
|
343
|
-
myParam: "fifth"
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
});
|
|
348
|
-
//# sourceMappingURL=client.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.test.js","names":["globalThis","IS_REACT_ACT_ENVIRONMENT","defineConfig","FoundryHostEventTarget","act","createRoot","afterEach","beforeEach","describe","expect","it","vi","FoundryWidget","useFoundryWidgetContext","transformEmitEventPayload","mockEmitEvent","fn","mockWidgetClient","subscribe","unsubscribe","ready","resize","emitEvent","hostEventTarget","mock","actual","importActual","createFoundryWidgetClient","config","id","name","type","parameters","myParam","displayName","events","eventA","parameterUpdateIds","eventB","client","container","root","EmitEventCapture","emitEventRef","context","current","mountWidget","document","createElement","body","appendChild","render","React","runAllTimersAsync","unmountWidget","unmount","removeChild","createDeferredTransformMock","pending","mocked","mockImplementation","_config","_eventId","payload","Promise","resolve","push","pendingCount","length","resolveAll","forEach","resolveNext","next","shift","resolveAtIndex","index","item","splice","clearAllMocks","useFakeTimers","useRealTimers","deferred","emit","parameterUpdates","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","toHaveBeenLastCalledWith","toHaveBeenNthCalledWith"],"sources":["client.test.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ndeclare global {\n var IS_REACT_ACT_ENVIRONMENT: boolean;\n}\nglobalThis.IS_REACT_ACT_ENVIRONMENT = true;\n\nimport type { Client } from \"@osdk/client\";\nimport { defineConfig, FoundryHostEventTarget } from \"@osdk/widget.client\";\nimport { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type { Mock } from \"vitest\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { FoundryWidget } from \"./client.js\";\nimport { useFoundryWidgetContext } from \"./context.js\";\nimport { transformEmitEventPayload } from \"./utils/transformEmitEventPayload.js\";\n\n// Mocks\nconst mockEmitEvent = vi.fn();\nconst mockWidgetClient = {\n subscribe: vi.fn(),\n unsubscribe: vi.fn(),\n ready: vi.fn(),\n resize: vi.fn(),\n emitEvent: mockEmitEvent,\n hostEventTarget: new FoundryHostEventTarget(),\n};\n\nvi.mock(\"./utils/transformEmitEventPayload.js\", () => ({\n transformEmitEventPayload: vi.fn(),\n}));\n\nvi.mock(\"@osdk/widget.client\", async () => {\n const actual = await vi.importActual(\"@osdk/widget.client\");\n return {\n ...actual,\n createFoundryWidgetClient: vi.fn(() => mockWidgetClient),\n };\n});\n\n// Test config\nconst config = defineConfig({\n id: \"testWidget\",\n name: \"Test Widget\",\n type: \"workshop\",\n parameters: {\n myParam: {\n displayName: \"My Param\",\n type: \"string\",\n },\n },\n events: {\n eventA: {\n displayName: \"Event A\",\n parameterUpdateIds: [\"myParam\"],\n },\n eventB: {\n displayName: \"Event B\",\n parameterUpdateIds: [\"myParam\"],\n },\n },\n});\n\ndescribe(\"FoundryWidget emitEvent race condition handling\", () => {\n type EmitEventFn = (eventId: string, payload: unknown) => void;\n\n const client = vi.fn() as Mock<Client> & Client;\n let container: HTMLDivElement;\n let root: Root;\n\n function EmitEventCapture(\n { emitEventRef }: { emitEventRef: { current: EmitEventFn } },\n ) {\n const context = useFoundryWidgetContext<typeof config>();\n emitEventRef.current = context.emitEvent as EmitEventFn;\n return null;\n }\n\n const mountWidget = async () => {\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n\n const emitEventRef = { current: null as unknown as EmitEventFn };\n\n act(() => {\n root.render(\n <FoundryWidget config={config} client={client}>\n <EmitEventCapture emitEventRef={emitEventRef} />\n </FoundryWidget>,\n );\n });\n\n await act(async () => {\n await vi.runAllTimersAsync();\n });\n\n return emitEventRef.current;\n };\n\n const unmountWidget = () => {\n act(() => {\n root.unmount();\n });\n document.body.removeChild(container);\n };\n\n const createDeferredTransformMock = () => {\n const pending: Array<{\n payload: { parameterUpdates: { myParam: string } };\n resolve: (value: { parameterUpdates: { myParam: string } }) => void;\n }> = [];\n\n vi.mocked(transformEmitEventPayload).mockImplementation(\n (_config, _eventId, payload) => ({\n type: \"async\" as const,\n payload: new Promise((resolve) => {\n pending.push({\n payload: payload as { parameterUpdates: { myParam: string } },\n resolve: resolve as (\n value: { parameterUpdates: { myParam: string } },\n ) => void,\n });\n }),\n }),\n );\n\n return {\n get pendingCount() {\n return pending.length;\n },\n resolveAll() {\n pending.forEach(({ payload, resolve }) => resolve(payload));\n },\n resolveNext() {\n const next = pending.shift();\n if (next) next.resolve(next.payload);\n },\n resolveAtIndex(index: number) {\n const item = pending[index];\n if (item) {\n pending.splice(index, 1);\n item.resolve(item.payload);\n }\n },\n };\n };\n\n beforeEach(() => {\n vi.clearAllMocks();\n vi.useFakeTimers();\n mockWidgetClient.hostEventTarget = new FoundryHostEventTarget();\n });\n\n afterEach(() => {\n unmountWidget();\n vi.useRealTimers();\n });\n\n it(\"should emit both events when different events are called\", async () => {\n const deferred = createDeferredTransformMock();\n const emit = await mountWidget();\n\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"valueA\" } });\n emit(\"eventB\", { parameterUpdates: { myParam: \"valueB\" } });\n });\n\n expect(deferred.pendingCount).toBe(2);\n\n await act(async () => {\n deferred.resolveAll();\n await vi.runAllTimersAsync();\n });\n\n // Both events should be emitted\n expect(mockEmitEvent).toHaveBeenCalledTimes(2);\n expect(mockEmitEvent).toHaveBeenCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"valueA\" },\n });\n expect(mockEmitEvent).toHaveBeenCalledWith(\"eventB\", {\n parameterUpdates: { myParam: \"valueB\" },\n });\n });\n\n it(\"should only emit the last call even when transforms resolve out of order\", async () => {\n const deferred = createDeferredTransformMock();\n const emit = await mountWidget();\n\n // Call emitEvent 3 times rapidly\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"first\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"second\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"third\" } });\n });\n\n expect(deferred.pendingCount).toBe(3);\n\n // Resolve in different order: second first, then third, then first\n // This proves only the last *call* emits, not just the last to resolve\n await act(async () => {\n deferred.resolveAtIndex(1); // \"second\" resolves first - should not emit\n await vi.runAllTimersAsync();\n });\n\n // No emit yet since \"second\" wasn't the last call\n expect(mockEmitEvent).toHaveBeenCalledTimes(0);\n\n await act(async () => {\n deferred.resolveAtIndex(1); // \"third\" resolves second (now at index 1)\n await vi.runAllTimersAsync();\n });\n\n // Now \"third\" should emit because it was the last call\n expect(mockEmitEvent).toHaveBeenCalledTimes(1);\n expect(mockEmitEvent).toHaveBeenCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"third\" },\n });\n\n await act(async () => {\n deferred.resolveAtIndex(0); // \"first\" resolves last - should not emit\n await vi.runAllTimersAsync();\n });\n\n // Still only one emit - all stale calls are ignored\n expect(mockEmitEvent).toHaveBeenCalledTimes(1);\n });\n\n it(\"should emit all calls when they complete sequentially\", async () => {\n const deferred = createDeferredTransformMock();\n const emit = await mountWidget();\n\n // First call\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"first\" } });\n });\n\n // Complete first call before making second\n await act(async () => {\n deferred.resolveNext();\n await vi.runAllTimersAsync();\n });\n\n expect(mockEmitEvent).toHaveBeenCalledTimes(1);\n expect(mockEmitEvent).toHaveBeenLastCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"first\" },\n });\n\n // Second call after first completed\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"second\" } });\n });\n\n await act(async () => {\n deferred.resolveNext();\n await vi.runAllTimersAsync();\n });\n\n // Both sequential calls should be emitted\n expect(mockEmitEvent).toHaveBeenCalledTimes(2);\n expect(mockEmitEvent).toHaveBeenLastCalledWith(\"eventA\", {\n parameterUpdates: { myParam: \"second\" },\n });\n });\n\n it(\"should emit all rapid calls synchronously when passThrough type is returned\", async () => {\n // Mock transformEmitEventPayload to return passThrough (synchronous) results\n vi.mocked(transformEmitEventPayload).mockImplementation(\n (_config, _eventId, payload) => ({\n type: \"passThrough\" as const,\n payload: payload as { parameterUpdates: { myParam: string } },\n }),\n );\n\n const emit = await mountWidget();\n\n // Emit 5 events rapidly - all should go through synchronously\n act(() => {\n emit(\"eventA\", { parameterUpdates: { myParam: \"first\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"second\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"third\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"fourth\" } });\n emit(\"eventA\", { parameterUpdates: { myParam: \"fifth\" } });\n });\n\n // All 5 should be emitted immediately without waiting for any async operations\n expect(mockEmitEvent).toHaveBeenCalledTimes(5);\n expect(mockEmitEvent).toHaveBeenNthCalledWith(1, \"eventA\", {\n parameterUpdates: { myParam: \"first\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(2, \"eventA\", {\n parameterUpdates: { myParam: \"second\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(3, \"eventA\", {\n parameterUpdates: { myParam: \"third\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(4, \"eventA\", {\n parameterUpdates: { myParam: \"fourth\" },\n });\n expect(mockEmitEvent).toHaveBeenNthCalledWith(5, \"eventA\", {\n parameterUpdates: { myParam: \"fifth\" },\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
|