Skip to content

Commit 635e6ae

Browse files
Lukas Geigerclaude
andcommitted
fix(web_companion): 4 PWA-Bugs – ignoreSearch, apple-touch-icon, file.text catch, prompt null
Bug #1: sw.js caches.match ohne ignoreSearch:true — Offline-Navigation schlug bei URLs mit Query-Params fehl (?demo=1, etc.) Bug #2: index.html fehlte apple-touch-icon — iOS-Homescreen zeigte generischen Screenshot Bug #3: app.js file.text() im change-Handler ohne try/catch — unhandled Promise rejection bei Lesefehler (gesperrte/binäre Datei) Bug #4: deferredInstallPrompt wurde nach prompt() nicht genullt — zweiter Install-Klick rief prompt() auf verbrauchtem Event auf Manifest: lang:'de' ergänzt Tests: 5 neue Assertions, 25/25 grün Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0a6380a commit 635e6ae

5 files changed

Lines changed: 42 additions & 4 deletions

File tree

web_companion/app.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,24 @@ elements.installButton?.addEventListener("click", async () => {
5454
if (!deferredInstallPrompt) {
5555
return;
5656
}
57-
deferredInstallPrompt.prompt();
58-
await deferredInstallPrompt.userChoice;
57+
const prompt = deferredInstallPrompt;
58+
deferredInstallPrompt = null;
59+
prompt.prompt();
60+
await prompt.userChoice;
5961
});
6062

6163
elements.fileInput?.addEventListener("change", async (event) => {
6264
const [file] = event.target.files || [];
6365
if (!file) {
6466
return;
6567
}
66-
const text = await file.text();
68+
let text;
69+
try {
70+
text = await file.text();
71+
} catch {
72+
setMessage("Datei konnte nicht gelesen werden.", "error");
73+
return;
74+
}
6775
loadWorkspace(text, `Datei: ${file.name}`);
6876
});
6977

web_companion/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<meta name="theme-color" content="#0f1720">
99
<link rel="manifest" href="./manifest.webmanifest">
1010
<link rel="icon" href="./icons/app.svg" type="image/svg+xml">
11+
<link rel="apple-touch-icon" href="./icons/app.svg">
1112
<link rel="stylesheet" href="./styles.css">
1213
</head>
1314
<body>

web_companion/manifest.webmanifest

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"description": "Liest redigierte DevCenter-Arbeitsstände lokal und offline im Browser.",
77
"start_url": "./index.html",
88
"display": "standalone",
9+
"lang": "de",
910
"background_color": "#071118",
1011
"theme_color": "#0f1720",
1112
"icons": [

web_companion/sw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ self.addEventListener("fetch", (event) => {
3939
}
4040

4141
event.respondWith(
42-
caches.match(event.request).then((cached) => {
42+
caches.match(event.request, { ignoreSearch: true }).then((cached) => {
4343
if (cached) {
4444
return cached;
4545
}

web_companion/tests/pwa.test.mjs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,31 @@ test("app.js: registriert Service Worker", () => {
9797
const src = fs.readFileSync(appJsPath, "utf8");
9898
assert.match(src, /serviceWorker\.register/);
9999
});
100+
101+
// --- Bug-Fix-Assertions ---
102+
103+
test("sw.js: caches.match setzt ignoreSearch:true (Offline-Fallback bei ?-Params)", () => {
104+
const src = fs.readFileSync(swPath, "utf8");
105+
assert.match(src, /ignoreSearch:\s*true/, "caches.match muss ignoreSearch:true setzen – offline schlägt bei ?demo=1 fehl");
106+
});
107+
108+
test("index.html: apple-touch-icon vorhanden (iOS Homescreen-Icon)", () => {
109+
const html = fs.readFileSync(indexPath, "utf8");
110+
assert.match(html, /rel="apple-touch-icon"/, "apple-touch-icon fehlt – iOS zeigt generischen Screenshot");
111+
});
112+
113+
test("manifest: lang-Feld vorhanden", () => {
114+
const m = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
115+
assert.ok(m.lang, "lang fehlt im Manifest");
116+
});
117+
118+
test("app.js: fileInput-Handler fängt file.text()-Fehler ab", () => {
119+
const src = fs.readFileSync(appJsPath, "utf8");
120+
assert.match(src, /file\.text\(\)/, "file.text() muss vorhanden sein");
121+
assert.match(src, /Datei konnte nicht gelesen werden/, "Fehlerfall für file.text() fehlt");
122+
});
123+
124+
test("app.js: deferredInstallPrompt wird vor prompt() genullt", () => {
125+
const src = fs.readFileSync(appJsPath, "utf8");
126+
assert.match(src, /deferredInstallPrompt\s*=\s*null/, "deferredInstallPrompt muss nach prompt() genullt werden");
127+
});

0 commit comments

Comments
 (0)