@@ -18,19 +18,20 @@ Transform the testing approach from separate Java→OpenAPI and OpenAPI→TypeSc
1818
1919## Progress Status
2020
21- ** Phase 1: Infrastructure** ✅ COMPLETE
22- - NodeRunner.java ✅
21+ ** Phase 1: Infrastructure** ✅ COMPLETE + SIMPLIFIED
22+ - ~~ NodeRunner.java~~ → Uses Flow's FrontendUtils.executeCommand ✅
2323- run-generator.mjs ✅
24- - FullStackTestHelper.java ✅
24+ - ~~ FullStackTestHelper.java~~ → Merged into AbstractFullStackTest ✅
2525- TypeScriptComparator.java ✅
26+ - ** AbstractFullStackTest.java** ✅ (base class with all configuration)
2627
2728** Phase 2: Convert Tests** 🔄 IN PROGRESS (4/47 converted)
2829
2930** Transfertypes Plugin (4/8):**
30- - ✅ UUIDFullStackTest (cleaned: removed connect-client.default.ts, endpoints.ts)
31- - ✅ JsonNodeFullStackTest (cleaned: removed connect-client.default.ts, endpoints.ts)
32- - ✅ MultipartFileFullStackTest (cleaned: removed connect-client.default.ts, endpoints.ts)
33- - ✅ PushTypeFullStackTest (cleaned: removed connect-client.default.ts, endpoints.ts)
31+ - ✅ UUIDTest (cleaned: removed connect-client.default.ts, endpoints.ts)
32+ - ✅ JsonNodeTest (cleaned: removed connect-client.default.ts, endpoints.ts)
33+ - ✅ MultipartFileTest (cleaned: removed connect-client.default.ts, endpoints.ts)
34+ - ✅ PushTypeTest (cleaned: removed connect-client.default.ts, endpoints.ts)
3435- ⏳ PageableTest
3536- ⏳ BarePageableTest
3637- ⏳ SignalTest (requires SignalsPlugin fix)
@@ -46,13 +47,27 @@ Transform the testing approach from separate Java→OpenAPI and OpenAPI→TypeSc
4647
4748## Phase 1: Build Full-Stack Testing Infrastructure
4849
49- ### 1.1 Create Node.js Test Runner (Java)
50- ** Location:** ` packages/java/typescript-generator/src/test/java/com/vaadin/hilla/parser/testutils/NodeRunner .java `
50+ ### 1.1 Create Abstract Base Test Class ✅ SIMPLIFIED
51+ ** Location:** ` packages/java/typescript-generator/src/test/java/com/vaadin/hilla/parser/testutils/AbstractFullStackTest .java `
5152
52- - Similar to ` GeneratorShellRunner ` but for tests
53- - Execute Node.js scripts with proper working directory
54- - Capture stdout/stderr for debugging
55- - Throw exceptions on non-zero exit codes
53+ ** Provides all test configuration in one place:**
54+ ``` java
55+ public abstract class AbstractFullStackTest {
56+ // Executes Java → OpenAPI → TypeScript pipeline
57+ // Compares generated TypeScript to snapshots
58+ // All configuration pre-configured (plugins, classpath, annotations)
59+
60+ protected void assertTypescriptMatchesSnapshot (Class<?> ... endpointClasses )
61+ throws Exception ;
62+ }
63+ ```
64+
65+ ** Key simplifications:**
66+ - Uses Flow's ` FrontendUtils.executeCommand() ` instead of custom NodeRunner
67+ - All helper methods integrated (no separate FullStackTestHelper)
68+ - Pre-configured with all plugins (Backbone, TransferTypes, Model, Nonnull, SubTypes, MultipartFileChecker)
69+ - Extended classpath includes Flux and EndpointSubscription
70+ - Both @Endpoint and @EndpointExposed annotations configured
5671
5772### 1.2 Create Generator Execution Script (Node.js)
5873** Location:** ` packages/java/typescript-generator/src/test/resources/run-generator.mjs `
@@ -64,20 +79,9 @@ Transform the testing approach from separate Java→OpenAPI and OpenAPI→TypeSc
6479// Outputs generated files as JSON map
6580```
6681
67- ### 1.3 Create Full-Stack Test Helper
68- ** Location:** ` packages/java/typescript-generator/src/test/java/com/vaadin/hilla/parser/testutils/FullStackTestHelper.java `
69-
70- ``` java
71- public class FullStackTestHelper {
72- // Execute full pipeline: Java → OpenAPI → TypeScript
73- public GeneratedFiles executeFullStack (OpenAPI openAPI );
74-
75- // Compare generated TS to expected snapshots
76- public void assertTypescriptMatches (GeneratedFiles actual , Path snapshotsDir );
77- }
78- ```
82+ ### 1.3 Create TypeScript Comparison Utilities
83+ ** Location:** ` packages/java/typescript-generator/src/test/java/com/vaadin/hilla/parser/testutils/TypeScriptComparator.java `
7984
80- ### 1.4 Create TypeScript Comparison Utilities
8185- Line-by-line diff with clear error messages
8286- Handle whitespace normalization
8387- Support for multiple file assertions
@@ -89,21 +93,32 @@ public class FullStackTestHelper {
8993
9094For each existing test (e.g., ` SignalTest.java ` ):
9195
92- ### 2.1 Update Test Method
93- ** Before:**
96+ ### 2.1 Update Test Method ✅ SIMPLIFIED
97+
98+ ** Before (old split testing):**
9499``` java
95100var openAPI = new Parser ()
96101 .execute(List . of(SignalEndpoint . class));
97102helper. executeParserWithConfig(openAPI); // Checks openapi.json
98103```
99104
100- ** After:**
105+ ** After (with AbstractFullStackTest) :**
101106``` java
102- var openAPI = new Parser ()
103- .execute(List . of(SignalEndpoint . class));
104- helper. executeFullStack(openAPI); // Generates and checks TypeScript
107+ public class SignalTest extends AbstractFullStackTest {
108+ @Test
109+ public void should_GenerateSignalEndpoint () throws Exception {
110+ assertTypescriptMatchesSnapshot(SignalEndpoint . class);
111+ }
112+ }
105113```
106114
115+ ** Benefits:**
116+ - No Parser configuration needed (handled by base class)
117+ - No helper instantiation needed
118+ - Single line test assertion
119+ - All plugins automatically included
120+ - Consistent across all tests
121+
107122### 2.2 Generate Initial TypeScript Snapshots
108123** Location pattern:** ` src/test/resources/com/vaadin/hilla/parser/.../snapshots/*.ts `
109124
@@ -121,10 +136,10 @@ Run tests in "generate mode" to create initial snapshots:
121136- ** Model tests** : Include model files (e.g., ` MyModel.ts ` )
122137- ** Subtypes tests** : Include model files with type guards
123138
124- ### 2.3 Update TestHelper Usage
125- - Remove ` executeParserWithConfig() ` calls
126- - Replace with ` executeFullStack() ` + ` assertTypescriptMatches ()`
127- - Keep same test structure and assertions for other aspects
139+ ### 2.3 Update Test Structure ✅ SIMPLIFIED
140+ - Extend ` AbstractFullStackTest ` base class
141+ - Replace entire test implementation with single ` assertTypescriptMatchesSnapshot ()` call
142+ - All configuration (plugins, classpath, annotations) handled automatically
128143
129144** Affected files:** ~ 42 test classes across:
130145- ` plugins/transfertypes/* `
@@ -169,19 +184,25 @@ Ensure each generator plugin has tests:
169184
170185For each TS test without Java equivalent (e.g., ` BasicClient.spec.ts ` ):
171186
172- ### 4.1 Create Java Test Class
187+ ### 4.1 Create Java Test Class ✅ SIMPLIFIED
173188** Example:** ` packages/java/typescript-generator/src/test/java/com/vaadin/hilla/parser/plugins/client/BasicClientTest.java `
174189
175190``` java
176- @Test
177- public void should_GenerateBasicClient() {
178- var openAPI = resourceLoader. loadOpenAPI(" BasicClient.json" );
179- var generated = helper. executeFullStack(openAPI);
180- helper. assertTypescriptMatches(generated,
181- resourceLoader. getSnapshotsDir());
191+ public class BasicClientTest extends AbstractFullStackTest {
192+ @Test
193+ public void should_GenerateBasicClient () throws Exception {
194+ assertTypescriptMatchesSnapshot(BasicClientEndpoint . class);
195+ }
182196}
183197```
184198
199+ ** Note:** If you need to load OpenAPI from JSON instead of generating from Java:
200+ ``` java
201+ // For edge cases where you have OpenAPI JSON but no Java equivalent
202+ var openAPI = resourceLoader. loadOpenAPI(" BasicClient.json" );
203+ // Then manually call executeFullStack (internal method)
204+ ```
205+
185206### 4.2 Copy OpenAPI Input
186207** From:** ` packages/ts/generator-plugin-client/test/basic/BasicClient.json `
187208** To:** ` packages/java/typescript-generator/src/test/resources/com/vaadin/hilla/parser/plugins/client/BasicClient.json `
@@ -288,6 +309,29 @@ If issues arise:
288309
289310## Best Practices for Writing Full-Stack Tests
290311
312+ ### 0. Use AbstractFullStackTest Base Class ✅
313+
314+ ** All tests should extend AbstractFullStackTest:**
315+ ``` java
316+ public class MyFeatureTest extends AbstractFullStackTest {
317+ @Test
318+ public void should_VerifyMyFeature () throws Exception {
319+ assertTypescriptMatchesSnapshot(MyEndpoint . class);
320+ }
321+ }
322+ ```
323+
324+ ** The base class provides:**
325+ - ✅ All plugins pre-configured (Backbone, TransferTypes, Model, Nonnull, SubTypes, MultipartFileChecker)
326+ - ✅ Extended classpath with Flux and EndpointSubscription
327+ - ✅ Both @Endpoint and @EndpointExposed annotations
328+ - ✅ Automatic Node.js execution via Flow's FrontendUtils
329+ - ✅ Snapshot comparison with clear error messages
330+
331+ ** Test complexity reduction:**
332+ - Before: ~ 60 lines per test (manual Parser setup, helper usage)
333+ - After: ~ 15 lines per test (just extend base class and assert)
334+
291335### 1. Keep Snapshots Minimal and Focused
292336
293337** DO:**
@@ -342,3 +386,106 @@ src/test/resources/com/vaadin/hilla/parser/plugins/{plugin}/{feature}/
342386- Model generation and structure
343387- Polymorphic types (subtypes)
344388- Nullability annotations
389+
390+ ---
391+
392+ ## Architecture Improvements and Simplifications
393+
394+ ### Refactoring Summary (3 commits)
395+
396+ The initial infrastructure was simplified through 3 major refactorings:
397+
398+ ** 1. Commit: Create AbstractFullStackTest base class**
399+ - Unified all test configuration in single base class
400+ - Eliminated boilerplate from test files
401+ - Pre-configured all plugins, classpath, and annotations
402+ - Result: -200 lines across test files
403+
404+ ** 2. Commit: Merge FullStackTestHelper into AbstractFullStackTest**
405+ - Removed unnecessary helper layer
406+ - All functionality integrated into base class
407+ - Cleaner architecture with single responsibility
408+ - Result: -39 lines (FullStackTestHelper removed)
409+
410+ ** 3. Commit: Replace NodeRunner with Flow's FrontendUtils.executeCommand**
411+ - ** Eliminated custom ProcessBuilder implementation entirely**
412+ - ** Uses existing Flow infrastructure (FrontendUtils.executeCommand)**
413+ - Platform-aware command execution (Windows/Unix)
414+ - Proper stream handling and error reporting
415+ - Result: ** -197 lines (NodeRunner removed)**
416+
417+ ### Net Impact
418+
419+ ** Code reduction: -436 lines**
420+ - Deleted: 557 lines of boilerplate and custom infrastructure
421+ - Added: 121 lines (AbstractFullStackTest base class)
422+
423+ ** Test simplification:**
424+ ``` java
425+ // Before: 63 lines
426+ public class UUIDFullStackTest {
427+ private final FullStackTestHelper helper = new FullStackTestHelper (getClass());
428+
429+ @Test
430+ public void should_ReplaceUUIDClassWithStringInTypeScript ()
431+ throws IOException , URISyntaxException , FullStackExecutionException {
432+ var openAPI = new Parser ()
433+ .classPath(Set . of(helper. getTargetDir(). toString()))
434+ .endpointAnnotations(List . of(Endpoint . class))
435+ .endpointExposedAnnotations(List . of(EndpointExposed . class))
436+ .addPlugin(new BackbonePlugin ())
437+ .addPlugin(new TransferTypesPlugin ())
438+ .execute(List . of(UUIDEndpoint . class));
439+ var generated = helper. executeFullStack(openAPI);
440+ helper. assertTypescriptMatches(generated, helper. getSnapshotsDir());
441+ }
442+ }
443+
444+ // After: 33 lines (48% reduction)
445+ public class UUIDTest extends AbstractFullStackTest {
446+ @Test
447+ public void should_ReplaceUUIDClassWithStringInTypeScript () throws Exception {
448+ assertTypescriptMatchesSnapshot(UUIDEndpoint . class);
449+ }
450+ }
451+ ```
452+
453+ ### Key Architectural Benefits
454+
455+ 1 . ** Reuses existing infrastructure** : No custom ProcessBuilder code, uses Flow's battle-tested FrontendUtils
456+ 2 . ** Single source of truth** : All test configuration in AbstractFullStackTest
457+ 3 . ** Consistent testing** : All tests use same plugins, classpath, and annotations
458+ 4 . ** Easy to maintain** : Changes to configuration only need to happen in one place
459+ 5 . ** Simple to write** : New tests are 3 lines (class + @Test + assertion)
460+
461+ ### Files Structure
462+
463+ ** Current infrastructure (as of refactoring):**
464+ ```
465+ packages/java/typescript-generator/src/test/java/com/vaadin/hilla/parser/testutils/
466+ ├── AbstractFullStackTest.java ← All-in-one base class (uses FrontendUtils)
467+ ├── TypeScriptComparator.java ← File comparison logic
468+ └── ResourceLoader.java ← Test resource utilities
469+
470+ packages/java/typescript-generator/src/test/resources/
471+ └── run-generator.mjs ← Node.js script (called by AbstractFullStackTest)
472+ ```
473+
474+ ** Removed files (no longer needed):**
475+ - ~~ NodeRunner.java~~ → Flow's FrontendUtils.executeCommand
476+ - ~~ FullStackTestHelper.java~~ → Merged into AbstractFullStackTest
477+
478+ ### Usage
479+
480+ Writing a new full-stack test is now trivial:
481+
482+ ``` java
483+ public class MyNewFeatureTest extends AbstractFullStackTest {
484+ @Test
485+ public void should_GenerateMyFeature () throws Exception {
486+ assertTypescriptMatchesSnapshot(MyEndpoint . class);
487+ }
488+ }
489+ ```
490+
491+ That's it! No configuration, no setup, no boilerplate.
0 commit comments