Precise DOM morphing
morphing typescript dom
at main 152 lines 4.0 kB view raw
1import { test, expect } from "vitest" 2import { morph } from "../../src/morphlex" 3import { dom } from "../new/utils" 4 5test("input type mismatch triggers continue - then finds matching type", () => { 6 // This test ensures we hit the continue statement on line 564 7 // by having two input candidates where: 8 // 1. First candidate has wrong type (continue is executed) 9 // 2. Second candidate has correct type (match succeeds) 10 const a = dom( 11 `<div> 12 <input type="text" data-marker="1"> 13 <input type="checkbox" data-marker="2"> 14 </div>`, 15 ) as HTMLElement 16 17 const b = dom( 18 `<div> 19 <input type="checkbox" data-marker="new"> 20 </div>`, 21 ) as HTMLElement 22 23 morph(a, b) 24 25 // The checkbox should be reused, text input removed 26 expect(a.children.length).toBe(1) 27 expect((a.children[0] as HTMLInputElement).type).toBe("checkbox") 28 expect((a.children[0] as HTMLInputElement).getAttribute("data-marker")).toBe("new") 29}) 30 31test("input type mismatch with multiple wrong types before match", () => { 32 // Multiple candidates with wrong types, continue is executed multiple times 33 const a = dom( 34 `<div> 35 <input type="text"> 36 <input type="radio"> 37 <input type="number"> 38 <input type="email" data-id="target"> 39 </div>`, 40 ) as HTMLElement 41 42 const b = dom( 43 `<div> 44 <input type="email" data-id="new"> 45 </div>`, 46 ) as HTMLElement 47 48 morph(a, b) 49 50 // Text, radio, and number inputs trigger continue, email matches 51 expect(a.children.length).toBe(1) 52 expect((a.children[0] as HTMLInputElement).type).toBe("email") 53 expect((a.children[0] as HTMLInputElement).getAttribute("data-id")).toBe("new") 54}) 55 56test("input type mismatch with no matching type - all trigger continue", () => { 57 // All candidates have wrong type, continue is executed for all, no match found 58 const a = dom( 59 `<div> 60 <input type="text"> 61 <input type="checkbox"> 62 <input type="radio"> 63 </div>`, 64 ) as HTMLElement 65 66 const b = dom( 67 `<div> 68 <input type="email"> 69 </div>`, 70 ) as HTMLElement 71 72 morph(a, b) 73 74 // No type matches, so new element is created, old ones removed 75 expect(a.children.length).toBe(1) 76 expect((a.children[0] as HTMLInputElement).type).toBe("email") 77}) 78 79test("input with matching type does not trigger continue", () => { 80 // When types match, the continue branch is NOT taken 81 const a = dom( 82 `<div> 83 <input type="text" data-value="old"> 84 <input type="text" data-value="old2"> 85 </div>`, 86 ) as HTMLElement 87 88 const b = dom( 89 `<div> 90 <input type="text" data-value="new"> 91 </div>`, 92 ) as HTMLElement 93 94 const firstInput = a.children[0] 95 96 morph(a, b) 97 98 // First text input matches without triggering continue 99 expect(a.children.length).toBe(1) 100 expect(a.children[0]).toBe(firstInput) 101 expect((a.children[0] as HTMLInputElement).getAttribute("data-value")).toBe("new") 102}) 103 104test("non-input elements skip the type check entirely", () => { 105 // isInputElement checks prevent non-inputs from entering the type check 106 const a = dom( 107 `<div> 108 <button data-test="1">A</button> 109 <button data-test="2">B</button> 110 </div>`, 111 ) as HTMLElement 112 113 const b = dom( 114 `<div> 115 <button data-test="new">C</button> 116 </div>`, 117 ) as HTMLElement 118 119 const firstButton = a.children[0] 120 121 morph(a, b) 122 123 // Buttons match by localName without any type checking 124 expect(a.children.length).toBe(1) 125 expect(a.children[0]).toBe(firstButton) 126 expect(a.children[0].getAttribute("data-test")).toBe("new") 127}) 128 129test("mixed inputs and non-inputs in localName matching", () => { 130 // Ensure the logic handles both inputs and non-inputs correctly 131 const a = dom( 132 `<div> 133 <input type="text"> 134 <button>Button</button> 135 <input type="email" class="target"> 136 </div>`, 137 ) as HTMLElement 138 139 const b = dom( 140 `<div> 141 <input type="email" class="new"> 142 <button>New Button</button> 143 </div>`, 144 ) as HTMLElement 145 146 morph(a, b) 147 148 // Email input and button should both be matched 149 expect(a.children.length).toBe(2) 150 expect((a.children[0] as HTMLInputElement).type).toBe("email") 151 expect(a.children[1].tagName).toBe("BUTTON") 152})