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
+156
View File
@@ -0,0 +1,156 @@
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import test from 'node:test';
import vm from 'node:vm';
async function load(name, options = {}) {
const filename = path.resolve(import.meta.dirname, '../public/js', name);
const context = { Wegwichtel: { Config: { apiBase: '/api', routeRadiusKm: 5, geolocationTimeoutMs: 7000 } }, ...options };
context.globalThis = context;
vm.runInNewContext(await fs.readFile(filename, 'utf8'), context, { filename });
return context;
}
const rawPosition = {
coords: { latitude: 50, longitude: 10, accuracy: 5, altitude: null, heading: 90, speed: 2 },
timestamp: 1234
};
test('GPS normalizes positions, forwards errors and clears replaced watches including watch zero', async () => {
const cleared = [];
let watchSuccess;
let watchFailure;
let currentOptions;
let watchOptions;
let watch = 0;
const error = new Error('GPS verweigert');
const service = {
getCurrentPosition(success, failure, options) { currentOptions = options; success(rawPosition); },
watchPosition(success, failure, options) {
watchSuccess = success; watchFailure = failure; watchOptions = options;
return watch++;
},
clearWatch(id) { cleared.push(id); }
};
const { Wegwichtel: ns } = await load('geolocation.js', { navigator: { geolocation: service } });
const current = await ns.Geo.current();
assert.equal(current.lat, 50);
assert.equal(current.lon, 10);
assert.equal(current.timestamp, 1234);
assert.equal(current.altitude, null);
assert.equal(currentOptions.timeout, 7000);
assert.equal(currentOptions.maximumAge, 30000);
service.getCurrentPosition = (success, failure) => failure(error);
await assert.rejects(ns.Geo.current(), value => value === error);
const positions = [];
const errors = [];
ns.Geo.start(value => positions.push(value), value => errors.push(value));
watchSuccess(rawPosition);
watchFailure(error);
assert.equal(positions[0].heading, 90);
assert.equal(positions[0].speed, 2);
assert.equal(watchOptions.enableHighAccuracy, true);
assert.equal(watchOptions.timeout, 20000);
assert.deepEqual(errors, [error]);
ns.Geo.start(() => {});
assert.deepEqual(cleared, [0]);
ns.Geo.stop();
ns.Geo.stop();
assert.deepEqual(cleared, [0, 1]);
});
test('GPS unsupported devices reject current location and optionally report tracking errors', async () => {
for (const navigator of [undefined, {}]) {
const { Wegwichtel: ns } = await load('geolocation.js', { navigator });
await assert.rejects(ns.Geo.current(), /keine Geolokalisierung/);
const errors = [];
ns.Geo.start(() => assert.fail('unexpected position'), error => errors.push(error));
assert.match(errors[0].message, /keine Geolokalisierung/);
ns.Geo.start(() => {});
ns.Geo.stop();
}
});
test('orientation permission denial and rejection do not subscribe to device events', async () => {
for (const DeviceOrientationEvent of [undefined,
{ requestPermission: async () => 'denied' },
{ requestPermission: async () => { throw new Error('Permission unavailable'); } }
]) {
const context = await load('orientation.js', {
DeviceOrientationEvent,
addEventListener() { assert.fail('unexpected orientation listener'); }
});
assert.equal(await context.Wegwichtel.Orientation.start(() => {}), false);
context.Wegwichtel.Orientation.stop();
}
});
test('orientation normalizes compass/absolute headings, ignores relative readings and removes old listeners', async () => {
for (const DeviceOrientationEvent of [{}, { requestPermission: async () => 'granted' }]) {
const listeners = new Map();
const removed = [];
const context = await load('orientation.js', {
DeviceOrientationEvent,
addEventListener(name, listener) { listeners.set(name, listener); },
removeEventListener(name, listener) {
assert.equal(listeners.get(name), listener);
listeners.delete(name); removed.push(name);
}
});
const values = [];
const ns = context.Wegwichtel;
assert.equal(await ns.Orientation.start(value => values.push(value)), true);
listeners.get('deviceorientation')({ webkitCompassHeading: -10 });
listeners.get('deviceorientation')({ absolute: true, alpha: 90 });
listeners.get('deviceorientationabsolute')({ type: 'deviceorientationabsolute', alpha: 370 });
listeners.get('deviceorientation')({ alpha: 90, absolute: false });
listeners.get('deviceorientation')({ absolute: true, alpha: Number.NaN });
assert.deepEqual(values, [350, 270, 350]);
await ns.Orientation.start(value => values.push(value));
assert.equal(removed.length, 2);
ns.Orientation.stop();
assert.equal(listeners.size, 0);
ns.Orientation.stop();
assert.equal(removed.length, 4);
}
});
test('API requests restrict listing to released routes, encode identifiers and propagate failures', async () => {
const requests = [];
const context = await load('api-client.js', {
URLSearchParams,
jQuery: { ajax(options) { requests.push(options); return Promise.resolve({ ok: true }); } }
});
const api = context.Wegwichtel.Api;
await api.health();
await api.routes(null);
await api.routes({ lat: 0, lon: -10 });
await api.route('a/b ?');
assert.deepEqual(requests.map(value => value.url), [
'/api/health', '/api/routes?activatedOnly=true',
'/api/routes?activatedOnly=true&lat=0&lon=-10&radiusKm=5', '/api/routes/a%2Fb%20%3F'
]);
for (const request of requests) {
assert.equal(request.method, 'GET');
assert.equal(request.dataType, 'json');
assert.equal(request.cache, false);
}
const error = new Error('Server nicht erreichbar');
context.jQuery.ajax = () => Promise.reject(error);
await assert.rejects(api.health(), value => value === error);
});
test('distance calculates cardinal bearings, geographic distance and the meter/kilometer boundary', async () => {
const { Wegwichtel: { Distance } } = await load('distance.js');
const origin = { lat: 0, lon: 0 };
assert.equal(Distance.meters(origin, origin), 0);
assert.ok(Math.abs(Distance.meters(origin, { lat: 1, lon: 0 }) - 111195) < 1);
assert.equal(Distance.bearing(origin, { lat: 1, lon: 0 }), 0);
assert.equal(Distance.bearing(origin, { lat: 0, lon: 1 }), 90);
assert.equal(Distance.bearing(origin, { lat: -1, lon: 0 }), 180);
assert.equal(Distance.bearing(origin, { lat: 0, lon: -1 }), 270);
assert.equal(Distance.normalizeDegrees(-370), 350);
assert.equal(Distance.format(999), '999 m');
assert.equal(Distance.format(1000), '1.0 km');
});