Improve practice website accessibility, contact links and imagery

This commit is contained in:
2026-10-14 12:11:01 +02:00
parent 4022e4adb6
commit 5f70e543e5
10 changed files with 383 additions and 774 deletions
+70
View File
@@ -0,0 +1,70 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const html = fs.readFileSync('index.html', 'utf8');
const calendar = html.slice(html.indexOf(' function viennaDate('), html.indexOf(" // Today's hours in hero card"));
const context = vm.createContext({ Intl, Date });
vm.runInContext(calendar, context);
test('closures include boundaries and cross years without repeating annually', () => {
const closures = [{ start: '2026-12-28', end: '2027-01-03' }];
for (const date of ['2026-12-28', '2026-12-31', '2027-01-01', '2027-01-03']) {
assert.equal(context.isClosureDay(date, closures), true, date);
}
for (const date of ['2026-12-27', '2027-01-04', '2027-12-28']) {
assert.equal(context.isClosureDay(date, closures), false, date);
}
assert.equal(context.isClosureDay('2026-10-14', []), false);
});
test('Vienna date remains correct around midnight and daylight saving time', () => {
assert.equal(context.viennaDate(new Date('2026-10-13T22:30:00Z')), '2026-10-14');
assert.equal(context.viennaDate(new Date('2026-12-31T23:30:00Z')), '2027-01-01');
assert.equal(context.viennaDate(new Date('2026-03-29T22:30:00Z')), '2026-03-30');
});
test('national holidays include fixed and movable holidays in 2026 and 2027', () => {
for (const date of ['2026-01-01', '2026-01-06', '2026-04-06', '2026-05-01', '2026-05-14', '2026-05-25', '2026-06-04', '2026-08-15', '2026-10-26', '2026-11-01', '2026-12-08', '2026-12-25', '2026-12-26', '2027-03-29', '2027-05-06', '2027-05-17', '2027-05-27']) {
assert.equal(context.isPublicHoliday(date), true, date);
}
for (const date of ['2026-10-14', '2026-04-03', '2026-11-15', '2026-12-24', '2027-04-06']) {
assert.equal(context.isPublicHoliday(date), false, date);
}
});
for (const file of ['index.html', 'impressum.html']) {
test(`${file}: scripts work when browser storage is blocked; menu and font states stay accessible`, () => {
const source = fs.readFileSync(file, 'utf8');
const elements = new Map();
const getElement = id => {
if (!elements.has(id)) elements.set(id, {
attrs: { 'aria-expanded': 'false' }, listeners: {}, classList: { toggle() {}, remove() {} },
setAttribute(key, value) { this.attrs[key] = value; },
getAttribute(key) { return this.attrs[key]; },
addEventListener(event, callback) { this.listeners[event] = callback; },
querySelectorAll() { return []; }, focus() { this.focused = true; }
});
return elements.get(id);
};
const document = { body: getElement('body'), getElementById: getElement, addEventListener() {} };
const sandbox = vm.createContext({ document, Intl, Date, setInterval() {},
localStorage: { getItem() { throw Error('blocked'); }, setItem() { throw Error('blocked'); } },
window: { matchMedia() { return { addEventListener() {} }; } }
});
const scripts = [...source.matchAll(/<script>([\s\S]*?)<\/script>/g)].map(match => match[1]);
for (const script of scripts) {
new vm.Script(script);
if (!script.includes('var _paq')) vm.runInContext(script, sandbox);
}
const menu = getElement('hamburger');
menu.listeners.click();
assert.equal(menu.attrs['aria-expanded'], 'true');
assert.equal(menu.attrs['aria-label'], 'Menü schließen');
menu.listeners.click();
assert.equal(menu.attrs['aria-expanded'], 'false');
getElement('font-large').listeners.click();
assert.equal(getElement('font-large-mobile').attrs['aria-pressed'], 'true');
assert.equal(getElement('font-normal').attrs['aria-pressed'], 'false');
});
}