@@ -31,6 +31,22 @@ async function dragCanvasPoint(page, from, to) {
3131 } , { from, to } ) ;
3232}
3333
34+ async function readCollisionSummary ( page ) {
35+ return JSON . parse ( await page . locator ( "#collisionSummary" ) . textContent ( ) ) ;
36+ }
37+
38+ async function canvasSignature ( page ) {
39+ return page . locator ( "#collisionCanvas" ) . evaluate ( ( canvas ) => {
40+ const context = canvas . getContext ( "2d" ) ;
41+ const data = context . getImageData ( 0 , 0 , canvas . width , canvas . height ) . data ;
42+ let signature = 0 ;
43+ for ( let index = 0 ; index < data . length ; index += 97 ) {
44+ signature = ( signature * 31 + data [ index ] * 3 + data [ index + 1 ] * 5 + data [ index + 2 ] * 7 + data [ index + 3 ] ) >>> 0 ;
45+ }
46+ return signature ;
47+ } ) ;
48+ }
49+
3450test . describe ( "Collision Inspector V2" , ( ) => {
3551 test ( "loads a game manifest and reports live vector, pixel, bounds, and hybrid collisions" , async ( { page } ) => {
3652 const server = await startRepoServer ( ) ;
@@ -139,6 +155,9 @@ test.describe("Collision Inspector V2", () => {
139155 await expect ( page . locator ( "#collisionSummaryContent #collisionSummary" ) ) . toBeVisible ( ) ;
140156 await expect ( page . locator ( "#resultContent" ) ) . not . toContainText ( "Mode" ) ;
141157 await expect ( page . locator ( ".collision-inspector-v2__legend" ) ) . toContainText ( "Heading" ) ;
158+ await expect ( page . locator ( ".collision-inspector-v2__legend span" ) . nth ( 3 ) ) . toHaveAttribute ( "title" , "Heading guide shows object rotation from its origin." ) ;
159+ await expect ( page . locator ( "#collisionCanvas" ) ) . toHaveAttribute ( "aria-describedby" , "collisionGuideNote" ) ;
160+ await expect ( page . locator ( "#collisionGuideNote" ) ) . toHaveText ( "Heading guides show each object's rotation from its origin." ) ;
142161 const summaryOverflow = await page . locator ( "#collisionSummaryContent" ) . evaluate ( ( element ) => getComputedStyle ( element ) . overflowY ) ;
143162 expect ( [ "auto" , "scroll" ] ) . toContain ( summaryOverflow ) ;
144163 const resultOverflow = await page . locator ( "#resultContent" ) . evaluate ( ( element ) => getComputedStyle ( element ) . overflowY ) ;
@@ -151,15 +170,21 @@ test.describe("Collision Inspector V2", () => {
151170 const logs = document . querySelector ( ".collision-inspector-v2__accordion--logs" ) . getBoundingClientRect ( ) ;
152171 const heights = [ result . height , summary . height , logs . height ] ;
153172 return {
173+ logContentHeight : document . querySelector ( "#collisionLogContent" ) . getBoundingClientRect ( ) . height ,
154174 inputMaxDelta : Math . abs ( manifest . height - pair . height ) ,
155175 maxDelta : Math . max ( ...heights ) - Math . min ( ...heights ) ,
176+ resultContentHeight : document . querySelector ( "#resultContent" ) . getBoundingClientRect ( ) . height ,
156177 resultWidth : result . width ,
178+ summaryContentHeight : document . querySelector ( "#collisionSummaryContent" ) . getBoundingClientRect ( ) . height ,
157179 summaryWidth : summary . width ,
158180 logsWidth : logs . width
159181 } ;
160182 } ) ;
161183 expect ( outputLayout . inputMaxDelta ) . toBeLessThanOrEqual ( 6 ) ;
162184 expect ( outputLayout . maxDelta ) . toBeLessThanOrEqual ( 6 ) ;
185+ expect ( outputLayout . resultContentHeight ) . toBeGreaterThan ( 80 ) ;
186+ expect ( outputLayout . summaryContentHeight ) . toBeGreaterThan ( 80 ) ;
187+ expect ( outputLayout . logContentHeight ) . toBeGreaterThan ( 80 ) ;
163188 expect ( Math . abs ( outputLayout . resultWidth - outputLayout . summaryWidth ) ) . toBeLessThanOrEqual ( 1 ) ;
164189 expect ( Math . abs ( outputLayout . summaryWidth - outputLayout . logsWidth ) ) . toBeLessThanOrEqual ( 1 ) ;
165190 await expect ( page . locator ( "button[aria-controls='collisionLogContent']" ) ) . toBeVisible ( ) ;
@@ -168,10 +193,23 @@ test.describe("Collision Inspector V2", () => {
168193 await page . locator ( "button[aria-controls='collisionLogContent']" ) . click ( ) ;
169194 await expect ( page . locator ( "#collisionLogContent" ) ) . toBeVisible ( ) ;
170195
196+ const initialSummary = await readCollisionSummary ( page ) ;
197+ const initialSignature = await canvasSignature ( page ) ;
171198 await page . locator ( "#objectARotationInput" ) . fill ( "45" ) ;
172199 await expect ( page . locator ( "#rotationState" ) ) . toHaveText ( "A 45 / B 0" ) ;
200+ const rotatedASummary = await readCollisionSummary ( page ) ;
201+ expect ( rotatedASummary . enginePath ) . toBe ( "src/engine/collision/objectVector.js" ) ;
202+ expect ( rotatedASummary . rotation . objectA ) . toBe ( 45 ) ;
203+ expect ( rotatedASummary . rotation . objectB ) . toBe ( 0 ) ;
204+ expect ( rotatedASummary . transformedPoints . objectA ) . not . toEqual ( initialSummary . transformedPoints . objectA ) ;
205+ expect ( await canvasSignature ( page ) ) . not . toBe ( initialSignature ) ;
173206 await page . locator ( "#objectBRotationInput" ) . fill ( "180" ) ;
174207 await expect ( page . locator ( "#rotationState" ) ) . toHaveText ( "A 45 / B 180" ) ;
208+ const rotatedBSummary = await readCollisionSummary ( page ) ;
209+ expect ( rotatedBSummary . enginePath ) . toBe ( "src/engine/collision/objectVector.js" ) ;
210+ expect ( rotatedBSummary . rotation . objectA ) . toBe ( 45 ) ;
211+ expect ( rotatedBSummary . rotation . objectB ) . toBe ( 180 ) ;
212+ expect ( rotatedBSummary . transformedPoints . objectB ) . not . toEqual ( initialSummary . transformedPoints . objectB ) ;
175213 await page . locator ( "#objectARotationInput" ) . fill ( "0" ) ;
176214 await expect ( page . locator ( "#rotationState" ) ) . toHaveText ( "A 0 / B 180" ) ;
177215
@@ -201,6 +239,11 @@ test.describe("Collision Inspector V2", () => {
201239 await page . locator ( "#collisionZoomInput" ) . fill ( "5" ) ;
202240 await expect ( page . locator ( "#zoomState" ) ) . toHaveText ( "5x" ) ;
203241 await expect ( page . locator ( "#collisionSummary" ) ) . toContainText ( '"zoom": 5' ) ;
242+ const zoomAspectRatio = await page . locator ( "#collisionCanvas" ) . evaluate ( ( canvas ) => {
243+ const rect = canvas . getBoundingClientRect ( ) ;
244+ return rect . width / rect . height ;
245+ } ) ;
246+ expect ( Math . abs ( zoomAspectRatio - ( 960 / 720 ) ) ) . toBeLessThan ( 0.02 ) ;
204247 await page . evaluate ( ( ) => window . __collisionInspectorV2App . setZoom ( 8 ) ) ;
205248 await expect ( page . locator ( "#zoomState" ) ) . toHaveText ( "5x" ) ;
206249 await expect ( page . locator ( "#collisionSummary" ) ) . toContainText ( '"zoom": 5' ) ;
0 commit comments