update tests
Sonarqube Scanner / Prepare environment (push) Successful in 14s
Sonarqube Scanner / Build and test (push) Successful in 35s
Sonarqube Scanner / SonarQube analysis (push) Successful in 1m37s
Sonarqube Scanner / Deploy to Server (push) Successful in 8s

This commit is contained in:
Florian Zumpe
2026-09-30 10:00:05 +02:00
parent c99a2e66fc
commit 6ecffb8137
2 changed files with 316 additions and 0 deletions
+160
View File
@@ -402,3 +402,163 @@ test('route control closes on escape and reports local storage failures', async
harness.globalListeners.get('pageshow')?.({});
assert.ok(harness.node('#route-control-local-list').appended.join('').includes('LocalStorage nicht lesbar'));
});
async function selectServer(setup) {
const button = new FakeNode('server-select');
button.dataValues.set('route-id', 'server-1');
await setup.harness.activate('[data-route-select]', button);
}
function observeSensors(setup) {
const calls = { stopped: 0, vibrations: 0, audio: [], slides: [] };
const ns = setup.context.Wegwichtel;
ns.Geo.start = (position, error) => { calls.position = position; calls.error = error; };
ns.Geo.stop = () => { calls.stopped += 1; };
ns.Orientation.start = async heading => { calls.heading = heading; return true; };
ns.Orientation.stop = () => { calls.stopped += 1; };
ns.Vibration.start = () => { calls.vibrations += 1; };
ns.AudioPlayer.load = url => calls.audio.push(url);
ns.Slideshow.show = images => calls.slides.push(images);
return calls;
}
test('tracking triggers each POI once, records media progress and pauses/resumes/stops sensors', async () => {
const setup = await loadApp();
const { context, harness, savedStates } = setup;
const calls = observeSensors(setup);
await context.Wegwichtel.App.initialize({ markStep() {} });
await selectServer(setup);
await harness.activate('#start-route', new FakeNode('start'));
assert.equal(harness.node('#pause-route').properties.get('disabled'), false);
calls.position({ lat: 50, lon: 10, accuracy: 5, heading: 90, speed: 1 });
assert.equal(harness.node('#poi-title').textValue, 'Serverweg Start');
assert.equal(calls.vibrations, 1);
assert.match(harness.node('#navigation-mode').textValue, /Serverweg Ziel/);
calls.position({ lat: 50, lon: 10, accuracy: 5 });
assert.equal(calls.vibrations, 1);
harness.$('#poi-audio').trigger('play');
assert.deepEqual(Array.from(savedStates.at(-1)[5]), [1]);
calls.heading(350);
calls.heading(10);
assert.match(harness.node('#navigation-arrow').styles.get('transform'), /rotate\(50\.0deg\)/);
calls.error(new Error('Signal verloren'));
assert.equal(harness.node('#tracking-status').textValue, 'GPS-Fehler: Signal verloren');
await harness.activate('#pause-route', new FakeNode('pause'));
assert.match(harness.node('#tracking-status').textValue, /pausiert/);
assert.equal(savedStates.at(-1)[1], 'paused');
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('#route-control-next').textValue, 'Alle Streckenpunkte erreicht');
assert.equal(harness.node('#navigation-distance').textValue, '0 m');
await harness.activate('#stop-route', new FakeNode('stop'));
assert.equal(savedStates.at(-1)[1], 'idle');
assert.equal(harness.node('#route-control-title').textValue, 'Route wählen');
assert.equal(harness.node('#navigation-footer').properties.get('hidden'), true);
assert.ok(calls.stopped >= 4);
});
test('saved route resumes paused, manual POI viewing and lifecycle events persist progress', async () => {
const setup = await loadApp();
const { context, harness, savedStates } = setup;
context.Wegwichtel.PrivacyStorage.activateRoute = () => ({
routeState: 'running', routeProgressIndex: 0,
visitedPoiIds: [1], viewedPoiIds: [1], playedAudioPoiIds: [1]
});
const calls = observeSensors(setup);
await context.Wegwichtel.App.initialize({ markStep() {} });
await selectServer(setup);
assert.match(harness.node('#tracking-status').textValue, /Gespeicherter/);
assert.equal(harness.node('#start-route').attributes.get('title'), 'Route fortsetzen');
const poi = new FakeNode('poi');
poi.dataValues.set('poi-id', 2);
await harness.key('[data-poi-select]', poi, ' ');
assert.equal(harness.node('#poi-title').textValue, 'Serverweg Ziel');
assert.deepEqual(Array.from(savedStates.at(-1)[4]), [1, 2]);
await harness.activate('#start-route', new FakeNode('resume'));
calls.position({ lat: 50, lon: 10, accuracy: 5 });
assert.equal(calls.vibrations, 0);
harness.globalListeners.get('pagehide')();
harness.document.visibilityState = 'hidden';
harness.document.dispatchEvent(new Event('visibilitychange'));
const enabled = new Event('wegwichtel:progress-storage-changed');
Object.defineProperty(enabled, 'detail', { value: { enabled: true } });
const before = savedStates.length;
harness.document.dispatchEvent(enabled);
assert.equal(savedStates.length, before + 1);
harness.globalListeners.get('popstate')({ state: { page: '#route-page' } });
assert.equal(harness.node('#route-page').attributes.has('hidden'), false);
await harness.activate('#stop-route', new FakeNode('stop'));
});
test('tracking handles an empty route and orientation permission resolving after pause', async () => {
const setup = await loadApp();
const { context, harness } = setup;
setup.serverRoute.pois = [];
setup.serverRoute.points = [];
const calls = observeSensors(setup);
let grant;
context.Wegwichtel.Orientation.start = () => new Promise(resolve => { grant = resolve; });
await context.Wegwichtel.App.initialize({ markStep() {} });
await selectServer(setup);
assert.match(harness.node('#poi-list').appended.join(''), /keine Streckenpunkte/);
await harness.activate('#start-route', new FakeNode('start'));
calls.position({ lat: 50, lon: 10, accuracy: 10 });
assert.equal(harness.node('#navigation-mode').textValue, 'Keine Navigationspunkte vorhanden');
await harness.activate('#pause-route', new FakeNode('pause'));
const stopped = calls.stopped;
grant(true);
await tick();
assert.equal(calls.stopped, stopped + 1);
assert.equal(harness.node('#navigation-mode').textValue, 'Route pausiert');
await harness.activate('#stop-route', new FakeNode('stop'));
});
test('route recommendations and accent-insensitive search use location without changing selection', async () => {
const setup = await loadApp();
const { context, harness } = setup;
context.Wegwichtel.Geo.current = async () => ({ lat: 50, lon: 10, accuracy: 8 });
const far = route('far', 'Äpfelweg');
far.start = { lat: 51, lon: 10 };
context.Wegwichtel.Api.routes = async () => ({ routes: [far, setup.serverRoute, null, {}] });
await context.Wegwichtel.App.initialize({ markStep() {} });
assert.match(harness.node('#location-hint').textValue, /Standort ermittelt/);
assert.match(harness.node('#nearby-route-list').appended.join(''), /Serverweg/);
assert.doesNotMatch(harness.node('#nearby-route-list').appended.join(''), /Äpfelweg/);
const position = context.Wegwichtel.App.currentPosition();
position.lat = 0;
assert.equal(context.Wegwichtel.App.currentPosition().lat, 50);
harness.$('#route-search').val('apfel').trigger('input');
assert.match(harness.node('#all-routes-summary').textValue, /1 von 2/);
let suggestions;
const autocomplete = harness.node('#route-search').autocompleteOptions;
autocomplete.source({ term: 'apfel' }, items => { suggestions = items; });
assert.equal(suggestions[0].value, 'Äpfelweg');
autocomplete.select({}, { item: { value: 'Serverweg' } });
assert.match(harness.node('#all-route-list').appended.join(''), /Serverweg/);
harness.$('#route-search').val('unbekannt').trigger('input');
assert.match(harness.node('#all-route-list').appended.join(''), /Keine Route entspricht/);
await harness.activate('#clear-route-search', new FakeNode('clear'));
assert.equal(harness.node('#route-search').value, '');
});
test('invalid API responses reject initialization and route selection errors restore the button', async () => {
const setup = await loadApp();
const { context, harness } = setup;
context.Wegwichtel.Api.routes = async () => ({ routes: null });
await assert.rejects(context.Wegwichtel.App.initialize({ markStep() {} }), /gültige Routenliste/);
const errors = [];
context.alert = message => errors.push(message);
context.Wegwichtel.Api.route = async () => { throw { responseJSON: { message: 'Strecke entfernt' } }; };
const button = new FakeNode('missing');
button.dataValues.set('route-id', 'missing');
await harness.activate('[data-route-select]', button, { isPrimary: false });
assert.equal(errors.length, 0);
await harness.activate('[data-route-select]', button, { pointerType: 'mouse', button: 2 });
assert.equal(errors.length, 0);
await harness.key('[data-route-select]', button, 'Escape');
assert.equal(errors.length, 0);
await harness.activate('[data-route-select]', button);
assert.deepEqual(errors, ['Strecke entfernt']);
assert.equal(button.properties.get('disabled'), false);
});