import './_planet.mjs'; import { test } from 'node:test'; import assert from 'node:assert/strict'; import { keyAction, exportName } from '../js/nav.js'; const k = (key, extra = {}) => keyAction({ key, target: { tagName: 'CANVAS' }, ...extra }); test('keys map to actions', () => { assert.deepEqual(k('ArrowLeft'), ['pan', -0.2, 0]); assert.deepEqual(k('ArrowDown'), ['pan', 0, 0.2]); assert.deepEqual(k('+'), ['zoom', 0.6]); assert.deepEqual(k('='), ['zoom', 0.6]); assert.deepEqual(k('-'), ['zoom', 1 / 0.6]); assert.deepEqual(k('Home'), ['home']); assert.deepEqual(k('f'), ['fullscreen']); assert.deepEqual(k('/'), ['search']); assert.equal(k('x'), null); }); test('typing and modifier chords are left alone', () => { for (const tagName of ['INPUT', 'TEXTAREA', 'SELECT']) assert.equal(keyAction({ key: 'ArrowLeft', target: { tagName } }), null); assert.equal(k('f', { ctrlKey: true }), null); assert.equal(k('ArrowUp', { metaKey: true }), null); assert.equal(k('-', { altKey: true }), null); }); test('export file names', () => { assert.equal(exportName({ layer: 'relief', over: '', view: 'globe' }), 'world-relief-globe.png'); assert.equal(exportName({ layer: 'relief', over: 'biomes', view: 'equal_earth' }), 'world-relief+biomes-equal_earth.png'); }); test('exports note procedural detail when tiles are showing', async () => { const { exportNotes } = await import('../js/nav.js'); assert.deepEqual(exportNotes({ view: { tiles: { active: true } } }), ['procedural detail — not data']); assert.deepEqual(exportNotes({ view: { tiles: { active: false } } }), []); assert.deepEqual(exportNotes({ view: {} }), []); }); test('Shift+arrows turn and tilt; plain arrows still pan; N points north', () => { const k = (key, o = {}) => keyAction({ key, target: { tagName: 'CANVAS' }, ...o }); assert.deepEqual(k('ArrowLeft', { shiftKey: true }), ['turn', -15, 0]); assert.deepEqual(k('ArrowUp', { shiftKey: true }), ['turn', 0, 10]); assert.deepEqual(k('ArrowLeft'), ['pan', -0.2, 0]); assert.deepEqual(k('n'), ['north']); assert.equal(k('n', { target: { tagName: 'INPUT' } }), null); }); test('G goes to ground view, ? shows the controls', () => { assert.deepEqual(k('g'), ['ground']); assert.deepEqual(k('?', { shiftKey: true }), ['help']); assert.equal(k('g', { target: { tagName: 'INPUT' } }), null); }); test('ground view: the eye above the spot looked at, close and tilted, heading kept', async () => { const { groundPose, GROUND_RANGE, GROUND_PITCH } = await import('../js/nav.js'); const ahead = GROUND_RANGE * Math.sin(GROUND_PITCH * Math.PI / 180) * 180 / Math.PI; // degrees of arc const n = groundPose({ lat: 0, lon: 10, range: 0.5, heading: 0, pitch: 0 }); assert.ok(Math.abs(n.lat - ahead) < 1e-9 && Math.abs(n.lon - 10) < 1e-9, 'looking north: the target lies ahead'); assert.equal(n.range, GROUND_RANGE); assert.equal(n.pitch, GROUND_PITCH); const e = groundPose({ lat: 0, lon: 10, range: 0.5, heading: 90, pitch: 0 }); assert.ok(Math.abs(e.lat) < 1e-9 && Math.abs(e.lon - 10 - ahead) < 1e-9 && e.heading === 90); assert.ok(GROUND_RANGE * 12742 < 5 && GROUND_PITCH >= 70); });