overhaul gpx creation and usage
This commit is contained in:
@@ -234,6 +234,16 @@ async function loadApp({ language = 'de-DE' } = {}) {
|
||||
const savedStates = [];
|
||||
const editor = { opened: 0, refreshed: 0 };
|
||||
const apiCalls = [];
|
||||
const frames = [];
|
||||
const animationTimers = new Map();
|
||||
let animationTimerId = 0;
|
||||
function finishAnimations() {
|
||||
while (frames.length) frames.shift()();
|
||||
for (const [id, callback] of animationTimers) {
|
||||
animationTimers.delete(id);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
harness.node('#route-control-dropdown').properties.set('hidden', true);
|
||||
harness.node('#route-search').value = '';
|
||||
@@ -284,7 +294,9 @@ async function loadApp({ language = 'de-DE' } = {}) {
|
||||
Vibration: { Patterns: { ACTIVE_POI: [100] }, start() {}, stop() {} }
|
||||
},
|
||||
alert() {},
|
||||
clearTimeout,
|
||||
clearTimeout(id) {
|
||||
if (!animationTimers.delete(id)) clearTimeout(id);
|
||||
},
|
||||
history: {
|
||||
state: null,
|
||||
back() {},
|
||||
@@ -292,7 +304,13 @@ async function loadApp({ language = 'de-DE' } = {}) {
|
||||
replaceState(state) { this.state = state; }
|
||||
},
|
||||
scrollTo() {},
|
||||
setTimeout,
|
||||
requestAnimationFrame: callback => frames.push(callback),
|
||||
setTimeout(callback, delay) {
|
||||
if (delay !== 180) return setTimeout(callback, delay);
|
||||
const id = --animationTimerId;
|
||||
animationTimers.set(id, callback);
|
||||
return id;
|
||||
},
|
||||
structuredClone,
|
||||
globalThis: null
|
||||
};
|
||||
@@ -309,6 +327,7 @@ async function loadApp({ language = 'de-DE' } = {}) {
|
||||
|
||||
return {
|
||||
apiCalls,
|
||||
finishAnimations,
|
||||
context,
|
||||
editor,
|
||||
harness,
|
||||
@@ -329,6 +348,39 @@ test('English browser settings localize app controls and retain user-authored tr
|
||||
assert.ok(harness.node('#local-route-list').appended.join('').includes('Lokaler Weg'));
|
||||
});
|
||||
|
||||
test('route menu animates opening and closing and can reopen during closing', async () => {
|
||||
const setup = await loadApp();
|
||||
const { context, harness } = setup;
|
||||
await context.Wegwichtel.App.initialize({ markStep() {} });
|
||||
const button = new FakeNode('toggle');
|
||||
const dropdown = harness.node('#route-control-dropdown');
|
||||
|
||||
await harness.activate('#route-control-button', button);
|
||||
assert.equal(dropdown.properties.get('hidden'), false);
|
||||
assert.equal(dropdown.classes.has('is-open'), false);
|
||||
setup.finishAnimations();
|
||||
assert.equal(dropdown.classes.has('is-open'), true);
|
||||
|
||||
await harness.activate('#route-control-button', button);
|
||||
assert.equal(dropdown.classes.has('is-open'), false);
|
||||
assert.equal(dropdown.properties.get('hidden'), false);
|
||||
assert.equal(harness.node('#route-control-button').attributes.get('aria-expanded'), 'false');
|
||||
await harness.activate('#route-control-button', button);
|
||||
setup.finishAnimations();
|
||||
assert.equal(dropdown.classes.has('is-open'), true);
|
||||
assert.equal(dropdown.properties.get('hidden'), false);
|
||||
|
||||
await harness.activate('#route-control-button', button);
|
||||
setup.finishAnimations();
|
||||
assert.equal(dropdown.properties.get('hidden'), true);
|
||||
|
||||
await harness.activate('#route-control-button', button);
|
||||
harness.fireDocumentKey('Escape');
|
||||
setup.finishAnimations();
|
||||
assert.equal(dropdown.properties.get('hidden'), true);
|
||||
assert.equal(dropdown.classes.has('is-open'), false);
|
||||
});
|
||||
|
||||
test('route control runtime loads server/local routes and supports switching without geolocation', async () => {
|
||||
const setup = await loadApp();
|
||||
const { context, harness, apiCalls, editor } = setup;
|
||||
@@ -352,6 +404,7 @@ test('route control runtime loads server/local routes and supports switching wit
|
||||
const newButton = new FakeNode('#route-control-new');
|
||||
await harness.activate('.route-control-actions #route-control-new', newButton);
|
||||
assert.equal(editor.opened, 1);
|
||||
setup.finishAnimations();
|
||||
assert.equal(harness.node('#route-control-dropdown').properties.get('hidden'), true);
|
||||
|
||||
const localButton = new FakeNode('local-select');
|
||||
@@ -409,6 +462,7 @@ test('route control closes on escape and reports local storage failures', async
|
||||
await harness.activate('#route-control-button', new FakeNode('toggle'));
|
||||
assert.equal(harness.node('#route-control-dropdown').properties.get('hidden'), false);
|
||||
harness.fireDocumentKey('Escape');
|
||||
setup.finishAnimations();
|
||||
assert.equal(harness.node('#route-control-dropdown').properties.get('hidden'), true);
|
||||
|
||||
context.Wegwichtel.LocalRoutes.listAppRoutes = () => { throw new Error('LocalStorage nicht lesbar'); };
|
||||
@@ -443,7 +497,17 @@ test('tracking triggers each POI once, records media progress and pauses/resumes
|
||||
await selectServer(setup);
|
||||
await harness.activate('#start-route', new FakeNode('start'));
|
||||
assert.equal(harness.node('#pause-route').properties.get('disabled'), false);
|
||||
const bearingTargets = [];
|
||||
context.Wegwichtel.Distance.bearing = (position, target) => {
|
||||
bearingTargets.push(target);
|
||||
return target.title ? 45 : 120;
|
||||
};
|
||||
calls.position({ lat: 50, lon: 10, accuracy: 5, heading: 90, speed: 1 });
|
||||
assert.equal(harness.node('#route-navigation-arrow').properties.get('hidden'), false);
|
||||
assert.equal(harness.node('#navigation-arrow').properties.get('hidden'), false);
|
||||
assert.notEqual(harness.node('#route-navigation-arrow').styles.get('transform'), harness.node('#navigation-arrow').styles.get('transform'));
|
||||
assert.ok(bearingTargets.some(target => target.title));
|
||||
assert.ok(bearingTargets.some(target => !target.title));
|
||||
assert.equal(harness.node('#poi-title').textValue, 'Serverweg Start');
|
||||
assert.equal(calls.vibrations, 1);
|
||||
assert.match(harness.node('#navigation-mode').textValue, /Serverweg Ziel/);
|
||||
@@ -459,10 +523,13 @@ test('tracking triggers each POI once, records media progress and pauses/resumes
|
||||
await harness.activate('#pause-route', new FakeNode('pause'));
|
||||
assert.match(harness.node('#tracking-status').textValue, /Du machst eine Pause/);
|
||||
assert.equal(savedStates.at(-1)[1], 'paused');
|
||||
assert.equal(harness.node('#route-navigation-arrow').properties.get('hidden'), true);
|
||||
assert.equal(harness.node('#navigation-arrow').properties.get('hidden'), true);
|
||||
await harness.activate('#start-route', new FakeNode('resume'));
|
||||
calls.position({ lat: 50.001, lon: 10.001, accuracy: 5 });
|
||||
assert.equal(calls.vibrations, 2);
|
||||
assert.equal(harness.node('#navigation-distance').textValue, '0 m');
|
||||
assert.equal(harness.node('#navigation-distance').textValue, '–');
|
||||
assert.equal(harness.node('#route-navigation-mode').textValue, 'Alle Stationen und das Ziel erreicht');
|
||||
await harness.activate('#stop-route', new FakeNode('stop'));
|
||||
assert.equal(savedStates.at(-1)[1], 'idle');
|
||||
assert.equal(harness.node('#navigation-footer').properties.get('hidden'), true);
|
||||
@@ -515,7 +582,7 @@ test('tracking handles an empty route and orientation permission resolving after
|
||||
assert.match(harness.node('#poi-list').appended.join(''), /keine Stationen/);
|
||||
await harness.activate('#start-route', new FakeNode('start'));
|
||||
calls.position({ lat: 50, lon: 10, accuracy: 10 });
|
||||
assert.equal(harness.node('#navigation-mode').textValue, 'Der Weg dieser Strecke fehlt.');
|
||||
assert.equal(harness.node('#route-navigation-mode').textValue, 'Der Weg dieser Strecke fehlt.');
|
||||
await harness.activate('#pause-route', new FakeNode('pause'));
|
||||
const stopped = calls.stopped;
|
||||
grant(true);
|
||||
|
||||
Reference in New Issue
Block a user