@omnitronix/bonnys-fortune-game-engine 1.3.2 → 1.5.0
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/README.md +25 -15
- package/dist/__tests__/base-game.test.js +255 -0
- package/dist/__tests__/base-game.test.js.map +1 -0
- package/dist/__tests__/bonnys-fortune-v1.game-engine.test.js +1 -1
- package/dist/__tests__/bonus-handlers.test.js +303 -0
- package/dist/__tests__/bonus-handlers.test.js.map +1 -0
- package/dist/__tests__/bonus-meters.test.js +508 -0
- package/dist/__tests__/bonus-meters.test.js.map +1 -0
- package/dist/__tests__/collect-feature-handler.test.js +386 -0
- package/dist/__tests__/collect-feature-handler.test.js.map +1 -0
- package/dist/__tests__/comprehensive.test.js +747 -0
- package/dist/__tests__/comprehensive.test.js.map +1 -0
- package/dist/__tests__/error-paths.test.js +373 -0
- package/dist/__tests__/error-paths.test.js.map +1 -0
- package/dist/__tests__/helpers/test-engine-factory.js +268 -0
- package/dist/__tests__/helpers/test-engine-factory.js.map +1 -0
- package/dist/__tests__/rng-gli19-compliance.test.js +292 -0
- package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -0
- package/dist/__tests__/rng-security.test.js +383 -0
- package/dist/__tests__/rng-security.test.js.map +1 -0
- package/dist/__tests__/rtp-simulation.test.js +242 -0
- package/dist/__tests__/rtp-simulation.test.js.map +1 -0
- package/dist/__tests__/state-transitions.test.js +307 -0
- package/dist/__tests__/state-transitions.test.js.map +1 -0
- package/dist/__tests__/steering-fortune-handler.test.js +286 -0
- package/dist/__tests__/steering-fortune-handler.test.js.map +1 -0
- package/dist/__tests__/symbol-distribution.test.js +195 -0
- package/dist/__tests__/symbol-distribution.test.js.map +1 -0
- package/dist/__tests__/treasure-hunt-handler.test.js +295 -0
- package/dist/__tests__/treasure-hunt-handler.test.js.map +1 -0
- package/dist/__tests__/win-calculator.test.js +515 -0
- package/dist/__tests__/win-calculator.test.js.map +1 -0
- package/dist/bonnys-fortune-v1.game-engine.js +14 -25
- package/dist/bonnys-fortune-v1.game-engine.js.map +1 -1
- package/dist/config/game-logic-config/game-logic-config.js +0 -2
- package/dist/config/game-logic-config/game-logic-config.js.map +1 -1
- package/dist/domain/types/{cheat-trigger-bonus-command.js → debug-trigger-bonus-command.js} +1 -1
- package/dist/domain/types/debug-trigger-bonus-command.js.map +1 -0
- package/dist/domain/types/{cheat-trigger-bonus-request.dto.js → debug-trigger-bonus-request.dto.js} +1 -1
- package/dist/domain/types/debug-trigger-bonus-request.dto.js.map +1 -0
- package/dist/domain/types/{cheat-update-bonus-meter-progress-command.js → debug-update-bonus-meter-progress-command.js} +1 -1
- package/dist/domain/types/debug-update-bonus-meter-progress-command.js.map +1 -0
- package/dist/domain/types/{cheat-update-bonus-meter-progress-request.dto.js → debug-update-bonus-meter-progress-request.dto.js} +1 -1
- package/dist/domain/types/debug-update-bonus-meter-progress-request.dto.js.map +1 -0
- package/dist/index.js.map +1 -1
- package/dist/logic/bonnys-fortune.game-logic.js +37 -17
- package/dist/logic/bonnys-fortune.game-logic.js.map +1 -1
- package/dist/logic/handlers/base-game.handler.js +1 -5
- package/dist/logic/handlers/base-game.handler.js.map +1 -1
- package/dist/rng/DummyRngClient.js +8 -1
- package/dist/rng/DummyRngClient.js.map +1 -1
- package/dist/rng/rng-client.factory.js.map +1 -1
- package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js +0 -9
- package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js.map +1 -1
- package/package.json +6 -6
- package/dist/__tests__/bonnys-fortune-v1.game-engine.test.d.ts +0 -1
- package/dist/bonnys-fortune-v1.game-engine.d.ts +0 -36
- package/dist/config/game-logic-config/file-system.game-logic-config-loader.d.ts +0 -4
- package/dist/config/game-logic-config/game-logic-config-loader.d.ts +0 -3
- package/dist/config/game-logic-config/game-logic-config.d.ts +0 -2
- package/dist/config/reel-strips-config/file-system.reel-strips-config-loader.d.ts +0 -4
- package/dist/config/reel-strips-config/reel-strip-option.dto.d.ts +0 -4
- package/dist/config/reel-strips-config/reel-strips-config-loader.d.ts +0 -3
- package/dist/config/reel-strips-config/reel-strips-config.dto.d.ts +0 -5
- package/dist/config/reel-strips-config/reel.dto.d.ts +0 -5
- package/dist/domain/game-round.types.d.ts +0 -9
- package/dist/domain/mappers/reel-strips-config.mapper.d.ts +0 -4
- package/dist/domain/reel-strip-option.d.ts +0 -7
- package/dist/domain/reel-strips-config.d.ts +0 -9
- package/dist/domain/reel.d.ts +0 -8
- package/dist/domain/types/cheat-trigger-bonus-command.d.ts +0 -5
- package/dist/domain/types/cheat-trigger-bonus-command.js.map +0 -1
- package/dist/domain/types/cheat-trigger-bonus-request.dto.d.ts +0 -5
- package/dist/domain/types/cheat-trigger-bonus-request.dto.js.map +0 -1
- package/dist/domain/types/cheat-update-bonus-meter-progress-command.d.ts +0 -5
- package/dist/domain/types/cheat-update-bonus-meter-progress-command.js.map +0 -1
- package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.d.ts +0 -5
- package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.js.map +0 -1
- package/dist/domain/types/game-spin-command.d.ts +0 -8
- package/dist/domain/types/game-spin-input.dto.d.ts +0 -8
- package/dist/domain/types/game-spin-output.dto.d.ts +0 -119
- package/dist/domain/types/game-symbols.response.dto.d.ts +0 -10
- package/dist/domain/types/reel-strip-option.dto.d.ts +0 -4
- package/dist/domain/types/reel-strips-config.dto.d.ts +0 -5
- package/dist/domain/types/reel.dto.d.ts +0 -5
- package/dist/domain/types/start-bonus-round-command.d.ts +0 -8
- package/dist/domain/types/start-bonus-round-input.dto.d.ts +0 -10
- package/dist/game-engine.interface.d.ts +0 -41
- package/dist/helpers/generate-hash.d.ts +0 -1
- package/dist/helpers/number-helper.d.ts +0 -23
- package/dist/helpers/optional-boolean-mapper.d.ts +0 -1
- package/dist/helpers/uuid-helper.d.ts +0 -3
- package/dist/helpers/validation-helper.d.ts +0 -14
- package/dist/index.d.ts +0 -2
- package/dist/logger/logger.d.ts +0 -22
- package/dist/logger/logger.js +0 -140
- package/dist/logger/logger.js.map +0 -1
- package/dist/logic/bonnys-fortune.game-logic.d.ts +0 -32
- package/dist/logic/bonnys-fortune.spin-generator.d.ts +0 -19
- package/dist/logic/bonnys-fortune.types.d.ts +0 -170
- package/dist/logic/bonnys-fortune.win-calculator.d.ts +0 -10
- package/dist/logic/game-logic-config.interface.d.ts +0 -180
- package/dist/logic/handlers/base-game.handler.d.ts +0 -15
- package/dist/logic/handlers/collect-feature-bonus.handler.d.ts +0 -13
- package/dist/logic/handlers/free-spins-bonus.handler.d.ts +0 -11
- package/dist/logic/handlers/steering-to-the-fortune-bonus.handler.d.ts +0 -11
- package/dist/logic/handlers/treasure-hunt-bonus.handler.d.ts +0 -15
- package/dist/rng/DummyRngClient.d.ts +0 -18
- package/dist/rng/rng-client.factory.d.ts +0 -7
- package/dist/rng/rng-client.interface.d.ts +0 -16
- package/dist/rng/rng-service.d.ts +0 -26
- package/dist/validation/abstract-game-logic-config.validator.d.ts +0 -4
- package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.d.ts +0 -131
- package/dist/validation/bonnys-fortune/bonnys-fortune-config.validator.d.ts +0 -5
- package/dist/validation/custom-decorators/IsNestedIntArray.d.ts +0 -2
- package/dist/validation/game-logic-config-validation.service.d.ts +0 -8
- package/dist/validation/reel-strips-config-validation.service.d.ts +0 -5
- package/src/__tests__/bonnys-fortune-v1.game-engine.test.ts +0 -80
- package/src/bonnys-fortune-v1.game-engine.ts +0 -314
- package/src/config/game-logic-config/file-system.game-logic-config-loader.ts +0 -27
- package/src/config/game-logic-config/game-logic-config-loader.ts +0 -3
- package/src/config/game-logic-config/game-logic-config.ts +0 -382
- package/src/config/reel-strips-config/file-system.reel-strips-config-loader.ts +0 -43
- package/src/config/reel-strips-config/reel-strip-option.dto.ts +0 -13
- package/src/config/reel-strips-config/reel-strips-config-loader.ts +0 -9
- package/src/config/reel-strips-config/reel-strips-config.dto.ts +0 -16
- package/src/config/reel-strips-config/reel.dto.ts +0 -16
- package/src/config/reel-strips-config/reels-BASE.csv +0 -52
- package/src/config/reel-strips-config/reels-BONUS.csv +0 -52
- package/src/domain/game-round.types.ts +0 -10
- package/src/domain/mappers/reel-strips-config.mapper.ts +0 -16
- package/src/domain/reel-strip-option.ts +0 -15
- package/src/domain/reel-strips-config.ts +0 -21
- package/src/domain/reel.ts +0 -17
- package/src/domain/types/cheat-trigger-bonus-command.ts +0 -5
- package/src/domain/types/cheat-trigger-bonus-request.dto.ts +0 -5
- package/src/domain/types/cheat-update-bonus-meter-progress-command.ts +0 -6
- package/src/domain/types/cheat-update-bonus-meter-progress-request.dto.ts +0 -5
- package/src/domain/types/game-spin-command.ts +0 -8
- package/src/domain/types/game-spin-input.dto.ts +0 -8
- package/src/domain/types/game-spin-output.dto.ts +0 -142
- package/src/domain/types/game-symbols.response.dto.ts +0 -11
- package/src/domain/types/reel-strip-option.dto.ts +0 -13
- package/src/domain/types/reel-strips-config.dto.ts +0 -15
- package/src/domain/types/reel.dto.ts +0 -15
- package/src/domain/types/start-bonus-round-command.ts +0 -8
- package/src/domain/types/start-bonus-round-input.dto.ts +0 -10
- package/src/game-engine.interface.ts +0 -59
- package/src/helpers/generate-hash.ts +0 -5
- package/src/helpers/number-helper.ts +0 -41
- package/src/helpers/optional-boolean-mapper.ts +0 -5
- package/src/helpers/uuid-helper.ts +0 -7
- package/src/helpers/validation-helper.ts +0 -27
- package/src/index.ts +0 -3
- package/src/logger/logger.ts +0 -178
- package/src/logic/bonnys-fortune.game-logic.ts +0 -490
- package/src/logic/bonnys-fortune.spin-generator.ts +0 -277
- package/src/logic/bonnys-fortune.types.ts +0 -223
- package/src/logic/bonnys-fortune.win-calculator.ts +0 -210
- package/src/logic/game-logic-config.interface.ts +0 -176
- package/src/logic/handlers/base-game.handler.ts +0 -221
- package/src/logic/handlers/collect-feature-bonus.handler.ts +0 -301
- package/src/logic/handlers/free-spins-bonus.handler.ts +0 -119
- package/src/logic/handlers/steering-to-the-fortune-bonus.handler.ts +0 -118
- package/src/logic/handlers/treasure-hunt-bonus.handler.ts +0 -232
- package/src/rng/DummyRngClient.ts +0 -108
- package/src/rng/rng-client.factory.ts +0 -27
- package/src/rng/rng-client.interface.ts +0 -38
- package/src/rng/rng-service.ts +0 -130
- package/src/validation/abstract-game-logic-config.validator.ts +0 -20
- package/src/validation/bonnys-fortune/bonnys-fortune-config.dto.ts +0 -379
- package/src/validation/bonnys-fortune/bonnys-fortune-config.validator.ts +0 -8
- package/src/validation/custom-decorators/IsNestedIntArray.ts +0 -29
- package/src/validation/game-logic-config-validation.service.ts +0 -28
- package/src/validation/reel-strips-config-validation.service.ts +0 -29
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtp-simulation.test.js","sourceRoot":"","sources":["../../src/__tests__/rtp-simulation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* State Transition Tests — Bonnys Fortune
|
|
5
|
+
*
|
|
6
|
+
* Validates the state machine that governs game flow:
|
|
7
|
+
* - INIT_SESSION_STATE → BASE_GAME_SPIN
|
|
8
|
+
* - BASE_GAME_SPIN → BASE_GAME_SPIN (no trigger)
|
|
9
|
+
* - BASE_GAME_SPIN → BONUS_GAME_1_SPIN (treasure hunt via debug)
|
|
10
|
+
* - BASE_GAME_SPIN → BONUS_GAME_2_SPIN (free spins via debug)
|
|
11
|
+
* - BASE_GAME_SPIN → BONUS_GAME_3_SPIN (steering fortune via debug)
|
|
12
|
+
* - BASE_GAME_SPIN → COLLECT_FEATURE_SPIN (collect feature via debug)
|
|
13
|
+
* - All bonus types → BASE_GAME_SPIN (after completion)
|
|
14
|
+
* - Bonus meter initialization and tracking
|
|
15
|
+
* - Invalid transitions rejected
|
|
16
|
+
*/
|
|
17
|
+
const test_engine_factory_1 = require("./helpers/test-engine-factory");
|
|
18
|
+
describe('State Transitions — Bonnys Fortune', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
(0, test_engine_factory_1.resetCommandIdCounter)();
|
|
21
|
+
});
|
|
22
|
+
describe('Initial State', () => {
|
|
23
|
+
it('should start in BASE_GAME_SPIN state after init', async () => {
|
|
24
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
25
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
26
|
+
expect(session.privateState.nextSpinType).toBe('BASE_GAME_SPIN');
|
|
27
|
+
});
|
|
28
|
+
it('should have empty pending bonuses after init', async () => {
|
|
29
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
30
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
31
|
+
expect(session.privateState.pendingBonuses).toBeDefined();
|
|
32
|
+
expect(session.privateState.pendingBonuses.length).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
it('should have no active bonus after init', async () => {
|
|
35
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
36
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
37
|
+
expect(session.privateState.activeBonus).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
it('should initialize bonus meters', async () => {
|
|
40
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
41
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
42
|
+
const meters = session.publicState.bonusMeters;
|
|
43
|
+
expect(meters).toBeDefined();
|
|
44
|
+
expect(typeof meters).toBe('object');
|
|
45
|
+
// Should have 3 meter entries (bonusGame1, bonusGame2, bonusGame3)
|
|
46
|
+
// collectFeature is triggered via steering fortune wheel, not by a meter
|
|
47
|
+
const meterKeys = Object.keys(meters || {});
|
|
48
|
+
expect(meterKeys.length).toBe(3);
|
|
49
|
+
});
|
|
50
|
+
it('should initialize bonus meters with valid thresholds', async () => {
|
|
51
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
52
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
53
|
+
const meters = session.publicState.bonusMeters;
|
|
54
|
+
for (const [, meter] of Object.entries(meters || {})) {
|
|
55
|
+
const m = meter;
|
|
56
|
+
expect(m.threshold).toBeGreaterThan(0);
|
|
57
|
+
expect(m.progress).toBeGreaterThanOrEqual(0);
|
|
58
|
+
expect(m.progress).toBeLessThanOrEqual(m.threshold);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
it('should set bet amount from init payload', async () => {
|
|
62
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
63
|
+
const session = await (0, test_engine_factory_1.initSession)(engine, 2.0);
|
|
64
|
+
expect(session.publicState.currentBetAmount).toBe(2.0);
|
|
65
|
+
});
|
|
66
|
+
it('should initialize per-bet-amount meter state', async () => {
|
|
67
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
68
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
69
|
+
// bonusMetersByAmount should be populated
|
|
70
|
+
expect(session.privateState.bonusMetersByAmount).toBeDefined();
|
|
71
|
+
expect(typeof session.privateState.bonusMetersByAmount).toBe('object');
|
|
72
|
+
const amounts = Object.keys(session.privateState.bonusMetersByAmount || {});
|
|
73
|
+
// At least 1 bet amount tier should be initialized
|
|
74
|
+
expect(amounts.length).toBeGreaterThanOrEqual(1);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('Base Game Transitions', () => {
|
|
78
|
+
it('should stay in BASE_GAME_SPIN when no bonus triggers', async () => {
|
|
79
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
80
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
81
|
+
let pub = session.publicState;
|
|
82
|
+
let priv = session.privateState;
|
|
83
|
+
let baseCount = 0;
|
|
84
|
+
for (let i = 0; i < 10; i++) {
|
|
85
|
+
if (priv.nextSpinType !== 'BASE_GAME_SPIN')
|
|
86
|
+
break;
|
|
87
|
+
const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
|
|
88
|
+
expect(result.success).toBe(true);
|
|
89
|
+
if (result.privateState.nextSpinType === 'BASE_GAME_SPIN') {
|
|
90
|
+
baseCount++;
|
|
91
|
+
}
|
|
92
|
+
pub = result.publicState;
|
|
93
|
+
priv = result.privateState;
|
|
94
|
+
}
|
|
95
|
+
// At least 1 spin should stay in base game
|
|
96
|
+
expect(baseCount).toBeGreaterThanOrEqual(1);
|
|
97
|
+
});
|
|
98
|
+
it('should update bonus meter progress during base game spins', async () => {
|
|
99
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
100
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
101
|
+
// Track initial meter state
|
|
102
|
+
const initialMeters = JSON.parse(JSON.stringify(session.publicState.bonusMeters));
|
|
103
|
+
let pub = session.publicState;
|
|
104
|
+
let priv = session.privateState;
|
|
105
|
+
// Execute several spins
|
|
106
|
+
for (let i = 0; i < 5; i++) {
|
|
107
|
+
if (priv.nextSpinType !== 'BASE_GAME_SPIN')
|
|
108
|
+
break;
|
|
109
|
+
const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
|
|
110
|
+
expect(result.success).toBe(true);
|
|
111
|
+
pub = result.publicState;
|
|
112
|
+
priv = result.privateState;
|
|
113
|
+
}
|
|
114
|
+
// Meters may have changed (or may not, depending on symbol hits)
|
|
115
|
+
const finalMeters = pub.bonusMeters;
|
|
116
|
+
expect(finalMeters).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
it('should carry state forward between spins', async () => {
|
|
119
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
120
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
121
|
+
const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
|
|
122
|
+
expect(result1.success).toBe(true);
|
|
123
|
+
if (result1.privateState.nextSpinType === 'BASE_GAME_SPIN') {
|
|
124
|
+
const result2 = await (0, test_engine_factory_1.executeSpin)(engine, result1.publicState, result1.privateState);
|
|
125
|
+
expect(result2.success).toBe(true);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('Bonus Transitions (via Debug)', () => {
|
|
130
|
+
const bonusTypes = [
|
|
131
|
+
{ type: 'bonusGame1', expectedSpin: 'BONUS_GAME_1_SPIN', name: 'Treasure Hunt' },
|
|
132
|
+
{ type: 'bonusGame2', expectedSpin: 'BONUS_GAME_2_SPIN', name: 'Free Spins' },
|
|
133
|
+
{ type: 'bonusGame3', expectedSpin: 'BONUS_GAME_3_SPIN', name: 'Steering Fortune' },
|
|
134
|
+
{ type: 'collectFeature', expectedSpin: 'COLLECT_FEATURE_SPIN', name: 'Collect Feature' },
|
|
135
|
+
];
|
|
136
|
+
for (const { type, expectedSpin, name } of bonusTypes) {
|
|
137
|
+
it(`should add ${name} to pending bonuses via debug trigger`, async () => {
|
|
138
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
139
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
140
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, type);
|
|
141
|
+
expect(debugResult.success).toBe(true);
|
|
142
|
+
// Debug trigger adds exactly 1 pending bonus
|
|
143
|
+
expect(debugResult.privateState.pendingBonuses.length).toBe(1);
|
|
144
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
145
|
+
expect(bonus.bonusType).toBe(type);
|
|
146
|
+
});
|
|
147
|
+
it(`should complete ${name} and return to BASE_GAME_SPIN`, async () => {
|
|
148
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
149
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
150
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, type);
|
|
151
|
+
if (!debugResult.success)
|
|
152
|
+
return;
|
|
153
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
154
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
155
|
+
expect(bonusResult.success).toBe(true);
|
|
156
|
+
// BF generates all bonus results upfront in START_BONUS_ROUND.
|
|
157
|
+
// Final state (nextSpinType = BASE_GAME_SPIN) is in last result entry.
|
|
158
|
+
let { publicState: pub, privateState: priv } = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
|
|
159
|
+
// Handle chained bonuses (steering fortune may chain to another bonus)
|
|
160
|
+
let maxChains = 5;
|
|
161
|
+
while (priv.pendingBonuses?.length > 0 && maxChains-- > 0) {
|
|
162
|
+
const nextBonus = priv.pendingBonuses[0];
|
|
163
|
+
const chainResult = await (0, test_engine_factory_1.startBonusRound)(engine, pub, priv, nextBonus.bonusType);
|
|
164
|
+
expect(chainResult.success).toBe(true);
|
|
165
|
+
({ publicState: pub, privateState: priv } = (0, test_engine_factory_1.extractFinalBonusState)(chainResult));
|
|
166
|
+
}
|
|
167
|
+
// After completion, should return to base
|
|
168
|
+
if (type !== 'bonusGame3') {
|
|
169
|
+
expect(priv.nextSpinType).toBe('BASE_GAME_SPIN');
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// Steering Fortune may still be chaining
|
|
173
|
+
expect(priv.nextSpinType).toBeDefined();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
it('should clear pending bonuses after starting a bonus round', async () => {
|
|
178
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
179
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
180
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame1');
|
|
181
|
+
if (!debugResult.success)
|
|
182
|
+
return;
|
|
183
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
184
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
185
|
+
expect(bonusResult.success).toBe(true);
|
|
186
|
+
// Pending bonus for this type should be consumed
|
|
187
|
+
const remaining = bonusResult.privateState.pendingBonuses.filter((b) => b.bonusId === bonus.bonusId);
|
|
188
|
+
expect(remaining.length).toBe(0);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
describe('Debug Update Bonus Meter', () => {
|
|
192
|
+
it('should update bonus meter progress via debug command', async () => {
|
|
193
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
194
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
195
|
+
// Get a meter key from the public state
|
|
196
|
+
const meters = session.publicState.bonusMeters;
|
|
197
|
+
const meterKeys = Object.keys(meters || {});
|
|
198
|
+
if (meterKeys.length === 0)
|
|
199
|
+
return;
|
|
200
|
+
const meterKey = meterKeys[0];
|
|
201
|
+
try {
|
|
202
|
+
const result = await engine.processCommand(session.publicState, session.privateState, {
|
|
203
|
+
id: (0, test_engine_factory_1.nextCommandId)('debug-meter'),
|
|
204
|
+
type: 'DEBUG_UPDATE_BONUS_METER_PROGRESS',
|
|
205
|
+
payload: {
|
|
206
|
+
meterId: meterKey,
|
|
207
|
+
progress: 5,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
expect(result.success).toBe(true);
|
|
211
|
+
const updatedMeter = result.publicState.bonusMeters?.[meterKey];
|
|
212
|
+
if (updatedMeter) {
|
|
213
|
+
expect(updatedMeter.progress).toBe(5);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
// Some implementations may not support this
|
|
218
|
+
expect(error).toBeInstanceOf(Error);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
describe('GET_SYMBOLS Command', () => {
|
|
223
|
+
it('should return symbol definitions', async () => {
|
|
224
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
225
|
+
await (0, test_engine_factory_1.waitForEngineReady)(engine);
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
const result = await engine.processCommand(null, null, {
|
|
228
|
+
id: (0, test_engine_factory_1.nextCommandId)('symbols'),
|
|
229
|
+
type: 'GET_SYMBOLS',
|
|
230
|
+
payload: {},
|
|
231
|
+
});
|
|
232
|
+
expect(result.success).toBe(true);
|
|
233
|
+
expect(result.outcome).toBeDefined();
|
|
234
|
+
expect(typeof result.outcome).toBe('object');
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
describe('Invalid Transitions', () => {
|
|
238
|
+
it('should reject SPIN when bonus spin is expected', async () => {
|
|
239
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
240
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
241
|
+
// Set nextSpinType to a bonus type
|
|
242
|
+
const modifiedPriv = {
|
|
243
|
+
...session.privateState,
|
|
244
|
+
nextSpinType: 'BONUS_GAME_1_SPIN',
|
|
245
|
+
};
|
|
246
|
+
try {
|
|
247
|
+
const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, modifiedPriv);
|
|
248
|
+
// Should fail or throw
|
|
249
|
+
if (result.success === false) {
|
|
250
|
+
expect(result.success).toBe(false);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
expect(error).toBeInstanceOf(Error);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
it('should reject START_BONUS_ROUND when no bonuses pending', async () => {
|
|
258
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
259
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
260
|
+
try {
|
|
261
|
+
const result = await engine.processCommand(session.publicState, session.privateState, {
|
|
262
|
+
id: (0, test_engine_factory_1.nextCommandId)('bonus'),
|
|
263
|
+
type: 'START_BONUS_ROUND',
|
|
264
|
+
payload: {
|
|
265
|
+
sessionId: 'test',
|
|
266
|
+
bonusId: 'fake-id',
|
|
267
|
+
bonusType: 'bonusGame1',
|
|
268
|
+
betAmount: 1.0,
|
|
269
|
+
gameCode: 'bonnys-fortune',
|
|
270
|
+
gameVersion: '1.0.0',
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
expect(result.success).toBe(false);
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
expect(error).toBeInstanceOf(Error);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
it('should reject START_BONUS_ROUND with mismatched bonus type', async () => {
|
|
280
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
281
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
282
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame1');
|
|
283
|
+
if (!debugResult.success)
|
|
284
|
+
return;
|
|
285
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
286
|
+
try {
|
|
287
|
+
const result = await engine.processCommand(debugResult.publicState, debugResult.privateState, {
|
|
288
|
+
id: (0, test_engine_factory_1.nextCommandId)('bonus'),
|
|
289
|
+
type: 'START_BONUS_ROUND',
|
|
290
|
+
payload: {
|
|
291
|
+
sessionId: 'test',
|
|
292
|
+
bonusId: bonus.bonusId,
|
|
293
|
+
bonusType: 'bonusGame2', // Wrong type
|
|
294
|
+
betAmount: 1.0,
|
|
295
|
+
gameCode: 'bonnys-fortune',
|
|
296
|
+
gameVersion: '1.0.0',
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
expect(result.success).toBe(false);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
expect(error).toBeInstanceOf(Error);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
//# sourceMappingURL=state-transitions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-transitions.test.js","sourceRoot":"","sources":["../../src/__tests__/state-transitions.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Steering Fortune Bonus Handler Tests - Bonnys Fortune
|
|
5
|
+
*
|
|
6
|
+
* Tests the Steering Fortune (bonusGame3) bonus feature:
|
|
7
|
+
* - Wheel spin mechanics
|
|
8
|
+
* - Prize resolution from wheel segments
|
|
9
|
+
* - Wheel animation states
|
|
10
|
+
* - Complete bonus flow
|
|
11
|
+
* - Prize tier distribution
|
|
12
|
+
*/
|
|
13
|
+
const test_engine_factory_1 = require("./helpers/test-engine-factory");
|
|
14
|
+
const bonnys_fortune_types_1 = require("../logic/bonnys-fortune.types");
|
|
15
|
+
describe('Steering Fortune Handler - Bonnys Fortune', () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
(0, test_engine_factory_1.resetCommandIdCounter)();
|
|
18
|
+
});
|
|
19
|
+
describe('Wheel Spin Mechanics', () => {
|
|
20
|
+
it('should execute wheel spin and return single result', async () => {
|
|
21
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
22
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
23
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
24
|
+
expect(debugResult.success).toBe(true);
|
|
25
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
26
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
27
|
+
expect(bonusResult.success).toBe(true);
|
|
28
|
+
expect(bonusResult.outcome?.results).toBeDefined();
|
|
29
|
+
// Steering Fortune produces exactly 1 result per spin
|
|
30
|
+
expect(bonusResult.outcome.results.length).toBe(1);
|
|
31
|
+
});
|
|
32
|
+
it('should use weighted draw for wheel segment selection', async () => {
|
|
33
|
+
const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(12345);
|
|
34
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
35
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
36
|
+
if (!debugResult.success)
|
|
37
|
+
return;
|
|
38
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
39
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
40
|
+
expect(bonusResult.success).toBe(true);
|
|
41
|
+
expect(bonusResult.rngOutcome).toBeDefined();
|
|
42
|
+
// Should have RNG call for wheel selection
|
|
43
|
+
expect(Object.keys(bonusResult.rngOutcome || {}).length).toBeGreaterThan(0);
|
|
44
|
+
});
|
|
45
|
+
it('should set spinType to BONUS_GAME_3_SPIN', async () => {
|
|
46
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
47
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
48
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
49
|
+
if (!debugResult.success)
|
|
50
|
+
return;
|
|
51
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
52
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
53
|
+
expect(bonusResult.success).toBe(true);
|
|
54
|
+
expect(bonusResult.outcome.results[0].result.spinType).toBe(bonnys_fortune_types_1.SpinType.BONUS_GAME_3_SPIN);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('Prize Resolution', () => {
|
|
58
|
+
it('should resolve to either MULTIPLIER or BONUS prize type', async () => {
|
|
59
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
60
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
61
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
62
|
+
if (!debugResult.success)
|
|
63
|
+
return;
|
|
64
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
65
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
66
|
+
expect(bonusResult.success).toBe(true);
|
|
67
|
+
const prizeType = bonusResult.outcome.results[0].result.prizeType;
|
|
68
|
+
expect([bonnys_fortune_types_1.PrizeType.MULTIPLIER, bonnys_fortune_types_1.PrizeType.BONUS]).toContain(prizeType);
|
|
69
|
+
});
|
|
70
|
+
it('should calculate playerWinning for MULTIPLIER prize type', async () => {
|
|
71
|
+
// Use mock RNG to force a multiplier prize (low RNG value typically hits first segment)
|
|
72
|
+
const { engine, mockRng } = (0, test_engine_factory_1.createEngineWithMockRng)([0]);
|
|
73
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
74
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
75
|
+
if (!debugResult.success)
|
|
76
|
+
return;
|
|
77
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
78
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
79
|
+
expect(bonusResult.success).toBe(true);
|
|
80
|
+
const result = bonusResult.outcome.results[0].result;
|
|
81
|
+
expect(result.playerWinning).toBeDefined();
|
|
82
|
+
expect(typeof result.playerWinning).toBe('number');
|
|
83
|
+
});
|
|
84
|
+
it('should include prizeValue in result', async () => {
|
|
85
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
86
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
87
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
88
|
+
if (!debugResult.success)
|
|
89
|
+
return;
|
|
90
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
91
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
92
|
+
expect(bonusResult.success).toBe(true);
|
|
93
|
+
const result = bonusResult.outcome.results[0].result;
|
|
94
|
+
expect(result.prizeValue).toBeDefined();
|
|
95
|
+
});
|
|
96
|
+
it('should set totalMultiplier for multiplier prizes', async () => {
|
|
97
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
98
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
99
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
100
|
+
if (!debugResult.success)
|
|
101
|
+
return;
|
|
102
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
103
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
104
|
+
expect(bonusResult.success).toBe(true);
|
|
105
|
+
const result = bonusResult.outcome.results[0].result;
|
|
106
|
+
expect(result.totalMultiplier).toBeDefined();
|
|
107
|
+
expect(typeof result.totalMultiplier).toBe('number');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('Bonus Chaining', () => {
|
|
111
|
+
it('should set triggeredBonus when prize is BONUS type', async () => {
|
|
112
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
113
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
114
|
+
// Run multiple attempts to hit a BONUS prize
|
|
115
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
116
|
+
(0, test_engine_factory_1.resetCommandIdCounter)();
|
|
117
|
+
const { engine: attemptEngine } = (0, test_engine_factory_1.createEngineWithLcgRng)(attempt * 1000);
|
|
118
|
+
const attemptSession = await (0, test_engine_factory_1.initSession)(attemptEngine);
|
|
119
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(attemptEngine, attemptSession.publicState, attemptSession.privateState, 'bonusGame3');
|
|
120
|
+
if (!debugResult.success)
|
|
121
|
+
continue;
|
|
122
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
123
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(attemptEngine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
124
|
+
if (!bonusResult.success)
|
|
125
|
+
continue;
|
|
126
|
+
const result = bonusResult.outcome.results[0].result;
|
|
127
|
+
if (result.prizeType === bonnys_fortune_types_1.PrizeType.BONUS) {
|
|
128
|
+
expect(result.triggeredBonus).toBeDefined();
|
|
129
|
+
expect(result.triggeredBonus.bonusId).toBeDefined();
|
|
130
|
+
expect(result.triggeredBonus.bonusType).toBeDefined();
|
|
131
|
+
return; // Test passed
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// If no BONUS prize found in 20 attempts, that's also valid (multipliers are more common)
|
|
135
|
+
expect(true).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
it('should add triggered bonus to pendingBonuses for chaining', async () => {
|
|
138
|
+
// Test the chaining mechanism by checking privateState
|
|
139
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
140
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
141
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
142
|
+
if (!debugResult.success)
|
|
143
|
+
return;
|
|
144
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
145
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
146
|
+
expect(bonusResult.success).toBe(true);
|
|
147
|
+
const finalState = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
|
|
148
|
+
const result = bonusResult.outcome.results[0].result;
|
|
149
|
+
if (result.prizeType === bonnys_fortune_types_1.PrizeType.BONUS) {
|
|
150
|
+
// Should have pending bonus for chaining
|
|
151
|
+
expect(finalState.privateState.pendingBonuses.length).toBe(1);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// No pending bonus for multiplier prizes
|
|
155
|
+
expect(finalState.privateState.pendingBonuses.length).toBe(0);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
describe('Complete Bonus Flow', () => {
|
|
160
|
+
it('should complete steering fortune and determine next state', async () => {
|
|
161
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
162
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
163
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
164
|
+
expect(debugResult.success).toBe(true);
|
|
165
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
166
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
167
|
+
expect(bonusResult.success).toBe(true);
|
|
168
|
+
const finalState = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
|
|
169
|
+
expect(finalState.privateState.nextSpinType).toBeDefined();
|
|
170
|
+
});
|
|
171
|
+
it('should return to BASE_GAME_SPIN for multiplier prizes', async () => {
|
|
172
|
+
// Run with different seeds until we get a multiplier prize
|
|
173
|
+
for (let seed = 0; seed < 50; seed++) {
|
|
174
|
+
(0, test_engine_factory_1.resetCommandIdCounter)();
|
|
175
|
+
const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(seed * 100);
|
|
176
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
177
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
178
|
+
if (!debugResult.success)
|
|
179
|
+
continue;
|
|
180
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
181
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
182
|
+
if (!bonusResult.success)
|
|
183
|
+
continue;
|
|
184
|
+
const result = bonusResult.outcome.results[0].result;
|
|
185
|
+
if (result.prizeType === bonnys_fortune_types_1.PrizeType.MULTIPLIER) {
|
|
186
|
+
const finalState = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
|
|
187
|
+
expect(finalState.privateState.nextSpinType).toBe(bonnys_fortune_types_1.SpinType.BASE_GAME_SPIN);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Skip if no multiplier found (weighted towards bonuses in config)
|
|
192
|
+
expect(true).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
it('should clear activeBonus after completion', async () => {
|
|
195
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
196
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
197
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
198
|
+
if (!debugResult.success)
|
|
199
|
+
return;
|
|
200
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
201
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
202
|
+
expect(bonusResult.success).toBe(true);
|
|
203
|
+
const finalState = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
|
|
204
|
+
expect(finalState.privateState.activeBonus).toBeUndefined();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe('Prize Tier Distribution', () => {
|
|
208
|
+
it('should produce valid prize values from wheel config', async () => {
|
|
209
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
210
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
211
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
212
|
+
if (!debugResult.success)
|
|
213
|
+
return;
|
|
214
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
215
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
216
|
+
expect(bonusResult.success).toBe(true);
|
|
217
|
+
const result = bonusResult.outcome.results[0].result;
|
|
218
|
+
if (result.prizeType === bonnys_fortune_types_1.PrizeType.MULTIPLIER) {
|
|
219
|
+
expect(typeof result.prizeValue).toBe('number');
|
|
220
|
+
expect(result.prizeValue).toBeGreaterThan(0);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// BONUS type - prizeValue should be the bonus type string
|
|
224
|
+
expect(typeof result.prizeValue).toBe('string');
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
it('should produce non-negative winnings', async () => {
|
|
228
|
+
const engine = (0, test_engine_factory_1.createEngine)();
|
|
229
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
230
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
231
|
+
if (!debugResult.success)
|
|
232
|
+
return;
|
|
233
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
234
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
235
|
+
expect(bonusResult.success).toBe(true);
|
|
236
|
+
expect(bonusResult.outcome.results[0].result.playerWinning).toBeGreaterThanOrEqual(0);
|
|
237
|
+
});
|
|
238
|
+
it('should scale winnings with bet amount for multiplier prizes', async () => {
|
|
239
|
+
const betAmounts = [1.0, 5.0, 10.0];
|
|
240
|
+
const winnings = [];
|
|
241
|
+
// Use same LCG seed to get same wheel outcome
|
|
242
|
+
for (const betAmount of betAmounts) {
|
|
243
|
+
(0, test_engine_factory_1.resetCommandIdCounter)();
|
|
244
|
+
const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(77777);
|
|
245
|
+
const session = await (0, test_engine_factory_1.initSession)(engine, betAmount);
|
|
246
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3', betAmount);
|
|
247
|
+
if (!debugResult.success)
|
|
248
|
+
continue;
|
|
249
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
250
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType, betAmount);
|
|
251
|
+
if (bonusResult.success) {
|
|
252
|
+
const result = bonusResult.outcome.results[0].result;
|
|
253
|
+
if (result.prizeType === bonnys_fortune_types_1.PrizeType.MULTIPLIER) {
|
|
254
|
+
winnings.push(result.playerWinning);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// If we got multiplier results, winnings should scale with bet
|
|
259
|
+
if (winnings.length >= 2) {
|
|
260
|
+
// Higher bet should produce higher or equal winnings
|
|
261
|
+
expect(winnings[1]).toBeGreaterThanOrEqual(winnings[0]);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
describe('RNG Determinism', () => {
|
|
266
|
+
it('should produce consistent results with same LCG seed', async () => {
|
|
267
|
+
const results = [];
|
|
268
|
+
for (let i = 0; i < 2; i++) {
|
|
269
|
+
(0, test_engine_factory_1.resetCommandIdCounter)();
|
|
270
|
+
const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(99999);
|
|
271
|
+
const session = await (0, test_engine_factory_1.initSession)(engine);
|
|
272
|
+
const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'bonusGame3');
|
|
273
|
+
if (!debugResult.success)
|
|
274
|
+
continue;
|
|
275
|
+
const bonus = debugResult.privateState.pendingBonuses[0];
|
|
276
|
+
const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
|
|
277
|
+
results.push(bonusResult.outcome.results[0].result);
|
|
278
|
+
}
|
|
279
|
+
expect(results.length).toBe(2);
|
|
280
|
+
expect(results[0].prizeType).toEqual(results[1].prizeType);
|
|
281
|
+
expect(results[0].prizeValue).toEqual(results[1].prizeValue);
|
|
282
|
+
expect(results[0].playerWinning).toEqual(results[1].playerWinning);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
//# sourceMappingURL=steering-fortune-handler.test.js.map
|