brick-engine-js 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/.env.local.example +2 -0
  2. package/.github/workflows/publish.yml +73 -0
  3. package/.prettierignore +2 -0
  4. package/.prettierrc.json +8 -0
  5. package/README.adoc +84 -0
  6. package/dist/8e23286c2fdf41fd795f.svg +32 -0
  7. package/dist/CNAME +1 -0
  8. package/dist/app.js +2 -0
  9. package/dist/app.js.map +1 -0
  10. package/dist/brick-engine.js +2 -0
  11. package/dist/brick-engine.js.map +1 -0
  12. package/dist/config/configs.d.ts +180 -0
  13. package/dist/config/configs.test.d.ts +1 -0
  14. package/dist/config/env.d.ts +2 -0
  15. package/dist/config/env.test.d.ts +1 -0
  16. package/dist/config/styles.d.ts +0 -0
  17. package/dist/core/Game.d.ts +107 -0
  18. package/dist/core/Game.test.d.ts +1 -0
  19. package/dist/core/InitialStateSnapshot.d.ts +19 -0
  20. package/dist/core/InitialStateSnapshot.test.d.ts +1 -0
  21. package/dist/core/helpers/CellHelper.d.ts +13 -0
  22. package/dist/core/helpers/CellHelper.test.d.ts +1 -0
  23. package/dist/core/helpers/ControlInputHandlerHelper.d.ts +32 -0
  24. package/dist/core/helpers/ControlInputHandlerHelper.test.d.ts +1 -0
  25. package/dist/core/helpers/CoordinateHelper.d.ts +54 -0
  26. package/dist/core/helpers/CoordinateHelper.test.d.ts +1 -0
  27. package/dist/core/helpers/InterfaceIdentifierHelper.d.ts +7 -0
  28. package/dist/core/helpers/InterfaceIdentifierHelper.test.d.ts +1 -0
  29. package/dist/core/helpers/RelativeValuesHelper.d.ts +23 -0
  30. package/dist/core/helpers/RelativeValuesHelper.test.d.ts +1 -0
  31. package/dist/core/module/control/GameControl.d.ts +62 -0
  32. package/dist/core/module/control/GameControl.test.d.ts +1 -0
  33. package/dist/core/module/control/GameControlKeyBinding.d.ts +36 -0
  34. package/dist/core/module/control/GameControlKeyBinding.test.d.ts +1 -0
  35. package/dist/core/module/grid/GameGrid.d.ts +399 -0
  36. package/dist/core/module/grid/GameGrid.test.d.ts +1 -0
  37. package/dist/core/module/grid/GameHudGrid.d.ts +24 -0
  38. package/dist/core/module/grid/GameHudGrid.test.d.ts +1 -0
  39. package/dist/core/module/grid/engines/GridAnalysisEngine.d.ts +29 -0
  40. package/dist/core/module/grid/engines/GridAnalysisEngine.test.d.ts +1 -0
  41. package/dist/core/module/grid/engines/GridLineEngine.d.ts +56 -0
  42. package/dist/core/module/grid/engines/GridLineEngine.test.d.ts +1 -0
  43. package/dist/core/module/grid/engines/GridMovementEngine.d.ts +29 -0
  44. package/dist/core/module/grid/engines/GridMovementEngine.test.d.ts +1 -0
  45. package/dist/core/module/grid/engines/GridRegionEngine.d.ts +26 -0
  46. package/dist/core/module/grid/engines/GridRegionEngine.test.d.ts +1 -0
  47. package/dist/core/module/grid/engines/GridTransformEngine.d.ts +24 -0
  48. package/dist/core/module/grid/engines/GridTransformEngine.test.d.ts +1 -0
  49. package/dist/core/module/renderer/DisplayRenderer.d.ts +51 -0
  50. package/dist/core/module/renderer/DisplayRenderer.test.d.ts +1 -0
  51. package/dist/core/module/renderer/GameRenderer.d.ts +59 -0
  52. package/dist/core/module/renderer/GameRenderer.test.d.ts +1 -0
  53. package/dist/core/module/renderer/HudRenderer.d.ts +56 -0
  54. package/dist/core/module/renderer/HudRenderer.test.d.ts +1 -0
  55. package/dist/core/module/score/GameScore.d.ts +117 -0
  56. package/dist/core/module/score/GameScore.test.d.ts +1 -0
  57. package/dist/core/module/session/GameSession.d.ts +20 -0
  58. package/dist/core/module/session/GameSession.test.d.ts +1 -0
  59. package/dist/core/module/sound/GameSound.d.ts +85 -0
  60. package/dist/core/module/sound/GameSound.test.d.ts +1 -0
  61. package/dist/core/module/state/GameState.d.ts +172 -0
  62. package/dist/core/module/state/GameState.test.d.ts +1 -0
  63. package/dist/core/module/text/GameText.d.ts +87 -0
  64. package/dist/core/module/text/GameText.test.d.ts +1 -0
  65. package/dist/core/module/time/GameTime.d.ts +76 -0
  66. package/dist/core/module/time/GameTime.test.d.ts +1 -0
  67. package/dist/core/types/Interfaces.d.ts +53 -0
  68. package/dist/core/types/Types.d.ts +114 -0
  69. package/dist/core/types/enums.d.ts +106 -0
  70. package/dist/core/types/modules.d.ts +723 -0
  71. package/dist/css/app.743066d8e4172b0e73f9.css +824 -0
  72. package/dist/css/app.743066d8e4172b0e73f9.css.map +1 -0
  73. package/dist/docs/GAME_DEVELOPER_GUIDE.html +727 -0
  74. package/dist/docs/brick-engine-guide.html +610 -0
  75. package/dist/docs/diagrams/lifecycle.mmd +19 -0
  76. package/dist/docs/documentation_style_guide.html +994 -0
  77. package/dist/docs/getting-started.html +648 -0
  78. package/dist/docs/images/lifecycle.svg +1 -0
  79. package/dist/docs/index.html +593 -0
  80. package/dist/docs/jsdoc_standard.html +656 -0
  81. package/dist/docs/publishing.html +573 -0
  82. package/dist/docs/reference/enums/Color.html +533 -0
  83. package/dist/docs/reference/enums/ControlEventType.html +505 -0
  84. package/dist/docs/reference/enums/ControlKey.html +529 -0
  85. package/dist/docs/reference/enums/FontAlignment.html +545 -0
  86. package/dist/docs/reference/enums/FontSize.html +517 -0
  87. package/dist/docs/reference/enums/Sound.html +558 -0
  88. package/dist/docs/reference/enums/StateProperty.html +525 -0
  89. package/dist/docs/reference/helpers/CellHelper.html +520 -0
  90. package/dist/docs/reference/helpers/ControlInputHandlerHelper.html +569 -0
  91. package/dist/docs/reference/helpers/CoordinateHelper.html +703 -0
  92. package/dist/docs/reference/helpers/RelativeValuesHelper.html +560 -0
  93. package/dist/docs/reference/interfaces/Debuggable.html +501 -0
  94. package/dist/docs/reference/interfaces/GameModules.html +544 -0
  95. package/dist/docs/reference/interfaces/Initializable.html +495 -0
  96. package/dist/docs/reference/interfaces/RendererInitializable.html +517 -0
  97. package/dist/docs/reference/interfaces/StateSyncable.html +542 -0
  98. package/dist/docs/reference/interfaces/modules/Control.html +648 -0
  99. package/dist/docs/reference/interfaces/modules/Grid.html +1256 -0
  100. package/dist/docs/reference/interfaces/modules/Renderer.html +522 -0
  101. package/dist/docs/reference/interfaces/modules/RendererComposite.html +577 -0
  102. package/dist/docs/reference/interfaces/modules/Score.html +669 -0
  103. package/dist/docs/reference/interfaces/modules/Session.html +585 -0
  104. package/dist/docs/reference/interfaces/modules/State.html +897 -0
  105. package/dist/docs/reference/interfaces/modules/Text.html +668 -0
  106. package/dist/docs/reference/interfaces/modules/Time.html +684 -0
  107. package/dist/docs/reference/modules/Debugger.html +579 -0
  108. package/dist/docs/reference/modules/DisplayRenderer.html +557 -0
  109. package/dist/docs/reference/modules/Game.html +909 -0
  110. package/dist/docs/reference/modules/GameControl.html +716 -0
  111. package/dist/docs/reference/modules/GameGrid.html +1910 -0
  112. package/dist/docs/reference/modules/GameHudGrid.html +508 -0
  113. package/dist/docs/reference/modules/GameMenu.html +538 -0
  114. package/dist/docs/reference/modules/GameRenderer.html +589 -0
  115. package/dist/docs/reference/modules/GameScore.html +664 -0
  116. package/dist/docs/reference/modules/GameSession.html +533 -0
  117. package/dist/docs/reference/modules/GameSound.html +636 -0
  118. package/dist/docs/reference/modules/GameState.html +922 -0
  119. package/dist/docs/reference/modules/GameText.html +701 -0
  120. package/dist/docs/reference/modules/GameTime.html +696 -0
  121. package/dist/docs/reference/modules/HudRenderer.html +568 -0
  122. package/dist/docs/reference/modules/InitialStateSnapshot.html +557 -0
  123. package/dist/docs/reference/modules/SessionModal.html +520 -0
  124. package/dist/docs/reference/types/Axis.html +505 -0
  125. package/dist/docs/reference/types/Cell.html +514 -0
  126. package/dist/docs/reference/types/ControlCallback.html +488 -0
  127. package/dist/docs/reference/types/Coordinate.html +510 -0
  128. package/dist/docs/reference/types/GameEntry.html +514 -0
  129. package/dist/docs/reference/types/GameEvent.html +514 -0
  130. package/dist/docs/reference/types/Piece.html +506 -0
  131. package/dist/docs/reference/types/RendererMetrics.html +514 -0
  132. package/dist/docs/reference/types/Vector.html +509 -0
  133. package/dist/docs/testing_best_practices.html +770 -0
  134. package/dist/favicon.ico +0 -0
  135. package/dist/fonts/digital-7.monoitalic.ttf +0 -0
  136. package/dist/images/cell.svg +32 -0
  137. package/dist/images/close.png +0 -0
  138. package/dist/images/games.png +0 -0
  139. package/dist/images/github.png +0 -0
  140. package/dist/images/letter-a.png +0 -0
  141. package/dist/images/letter-d.png +0 -0
  142. package/dist/images/letter-j.png +0 -0
  143. package/dist/images/letter-s.png +0 -0
  144. package/dist/images/letter-w.png +0 -0
  145. package/dist/images/meta-image.png +0 -0
  146. package/dist/images/number-1.png +0 -0
  147. package/dist/images/number-2.png +0 -0
  148. package/dist/images/number-3.png +0 -0
  149. package/dist/images/number-4.png +0 -0
  150. package/dist/images/number-5.png +0 -0
  151. package/dist/images/number-6.png +0 -0
  152. package/dist/images/splash.gif +0 -0
  153. package/dist/index.d.ts +8 -0
  154. package/dist/index.html +1 -0
  155. package/dist/index.test.d.ts +1 -0
  156. package/dist/main.d.ts +3 -0
  157. package/dist/main.test.d.ts +1 -0
  158. package/dist/menu/GameMenu.d.ts +15 -0
  159. package/dist/menu/GameMenu.test.d.ts +1 -0
  160. package/dist/menu/GameMenuSingleton.d.ts +6 -0
  161. package/dist/menu/GameMenuSingleton.test.d.ts +1 -0
  162. package/dist/menu/GameRepository.d.ts +7 -0
  163. package/dist/menu/GameRepository.test.d.ts +1 -0
  164. package/dist/menu/manager/GameManager.d.ts +6 -0
  165. package/dist/menu/manager/GameManager.test.d.ts +1 -0
  166. package/dist/sounds/sound_00.wav +0 -0
  167. package/dist/sounds/sound_01.wav +0 -0
  168. package/dist/sounds/sound_02.wav +0 -0
  169. package/dist/sounds/sound_03.wav +0 -0
  170. package/dist/sounds/sound_04.wav +0 -0
  171. package/dist/sounds/sound_05.wav +0 -0
  172. package/dist/sounds/sound_06.wav +0 -0
  173. package/dist/sounds/sound_07.wav +0 -0
  174. package/dist/sounds/sound_08.wav +0 -0
  175. package/dist/sounds/sound_09.wav +0 -0
  176. package/dist/sounds/sound_10.wav +0 -0
  177. package/dist/sounds/sound_11.wav +0 -0
  178. package/dist/sounds/sound_12.wav +0 -0
  179. package/dist/sounds/sound_13.wav +0 -0
  180. package/dist/sounds/sound_14.wav +0 -0
  181. package/dist/sounds/sound_15.wav +0 -0
  182. package/dist/types/interfaces.d.ts +5 -0
  183. package/dist/vendor/p5.min.js +1 -0
  184. package/dist/view/Debugger.d.ts +12 -0
  185. package/dist/view/Debugger.test.d.ts +1 -0
  186. package/dist/view/GameView.d.ts +101 -0
  187. package/dist/view/GameView.test.d.ts +1 -0
  188. package/dist/view/SessionModal.d.ts +12 -0
  189. package/dist/view/SessionModal.test.d.ts +4 -0
  190. package/dist/view/components/layout/ButtonLayout.d.ts +25 -0
  191. package/dist/view/components/layout/ButtonLayout.test.d.ts +1 -0
  192. package/dist/view/components/layout/ContainerLayout.d.ts +23 -0
  193. package/dist/view/components/layout/ContainerLayout.test.d.ts +1 -0
  194. package/dist/view/components/layout/FrameLayout.d.ts +11 -0
  195. package/dist/view/components/layout/FrameLayout.test.d.ts +1 -0
  196. package/dist/view/components/ui/BigButton.d.ts +13 -0
  197. package/dist/view/components/ui/BigButton.test.d.ts +1 -0
  198. package/dist/view/components/ui/Button.d.ts +12 -0
  199. package/dist/view/components/ui/Button.test.d.ts +1 -0
  200. package/dist/view/components/ui/Canvas.d.ts +22 -0
  201. package/dist/view/components/ui/Canvas.test.d.ts +1 -0
  202. package/dist/view/components/ui/SmallButton.d.ts +13 -0
  203. package/dist/view/components/ui/SmallButton.test.d.ts +1 -0
  204. package/dist/view/theme/applyColors.d.ts +10 -0
  205. package/dist/view/theme/applyColors.test.d.ts +1 -0
  206. package/dist/view/theme/dimensions.d.ts +13 -0
  207. package/dist/view/theme/dimensions.test.d.ts +1 -0
  208. package/docs/GAME_DEVELOPER_GUIDE.adoc +167 -0
  209. package/docs/brick-engine-guide.adoc +87 -0
  210. package/docs/diagrams/lifecycle.mmd +19 -0
  211. package/docs/documentation_style_guide.adoc +210 -0
  212. package/docs/getting-started.adoc +147 -0
  213. package/docs/images/lifecycle.svg +1 -0
  214. package/docs/jsdoc_standard.adoc +109 -0
  215. package/docs/publishing.adoc +58 -0
  216. package/docs/reference/enums/Color.adoc +35 -0
  217. package/docs/reference/enums/ControlEventType.adoc +28 -0
  218. package/docs/reference/enums/ControlKey.adoc +34 -0
  219. package/docs/reference/enums/FontAlignment.adoc +43 -0
  220. package/docs/reference/enums/FontSize.adoc +31 -0
  221. package/docs/reference/enums/Sound.adoc +42 -0
  222. package/docs/reference/enums/StateProperty.adoc +33 -0
  223. package/docs/reference/helpers/CellHelper.adoc +37 -0
  224. package/docs/reference/helpers/ControlInputHandlerHelper.adoc +57 -0
  225. package/docs/reference/helpers/CoordinateHelper.adoc +118 -0
  226. package/docs/reference/helpers/RelativeValuesHelper.adoc +53 -0
  227. package/docs/reference/interfaces/Debuggable.adoc +29 -0
  228. package/docs/reference/interfaces/GameModules.adoc +35 -0
  229. package/docs/reference/interfaces/Initializable.adoc +24 -0
  230. package/docs/reference/interfaces/RendererInitializable.adoc +33 -0
  231. package/docs/reference/interfaces/StateSyncable.adoc +41 -0
  232. package/docs/reference/interfaces/modules/Control.adoc +98 -0
  233. package/docs/reference/interfaces/modules/Grid.adoc +411 -0
  234. package/docs/reference/interfaces/modules/Renderer.adoc +34 -0
  235. package/docs/reference/interfaces/modules/RendererComposite.adoc +57 -0
  236. package/docs/reference/interfaces/modules/Score.adoc +107 -0
  237. package/docs/reference/interfaces/modules/Session.adoc +66 -0
  238. package/docs/reference/interfaces/modules/State.adoc +290 -0
  239. package/docs/reference/interfaces/modules/Text.adoc +110 -0
  240. package/docs/reference/interfaces/modules/Time.adoc +119 -0
  241. package/docs/reference/modules/Debugger.adoc +71 -0
  242. package/docs/reference/modules/DisplayRenderer.adoc +55 -0
  243. package/docs/reference/modules/Game.adoc +256 -0
  244. package/docs/reference/modules/GameControl.adoc +139 -0
  245. package/docs/reference/modules/GameGrid.adoc +794 -0
  246. package/docs/reference/modules/GameHudGrid.adoc +38 -0
  247. package/docs/reference/modules/GameMenu.adoc +39 -0
  248. package/docs/reference/modules/GameRenderer.adoc +79 -0
  249. package/docs/reference/modules/GameScore.adoc +138 -0
  250. package/docs/reference/modules/GameSession.adoc +43 -0
  251. package/docs/reference/modules/GameSound.adoc +111 -0
  252. package/docs/reference/modules/GameState.adoc +318 -0
  253. package/docs/reference/modules/GameText.adoc +139 -0
  254. package/docs/reference/modules/GameTime.adoc +141 -0
  255. package/docs/reference/modules/HudRenderer.adoc +56 -0
  256. package/docs/reference/modules/InitialStateSnapshot.adoc +47 -0
  257. package/docs/reference/modules/SessionModal.adoc +34 -0
  258. package/docs/reference/types/Axis.adoc +28 -0
  259. package/docs/reference/types/Cell.adoc +29 -0
  260. package/docs/reference/types/ControlCallback.adoc +23 -0
  261. package/docs/reference/types/Coordinate.adoc +29 -0
  262. package/docs/reference/types/GameEntry.adoc +29 -0
  263. package/docs/reference/types/GameEvent.adoc +29 -0
  264. package/docs/reference/types/Piece.adoc +32 -0
  265. package/docs/reference/types/RendererMetrics.adoc +29 -0
  266. package/docs/reference/types/Vector.adoc +28 -0
  267. package/docs/testing_best_practices.adoc +190 -0
  268. package/eslint.config.mjs +29 -0
  269. package/package.json +54 -0
  270. package/public/CNAME +1 -0
  271. package/public/docs/GAME_DEVELOPER_GUIDE.html +727 -0
  272. package/public/docs/brick-engine-guide.html +610 -0
  273. package/public/docs/diagrams/lifecycle.mmd +19 -0
  274. package/public/docs/documentation_style_guide.html +994 -0
  275. package/public/docs/getting-started.html +648 -0
  276. package/public/docs/images/lifecycle.svg +1 -0
  277. package/public/docs/index.html +593 -0
  278. package/public/docs/jsdoc_standard.html +656 -0
  279. package/public/docs/publishing.html +573 -0
  280. package/public/docs/reference/enums/Color.html +533 -0
  281. package/public/docs/reference/enums/ControlEventType.html +505 -0
  282. package/public/docs/reference/enums/ControlKey.html +529 -0
  283. package/public/docs/reference/enums/FontAlignment.html +545 -0
  284. package/public/docs/reference/enums/FontSize.html +517 -0
  285. package/public/docs/reference/enums/Sound.html +558 -0
  286. package/public/docs/reference/enums/StateProperty.html +525 -0
  287. package/public/docs/reference/helpers/CellHelper.html +520 -0
  288. package/public/docs/reference/helpers/ControlInputHandlerHelper.html +569 -0
  289. package/public/docs/reference/helpers/CoordinateHelper.html +703 -0
  290. package/public/docs/reference/helpers/RelativeValuesHelper.html +560 -0
  291. package/public/docs/reference/interfaces/Debuggable.html +501 -0
  292. package/public/docs/reference/interfaces/GameModules.html +544 -0
  293. package/public/docs/reference/interfaces/Initializable.html +495 -0
  294. package/public/docs/reference/interfaces/RendererInitializable.html +517 -0
  295. package/public/docs/reference/interfaces/StateSyncable.html +542 -0
  296. package/public/docs/reference/interfaces/modules/Control.html +648 -0
  297. package/public/docs/reference/interfaces/modules/Grid.html +1256 -0
  298. package/public/docs/reference/interfaces/modules/Renderer.html +522 -0
  299. package/public/docs/reference/interfaces/modules/RendererComposite.html +577 -0
  300. package/public/docs/reference/interfaces/modules/Score.html +669 -0
  301. package/public/docs/reference/interfaces/modules/Session.html +585 -0
  302. package/public/docs/reference/interfaces/modules/State.html +897 -0
  303. package/public/docs/reference/interfaces/modules/Text.html +668 -0
  304. package/public/docs/reference/interfaces/modules/Time.html +684 -0
  305. package/public/docs/reference/modules/Debugger.html +579 -0
  306. package/public/docs/reference/modules/DisplayRenderer.html +557 -0
  307. package/public/docs/reference/modules/Game.html +909 -0
  308. package/public/docs/reference/modules/GameControl.html +716 -0
  309. package/public/docs/reference/modules/GameGrid.html +1910 -0
  310. package/public/docs/reference/modules/GameHudGrid.html +508 -0
  311. package/public/docs/reference/modules/GameMenu.html +538 -0
  312. package/public/docs/reference/modules/GameRenderer.html +589 -0
  313. package/public/docs/reference/modules/GameScore.html +664 -0
  314. package/public/docs/reference/modules/GameSession.html +533 -0
  315. package/public/docs/reference/modules/GameSound.html +636 -0
  316. package/public/docs/reference/modules/GameState.html +922 -0
  317. package/public/docs/reference/modules/GameText.html +701 -0
  318. package/public/docs/reference/modules/GameTime.html +696 -0
  319. package/public/docs/reference/modules/HudRenderer.html +568 -0
  320. package/public/docs/reference/modules/InitialStateSnapshot.html +557 -0
  321. package/public/docs/reference/modules/SessionModal.html +520 -0
  322. package/public/docs/reference/types/Axis.html +505 -0
  323. package/public/docs/reference/types/Cell.html +514 -0
  324. package/public/docs/reference/types/ControlCallback.html +488 -0
  325. package/public/docs/reference/types/Coordinate.html +510 -0
  326. package/public/docs/reference/types/GameEntry.html +514 -0
  327. package/public/docs/reference/types/GameEvent.html +514 -0
  328. package/public/docs/reference/types/Piece.html +506 -0
  329. package/public/docs/reference/types/RendererMetrics.html +514 -0
  330. package/public/docs/reference/types/Vector.html +509 -0
  331. package/public/docs/testing_best_practices.html +770 -0
  332. package/public/favicon.ico +0 -0
  333. package/public/fonts/digital-7.monoitalic.ttf +0 -0
  334. package/public/images/cell.svg +32 -0
  335. package/public/images/close.png +0 -0
  336. package/public/images/games.png +0 -0
  337. package/public/images/github.png +0 -0
  338. package/public/images/letter-a.png +0 -0
  339. package/public/images/letter-d.png +0 -0
  340. package/public/images/letter-j.png +0 -0
  341. package/public/images/letter-s.png +0 -0
  342. package/public/images/letter-w.png +0 -0
  343. package/public/images/meta-image.png +0 -0
  344. package/public/images/number-1.png +0 -0
  345. package/public/images/number-2.png +0 -0
  346. package/public/images/number-3.png +0 -0
  347. package/public/images/number-4.png +0 -0
  348. package/public/images/number-5.png +0 -0
  349. package/public/images/number-6.png +0 -0
  350. package/public/images/splash.gif +0 -0
  351. package/public/index.html +15 -0
  352. package/public/sounds/sound_00.wav +0 -0
  353. package/public/sounds/sound_01.wav +0 -0
  354. package/public/sounds/sound_02.wav +0 -0
  355. package/public/sounds/sound_03.wav +0 -0
  356. package/public/sounds/sound_04.wav +0 -0
  357. package/public/sounds/sound_05.wav +0 -0
  358. package/public/sounds/sound_06.wav +0 -0
  359. package/public/sounds/sound_07.wav +0 -0
  360. package/public/sounds/sound_08.wav +0 -0
  361. package/public/sounds/sound_09.wav +0 -0
  362. package/public/sounds/sound_10.wav +0 -0
  363. package/public/sounds/sound_11.wav +0 -0
  364. package/public/sounds/sound_12.wav +0 -0
  365. package/public/sounds/sound_13.wav +0 -0
  366. package/public/sounds/sound_14.wav +0 -0
  367. package/public/sounds/sound_15.wav +0 -0
  368. package/public/style/body.css +86 -0
  369. package/public/style/buttons.css +233 -0
  370. package/public/style/debugger.css +117 -0
  371. package/public/style/sessionModal.css +155 -0
  372. package/public/style/sourceCodeAndCommands.css +74 -0
  373. package/public/style/splash.css +13 -0
  374. package/public/style/theme.css +137 -0
  375. package/scripts/generate-diagrams.sh +20 -0
  376. package/scripts/generate-docs.js +111 -0
  377. package/src/client-game.d.ts +1 -0
  378. package/src/config/configs.test.ts +20 -0
  379. package/src/config/configs.ts +197 -0
  380. package/src/config/env.test.ts +59 -0
  381. package/src/config/env.ts +7 -0
  382. package/src/config/styles.ts +5 -0
  383. package/src/core/Game.test.ts +167 -0
  384. package/src/core/Game.ts +307 -0
  385. package/src/core/InitialStateSnapshot.test.ts +51 -0
  386. package/src/core/InitialStateSnapshot.ts +46 -0
  387. package/src/core/helpers/CellHelper.test.ts +33 -0
  388. package/src/core/helpers/CellHelper.ts +21 -0
  389. package/src/core/helpers/ControlInputHandlerHelper.test.ts +116 -0
  390. package/src/core/helpers/ControlInputHandlerHelper.ts +68 -0
  391. package/src/core/helpers/CoordinateHelper.test.ts +113 -0
  392. package/src/core/helpers/CoordinateHelper.ts +82 -0
  393. package/src/core/helpers/InterfaceIdentifierHelper.test.ts +122 -0
  394. package/src/core/helpers/InterfaceIdentifierHelper.ts +43 -0
  395. package/src/core/helpers/RelativeValuesHelper.test.ts +47 -0
  396. package/src/core/helpers/RelativeValuesHelper.ts +29 -0
  397. package/src/core/module/control/GameControl.test.ts +82 -0
  398. package/src/core/module/control/GameControl.ts +142 -0
  399. package/src/core/module/control/GameControlKeyBinding.test.ts +59 -0
  400. package/src/core/module/control/GameControlKeyBinding.ts +92 -0
  401. package/src/core/module/grid/GameGrid.test.ts +83 -0
  402. package/src/core/module/grid/GameGrid.ts +610 -0
  403. package/src/core/module/grid/GameHudGrid.test.ts +22 -0
  404. package/src/core/module/grid/GameHudGrid.ts +40 -0
  405. package/src/core/module/grid/engines/GridAnalysisEngine.test.ts +157 -0
  406. package/src/core/module/grid/engines/GridAnalysisEngine.ts +124 -0
  407. package/src/core/module/grid/engines/GridLineEngine.test.ts +132 -0
  408. package/src/core/module/grid/engines/GridLineEngine.ts +165 -0
  409. package/src/core/module/grid/engines/GridMovementEngine.test.ts +125 -0
  410. package/src/core/module/grid/engines/GridMovementEngine.ts +113 -0
  411. package/src/core/module/grid/engines/GridRegionEngine.test.ts +136 -0
  412. package/src/core/module/grid/engines/GridRegionEngine.ts +52 -0
  413. package/src/core/module/grid/engines/GridTransformEngine.test.ts +98 -0
  414. package/src/core/module/grid/engines/GridTransformEngine.ts +70 -0
  415. package/src/core/module/renderer/DisplayRenderer.test.ts +86 -0
  416. package/src/core/module/renderer/DisplayRenderer.ts +152 -0
  417. package/src/core/module/renderer/GameRenderer.test.ts +103 -0
  418. package/src/core/module/renderer/GameRenderer.ts +144 -0
  419. package/src/core/module/renderer/HudRenderer.test.ts +108 -0
  420. package/src/core/module/renderer/HudRenderer.ts +203 -0
  421. package/src/core/module/score/GameScore.test.ts +71 -0
  422. package/src/core/module/score/GameScore.ts +188 -0
  423. package/src/core/module/session/GameSession.test.ts +176 -0
  424. package/src/core/module/session/GameSession.ts +103 -0
  425. package/src/core/module/sound/GameSound.test.ts +117 -0
  426. package/src/core/module/sound/GameSound.ts +229 -0
  427. package/src/core/module/state/GameState.test.ts +101 -0
  428. package/src/core/module/state/GameState.ts +339 -0
  429. package/src/core/module/text/GameText.test.ts +87 -0
  430. package/src/core/module/text/GameText.ts +150 -0
  431. package/src/core/module/time/GameTime.test.ts +86 -0
  432. package/src/core/module/time/GameTime.ts +144 -0
  433. package/src/core/types/Interfaces.ts +59 -0
  434. package/src/core/types/Types.ts +124 -0
  435. package/src/core/types/enums.ts +113 -0
  436. package/src/core/types/modules.ts +841 -0
  437. package/src/index.test.ts +15 -0
  438. package/src/index.ts +9 -0
  439. package/src/main.test.ts +137 -0
  440. package/src/main.ts +77 -0
  441. package/src/menu/GameMenu.test.ts +157 -0
  442. package/src/menu/GameMenu.ts +124 -0
  443. package/src/menu/GameMenuSingleton.test.ts +26 -0
  444. package/src/menu/GameMenuSingleton.ts +13 -0
  445. package/src/menu/GameRepository.test.ts +46 -0
  446. package/src/menu/GameRepository.ts +47 -0
  447. package/src/menu/manager/GameManager.test.ts +68 -0
  448. package/src/menu/manager/GameManager.ts +50 -0
  449. package/src/types/global.d.ts +8 -0
  450. package/src/types/interfaces.ts +5 -0
  451. package/src/view/Debugger.test.ts +152 -0
  452. package/src/view/Debugger.ts +124 -0
  453. package/src/view/GameView.test.ts +95 -0
  454. package/src/view/GameView.ts +244 -0
  455. package/src/view/SessionModal.test.ts +141 -0
  456. package/src/view/SessionModal.ts +73 -0
  457. package/src/view/components/layout/ButtonLayout.test.ts +28 -0
  458. package/src/view/components/layout/ButtonLayout.ts +63 -0
  459. package/src/view/components/layout/ContainerLayout.test.ts +48 -0
  460. package/src/view/components/layout/ContainerLayout.ts +50 -0
  461. package/src/view/components/layout/FrameLayout.test.ts +24 -0
  462. package/src/view/components/layout/FrameLayout.ts +25 -0
  463. package/src/view/components/ui/BigButton.test.ts +28 -0
  464. package/src/view/components/ui/BigButton.ts +31 -0
  465. package/src/view/components/ui/Button.test.ts +30 -0
  466. package/src/view/components/ui/Button.ts +30 -0
  467. package/src/view/components/ui/Canvas.test.ts +32 -0
  468. package/src/view/components/ui/Canvas.ts +34 -0
  469. package/src/view/components/ui/SmallButton.test.ts +48 -0
  470. package/src/view/components/ui/SmallButton.ts +32 -0
  471. package/src/view/theme/applyColors.test.ts +47 -0
  472. package/src/view/theme/applyColors.ts +38 -0
  473. package/src/view/theme/dimensions.test.ts +34 -0
  474. package/src/view/theme/dimensions.ts +53 -0
  475. package/tsconfig.json +16 -0
  476. package/vitest.config.ts +14 -0
  477. package/webpack.config.js +133 -0
