wyreframe 0.1.0 → 0.1.5
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/LICENSE +692 -0
- package/README.md +65 -5
- package/package.json +8 -7
- package/src/index.ts +425 -0
- package/src/renderer/Renderer.gen.tsx +49 -0
- package/src/renderer/Renderer.mjs +41 -1
- package/src/renderer/Renderer.res +78 -0
- package/src/parser/Core/__tests__/Bounds_test.mjs +0 -326
- package/src/parser/Core/__tests__/Bounds_test.res +0 -412
- package/src/parser/Core/__tests__/Grid_test.mjs +0 -322
- package/src/parser/Core/__tests__/Grid_test.res +0 -319
- package/src/parser/Core/__tests__/Types_test.mjs +0 -614
- package/src/parser/Core/__tests__/Types_test.res +0 -650
- package/src/parser/Detector/__tests__/BoxTracer_test.mjs +0 -70
- package/src/parser/Detector/__tests__/BoxTracer_test.res +0 -92
- package/src/parser/Detector/__tests__/HierarchyBuilder_test.mjs +0 -489
- package/src/parser/Detector/__tests__/HierarchyBuilder_test.res +0 -849
- package/src/parser/Detector/__tests__/ShapeDetector_test.mjs +0 -377
- package/src/parser/Detector/__tests__/ShapeDetector_test.res +0 -563
- package/src/parser/Interactions/__tests__/InteractionMerger_test.mjs +0 -576
- package/src/parser/Interactions/__tests__/InteractionMerger_test.res +0 -646
- package/src/parser/Scanner/__tests__/Grid_manual.mjs +0 -214
- package/src/parser/Scanner/__tests__/Grid_manual.res +0 -141
- package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.mjs +0 -189
- package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.res +0 -257
- package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.mjs +0 -202
- package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.res +0 -250
- package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.mjs +0 -293
- package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.res +0 -134
- package/src/parser/Semantic/Elements/__tests__/InputParser_test.mjs +0 -253
- package/src/parser/Semantic/Elements/__tests__/InputParser_test.res +0 -304
- package/src/parser/Semantic/Elements/__tests__/LinkParser_test.mjs +0 -289
- package/src/parser/Semantic/Elements/__tests__/LinkParser_test.res +0 -402
- package/src/parser/Semantic/Elements/__tests__/TextParser_test.mjs +0 -149
- package/src/parser/Semantic/Elements/__tests__/TextParser_test.res +0 -167
- package/src/parser/Semantic/__tests__/ASTBuilder_test.mjs +0 -187
- package/src/parser/Semantic/__tests__/ASTBuilder_test.res +0 -192
- package/src/parser/Semantic/__tests__/ParserRegistry_test.mjs +0 -154
- package/src/parser/Semantic/__tests__/ParserRegistry_test.res +0 -191
- package/src/parser/Semantic/__tests__/SemanticParser_integration_test.mjs +0 -768
- package/src/parser/Semantic/__tests__/SemanticParser_integration_test.res +0 -1069
- package/src/parser/Semantic/__tests__/SemanticParser_manual.mjs +0 -1329
- package/src/parser/Semantic/__tests__/SemanticParser_manual.res +0 -544
- package/src/parser/__tests__/GridScanner_integration.test.mjs +0 -632
- package/src/parser/__tests__/GridScanner_integration.test.res +0 -816
- package/src/parser/__tests__/Performance.test.mjs +0 -244
- package/src/parser/__tests__/Performance.test.res +0 -371
- package/src/parser/__tests__/PerformanceFixtures.mjs +0 -200
- package/src/parser/__tests__/PerformanceFixtures.res +0 -284
- package/src/parser/__tests__/WyreframeParser_integration.test.mjs +0 -770
- package/src/parser/__tests__/WyreframeParser_integration.test.res +0 -1008
- package/src/parser/__tests__/fixtures/alignment-test.txt +0 -9
- package/src/parser/__tests__/fixtures/all-elements.txt +0 -16
- package/src/parser/__tests__/fixtures/login-scene.txt +0 -17
- package/src/parser/__tests__/fixtures/multi-scene.txt +0 -25
- package/src/parser/__tests__/fixtures/nested-boxes.txt +0 -15
- package/src/parser/__tests__/fixtures/simple-box.txt +0 -5
- package/src/parser/__tests__/fixtures/with-dividers.txt +0 -14
|
@@ -1,1069 +0,0 @@
|
|
|
1
|
-
// SemanticParser_integration_test.res
|
|
2
|
-
// Integration tests for SemanticParser module
|
|
3
|
-
//
|
|
4
|
-
// Test Coverage:
|
|
5
|
-
// - Login scene parsing
|
|
6
|
-
// - Multiple scenes handling
|
|
7
|
-
// - Nested box structures
|
|
8
|
-
// - Horizontal dividers
|
|
9
|
-
// - All element types recognition
|
|
10
|
-
// - Element alignment calculation
|
|
11
|
-
//
|
|
12
|
-
// Requirements: REQ-25 (Testability - Unit Test Coverage)
|
|
13
|
-
|
|
14
|
-
open Vitest
|
|
15
|
-
|
|
16
|
-
// Helper for passing tests
|
|
17
|
-
let pass = ()
|
|
18
|
-
|
|
19
|
-
// =============================================================================
|
|
20
|
-
// Recursive Element Search Helpers
|
|
21
|
-
// =============================================================================
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Recursively collect all elements including those nested inside Box children.
|
|
25
|
-
* This is needed because named boxes contain their elements in Box.children,
|
|
26
|
-
* not directly in scene.elements.
|
|
27
|
-
*/
|
|
28
|
-
let rec collectAllElements = (elements: array<Types.element>): array<Types.element> => {
|
|
29
|
-
elements->Array.flatMap(el => {
|
|
30
|
-
switch el {
|
|
31
|
-
| Types.Box({children}) => Array.concat([el], collectAllElements(children))
|
|
32
|
-
| other => [other]
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Check if any element matches a predicate, searching recursively.
|
|
39
|
-
*/
|
|
40
|
-
let hasElement = (elements: array<Types.element>, predicate: Types.element => bool): bool => {
|
|
41
|
-
let allElements = collectAllElements(elements)
|
|
42
|
-
allElements->Array.some(predicate)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ============================================================================
|
|
46
|
-
// TEST CASE SP-01: Simple Login Scene Parsing
|
|
47
|
-
// ============================================================================
|
|
48
|
-
|
|
49
|
-
describe("SemanticParser Integration - Login Scene", t => {
|
|
50
|
-
test("SP-01: parses complete login scene with all elements", t => {
|
|
51
|
-
let wireframe = `
|
|
52
|
-
@scene: login
|
|
53
|
-
@title: Login Page
|
|
54
|
-
|
|
55
|
-
+--Login----------------+
|
|
56
|
-
| |
|
|
57
|
-
| * Welcome |
|
|
58
|
-
| |
|
|
59
|
-
| Email: #email |
|
|
60
|
-
| |
|
|
61
|
-
| Password: #password |
|
|
62
|
-
| |
|
|
63
|
-
| [ Login ] |
|
|
64
|
-
| |
|
|
65
|
-
+-----------------------+
|
|
66
|
-
`
|
|
67
|
-
|
|
68
|
-
switch Parser.parse(wireframe) {
|
|
69
|
-
| Ok(ast) => {
|
|
70
|
-
// Verify scene count
|
|
71
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
72
|
-
|
|
73
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
74
|
-
|
|
75
|
-
// Verify scene metadata
|
|
76
|
-
t->expect(scene.id)->Expect.toBe("login")
|
|
77
|
-
t->expect(scene.title)->Expect.toBe("Login Page")
|
|
78
|
-
|
|
79
|
-
// Verify emphasis text element exists (search recursively inside boxes)
|
|
80
|
-
let emphasisFound = hasElement(scene.elements, el =>
|
|
81
|
-
switch el {
|
|
82
|
-
| Types.Text({emphasis: true, content}) => content->String.includes("Welcome")
|
|
83
|
-
| _ => false
|
|
84
|
-
}
|
|
85
|
-
)
|
|
86
|
-
t->expect(emphasisFound)->Expect.toBe(true)
|
|
87
|
-
|
|
88
|
-
// Verify email input exists (search recursively)
|
|
89
|
-
let emailInputFound = hasElement(scene.elements, el =>
|
|
90
|
-
switch el {
|
|
91
|
-
| Types.Input({id: "email"}) => true
|
|
92
|
-
| _ => false
|
|
93
|
-
}
|
|
94
|
-
)
|
|
95
|
-
t->expect(emailInputFound)->Expect.toBe(true)
|
|
96
|
-
|
|
97
|
-
// Verify password input exists (search recursively)
|
|
98
|
-
let passwordInputFound = hasElement(scene.elements, el =>
|
|
99
|
-
switch el {
|
|
100
|
-
| Types.Input({id: "password"}) => true
|
|
101
|
-
| _ => false
|
|
102
|
-
}
|
|
103
|
-
)
|
|
104
|
-
t->expect(passwordInputFound)->Expect.toBe(true)
|
|
105
|
-
|
|
106
|
-
// Verify login button exists (search recursively)
|
|
107
|
-
let loginButtonFound = hasElement(scene.elements, el =>
|
|
108
|
-
switch el {
|
|
109
|
-
| Types.Button({text: "Login"}) => true
|
|
110
|
-
| _ => false
|
|
111
|
-
}
|
|
112
|
-
)
|
|
113
|
-
t->expect(loginButtonFound)->Expect.toBe(true)
|
|
114
|
-
|
|
115
|
-
// Verify total element count (box + content elements)
|
|
116
|
-
t->expect(Array.length(scene.elements))->Expect.Int.toBeGreaterThan(0)
|
|
117
|
-
}
|
|
118
|
-
| Error(errors) => {
|
|
119
|
-
Console.error(errors)
|
|
120
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-01: Expected successful parse of login scene
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
test("SP-01a: login scene elements have correct positions", t => {
|
|
126
|
-
let wireframe = `
|
|
127
|
-
@scene: login
|
|
128
|
-
|
|
129
|
-
+--Login---+
|
|
130
|
-
| #email |
|
|
131
|
-
| [ OK ] |
|
|
132
|
-
+----------+
|
|
133
|
-
`
|
|
134
|
-
|
|
135
|
-
switch Parser.parse(wireframe) {
|
|
136
|
-
| Ok(ast) => {
|
|
137
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
138
|
-
|
|
139
|
-
// Check that elements have position information
|
|
140
|
-
scene.elements->Array.forEach(el => {
|
|
141
|
-
switch el {
|
|
142
|
-
| Types.Input({position}) => {
|
|
143
|
-
t->expect(position.row)->Expect.Int.toBeGreaterThanOrEqual(0)
|
|
144
|
-
t->expect(position.col)->Expect.Int.toBeGreaterThanOrEqual(0)
|
|
145
|
-
}
|
|
146
|
-
| Types.Button({position}) => {
|
|
147
|
-
t->expect(position.row)->Expect.Int.toBeGreaterThanOrEqual(0)
|
|
148
|
-
t->expect(position.col)->Expect.Int.toBeGreaterThanOrEqual(0)
|
|
149
|
-
}
|
|
150
|
-
| _ => ()
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
155
|
-
}
|
|
156
|
-
})
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
// ============================================================================
|
|
160
|
-
// TEST CASE SP-02: Multiple Scenes Parsing
|
|
161
|
-
// ============================================================================
|
|
162
|
-
|
|
163
|
-
describe("SemanticParser Integration - Multiple Scenes", t => {
|
|
164
|
-
test("SP-02: parses multiple scenes separated by dividers", t => {
|
|
165
|
-
let wireframe = `
|
|
166
|
-
@scene: home
|
|
167
|
-
@title: Home Screen
|
|
168
|
-
|
|
169
|
-
+----------+
|
|
170
|
-
| Home |
|
|
171
|
-
+----------+
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
@scene: settings
|
|
176
|
-
@title: Settings Screen
|
|
177
|
-
|
|
178
|
-
+--------------+
|
|
179
|
-
| Settings |
|
|
180
|
-
+--------------+
|
|
181
|
-
`
|
|
182
|
-
|
|
183
|
-
switch Parser.parse(wireframe) {
|
|
184
|
-
| Ok(ast) => {
|
|
185
|
-
// Verify scene count
|
|
186
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(2)
|
|
187
|
-
|
|
188
|
-
// Verify first scene
|
|
189
|
-
let homeScene = ast.scenes->Array.getUnsafe(0)
|
|
190
|
-
t->expect(homeScene.id)->Expect.toBe("home")
|
|
191
|
-
t->expect(homeScene.title)->Expect.toBe("Home Screen")
|
|
192
|
-
|
|
193
|
-
// Verify second scene
|
|
194
|
-
let settingsScene = ast.scenes->Array.getUnsafe(1)
|
|
195
|
-
t->expect(settingsScene.id)->Expect.toBe("settings")
|
|
196
|
-
t->expect(settingsScene.title)->Expect.toBe("Settings Screen")
|
|
197
|
-
|
|
198
|
-
// Verify scenes are separate
|
|
199
|
-
t->expect(homeScene.id)->Expect.not->Expect.toBe(settingsScene.id)
|
|
200
|
-
}
|
|
201
|
-
| Error(errors) => {
|
|
202
|
-
Console.error(errors)
|
|
203
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-02: Expected successful parse of multiple scenes
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
test("SP-02a: handles three or more scenes", t => {
|
|
209
|
-
let wireframe = `
|
|
210
|
-
@scene: one
|
|
211
|
-
+----+
|
|
212
|
-
| 1 |
|
|
213
|
-
+----+
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
@scene: two
|
|
218
|
-
+----+
|
|
219
|
-
| 2 |
|
|
220
|
-
+----+
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
@scene: three
|
|
225
|
-
+----+
|
|
226
|
-
| 3 |
|
|
227
|
-
+----+
|
|
228
|
-
`
|
|
229
|
-
|
|
230
|
-
switch Parser.parse(wireframe) {
|
|
231
|
-
| Ok(ast) => {
|
|
232
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(3)
|
|
233
|
-
t->expect((ast.scenes->Array.getUnsafe(0)).id)->Expect.toBe("one")
|
|
234
|
-
t->expect((ast.scenes->Array.getUnsafe(1)).id)->Expect.toBe("two")
|
|
235
|
-
t->expect((ast.scenes->Array.getUnsafe(2)).id)->Expect.toBe("three")
|
|
236
|
-
}
|
|
237
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse of three scenes
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
// ============================================================================
|
|
243
|
-
// TEST CASE SP-03: Nested Boxes Structure
|
|
244
|
-
// ============================================================================
|
|
245
|
-
|
|
246
|
-
describe("SemanticParser Integration - Nested Boxes", t => {
|
|
247
|
-
test("SP-03: parses nested box hierarchy correctly", t => {
|
|
248
|
-
let wireframe = `
|
|
249
|
-
@scene: nested
|
|
250
|
-
|
|
251
|
-
+--Outer-------------+
|
|
252
|
-
| |
|
|
253
|
-
| +--Inner-------+ |
|
|
254
|
-
| | | |
|
|
255
|
-
| | [ Button ] | |
|
|
256
|
-
| | | |
|
|
257
|
-
| +--------------+ |
|
|
258
|
-
| |
|
|
259
|
-
+--------------------+
|
|
260
|
-
`
|
|
261
|
-
|
|
262
|
-
switch Parser.parse(wireframe) {
|
|
263
|
-
| Ok(ast) => {
|
|
264
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
265
|
-
|
|
266
|
-
// Find outer box
|
|
267
|
-
let outerBox = scene.elements->Array.find(el =>
|
|
268
|
-
switch el {
|
|
269
|
-
| Types.Box({name: Some("Outer")}) => true
|
|
270
|
-
| _ => false
|
|
271
|
-
}
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
switch outerBox {
|
|
275
|
-
| Some(Types.Box({name, children})) => {
|
|
276
|
-
t->expect(name)->Expect.toBe(Some("Outer"))
|
|
277
|
-
t->expect(Array.length(children))->Expect.Int.toBeGreaterThan(0)
|
|
278
|
-
|
|
279
|
-
// Check for inner box in children
|
|
280
|
-
let hasInnerBox = children->Array.some(child =>
|
|
281
|
-
switch child {
|
|
282
|
-
| Types.Box({name: Some("Inner")}) => true
|
|
283
|
-
| _ => false
|
|
284
|
-
}
|
|
285
|
-
)
|
|
286
|
-
t->expect(hasInnerBox)->Expect.toBe(true)
|
|
287
|
-
}
|
|
288
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find outer box
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
| Error(errors) => {
|
|
292
|
-
Console.error(errors)
|
|
293
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-03: Expected successful parse of nested boxes
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
test("SP-03a: handles three-level nesting", t => {
|
|
299
|
-
let wireframe = `
|
|
300
|
-
@scene: deep
|
|
301
|
-
|
|
302
|
-
+--Level1---------------+
|
|
303
|
-
| |
|
|
304
|
-
| +--Level2-----------+ |
|
|
305
|
-
| | | |
|
|
306
|
-
| | +--Level3------+ | |
|
|
307
|
-
| | | [ OK ] | | |
|
|
308
|
-
| | +--------------+ | |
|
|
309
|
-
| | | |
|
|
310
|
-
| +-------------------+ |
|
|
311
|
-
| |
|
|
312
|
-
+-----------------------+
|
|
313
|
-
`
|
|
314
|
-
|
|
315
|
-
switch Parser.parse(wireframe) {
|
|
316
|
-
| Ok(ast) => {
|
|
317
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
318
|
-
|
|
319
|
-
// Verify level 1 box exists
|
|
320
|
-
let hasLevel1 = scene.elements->Array.some(el =>
|
|
321
|
-
switch el {
|
|
322
|
-
| Types.Box({name: Some(n)}) => n->String.includes("Level1")
|
|
323
|
-
| _ => false
|
|
324
|
-
}
|
|
325
|
-
)
|
|
326
|
-
t->expect(hasLevel1)->Expect.toBe(true)
|
|
327
|
-
}
|
|
328
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse of deeply nested boxes
|
|
329
|
-
}
|
|
330
|
-
})
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// TEST CASE SP-04: Horizontal Dividers
|
|
335
|
-
// ============================================================================
|
|
336
|
-
|
|
337
|
-
describe("SemanticParser Integration - Dividers", t => {
|
|
338
|
-
test("SP-04: detects horizontal dividers within boxes", t => {
|
|
339
|
-
let wireframe = `
|
|
340
|
-
@scene: sections
|
|
341
|
-
|
|
342
|
-
+------------------+
|
|
343
|
-
| Section 1 |
|
|
344
|
-
| |
|
|
345
|
-
+==================+
|
|
346
|
-
| Section 2 |
|
|
347
|
-
| |
|
|
348
|
-
+------------------+
|
|
349
|
-
`
|
|
350
|
-
|
|
351
|
-
switch Parser.parse(wireframe) {
|
|
352
|
-
| Ok(ast) => {
|
|
353
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
354
|
-
|
|
355
|
-
// Check for divider element
|
|
356
|
-
let hasDivider = scene.elements->Array.some(el =>
|
|
357
|
-
switch el {
|
|
358
|
-
| Types.Divider(_) => true
|
|
359
|
-
| _ => false
|
|
360
|
-
}
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
// Note: Dividers might be represented as box boundaries
|
|
364
|
-
// or as separate elements depending on implementation
|
|
365
|
-
t->expect(Array.length(scene.elements))->Expect.Int.toBeGreaterThan(0)
|
|
366
|
-
}
|
|
367
|
-
| Error(errors) => {
|
|
368
|
-
Console.error(errors)
|
|
369
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-04: Expected successful parse with dividers
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
})
|
|
373
|
-
|
|
374
|
-
test("SP-04a: handles multiple dividers in one box", t => {
|
|
375
|
-
let wireframe = `
|
|
376
|
-
@scene: multi
|
|
377
|
-
|
|
378
|
-
+----------+
|
|
379
|
-
| Part 1 |
|
|
380
|
-
+==========+
|
|
381
|
-
| Part 2 |
|
|
382
|
-
+==========+
|
|
383
|
-
| Part 3 |
|
|
384
|
-
+----------+
|
|
385
|
-
`
|
|
386
|
-
|
|
387
|
-
switch Parser.parse(wireframe) {
|
|
388
|
-
| Ok(ast) => {
|
|
389
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
390
|
-
|
|
391
|
-
// Verify scene has content
|
|
392
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
393
|
-
t->expect(Array.length(scene.elements))->Expect.Int.toBeGreaterThan(0)
|
|
394
|
-
}
|
|
395
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse with multiple dividers
|
|
396
|
-
}
|
|
397
|
-
})
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
// ============================================================================
|
|
401
|
-
// TEST CASE SP-05: All Element Types Recognition
|
|
402
|
-
// ============================================================================
|
|
403
|
-
|
|
404
|
-
describe("SemanticParser Integration - All Element Types", t => {
|
|
405
|
-
test("SP-05: recognizes all supported element types in one scene", t => {
|
|
406
|
-
let wireframe = `
|
|
407
|
-
@scene: alltypes
|
|
408
|
-
|
|
409
|
-
+----------------------+
|
|
410
|
-
| * Emphasis Text |
|
|
411
|
-
| |
|
|
412
|
-
| Plain Text |
|
|
413
|
-
| |
|
|
414
|
-
| [ Button ] |
|
|
415
|
-
| |
|
|
416
|
-
| #input |
|
|
417
|
-
| |
|
|
418
|
-
| "Link Text" |
|
|
419
|
-
| |
|
|
420
|
-
| [x] Checked Box |
|
|
421
|
-
| |
|
|
422
|
-
| [ ] Unchecked Box |
|
|
423
|
-
+----------------------+
|
|
424
|
-
`
|
|
425
|
-
|
|
426
|
-
switch Parser.parse(wireframe) {
|
|
427
|
-
| Ok(ast) => {
|
|
428
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
429
|
-
|
|
430
|
-
// Check for emphasis text
|
|
431
|
-
let hasEmphasis = scene.elements->Array.some(el =>
|
|
432
|
-
switch el {
|
|
433
|
-
| Types.Text({emphasis: true}) => true
|
|
434
|
-
| _ => false
|
|
435
|
-
}
|
|
436
|
-
)
|
|
437
|
-
t->expect(hasEmphasis)->Expect.toBe(true)
|
|
438
|
-
|
|
439
|
-
// Check for plain text
|
|
440
|
-
let hasPlainText = scene.elements->Array.some(el =>
|
|
441
|
-
switch el {
|
|
442
|
-
| Types.Text({emphasis: false}) => true
|
|
443
|
-
| _ => false
|
|
444
|
-
}
|
|
445
|
-
)
|
|
446
|
-
t->expect(hasPlainText)->Expect.toBe(true)
|
|
447
|
-
|
|
448
|
-
// Check for button
|
|
449
|
-
let hasButton = scene.elements->Array.some(el =>
|
|
450
|
-
switch el {
|
|
451
|
-
| Types.Button(_) => true
|
|
452
|
-
| _ => false
|
|
453
|
-
}
|
|
454
|
-
)
|
|
455
|
-
t->expect(hasButton)->Expect.toBe(true)
|
|
456
|
-
|
|
457
|
-
// Check for input
|
|
458
|
-
let hasInput = scene.elements->Array.some(el =>
|
|
459
|
-
switch el {
|
|
460
|
-
| Types.Input(_) => true
|
|
461
|
-
| _ => false
|
|
462
|
-
}
|
|
463
|
-
)
|
|
464
|
-
t->expect(hasInput)->Expect.toBe(true)
|
|
465
|
-
|
|
466
|
-
// Check for link
|
|
467
|
-
let hasLink = scene.elements->Array.some(el =>
|
|
468
|
-
switch el {
|
|
469
|
-
| Types.Link(_) => true
|
|
470
|
-
| _ => false
|
|
471
|
-
}
|
|
472
|
-
)
|
|
473
|
-
t->expect(hasLink)->Expect.toBe(true)
|
|
474
|
-
|
|
475
|
-
// Check for checked checkbox
|
|
476
|
-
let hasCheckedBox = scene.elements->Array.some(el =>
|
|
477
|
-
switch el {
|
|
478
|
-
| Types.Checkbox({checked: true}) => true
|
|
479
|
-
| _ => false
|
|
480
|
-
}
|
|
481
|
-
)
|
|
482
|
-
t->expect(hasCheckedBox)->Expect.toBe(true)
|
|
483
|
-
|
|
484
|
-
// Check for unchecked checkbox
|
|
485
|
-
let hasUncheckedBox = scene.elements->Array.some(el =>
|
|
486
|
-
switch el {
|
|
487
|
-
| Types.Checkbox({checked: false}) => true
|
|
488
|
-
| _ => false
|
|
489
|
-
}
|
|
490
|
-
)
|
|
491
|
-
t->expect(hasUncheckedBox)->Expect.toBe(true)
|
|
492
|
-
}
|
|
493
|
-
| Error(errors) => {
|
|
494
|
-
Console.error(errors)
|
|
495
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-05: Expected successful parse of all element types
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
})
|
|
499
|
-
})
|
|
500
|
-
|
|
501
|
-
// ============================================================================
|
|
502
|
-
// TEST CASE SP-06: Element Alignment Calculation
|
|
503
|
-
// ============================================================================
|
|
504
|
-
|
|
505
|
-
describe("SemanticParser Integration - Alignment", t => {
|
|
506
|
-
test("SP-06: calculates element alignment based on position", t => {
|
|
507
|
-
let wireframe = `
|
|
508
|
-
@scene: alignment
|
|
509
|
-
|
|
510
|
-
+---------------------------+
|
|
511
|
-
| [ Left ] |
|
|
512
|
-
| |
|
|
513
|
-
| [ Center ] |
|
|
514
|
-
| |
|
|
515
|
-
| [ Right ] |
|
|
516
|
-
+---------------------------+
|
|
517
|
-
`
|
|
518
|
-
|
|
519
|
-
switch Parser.parse(wireframe) {
|
|
520
|
-
| Ok(ast) => {
|
|
521
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
522
|
-
|
|
523
|
-
// Collect all buttons
|
|
524
|
-
let buttons = scene.elements->Array.filter(el =>
|
|
525
|
-
switch el {
|
|
526
|
-
| Types.Button(_) => true
|
|
527
|
-
| _ => false
|
|
528
|
-
}
|
|
529
|
-
)
|
|
530
|
-
|
|
531
|
-
t->expect(Array.length(buttons))->Expect.toBe(3)
|
|
532
|
-
|
|
533
|
-
// Check alignments (order may vary)
|
|
534
|
-
let hasLeft = buttons->Array.some(el =>
|
|
535
|
-
switch el {
|
|
536
|
-
| Types.Button({align: Types.Left}) => true
|
|
537
|
-
| _ => false
|
|
538
|
-
}
|
|
539
|
-
)
|
|
540
|
-
t->expect(hasLeft)->Expect.toBe(true)
|
|
541
|
-
|
|
542
|
-
let hasCenter = buttons->Array.some(el =>
|
|
543
|
-
switch el {
|
|
544
|
-
| Types.Button({align: Types.Center}) => true
|
|
545
|
-
| _ => false
|
|
546
|
-
}
|
|
547
|
-
)
|
|
548
|
-
t->expect(hasCenter)->Expect.toBe(true)
|
|
549
|
-
|
|
550
|
-
let hasRight = buttons->Array.some(el =>
|
|
551
|
-
switch el {
|
|
552
|
-
| Types.Button({align: Types.Right}) => true
|
|
553
|
-
| _ => false
|
|
554
|
-
}
|
|
555
|
-
)
|
|
556
|
-
t->expect(hasRight)->Expect.toBe(true)
|
|
557
|
-
}
|
|
558
|
-
| Error(errors) => {
|
|
559
|
-
Console.error(errors)
|
|
560
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-06: Expected successful parse with alignment
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
})
|
|
564
|
-
})
|
|
565
|
-
|
|
566
|
-
// ============================================================================
|
|
567
|
-
// TEST CASE SP-07-11: Individual Element Type Tests
|
|
568
|
-
// ============================================================================
|
|
569
|
-
|
|
570
|
-
describe("SemanticParser Integration - Button Elements", t => {
|
|
571
|
-
test("SP-07: parses button with simple text", t => {
|
|
572
|
-
let wireframe = `
|
|
573
|
-
@scene: btn
|
|
574
|
-
+------------+
|
|
575
|
-
| [ Submit ] |
|
|
576
|
-
+------------+
|
|
577
|
-
`
|
|
578
|
-
|
|
579
|
-
switch Parser.parse(wireframe) {
|
|
580
|
-
| Ok(ast) => {
|
|
581
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
582
|
-
|
|
583
|
-
let button = scene.elements->Array.find(el =>
|
|
584
|
-
switch el {
|
|
585
|
-
| Types.Button(_) => true
|
|
586
|
-
| _ => false
|
|
587
|
-
}
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
switch button {
|
|
591
|
-
| Some(Types.Button({text, id})) => {
|
|
592
|
-
t->expect(text)->Expect.toBe("Submit")
|
|
593
|
-
t->expect(id)->Expect.toBe("submit")
|
|
594
|
-
}
|
|
595
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find button
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
599
|
-
}
|
|
600
|
-
})
|
|
601
|
-
|
|
602
|
-
test("SP-07a: parses button with multi-word text", t => {
|
|
603
|
-
let wireframe = `
|
|
604
|
-
@scene: btn
|
|
605
|
-
+--------------------+
|
|
606
|
-
| [ Create Account ] |
|
|
607
|
-
+--------------------+
|
|
608
|
-
`
|
|
609
|
-
|
|
610
|
-
switch Parser.parse(wireframe) {
|
|
611
|
-
| Ok(ast) => {
|
|
612
|
-
let button = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
613
|
-
switch el {
|
|
614
|
-
| Types.Button({text}) => text === "Create Account"
|
|
615
|
-
| _ => false
|
|
616
|
-
}
|
|
617
|
-
)
|
|
618
|
-
|
|
619
|
-
switch button {
|
|
620
|
-
| Some(Types.Button({id})) => t->expect(id)->Expect.toBe("create-account")
|
|
621
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find multi-word button
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
625
|
-
}
|
|
626
|
-
})
|
|
627
|
-
})
|
|
628
|
-
|
|
629
|
-
describe("SemanticParser Integration - Input Elements", t => {
|
|
630
|
-
test("SP-08: parses input field with ID", t => {
|
|
631
|
-
let wireframe = `
|
|
632
|
-
@scene: inp
|
|
633
|
-
+----------+
|
|
634
|
-
| #email |
|
|
635
|
-
+----------+
|
|
636
|
-
`
|
|
637
|
-
|
|
638
|
-
switch Parser.parse(wireframe) {
|
|
639
|
-
| Ok(ast) => {
|
|
640
|
-
let input = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
641
|
-
switch el {
|
|
642
|
-
| Types.Input(_) => true
|
|
643
|
-
| _ => false
|
|
644
|
-
}
|
|
645
|
-
)
|
|
646
|
-
|
|
647
|
-
switch input {
|
|
648
|
-
| Some(Types.Input({id})) => t->expect(id)->Expect.toBe("email")
|
|
649
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find input
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
653
|
-
}
|
|
654
|
-
})
|
|
655
|
-
|
|
656
|
-
test("SP-08a: parses input with label prefix", t => {
|
|
657
|
-
let wireframe = `
|
|
658
|
-
@scene: inp
|
|
659
|
-
+-----------------+
|
|
660
|
-
| Email: #email |
|
|
661
|
-
+-----------------+
|
|
662
|
-
`
|
|
663
|
-
|
|
664
|
-
switch Parser.parse(wireframe) {
|
|
665
|
-
| Ok(ast) => {
|
|
666
|
-
let input = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
667
|
-
switch el {
|
|
668
|
-
| Types.Input({id: "email"}) => true
|
|
669
|
-
| _ => false
|
|
670
|
-
}
|
|
671
|
-
)
|
|
672
|
-
|
|
673
|
-
t->expect(input)->Expect.not->Expect.toBe(None)
|
|
674
|
-
}
|
|
675
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
676
|
-
}
|
|
677
|
-
})
|
|
678
|
-
})
|
|
679
|
-
|
|
680
|
-
describe("SemanticParser Integration - Link Elements", t => {
|
|
681
|
-
test("SP-09: parses link with quoted text", t => {
|
|
682
|
-
let wireframe = `
|
|
683
|
-
@scene: lnk
|
|
684
|
-
+------------------+
|
|
685
|
-
| "Click Here" |
|
|
686
|
-
+------------------+
|
|
687
|
-
`
|
|
688
|
-
|
|
689
|
-
switch Parser.parse(wireframe) {
|
|
690
|
-
| Ok(ast) => {
|
|
691
|
-
let link = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
692
|
-
switch el {
|
|
693
|
-
| Types.Link(_) => true
|
|
694
|
-
| _ => false
|
|
695
|
-
}
|
|
696
|
-
)
|
|
697
|
-
|
|
698
|
-
switch link {
|
|
699
|
-
| Some(Types.Link({text, id})) => {
|
|
700
|
-
t->expect(text)->Expect.toBe("Click Here")
|
|
701
|
-
t->expect(id)->Expect.toBe("click-here")
|
|
702
|
-
}
|
|
703
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find link
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
707
|
-
}
|
|
708
|
-
})
|
|
709
|
-
})
|
|
710
|
-
|
|
711
|
-
describe("SemanticParser Integration - Checkbox Elements", t => {
|
|
712
|
-
test("SP-10: parses checked checkbox", t => {
|
|
713
|
-
let wireframe = `
|
|
714
|
-
@scene: chk
|
|
715
|
-
+-------------------+
|
|
716
|
-
| [x] Accept terms |
|
|
717
|
-
+-------------------+
|
|
718
|
-
`
|
|
719
|
-
|
|
720
|
-
switch Parser.parse(wireframe) {
|
|
721
|
-
| Ok(ast) => {
|
|
722
|
-
let checkbox = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
723
|
-
switch el {
|
|
724
|
-
| Types.Checkbox({checked: true}) => true
|
|
725
|
-
| _ => false
|
|
726
|
-
}
|
|
727
|
-
)
|
|
728
|
-
|
|
729
|
-
switch checkbox {
|
|
730
|
-
| Some(Types.Checkbox({label})) => t->expect(label)->Expect.toBe("Accept terms")
|
|
731
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find checked checkbox
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
735
|
-
}
|
|
736
|
-
})
|
|
737
|
-
|
|
738
|
-
test("SP-10a: parses unchecked checkbox", t => {
|
|
739
|
-
let wireframe = `
|
|
740
|
-
@scene: chk
|
|
741
|
-
+---------------------+
|
|
742
|
-
| [ ] Decline offer |
|
|
743
|
-
+---------------------+
|
|
744
|
-
`
|
|
745
|
-
|
|
746
|
-
switch Parser.parse(wireframe) {
|
|
747
|
-
| Ok(ast) => {
|
|
748
|
-
let checkbox = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
749
|
-
switch el {
|
|
750
|
-
| Types.Checkbox({checked: false}) => true
|
|
751
|
-
| _ => false
|
|
752
|
-
}
|
|
753
|
-
)
|
|
754
|
-
|
|
755
|
-
t->expect(checkbox)->Expect.not->Expect.toBe(None)
|
|
756
|
-
}
|
|
757
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
758
|
-
}
|
|
759
|
-
})
|
|
760
|
-
})
|
|
761
|
-
|
|
762
|
-
describe("SemanticParser Integration - Emphasis Text", t => {
|
|
763
|
-
test("SP-11: parses emphasis text with asterisk", t => {
|
|
764
|
-
let wireframe = `
|
|
765
|
-
@scene: emp
|
|
766
|
-
+-----------------+
|
|
767
|
-
| * Important |
|
|
768
|
-
+-----------------+
|
|
769
|
-
`
|
|
770
|
-
|
|
771
|
-
switch Parser.parse(wireframe) {
|
|
772
|
-
| Ok(ast) => {
|
|
773
|
-
let emphasisText = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
774
|
-
switch el {
|
|
775
|
-
| Types.Text({emphasis: true}) => true
|
|
776
|
-
| _ => false
|
|
777
|
-
}
|
|
778
|
-
)
|
|
779
|
-
|
|
780
|
-
switch emphasisText {
|
|
781
|
-
| Some(Types.Text({content})) => t->expect(content)->Expect.String.toContain("Important")
|
|
782
|
-
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected to find emphasis text
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse
|
|
786
|
-
}
|
|
787
|
-
})
|
|
788
|
-
})
|
|
789
|
-
|
|
790
|
-
// ============================================================================
|
|
791
|
-
// TEST CASE SP-12: Mixed Content Scene
|
|
792
|
-
// ============================================================================
|
|
793
|
-
|
|
794
|
-
describe("SemanticParser Integration - Mixed Content", t => {
|
|
795
|
-
test("SP-12: parses complex scene with mixed element types", t => {
|
|
796
|
-
let wireframe = `
|
|
797
|
-
@scene: mixed
|
|
798
|
-
|
|
799
|
-
+-------------------------+
|
|
800
|
-
| * Registration Form |
|
|
801
|
-
| |
|
|
802
|
-
| Name: #name |
|
|
803
|
-
| Email: #email |
|
|
804
|
-
| |
|
|
805
|
-
| [x] Accept terms |
|
|
806
|
-
| |
|
|
807
|
-
| [ Sign Up ] |
|
|
808
|
-
| |
|
|
809
|
-
| "Already registered?" |
|
|
810
|
-
+-------------------------+
|
|
811
|
-
`
|
|
812
|
-
|
|
813
|
-
switch Parser.parse(wireframe) {
|
|
814
|
-
| Ok(ast) => {
|
|
815
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
816
|
-
|
|
817
|
-
// Count different element types
|
|
818
|
-
let emphasisCount = scene.elements->Array.filter(el =>
|
|
819
|
-
switch el {
|
|
820
|
-
| Types.Text({emphasis: true}) => true
|
|
821
|
-
| _ => false
|
|
822
|
-
}
|
|
823
|
-
)->Array.length
|
|
824
|
-
|
|
825
|
-
let inputCount = scene.elements->Array.filter(el =>
|
|
826
|
-
switch el {
|
|
827
|
-
| Types.Input(_) => true
|
|
828
|
-
| _ => false
|
|
829
|
-
}
|
|
830
|
-
)->Array.length
|
|
831
|
-
|
|
832
|
-
let checkboxCount = scene.elements->Array.filter(el =>
|
|
833
|
-
switch el {
|
|
834
|
-
| Types.Checkbox(_) => true
|
|
835
|
-
| _ => false
|
|
836
|
-
}
|
|
837
|
-
)->Array.length
|
|
838
|
-
|
|
839
|
-
let buttonCount = scene.elements->Array.filter(el =>
|
|
840
|
-
switch el {
|
|
841
|
-
| Types.Button(_) => true
|
|
842
|
-
| _ => false
|
|
843
|
-
}
|
|
844
|
-
)->Array.length
|
|
845
|
-
|
|
846
|
-
let linkCount = scene.elements->Array.filter(el =>
|
|
847
|
-
switch el {
|
|
848
|
-
| Types.Link(_) => true
|
|
849
|
-
| _ => false
|
|
850
|
-
}
|
|
851
|
-
)->Array.length
|
|
852
|
-
|
|
853
|
-
// Verify all types are present
|
|
854
|
-
t->expect(emphasisCount)->Expect.Int.toBeGreaterThan(0)
|
|
855
|
-
t->expect(inputCount)->Expect.Int.toBeGreaterThanOrEqual(2) // name and email
|
|
856
|
-
t->expect(checkboxCount)->Expect.Int.toBeGreaterThan(0)
|
|
857
|
-
t->expect(buttonCount)->Expect.Int.toBeGreaterThan(0)
|
|
858
|
-
t->expect(linkCount)->Expect.Int.toBeGreaterThan(0)
|
|
859
|
-
|
|
860
|
-
// Verify scene has substantial content
|
|
861
|
-
t->expect(Array.length(scene.elements))->Expect.Int.toBeGreaterThan(5)
|
|
862
|
-
}
|
|
863
|
-
| Error(errors) => {
|
|
864
|
-
Console.error(errors)
|
|
865
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-12: Expected successful parse of mixed content scene
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
})
|
|
869
|
-
})
|
|
870
|
-
|
|
871
|
-
// ============================================================================
|
|
872
|
-
// TEST CASE SP-14: Scene Directives Parsing
|
|
873
|
-
// ============================================================================
|
|
874
|
-
|
|
875
|
-
describe("SemanticParser Integration - Scene Directives", t => {
|
|
876
|
-
test("SP-14: parses scene directives correctly", t => {
|
|
877
|
-
let wireframe = `
|
|
878
|
-
@scene: test
|
|
879
|
-
@title: Test Scene
|
|
880
|
-
@transition: fade
|
|
881
|
-
|
|
882
|
-
+----------+
|
|
883
|
-
| Content |
|
|
884
|
-
+----------+
|
|
885
|
-
`
|
|
886
|
-
|
|
887
|
-
switch Parser.parse(wireframe) {
|
|
888
|
-
| Ok(ast) => {
|
|
889
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
890
|
-
|
|
891
|
-
t->expect(scene.id)->Expect.toBe("test")
|
|
892
|
-
t->expect(scene.title)->Expect.toBe("Test Scene")
|
|
893
|
-
t->expect(scene.transition)->Expect.toBe("fade")
|
|
894
|
-
}
|
|
895
|
-
| Error(errors) => {
|
|
896
|
-
Console.error(errors)
|
|
897
|
-
t->expect(true)->Expect.toBe(false) // fail: SP-14: Expected successful parse of scene directives
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
})
|
|
901
|
-
|
|
902
|
-
test("SP-14a: handles missing optional directives", t => {
|
|
903
|
-
let wireframe = `
|
|
904
|
-
@scene: minimal
|
|
905
|
-
|
|
906
|
-
+----------+
|
|
907
|
-
| Content |
|
|
908
|
-
+----------+
|
|
909
|
-
`
|
|
910
|
-
|
|
911
|
-
switch Parser.parse(wireframe) {
|
|
912
|
-
| Ok(ast) => {
|
|
913
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
914
|
-
|
|
915
|
-
t->expect(scene.id)->Expect.toBe("minimal")
|
|
916
|
-
// Title and transition should have defaults or be empty
|
|
917
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
918
|
-
}
|
|
919
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse with minimal directives
|
|
920
|
-
}
|
|
921
|
-
})
|
|
922
|
-
})
|
|
923
|
-
|
|
924
|
-
// ============================================================================
|
|
925
|
-
// TEST CASE SP-15: Empty Scene Handling
|
|
926
|
-
// ============================================================================
|
|
927
|
-
|
|
928
|
-
describe("SemanticParser Integration - Empty Scenes", t => {
|
|
929
|
-
test("SP-15: handles empty scene gracefully", t => {
|
|
930
|
-
let wireframe = `
|
|
931
|
-
@scene: empty
|
|
932
|
-
|
|
933
|
-
+-------+
|
|
934
|
-
| |
|
|
935
|
-
+-------+
|
|
936
|
-
`
|
|
937
|
-
|
|
938
|
-
switch Parser.parse(wireframe) {
|
|
939
|
-
| Ok(ast) => {
|
|
940
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
941
|
-
|
|
942
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
943
|
-
t->expect(scene.id)->Expect.toBe("empty")
|
|
944
|
-
|
|
945
|
-
// Empty scene should still have valid structure
|
|
946
|
-
t->expect(Array.isArray(scene.elements))->Expect.toBe(true)
|
|
947
|
-
}
|
|
948
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: SP-15: Expected successful parse of empty scene
|
|
949
|
-
}
|
|
950
|
-
})
|
|
951
|
-
|
|
952
|
-
test("SP-15a: handles scene with only whitespace", t => {
|
|
953
|
-
let wireframe = `
|
|
954
|
-
@scene: whitespace
|
|
955
|
-
|
|
956
|
-
+-----------+
|
|
957
|
-
| |
|
|
958
|
-
| |
|
|
959
|
-
| |
|
|
960
|
-
+-----------+
|
|
961
|
-
`
|
|
962
|
-
|
|
963
|
-
switch Parser.parse(wireframe) {
|
|
964
|
-
| Ok(ast) => {
|
|
965
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
966
|
-
|
|
967
|
-
let scene = ast.scenes->Array.getUnsafe(0)
|
|
968
|
-
t->expect(scene.id)->Expect.toBe("whitespace")
|
|
969
|
-
}
|
|
970
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful parse of whitespace-only scene
|
|
971
|
-
}
|
|
972
|
-
})
|
|
973
|
-
})
|
|
974
|
-
|
|
975
|
-
// ============================================================================
|
|
976
|
-
// EDGE CASES AND ERROR HANDLING
|
|
977
|
-
// ============================================================================
|
|
978
|
-
|
|
979
|
-
describe("SemanticParser Integration - Edge Cases", t => {
|
|
980
|
-
test("handles very long element text", t => {
|
|
981
|
-
let wireframe = `
|
|
982
|
-
@scene: long
|
|
983
|
-
|
|
984
|
-
+---------------------------------------------------+
|
|
985
|
-
| [ Very Long Button Text That Spans ] |
|
|
986
|
-
+---------------------------------------------------+
|
|
987
|
-
`
|
|
988
|
-
|
|
989
|
-
switch Parser.parse(wireframe) {
|
|
990
|
-
| Ok(ast) => {
|
|
991
|
-
let button = (ast.scenes->Array.getUnsafe(0)).elements->Array.find(el =>
|
|
992
|
-
switch el {
|
|
993
|
-
| Types.Button(_) => true
|
|
994
|
-
| _ => false
|
|
995
|
-
}
|
|
996
|
-
)
|
|
997
|
-
|
|
998
|
-
t->expect(button)->Expect.not->Expect.toBe(None)
|
|
999
|
-
}
|
|
1000
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected to handle long text
|
|
1001
|
-
}
|
|
1002
|
-
})
|
|
1003
|
-
|
|
1004
|
-
test("handles special characters in text", t => {
|
|
1005
|
-
let wireframe = `
|
|
1006
|
-
@scene: special
|
|
1007
|
-
|
|
1008
|
-
+-------------------+
|
|
1009
|
-
| "Sign Up & Go!" |
|
|
1010
|
-
+-------------------+
|
|
1011
|
-
`
|
|
1012
|
-
|
|
1013
|
-
switch Parser.parse(wireframe) {
|
|
1014
|
-
| Ok(ast) => {
|
|
1015
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
1016
|
-
}
|
|
1017
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected to handle special characters
|
|
1018
|
-
}
|
|
1019
|
-
})
|
|
1020
|
-
|
|
1021
|
-
test("handles unicode characters", t => {
|
|
1022
|
-
let wireframe = `
|
|
1023
|
-
@scene: unicode
|
|
1024
|
-
|
|
1025
|
-
+-------------+
|
|
1026
|
-
| * Hello |
|
|
1027
|
-
+-------------+
|
|
1028
|
-
`
|
|
1029
|
-
|
|
1030
|
-
switch Parser.parse(wireframe) {
|
|
1031
|
-
| Ok(ast) => {
|
|
1032
|
-
t->expect(Array.length(ast.scenes))->Expect.toBe(1)
|
|
1033
|
-
}
|
|
1034
|
-
| Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected to handle unicode
|
|
1035
|
-
}
|
|
1036
|
-
})
|
|
1037
|
-
})
|
|
1038
|
-
|
|
1039
|
-
// ============================================================================
|
|
1040
|
-
// SUMMARY
|
|
1041
|
-
// ============================================================================
|
|
1042
|
-
|
|
1043
|
-
/*
|
|
1044
|
-
* Test Coverage Summary:
|
|
1045
|
-
*
|
|
1046
|
-
* SP-01: Simple Login Scene - ✓
|
|
1047
|
-
* SP-02: Multiple Scenes - ✓
|
|
1048
|
-
* SP-03: Nested Boxes - ✓
|
|
1049
|
-
* SP-04: Dividers - ✓
|
|
1050
|
-
* SP-05: All Element Types - ✓
|
|
1051
|
-
* SP-06: Alignment - ✓
|
|
1052
|
-
* SP-07: Buttons - ✓
|
|
1053
|
-
* SP-08: Inputs - ✓
|
|
1054
|
-
* SP-09: Links - ✓
|
|
1055
|
-
* SP-10: Checkboxes - ✓
|
|
1056
|
-
* SP-11: Emphasis - ✓
|
|
1057
|
-
* SP-12: Mixed Content - ✓
|
|
1058
|
-
* SP-14: Scene Directives - ✓
|
|
1059
|
-
* SP-15: Empty Scenes - ✓
|
|
1060
|
-
*
|
|
1061
|
-
* Additional Coverage:
|
|
1062
|
-
* - Edge cases (long text, special chars, unicode)
|
|
1063
|
-
* - Error handling (partial parses)
|
|
1064
|
-
* - Position information validation
|
|
1065
|
-
* - Element property validation
|
|
1066
|
-
*
|
|
1067
|
-
* Total Tests: 30+
|
|
1068
|
-
* Coverage Target: ≥90% for SemanticParser module
|
|
1069
|
-
*/
|