code wiki / (root) / nx_ttt_bits_up_e2e.nx

nx_ttt_bits_up_e2e.nx source

↩ module page · 106 lines · 4867 B

1// nx_ttt_bits_up_e2e.nx -- REAL bits-up end-to-end test driving the 2// actual nx_tictactoe game through the 5 bits-up test driver primitives. 3// Equivalent to nishi-pages/scripts/_bits_up_check.mjs but 100% NishiLang. 4// 5// What this proves: the .mjs Playwright harness can be retired in favor 6// of bits-up substrate. No JS, no Playwright, no browser engine -- the 7// game's actual state machine + AI + render are driven through the same 8// click-dispatch lifecycle the browser uses, with HTML emitted via fd 99 9// captured into a buffer, queried by the DOM primitives, asserted by 10// the test harness DSL. 11 12import "nx_test_harness.nx" 13import "nx_game_harness.nx" 14import "nx_dom_query.nx" 15import "nx_dom_click.nx" 16import "nx_tictactoe.nx" 17import "nx_tictactoe_render.nx" 18const K_MAGIC_65536: i64 = 65536 19 20func _ttt_e2e_strlen(s: *u8) -> i64 { 21 var n: i64 = 0 22 while s[n] != 0 { n = n + 1 } 23 return n 24} 25 26func main() -> i64 { 27 nx_test_init() 28 29 // ---- Cycle 1: fresh game ---- 30 let state: *i64 = nx_ttt_init() 31 let buf: *u8 = sys_mmap(K_MAGIC_65536) 32 33 let cap1: *NxGameCapture = nx_capture_start() 34 nx_ttt_render(state) 35 let n1: i64 = nx_capture_end(cap1, buf, K_MAGIC_65536 as i64) 36 37 nx_test_expect_eq("real game cycle 1: bytes captured > 0" as *u8, 38 n1 > 0, 1 as i64) 39 nx_test_expect_class_count("real game: 9 .cell elements" as *u8, 40 buf, n1, "cell" as *u8, 9 as i64) 41 // 9 cell buttons + 1 reset button = 10 buttons in controls. 42 nx_test_expect_tag_count("real game: 10 <button> tags (9 cells + reset)" as *u8, 43 buf, n1, "button" as *u8, 10 as i64) 44 nx_test_expect_contains("real game: status shows player turn" as *u8, 45 buf, n1, "Your move" as *u8) 46 nx_test_expect_not_contains("real game: no X yet" as *u8, 47 buf, n1, ">X<" as *u8) 48 nx_test_expect_not_contains("real game: no O yet" as *u8, 49 buf, n1, ">O<" as *u8) 50 51 // ---- Click cell 4 (center) -- bits-up click intent extraction ---- 52 let intent: *NxClickIntent = nx_dom_click_intent(buf, n1, 53 "data-cell-idx" as *u8, 54 "4" as *u8) 55 nx_test_expect_click("click intent for cell 4 (action=1, arg0=4)" as *u8, 56 intent, 1 as i64, 4 as i64) 57 // Dispatch through the REAL game's action function. 58 nx_ttt_action(state, intent.action, intent.arg0, intent.arg1, 59 intent.arg2, intent.arg3) 60 61 // ---- Cycle 2: after click ---- 62 let cap2: *NxGameCapture = nx_capture_start() 63 nx_ttt_render(state) 64 let n2: i64 = nx_capture_end(cap2, buf, K_MAGIC_65536 as i64) 65 66 nx_test_expect_contains("after click: X visible somewhere" as *u8, 67 buf, n2, ">X<" as *u8) 68 nx_test_expect_contains("after click: O visible (AI played)" as *u8, 69 buf, n2, ">O<" as *u8) 70 71 // Verify the X landed at cell 4 specifically by querying the DOM. 72 let cell4: *NxDomQueryResult = nx_dom_find_attr_eq(buf, n2, 73 "data-cell-idx" as *u8, 74 "4" as *u8) 75 nx_test_expect_eq("cell-4 element still found in DOM" as *u8, 76 cell4.found, 1 as i64) 77 78 // State-hash determinism: the same state produces the same hash. 79 let h1: i64 = nx_ttt_state_hash(state) 80 let h2: i64 = nx_ttt_state_hash(state) 81 nx_test_expect_eq("state hash is deterministic for same state" as *u8, 82 h1, h2) 83 84 // ---- Click the reset button (data-action=2) ---- 85 let reset_intent: *NxClickIntent = nx_dom_click_intent(buf, n2, 86 "data-action" as *u8, 87 "2" as *u8) 88 nx_test_expect_click("reset button found (action=2, arg0=0)" as *u8, 89 reset_intent, 2 as i64, 0 as i64) 90 nx_ttt_action(state, reset_intent.action, reset_intent.arg0, 91 reset_intent.arg1, reset_intent.arg2, reset_intent.arg3) 92 93 // ---- Cycle 3: after reset, should be clean board ---- 94 let cap3: *NxGameCapture = nx_capture_start() 95 nx_ttt_render(state) 96 let n3: i64 = nx_capture_end(cap3, buf, K_MAGIC_65536 as i64) 97 98 nx_test_expect_class_count("after reset: 9 .cell elements" as *u8, 99 buf, n3, "cell" as *u8, 9 as i64) 100 nx_test_expect_not_contains("after reset: no X" as *u8, 101 buf, n3, ">X<" as *u8) 102 nx_test_expect_not_contains("after reset: no O" as *u8, 103 buf, n3, ">O<" as *u8) 104 105 return nx_test_summary() 106}