wyreframe 0.1.0 → 0.1.1

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 (59) hide show
  1. package/LICENSE +692 -0
  2. package/README.md +65 -5
  3. package/package.json +8 -7
  4. package/src/index.ts +425 -0
  5. package/src/renderer/Renderer.gen.tsx +49 -0
  6. package/src/renderer/Renderer.mjs +41 -1
  7. package/src/renderer/Renderer.res +78 -0
  8. package/src/test/Expect.mjs +9 -0
  9. package/src/parser/Core/__tests__/Bounds_test.mjs +0 -326
  10. package/src/parser/Core/__tests__/Bounds_test.res +0 -412
  11. package/src/parser/Core/__tests__/Grid_test.mjs +0 -322
  12. package/src/parser/Core/__tests__/Grid_test.res +0 -319
  13. package/src/parser/Core/__tests__/Types_test.mjs +0 -614
  14. package/src/parser/Core/__tests__/Types_test.res +0 -650
  15. package/src/parser/Detector/__tests__/BoxTracer_test.mjs +0 -70
  16. package/src/parser/Detector/__tests__/BoxTracer_test.res +0 -92
  17. package/src/parser/Detector/__tests__/HierarchyBuilder_test.mjs +0 -489
  18. package/src/parser/Detector/__tests__/HierarchyBuilder_test.res +0 -849
  19. package/src/parser/Detector/__tests__/ShapeDetector_test.mjs +0 -377
  20. package/src/parser/Detector/__tests__/ShapeDetector_test.res +0 -563
  21. package/src/parser/Interactions/__tests__/InteractionMerger_test.mjs +0 -576
  22. package/src/parser/Interactions/__tests__/InteractionMerger_test.res +0 -646
  23. package/src/parser/Scanner/__tests__/Grid_manual.mjs +0 -214
  24. package/src/parser/Scanner/__tests__/Grid_manual.res +0 -141
  25. package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.mjs +0 -189
  26. package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.res +0 -257
  27. package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.mjs +0 -202
  28. package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.res +0 -250
  29. package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.mjs +0 -293
  30. package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.res +0 -134
  31. package/src/parser/Semantic/Elements/__tests__/InputParser_test.mjs +0 -253
  32. package/src/parser/Semantic/Elements/__tests__/InputParser_test.res +0 -304
  33. package/src/parser/Semantic/Elements/__tests__/LinkParser_test.mjs +0 -289
  34. package/src/parser/Semantic/Elements/__tests__/LinkParser_test.res +0 -402
  35. package/src/parser/Semantic/Elements/__tests__/TextParser_test.mjs +0 -149
  36. package/src/parser/Semantic/Elements/__tests__/TextParser_test.res +0 -167
  37. package/src/parser/Semantic/__tests__/ASTBuilder_test.mjs +0 -187
  38. package/src/parser/Semantic/__tests__/ASTBuilder_test.res +0 -192
  39. package/src/parser/Semantic/__tests__/ParserRegistry_test.mjs +0 -154
  40. package/src/parser/Semantic/__tests__/ParserRegistry_test.res +0 -191
  41. package/src/parser/Semantic/__tests__/SemanticParser_integration_test.mjs +0 -768
  42. package/src/parser/Semantic/__tests__/SemanticParser_integration_test.res +0 -1069
  43. package/src/parser/Semantic/__tests__/SemanticParser_manual.mjs +0 -1329
  44. package/src/parser/Semantic/__tests__/SemanticParser_manual.res +0 -544
  45. package/src/parser/__tests__/GridScanner_integration.test.mjs +0 -632
  46. package/src/parser/__tests__/GridScanner_integration.test.res +0 -816
  47. package/src/parser/__tests__/Performance.test.mjs +0 -244
  48. package/src/parser/__tests__/Performance.test.res +0 -371
  49. package/src/parser/__tests__/PerformanceFixtures.mjs +0 -200
  50. package/src/parser/__tests__/PerformanceFixtures.res +0 -284
  51. package/src/parser/__tests__/WyreframeParser_integration.test.mjs +0 -770
  52. package/src/parser/__tests__/WyreframeParser_integration.test.res +0 -1008
  53. package/src/parser/__tests__/fixtures/alignment-test.txt +0 -9
  54. package/src/parser/__tests__/fixtures/all-elements.txt +0 -16
  55. package/src/parser/__tests__/fixtures/login-scene.txt +0 -17
  56. package/src/parser/__tests__/fixtures/multi-scene.txt +0 -25
  57. package/src/parser/__tests__/fixtures/nested-boxes.txt +0 -15
  58. package/src/parser/__tests__/fixtures/simple-box.txt +0 -5
  59. package/src/parser/__tests__/fixtures/with-dividers.txt +0 -14
