Good documentation lets anyone (including future-you) understand what code does. The game engine uses JSDoc-style comments throughout. From Character.js:
Code Runner Challenge
Add JSDoc comments to the class below. Every method needs a description, @param, and @returns tag.
View IPYNB Source
/**
* Character is a dynamic class that manages the data and events for objects like player and NPCs.
*
* @property {Object} position - The current position of the object.
* @property {Object} velocity - The current velocity of the object.
* @property {number} size - The size of the object.
* @method draw - Draws the object on the canvas.
* @method update - Updates the object's position each frame.
* @method destroy - Removes the object from the game environment.
*/
class Character extends GameObject {
/**
* @param {Object|null} data - The sprite data for the object. If null, a default red square is used.
* @param {Object|null} gameEnv - The game environment context.
*/
constructor(data = null, gameEnv = null) { ... }
}
Lines: 1
Characters: 0
Output
Click "Run" in code control panel to see output ...
And from Player.js β method-level JSDoc:
Code Runner Challenge
Test error handling. The first call hits a bad URL to trigger error handling. The second hits a good one.
View IPYNB Source
/**
* Handles key up events to stop the player's velocity.
* Removes the key from the active pressedKeys array.
*
* @param {Object} event - The keyup event object containing keyCode.
*/
handleKeyUp({ keyCode }) {
if (keyCode in this.pressedKeys) {
delete this.pressedKeys[keyCode];
}
this.updateVelocity();
this.updateDirection();
}
Lines: 1
Characters: 0
Output
Click "Run" in code control panel to see output ...
Comment density target: > 10% β for every ~10 lines of code there should be at least 1 line of comments.
%%js
//CODE_RUNNER: Add JSDoc comments to the class below. Every method needs a description, @param, and @returns tag.
/**
* ScoreTracker manages player score and high score for a game session.
*
* @property {number} score - Current session score.
* @property {number} highScore - All-time high score.
* @property {string} playerName - The player's display name.
*/
class ScoreTracker {
/**
* @param {string} playerName - Display name shown on leaderboard.
*/
constructor(playerName) {
this.playerName = playerName;
this.score = 0;
this.highScore = 0;
}
/**
* Adds points to the current score. Updates high score if beaten.
* @param {number} points - Points to add (must be positive).
* @returns {number} The updated score.
*/
addPoints(points) {
if (points > 0) this.score += points;
if (this.score > this.highScore) this.highScore = this.score;
return this.score;
}
// TODO: Add JSDoc for this method
reset() {
this.score = 0;
}
// TODO: Add JSDoc for this method
getSummary() {
return `${this.playerName}: Score=${this.score}, Best=${this.highScore}`;
}
}
const tracker = new ScoreTracker('Seonyoo');
tracker.addPoints(100);
tracker.addPoints(250);
console.log(tracker.getSummary());
tracker.reset();
tracker.addPoints(50);
console.log(tracker.getSummary());
2. Gameplay Testing β Level & Collision Verification
Manual gameplay testing checklist for the game engine:
| Test |
What to verify |
Pass criteria |
| Player movement |
W/A/S/D and arrow keys |
Player moves in correct direction, stops at boundary |
| Jump physics |
Press W with gravity enabled |
Player rises then falls naturally |
| Coin collision |
Walk into a coin |
Coin disappears, score increments |
| Enemy collision |
Shark touches player |
Explosion animation plays, level restarts |
| Level completion |
Reach end platform |
Transition to next level triggers |
| Boundary check |
Move to canvas edge |
Player doesnβt leave the screen |
From Shark.js β the collision handling code that must work correctly:
handleCollisionEvent() {
var player = this.gameEnv.gameObjects.find(obj => obj instanceof Player);
this.velocity.x = 0;
this.velocity.y = 0;
this.explode(player.position.x, player.position.y);
player.destroy();
this.playerDestroyed = true;
setTimeout(() => {
this.gameEnv.gameControl.currentLevel.restart = true;
}, 2000); // test: does the 2000ms delay feel right?
}
3. API Integration Testing
After wiring up the Leaderboard API, verify it works end-to-end:
// Integration test: POST a score, then GET leaderboard to confirm it saved
async function testLeaderboardIntegration() {
const testPayload = { playerName: 'TestUser', score: 9999 };
// Step 1: POST score
const postRes = await fetch(`${javaURI}/api/scores`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(testPayload)
});
console.log('POST status:', postRes.status); // expect 200 or 201
// Step 2: GET leaderboard and verify test entry appears
const getRes = await fetch(`${javaURI}/api/scores`, { credentials: 'include' });
const scores = await getRes.json();
const found = scores.find(s => s.playerName === 'TestUser' && s.score === 9999);
console.log('Score saved correctly:', !!found); // expect true
}
4. API Error Handling
Every fetch call needs a try/catch and an !response.ok check. From login.js:
fetch(options.URL, requestOptions)
.then(response => {
if (!response.ok) { // HTTP errors (4xx, 5xx)
const errorMsg = 'Login error: ' + response.status;
console.log(errorMsg);
document.getElementById(options.message).textContent = errorMsg;
return; // exit early
}
options.callback(); // success path
})
.catch(error => { // network errors (CORS, server down)
console.log('Possible CORS or Service Down error: ' + error);
document.getElementById(options.message).textContent =
'Possible CORS or service down error: ' + error;
});
%%js
//CODE_RUNNER: Test error handling. The first call hits a bad URL to trigger error handling. The second hits a good one.
async function fetchWithErrorHandling(url, label) {
try {
const response = await fetch(url);
if (!response.ok) {
// HTTP error β server responded but with error code
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log(`[${label}] SUCCESS β got data:`, Object.keys(data));
return data;
} catch (error) {
// Catches both network failures AND our thrown HTTP errors
console.error(`[${label}] ERROR:`, error.message);
return null;
}
}
// Test 1: bad endpoint
await fetchWithErrorHandling(
'https://official-joke-api.appspot.com/jokes/does_not_exist',
'Bad endpoint'
);
// Test 2: working endpoint
await fetchWithErrorHandling(
'https://official-joke-api.appspot.com/random_joke',
'Good endpoint'
);
Summary
| Area |
What to do |
Tool |
| Documentation |
JSDoc /** */ on every class + method; > 10% comment density |
Code review |
| Gameplay testing |
Play through level; check collision, movement, level transitions |
Live demo |
| Integration testing |
POST score β GET leaderboard; confirm AI NPC responds |
DevTools Network tab |
| API error handling |
try/catch + !response.ok on every fetch |
Code review |