From cfd9ce3ea4163eefd3033d01990c4e60cfe15ae3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laban?= <jerome@platform.uno>
Date: Wed, 12 Mar 2025 15:16:58 -0400
Subject: [PATCH 1/5] fix(webview2): [wasm] Fix ExecuteScriptAsync

---
 .../Given_WebView2.cs                         | 58 +++++++++++++++++++
 .../Native/Wasm/NativeWebView.Interop.wasm.cs |  2 +-
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs

diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
new file mode 100644
index 000000000000..54629da0d8a6
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
@@ -0,0 +1,58 @@
+#if HAS_UNO_WINUI
+using System;
+using System.Threading.Tasks;
+using Private.Infrastructure;
+using Microsoft/* UWP don't rename */.UI.Xaml.Controls;
+using System.Linq;
+using Microsoft.Web.WebView2.Core;
+using System.Diagnostics;
+
+namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls;
+
+[TestClass]
+[RunsOnUIThread]
+public class Given_WebView
+{
+	[TestMethod]
+	public async Task When_InvokeScriptAsync()
+	{
+		var border = new Border();
+		var webView = new WebView2();
+		webView.Width = 200;
+		webView.Height = 200;
+		border.Child = webView;
+		TestServices.WindowHelper.WindowContent = border;
+		bool navigated = false;
+		await TestServices.WindowHelper.WaitForLoaded(border);
+		webView.NavigationCompleted += (sender, e) => navigated = true;
+		webView.NavigateToString("<html><body><div id='test' style='width: 100px; height: 100px; background-color: blue;' /></body></html>");
+		await TestServices.WindowHelper.WaitFor(() => navigated);
+
+		var sw = Stopwatch.StartNew();
+		string color = null;
+
+		do
+		{
+			// We need to wait for the element to be available, navigated
+			// may be set to true too early on wasm.
+			color = await webView.ExecuteScriptAsync(
+				"""
+				let testElement = document.getElementById('test');
+				if(testElement){
+					return testElement.style.backgroundColor.toString();
+				}
+				return "";
+				""");
+
+		} while (sw.Elapsed < TimeSpan.FromSeconds(5) && string.IsNullOrEmpty(color));
+
+		Assert.AreEqual("blue", color);
+
+		// Change color to red
+		await webView.ExecuteScriptAsync("document.getElementById('test').style.backgroundColor = 'red'");
+		color = await webView.ExecuteScriptAsync("document.getElementById('test').style.backgroundColor.toString()");
+
+		Assert.AreEqual("red", color);
+	}
+}
+#endif
diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.Interop.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.Interop.wasm.cs
index d9f7c3ddb4be..a7c2e9a6d118 100644
--- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.Interop.wasm.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.Interop.wasm.cs
@@ -20,7 +20,7 @@ internal static partial class NativeMethods
 		[JSImport("globalThis.Microsoft.UI.Xaml.Controls.WebView.goForward")]
 		internal static partial void GoForward(IntPtr htmlId);
 
-		[JSImport("globalThis.Microsoft.UI.Xaml.Controls.WebView.executeScriptAsync")]
+		[JSImport("globalThis.Microsoft.UI.Xaml.Controls.WebView.executeScript")]
 		internal static partial string ExecuteScript(IntPtr htmlId, string script);
 
 		[JSImport("globalThis.Microsoft.UI.Xaml.Controls.WebView.getDocumentTitle")]

From 24c958dde1e92ce7e3e33f1022cdbdef3b3d7c28 Mon Sep 17 00:00:00 2001
From: Jerome Laban <jerome@platform.uno>
Date: Sat, 15 Mar 2025 23:29:16 -0400
Subject: [PATCH 2/5] chore: Adjust test name, use function for conditional
 return

---
 .../Windows_UI_Xaml_Controls/Given_WebView2.cs     | 14 ++++++++------
 .../WebView/Native/Wasm/NativeWebView.wasm.cs      |  6 +++++-
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
index 54629da0d8a6..78e79e0408d8 100644
--- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
@@ -11,7 +11,7 @@ namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls;
 
 [TestClass]
 [RunsOnUIThread]
-public class Given_WebView
+public class Given_WebView2
 {
 	[TestMethod]
 	public async Task When_InvokeScriptAsync()
@@ -37,11 +37,13 @@ public async Task When_InvokeScriptAsync()
 			// may be set to true too early on wasm.
 			color = await webView.ExecuteScriptAsync(
 				"""
-				let testElement = document.getElementById('test');
-				if(testElement){
-					return testElement.style.backgroundColor.toString();
-				}
-				return "";
+				(function () {
+					let testElement = document.getElementById('test');
+					if(testElement){
+						return testElement.style.backgroundColor.toString();
+					}
+					return "";
+				})()
 				""");
 
 		} while (sw.Elapsed < TimeSpan.FromSeconds(5) && string.IsNullOrEmpty(color));
diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs
index d16e0af64bc8..bec23aab3b26 100644
--- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs
@@ -48,7 +48,11 @@ private void OnNavigationCompleted(object sender, EventArgs e)
 		_coreWebView.RaiseNavigationCompleted(uri, true, 200, CoreWebView2WebErrorStatus.Unknown);
 	}
 
