From 9f30e1ac225c1860f0f3754b0e62d7a739fbafba Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Mon, 23 Feb 2026 15:43:46 +0100 Subject: [PATCH] Fix QR code not blurred by default in settings The token value was correctly blurred by default (showToken=false), but the QR code images (tunnel and direct) were always shown unblurred, exposing the encoded token. Now both QR code images use the same showToken toggle to apply a CSS blur filter, matching the token's behavior. Changes: - Settings.razor: Add blurred class to both QR code img elements based on showToken - Settings.razor.css: Add blur styles for .qr-code img.blurred with hover reveal - QrCodeBlurTests.cs: 6 tests verifying blur markup and CSS contracts - mode-switch-scenarios.json: UI scenario for QR code blur toggle Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- PolyPilot.Tests/QrCodeBlurTests.cs | 89 +++++++++++++++++++ .../Scenarios/mode-switch-scenarios.json | 47 ++++++++++ PolyPilot/Components/Pages/Settings.razor | 4 +- PolyPilot/Components/Pages/Settings.razor.css | 10 +++ 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 PolyPilot.Tests/QrCodeBlurTests.cs diff --git a/PolyPilot.Tests/QrCodeBlurTests.cs b/PolyPilot.Tests/QrCodeBlurTests.cs new file mode 100644 index 0000000000..62ccff8aa1 --- /dev/null +++ b/PolyPilot.Tests/QrCodeBlurTests.cs @@ -0,0 +1,89 @@ +using System.Text.RegularExpressions; + +namespace PolyPilot.Tests; + +/// +/// Tests that verify the QR code images in Settings are blurred by default +/// (when showToken is false), matching the token's blur behavior. +/// Since these are Blazor components, we verify the source markup contracts. +/// +public class QrCodeBlurTests +{ + private static string GetSettingsRazorPath() + { + // Navigate from test project to main project + var testDir = AppContext.BaseDirectory; + var repoRoot = Path.GetFullPath(Path.Combine(testDir, "..", "..", "..", "..")); + return Path.Combine(repoRoot, "PolyPilot", "Components", "Pages", "Settings.razor"); + } + + private static string GetSettingsCssPath() + { + var testDir = AppContext.BaseDirectory; + var repoRoot = Path.GetFullPath(Path.Combine(testDir, "..", "..", "..", "..")); + return Path.Combine(repoRoot, "PolyPilot", "Components", "Pages", "Settings.razor.css"); + } + + [Fact] + public void QrCodeImages_UseBlurredClassFromShowTokenToggle() + { + var razorContent = File.ReadAllText(GetSettingsRazorPath()); + + // Both QR code img tags should use the showToken toggle for blurred class + var qrImgPattern = new Regex(@"= 2, + $"Expected at least 2 QR code tags with showToken-based blur class, found {matches.Count}. " + + "Both tunnel and direct QR codes must be blurred when token is hidden."); + } + + [Fact] + public void TokenValue_UsesBlurredClassFromShowTokenToggle() + { + var razorContent = File.ReadAllText(GetSettingsRazorPath()); + + // Token code element should also use showToken toggle + Assert.Contains(@"@(showToken ? """" : ""blurred"")", razorContent); + } + + [Fact] + public void ShowToken_DefaultsFalse() + { + var razorContent = File.ReadAllText(GetSettingsRazorPath()); + + // showToken should be declared as bool (defaults to false) + Assert.Matches(@"private\s+bool\s+showToken\s*;", razorContent); + + // It should NOT be initialized to true + Assert.DoesNotMatch(@"private\s+bool\s+showToken\s*=\s*true", razorContent); + } + + [Fact] + public void Css_HasBlurredStyleForQrCodeImages() + { + var cssContent = File.ReadAllText(GetSettingsCssPath()); + + // CSS must define blur styles for QR code images + Assert.Contains(".qr-code img.blurred", cssContent); + Assert.Contains("filter: blur(", cssContent); + } + + [Fact] + public void Css_QrCodeImageHasTransition() + { + var cssContent = File.ReadAllText(GetSettingsCssPath()); + + // QR code img should have a transition for smooth blur toggle + Assert.Contains("transition: filter", cssContent); + } + + [Fact] + public void Css_BlurredQrCodeHasHoverReveal() + { + var cssContent = File.ReadAllText(GetSettingsCssPath()); + + // Blurred QR should partially reveal on hover (like the token does) + Assert.Contains(".qr-code img.blurred:hover", cssContent); + } +} diff --git a/PolyPilot.Tests/Scenarios/mode-switch-scenarios.json b/PolyPilot.Tests/Scenarios/mode-switch-scenarios.json index d9d92b680c..a338a15112 100644 --- a/PolyPilot.Tests/Scenarios/mode-switch-scenarios.json +++ b/PolyPilot.Tests/Scenarios/mode-switch-scenarios.json @@ -825,6 +825,53 @@ "note": "Filter input is visible when expanded" } ] + }, + { + "id": "settings-qr-code-blur", + "name": "QR code is blurred by default alongside token", + "steps": [ + { + "action": "note", + "note": "Navigate to /settings page. Requires an active DevTunnel to see QR code." + }, + { + "action": "evaluate", + "script": "document.querySelector('.qr-code img')?.classList.contains('blurred')", + "expect": { + "equals": true + }, + "note": "QR code image is blurred by default (showToken=false)" + }, + { + "action": "evaluate", + "script": "document.querySelector('.token-value')?.classList.contains('blurred')", + "expect": { + "equals": true + }, + "note": "Token value is also blurred by default" + }, + { + "action": "click", + "selector": ".tunnel-token .copy-btn", + "note": "Click reveal/hide token button" + }, + { + "action": "evaluate", + "script": "document.querySelector('.qr-code img')?.classList.contains('blurred')", + "expect": { + "equals": false + }, + "note": "QR code is revealed when token is shown" + }, + { + "action": "evaluate", + "script": "document.querySelector('.token-value')?.classList.contains('blurred')", + "expect": { + "equals": false + }, + "note": "Token is also revealed" + } + ] } ] } diff --git a/PolyPilot/Components/Pages/Settings.razor b/PolyPilot/Components/Pages/Settings.razor index c4f49982b6..c251e115ef 100644 --- a/PolyPilot/Components/Pages/Settings.razor +++ b/PolyPilot/Components/Pages/Settings.razor @@ -178,7 +178,7 @@ @if (!string.IsNullOrEmpty(qrCodeDataUri)) {
- QR Code + QR Code

Scan with PolyPilot on iOS/Android to connect

} @@ -244,7 +244,7 @@ @if (!string.IsNullOrEmpty(directQrCodeDataUri)) {
- QR Code + QR Code

Scan with PolyPilot on iOS/Android to connect

} diff --git a/PolyPilot/Components/Pages/Settings.razor.css b/PolyPilot/Components/Pages/Settings.razor.css index a1407c3710..75df77961a 100644 --- a/PolyPilot/Components/Pages/Settings.razor.css +++ b/PolyPilot/Components/Pages/Settings.razor.css @@ -728,6 +728,16 @@ border-radius: 8px; padding: 12px; background: #fff; + transition: filter 0.2s ease; +} + +.qr-code img.blurred { + filter: blur(8px); + cursor: pointer; +} + +.qr-code img.blurred:hover { + filter: blur(4px); } .qr-hint {