Textsystem: Bis-Strich mit Leerzeichen (Zahl – Zahl) per Agent-Sweep
562 Ersetzungen in 50 Dateien: Halbgeviertstrich zwischen zwei Ziffern (= "bis"-Bereich) bekommt Leerzeichen davor/danach (3–4 -> 3 – 4). Regex /([0-9])\s*–\s*(?=[0-9])/ auf Rohtext (format-erhaltend, CRLF/Einrueckung unveraendert), Bindestriche in Woertern und Minuszeichen unangetastet, alle JSON weiter gueltig. Energiemanager-Zeitbloecke sind Display-Labels (kein Logik-Key) -> safe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const b = await chromium.launch(); const p = await b.newPage();
|
||||
const errs=[]; p.on('pageerror',e=>errs.push(e.message)); p.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
|
||||
await p.route('**/api/admin', r => r.fulfill({ contentType:'application/json', body: JSON.stringify({authenticated:true}) }));
|
||||
await p.goto('http://localhost/geograsim/App/admin-weltkueche.html');
|
||||
await p.waitForTimeout(2000);
|
||||
const r = await p.evaluate(() => {
|
||||
const dishes = [...document.querySelectorAll('.dish')];
|
||||
const names = dishes.map(d => d.querySelector('.nm')?.textContent);
|
||||
function dishInfo(namePart){
|
||||
const d = dishes.find(x => (x.querySelector('.nm')?.textContent||'').toLowerCase().includes(namePart));
|
||||
if(!d) return null;
|
||||
const rows = [...d.querySelectorAll('tbody tr')].map(tr => ({
|
||||
ing: tr.querySelector('.ing-nm')?.textContent.replace(/\s+/g,' ').trim(),
|
||||
ok: [...tr.querySelectorAll('.cty.ok')].map(c=>c.textContent.replace(/\s+/g,' ').trim()),
|
||||
dist: [...tr.querySelectorAll('.cty.dist')].map(c=>c.title.split(' · ')[0]),
|
||||
}));
|
||||
return rows;
|
||||
}
|
||||
const groestl = dishInfo('tiroler gröstl');
|
||||
const kart = groestl && groestl.find(r => /Kartoffel/i.test(r.ing));
|
||||
const eierRow = groestl && groestl.find(r => /Eier/i.test(r.ing));
|
||||
return {
|
||||
dishCount: dishes.length,
|
||||
sampleNames: names.slice(0,6),
|
||||
kartoffelOk: kart ? kart.ok : null,
|
||||
eierOk: eierRow ? eierRow.ok : null,
|
||||
warnCount: document.querySelectorAll('.warn').length,
|
||||
};
|
||||
});
|
||||
console.log(JSON.stringify({result:r, pageErrors:errs}, null, 2));
|
||||
await b.close();
|
||||
})();
|
||||
@@ -0,0 +1,19 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const r = await page.request.get('https://geograsim.at/teacher.html');
|
||||
const html = await r.text();
|
||||
console.log('STATUS', r.status(), 'LEN', html.length);
|
||||
console.log('has renderLiveGesamt:', html.includes('renderLiveGesamt'));
|
||||
console.log('has _liveQualityBar:', html.includes('_liveQualityBar'));
|
||||
console.log('has tab-bar:', html.includes('tab-bar'));
|
||||
console.log('has Ergebnisse:', html.includes('Ergebnisse'));
|
||||
console.log('has external script src (module?):', /<script[^>]+src=/i.test(html));
|
||||
// show script tags
|
||||
const scripts = [...html.matchAll(/<script[^>]*>/gi)].map(m=>m[0]);
|
||||
console.log('SCRIPT TAGS:', JSON.stringify(scripts, null, 2));
|
||||
// show first 600 chars to see redirect logic
|
||||
console.log('HEAD:', html.slice(0, 1200));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,22 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const r = await page.request.get('https://geograsim.at/teacher.html');
|
||||
const html = await r.text();
|
||||
|
||||
const idxLogin = html.indexOf('login.html');
|
||||
console.log('--- context around first login.html reference ---');
|
||||
console.log(html.slice(idxLogin - 400, idxLogin + 120));
|
||||
|
||||
for (const name of ['renderLiveGesamt', '_liveQualityBar']) {
|
||||
const idx = html.indexOf('function ' + name);
|
||||
console.log('\n--- "function ' + name + '" @' + idx + ' ---');
|
||||
if (idx >= 0) console.log(html.slice(idx - 60, idx + 120));
|
||||
}
|
||||
|
||||
const idxErg = html.indexOf('Ergebnisse');
|
||||
console.log('\n--- context around Ergebnisse ---');
|
||||
console.log(html.slice(idxErg - 220, idxErg + 80));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,29 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const r = await page.request.get('https://geograsim.at/teacher.html');
|
||||
const html = await r.text();
|
||||
|
||||
// 1) Static tab-bar markup
|
||||
const tb = html.indexOf('id="tab-bar"');
|
||||
console.log('--- #tab-bar markup ---');
|
||||
console.log(tb >= 0 ? html.slice(tb - 40, tb + 700) : 'tab-bar id NOT found');
|
||||
|
||||
// 2) Extract _liveQualityBar function body and run it in isolation
|
||||
const start = html.indexOf('function _liveQualityBar');
|
||||
// find matching braces
|
||||
let i = html.indexOf('{', start), depth = 0, end = -1;
|
||||
for (; i < html.length; i++) {
|
||||
if (html[i] === '{') depth++;
|
||||
else if (html[i] === '}') { depth--; if (depth === 0) { end = i + 1; break; } }
|
||||
}
|
||||
const fnSrc = html.slice(start, end);
|
||||
const fn = new Function(fnSrc + '\nreturn _liveQualityBar;')();
|
||||
const sample = fn(8, 2);
|
||||
console.log('\n--- _liveQualityBar(8,2) OUTPUT ---');
|
||||
console.log(sample);
|
||||
console.log('\ncontains "80":', String(sample).includes('80'));
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
* gen-display-preview.js
|
||||
* ----------------------
|
||||
* Lokales Admin-Werkzeug: erstellt Bildschirmfotos aller Simulationen
|
||||
* (Onboarding/Start + Spielverlauf) in zwei Auflösungen (iPad + Full HD)
|
||||
* und generiert daraus eine statische Galerie-Seite.
|
||||
*
|
||||
* Ausgabe: App/.LocalDeveloperTools/display-preview/
|
||||
* shots/<id>__<vp>__<screen>.png
|
||||
* display_preview.html
|
||||
*
|
||||
* Start: node gen-display-preview.js
|
||||
*/
|
||||
const { chromium } = require('@playwright/test');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// --- Pfade ---------------------------------------------------------------
|
||||
const APP_DIR = 'C:/xampp/htdocs/geograsim/App';
|
||||
const SIMS_DIR = path.join(APP_DIR, 'sims');
|
||||
const OUT_DIR = path.join(APP_DIR, '.LocalDeveloperTools', 'display-preview');
|
||||
const SHOTS_DIR = path.join(OUT_DIR, 'shots');
|
||||
const BASE_URL = 'http://localhost/geograsim/App/sims';
|
||||
|
||||
// --- Viewports -----------------------------------------------------------
|
||||
const VIEWPORTS = [
|
||||
{ key: 'ipad', label: 'iPad', w: 1180, h: 820 },
|
||||
{ key: 'fullhd', label: 'Full HD', w: 1920, h: 1080 },
|
||||
];
|
||||
|
||||
// --- Freundliche Namen ---------------------------------------------------
|
||||
const NAMES = {
|
||||
weltkueche: '🍲 Welt-Küche',
|
||||
fluss: '🌊 Flussmanagement',
|
||||
heli: '🚁 Helikopter-Navigation',
|
||||
energiemanager: '⚡ Energiemanager',
|
||||
'eu-werkstatt': '🇪🇺 EU-Werkstatt',
|
||||
farmer: '🌾 Farmer',
|
||||
busfahrt: '🚌 Busfahrt',
|
||||
sonnensystem: '🪐 Sonnensystem',
|
||||
tourismustal: '🏔️ Tourismustal',
|
||||
tourismusregion: '🗺️ Tourismusregion',
|
||||
logistik: '🚚 Logistik',
|
||||
fluggesellschaft:'✈️ Fluggesellschaft',
|
||||
staustufen: '💧 Staustufen',
|
||||
entscheidungstag:'📅 Entscheidungstag',
|
||||
vulkan: '🌋 Vulkan',
|
||||
wal: '🐋 Wal',
|
||||
kofferdetektiv: '🧳 Kofferdetektiv',
|
||||
stadt: '🏙️ Stadt',
|
||||
};
|
||||
|
||||
// --- Sims finden ---------------------------------------------------------
|
||||
function findSims() {
|
||||
return fs.readdirSync(SIMS_DIR, { withFileTypes: true })
|
||||
.filter(d => d.isDirectory() && fs.existsSync(path.join(SIMS_DIR, d.name, 'game.html')))
|
||||
.map(d => d.name)
|
||||
.sort();
|
||||
}
|
||||
|
||||
// --- In-Page: sichtbaren Start-/Weiter-Button klicken --------------------
|
||||
async function clickStartLike(page) {
|
||||
return await page.evaluate(() => {
|
||||
const isVisible = (el) => {
|
||||
if (!el) return false;
|
||||
const r = el.getBoundingClientRect();
|
||||
if (r.width < 4 || r.height < 4) return false;
|
||||
if (r.bottom < 0 || r.right < 0) return false;
|
||||
const st = getComputedStyle(el);
|
||||
return st.visibility !== 'hidden' && st.display !== 'none' && st.opacity !== '0'
|
||||
&& !el.disabled && !el.classList.contains('hidden');
|
||||
};
|
||||
// 1) Prioritäts-Selektoren (bekannte Start-/Primary-Buttons der Plattform)
|
||||
const prio = [
|
||||
'.ggs-qi-btn-primary', '[data-action="start"]',
|
||||
'#btnStart', '#obs-start', '#phase-start',
|
||||
'.sn-btn-primary', '.ggs-btn-primary',
|
||||
'.era-card-cta', '.scene-btn',
|
||||
'.map-btn', '.btn.primary', '.primary', '.next',
|
||||
];
|
||||
for (const sel of prio) {
|
||||
const el = [...document.querySelectorAll(sel)].find(isVisible);
|
||||
if (el) { el.click(); return sel + ' :: ' + (el.textContent || '').trim().slice(0, 24); }
|
||||
}
|
||||
// 2) Text-basiert — führende Emojis/Pfeile/Ziffern strippen, dann Anfang prüfen
|
||||
const clean = (s) => (s || '').replace(/^[^\p{L}]+/u, '').trim();
|
||||
const rx = /^(los geht|los!|los →|los\b|start|starten|jetzt starten|neue partie|partie starten|spielen|spiel starten|beginnen|anfangen|einsteigen|erntejahr starten|routenplanung starten|in dieser welt starten|szene|weiter|verstanden|fertig|karte wählen|auswählen)/i;
|
||||
const cands = [...document.querySelectorAll('button, a.btn, a[role=button], .btn, [role=button], [onclick]')];
|
||||
const el = cands.find(e => {
|
||||
if (!isVisible(e)) return false;
|
||||
const t = clean(e.textContent);
|
||||
return t.length > 0 && t.length < 44 && rx.test(t);
|
||||
});
|
||||
if (el) { el.click(); return 'text :: ' + (el.textContent || '').trim().slice(0, 24); }
|
||||
return null;
|
||||
}).catch(() => null);
|
||||
}
|
||||
|
||||
// --- Ein Screenshot ------------------------------------------------------
|
||||
async function shoot(page, file) {
|
||||
try {
|
||||
await page.screenshot({ path: file }); // Viewport-Ausschnitt (exakte Auflösung)
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.log(' ! Screenshot-Fehler:', e.message.slice(0, 80));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const sims = findSims();
|
||||
// Optional: nur bestimmte Sims neu schießen (HTML wird immer komplett neu erzeugt).
|
||||
const onlyArg = (process.argv.find(a => a.startsWith('--only=')) || '').slice(7);
|
||||
const shootList = onlyArg ? onlyArg.split(',').map(s => s.trim()).filter(Boolean) : sims;
|
||||
console.log('Gefundene Sims (' + sims.length + '):', sims.join(', '));
|
||||
if (onlyArg) console.log('Neu geschossen werden nur:', shootList.join(', '));
|
||||
fs.mkdirSync(SHOTS_DIR, { recursive: true });
|
||||
|
||||
const browser = await chromium.launch();
|
||||
// results[id][vp] = { start:bool, play:bool, play2:bool, errs:[] }
|
||||
const results = {};
|
||||
|
||||
for (const vp of VIEWPORTS) {
|
||||
console.log('\n===== Viewport ' + vp.label + ' (' + vp.w + '×' + vp.h + ') =====');
|
||||
for (const id of shootList) {
|
||||
results[id] = results[id] || {};
|
||||
const r = { start: false, play: false, play2: false, errs: [] };
|
||||
results[id][vp.key] = r;
|
||||
|
||||
const ctx = await browser.newContext({
|
||||
viewport: { width: vp.w, height: vp.h },
|
||||
deviceScaleFactor: 1,
|
||||
});
|
||||
const page = await ctx.newPage();
|
||||
page.on('pageerror', e => { if (r.errs.length < 4) r.errs.push('PE:' + e.message.slice(0, 60)); });
|
||||
page.on('console', m => { if (m.type() === 'error' && r.errs.length < 4) r.errs.push('CON:' + m.text().slice(0, 60)); });
|
||||
|
||||
const url = BASE_URL + '/' + id + '/game.html';
|
||||
try {
|
||||
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
} catch (e) {
|
||||
r.errs.push('GOTO:' + e.message.slice(0, 50));
|
||||
}
|
||||
|
||||
// 1) Onboarding/Start
|
||||
await page.waitForTimeout(2500);
|
||||
r.start = await shoot(page, path.join(SHOTS_DIR, id + '__' + vp.key + '__start.png'));
|
||||
|
||||
// 2) Spielverlauf: mehrere Runden klicken (Onboarding schließen -> Menü -> Spiel -> Tutorial weg)
|
||||
let clicks = 0, last = null;
|
||||
for (let round = 0; round < 4; round++) {
|
||||
const clicked = await clickStartLike(page);
|
||||
if (!clicked) break;
|
||||
clicks++;
|
||||
if (clicked === last) break; // gleiches Element erneut -> Abbruch
|
||||
last = clicked;
|
||||
await page.waitForTimeout(800);
|
||||
}
|
||||
if (clicks > 0) {
|
||||
await page.waitForTimeout(2500);
|
||||
r.play = await shoot(page, path.join(SHOTS_DIR, id + '__' + vp.key + '__play.png'));
|
||||
|
||||
// 3) optionaler zweiter Play-Screen: noch ein Weiter/Start, falls vorhanden
|
||||
const more = await clickStartLike(page);
|
||||
if (more && more !== last) {
|
||||
await page.waitForTimeout(2000);
|
||||
r.play2 = await shoot(page, path.join(SHOTS_DIR, id + '__' + vp.key + '__play2.png'));
|
||||
}
|
||||
}
|
||||
|
||||
const flags = [r.start ? 'S' : '-', r.play ? 'P' : '-', r.play2 ? 'P2' : '--'].join(' ');
|
||||
console.log(' ' + id.padEnd(18) + '[' + flags + ']'
|
||||
+ (clicks ? ' clicks=' + clicks : ' (kein Start-Button)')
|
||||
+ (r.errs.length ? ' ' + r.errs.slice(0, 2).join(' | ') : ''));
|
||||
|
||||
await ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
|
||||
// --- HTML generieren ---------------------------------------------------
|
||||
const genDate = new Date().toLocaleString('de-AT', {
|
||||
year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit',
|
||||
});
|
||||
|
||||
const screens = [
|
||||
{ key: 'start', label: 'Onboarding / Start' },
|
||||
{ key: 'play', label: 'Spielverlauf' },
|
||||
{ key: 'play2', label: 'Spielverlauf (2)' },
|
||||
];
|
||||
|
||||
function cell(id, vp, screenKey) {
|
||||
const rel = 'shots/' + id + '__' + vp.key + '__' + screenKey + '.png';
|
||||
const abs = path.join(SHOTS_DIR, id + '__' + vp.key + '__' + screenKey + '.png');
|
||||
if (fs.existsSync(abs)) {
|
||||
return '<a href="' + rel + '" target="_blank" class="shot">'
|
||||
+ '<img loading="lazy" src="' + rel + '" alt="' + id + ' ' + vp.label + ' ' + screenKey + '">'
|
||||
+ '<span class="cap">' + vp.label + ' · ' + vp.w + '×' + vp.h + '</span></a>';
|
||||
}
|
||||
return '<div class="missing">— kein Screenshot —<span class="cap">' + vp.label + '</span></div>';
|
||||
}
|
||||
|
||||
let blocks = '';
|
||||
for (const id of sims) {
|
||||
const name = NAMES[id] || (id.charAt(0).toUpperCase() + id.slice(1));
|
||||
// nur Screen-Zeilen zeigen, die mindestens ein Bild haben
|
||||
const activeScreens = screens.filter(sc =>
|
||||
VIEWPORTS.some(vp => fs.existsSync(path.join(SHOTS_DIR, id + '__' + vp.key + '__' + sc.key + '.png')))
|
||||
);
|
||||
const rows = (activeScreens.length ? activeScreens : [screens[0]]).map(sc =>
|
||||
'<tr><th class="screen">' + sc.label + '</th>'
|
||||
+ VIEWPORTS.map(vp => '<td>' + cell(id, vp, sc.key) + '</td>').join('')
|
||||
+ '</tr>'
|
||||
).join('\n');
|
||||
|
||||
blocks += '\n<section class="sim" id="sim-' + id + '">'
|
||||
+ '<h2>' + name + ' <span class="simid">' + id + '</span></h2>'
|
||||
+ '<table><thead><tr><th class="screen"></th>'
|
||||
+ VIEWPORTS.map(vp => '<th>' + vp.label + ' <span class="res">' + vp.w + '×' + vp.h + '</span></th>').join('')
|
||||
+ '</tr></thead><tbody>' + rows + '</tbody></table></section>';
|
||||
}
|
||||
|
||||
const nav = sims.map(id =>
|
||||
'<a href="#sim-' + id + '">' + (NAMES[id] || id) + '</a>'
|
||||
).join('');
|
||||
|
||||
const html = `<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Display-Vorschau (lokal)</title>
|
||||
<style>
|
||||
:root { --bg:#f4f2ec; --card:#fff; --ink:#1f2b26; --accent:#1f4b37; --muted:#6b7a72; --line:rgba(0,0,0,.08); }
|
||||
* { box-sizing:border-box; }
|
||||
body { margin:0; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; background:var(--bg); color:var(--ink); }
|
||||
header { background:var(--accent); color:#fff; padding:20px 28px; position:sticky; top:0; z-index:10; box-shadow:0 2px 10px rgba(0,0,0,.15); }
|
||||
header h1 { margin:0; font-size:1.4rem; }
|
||||
header .meta { font-size:.82rem; opacity:.85; margin-top:4px; }
|
||||
nav.toc { display:flex; flex-wrap:wrap; gap:6px; padding:14px 28px; background:#e9e6dd; border-bottom:1px solid var(--line); }
|
||||
nav.toc a { font-size:.82rem; text-decoration:none; color:var(--accent); background:#fff; border:1px solid var(--line); border-radius:999px; padding:4px 11px; }
|
||||
nav.toc a:hover { background:var(--accent); color:#fff; }
|
||||
main { padding:24px 28px 60px; max-width:1500px; margin:0 auto; }
|
||||
section.sim { background:var(--card); border-radius:14px; padding:18px 20px 22px; margin-bottom:26px; box-shadow:0 4px 14px rgba(0,0,0,.06); scroll-margin-top:90px; }
|
||||
section.sim h2 { margin:0 0 14px; font-size:1.25rem; color:var(--accent); display:flex; align-items:baseline; gap:10px; }
|
||||
.simid { font-size:.72rem; font-weight:600; color:var(--muted); background:#eef0ec; padding:2px 8px; border-radius:6px; letter-spacing:.03em; }
|
||||
table { width:100%; border-collapse:collapse; table-layout:fixed; }
|
||||
thead th { text-align:left; font-size:.82rem; color:var(--muted); padding:0 0 8px; font-weight:700; }
|
||||
thead th .res { font-weight:500; opacity:.7; }
|
||||
th.screen { width:150px; vertical-align:top; font-size:.9rem; color:var(--ink); padding-top:8px; }
|
||||
td { padding:6px 6px 14px; vertical-align:top; width:calc((100% - 150px)/2); }
|
||||
a.shot { display:block; border:1px solid var(--line); border-radius:8px; overflow:hidden; background:#0d1512; text-decoration:none; }
|
||||
a.shot img { display:block; width:100%; max-width:100%; height:auto; }
|
||||
.cap { display:block; font-size:.72rem; color:var(--muted); padding:5px 8px; background:#fafafa; border-top:1px solid var(--line); }
|
||||
a.shot .cap { color:#c8d4ce; background:#141f1a; border-top:none; }
|
||||
.missing { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; min-height:120px; border:1px dashed var(--line); border-radius:8px; color:var(--muted); font-size:.85rem; background:#faf9f5; }
|
||||
.missing .cap { background:none; border:none; }
|
||||
@media (max-width:820px){ th.screen{width:90px;} td{width:calc((100% - 90px)/2);} }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Display-Vorschau (lokal)</h1>
|
||||
<div class="meta">${sims.length} Simulationen · je Onboarding/Start + Spielverlauf · iPad 1180×820 & Full HD 1920×1080 · generiert am ${genDate}</div>
|
||||
</header>
|
||||
<nav class="toc">${nav}</nav>
|
||||
<main>${blocks}
|
||||
</main>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const outFile = path.join(OUT_DIR, 'display_preview.html');
|
||||
fs.writeFileSync(outFile, html, 'utf8');
|
||||
console.log('\nHTML geschrieben: ' + outFile);
|
||||
|
||||
// --- Zusammenfassung ---------------------------------------------------
|
||||
console.log('\n===== ZUSAMMENFASSUNG =====');
|
||||
let totalShots = 0, missingPlay = [];
|
||||
for (const id of sims) {
|
||||
const parts = [];
|
||||
for (const vp of VIEWPORTS) {
|
||||
const r = (results[id] && results[id][vp.key]) || {};
|
||||
const n = (r.start ? 1 : 0) + (r.play ? 1 : 0) + (r.play2 ? 1 : 0);
|
||||
totalShots += n;
|
||||
parts.push(vp.label + ':' + n + '/3(' + (r.start ? 'S' : '-') + (r.play ? 'P' : '-') + (r.play2 ? '2' : '-') + ')');
|
||||
if (!r.play) missingPlay.push(id + '/' + vp.key);
|
||||
}
|
||||
console.log(' ' + id.padEnd(18) + parts.join(' '));
|
||||
}
|
||||
console.log('\nScreenshots gesamt: ' + totalShots);
|
||||
console.log('Fehlende Play-Screens: ' + (missingPlay.length ? missingPlay.join(', ') : 'keine'));
|
||||
console.log('Seite: http://localhost/geograsim/App/.LocalDeveloperTools/display-preview/display_preview.html');
|
||||
})();
|
||||
@@ -0,0 +1,17 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const res = await page.goto('http://localhost/geograsim/App/modul-weltkueche');
|
||||
await page.waitForTimeout(700);
|
||||
const r = await page.evaluate(() => {
|
||||
const sec = document.getElementById('lehrplan-bezug');
|
||||
const komps = [...document.querySelectorAll('.md-kompetenz .md-kompetenz-title')].map(e=>e.textContent.trim());
|
||||
const anchors = document.querySelectorAll('.md-anchor').length;
|
||||
const countryChips = [...document.querySelectorAll('.md-lehrplan-filters .md-chip')].map(c=>c.textContent.trim());
|
||||
const empty = document.body.textContent.includes('Noch keine Kompetenzen zugeordnet');
|
||||
return { hasSection: !!sec, kompetenzTitles: komps, anchorCount: anchors, countryChips, showsEmpty: empty };
|
||||
});
|
||||
console.log(JSON.stringify({ httpStatus: res.status(), result: r }, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,17 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const res = await page.goto('https://geograsim.at/modul-weltkueche', { waitUntil: 'networkidle' });
|
||||
await page.waitForTimeout(700);
|
||||
const r = await page.evaluate(() => {
|
||||
const sec = document.getElementById('lehrplan-bezug');
|
||||
const komps = [...document.querySelectorAll('.md-kompetenz .md-kompetenz-title')].map(e=>e.textContent.trim());
|
||||
const anchors = document.querySelectorAll('.md-anchor').length;
|
||||
const countryChips = [...document.querySelectorAll('.md-lehrplan-filters .md-chip')].map(c=>c.textContent.trim());
|
||||
const empty = document.body.textContent.includes('Noch keine Kompetenzen zugeordnet');
|
||||
return { hasSection: !!sec, kompetenzTitles: komps, anchorCount: anchors, countryChips, showsEmpty: empty };
|
||||
});
|
||||
console.log(JSON.stringify({ httpStatus: res.status(), result: r }, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,37 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
|
||||
await page.goto('http://localhost/geograsim/App/modul-weltkueche', { waitUntil:'domcontentloaded' });
|
||||
await page.waitForTimeout(700);
|
||||
|
||||
async function snapshot() {
|
||||
return await page.evaluate(() => {
|
||||
const all = [...document.querySelectorAll('.md-anchor')];
|
||||
const visible = all.filter(a => !a.classList.contains('hidden'));
|
||||
const byType = t => visible.filter(a => a.dataset.anchorType===t).length;
|
||||
const fachCountries = {};
|
||||
visible.filter(a=>a.dataset.anchorType==='fach').forEach(a=>{ fachCountries[a.dataset.country]=(fachCountries[a.dataset.country]||0)+1; });
|
||||
return { total: all.length, visible: visible.length, fachVisible: byType('fach'), fachCountries };
|
||||
});
|
||||
}
|
||||
async function clickChip(country) {
|
||||
await page.evaluate((c) => {
|
||||
const btn = [...document.querySelectorAll('.md-chip')].find(b => (b.dataset.country||'')===c);
|
||||
if (btn) btn.click();
|
||||
}, country);
|
||||
await page.waitForTimeout(200);
|
||||
}
|
||||
|
||||
const start = await snapshot();
|
||||
await clickChip(''); // Alle Länder
|
||||
const alle = await snapshot();
|
||||
await clickChip('DE'); // Deutschland
|
||||
const de = await snapshot();
|
||||
await clickChip('AT'); // Österreich
|
||||
const at = await snapshot();
|
||||
|
||||
console.log(JSON.stringify({ start, alle, de, at, pageErrors: errs }, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,15 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
|
||||
await page.goto('https://geograsim.at/modul-weltkueche', { waitUntil:'domcontentloaded' });
|
||||
await page.waitForTimeout(900);
|
||||
async function snap(){ return await page.evaluate(()=>{ const all=[...document.querySelectorAll('.md-anchor')]; const vis=all.filter(a=>!a.classList.contains('hidden')); const fc={}; vis.filter(a=>a.dataset.anchorType==='fach').forEach(a=>fc[a.dataset.country]=(fc[a.dataset.country]||0)+1); return {total:all.length, visible:vis.length, fach:vis.filter(a=>a.dataset.anchorType==='fach').length, fachCountries:fc}; }); }
|
||||
async function chip(c){ await page.evaluate(c=>{const b=[...document.querySelectorAll('.md-chip')].find(x=>(x.dataset.country||'')===c); if(b)b.click();},c); await page.waitForTimeout(200); }
|
||||
await chip(''); const alle=await snap();
|
||||
await chip('DE'); const de=await snap();
|
||||
await chip('AT'); const at=await snap();
|
||||
console.log(JSON.stringify({alle,de,at,pageErrors:errs},null,2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,25 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const b = await chromium.launch(); const p = await b.newPage();
|
||||
await p.addInitScript(() => {
|
||||
window.__GGS__ = { simId: 'test', baseUrl: '' };
|
||||
window.fetch = () => Promise.resolve({ ok:true, json:()=>Promise.resolve({}) }); // Heartbeat stummschalten
|
||||
});
|
||||
await p.goto('about:blank');
|
||||
await p.addScriptTag({ path: 'C:/xampp/htdocs/geograsim/App/assets/js/live-client.js' });
|
||||
const read = () => p.evaluate(() => window.__GGS_LIVE__ ? window.__GGS_LIVE__.activeMs : null);
|
||||
const set = (v) => p.evaluate((v) => window.__GGS_LIVE__.setPaused(v), v);
|
||||
await p.waitForTimeout(300);
|
||||
const a1 = await read();
|
||||
await p.waitForTimeout(2500); const a2 = await read(); // sollte gestiegen sein
|
||||
await set(true);
|
||||
await p.waitForTimeout(2500); const a3 = await read(); // sollte eingefroren sein
|
||||
await set(false);
|
||||
await p.waitForTimeout(2500); const a4 = await read(); // sollte wieder steigen
|
||||
const grewNormal = (a2 - a1) > 1500;
|
||||
const frozen = (a3 - a2) < 300;
|
||||
const resumed = (a4 - a3) > 1500;
|
||||
console.log(JSON.stringify({ a1,a2,a3,a4, grewNormal, frozen, resumed,
|
||||
verdict: (grewNormal && frozen && resumed) ? 'PASS' : 'FAIL' }, null, 2));
|
||||
await b.close();
|
||||
})();
|
||||
@@ -0,0 +1,74 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const out = {};
|
||||
|
||||
// 1) modul-weltkueche: Lehrplan-Bezug jetzt vorhanden?
|
||||
{
|
||||
const page = await browser.newPage();
|
||||
await page.goto('https://geograsim.at/modul-weltkueche', { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(1000);
|
||||
out.modulWeltkueche = await page.evaluate(() => ({
|
||||
kompetenzTitles: [...document.querySelectorAll('.md-kompetenz-title')].map(e=>e.textContent.trim()),
|
||||
anchorCount: document.querySelectorAll('.md-anchor').length,
|
||||
showsEmpty: document.body.textContent.includes('Noch keine Kompetenzen zugeordnet'),
|
||||
}));
|
||||
await page.close();
|
||||
}
|
||||
|
||||
// 2) Weltküche-Sim: Artikel + Ukraine-Feedback
|
||||
{
|
||||
const page = await browser.newPage();
|
||||
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
|
||||
await page.goto('https://geograsim.at/sims/weltkueche/game.html', { waitUntil:'domcontentloaded' });
|
||||
await page.waitForTimeout(2000);
|
||||
out.weltkueche = await page.evaluate(async () => {
|
||||
try {
|
||||
if (!DISHES.length) await loadWeltkuecheData();
|
||||
const dish = DISHES.find(d=>d.id==='tiroler-groestl'); current={dish};
|
||||
buildTaskFor('kartoffel');
|
||||
return {
|
||||
kartoffelArt: ING.kartoffel.art,
|
||||
badArticles: Object.entries(ING).filter(([k,v])=>!['der','die','das'].includes(v&&v.art)).map(([k])=>k),
|
||||
wrongUA: explainChoice('kartoffel','ukraine',false).text,
|
||||
};
|
||||
} catch(e){ return { error:String(e) }; }
|
||||
});
|
||||
out.weltkueche.pageErrors = errs;
|
||||
await page.close();
|
||||
}
|
||||
|
||||
// 3) teacher.html: lädt + neue Funktionen da (direkter Link, den das Produkt nutzt)
|
||||
{
|
||||
const page = await browser.newPage();
|
||||
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
|
||||
// teacher.html leitet ohne Login auf login.html um — Navigation abfangen, sofort auswerten
|
||||
await page.route('**/login.html', r=>r.abort());
|
||||
await page.goto('https://geograsim.at/teacher.html', { waitUntil:'domcontentloaded' }).catch(()=>{});
|
||||
await page.waitForTimeout(1500);
|
||||
out.teacher = await page.evaluate(() => ({
|
||||
hasRenderGesamt: typeof renderLiveGesamt === 'function',
|
||||
hasQualityBar: typeof _liveQualityBar === 'function',
|
||||
qualitySample: (typeof _liveQualityBar==='function') ? _liveQualityBar(8,2) : null,
|
||||
tabLabels: [...document.querySelectorAll('#tab-bar .tab')].map(t=>t.textContent.trim()),
|
||||
})).catch(e=>({evalError:String(e)}));
|
||||
out.teacher.pageErrors = errs;
|
||||
await page.close();
|
||||
}
|
||||
|
||||
// 4) Tourismusregion passstrasse Karte
|
||||
{
|
||||
const page = await browser.newPage();
|
||||
const mc = await page.request.get('https://geograsim.at/sims/tourismusregion/js/maps-custom.json');
|
||||
const j = await mc.json();
|
||||
out.tourismus = {
|
||||
keys: Object.keys(j),
|
||||
passBergaufPoints: j.passstrasse?.routes?.bergauf?.length ?? null,
|
||||
passSlots: (j.passstrasse?.slots||[]).length,
|
||||
};
|
||||
await page.close();
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(out, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,21 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const b = await chromium.launch(); const p = await b.newPage();
|
||||
const errs=[]; p.on('pageerror',e=>errs.push(e.message)); p.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
|
||||
await p.route('**/login.html', r=>r.abort());
|
||||
await p.goto('http://localhost/geograsim/App/teacher.html',{waitUntil:'domcontentloaded'}).catch(()=>{});
|
||||
await p.waitForTimeout(1200);
|
||||
const r = await p.evaluate(() => ({
|
||||
hasSimWord: typeof simWord==='function',
|
||||
hasSimCode: typeof simCode==='function',
|
||||
logistikWord: typeof simWord==='function' ? simWord('logistik') : null,
|
||||
logistikCode: typeof simCode==='function' ? simCode('logistik') : null,
|
||||
unknownCode: typeof simCode==='function' ? simCode('irgendwas') : null,
|
||||
logistikFields: (typeof LIVE_PRIMARY_FIELDS==='object' && LIVE_PRIMARY_FIELDS.logistik) ? LIVE_PRIMARY_FIELDS.logistik.map(f=>f.label) : null,
|
||||
liveShortLogistik: typeof LIVE_SIM_SHORT==='object' ? LIVE_SIM_SHORT.logistik : null,
|
||||
// Kürzel-Eindeutigkeit
|
||||
codesUnique: (function(){ if(typeof SIM_LABELS!=='object') return null; var seen={},dup=[]; Object.keys(SIM_LABELS).forEach(k=>{var c=SIM_LABELS[k].c; if(seen[c])dup.push(c); seen[c]=1;}); return dup; })(),
|
||||
}));
|
||||
console.log(JSON.stringify({result:r, pageErrors:errs}, null, 2));
|
||||
await b.close();
|
||||
})();
|
||||
@@ -0,0 +1,26 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror', e => errors.push('PAGEERROR: '+e.message));
|
||||
page.on('console', m => { if (m.type()==='error') errors.push(m.text()); });
|
||||
const res = await page.goto('http://localhost/geograsim/App/teacher');
|
||||
await page.waitForTimeout(1000);
|
||||
const r = await page.evaluate(() => {
|
||||
const tabs = [...document.querySelectorAll('#tab-bar .tab')].map(t => t.textContent.trim());
|
||||
let toggle = null;
|
||||
try { toggle = (typeof _liveToggleHtml === 'function') ? _liveToggleHtml() : null; } catch(e){ toggle = 'ERR:'+e.message; }
|
||||
return {
|
||||
tabLabels: tabs,
|
||||
hasSetLiveMode: typeof setLiveMode === 'function',
|
||||
hasRenderGesamt: typeof renderLiveGesamt === 'function',
|
||||
hasQualityBar: typeof _liveQualityBar === 'function',
|
||||
qualitySample: (typeof _liveQualityBar === 'function') ? _liveQualityBar(8,2) : null,
|
||||
toggleHasGesamt: (typeof toggle === 'string') ? toggle.includes('Gesamt') : toggle,
|
||||
toggleHasTag: (typeof toggle === 'string') ? toggle.includes('Tag') : toggle,
|
||||
};
|
||||
});
|
||||
console.log(JSON.stringify({ httpStatus: res.status(), result: r, pageErrors: errors }, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,21 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const b = await chromium.launch(); const p = await b.newPage({ viewport:{width:1180,height:820} });
|
||||
const errs=[]; p.on('pageerror',e=>errs.push(e.message)); p.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
|
||||
await p.goto('http://localhost/geograsim/App/sims/tourismusregion/game.html');
|
||||
await p.waitForTimeout(1500);
|
||||
await p.click('.map-btn'); // Route klicken → Spiel startet → Willkommenskarte
|
||||
await p.waitForTimeout(2000);
|
||||
const r = await p.evaluate(() => {
|
||||
const card = document.getElementById('cardText');
|
||||
const txt = card ? card.textContent : '';
|
||||
return {
|
||||
started: !!window.__ttState,
|
||||
cardHasEnvText: /Umwelt ist deine Landschaft/.test(txt),
|
||||
cardHasNaturschutz: /Naturschutzgebiet/.test(txt),
|
||||
envKpi: document.getElementById('kEnv')?.textContent,
|
||||
};
|
||||
});
|
||||
console.log(JSON.stringify({ result:r, pageErrors: errs.filter(e=>!/404|Failed to load resource/.test(e)) }, null, 2));
|
||||
await b.close();
|
||||
})();
|
||||
@@ -0,0 +1,38 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror', e => errors.push('PAGEERROR: '+e.message));
|
||||
page.on('console', m => { if (m.type()==='error') errors.push(m.text()); });
|
||||
|
||||
// 1) maps-custom.json direkt prüfen
|
||||
const mc = await page.request.get('http://localhost/geograsim/App/sims/tourismusregion/js/maps-custom.json');
|
||||
const mcJson = await mc.json();
|
||||
const ps = mcJson.passstrasse || null;
|
||||
|
||||
// 2) Hintergrundbild erreichbar?
|
||||
const img = await page.request.get('http://localhost/geograsim/App/sims/tourismusregion/assets/maps/passstrasse.png');
|
||||
|
||||
// 3) Sim-Startscreen laden, Kartenliste prüfen
|
||||
const res = await page.goto('http://localhost/geograsim/App/sims/tourismusregion/game.html');
|
||||
await page.waitForTimeout(2500);
|
||||
const startInfo = await page.evaluate(() => {
|
||||
const list = document.getElementById('mapList');
|
||||
const labels = list ? [...list.querySelectorAll('*')].map(e=>e.textContent).filter(t=>t && t.length<40) : [];
|
||||
const hasPass = !!(list && /Passstra/i.test(list.textContent||''));
|
||||
return { mapListText: (list?list.textContent:'').replace(/\s+/g,' ').trim().slice(0,300), hasPass };
|
||||
});
|
||||
|
||||
console.log(JSON.stringify({
|
||||
httpStatus: res.status(),
|
||||
passInMapsCustom: !!ps,
|
||||
routeKeys: ps ? Object.keys(ps.routes||{}) : null,
|
||||
bergaufPoints: ps && ps.routes && ps.routes.bergauf ? ps.routes.bergauf.length : null,
|
||||
slotCount: ps ? (ps.slots||[]).length : null,
|
||||
bgImageStatus: img.status(),
|
||||
startInfo,
|
||||
pageErrors: errors
|
||||
}, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,30 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage({ viewport: { width: 1180, height: 820 } }); // iPad Landscape
|
||||
const errs=[]; page.on('pageerror',e=>errs.push(e.message)); page.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
|
||||
await page.goto('http://localhost/geograsim/App/sims/tourismusregion/game.html');
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
const before = await page.evaluate(() => ({
|
||||
hasPlayerName: !!document.getElementById('playerName'),
|
||||
hasClassCode: !!document.getElementById('classCode'),
|
||||
hasBtnStart: !!document.getElementById('btnStart'),
|
||||
hasBtnSave: !!document.getElementById('btnSave'),
|
||||
mapBtnCount: document.querySelectorAll('.map-btn').length,
|
||||
startOverlayHidden: document.getElementById('startOverlay').classList.contains('hidden'),
|
||||
}));
|
||||
|
||||
// ② Klick auf erste Route sollte SOFORT starten
|
||||
await page.click('.map-btn');
|
||||
await page.waitForTimeout(2500);
|
||||
const after = await page.evaluate(() => ({
|
||||
startOverlayHidden: document.getElementById('startOverlay').classList.contains('hidden'),
|
||||
gameStarted: !!window.__ttState,
|
||||
mapId: window.__ttState && window.__ttState.map && window.__ttState.map.id,
|
||||
}));
|
||||
|
||||
await page.screenshot({ path: 'C:/Users/herr_/AppData/Local/Temp/claude/c--xampp-htdocs-geograsim/c02572ea-7616-4524-a974-dff0e5670d2c/scratchpad/tr-ipad.png' });
|
||||
console.log(JSON.stringify({ before, after, pageErrors: errs }, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,27 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('console', m => { if (m.type()==='error') errors.push(m.text()); });
|
||||
page.on('pageerror', e => errors.push('PAGEERROR: '+e.message));
|
||||
await page.goto('http://localhost/geograsim/App/sims/weltkueche/game.html');
|
||||
await page.waitForTimeout(1500);
|
||||
const r = await page.evaluate(async () => {
|
||||
try {
|
||||
if (!DISHES.length) await loadWeltkuecheData();
|
||||
const dish = DISHES.find(d => d.id === 'tiroler-groestl');
|
||||
if (!dish) return { error: 'no tiroler-groestl dish' };
|
||||
current = { dish };
|
||||
const task = buildTaskFor('kartoffel');
|
||||
const art = ING.kartoffel.art;
|
||||
const correctAT = explainChoice('kartoffel', 'oesterreich', true).text;
|
||||
const correctDE = explainChoice('kartoffel', 'deutschland', true).text;
|
||||
const wrongUA = explainChoice('kartoffel', 'ukraine', false).text;
|
||||
const bad = Object.entries(ING).filter(([k,v]) => !['der','die','das'].includes(v && v.art)).map(([k])=>k);
|
||||
return { art, taskCorrect: task.correct, correctAT, correctDE, wrongUA, badArticles: bad, ingCount: Object.keys(ING).length };
|
||||
} catch (e) { return { error: String(e), stack: e.stack }; }
|
||||
});
|
||||
console.log(JSON.stringify({ result: r, consoleErrors: errors }, null, 2));
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -0,0 +1,38 @@
|
||||
const { chromium } = require('@playwright/test');
|
||||
(async () => {
|
||||
const b = await chromium.launch(); const p = await b.newPage();
|
||||
const errs=[]; p.on('pageerror',e=>errs.push(e.message)); p.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
|
||||
await p.goto('http://localhost/geograsim/App/sims/weltkueche/game.html');
|
||||
await p.waitForTimeout(1500);
|
||||
const r = await p.evaluate(async () => {
|
||||
try {
|
||||
if (!DISHES.length) await loadWeltkuecheData();
|
||||
function taskFor(ingKey, heimat){
|
||||
current = { dish: { id:'test-'+ingKey, heimat: heimat, ings:[ingKey], signature:{} } };
|
||||
try { delete _taskCache[ingKey]; } catch(_){}
|
||||
return buildTaskFor(ingKey);
|
||||
}
|
||||
const dEggsDE = _wkDist('oesterreich','deutschland');
|
||||
const dEggsFR = _wkDist('oesterreich','frankreich');
|
||||
const eier = taskFor('eier','oesterreich');
|
||||
const kart = taskFor('kartoffel','oesterreich');
|
||||
const milch = taskFor('milch','oesterreich');
|
||||
// alle Zutaten müssen fehlerfrei bauen
|
||||
let buildErr = null;
|
||||
for (const k of Object.keys(ING)) {
|
||||
current = { dish:{id:'x',heimat:'oesterreich',ings:[k],signature:{}} };
|
||||
try { delete _taskCache[k]; buildTaskFor(k); } catch(e){ buildErr = k+': '+e.message; break; }
|
||||
}
|
||||
return {
|
||||
distDE: Math.round(dEggsDE), distFR: Math.round(dEggsFR),
|
||||
eierCorrect: eier.correct, eierChoices: eier.choices,
|
||||
eierDistractors: eier.choices.length - eier.correct.length,
|
||||
kartoffelCorrect: kart.correct,
|
||||
milchCorrect: milch.correct,
|
||||
buildErr, ingCount: Object.keys(ING).length,
|
||||
};
|
||||
} catch(e){ return { error:String(e), stack:e.stack }; }
|
||||
});
|
||||
console.log(JSON.stringify({result:r, pageErrors:errs}, null, 2));
|
||||
await b.close();
|
||||
})();
|
||||
Reference in New Issue
Block a user