@@ -0,0 +1,770 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <meta name="generator" content="Asciidoctor 2.0.20">
8
+ <title>Testing Best Practices with Vitest</title>
9
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
10
+ <style>
11
+ /*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
12
+ /* Uncomment the following line when using as a custom stylesheet */
13
+ /* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
14
+ html{font-family:sans-serif;-webkit-text-size-adjust:100%}
15
+ a{background:none}
16
+ a:focus{outline:thin dotted}
17
+ a:active,a:hover{outline:0}
18
+ h1{font-size:2em;margin:.67em 0}
19
+ b,strong{font-weight:bold}
20
+ abbr{font-size:.9em}
21
+ abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
22
+ dfn{font-style:italic}
23
+ hr{height:0}
24
+ mark{background:#ff0;color:#000}
25
+ code,kbd,pre,samp{font-family:monospace;font-size:1em}
26
+ pre{white-space:pre-wrap}
27
+ q{quotes:"\201C" "\201D" "\2018" "\2019"}
28
+ small{font-size:80%}
29
+ sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
30
+ sup{top:-.5em}
31
+ sub{bottom:-.25em}
32
+ img{border:0}
33
+ svg:not(:root){overflow:hidden}
34
+ figure{margin:0}
35
+ audio,video{display:inline-block}
36
+ audio:not([controls]){display:none;height:0}
37
+ fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
38
+ legend{border:0;padding:0}
39
+ button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
40
+ button,input{line-height:normal}
41
+ button,select{text-transform:none}
42
+ button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
43
+ button[disabled],html input[disabled]{cursor:default}
44
+ input[type=checkbox],input[type=radio]{padding:0}
45
+ button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
46
+ textarea{overflow:auto;vertical-align:top}
47
+ table{border-collapse:collapse;border-spacing:0}
48
+ *,::before,::after{box-sizing:border-box}
49
+ html,body{font-size:100%}
50
+ body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
51
+ a:hover{cursor:pointer}
52
+ img,object,embed{max-width:100%;height:auto}
53
+ object,embed{height:100%}
54
+ img{-ms-interpolation-mode:bicubic}
55
+ .left{float:left!important}
56
+ .right{float:right!important}
57
+ .text-left{text-align:left!important}
58
+ .text-right{text-align:right!important}
59
+ .text-center{text-align:center!important}
60
+ .text-justify{text-align:justify!important}
61
+ .hide{display:none}
62
+ img,object,svg{display:inline-block;vertical-align:middle}
63
+ textarea{height:auto;min-height:50px}
64
+ select{width:100%}
65
+ .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
66
+ div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
67
+ a{color:#2156a5;text-decoration:underline;line-height:inherit}
68
+ a:hover,a:focus{color:#1d4b8f}
69
+ a img{border:0}
70
+ p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
71
+ p aside{font-size:.875em;line-height:1.35;font-style:italic}
72
+ h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
73
+ h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
74
+ h1{font-size:2.125em}
75
+ h2{font-size:1.6875em}
76
+ h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
77
+ h4,h5{font-size:1.125em}
78
+ h6{font-size:1em}
79
+ hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
80
+ em,i{font-style:italic;line-height:inherit}
81
+ strong,b{font-weight:bold;line-height:inherit}
82
+ small{font-size:60%;line-height:inherit}
83
+ code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
84
+ ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
85
+ ul,ol{margin-left:1.5em}
86
+ ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
87
+ ul.circle{list-style-type:circle}
88
+ ul.disc{list-style-type:disc}
89
+ ul.square{list-style-type:square}
90
+ ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}
91
+ ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
92
+ dl dt{margin-bottom:.3125em;font-weight:bold}
93
+ dl dd{margin-bottom:1.25em}
94
+ blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
95
+ blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
96
+ @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
97
+ h1{font-size:2.75em}
98
+ h2{font-size:2.3125em}
99
+ h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
100
+ h4{font-size:1.4375em}}
101
+ table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
102
+ table thead,table tfoot{background:#f7f8f7}
103
+ table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
104
+ table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
105
+ table tr.even,table tr.alt{background:#f8f8f7}
106
+ table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
107
+ h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
108
+ h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
109
+ .center{margin-left:auto;margin-right:auto}
110
+ .stretch{width:100%}
111
+ .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
112
+ .clearfix::after,.float-group::after{clear:both}
113
+ :not(pre).nobreak{word-wrap:normal}
114
+ :not(pre).nowrap{white-space:nowrap}
115
+ :not(pre).pre-wrap{white-space:pre-wrap}
116
+ :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
117
+ pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
118
+ pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
119
+ pre>code{display:block}
120
+ pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
121
+ em em{font-style:normal}
122
+ strong strong{font-weight:400}
123
+ .keyseq{color:rgba(51,51,51,.8)}
124
+ kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
125
+ .keyseq kbd:first-child{margin-left:0}
126
+ .keyseq kbd:last-child{margin-right:0}
127
+ .menuseq,.menuref{color:#000}
128
+ .menuseq b:not(.caret),.menuref{font-weight:inherit}
129
+ .menuseq{word-spacing:-.02em}
130
+ .menuseq b.caret{font-size:1.25em;line-height:.8}
131
+ .menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
132
+ b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
133
+ b.button::before{content:"[";padding:0 3px 0 2px}
134
+ b.button::after{content:"]";padding:0 2px 0 3px}
135
+ p a>code:hover{color:rgba(0,0,0,.9)}
136
+ #header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
137
+ #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
138
+ #header::after,#content::after,#footnotes::after,#footer::after{clear:both}
139
+ #content{margin-top:1.25em}
140
+ #content::before{content:none}
141
+ #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
142
+ #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
143
+ #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
144
+ #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
145
+ #header .details span:first-child{margin-left:-.125em}
146
+ #header .details span.email a{color:rgba(0,0,0,.85)}
147
+ #header .details br{display:none}
148
+ #header .details br+span::before{content:"\00a0\2013\00a0"}
149
+ #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
150
+ #header .details br+span#revremark::before{content:"\00a0|\00a0"}
151
+ #header #revnumber{text-transform:capitalize}
152
+ #header #revnumber::after{content:"\00a0"}
153
+ #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
154
+ #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
155
+ #toc>ul{margin-left:.125em}
156
+ #toc ul.sectlevel0>li>a{font-style:italic}
157
+ #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
158
+ #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
159
+ #toc li{line-height:1.3334;margin-top:.3334em}
160
+ #toc a{text-decoration:none}
161
+ #toc a:active{text-decoration:underline}
162
+ #toctitle{color:#7a2518;font-size:1.2em}
163
+ @media screen and (min-width:768px){#toctitle{font-size:1.375em}
164
+ body.toc2{padding-left:15em;padding-right:0}
165
+ #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
166
+ #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
167
+ #toc.toc2>ul{font-size:.9em;margin-bottom:0}
168
+ #toc.toc2 ul ul{margin-left:0;padding-left:1em}
169
+ #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
170
+ body.toc2.toc-right{padding-left:0;padding-right:15em}
171
+ body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
172
+ @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
173
+ #toc.toc2{width:20em}
174
+ #toc.toc2 #toctitle{font-size:1.375em}
175
+ #toc.toc2>ul{font-size:.95em}
176
+ #toc.toc2 ul ul{padding-left:1.25em}
177
+ body.toc2.toc-right{padding-left:0;padding-right:20em}}
178
+ #content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
179
+ #content #toc>:first-child{margin-top:0}
180
+ #content #toc>:last-child{margin-bottom:0}
181
+ #footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
182
+ #footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
183
+ #content{margin-bottom:.625em}
184
+ .sect1{padding-bottom:.625em}
185
+ @media screen and (min-width:768px){#content{margin-bottom:1.25em}
186
+ .sect1{padding-bottom:1.25em}}
187
+ .sect1:last-child{padding-bottom:0}
188
+ .sect1+.sect1{border-top:1px solid #e7e7e9}
189
+ #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
190
+ #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
191
+ #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
192
+ #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
193
+ #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
194
+ details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
195
+ details{margin-left:1.25rem}
196
+ details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
197
+ details>summary::-webkit-details-marker{display:none}
198
+ details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
199
+ details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
200
+ details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
201
+ .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
202
+ table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
203
+ .paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
204
+ .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
205
+ .admonitionblock>table td.icon{text-align:center;width:80px}
206
+ .admonitionblock>table td.icon img{max-width:none}
207
+ .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
208
+ .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
209
+ .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
210
+ .exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
211
+ .sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
212
+ .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
213
+ .exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0}
214
+ .exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
215
+ .literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
216
+ @media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
217
+ @media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
218
+ .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
219
+ .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
220
+ .listingblock>.content{position:relative}
221
+ .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
222
+ .listingblock:hover code[data-lang]::before{display:block}
223
+ .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
224
+ .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
225
+ .listingblock pre.highlightjs{padding:0}
226
+ .listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
227
+ .listingblock pre.prettyprint{border-width:0}
228
+ .prettyprint{background:#f7f7f8}
229
+ pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
230
+ pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
231
+ pre.prettyprint li code[data-lang]::before{opacity:1}
232
+ pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
233
+ table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
234
+ table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
235
+ table.linenotable td.code{padding-left:.75em}
236
+ table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
237
+ pre.pygments span.linenos{display:inline-block;margin-right:.75em}
238
+ .quoteblock{margin:0 1em 1.25em 1.5em;display:table}
239
+ .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
240
+ .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
241
+ .quoteblock blockquote{margin:0;padding:0;border:0}
242
+ .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
243
+ .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
244
+ .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
245
+ .verseblock{margin:0 1em 1.25em}
246
+ .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
247
+ .verseblock pre strong{font-weight:400}
248
+ .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
249
+ .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
250
+ .quoteblock .attribution br,.verseblock .attribution br{display:none}
251
+ .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
252
+ .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
253
+ .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
254
+ .quoteblock.abstract{margin:0 1em 1.25em;display:block}
255
+ .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
256
+ .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
257
+ .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
258
+ .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
259
+ .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
260
+ p.tableblock:last-child{margin-bottom:0}
261
+ td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
262
+ td.tableblock>.content>:last-child{margin-bottom:-1.25em}
263
+ table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
264
+ table.grid-all>*>tr>*{border-width:1px}
265
+ table.grid-cols>*>tr>*{border-width:0 1px}
266
+ table.grid-rows>*>tr>*{border-width:1px 0}
267
+ table.frame-all{border-width:1px}
268
+ table.frame-ends{border-width:1px 0}
269
+ table.frame-sides{border-width:0 1px}
270
+ table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
271
+ table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
272
+ table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
273
+ table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
274
+ table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
275
+ th.halign-left,td.halign-left{text-align:left}
276
+ th.halign-right,td.halign-right{text-align:right}
277
+ th.halign-center,td.halign-center{text-align:center}
278
+ th.valign-top,td.valign-top{vertical-align:top}
279
+ th.valign-bottom,td.valign-bottom{vertical-align:bottom}
280
+ th.valign-middle,td.valign-middle{vertical-align:middle}
281
+ table thead th,table tfoot th{font-weight:bold}
282
+ tbody tr th{background:#f7f8f7}
283
+ tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
284
+ p.tableblock>code:only-child{background:none;padding:0}
285
+ p.tableblock{font-size:1em}
286
+ ol{margin-left:1.75em}
287
+ ul li ol{margin-left:1.5em}
288
+ dl dd{margin-left:1.125em}
289
+ dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
290
+ li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
291
+ ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
292
+ ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
293
+ ul.unstyled,ol.unstyled{margin-left:0}
294
+ li>p:empty:only-child::before{content:"";display:inline-block}
295
+ ul.checklist>li>p:first-child{margin-left:-1em}
296
+ ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
297
+ ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
298
+ ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
299
+ ul.inline>li{margin-left:1.25em}
300
+ .unstyled dl dt{font-weight:400;font-style:normal}
301
+ ol.arabic{list-style-type:decimal}
302
+ ol.decimal{list-style-type:decimal-leading-zero}
303
+ ol.loweralpha{list-style-type:lower-alpha}
304
+ ol.upperalpha{list-style-type:upper-alpha}
305
+ ol.lowerroman{list-style-type:lower-roman}
306
+ ol.upperroman{list-style-type:upper-roman}
307
+ ol.lowergreek{list-style-type:lower-greek}
308
+ .hdlist>table,.colist>table{border:0;background:none}
309
+ .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
310
+ td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
311
+ td.hdlist1{font-weight:bold;padding-bottom:1.25em}
312
+ td.hdlist2{word-wrap:anywhere}
313
+ .literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
314
+ .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
315
+ .colist td:not([class]):first-child img{max-width:none}
316
+ .colist td:not([class]):last-child{padding:.25em 0}
317
+ .thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
318
+ .imageblock.left{margin:.25em .625em 1.25em 0}
319
+ .imageblock.right{margin:.25em 0 1.25em .625em}
320
+ .imageblock>.title{margin-bottom:0}
321
+ .imageblock.thumb,.imageblock.th{border-width:6px}
322
+ .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
323
+ .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
324
+ .image.left{margin-right:.625em}
325
+ .image.right{margin-left:.625em}
326
+ a.image{text-decoration:none;display:inline-block}
327
+ a.image object{pointer-events:none}
328
+ sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
329
+ sup.footnote a,sup.footnoteref a{text-decoration:none}
330
+ sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
331
+ #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
332
+ #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
333
+ #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
334
+ #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
335
+ #footnotes .footnote:last-of-type{margin-bottom:0}
336
+ #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
337
+ div.unbreakable{page-break-inside:avoid}
338
+ .big{font-size:larger}
339
+ .small{font-size:smaller}
340
+ .underline{text-decoration:underline}
341
+ .overline{text-decoration:overline}
342
+ .line-through{text-decoration:line-through}
343
+ .aqua{color:#00bfbf}
344
+ .aqua-background{background:#00fafa}
345
+ .black{color:#000}
346
+ .black-background{background:#000}
347
+ .blue{color:#0000bf}
348
+ .blue-background{background:#0000fa}
349
+ .fuchsia{color:#bf00bf}
350
+ .fuchsia-background{background:#fa00fa}
351
+ .gray{color:#606060}
352
+ .gray-background{background:#7d7d7d}
353
+ .green{color:#006000}
354
+ .green-background{background:#007d00}
355
+ .lime{color:#00bf00}
356
+ .lime-background{background:#00fa00}
357
+ .maroon{color:#600000}
358
+ .maroon-background{background:#7d0000}
359
+ .navy{color:#000060}
360
+ .navy-background{background:#00007d}
361
+ .olive{color:#606000}
362
+ .olive-background{background:#7d7d00}
363
+ .purple{color:#600060}
364
+ .purple-background{background:#7d007d}
365
+ .red{color:#bf0000}
366
+ .red-background{background:#fa0000}
367
+ .silver{color:#909090}
368
+ .silver-background{background:#bcbcbc}
369
+ .teal{color:#006060}
370
+ .teal-background{background:#007d7d}
371
+ .white{color:#bfbfbf}
372
+ .white-background{background:#fafafa}
373
+ .yellow{color:#bfbf00}
374
+ .yellow-background{background:#fafa00}
375
+ span.icon>.fa{cursor:default}
376
+ a span.icon>.fa{cursor:inherit}
377
+ .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
378
+ .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
379
+ .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
380
+ .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
381
+ .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
382
+ .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
383
+ .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
384
+ .conum[data-value] *{color:#fff!important}
385
+ .conum[data-value]+b{display:none}
386
+ .conum[data-value]::after{content:attr(data-value)}
387
+ pre .conum[data-value]{position:relative;top:-.125em}
388
+ b.conum *{color:inherit!important}
389
+ .conum:not([data-value]):empty{display:none}
390
+ dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
391
+ h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
392
+ p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
393
+ p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem}
394
+ p{margin-bottom:1.25rem}
395
+ .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
396
+ .exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
397
+ .print-only{display:none!important}
398
+ @page{margin:1.25cm .75cm}
399
+ @media print{*{box-shadow:none!important;text-shadow:none!important}
400
+ html{font-size:80%}
401
+ a{color:inherit!important;text-decoration:underline!important}
402
+ a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
403
+ a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
404
+ abbr[title]{border-bottom:1px dotted}
405
+ abbr[title]::after{content:" (" attr(title) ")"}
406
+ pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
407
+ thead{display:table-header-group}
408
+ svg{max-width:100%}
409
+ p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
410
+ h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
411
+ #header,#content,#footnotes,#footer{max-width:none}
412
+ #toc,.sidebarblock,.exampleblock>.content{background:none!important}
413
+ #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
414
+ body.book #header{text-align:center}
415
+ body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
416
+ body.book #header .details{border:0!important;display:block;padding:0!important}
417
+ body.book #header .details span:first-child{margin-left:0!important}
418
+ body.book #header .details br{display:block}
419
+ body.book #header .details br+span::before{content:none!important}
420
+ body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
421
+ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
422
+ .listingblock code[data-lang]::before{display:block}
423
+ #footer{padding:0 .9375em}
424
+ .hide-on-print{display:none!important}
425
+ .print-only{display:block!important}
426
+ .hide-for-print{display:none!important}
427
+ .show-for-print{display:inherit!important}}
428
+ @media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
429
+ .sect1{padding:0!important}
430
+ .sect1+.sect1{border:0}
431
+ #footer{background:none}
432
+ #footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
433
+ @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
434
+ </style>
435
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
436
+ </head>
437
+ <body class="article toc2 toc-left">
438
+ <div id="header">
439
+ <h1>Testing Best Practices with Vitest</h1>
440
+ <div id="toc" class="toc2">
441
+ <div id="toctitle">Table of Contents</div>
442
+ <ul class="sectlevel1">
443
+ <li><a href="#_core_pattern_triple_a_aaa">Core Pattern: Triple A (AAA)</a>
444
+ <ul class="sectlevel2">
445
+ <li><a href="#_arrange">[ARRANGE]</a></li>
446
+ <li><a href="#_act">[ACT]</a></li>
447
+ <li><a href="#_assert">[ASSERT]</a></li>
448
+ </ul>
449
+ </li>
450
+ <li><a href="#_naming_conventions">Naming Conventions</a></li>
451
+ <li><a href="#_ai_assisted_testing_best_practices">AI-Assisted Testing Best Practices</a></li>
452
+ <li><a href="#_vitest_configuration_standard">Vitest Configuration Standard</a></li>
453
+ <li><a href="#_advanced_mocking_stubs">Advanced Mocking &amp; Stubs</a>
454
+ <ul class="sectlevel2">
455
+ <li><a href="#_mocking_browser_apis">Mocking Browser APIs</a></li>
456
+ <li><a href="#_constructible_mocks">Constructible Mocks</a></li>
457
+ <li><a href="#_hoisted_variables">Hoisted Variables</a></li>
458
+ </ul>
459
+ </li>
460
+ <li><a href="#_testing_entry_points_main_ts">Testing Entry Points (main.ts)</a>
461
+ <ul class="sectlevel2">
462
+ <li><a href="#_workaround_for_dynamic_imports_with_webpackts_ts1323">Workaround for Dynamic Imports with Webpack/TS (TS1323)</a></li>
463
+ </ul>
464
+ </li>
465
+ <li><a href="#_eslint_type_safety_in_tests">ESLint &amp; Type Safety in Tests</a></li>
466
+ <li><a href="#_example_testing_a_grid_engine">Example: Testing a Grid Engine</a></li>
467
+ </ul>
468
+ </div>
469
+ </div>
470
+ <div id="content">
471
+ <div id="preamble">
472
+ <div class="sectionbody">
473
+ <div class="paragraph">
474
+ <p>This document defines the standards and best practices for unit testing in the Brick Engine project using <strong>Vitest</strong>. It is designed to be easily parsed by both developers and AI assistants.</p>
475
+ </div>
476
+ </div>
477
+ </div>
478
+ <div class="sect1">
479
+ <h2 id="_core_pattern_triple_a_aaa">Core Pattern: Triple A (AAA)</h2>
480
+ <div class="sectionbody">
481
+ <div class="paragraph">
482
+ <p>All tests must follow the <strong>Arrange, Act, Assert</strong> pattern. Use explicit comments to demarcate these phases, as this helps AI models understand the test logic context.</p>
483
+ </div>
484
+ <div class="sect2">
485
+ <h3 id="_arrange">[ARRANGE]</h3>
486
+ <div class="paragraph">
487
+ <p>Set up the test environment, prepare data, and initialize the object under test.</p>
488
+ </div>
489
+ <div class="listingblock">
490
+ <div class="content">
491
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">// [ARRANGE]
492
+ const grid = new GameGrid();
493
+ const coordinate = { x: 5, y: 5 };</code></pre>
494
+ </div>
495
+ </div>
496
+ </div>
497
+ <div class="sect2">
498
+ <h3 id="_act">[ACT]</h3>
499
+ <div class="paragraph">
500
+ <p>Execute the specific method or behavior being tested. Limit this to a single action if possible.</p>
501
+ </div>
502
+ <div class="listingblock">
503
+ <div class="content">
504
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">// [ACT]
505
+ const result = grid.isValidCoordinate(coordinate);</code></pre>
506
+ </div>
507
+ </div>
508
+ </div>
509
+ <div class="sect2">
510
+ <h3 id="_assert">[ASSERT]</h3>
511
+ <div class="paragraph">
512
+ <p>Verify the outcome. Use descriptive expectations.</p>
513
+ </div>
514
+ <div class="listingblock">
515
+ <div class="content">
516
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">// [ASSERT]
517
+ expect(result).toBe(true);</code></pre>
518
+ </div>
519
+ </div>
520
+ </div>
521
+ </div>
522
+ </div>
523
+ <div class="sect1">
524
+ <h2 id="_naming_conventions">Naming Conventions</h2>
525
+ <div class="sectionbody">
526
+ <div class="paragraph">
527
+ <p>Test descriptions should follow the pattern: <code>should [expected result] when [scenario or action]</code>.</p>
528
+ </div>
529
+ <div class="ulist">
530
+ <ul>
531
+ <li>
532
+ <p><strong>Bad:</strong> <code>test grid validation</code></p>
533
+ </li>
534
+ <li>
535
+ <p><strong>Good:</strong> <code>should return true when coordinate is within grid boundaries</code></p>
536
+ </li>
537
+ </ul>
538
+ </div>
539
+ </div>
540
+ </div>
541
+ <div class="sect1">
542
+ <h2 id="_ai_assisted_testing_best_practices">AI-Assisted Testing Best Practices</h2>
543
+ <div class="sectionbody">
544
+ <div class="paragraph">
545
+ <p>To facilitate AI-driven test generation and debugging:</p>
546
+ </div>
547
+ <div class="olist arabic">
548
+ <ol class="arabic">
549
+ <li>
550
+ <p><strong>Be Explicit</strong>: Use the <code>// [ARRANGE]</code>, <code>// [ACT]</code>, and <code>// [ASSERT]</code> tags.</p>
551
+ </li>
552
+ <li>
553
+ <p><strong>Context Injection</strong>: When asking an AI to write a test, provide the interface of the module and dependencies.</p>
554
+ </li>
555
+ <li>
556
+ <p><strong>One Logic per Test</strong>: Avoid "Giant Tests". Test one specific behavior per <code>it</code> block.</p>
557
+ </li>
558
+ <li>
559
+ <p><strong>Mocking Constants</strong>: Always mock global configurations (like <code>configs</code>) to ensure tests are deterministic.</p>
560
+ </li>
561
+ </ol>
562
+ </div>
563
+ </div>
564
+ </div>
565
+ <div class="sect1">
566
+ <h2 id="_vitest_configuration_standard">Vitest Configuration Standard</h2>
567
+ <div class="sectionbody">
568
+ <div class="ulist">
569
+ <ul>
570
+ <li>
571
+ <p><strong>Globals</strong>: Use <code>globals: true</code> to avoid importing <code>describe</code>, <code>it</code>, <code>expect</code> in every file.</p>
572
+ </li>
573
+ <li>
574
+ <p><strong>Environment</strong>: Use <code>@vitest-environment jsdom</code> at the top of files that interact with DOM or p5.js.</p>
575
+ </li>
576
+ <li>
577
+ <p><strong>Coverage</strong>: Target at least 80% coverage for "Engines" and "Helpers".</p>
578
+ </li>
579
+ <li>
580
+ <p><strong>Aliases</strong>: If using bundler aliases (e.g., <code>@client-game</code>), define them in <code>vitest.config.ts</code> using <code>resolve.alias</code>.</p>
581
+ </li>
582
+ </ul>
583
+ </div>
584
+ </div>
585
+ </div>
586
+ <div class="sect1">
587
+ <h2 id="_advanced_mocking_stubs">Advanced Mocking &amp; Stubs</h2>
588
+ <div class="sectionbody">
589
+ <div class="sect2">
590
+ <h3 id="_mocking_browser_apis">Mocking Browser APIs</h3>
591
+ <div class="paragraph">
592
+ <p>For tests requiring browser features in JSDOM:</p>
593
+ </div>
594
+ <div class="listingblock">
595
+ <div class="content">
596
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">// [ARRANGE]
597
+ vi.stubGlobal('localStorage', {
598
+ getItem: vi.fn(),
599
+ setItem: vi.fn(),
600
+ });
601
+
602
+ vi.stubGlobal('AudioContext', vi.fn().mockImplementation(function() {
603
+ return {
604
+ createGain: vi.fn().mockReturnThis(),
605
+ destination: {},
606
+ };
607
+ }));</code></pre>
608
+ </div>
609
+ </div>
610
+ </div>
611
+ <div class="sect2">
612
+ <h3 id="_constructible_mocks">Constructible Mocks</h3>
613
+ <div class="paragraph">
614
+ <p>When mocking a class that will be instantiated with <code>new</code>, Vitest requires the mock to be a <code>function</code> or <code>class</code>:</p>
615
+ </div>
616
+ <div class="listingblock">
617
+ <div class="content">
618
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">vi.mock('./MyModule', () =&gt; ({
619
+ default: vi.fn().mockImplementation(function() {
620
+ return {
621
+ doSomething: vi.fn()
622
+ };
623
+ })
624
+ }));</code></pre>
625
+ </div>
626
+ </div>
627
+ </div>
628
+ <div class="sect2">
629
+ <h3 id="_hoisted_variables">Hoisted Variables</h3>
630
+ <div class="paragraph">
631
+ <p>If you need to share variables between your test and the <code>vi.mock</code> factory (which is hoisted), use <code>vi.hoisted</code>:</p>
632
+ </div>
633
+ <div class="listingblock">
634
+ <div class="content">
635
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">const { mockRef } = vi.hoisted(() =&gt; ({
636
+ mockRef: { id: 1 }
637
+ }));
638
+
639
+ vi.mock('./module', () =&gt; ({
640
+ default: () =&gt; mockRef
641
+ }));</code></pre>
642
+ </div>
643
+ </div>
644
+ </div>
645
+ </div>
646
+ </div>
647
+ <div class="sect1">
648
+ <h2 id="_testing_entry_points_main_ts">Testing Entry Points (main.ts)</h2>
649
+ <div class="sectionbody">
650
+ <div class="paragraph">
651
+ <p>Tests for entry points that execute code on import require isolation:</p>
652
+ </div>
653
+ <div class="olist arabic">
654
+ <ol class="arabic">
655
+ <li>
656
+ <p>Use <code>vi.resetModules()</code> in <code>beforeEach</code>.</p>
657
+ </li>
658
+ <li>
659
+ <p>Use dynamic <code>import()</code> within the <code>it</code> block.</p>
660
+ </li>
661
+ <li>
662
+ <p>Set environment flags (like <code>APP_MODE</code>) <strong>before</strong> the dynamic import.</p>
663
+ </li>
664
+ </ol>
665
+ </div>
666
+ <div class="listingblock">
667
+ <div class="content">
668
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">it('should init in client mode', async () =&gt; {
669
+ (isClientMode as vi.Mock).mockReturnValue(true);
670
+ await import('./main'); // Triggers execution
671
+ expect(p5).toHaveBeenCalled();
672
+ });</code></pre>
673
+ </div>
674
+ </div>
675
+ <div class="sect2">
676
+ <h3 id="_workaround_for_dynamic_imports_with_webpackts_ts1323">Workaround for Dynamic Imports with Webpack/TS (TS1323)</h3>
677
+ <div class="paragraph">
678
+ <p>When the project uses a <code>tsconfig.json</code> meant for the browser (e.g., configuring <code>module: commonjs</code>), running bundlers like <code>webpack</code> over the test files can trigger <strong>TS1323</strong> because the TS compiler doesn&#8217;t understand the dynamic inputs naturally.</p>
679
+ </div>
680
+ <div class="paragraph">
681
+ <p><strong>To resolve this properly without ANY <code>@ts-expect-error</code>:</strong>
682
+ 1. Set the <code>module</code> resolving option in <code>tsconfig.json</code> to <code>"ESNext"</code> or <code>"ES2020"</code> so TS allows dynamic imports. Webpack can still easily compile it targeting ES5.
683
+ 2. Create ambient definition files (e.g., <code>src/client-game.d.ts</code>) containing module declarations (<code>declare module '@client-game';</code>) to resolve TS2307 dynamically missing paths.</p>
684
+ </div>
685
+ <div class="listingblock">
686
+ <div class="content">
687
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">it('should init in client mode', async () =&gt; {
688
+ // Both dynamic imports work natively without errors!
689
+ const { isClientMode } = await import('./config/env');
690
+ (isClientMode as unknown as Mock).mockReturnValue(true);
691
+
692
+ // Import and execute
693
+ await import('./main');
694
+
695
+ // ... assertions ...
696
+ });</code></pre>
697
+ </div>
698
+ </div>
699
+ </div>
700
+ </div>
701
+ </div>
702
+ <div class="sect1">
703
+ <h2 id="_eslint_type_safety_in_tests">ESLint &amp; Type Safety in Tests</h2>
704
+ <div class="sectionbody">
705
+ <div class="paragraph">
706
+ <p>Maintain code quality even in tests:</p>
707
+ </div>
708
+ <div class="ulist">
709
+ <ul>
710
+ <li>
711
+ <p><strong>Avoid <code>any</code></strong>: Use <code>unknown as vi.Mock</code> or cast to specific interfaces.</p>
712
+ </li>
713
+ <li>
714
+ <p><strong>Private Members</strong>: Use <code>// @ts-expect-error</code> or <code>(instance as any)._privateProp</code> only when absolutely necessary to verify internal state, but prefer testing public behavior.</p>
715
+ </li>
716
+ <li>
717
+ <p><strong>Mock Dependencies</strong>: Mock sub-packages (e.g., <code>view</code> or <code>manager</code>) when testing core orchestrators to isolate logic.</p>
718
+ </li>
719
+ </ul>
720
+ </div>
721
+ </div>
722
+ </div>
723
+ <div class="sect1">
724
+ <h2 id="_example_testing_a_grid_engine">Example: Testing a Grid Engine</h2>
725
+ <div class="sectionbody">
726
+ <div class="listingblock">
727
+ <div class="content">
728
+ <pre class="highlight"><code class="language-typescript" data-lang="typescript">import { describe, it, expect, beforeEach, vi } from 'vitest';
729
+ import GridAnalysisEngine from './GridAnalysisEngine';
730
+ import { Grid } from '../../../types/modules';
731
+
732
+ describe('GridAnalysisEngine', () =&gt; {
733
+ let engine: GridAnalysisEngine;
734
+ let mockGrid: Grid;
735
+
736
+ beforeEach(() =&gt; {
737
+ // [ARRANGE]
738
+ mockGrid = {
739
+ width: 10,
740
+ height: 20,
741
+ isCellActive: vi.fn(),
742
+ // ... other properties
743
+ } as unknown as Grid;
744
+ engine = new GridAnalysisEngine(mockGrid);
745
+ });
746
+
747
+ it('should identify full rows when all cells in a row are active', () =&gt; {
748
+ // [ARRANGE]
749
+ vi.mocked(mockGrid.isCellActive).mockImplementation(({ y }) =&gt; y === 5);
750
+
751
+ // [ACT]
752
+ const fullRows = engine.getFullRows();
753
+
754
+ // [ASSERT]
755
+ expect(fullRows).toContain(5);
756
+ expect(fullRows.length).toBe(1);
757
+ });
758
+ });</code></pre>
759
+ </div>
760
+ </div>
761
+ </div>
762
+ </div>
763
+ </div>
764
+ <div id="footer">
765
+ <div id="footer-text">
766
+ Last updated 2026-02-23 19:45:09 UTC
767
+ </div>
768
+ </div>
769
+ </body>
770
+ </html>