-	public Task<string> ExecuteScriptAsync(string script, CancellationToken token) => Task.FromResult(NativeMethods.ExecuteScript(HtmlId, script));
+	public async Task<string> ExecuteScriptAsync(string script, CancellationToken token)
+	{
+		await Task.Yield();
+		return NativeMethods.ExecuteScript(HtmlId, script);
+	}
 
 	public Task<string> InvokeScriptAsync(string script, string[] arguments, CancellationToken token) => Task.FromResult<string>("");
 

From c3646509f837532933d8ff7cf93367284ff1fc96 Mon Sep 17 00:00:00 2001
From: Jerome Laban <jerome@platform.uno>
Date: Mon, 17 Mar 2025 09:59:41 -0400
Subject: [PATCH 3/5] chore: Adjust for string quoting

---
 .../Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs         | 4 ++--
 .../Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs  | 5 ++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
index 78e79e0408d8..38a5a5bf5b71 100644
--- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
@@ -48,13 +48,13 @@ public async Task When_InvokeScriptAsync()
 
 		} while (sw.Elapsed < TimeSpan.FromSeconds(5) && string.IsNullOrEmpty(color));
 
-		Assert.AreEqual("blue", color);
+		Assert.AreEqual("\"blue\"", color);
 
 		// Change color to red
 		await webView.ExecuteScriptAsync("document.getElementById('test').style.backgroundColor = 'red'");
 		color = await webView.ExecuteScriptAsync("document.getElementById('test').style.backgroundColor.toString()");
 
-		Assert.AreEqual("red", color);
+		Assert.AreEqual("\"red\"", color);
 	}
 }
 #endif
diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs
index bec23aab3b26..37dd0e279b96 100644
--- a/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/WebView/Native/Wasm/NativeWebView.wasm.cs
@@ -51,7 +51,10 @@ private void OnNavigationCompleted(object sender, EventArgs e)
 	public async Task<string> ExecuteScriptAsync(string script, CancellationToken token)
 	{
 		await Task.Yield();
-		return NativeMethods.ExecuteScript(HtmlId, script);
+		var result = NativeMethods.ExecuteScript(HtmlId, script);
+
+		// String needs to be wrapped in quotes to match Windows behavior
+		return $"\"{result.Replace("\"", "\\\"")}\"";
 	}
 
 	public Task<string> InvokeScriptAsync(string script, string[] arguments, CancellationToken token) => Task.FromResult<string>("");

From 65602446afbdfb8b33a9a3ae5012ff445a168f1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laban?= <jlaban@gmail.com>
Date: Mon, 17 Mar 2025 21:10:37 -0400
Subject: [PATCH 4/5] chore: Adjust for skia targets

---
 .../Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs         | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
index 38a5a5bf5b71..3f6d9c55a6e2 100644
--- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
@@ -14,6 +14,9 @@ namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls;
 public class Given_WebView2
 {
 	[TestMethod]
+#if __SKIA__
+	[Ignore("WebView2 is not yet supported on skia targets")]
+#endif
 	public async Task When_InvokeScriptAsync()
 	{
 		var border = new Border();
@@ -46,7 +49,7 @@ public async Task When_InvokeScriptAsync()
 				})()
 				""");
 
-		} while (sw.Elapsed < TimeSpan.FromSeconds(5) && string.IsNullOrEmpty(color));
+		} while (sw.Elapsed < TimeSpan.FromSeconds(5) && string.IsNullOrEmpty(color.Replace("\"", "")));
 
 		Assert.AreEqual("\"blue\"", color);
 

From a7beb8796fd1a5f77ba072df3e393067c346f12d Mon Sep 17 00:00:00 2001
From: Jerome Laban <jerome@platform.uno>
Date: Tue, 18 Mar 2025 08:34:49 -0400
Subject: [PATCH 5/5] chore: Adjust timeout for iOS

---
 .../Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs          | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
index 3f6d9c55a6e2..ca10e0cbaa6a 100644
--- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_WebView2.cs
@@ -29,7 +29,7 @@ public async Task When_InvokeScriptAsync()
 		await TestServices.WindowHelper.WaitForLoaded(border);
 		webView.NavigationCompleted += (sender, e) => navigated = true;
 		webView.NavigateToString("<html><body><div id='test' style='width: 100px; height: 100px; background-color: blue;' /></body></html>");
-		await TestServices.WindowHelper.WaitFor(() => navigated);
+		await TestServices.WindowHelper.WaitFor(() => navigated, timeoutMS: 10000);
 
 		var sw = Stopwatch.StartNew();
 		string color = null;
@@ -49,7 +49,7 @@ public async Task When_InvokeScriptAsync()
 				})()
 				""");
 
-		} while (sw.Elapsed < TimeSpan.FromSeconds(5) && string.IsNullOrEmpty(color.Replace("\"", "")));
+		} while (sw.Elapsed < TimeSpan.FromSeconds(10) && string.IsNullOrEmpty(color.Replace("\"", "")));
 
 		Assert.AreEqual("\"blue\"", color);