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;
+
+/// = 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))
{
Scan with PolyPilot on iOS/Android to connect
Scan with PolyPilot on iOS/Android to connect