feat(player-ui): add pre-reader controls and onboarding
This commit is contained in:
@@ -22,6 +22,56 @@ test("keyboard and swipe controls produce equivalent directions", () => {
|
||||
assert.equal(player.directionFromSwipe(0, 0, 12, 4), null);
|
||||
});
|
||||
|
||||
test("joystick produces only cardinal, bounded movement intentions", () => {
|
||||
assert.equal(player.joystickDirection(10, 10, null), null);
|
||||
assert.equal(player.joystickDirection(44, 8, null), "east");
|
||||
assert.equal(player.joystickDirection(-8, -44, null), "north");
|
||||
assert.equal(player.joystickDirection(42, 38, "east"), "east");
|
||||
assert.equal(player.joystickDirection(38, 42, "north"), "south");
|
||||
const vector = player.joystickVector(300, 0, 57, null);
|
||||
assert.equal(vector.direction, "east");
|
||||
assert.equal(vector.x, 57);
|
||||
assert.equal(vector.y, 0);
|
||||
});
|
||||
|
||||
test("joystick repeat interval is monotonic and remains slower than cooldown", () => {
|
||||
assert.equal(player.joystickRepeatMs(player.JOYSTICK_DEAD_ZONE, 60), null);
|
||||
const near = player.joystickRepeatMs(25, 60);
|
||||
const far = player.joystickRepeatMs(60, 60);
|
||||
assert.ok(near > far);
|
||||
assert.ok(far >= player.JOYSTICK_FAST_REPEAT_MS);
|
||||
assert.ok(player.JOYSTICK_FAST_REPEAT_MS > 150);
|
||||
});
|
||||
|
||||
test("player map cells enlarge small projections without exceeding a readable bound", () => {
|
||||
const sevenBySeven = player.playerCellSize(396, 730, 7, 7);
|
||||
const fourByFour = player.playerCellSize(396, 730, 4, 4);
|
||||
assert.ok(sevenBySeven >= 46);
|
||||
assert.ok(fourByFour > sevenBySeven);
|
||||
assert.ok(fourByFour <= 72);
|
||||
});
|
||||
|
||||
test("onboarding has bounded, replayable steps", () => {
|
||||
assert.equal(player.ONBOARDING_STEPS.length, 8);
|
||||
assert.equal(player.nextOnboardingStep(0), 1);
|
||||
assert.equal(player.nextOnboardingStep(6), 7);
|
||||
assert.equal(player.nextOnboardingStep(7), null);
|
||||
});
|
||||
|
||||
test("child controls reset safely and retain accessible alternatives", () => {
|
||||
const html = fs.readFileSync(path.join(project, "web/index.html"), "utf8");
|
||||
const script = fs.readFileSync(path.join(project, "web/player.js"), "utf8");
|
||||
assert.match(script, /addEventListener\("pointerup", stopJoystick\)/);
|
||||
assert.match(script, /addEventListener\("pointercancel", stopJoystick\)/);
|
||||
assert.match(script, /addEventListener\("blur", resetJoystick\)/);
|
||||
assert.match(script, /connectionState !== "online"\) resetJoystick\(\)/);
|
||||
assert.match(script, /snapshot\.phase === "paused"\) \{ resetJoystick\(\)/);
|
||||
assert.match(script, /setMuted\(!state\.muted\)/);
|
||||
assert.match(script, /setReducedMotion\(!state\.reducedMotion\)/);
|
||||
assert.match(script, /onboarding-replay/);
|
||||
assert.match(html, /id="onboarding-dots"[\s\S]*?<span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span>/);
|
||||
});
|
||||
|
||||
test("frontend name suggestions randomize both words and remain bounded", () => {
|
||||
const picks = [3, 4];
|
||||
const suggestion = player.randomSuggestedName([], () => picks.shift());
|
||||
@@ -112,6 +162,12 @@ test("player assets are local, Russian, accessible, and responsive", () => {
|
||||
assert.match(css, /@media \(min-width: 721px\) and \(max-width: 980px\)/);
|
||||
assert.match(css, /height: calc\(100dvh - 78px\)/);
|
||||
assert.match(css, /\.dpad \{ display: none; \}/);
|
||||
assert.match(html, /id="joystick"/);
|
||||
assert.match(html, /id="onboarding"/);
|
||||
assert.match(html, /id="mute-toggle"/);
|
||||
assert.match(css, /\.joystick \{[^}]*width: 180px; height: 180px/);
|
||||
assert.match(script, /resetJoystick/);
|
||||
assert.match(script, /playerCellSize/);
|
||||
assert.match(css, /\(hover: none\) and \(pointer: coarse\) and \(max-height: 720px\)/);
|
||||
assert.match(icons, /id="key"/);
|
||||
assert.match(icons, /id="maze"/);
|
||||
|
||||
Reference in New Issue
Block a user