@@ -85,6 +85,13 @@ rust/leanspec-http/tests/
8585- Verify response structure compatibility
8686- Test serialization consistency
8787
88+ ** Comparative Testing** (RECOMMENDED):
89+ - Run both Next.js API (` pnpm -F @leanspec/ui dev ` ) and Rust HTTP server side-by-side
90+ - Make identical requests to both servers with same test data
91+ - Compare JSON responses field-by-field
92+ - Validate identical behavior and structure
93+ - Catch subtle differences that static schema checks might miss
94+
8895** Test Fixtures** :
8996- Reusable test projects with known spec structure
9097- Sample specs with various statuses, priorities, tags
@@ -93,10 +100,11 @@ rust/leanspec-http/tests/
93100** Tools** :
94101- ` axum-test ` or raw Axum router testing
95102- ` reqwest ` for HTTP client
96- - ` serde_json ` for response validation
103+ - ` serde_json ` for response validation and comparison
97104- ` schemars ` for JSON Schema generation and validation
98105- ` tempfile ` for temporary test projects
99106- ` tokio::test ` for async tests
107+ - ` assert_json_diff ` for comparing JSON responses between servers
100108
101109## Plan
102110
@@ -107,6 +115,8 @@ rust/leanspec-http/tests/
107115- [ ] Add test utilities (assertions, matchers)
108116- [ ] Set up schema validation utilities
109117- [ ] Document reference Next.js API schemas
118+ - [ ] Create dual-server test helper (optional: spawn both Next.js + Rust)
119+ - [ ] Add JSON response comparison utilities
110120
111121### Phase 2: Project Management Tests (Day 2)
112122- [ ] Test GET ` /api/projects ` (list all, empty state, multi-project)
@@ -183,9 +193,82 @@ rust/leanspec-http/tests/
183193- [ ] Large dataset testing (100+ specs)
184194- [ ] Test documentation/examples
185195- [ ] JSON Schema exports for documentation
196+ - [ ] ** Comparative tests with live Next.js API** (side-by-side validation)
186197
187198## Test Examples
188199
200+ ### Comparative Testing (Next.js vs Rust)
201+
202+ ``` rust
203+ #[tokio:: test]
204+ #[ignore] // Only run when Next.js server is running
205+ async fn test_compare_specs_response_with_nextjs () {
206+ // Set up test project with known specs
207+ let test_project = setup_test_project_with_fixtures (). await ;
208+
209+ // Start Rust HTTP server
210+ let rust_client = reqwest :: Client :: new ();
211+ let rust_base = " http://localhost:3001" ; // Rust server
212+
213+ // Assume Next.js is running on default port
214+ let nextjs_client = reqwest :: Client :: new ();
215+ let nextjs_base = " http://localhost:3000" ; // Next.js server
216+
217+ // Compare GET /api/specs responses
218+ let rust_res = rust_client
219+ . get (format! (" {}/api/specs" , rust_base ))
220+ . send ()
221+ . await
222+ . unwrap ();
223+ let rust_json : serde_json :: Value = rust_res . json (). await . unwrap ();
224+
225+ let nextjs_res = nextjs_client
226+ . get (format! (" {}/api/projects/default/specs" , nextjs_base ))
227+ . send ()
228+ . await
229+ . unwrap ();
230+ let nextjs_json : serde_json :: Value = nextjs_res . json (). await . unwrap ();
231+
232+ // Compare response structure
233+ assert_json_diff :: assert_json_eq! (
234+ rust_json [" specs" ][0 ][" specNumber" ],
235+ nextjs_json [" specs" ][0 ][" specNumber" ]
236+ );
237+ assert_json_diff :: assert_json_eq! (
238+ rust_json [" specs" ][0 ][" specName" ],
239+ nextjs_json [" specs" ][0 ][" specName" ]
240+ );
241+
242+ // Verify both use camelCase
243+ assert! (rust_json [" specs" ][0 ]. get (" specNumber" ). is_some ());
244+ assert! (rust_json [" specs" ][0 ]. get (" spec_number" ). is_none ());
245+ }
246+
247+ #[tokio:: test]
248+ async fn test_compare_stats_response_structure () {
249+ let rust_app = test_server_with_fixtures (). await ;
250+
251+ // Get stats from Rust API
252+ let rust_res = rust_app . get (" /api/stats" ). send (). await ;
253+ let rust_json : serde_json :: Value = rust_res . json (). await ;
254+
255+ // Validate structure matches Next.js format
256+ // Next.js returns: { stats: { total, byStatus, byPriority, byTag, ... } }
257+ assert! (rust_json . get (" total" ). is_some ());
258+ assert! (rust_json . get (" byStatus" ). is_some ());
259+ assert! (rust_json . get (" byPriority" ). is_some ());
260+ assert! (rust_json . get (" byTag" ). is_some ());
261+ assert! (rust_json . get (" completionPercentage" ). is_some ());
262+
263+ // Validate nested structure (camelCase)
264+ let by_status = & rust_json [" byStatus" ];
265+ assert! (by_status . get (" planned" ). is_some ());
266+ assert! (by_status . get (" inProgress" ). is_some ()); // camelCase
267+ assert! (by_status . get (" in_progress" ). is_none ()); // NOT snake_case
268+ assert! (by_status . get (" complete" ). is_some ());
269+ }
270+ ```
271+
189272### Schema Validation Test
190273
191274``` rust
@@ -347,6 +430,35 @@ async fn test_search_relevance_ranking() {
3474304 . Document any intentional differences
3484315 . Create compatibility tests that would fail on schema drift
349432
433+ ** Comparative Testing (Recommended)** :
434+ 1 . Run Next.js dev server: ` pnpm -F @leanspec/ui dev ` (port 3000)
435+ 2 . Run Rust HTTP server: ` cargo run --bin leanspec-http ` (port 3001)
436+ 3 . Point both at same test project directory
437+ 4 . Make identical requests to both APIs
438+ 5 . Compare JSON responses field-by-field using ` assert_json_diff `
439+ 6 . Validates not just schema but actual behavior
440+
441+ ** Benefits of Live Comparison** :
442+ - Catches subtle differences that static checks miss
443+ - Validates actual serialization behavior
444+ - Tests with real Next.js API implementation
445+ - No need to manually extract/maintain reference schemas
446+ - Confirms identical responses for same input
447+
448+ ** Setup for Comparative Tests** :
449+ ``` bash
450+ # Terminal 1: Start Next.js API
451+ cd /path/to/lean-spec
452+ pnpm -F @leanspec/ui dev
453+
454+ # Terminal 2: Start Rust HTTP server
455+ cd /path/to/lean-spec/rust/leanspec-http
456+ cargo run
457+
458+ # Terminal 3: Run comparative tests
459+ cargo test --test comparative -- --ignored
460+ ```
461+
350462** Key Fields to Validate** :
351463- ` specNumber ` (not ` spec_number ` )
352464- ` specName ` (not ` spec_name ` )
@@ -405,3 +517,10 @@ async fn test_search_relevance_ranking() {
405517- Defined test architecture and strategy
406518- 5-day implementation plan
407519- Priority: HIGH - prerequisite for Spec 190
520+
521+ ### 2025-12-19: Schema Alignment Added
522+ - Added explicit schema compatibility testing with Next.js APIs
523+ - Documented key fields to validate (camelCase serialization)
524+ - Added comparative testing strategy (run both servers side-by-side)
525+ - Confirmed Rust types already use camelCase via ` #[serde(rename_all = "camelCase")] `
526+ - Added example tests for live API comparison
0 commit comments