Testing Guide
Reference

How to test your game locally before uploading. Mock platform messages, simulate responses, and catch bugs early.

Preview Mode

The easiest way to test is the platform's built-in preview sandbox. Go to Dashboard → My Games → Create New Game, select your HTML file, and click Preview. This gives you:

FeatureDetails
Test balance$1,000 test balance (no real money)
Same APIAll postMessage APIs work identically to production
window.TEST_MODESet to true so your game can detect preview mode
window.PREVIEW_MODEAlso set to true
GAME_CONFIG_FOR_APIInjected so you can include it in messages for validation

Local Testing (Without Platform)

You can test your game's UI and logic locally by mocking the platform's postMessage responses. Add this script to your HTML file during development, then remove it before uploading:

1<!-- Add this BEFORE your game script during local dev -->
2<!-- REMOVE before uploading to the platform -->
3<script>
4(function() {
5 // Mock platform variables
6 window.GAME_STAKE = 10;
7 window.GAME_STAKE_USD = 10;
8 window.GAME_CURRENCY = 'USDT';
9 window.TEST_MODE = true;
10 window.PREVIEW_MODE = true;
11
12 // Intercept postMessages and respond with mock data
13 window.addEventListener('message', function(e) {
14 var d = e.data;
15 if (!d || !d.type) return;
16
17 // Mock one-shot bet
18 if (d.type === 'bet') {
19 var multipliers = window.GAME_CONFIG?.multipliers || [0, 2];
20 var pick = multipliers[Math.floor(Math.random() * multipliers.length)];
21 window.postMessage({
22 type: 'betResult',
23 id: d.id,
24 result: {
25 multiplier: pick,
26 result: pick > 1 ? 'WIN' : pick === 1 ? 'PUSH' : 'LOSS',
27 payout: d.stake * pick,
28 payoutUsd: d.stake * pick,
29 profit: d.stake * (pick - 1),
30 profitUsd: d.stake * (pick - 1),
31 balance: 100
32 }
33 }, '*');
34 }
35
36 // Mock path start
37 if (d.type === 'pathStart') {
38 window.postMessage({
39 id: d.id,
40 sessionId: 'mock-' + Date.now(),
41 positionHash: 'mock-hash',
42 gridSize: window.GAME_CONFIG?.totalChoices || 25,
43 mines: window.GAME_CONFIG?.losingChoices || 3,
44 maxSteps: 22,
45 replacement: window.GAME_CONFIG?.replacement || false,
46 multipliers: [
47 { step: 1, multiplier: 1.03, survivalProb: 0.88 },
48 { step: 2, multiplier: 1.07, survivalProb: 0.88 }
49 ],
50 stake: d.stake,
51 stakeUsd: d.stake,
52 currency: d.currency
53 }, '*');
54 }
55
56 // Mock path reveal (random safe/hazard)
57 if (d.type === 'pathReveal') {
58 var safe = Math.random() > 0.12;
59 if (safe) {
60 window.postMessage({
61 id: d.id,
62 survived: true,
63 step: 1,
64 multiplier: 1.03,
65 potentialPayout: d.stake * 1.03,
66 potentialPayoutUsd: d.stake * 1.03,
67 nextMultiplier: 1.07,
68 nextSurvivalProb: 0.88,
69 revealedTiles: [d.position],
70 canCashout: true,
71 canContinue: true,
72 gameOver: false
73 }, '*');
74 } else {
75 window.postMessage({
76 id: d.id,
77 survived: false,
78 hitMine: true,
79 multiplier: 0,
80 payout: 0,
81 minePositions: [3, 12, 19],
82 serverSeed: 'mock-seed',
83 gameOver: true
84 }, '*');
85 }
86 }
87
88 // Mock multiplier start
89 if (d.type === 'multiplierStart') {
90 window.postMessage({
91 id: d.id,
92 sessionId: 'mock-' + Date.now(),
93 commitHash: 'mock-hash',
94 serverSeedHash: 'mock-seed-hash',
95 curve: window.GAME_CONFIG?.curve || 'exponential',
96 growthRate: window.GAME_CONFIG?.growthRate || 0.1386,
97 maxMultiplier: window.GAME_CONFIG?.maxMultiplier || 1000000,
98 startTime: Date.now(),
99 stake: d.stake,
100 stakeUsd: d.stake
101 }, '*');
102
103 // Auto-crash after 3–10 seconds
104 var crashDelay = 3000 + Math.random() * 7000;
105 var rate = window.GAME_CONFIG?.growthRate || 0.1386;
106 setTimeout(function() {
107 var crashMult = Math.exp(rate * (crashDelay / 1000));
108 window.postMessage({
109 type: 'serverCrash',
110 crashMultiplier: parseFloat(crashMult.toFixed(2)),
111 serverSeed: 'mock-seed',
112 commitHash: 'mock-hash'
113 }, '*');
114 }, crashDelay);
115 }
116
117 // Mock multiplier cashout
118 if (d.type === 'multiplierCashout') {
119 window.postMessage({
120 id: d.id,
121 success: true,
122 multiplier: 1.5,
123 payout: d.stake * 1.5,
124 payoutUsd: d.stake * 1.5,
125 profit: d.stake * 0.5,
126 profitUsd: d.stake * 0.5,
127 crashPoint: 5.67,
128 serverSeed: 'mock-seed',
129 commitHash: 'mock-hash',
130 gameOver: true
131 }, '*');
132 }
133
134 // Mock state machine start
135 if (d.type === 'stateMachineStart') {
136 var gen = window.GAME_GENERATOR;
137 var initial = gen?.initialStates?.() || [[['START', 0], 1.0, 0, null]];
138 var st = initial[0][0];
139 window.postMessage({
140 id: d.id,
141 sessionId: 'mock-' + Date.now(),
142 currentState: st,
143 allowedActions: gen?.allowedActions?.(st) || [],
144 totalWager: 1,
145 status: 'playing',
146 commitHash: 'mock-hash',
147 stake: d.stake,
148 stakeUsd: d.stake
149 }, '*');
150 }
151
152 // Mock state machine action
153 if (d.type === 'stateMachineAction') {
154 var gen2 = window.GAME_GENERATOR;
155 // Pick a random transition
156 var transitions = gen2?.transitions?.(['START', 0], d.action) || [];
157 if (transitions.length > 0) {
158 var r = Math.random(), cumul = 0;
159 var picked = transitions[0];
160 for (var i = 0; i < transitions.length; i++) {
161 cumul += transitions[i][1];
162 if (r <= cumul) { picked = transitions[i]; break; }
163 }
164 var nextState = picked[0];
165 var payout = picked[3];
166 var isOver = payout !== null;
167 window.postMessage({
168 id: d.id,
169 currentState: nextState,
170 allowedActions: isOver ? [] : (gen2?.allowedActions?.(nextState) || []),
171 totalWager: 1,
172 totalPayout: payout || 0,
173 payoutMultiplier: payout || 0,
174 payoutUsd: (payout || 0) * (d.stake || 1),
175 serverSeed: isOver ? 'mock-seed' : undefined,
176 gameOver: isOver,
177 status: isOver ? 'finished' : 'playing'
178 }, '*');
179 }
180 }
181 });
182
183 console.log('[Mock Platform] Local testing active — remove before upload');
184})();
185</script>
Remove the mock script before uploading. The platform will provide all these responses in production. Leaving the mock in will cause duplicate responses.

