brick-engine-js 1.0.1 → 1.0.3
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.
- package/dist/docs/GAME_DEVELOPER_GUIDE.html +1 -1
- package/dist/docs/brick-engine-guide.html +1 -1
- package/dist/docs/getting-started.html +1 -1
- package/dist/docs/jsdoc_standard.html +1 -1
- package/dist/docs/publishing.html +1 -1
- package/dist/docs/reference/interfaces/modules/Session.html +1 -1
- package/dist/docs/reference/modules/GameMenu.html +1 -1
- package/dist/docs/reference/modules/GameSession.html +1 -1
- package/dist/docs/reference/modules/InitialStateSnapshot.html +1 -1
- package/dist/docs/reference/modules/SessionModal.html +1 -1
- package/dist/docs/testing_best_practices.html +1 -1
- package/package.json +8 -1
- package/public/docs/GAME_DEVELOPER_GUIDE.html +1 -1
- package/public/docs/brick-engine-guide.html +1 -1
- package/public/docs/getting-started.html +1 -1
- package/public/docs/jsdoc_standard.html +1 -1
- package/public/docs/publishing.html +1 -1
- package/public/docs/reference/interfaces/modules/Session.html +1 -1
- package/public/docs/reference/modules/GameMenu.html +1 -1
- package/public/docs/reference/modules/GameSession.html +1 -1
- package/public/docs/reference/modules/InitialStateSnapshot.html +1 -1
- package/public/docs/reference/modules/SessionModal.html +1 -1
- package/public/docs/testing_best_practices.html +1 -1
- package/.env.local.example +0 -2
- package/.github/workflows/publish.yml +0 -73
- package/.prettierignore +0 -2
- package/.prettierrc.json +0 -8
- package/eslint.config.mjs +0 -29
- package/scripts/generate-diagrams.sh +0 -20
- package/scripts/generate-docs.js +0 -111
- package/src/client-game.d.ts +0 -1
- package/src/config/configs.test.ts +0 -20
- package/src/config/configs.ts +0 -197
- package/src/config/env.test.ts +0 -59
- package/src/config/env.ts +0 -7
- package/src/config/styles.ts +0 -5
- package/src/core/Game.test.ts +0 -167
- package/src/core/Game.ts +0 -307
- package/src/core/InitialStateSnapshot.test.ts +0 -51
- package/src/core/InitialStateSnapshot.ts +0 -46
- package/src/core/helpers/CellHelper.test.ts +0 -33
- package/src/core/helpers/CellHelper.ts +0 -21
- package/src/core/helpers/ControlInputHandlerHelper.test.ts +0 -116
- package/src/core/helpers/ControlInputHandlerHelper.ts +0 -68
- package/src/core/helpers/CoordinateHelper.test.ts +0 -113
- package/src/core/helpers/CoordinateHelper.ts +0 -82
- package/src/core/helpers/InterfaceIdentifierHelper.test.ts +0 -122
- package/src/core/helpers/InterfaceIdentifierHelper.ts +0 -43
- package/src/core/helpers/RelativeValuesHelper.test.ts +0 -47
- package/src/core/helpers/RelativeValuesHelper.ts +0 -29
- package/src/core/module/control/GameControl.test.ts +0 -82
- package/src/core/module/control/GameControl.ts +0 -142
- package/src/core/module/control/GameControlKeyBinding.test.ts +0 -59
- package/src/core/module/control/GameControlKeyBinding.ts +0 -92
- package/src/core/module/grid/GameGrid.test.ts +0 -83
- package/src/core/module/grid/GameGrid.ts +0 -610
- package/src/core/module/grid/GameHudGrid.test.ts +0 -22
- package/src/core/module/grid/GameHudGrid.ts +0 -40
- package/src/core/module/grid/engines/GridAnalysisEngine.test.ts +0 -157
- package/src/core/module/grid/engines/GridAnalysisEngine.ts +0 -124
- package/src/core/module/grid/engines/GridLineEngine.test.ts +0 -132
- package/src/core/module/grid/engines/GridLineEngine.ts +0 -165
- package/src/core/module/grid/engines/GridMovementEngine.test.ts +0 -125
- package/src/core/module/grid/engines/GridMovementEngine.ts +0 -113
- package/src/core/module/grid/engines/GridRegionEngine.test.ts +0 -136
- package/src/core/module/grid/engines/GridRegionEngine.ts +0 -52
- package/src/core/module/grid/engines/GridTransformEngine.test.ts +0 -98
- package/src/core/module/grid/engines/GridTransformEngine.ts +0 -70
- package/src/core/module/renderer/DisplayRenderer.test.ts +0 -86
- package/src/core/module/renderer/DisplayRenderer.ts +0 -152
- package/src/core/module/renderer/GameRenderer.test.ts +0 -103
- package/src/core/module/renderer/GameRenderer.ts +0 -144
- package/src/core/module/renderer/HudRenderer.test.ts +0 -108
- package/src/core/module/renderer/HudRenderer.ts +0 -203
- package/src/core/module/score/GameScore.test.ts +0 -71
- package/src/core/module/score/GameScore.ts +0 -188
- package/src/core/module/session/GameSession.test.ts +0 -176
- package/src/core/module/session/GameSession.ts +0 -103
- package/src/core/module/sound/GameSound.test.ts +0 -117
- package/src/core/module/sound/GameSound.ts +0 -229
- package/src/core/module/state/GameState.test.ts +0 -101
- package/src/core/module/state/GameState.ts +0 -339
- package/src/core/module/text/GameText.test.ts +0 -87
- package/src/core/module/text/GameText.ts +0 -150
- package/src/core/module/time/GameTime.test.ts +0 -86
- package/src/core/module/time/GameTime.ts +0 -144
- package/src/core/types/Interfaces.ts +0 -59
- package/src/core/types/Types.ts +0 -124
- package/src/core/types/enums.ts +0 -113
- package/src/core/types/modules.ts +0 -841
- package/src/index.test.ts +0 -15
- package/src/index.ts +0 -9
- package/src/main.test.ts +0 -137
- package/src/main.ts +0 -77
- package/src/menu/GameMenu.test.ts +0 -157
- package/src/menu/GameMenu.ts +0 -124
- package/src/menu/GameMenuSingleton.test.ts +0 -26
- package/src/menu/GameMenuSingleton.ts +0 -13
- package/src/menu/GameRepository.test.ts +0 -46
- package/src/menu/GameRepository.ts +0 -47
- package/src/menu/manager/GameManager.test.ts +0 -68
- package/src/menu/manager/GameManager.ts +0 -50
- package/src/types/global.d.ts +0 -8
- package/src/types/interfaces.ts +0 -5
- package/src/view/Debugger.test.ts +0 -152
- package/src/view/Debugger.ts +0 -124
- package/src/view/GameView.test.ts +0 -95
- package/src/view/GameView.ts +0 -244
- package/src/view/SessionModal.test.ts +0 -141
- package/src/view/SessionModal.ts +0 -73
- package/src/view/components/layout/ButtonLayout.test.ts +0 -28
- package/src/view/components/layout/ButtonLayout.ts +0 -63
- package/src/view/components/layout/ContainerLayout.test.ts +0 -48
- package/src/view/components/layout/ContainerLayout.ts +0 -50
- package/src/view/components/layout/FrameLayout.test.ts +0 -24
- package/src/view/components/layout/FrameLayout.ts +0 -25
- package/src/view/components/ui/BigButton.test.ts +0 -28
- package/src/view/components/ui/BigButton.ts +0 -31
- package/src/view/components/ui/Button.test.ts +0 -30
- package/src/view/components/ui/Button.ts +0 -30
- package/src/view/components/ui/Canvas.test.ts +0 -32
- package/src/view/components/ui/Canvas.ts +0 -34
- package/src/view/components/ui/SmallButton.test.ts +0 -48
- package/src/view/components/ui/SmallButton.ts +0 -32
- package/src/view/theme/applyColors.test.ts +0 -47
- package/src/view/theme/applyColors.ts +0 -38
- package/src/view/theme/dimensions.test.ts +0 -34
- package/src/view/theme/dimensions.ts +0 -53
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -14
- package/webpack.config.js +0 -133
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/** @vitest-environment jsdom */
|
|
2
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
3
|
-
import GameManager from './GameManager';
|
|
4
|
-
import Game from '../../core/Game';
|
|
5
|
-
import p5 from 'p5';
|
|
6
|
-
|
|
7
|
-
describe('GameManager', () => {
|
|
8
|
-
let manager: GameManager;
|
|
9
|
-
let mockGame: Record<string, unknown>;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
document.head.innerHTML = '';
|
|
13
|
-
manager = new GameManager();
|
|
14
|
-
mockGame = {
|
|
15
|
-
p: {} as p5,
|
|
16
|
-
view: {},
|
|
17
|
-
switchGame: vi.fn(),
|
|
18
|
-
};
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
delete (window as unknown as Record<string, unknown>).BrickEngineGame;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should load script and switch game', async () => {
|
|
26
|
-
// [ARRANGE]
|
|
27
|
-
const entry = { id: 'test-game', name: 'TestGame', url: 'http://example.com/test.js' };
|
|
28
|
-
|
|
29
|
-
// Mocking script loading behavior
|
|
30
|
-
const appendSpy = vi.spyOn(document.head, 'appendChild').mockImplementation(((el: HTMLScriptElement) => {
|
|
31
|
-
// Simulate script load success
|
|
32
|
-
setTimeout(() => {
|
|
33
|
-
(window as unknown as Record<string, unknown>).BrickEngineGame = vi.fn().mockImplementation(function () {
|
|
34
|
-
return {};
|
|
35
|
-
});
|
|
36
|
-
if (el.onload) el.onload(new Event('load'));
|
|
37
|
-
}, 0);
|
|
38
|
-
return el;
|
|
39
|
-
}) as unknown as <T extends Node>(node: T) => T);
|
|
40
|
-
|
|
41
|
-
// [ACT]
|
|
42
|
-
await manager.handleGameSwitch(entry, mockGame as unknown as Game);
|
|
43
|
-
|
|
44
|
-
// [ASSERT]
|
|
45
|
-
expect(appendSpy).toHaveBeenCalled();
|
|
46
|
-
expect(mockGame.switchGame).toHaveBeenCalled();
|
|
47
|
-
expect((window as unknown as Record<string, unknown>).BrickEngineGame).toBeUndefined(); // Should be deleted after switch
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should handle script load failure', async () => {
|
|
51
|
-
// [ARRANGE]
|
|
52
|
-
const entry = { id: 'fail-game', name: 'FailGame', url: 'http://example.com/fail.js' };
|
|
53
|
-
vi.spyOn(document.head, 'appendChild').mockImplementation(((el: HTMLScriptElement) => {
|
|
54
|
-
setTimeout(() => {
|
|
55
|
-
if (el.onerror) el.onerror(new Event('error'));
|
|
56
|
-
}, 0);
|
|
57
|
-
return el;
|
|
58
|
-
}) as unknown as <T extends Node>(node: T) => T);
|
|
59
|
-
|
|
60
|
-
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
61
|
-
|
|
62
|
-
// [ACT]
|
|
63
|
-
await manager.handleGameSwitch(entry, mockGame as unknown as Game);
|
|
64
|
-
|
|
65
|
-
// [ASSERT]
|
|
66
|
-
expect(consoleSpy).toHaveBeenCalledWith('Failed to load game:', expect.any(Error));
|
|
67
|
-
});
|
|
68
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import Game from '../../core/Game';
|
|
2
|
-
import { GameEntry } from '../../types/interfaces';
|
|
3
|
-
|
|
4
|
-
export default class GameManager {
|
|
5
|
-
public async handleGameSwitch(entry: GameEntry, actualGame: Game) {
|
|
6
|
-
try {
|
|
7
|
-
await this._loadGameScript(entry.url);
|
|
8
|
-
|
|
9
|
-
// Client must define window.BrickEngineGame
|
|
10
|
-
console.log('Game instance defined on window.BrickEngineGame by client project: ', window.BrickEngineGame);
|
|
11
|
-
|
|
12
|
-
if (window.BrickEngineGame) {
|
|
13
|
-
const gameInstance = new window.BrickEngineGame(actualGame.p, actualGame.view);
|
|
14
|
-
console.log('Game loaded: ', entry.name);
|
|
15
|
-
console.log('Game loaded: ', entry.name);
|
|
16
|
-
|
|
17
|
-
// Set properly the Game ID using the GameRepository fetch ID
|
|
18
|
-
gameInstance.gameId = entry.id;
|
|
19
|
-
|
|
20
|
-
console.log('Switching to game');
|
|
21
|
-
actualGame.switchGame(gameInstance);
|
|
22
|
-
|
|
23
|
-
console.log('Game switched');
|
|
24
|
-
// Cleanup
|
|
25
|
-
console.log('Cleaning up window.BrickEngineGame');
|
|
26
|
-
delete window.BrickEngineGame;
|
|
27
|
-
} else {
|
|
28
|
-
console.error('Game bundle loaded but window.BrickEngineGame was not set.');
|
|
29
|
-
}
|
|
30
|
-
} catch (e) {
|
|
31
|
-
console.error('Failed to load game:', e);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
private _loadGameScript(url: string): Promise<void> {
|
|
36
|
-
return new Promise((resolve, reject) => {
|
|
37
|
-
const existingScript = document.getElementById('game-client-script');
|
|
38
|
-
if (existingScript) {
|
|
39
|
-
existingScript.remove();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const script = document.createElement('script');
|
|
43
|
-
script.src = url;
|
|
44
|
-
script.id = 'game-client-script';
|
|
45
|
-
script.onload = () => resolve();
|
|
46
|
-
script.onerror = () => reject(new Error(`Failed to load script ${url}`));
|
|
47
|
-
document.head.appendChild(script);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
}
|
package/src/types/global.d.ts
DELETED
package/src/types/interfaces.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/** @vitest-environment jsdom */
|
|
2
|
-
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
|
3
|
-
import Debugger from './Debugger';
|
|
4
|
-
import type p5 from 'p5';
|
|
5
|
-
import configs from '../config/configs';
|
|
6
|
-
import { GameModules } from '../core/types/Types';
|
|
7
|
-
|
|
8
|
-
// Mock configs
|
|
9
|
-
vi.mock('../config/configs', () => ({
|
|
10
|
-
default: {
|
|
11
|
-
game: {
|
|
12
|
-
debugger: {
|
|
13
|
-
enabled: true,
|
|
14
|
-
msInterval: 1000,
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
describe('Debugger', () => {
|
|
21
|
-
let mockP5: Record<string, Mock>;
|
|
22
|
-
let mockGameModules: Record<string, unknown>;
|
|
23
|
-
let debuggerInstance: Debugger;
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
// [ARRANGE]
|
|
27
|
-
mockP5 = {
|
|
28
|
-
createElement: vi.fn().mockImplementation(() => ({
|
|
29
|
-
id: vi.fn().mockReturnThis(),
|
|
30
|
-
parent: vi.fn().mockReturnThis(),
|
|
31
|
-
class: vi.fn().mockReturnThis(),
|
|
32
|
-
html: vi.fn().mockReturnThis(),
|
|
33
|
-
attribute: vi.fn().mockReturnThis(),
|
|
34
|
-
mouseClicked: vi.fn().mockReturnThis(),
|
|
35
|
-
toggleClass: vi.fn().mockReturnThis(),
|
|
36
|
-
remove: vi.fn().mockReturnThis(),
|
|
37
|
-
elt: { hasAttribute: vi.fn().mockReturnValue(false) },
|
|
38
|
-
})),
|
|
39
|
-
select: vi.fn().mockReturnValue(null), // By default, no existing elements
|
|
40
|
-
selectAll: vi.fn().mockReturnValue([]),
|
|
41
|
-
} as unknown as Record<string, Mock>;
|
|
42
|
-
|
|
43
|
-
mockGameModules = {
|
|
44
|
-
state: {
|
|
45
|
-
getDebugData: vi.fn().mockReturnValue({ on: true }),
|
|
46
|
-
},
|
|
47
|
-
control: {
|
|
48
|
-
getDebugData: vi.fn().mockReturnValue({ lastKey: 'UP' }),
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
debuggerInstance = new Debugger(mockGameModules as unknown as GameModules, mockP5 as unknown as p5);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should setup DOM elements when enabled', () => {
|
|
56
|
-
// [ACT]
|
|
57
|
-
debuggerInstance.setup();
|
|
58
|
-
|
|
59
|
-
// [ASSERT]
|
|
60
|
-
expect(mockP5.createElement).toHaveBeenCalledWith('details');
|
|
61
|
-
expect(mockP5.createElement).toHaveBeenCalledWith('summary');
|
|
62
|
-
expect((mockGameModules.state as { getDebugData: Mock }).getDebugData).toHaveBeenCalled();
|
|
63
|
-
expect((mockGameModules.control as { getDebugData: Mock }).getDebugData).toHaveBeenCalled();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should not setup DOM elements if debugger is disabled', () => {
|
|
67
|
-
// [ARRANGE]
|
|
68
|
-
// @ts-expect-error - testing configuration override
|
|
69
|
-
configs.game.debugger.enabled = false;
|
|
70
|
-
|
|
71
|
-
// [ACT]
|
|
72
|
-
debuggerInstance.setup();
|
|
73
|
-
|
|
74
|
-
// [ASSERT]
|
|
75
|
-
expect(mockP5.createElement).not.toHaveBeenCalled();
|
|
76
|
-
|
|
77
|
-
// Restore for other tests
|
|
78
|
-
// @ts-expect-error - testing configuration override
|
|
79
|
-
configs.game.debugger.enabled = true;
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should set game modules and preserve open states of details tabs', () => {
|
|
83
|
-
// [ARRANGE]
|
|
84
|
-
|
|
85
|
-
// Mock the presence of an existing open #debugger details
|
|
86
|
-
const existingDetails = {
|
|
87
|
-
elt: { hasAttribute: vi.fn().mockImplementation(attr => attr === 'open') },
|
|
88
|
-
remove: vi.fn(),
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Mock an open module details element
|
|
92
|
-
const openModuleDetails = {
|
|
93
|
-
id: vi.fn().mockReturnValue('debugger-state'),
|
|
94
|
-
elt: { hasAttribute: vi.fn().mockImplementation(attr => attr === 'open') },
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
mockP5.select.mockImplementation((selector: string) => {
|
|
98
|
-
if (selector === '#debugger') return existingDetails;
|
|
99
|
-
return { elt: { hasAttribute: () => false } };
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
mockP5.selectAll.mockImplementation((selector: string) => {
|
|
103
|
-
if (selector === '.debugger-module') return [openModuleDetails];
|
|
104
|
-
return [];
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
const newGameModules = {
|
|
108
|
-
state: { getDebugData: vi.fn().mockReturnValue({ on: false }) },
|
|
109
|
-
grid: { getDebugData: vi.fn().mockReturnValue({ width: 10 }) },
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// Track how attributes are applied to elements being created
|
|
113
|
-
const createSpy = vi.spyOn(mockP5, 'createElement');
|
|
114
|
-
|
|
115
|
-
// [ACT]
|
|
116
|
-
debuggerInstance.setGameModules(newGameModules as unknown as GameModules);
|
|
117
|
-
|
|
118
|
-
// [ASSERT]
|
|
119
|
-
expect(existingDetails.remove).toHaveBeenCalled();
|
|
120
|
-
|
|
121
|
-
// Ensure new 'details' element was set to 'open' because wasOpen was true
|
|
122
|
-
// And 'debugger-state' module also got 'open' attribute
|
|
123
|
-
|
|
124
|
-
// Find created elements matching the details container
|
|
125
|
-
const detailsInvocations = createSpy.mock.results.filter(r => r.value.id.mock.calls.some((c: unknown[]) => c[0] === 'debugger'));
|
|
126
|
-
expect(detailsInvocations.length).toBeGreaterThan(0);
|
|
127
|
-
expect(detailsInvocations[0].value.attribute).toHaveBeenCalledWith('open', '');
|
|
128
|
-
|
|
129
|
-
// Find module elements matching 'debugger-state'
|
|
130
|
-
const stateModuleInvocations = createSpy.mock.results.filter(r => r.value.id.mock.calls.some((c: unknown[]) => c[0] === 'debugger-state'));
|
|
131
|
-
expect(stateModuleInvocations.length).toBeGreaterThan(0);
|
|
132
|
-
expect(stateModuleInvocations[0].value.attribute).toHaveBeenCalledWith('open', '');
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('should update debugger values', () => {
|
|
136
|
-
// [ARRANGE]
|
|
137
|
-
debuggerInstance.setup();
|
|
138
|
-
|
|
139
|
-
// Change mock implementation to simulate updated state
|
|
140
|
-
(mockGameModules.state as { getDebugData: Mock }).getDebugData.mockReturnValue({ on: false });
|
|
141
|
-
|
|
142
|
-
// [ACT]
|
|
143
|
-
debuggerInstance.update();
|
|
144
|
-
|
|
145
|
-
// [ASSERT]
|
|
146
|
-
// the mock elements returned by createElement have a `html` spy
|
|
147
|
-
// Let's verify that the html spy was called with 'false' (the updated value)
|
|
148
|
-
const allHtmlCalls = mockP5.createElement.mock.results.map(res => res.value.html.mock.calls).flat(1);
|
|
149
|
-
|
|
150
|
-
expect(allHtmlCalls).toContainEqual(['false']);
|
|
151
|
-
});
|
|
152
|
-
});
|
package/src/view/Debugger.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import p5 from 'p5';
|
|
2
|
-
import { Debuggable, Initializable } from '../core/types/Interfaces';
|
|
3
|
-
import { GameModules } from '../core/types/Types';
|
|
4
|
-
import configs from '../config/configs';
|
|
5
|
-
|
|
6
|
-
type DebuggerModule = {
|
|
7
|
-
module: Debuggable;
|
|
8
|
-
properties: DebuggerProperty[];
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
type DebuggerProperty = {
|
|
12
|
-
key: string;
|
|
13
|
-
element: p5.Element;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default class NewDebugger implements Initializable {
|
|
17
|
-
private _p: p5;
|
|
18
|
-
private _gameModules: GameModules;
|
|
19
|
-
|
|
20
|
-
private _moduleElements: DebuggerModule[] = [];
|
|
21
|
-
|
|
22
|
-
constructor(gameModules: GameModules, p: p5) {
|
|
23
|
-
this._gameModules = gameModules;
|
|
24
|
-
this._p = p;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
setup() {
|
|
28
|
-
if (!configs.game.debugger.enabled) return;
|
|
29
|
-
|
|
30
|
-
const existingDetails = this._p.select('#debugger');
|
|
31
|
-
const wasOpen = existingDetails ? existingDetails.elt.hasAttribute('open') : false;
|
|
32
|
-
const openModules = new Set<string>();
|
|
33
|
-
|
|
34
|
-
if (existingDetails) {
|
|
35
|
-
const modules = this._p.selectAll('.debugger-module');
|
|
36
|
-
modules.forEach(module => {
|
|
37
|
-
if (module.elt.hasAttribute('open')) {
|
|
38
|
-
openModules.add(module.id());
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
existingDetails.remove();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this._moduleElements = [];
|
|
45
|
-
|
|
46
|
-
const details = this._p.createElement('details');
|
|
47
|
-
details.id('debugger');
|
|
48
|
-
if (wasOpen) details.attribute('open', '');
|
|
49
|
-
details.parent(this._p.select('body'));
|
|
50
|
-
|
|
51
|
-
const summary = this._p.createElement('summary');
|
|
52
|
-
summary.id('debugger-summary');
|
|
53
|
-
summary.html('Debug');
|
|
54
|
-
summary.parent(details);
|
|
55
|
-
|
|
56
|
-
Object.entries(this._gameModules).forEach(([name, module]) => {
|
|
57
|
-
if ('getDebugData' in module) {
|
|
58
|
-
const moduleProperty: DebuggerModule = {
|
|
59
|
-
module: module as Debuggable,
|
|
60
|
-
properties: [],
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const moduleDetails = this._p.createElement('details');
|
|
64
|
-
moduleDetails.class('debugger-module');
|
|
65
|
-
moduleDetails.id(`debugger-${name}`);
|
|
66
|
-
if (openModules.has(`debugger-${name}`)) {
|
|
67
|
-
moduleDetails.attribute('open', '');
|
|
68
|
-
}
|
|
69
|
-
moduleDetails.parent(details);
|
|
70
|
-
|
|
71
|
-
const moduleSummary = this._p.createElement('summary');
|
|
72
|
-
moduleSummary.id(`debugger-${name}-summary`);
|
|
73
|
-
moduleSummary.html(name);
|
|
74
|
-
moduleSummary.class('debugger-module-summary');
|
|
75
|
-
moduleSummary.parent(moduleDetails);
|
|
76
|
-
|
|
77
|
-
const moduleData = (module as unknown as Debuggable).getDebugData();
|
|
78
|
-
|
|
79
|
-
Object.entries(moduleData).forEach(([key, value]) => {
|
|
80
|
-
const dataElement = this._p.createElement('div');
|
|
81
|
-
dataElement.class('debugger-container');
|
|
82
|
-
dataElement.id(`debugger-container-${key}-${value}`);
|
|
83
|
-
dataElement.parent(moduleDetails);
|
|
84
|
-
|
|
85
|
-
dataElement.mouseClicked(() => {
|
|
86
|
-
dataElement.toggleClass('highlight');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const dataKeyElement = this._p.createElement('p');
|
|
90
|
-
dataKeyElement.id(`debugger-${key}-${value}`);
|
|
91
|
-
dataKeyElement.html(`${key}:`);
|
|
92
|
-
dataKeyElement.parent(dataElement);
|
|
93
|
-
|
|
94
|
-
const dataValueElement = this._p.createElement('span');
|
|
95
|
-
dataValueElement.id(`debugger-${key}-${value}-value`);
|
|
96
|
-
dataValueElement.html(`${value}`);
|
|
97
|
-
dataValueElement.parent(dataElement);
|
|
98
|
-
|
|
99
|
-
moduleProperty.properties.push({
|
|
100
|
-
key,
|
|
101
|
-
element: dataValueElement,
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
this._moduleElements.push(moduleProperty);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
setGameModules(gameModules: GameModules) {
|
|
111
|
-
this._gameModules = gameModules;
|
|
112
|
-
this.setup();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
update() {
|
|
116
|
-
this._moduleElements.forEach(moduleProperty => {
|
|
117
|
-
const data = moduleProperty.module.getDebugData();
|
|
118
|
-
|
|
119
|
-
moduleProperty.properties.forEach(property => {
|
|
120
|
-
property.element.html(`${data[property.key]}`);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/** @vitest-environment jsdom */
|
|
2
|
-
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
|
3
|
-
import GameView from './GameView';
|
|
4
|
-
import type p5 from 'p5';
|
|
5
|
-
import { ControlKey } from '../core/types/enums';
|
|
6
|
-
import { Control } from '../core/types/modules';
|
|
7
|
-
|
|
8
|
-
const { createMockButton } = vi.hoisted(() => ({
|
|
9
|
-
createMockButton: () => ({
|
|
10
|
-
mousePressed: vi.fn().mockReturnThis(),
|
|
11
|
-
mouseReleased: vi.fn().mockReturnThis(),
|
|
12
|
-
mouseOut: vi.fn().mockReturnThis(),
|
|
13
|
-
}),
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
// Mock sub-components/layouts
|
|
17
|
-
vi.mock('./theme/applyColors', () => ({ default: vi.fn() }));
|
|
18
|
-
vi.mock('./theme/dimensions', () => ({ default: vi.fn() }));
|
|
19
|
-
vi.mock('./components/layout/ButtonLayout', () => ({
|
|
20
|
-
default: vi.fn().mockReturnValue({
|
|
21
|
-
largeButtonContainer: {},
|
|
22
|
-
smallButtonContainer: {},
|
|
23
|
-
directionHorizontalContainer: {},
|
|
24
|
-
directionVerticalContainer: {},
|
|
25
|
-
}),
|
|
26
|
-
}));
|
|
27
|
-
vi.mock('./components/layout/ContainerLayout', () => ({
|
|
28
|
-
default: vi.fn().mockReturnValue({ container: {}, height: 800, width: 400 }),
|
|
29
|
-
}));
|
|
30
|
-
vi.mock('./components/layout/FrameLayout', () => ({ default: vi.fn() }));
|
|
31
|
-
vi.mock('./components/ui/BigButton', () => ({ default: vi.fn().mockImplementation(createMockButton) }));
|
|
32
|
-
vi.mock('./components/ui/Button', () => ({ default: vi.fn().mockImplementation(createMockButton) }));
|
|
33
|
-
vi.mock('./components/ui/Canvas', () => ({
|
|
34
|
-
default: vi.fn().mockReturnValue({ canvas: {}, canvasHeight: 500, canvasWidth: 400 }),
|
|
35
|
-
}));
|
|
36
|
-
vi.mock('./components/ui/SmallButton', () => ({ default: vi.fn().mockImplementation(createMockButton) }));
|
|
37
|
-
|
|
38
|
-
describe('GameView', () => {
|
|
39
|
-
let gameView: GameView;
|
|
40
|
-
let mockP5: Record<string, unknown>;
|
|
41
|
-
let parent: HTMLElement;
|
|
42
|
-
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
document.body.innerHTML = '<div id="splash"></div>';
|
|
45
|
-
parent = document.body;
|
|
46
|
-
mockP5 = {};
|
|
47
|
-
gameView = new GameView(mockP5 as unknown as p5, parent);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should build the game body', () => {
|
|
51
|
-
// [ACT]
|
|
52
|
-
const result = gameView.build();
|
|
53
|
-
|
|
54
|
-
// [ASSERT]
|
|
55
|
-
expect(result.canvasWidth).toBe(400);
|
|
56
|
-
expect(gameView.isBodyBuilt()).toBe(true);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should bind controls to buttons', () => {
|
|
60
|
-
// [ARRANGE]
|
|
61
|
-
gameView.build();
|
|
62
|
-
const mockControl = { notify: vi.fn() };
|
|
63
|
-
|
|
64
|
-
// [ACT]
|
|
65
|
-
gameView.bindControls(mockControl as unknown as Control);
|
|
66
|
-
|
|
67
|
-
// Accessing private buttons for check
|
|
68
|
-
// @ts-expect-error - testing private property
|
|
69
|
-
const actionBtn = gameView._actionBtn;
|
|
70
|
-
expect(actionBtn.mousePressed).toHaveBeenCalled();
|
|
71
|
-
|
|
72
|
-
// Trigger a click simulation
|
|
73
|
-
const pressHandler = (actionBtn.mousePressed as unknown as Mock).mock.calls[0][0];
|
|
74
|
-
pressHandler();
|
|
75
|
-
|
|
76
|
-
expect(mockControl.notify).toHaveBeenCalledWith(ControlKey.ACTION, expect.anything());
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should unbind controls', () => {
|
|
80
|
-
// [ARRANGE]
|
|
81
|
-
gameView.build();
|
|
82
|
-
gameView.bindControls({ notify: vi.fn() } as unknown as Control);
|
|
83
|
-
|
|
84
|
-
// @ts-expect-error - testing private property
|
|
85
|
-
const actionBtn = gameView._actionBtn;
|
|
86
|
-
const initialCalls = (actionBtn.mousePressed as unknown as Mock).mock.calls.length;
|
|
87
|
-
|
|
88
|
-
// [ACT]
|
|
89
|
-
gameView.unbindControls();
|
|
90
|
-
|
|
91
|
-
// [ASSERT]
|
|
92
|
-
// Should have been called again to override with empty func
|
|
93
|
-
expect(actionBtn.mousePressed).toHaveBeenCalledTimes(initialCalls + 1);
|
|
94
|
-
});
|
|
95
|
-
});
|