@@ -1,646 +0,0 @@
1
- /**
2
- * InteractionMerger_test.res
3
- *
4
- * Unit tests for the InteractionMerger module.
5
- * Tests validation, error detection, and successful merging of interactions.
6
- */
7
-
8
- open Vitest
9
- open Types
10
- open InteractionMerger
11
-
12
- describe("InteractionMerger", t => {
13
- // ============================================================================
14
- // Test Fixtures
15
- // ============================================================================
16
-
17
- let makePosition = (row, col) => Position.make(row, col)
18
- let makeBounds = (top, left, bottom, right) => Bounds.make(~top, ~left, ~bottom, ~right)
19
-
20
- // Simple scene with button and input
21
- let simpleScene: scene = {
22
- id: "login",
23
- title: "Login",
24
- transition: "fade",
25
- device: Desktop,
26
- elements: [
27
- Button({
28
- id: "submit-btn",
29
- text: "Submit",
30
- position: makePosition(5, 10),
31
- align: Center,
32
- actions: [],
33
- }),
34
- Input({
35
- id: "email",
36
- placeholder: Some("Email"),
37
- position: makePosition(3, 10),
38
- }),
39
- ],
40
- }
41
-
42
- // Scene with nested boxes
43
- let nestedScene: scene = {
44
- id: "dashboard",
45
- title: "Dashboard",
46
- transition: "slide",
47
- device: Desktop,
48
- elements: [
49
- Box({
50
- name: Some("Container"),
51
- bounds: makeBounds(0, 0, 10, 20),
52
- children: [
53
- Button({
54
- id: "action-btn",
55
- text: "Action",
56
- position: makePosition(2, 5),
57
- align: Left,
58
- actions: [],
59
- }),
60
- Section({
61
- name: "settings",
62
- children: [
63
- Link({
64
- id: "settings-link",
65
- text: "Settings",
66
- position: makePosition(4, 5),
67
- align: Left,
68
- actions: [],
69
- }),
70
- ],
71
- }),
72
- ],
73
- }),
74
- ],
75
- }
76
-
77
- // Valid interactions for simple scene
78
- let validInteractions: array<sceneInteractions> = [
79
- {
80
- sceneId: "login",
81
- interactions: [
82
- {
83
- elementId: "submit-btn",
84
- properties: Js.Dict.fromArray([("variant", Js.Json.string("primary"))]),
85
- actions: [
86
- Goto({
87
- target: "dashboard",
88
- transition: "slide",
89
- condition: None,
90
- }),
91
- ],
92
- },
93
- {
94
- elementId: "email",
95
- properties: Dict.fromArray([("required", JSON.Encode.bool(true))]),
96
- actions: [],
97
- },
98
- ],
99
- },
100
- ]
101
-
102
- // ============================================================================
103
- // Element ID Collection Tests
104
- // ============================================================================
105
-
106
- describe("collectElementIds", t => {
107
- test("collects ID from Button element", t => {
108
- let button = Button({
109
- id: "test-btn",
110
- text: "Test",
111
- position: makePosition(0, 0),
112
- align: Left,
113
- actions: [],
114
- })
115
-
116
- let ids = collectElementIds(button)
117
-
118
- t->expect(ids->Belt.Set.String.has("test-btn"))->Expect.toBe(true)
119
- })
120
-
121
- test("collects ID from Input element", t => {
122
- let input = Input({
123
- id: "test-input",
124
- placeholder: None,
125
- position: makePosition(0, 0),
126
- })
127
-
128
- let ids = collectElementIds(input)
129
-
130
- t->expect(ids->Belt.Set.String.has("test-input"))->Expect.toBe(true)
131
- })
132
-
133
- test("collects ID from Link element", t => {
134
- let link = Link({
135
- id: "test-link",
136
- text: "Test Link",
137
- position: makePosition(0, 0),
138
- align: Left,
139
- actions: [],
140
- })
141
-
142
- let ids = collectElementIds(link)
143
-
144
- t->expect(ids->Belt.Set.String.has("test-link"))->Expect.toBe(true)
145
- })
146
-
147
- test("collects name from Section element", t => {
148
- let section = Section({
149
- name: "test-section",
150
- children: [],
151
- })
152
-
153
- let ids = collectElementIds(section)
154
-
155
- t->expect(ids->Belt.Set.String.has("test-section"))->Expect.toBe(true)
156
- })
157
-
158
- test("returns empty set for elements without IDs", t => {
159
- let checkbox = Checkbox({
160
- checked: true,
161
- label: "Test",
162
- position: makePosition(0, 0),
163
- })
164
-
165
- let ids = collectElementIds(checkbox)
166
-
167
- t->expect(ids->Belt.Set.String.size)->Expect.toBe(0)
168
- })
169
-
170
- test("recursively collects IDs from Box children", t => {
171
- let box = Box({
172
- name: Some("Container"),
173
- bounds: makeBounds(0, 0, 10, 10),
174
- children: [
175
- Button({
176
- id: "btn1",
177
- text: "Button 1",
178
- position: makePosition(2, 2),
179
- align: Left,
180
- actions: [],
181
- }),
182
- Button({
183
- id: "btn2",
184
- text: "Button 2",
185
- position: makePosition(4, 2),
186
- align: Left,
187
- actions: [],
188
- }),
189
- ],
190
- })
191
-
192
- let ids = collectElementIds(box)
193
-
194
- t->expect(ids->Belt.Set.String.has("btn1"))->Expect.toBe(true)
195
- t->expect(ids->Belt.Set.String.has("btn2"))->Expect.toBe(true)
196
- t->expect(ids->Belt.Set.String.size)->Expect.toBe(2)
197
- })
198
-
199
- test("recursively collects IDs from nested Boxes", t => {
200
- let box = Box({
201
- name: Some("Outer"),
202
- bounds: makeBounds(0, 0, 20, 20),
203
- children: [
204
- Box({
205
- name: Some("Inner"),
206
- bounds: makeBounds(2, 2, 18, 18),
207
- children: [
208
- Input({
209
- id: "nested-input",
210
- placeholder: None,
211
- position: makePosition(5, 5),
212
- }),
213
- ],
214
- }),
215
- ],
216
- })
217
-
218
- let ids = collectElementIds(box)
219
-
220
- t->expect(ids->Belt.Set.String.has("nested-input"))->Expect.toBe(true)
221
- })
222
-
223
- test("collects IDs from Row children", t => {
224
- let row = Row({
225
- children: [
226
- Button({
227
- id: "row-btn1",
228
- text: "Button 1",
229
- position: makePosition(0, 0),
230
- align: Left,
231
- actions: [],
232
- }),
233
- Button({
234
- id: "row-btn2",
235
- text: "Button 2",
236
- position: makePosition(0, 10),
237
- align: Left,
238
- actions: [],
239
- }),
240
- ],
241
- align: Center,
242
- })
243
-
244
- let ids = collectElementIds(row)
245
-
246
- t->expect(ids->Belt.Set.String.has("row-btn1"))->Expect.toBe(true)
247
- t->expect(ids->Belt.Set.String.has("row-btn2"))->Expect.toBe(true)
248
- })
249
-
250
- test("collects IDs from Section and its children", t => {
251
- let section = Section({
252
- name: "my-section",
253
- children: [
254
- Link({
255
- id: "section-link",
256
- text: "Link",
257
- position: makePosition(0, 0),
258
- align: Left,
259
- actions: [],
260
- }),
261
- ],
262
- })
263
-
264
- let ids = collectElementIds(section)
265
-
266
- t->expect(ids->Belt.Set.String.has("my-section"))->Expect.toBe(true)
267
- t->expect(ids->Belt.Set.String.has("section-link"))->Expect.toBe(true)
268
- })
269
- })
270
-
271
- describe("collectSceneElementIds", t => {
272
- test("collects all element IDs from scene", t => {
273
- let ids = collectSceneElementIds(simpleScene)
274
-
275
- t->expect(ids->Belt.Set.String.has("submit-btn"))->Expect.toBe(true)
276
- t->expect(ids->Belt.Set.String.has("email"))->Expect.toBe(true)
277
- t->expect(ids->Belt.Set.String.size)->Expect.toBe(2)
278
- })
279
-
280
- test("collects IDs from nested elements in scene", t => {
281
- let ids = collectSceneElementIds(nestedScene)
282
-
283
- t->expect(ids->Belt.Set.String.has("action-btn"))->Expect.toBe(true)
284
- t->expect(ids->Belt.Set.String.has("settings"))->Expect.toBe(true)
285
- t->expect(ids->Belt.Set.String.has("settings-link"))->Expect.toBe(true)
286
- t->expect(ids->Belt.Set.String.size)->Expect.toBe(3)
287
- })
288
- })
289
-
290
- describe("buildSceneElementMap", t => {
291
- test("builds map of scene IDs to element IDs", t => {
292
- let ast: ast = {
293
- scenes: [simpleScene, nestedScene],
294
- }
295
-
296
- let sceneMap = buildSceneElementMap(ast)
297
-
298
- t->expect(sceneMap->Belt.Map.String.size)->Expect.toBe(2)
299
-
300
- let loginIds = sceneMap->Belt.Map.String.get("login")
301
- t->expect(loginIds->Option.isSome)->Expect.toBe(true)
302
- loginIds->Option.forEach(ids => {
303
- t->expect(ids->Belt.Set.String.has("submit-btn"))->Expect.toBe(true)
304
- t->expect(ids->Belt.Set.String.has("email"))->Expect.toBe(true)
305
- })
306
-
307
- let dashboardIds = sceneMap->Belt.Map.String.get("dashboard")
308
- t->expect(dashboardIds->Option.isSome)->Expect.toBe(true)
309
- dashboardIds->Option.forEach(ids => {
310
- t->expect(ids->Belt.Set.String.has("action-btn"))->Expect.toBe(true)
311
- t->expect(ids->Belt.Set.String.has("settings-link"))->Expect.toBe(true)
312
- })
313
- })
314
- })
315
-
316
- // ============================================================================
317
- // Validation Tests
318
- // ============================================================================
319
-
320
- describe("validateInteractions", t => {
321
- test("returns no errors for valid interactions", t => {
322
- let ast: ast = {scenes: [simpleScene]}
323
- let sceneMap = buildSceneElementMap(ast)
324
-
325
- let errors = validateInteractions(validInteractions, sceneMap)
326
-
327
- t->expect(errors->Array.length)->Expect.toBe(0)
328
- })
329
-
330
- test("detects missing element", t => {
331
- let ast: ast = {scenes: [simpleScene]}
332
- let sceneMap = buildSceneElementMap(ast)
333
-
334
- let invalidInteractions = [
335
- {
336
- sceneId: "login",
337
- interactions: [
338
- {
339
- elementId: "nonexistent-btn",
340
- properties: Js.Dict.empty(),
341
- actions: [],
342
- },
343
- ],
344
- },
345
- ]
346
-
347
- let errors = validateInteractions(invalidInteractions, sceneMap)
348
-
349
- t->expect(errors->Array.length)->Expect.toBe(1)
350
- switch errors[0] {
351
- | Some(ElementNotFound({elementId})) => t->expect(elementId)->Expect.toBe("nonexistent-btn")
352
- | _ => t->expect(true)->Expect.toBe(false) // fail: Expected ElementNotFound error
353
- }
354
- })
355
-
356
- test("detects missing scene", t => {
357
- let ast: ast = {scenes: [simpleScene]}
358
- let sceneMap = buildSceneElementMap(ast)
359
-
360
- let invalidInteractions = [
361
- {
362
- sceneId: "nonexistent-scene",
363
- interactions: [
364
- {
365
- elementId: "some-btn",
366
- properties: Js.Dict.empty(),
367
- actions: [],
368
- },
369
- ],
370
- },
371
- ]
372
-
373
- let errors = validateInteractions(invalidInteractions, sceneMap)
374
-
375
- t->expect(errors->Array.length)->Expect.toBe(1)
376
- switch errors[0] {
377
- | Some(SceneNotFound({sceneId})) => t->expect(sceneId)->Expect.toBe("nonexistent-scene")
378
- | _ => t->expect(true)->Expect.toBe(false) // fail: Expected SceneNotFound error
379
- }
380
- })
381
-
382
- test("detects duplicate interaction for same element", t => {
383
- let ast: ast = {scenes: [simpleScene]}
384
- let sceneMap = buildSceneElementMap(ast)
385
-
386
- let duplicateInteractions = [
387
- {
388
- sceneId: "login",
389
- interactions: [
390
- {
391
- elementId: "submit-btn",
392
- properties: Js.Dict.empty(),
393
- actions: [],
394
- },
395
- {
396
- elementId: "submit-btn",
397
- properties: Js.Dict.empty(),
398
- actions: [],
399
- },
400
- ],
401
- },
402
- ]
403
-
404
- let errors = validateInteractions(duplicateInteractions, sceneMap)
405
-
406
- t->expect(errors->Array.length)->Expect.toBe(1)
407
- switch errors[0] {
408
- | Some(DuplicateInteraction({elementId})) => t->expect(elementId)->Expect.toBe("submit-btn")
409
- | _ => t->expect(true)->Expect.toBe(false) // fail: Expected DuplicateInteraction error
410
- }
411
- })
412
-
413
- test("reports multiple errors", t => {
414
- let ast: ast = {scenes: [simpleScene]}
415
- let sceneMap = buildSceneElementMap(ast)
416
-
417
- let multiErrorInteractions = [
418
- {
419
- sceneId: "login",
420
- interactions: [
421
- {
422
- elementId: "nonexistent1",
423
- properties: Js.Dict.empty(),
424
- actions: [],
425
- },
426
- {
427
- elementId: "nonexistent2",
428
- properties: Js.Dict.empty(),
429
- actions: [],
430
- },
431
- ],
432
- },
433
- ]
434
-
435
- let errors = validateInteractions(multiErrorInteractions, sceneMap)
436
-
437
- t->expect(errors->Array.length)->Expect.toBe(2)
438
- })
439
- })
440
-
441
- // ============================================================================
442
- // Merge Function Tests
443
- // ============================================================================
444
-
445
- describe("mergeInteractions", t => {
446
- test("successfully merges valid interactions", t => {
447
- let ast: ast = {scenes: [simpleScene]}
448
-
449
- let result = mergeInteractions(ast, validInteractions)
450
-
451
- t->expect(result->Result.isOk)->Expect.toBe(true)
452
- result->Result.forEach(mergedAst => {
453
- t->expect(mergedAst.scenes->Array.length)->Expect.toBe(1)
454
- })
455
- })
456
-
457
- test("returns error for invalid interactions (hard errors)", t => {
458
- let ast: ast = {scenes: [simpleScene]}
459
-
460
- // SceneNotFound is a hard error (unlike ElementNotFound which is soft)
461
- let invalidInteractions = [
462
- {
463
- sceneId: "nonexistent-scene", // This scene doesn't exist
464
- interactions: [
465
- {
466
- elementId: "some-btn",
467
- properties: Js.Dict.empty(),
468
- actions: [],
469
- },
470
- ],
471
- },
472
- ]
473
-
474
- let result = mergeInteractions(ast, invalidInteractions)
475
-
476
- t->expect(result->Result.isError)->Expect.toBe(true)
477
- switch result {
478
- | Error(errors) => t->expect(errors->Array.length)->Expect.Int.toBeGreaterThan(0)
479
- | Ok(_) => t->expect(true)->Expect.toBe(false) // fail: Expected error result
480
- }
481
- })
482
-
483
- test("preserves scene structure after merge", t => {
484
- let ast: ast = {scenes: [simpleScene]}
485
-
486
- let result = mergeInteractions(ast, validInteractions)
487
-
488
- result->Result.forEach(mergedAst => {
489
- t->expect(mergedAst.scenes[0]->Option.map(s => s.id))->Expect.toEqual(Some("login"))
490
- t->expect(mergedAst.scenes[0]->Option.map(s => s.title))->Expect.toEqual(Some("Login"))
491
- t->expect(mergedAst.scenes[0]->Option.map(s => s.elements->Array.length))->Expect.toEqual(Some(2))
492
- })
493
- })
494
-
495
- test("handles multiple scenes with interactions", t => {
496
- let ast: ast = {scenes: [simpleScene, nestedScene]}
497
-
498
- let multiSceneInteractions = [
499
- {
500
- sceneId: "login",
501
- interactions: [
502
- {
503
- elementId: "submit-btn",
504
- properties: Js.Dict.empty(),
505
- actions: [],
506
- },
507
- ],
508
- },
509
- {
510
- sceneId: "dashboard",
511
- interactions: [
512
- {
513
- elementId: "action-btn",
514
- properties: Js.Dict.empty(),
515
- actions: [],
516
- },
517
- ],
518
- },
519
- ]
520
-
521
- let result = mergeInteractions(ast, multiSceneInteractions)
522
-
523
- t->expect(result->Result.isOk)->Expect.toBe(true)
524
- result->Result.forEach(mergedAst => {
525
- t->expect(mergedAst.scenes->Array.length)->Expect.toBe(2)
526
- })
527
- })
528
-
529
- test("merges empty interactions successfully", t => {
530
- let ast: ast = {scenes: [simpleScene]}
531
-
532
- let result = mergeInteractions(ast, [])
533
-
534
- t->expect(result->Result.isOk)->Expect.toBe(true)
535
- })
536
- })
537
-
538
- // ============================================================================
539
- // Error Formatting Tests
540
- // ============================================================================
541
-
542
- describe("formatError", t => {
543
- test("formats ElementNotFound error", t => {
544
- let error = ElementNotFound({
545
- sceneId: "login",
546
- elementId: "missing-btn",
547
- position: None,
548
- })
549
-
550
- let message = formatError(error)
551
-
552
- t->expect(message)->Expect.String.toContain("missing-btn")
553
- t->expect(message)->Expect.String.toContain("login")
554
- })
555
-
556
- test("formats DuplicateInteraction error", t => {
557
- let error = DuplicateInteraction({
558
- sceneId: "login",
559
- elementId: "duplicate-btn",
560
- })
561
-
562
- let message = formatError(error)
563
-
564
- t->expect(message)->Expect.String.toContain("duplicate-btn")
565
- t->expect(message)->Expect.String.toContain("Duplicate")
566
- })
567
-
568
- test("formats SceneNotFound error", t => {
569
- let error = SceneNotFound({sceneId: "missing-scene"})
570
-
571
- let message = formatError(error)
572
-
573
- t->expect(message)->Expect.String.toContain("missing-scene")
574
- t->expect(message)->Expect.String.toContain("not found")
575
- })
576
- })
577
-
578
- describe("formatErrors", t => {
579
- test("formats multiple errors with newlines", t => {
580
- let errors = [
581
- ElementNotFound({
582
- sceneId: "login",
583
- elementId: "btn1",
584
- position: None,
585
- }),
586
- ElementNotFound({
587
- sceneId: "login",
588
- elementId: "btn2",
589
- position: None,
590
- }),
591
- ]
592
-
593
- let message = formatErrors(errors)
594
-
595
- t->expect(message)->Expect.String.toContain("btn1")
596
- t->expect(message)->Expect.String.toContain("btn2")
597
- t->expect(message)->Expect.String.toContain("\n")
598
- })
599
- })
600
-
601
- // ============================================================================
602
- // findInteractionForElement Tests
603
- // ============================================================================
604
-
605
- describe("findInteractionForElement", t => {
606
- test("finds interaction for element", t => {
607
- let sceneInteractions = Some({
608
- sceneId: "login",
609
- interactions: [
610
- {
611
- elementId: "test-btn",
612
- properties: Js.Dict.empty(),
613
- actions: [],
614
- },
615
- ],
616
- })
617
-
618
- let result = findInteractionForElement("test-btn", sceneInteractions)
619
-
620
- t->expect(result->Option.isSome)->Expect.toBe(true)
621
- })
622
-
623
- test("returns None when element not found", t => {
624
- let sceneInteractions = Some({
625
- sceneId: "login",
626
- interactions: [
627
- {
628
- elementId: "test-btn",
629
- properties: Js.Dict.empty(),
630
- actions: [],
631
- },
632
- ],
633
- })
634
-
635
- let result = findInteractionForElement("other-btn", sceneInteractions)
636
-
637
- t->expect(result->Option.isNone)->Expect.toBe(true)
638
- })
639
-
640
- test("returns None when no scene interactions", t => {
641
- let result = findInteractionForElement("test-btn", None)
642
-
643
- t->expect(result->Option.isNone)->Expect.toBe(true)
644
- })
645
- })
646
- })