What to Test

TestHow
Config is validUpload to preview — the platform validates on upload and shows errors
Win and loss flowsUse mock or preview mode, verify both WIN and LOSS UI paths
Error handlingTemporarily return errors in mock to verify your try/catch works
Session restoreStart a path/multiplier/state-machine game, refresh the page, verify sessionResume restores UI
Stake updatesChange bet amount in platform UI, verify your game reflects it
Rapid clicksClick bet/action buttons rapidly — verify rate limiting is handled gracefully
PVP (two tabs)Open two browser tabs in preview mode to simulate both players

Simulating Errors

Add temporary error responses to your mock to test error handling:

1// Add inside the mock 'bet' handler to test error path:
2if (Math.random() < 0.3) {
3 window.postMessage({
4 type: 'betResult',
5 id: d.id,
6 result: { error: 'Insufficient balance' }
7 }, '*');
8 return;
9}

Debugging Tips

Log all messagesAdd window.addEventListener('message', e => console.log('MSG:', e.data)) at the top of your script to see every message.
Check GAME_CONFIGOpen console and type window.GAME_CONFIG to verify it's set correctly.
Check platform varsType window.GAME_STAKE, window.TEST_MODE, etc. to verify injection.
Network tabpostMessages don't show in the Network tab — use the console listener above.
iframe sandboxIf testing locally, open your HTML file directly in the browser (not inside an iframe) with the mock script.
The preview sandbox is the most reliable way to test. Use local mocking only for rapid UI iteration — always do a final test in the platform preview before uploading.