From 9974743bd29953544dee0c5d3fb960af9340d409 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:07:39 +0000 Subject: [PATCH 01/24] Initial plan From 3ff1cd93519e56147080bb59b0585fb988af170c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:14:41 +0000 Subject: [PATCH 02/24] Add custom user agent to iOS and Android WebViews Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../main/java/org/wordpress/gutenberg/GutenbergView.kt | 6 ++++++ .../GutenbergKit/Sources/EditorViewController.swift | 1 + ios/Sources/GutenbergKit/Sources/GBWebView.swift | 10 ++++++++++ 3 files changed, 17 insertions(+) diff --git a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt index 6ea3abea..b284eefd 100644 --- a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt +++ b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt @@ -125,6 +125,11 @@ class GutenbergView : WebView { this.settings.javaScriptCanOpenWindowsAutomatically = true this.settings.javaScriptEnabled = true this.settings.domStorageEnabled = true + + // Set custom user agent + val defaultUserAgent = this.settings.userAgentString + this.settings.userAgentString = "$defaultUserAgent GutenbergKit/$VERSION" + this.addJavascriptInterface(this, "editorDelegate") this.visibility = View.GONE @@ -720,6 +725,7 @@ class GutenbergView : WebView { companion object { private const val ASSET_LOADING_TIMEOUT_MS = 5000L + private const val VERSION = "0.11.1" // Warmup state management private var warmupHandler: Handler? = null diff --git a/ios/Sources/GutenbergKit/Sources/EditorViewController.swift b/ios/Sources/GutenbergKit/Sources/EditorViewController.swift index f684546a..e9738782 100644 --- a/ios/Sources/GutenbergKit/Sources/EditorViewController.swift +++ b/ios/Sources/GutenbergKit/Sources/EditorViewController.swift @@ -177,6 +177,7 @@ public final class EditorViewController: UIViewController, GutenbergEditorContro self.webView = GBWebView(frame: .zero, configuration: config) self.webView.scrollView.keyboardDismissMode = .interactive + self.webView.customUserAgent = GBWebView.createCustomUserAgent() self.isWarmupMode = isWarmupMode diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index 7c036fe8..34d227b6 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -1,6 +1,16 @@ import WebKit class GBWebView: WKWebView { + + /// The GutenbergKit version string + static let version = "0.11.1" + + /// Creates a custom user agent string by appending GutenbergKit identifier to the default user agent + static func createCustomUserAgent() -> String { + let webView = WKWebView() + let defaultUserAgent = webView.value(forKey: "userAgent") as? String ?? "" + return "\(defaultUserAgent) GutenbergKit/\(version)" + } #if canImport(UIKit) /// Disables the default bottom bar that competes with the Gutenberg inserter From e41c61b118274353ddadbb55ef0a2cf6dfcaf360 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:15:33 +0000 Subject: [PATCH 03/24] Add tests for custom user agent functionality Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../wordpress/gutenberg/GutenbergViewTest.kt | 16 ++++++++++ .../GutenbergKitTests/GBWebViewTests.swift | 32 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 ios/Tests/GutenbergKitTests/GBWebViewTests.swift diff --git a/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt b/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt index ede20c98..ba2834a0 100644 --- a/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt +++ b/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt @@ -147,4 +147,20 @@ class GutenbergViewTest { assertEquals("File path callback should be null after reset", null, gutenbergView.filePathCallback) } + + @Test + fun `initializeWebView sets custom user agent with GutenbergKit identifier`() { + // Given + val gutenbergView = GutenbergView(RuntimeEnvironment.getApplication()) + + // When + gutenbergView.initializeWebView() + + // Then + val userAgent = gutenbergView.settings.userAgentString + assertTrue("User agent should contain GutenbergKit identifier", + userAgent.contains("GutenbergKit/")) + assertTrue("User agent should contain version number", + userAgent.contains("GutenbergKit/0.11.1")) + } } diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift new file mode 100644 index 00000000..4ce7ef85 --- /dev/null +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -0,0 +1,32 @@ +import XCTest +import WebKit +@testable import GutenbergKit + +final class GBWebViewTests: XCTestCase { + + func testCreateCustomUserAgent() { + // When + let customUserAgent = GBWebView.createCustomUserAgent() + + // Then + XCTAssertTrue(customUserAgent.contains("GutenbergKit/"), + "User agent should contain GutenbergKit identifier") + XCTAssertTrue(customUserAgent.contains("GutenbergKit/0.11.1"), + "User agent should contain version number") + } + + func testCustomUserAgentAppendsToDefault() { + // Given + let defaultWebView = WKWebView() + let defaultUserAgent = defaultWebView.value(forKey: "userAgent") as? String ?? "" + + // When + let customUserAgent = GBWebView.createCustomUserAgent() + + // Then + XCTAssertTrue(customUserAgent.hasPrefix(defaultUserAgent), + "Custom user agent should start with default user agent") + XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/0.11.1"), + "Custom user agent should end with GutenbergKit identifier") + } +} From a09b7e93bc4aeba27bdb7a665216ba24c49d2bdd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:16:35 +0000 Subject: [PATCH 04/24] Set custom user agent in HTMLWebViewRenderer for consistency Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift b/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift index 991b12a3..ad7ec168 100644 --- a/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift +++ b/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift @@ -94,6 +94,7 @@ final class HTMLWebViewRenderer { // Create web view with small initial frame for off-screen rendering // Frame will be adjusted per render based on viewport width and content height webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 1200, height: 100), configuration: config) + webView.customUserAgent = GBWebView.createCustomUserAgent() delegate = RenderDelegate() webView.navigationDelegate = delegate From 24cc77ec9f167ede896aad52815fa7901c91a5d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:17:40 +0000 Subject: [PATCH 05/24] Cache default user agent and improve test robustness Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../GutenbergKit/Sources/GBWebView.swift | 8 +++++-- .../GutenbergKitTests/GBWebViewTests.swift | 22 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index 34d227b6..57d983dc 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -5,10 +5,14 @@ class GBWebView: WKWebView { /// The GutenbergKit version string static let version = "0.11.1" + /// Cached default user agent to avoid repeated WKWebView instantiation + private static let defaultUserAgent: String = { + let webView = WKWebView() + return webView.value(forKey: "userAgent") as? String ?? "" + }() + /// Creates a custom user agent string by appending GutenbergKit identifier to the default user agent static func createCustomUserAgent() -> String { - let webView = WKWebView() - let defaultUserAgent = webView.value(forKey: "userAgent") as? String ?? "" return "\(defaultUserAgent) GutenbergKit/\(version)" } diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index 4ce7ef85..acd8e42e 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -13,20 +13,28 @@ final class GBWebViewTests: XCTestCase { "User agent should contain GutenbergKit identifier") XCTAssertTrue(customUserAgent.contains("GutenbergKit/0.11.1"), "User agent should contain version number") + XCTAssertTrue(customUserAgent.contains("Mozilla"), + "User agent should contain Mozilla identifier from default user agent") } - func testCustomUserAgentAppendsToDefault() { - // Given - let defaultWebView = WKWebView() - let defaultUserAgent = defaultWebView.value(forKey: "userAgent") as? String ?? "" - + func testCustomUserAgentEndsWithGutenbergKitIdentifier() { // When let customUserAgent = GBWebView.createCustomUserAgent() // Then - XCTAssertTrue(customUserAgent.hasPrefix(defaultUserAgent), - "Custom user agent should start with default user agent") XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/0.11.1"), "Custom user agent should end with GutenbergKit identifier") } + + func testCustomUserAgentIsConsistent() { + // Given + let firstCall = GBWebView.createCustomUserAgent() + + // When + let secondCall = GBWebView.createCustomUserAgent() + + // Then + XCTAssertEqual(firstCall, secondCall, + "Custom user agent should be consistent across calls") + } } From 46febb2fa85d0f59b99600fb6f27076a8b7f6cda Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:19:20 +0000 Subject: [PATCH 06/24] Use public APIs and version constants in tests Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../org/wordpress/gutenberg/GutenbergView.kt | 2 +- .../wordpress/gutenberg/GutenbergViewTest.kt | 2 +- .../GutenbergKit/Sources/GBWebView.swift | 17 +++++++++++++++-- .../GutenbergKitTests/GBWebViewTests.swift | 4 ++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt index b284eefd..99694eb4 100644 --- a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt +++ b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt @@ -725,7 +725,7 @@ class GutenbergView : WebView { companion object { private const val ASSET_LOADING_TIMEOUT_MS = 5000L - private const val VERSION = "0.11.1" + internal const val VERSION = "0.11.1" // Warmup state management private var warmupHandler: Handler? = null diff --git a/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt b/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt index ba2834a0..8492c80c 100644 --- a/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt +++ b/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt @@ -161,6 +161,6 @@ class GutenbergViewTest { assertTrue("User agent should contain GutenbergKit identifier", userAgent.contains("GutenbergKit/")) assertTrue("User agent should contain version number", - userAgent.contains("GutenbergKit/0.11.1")) + userAgent.contains("GutenbergKit/${GutenbergView.VERSION}")) } } diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index 57d983dc..80fa30f9 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -5,10 +5,23 @@ class GBWebView: WKWebView { /// The GutenbergKit version string static let version = "0.11.1" - /// Cached default user agent to avoid repeated WKWebView instantiation + /// Cached default user agent, lazily initialized private static let defaultUserAgent: String = { + // Use a temporary WKWebView to get the default user agent + // We need to use evaluateJavaScript since customUserAgent is write-only let webView = WKWebView() - return webView.value(forKey: "userAgent") as? String ?? "" + let semaphore = DispatchSemaphore(value: 0) + var userAgent = "" + + webView.evaluateJavaScript("navigator.userAgent") { result, error in + if let result = result as? String { + userAgent = result + } + semaphore.signal() + } + + semaphore.wait() + return userAgent }() /// Creates a custom user agent string by appending GutenbergKit identifier to the default user agent diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index acd8e42e..f2779eb5 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -11,7 +11,7 @@ final class GBWebViewTests: XCTestCase { // Then XCTAssertTrue(customUserAgent.contains("GutenbergKit/"), "User agent should contain GutenbergKit identifier") - XCTAssertTrue(customUserAgent.contains("GutenbergKit/0.11.1"), + XCTAssertTrue(customUserAgent.contains("GutenbergKit/\(GBWebView.version)"), "User agent should contain version number") XCTAssertTrue(customUserAgent.contains("Mozilla"), "User agent should contain Mozilla identifier from default user agent") @@ -22,7 +22,7 @@ final class GBWebViewTests: XCTestCase { let customUserAgent = GBWebView.createCustomUserAgent() // Then - XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/0.11.1"), + XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/\(GBWebView.version)"), "Custom user agent should end with GutenbergKit identifier") } From 96efbf700ff74785970d8b60f29263c2ecb517ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:21:12 +0000 Subject: [PATCH 07/24] Cache custom user agent to avoid repeated WebView instantiation Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../GutenbergKit/Sources/GBWebView.swift | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index 80fa30f9..a9bcddb8 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -5,28 +5,39 @@ class GBWebView: WKWebView { /// The GutenbergKit version string static let version = "0.11.1" - /// Cached default user agent, lazily initialized - private static let defaultUserAgent: String = { - // Use a temporary WKWebView to get the default user agent - // We need to use evaluateJavaScript since customUserAgent is write-only + /// Cached custom user agent to avoid repeated WebView instantiation + private static var cachedCustomUserAgent: String? + + /// Creates a custom user agent string by appending GutenbergKit identifier to the default user agent + /// The result is cached after the first call to avoid performance overhead + static func createCustomUserAgent() -> String { + // Return cached value if available + if let cached = cachedCustomUserAgent { + return cached + } + + // Get the default user agent by creating a temporary WKWebView let webView = WKWebView() - let semaphore = DispatchSemaphore(value: 0) - var userAgent = "" + var defaultUserAgent = "" + + // Use DispatchGroup for synchronous wait + // This is safe during view initialization as it's not on a critical path + let group = DispatchGroup() + group.enter() webView.evaluateJavaScript("navigator.userAgent") { result, error in if let result = result as? String { - userAgent = result + defaultUserAgent = result } - semaphore.signal() + group.leave() } - semaphore.wait() - return userAgent - }() - - /// Creates a custom user agent string by appending GutenbergKit identifier to the default user agent - static func createCustomUserAgent() -> String { - return "\(defaultUserAgent) GutenbergKit/\(version)" + group.wait() + + // Cache and return the result + let customUserAgent = "\(defaultUserAgent) GutenbergKit/\(version)" + cachedCustomUserAgent = customUserAgent + return customUserAgent } #if canImport(UIKit) From 5602c97a0536c6a7cca2a1dcfb06454c013bf5d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 14:49:06 +0000 Subject: [PATCH 08/24] Source version from package.json instead of hardcoding in native code Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../gutenberg/GutenbergKitVersion.kt | 14 +++++ .../org/wordpress/gutenberg/GutenbergView.kt | 3 +- .../wordpress/gutenberg/GutenbergViewTest.kt | 2 +- bin/generate-version.js | 57 +++++++++++++++++++ .../GutenbergKit/Sources/GBWebView.swift | 5 +- .../Sources/GutenbergKitVersion.swift | 7 +++ .../GutenbergKitTests/GBWebViewTests.swift | 4 +- package.json | 3 +- 8 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt create mode 100755 bin/generate-version.js create mode 100644 ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift diff --git a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt new file mode 100644 index 00000000..0386dbfd --- /dev/null +++ b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt @@ -0,0 +1,14 @@ +// This file is auto-generated by bin/generate-version.js +// Do not edit manually - changes will be overwritten + +package org.wordpress.gutenberg + +/** + * GutenbergKit version information + */ +object GutenbergKitVersion { + /** + * The GutenbergKit version string + */ + const val VERSION = "0.11.1" +} diff --git a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt index 99694eb4..572b484a 100644 --- a/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt +++ b/android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt @@ -128,7 +128,7 @@ class GutenbergView : WebView { // Set custom user agent val defaultUserAgent = this.settings.userAgentString - this.settings.userAgentString = "$defaultUserAgent GutenbergKit/$VERSION" + this.settings.userAgentString = "$defaultUserAgent GutenbergKit/${GutenbergKitVersion.VERSION}" this.addJavascriptInterface(this, "editorDelegate") this.visibility = View.GONE @@ -725,7 +725,6 @@ class GutenbergView : WebView { companion object { private const val ASSET_LOADING_TIMEOUT_MS = 5000L - internal const val VERSION = "0.11.1" // Warmup state management private var warmupHandler: Handler? = null diff --git a/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt b/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt index 8492c80c..b070e14a 100644 --- a/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt +++ b/android/Gutenberg/src/test/java/org/wordpress/gutenberg/GutenbergViewTest.kt @@ -161,6 +161,6 @@ class GutenbergViewTest { assertTrue("User agent should contain GutenbergKit identifier", userAgent.contains("GutenbergKit/")) assertTrue("User agent should contain version number", - userAgent.contains("GutenbergKit/${GutenbergView.VERSION}")) + userAgent.contains("GutenbergKit/${GutenbergKitVersion.VERSION}")) } } diff --git a/bin/generate-version.js b/bin/generate-version.js new file mode 100755 index 00000000..cccdd68c --- /dev/null +++ b/bin/generate-version.js @@ -0,0 +1,57 @@ +#!/usr/bin/env node + +/** + * Generate version files for iOS and Android from package.json + * This ensures a single source of truth for the version number + */ + +import { readFileSync, writeFileSync } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const rootDir = join(__dirname, '..'); + +// Read version from package.json +const packageJson = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf8')); +const version = packageJson.version; + +console.log(`[GBK] Generating version files for version ${version}`); + +// Generate iOS version file +const iosVersionContent = `// This file is auto-generated by bin/generate-version.js +// Do not edit manually - changes will be overwritten + +extension GutenbergKit { + /// The GutenbergKit version string + public static let version = "${version}" +} +`; + +const iosVersionPath = join(rootDir, 'ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift'); +writeFileSync(iosVersionPath, iosVersionContent, 'utf8'); +console.log(`[GBK] Generated ${iosVersionPath}`); + +// Generate Android version file +const androidVersionContent = `// This file is auto-generated by bin/generate-version.js +// Do not edit manually - changes will be overwritten + +package org.wordpress.gutenberg + +/** + * GutenbergKit version information + */ +object GutenbergKitVersion { + /** + * The GutenbergKit version string + */ + const val VERSION = "${version}" +} +`; + +const androidVersionPath = join(rootDir, 'android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt'); +writeFileSync(androidVersionPath, androidVersionContent, 'utf8'); +console.log(`[GBK] Generated ${androidVersionPath}`); + +console.log('[GBK] Version files generated successfully'); diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index a9bcddb8..e17916cd 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -2,9 +2,6 @@ import WebKit class GBWebView: WKWebView { - /// The GutenbergKit version string - static let version = "0.11.1" - /// Cached custom user agent to avoid repeated WebView instantiation private static var cachedCustomUserAgent: String? @@ -35,7 +32,7 @@ class GBWebView: WKWebView { group.wait() // Cache and return the result - let customUserAgent = "\(defaultUserAgent) GutenbergKit/\(version)" + let customUserAgent = "\(defaultUserAgent) GutenbergKit/\(GutenbergKit.version)" cachedCustomUserAgent = customUserAgent return customUserAgent } diff --git a/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift b/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift new file mode 100644 index 00000000..75d8cf03 --- /dev/null +++ b/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift @@ -0,0 +1,7 @@ +// This file is auto-generated by bin/generate-version.js +// Do not edit manually - changes will be overwritten + +extension GutenbergKit { + /// The GutenbergKit version string + public static let version = "0.11.1" +} diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index f2779eb5..fa57696f 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -11,7 +11,7 @@ final class GBWebViewTests: XCTestCase { // Then XCTAssertTrue(customUserAgent.contains("GutenbergKit/"), "User agent should contain GutenbergKit identifier") - XCTAssertTrue(customUserAgent.contains("GutenbergKit/\(GBWebView.version)"), + XCTAssertTrue(customUserAgent.contains("GutenbergKit/\(GutenbergKit.version)"), "User agent should contain version number") XCTAssertTrue(customUserAgent.contains("Mozilla"), "User agent should contain Mozilla identifier from default user agent") @@ -22,7 +22,7 @@ final class GBWebViewTests: XCTestCase { let customUserAgent = GBWebView.createCustomUserAgent() // Then - XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/\(GBWebView.version)"), + XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/\(GutenbergKit.version)"), "Custom user agent should end with GutenbergKit identifier") } diff --git a/package.json b/package.json index afd82ff0..4ee09849 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,10 @@ "dev:tools": "react-devtools", "build": "vite --emptyOutDir build", "format": "prettier --write .", + "generate-version": "node bin/generate-version.js", "lint:js": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "lint:js:fix": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0 --fix", - "postinstall": "patch-package && npm run prep-translations", + "postinstall": "patch-package && npm run prep-translations && npm run generate-version", "prep-translations": "node bin/prep-translations.js", "preview": "vite preview --host", "test:unit": "vitest run", From ca964571cfe480ebf1d0e940744856d1f3d3145a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:15:08 +0000 Subject: [PATCH 09/24] Use logger utility and format generate-version.js Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- bin/generate-version.js | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/bin/generate-version.js b/bin/generate-version.js index cccdd68c..602e2ebd 100755 --- a/bin/generate-version.js +++ b/bin/generate-version.js @@ -5,19 +5,29 @@ * This ensures a single source of truth for the version number */ +/** + * External dependencies + */ import { readFileSync, writeFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const rootDir = join(__dirname, '..'); +/** + * Internal dependencies + */ +import { info } from '../src/utils/logger.js'; + +const __filename = fileURLToPath( import.meta.url ); +const __dirname = dirname( __filename ); +const rootDir = join( __dirname, '..' ); // Read version from package.json -const packageJson = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf8')); +const packageJson = JSON.parse( + readFileSync( join( rootDir, 'package.json' ), 'utf8' ) +); const version = packageJson.version; -console.log(`[GBK] Generating version files for version ${version}`); +info( `Generating version files for version ${ version }` ); // Generate iOS version file const iosVersionContent = `// This file is auto-generated by bin/generate-version.js @@ -25,13 +35,16 @@ const iosVersionContent = `// This file is auto-generated by bin/generate-versio extension GutenbergKit { /// The GutenbergKit version string - public static let version = "${version}" + public static let version = "${ version }" } `; -const iosVersionPath = join(rootDir, 'ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift'); -writeFileSync(iosVersionPath, iosVersionContent, 'utf8'); -console.log(`[GBK] Generated ${iosVersionPath}`); +const iosVersionPath = join( + rootDir, + 'ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift' +); +writeFileSync( iosVersionPath, iosVersionContent, 'utf8' ); +info( `Generated ${ iosVersionPath }` ); // Generate Android version file const androidVersionContent = `// This file is auto-generated by bin/generate-version.js @@ -46,12 +59,15 @@ object GutenbergKitVersion { /** * The GutenbergKit version string */ - const val VERSION = "${version}" + const val VERSION = "${ version }" } `; -const androidVersionPath = join(rootDir, 'android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt'); -writeFileSync(androidVersionPath, androidVersionContent, 'utf8'); -console.log(`[GBK] Generated ${androidVersionPath}`); +const androidVersionPath = join( + rootDir, + 'android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergKitVersion.kt' +); +writeFileSync( androidVersionPath, androidVersionContent, 'utf8' ); +info( `Generated ${ androidVersionPath }` ); -console.log('[GBK] Version files generated successfully'); +info( 'Version files generated successfully' ); From 04196322588fe203baee88aa6e44359fd7998e8f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:24:32 +0000 Subject: [PATCH 10/24] Fix Swift compilation: use enum namespace instead of extension Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- bin/generate-version.js | 3 ++- ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/generate-version.js b/bin/generate-version.js index 602e2ebd..558828c1 100755 --- a/bin/generate-version.js +++ b/bin/generate-version.js @@ -33,7 +33,8 @@ info( `Generating version files for version ${ version }` ); const iosVersionContent = `// This file is auto-generated by bin/generate-version.js // Do not edit manually - changes will be overwritten -extension GutenbergKit { +/// GutenbergKit version information namespace +public enum GutenbergKit { /// The GutenbergKit version string public static let version = "${ version }" } diff --git a/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift b/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift index 75d8cf03..f9003b3a 100644 --- a/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift +++ b/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift @@ -1,7 +1,8 @@ // This file is auto-generated by bin/generate-version.js // Do not edit manually - changes will be overwritten -extension GutenbergKit { +/// GutenbergKit version information namespace +public enum GutenbergKit { /// The GutenbergKit version string public static let version = "0.11.1" } From 3bdab9db608d46916f19622cde810689e9381bb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 18:01:22 +0000 Subject: [PATCH 11/24] Fix Swift module name conflict: rename to GBKVersion Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- bin/generate-version.js | 4 ++-- ios/Sources/GutenbergKit/Sources/GBWebView.swift | 2 +- ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift | 4 ++-- ios/Tests/GutenbergKitTests/GBWebViewTests.swift | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/generate-version.js b/bin/generate-version.js index 558828c1..3613a73d 100755 --- a/bin/generate-version.js +++ b/bin/generate-version.js @@ -33,8 +33,8 @@ info( `Generating version files for version ${ version }` ); const iosVersionContent = `// This file is auto-generated by bin/generate-version.js // Do not edit manually - changes will be overwritten -/// GutenbergKit version information namespace -public enum GutenbergKit { +/// GutenbergKit version information +public struct GBKVersion { /// The GutenbergKit version string public static let version = "${ version }" } diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index e17916cd..46505c14 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -32,7 +32,7 @@ class GBWebView: WKWebView { group.wait() // Cache and return the result - let customUserAgent = "\(defaultUserAgent) GutenbergKit/\(GutenbergKit.version)" + let customUserAgent = "\(defaultUserAgent) GutenbergKit/\(GBKVersion.version)" cachedCustomUserAgent = customUserAgent return customUserAgent } diff --git a/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift b/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift index f9003b3a..35b1ffc3 100644 --- a/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift +++ b/ios/Sources/GutenbergKit/Sources/GutenbergKitVersion.swift @@ -1,8 +1,8 @@ // This file is auto-generated by bin/generate-version.js // Do not edit manually - changes will be overwritten -/// GutenbergKit version information namespace -public enum GutenbergKit { +/// GutenbergKit version information +public struct GBKVersion { /// The GutenbergKit version string public static let version = "0.11.1" } diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index fa57696f..823cf3ca 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -11,7 +11,7 @@ final class GBWebViewTests: XCTestCase { // Then XCTAssertTrue(customUserAgent.contains("GutenbergKit/"), "User agent should contain GutenbergKit identifier") - XCTAssertTrue(customUserAgent.contains("GutenbergKit/\(GutenbergKit.version)"), + XCTAssertTrue(customUserAgent.contains("GutenbergKit/\(GBKVersion.version)"), "User agent should contain version number") XCTAssertTrue(customUserAgent.contains("Mozilla"), "User agent should contain Mozilla identifier from default user agent") @@ -22,7 +22,7 @@ final class GBWebViewTests: XCTestCase { let customUserAgent = GBWebView.createCustomUserAgent() // Then - XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/\(GutenbergKit.version)"), + XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/\(GBKVersion.version)"), "Custom user agent should end with GutenbergKit identifier") } From edf1acb95a8e298bacc6934b17783c591c8dc330 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:24:26 +0000 Subject: [PATCH 12/24] Use applicationNameForUserAgent instead of customUserAgent Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../Sources/EditorViewController.swift | 2 +- .../GutenbergKit/Sources/GBWebView.swift | 35 ------------------ .../HTMLPreview/HTMLWebViewRenderer.swift | 2 +- .../GutenbergKitTests/GBWebViewTests.swift | 36 ++++++------------- 4 files changed, 13 insertions(+), 62 deletions(-) diff --git a/ios/Sources/GutenbergKit/Sources/EditorViewController.swift b/ios/Sources/GutenbergKit/Sources/EditorViewController.swift index e9738782..9403c36c 100644 --- a/ios/Sources/GutenbergKit/Sources/EditorViewController.swift +++ b/ios/Sources/GutenbergKit/Sources/EditorViewController.swift @@ -177,7 +177,7 @@ public final class EditorViewController: UIViewController, GutenbergEditorContro self.webView = GBWebView(frame: .zero, configuration: config) self.webView.scrollView.keyboardDismissMode = .interactive - self.webView.customUserAgent = GBWebView.createCustomUserAgent() + self.webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" self.isWarmupMode = isWarmupMode diff --git a/ios/Sources/GutenbergKit/Sources/GBWebView.swift b/ios/Sources/GutenbergKit/Sources/GBWebView.swift index 46505c14..7c036fe8 100644 --- a/ios/Sources/GutenbergKit/Sources/GBWebView.swift +++ b/ios/Sources/GutenbergKit/Sources/GBWebView.swift @@ -1,41 +1,6 @@ import WebKit class GBWebView: WKWebView { - - /// Cached custom user agent to avoid repeated WebView instantiation - private static var cachedCustomUserAgent: String? - - /// Creates a custom user agent string by appending GutenbergKit identifier to the default user agent - /// The result is cached after the first call to avoid performance overhead - static func createCustomUserAgent() -> String { - // Return cached value if available - if let cached = cachedCustomUserAgent { - return cached - } - - // Get the default user agent by creating a temporary WKWebView - let webView = WKWebView() - var defaultUserAgent = "" - - // Use DispatchGroup for synchronous wait - // This is safe during view initialization as it's not on a critical path - let group = DispatchGroup() - group.enter() - - webView.evaluateJavaScript("navigator.userAgent") { result, error in - if let result = result as? String { - defaultUserAgent = result - } - group.leave() - } - - group.wait() - - // Cache and return the result - let customUserAgent = "\(defaultUserAgent) GutenbergKit/\(GBKVersion.version)" - cachedCustomUserAgent = customUserAgent - return customUserAgent - } #if canImport(UIKit) /// Disables the default bottom bar that competes with the Gutenberg inserter diff --git a/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift b/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift index ad7ec168..a3891172 100644 --- a/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift +++ b/ios/Sources/GutenbergKit/Sources/Views/HTMLPreview/HTMLWebViewRenderer.swift @@ -94,7 +94,7 @@ final class HTMLWebViewRenderer { // Create web view with small initial frame for off-screen rendering // Frame will be adjusted per render based on viewport width and content height webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 1200, height: 100), configuration: config) - webView.customUserAgent = GBWebView.createCustomUserAgent() + webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" delegate = RenderDelegate() webView.navigationDelegate = delegate diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index 823cf3ca..59df757c 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -4,37 +4,23 @@ import WebKit final class GBWebViewTests: XCTestCase { - func testCreateCustomUserAgent() { - // When - let customUserAgent = GBWebView.createCustomUserAgent() + func testApplicationNameForUserAgent() { + // Given + let webView = GBWebView() - // Then - XCTAssertTrue(customUserAgent.contains("GutenbergKit/"), - "User agent should contain GutenbergKit identifier") - XCTAssertTrue(customUserAgent.contains("GutenbergKit/\(GBKVersion.version)"), - "User agent should contain version number") - XCTAssertTrue(customUserAgent.contains("Mozilla"), - "User agent should contain Mozilla identifier from default user agent") - } - - func testCustomUserAgentEndsWithGutenbergKitIdentifier() { // When - let customUserAgent = GBWebView.createCustomUserAgent() + webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" // Then - XCTAssertTrue(customUserAgent.hasSuffix(" GutenbergKit/\(GBKVersion.version)"), - "Custom user agent should end with GutenbergKit identifier") + XCTAssertEqual(webView.applicationNameForUserAgent, "GutenbergKit/\(GBKVersion.version)", + "Application name should be set correctly") } - func testCustomUserAgentIsConsistent() { - // Given - let firstCall = GBWebView.createCustomUserAgent() - - // When - let secondCall = GBWebView.createCustomUserAgent() - + func testVersionConstantExists() { // Then - XCTAssertEqual(firstCall, secondCall, - "Custom user agent should be consistent across calls") + XCTAssertFalse(GBKVersion.version.isEmpty, + "Version constant should not be empty") + XCTAssertTrue(GBKVersion.version.contains("."), + "Version should be in semantic versioning format") } } From 1ad006f574f49b0a384e3cf972681c2833069d54 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:43:03 +0000 Subject: [PATCH 13/24] Convert tests to Swift Testing and verify navigator.userAgent Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- .../GutenbergKitTests/GBWebViewTests.swift | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index 59df757c..2bc67c91 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -1,10 +1,13 @@ -import XCTest +import Foundation +import Testing import WebKit @testable import GutenbergKit -final class GBWebViewTests: XCTestCase { +@Suite("GBWebView Tests") +struct GBWebViewTests { - func testApplicationNameForUserAgent() { + @Test("Application name for user agent is set correctly") + func testApplicationNameForUserAgent() async throws { // Given let webView = GBWebView() @@ -12,15 +15,36 @@ final class GBWebViewTests: XCTestCase { webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" // Then - XCTAssertEqual(webView.applicationNameForUserAgent, "GutenbergKit/\(GBKVersion.version)", - "Application name should be set correctly") + #expect(webView.applicationNameForUserAgent == "GutenbergKit/\(GBKVersion.version)") } - func testVersionConstantExists() { + @Test("Version constant exists and is valid") + func testVersionConstantExists() async throws { // Then - XCTAssertFalse(GBKVersion.version.isEmpty, - "Version constant should not be empty") - XCTAssertTrue(GBKVersion.version.contains("."), - "Version should be in semantic versioning format") + #expect(!GBKVersion.version.isEmpty) + #expect(GBKVersion.version.contains(".")) + } + + @Test("Navigator user agent includes GutenbergKit identifier") + func testNavigatorUserAgentIncludesGutenbergKit() async throws { + // Given + let webView = GBWebView() + webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" + + // Load a simple HTML page to ensure the WebView is ready + let html = "
Test" + webView.loadHTMLString(html, baseURL: nil) + + // Wait for the page to load + try await Task.sleep(for: .milliseconds(500)) + + // When - evaluate navigator.userAgent in the WebView + let userAgent = try await webView.evaluateJavaScript("navigator.userAgent") as? String + + // Then + #expect(userAgent != nil) + if let userAgent = userAgent { + #expect(userAgent.contains("GutenbergKit/\(GBKVersion.version)")) + } } } From d183fa5cf545a2e77157df092e474e42186ee195 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:45:13 +0000 Subject: [PATCH 14/24] Simplify test assertion using optional chaining Co-authored-by: dcalhoun <438664+dcalhoun@users.noreply.github.com> --- ios/Tests/GutenbergKitTests/GBWebViewTests.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index 2bc67c91..0620acc8 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -42,9 +42,6 @@ struct GBWebViewTests { let userAgent = try await webView.evaluateJavaScript("navigator.userAgent") as? String // Then - #expect(userAgent != nil) - if let userAgent = userAgent { - #expect(userAgent.contains("GutenbergKit/\(GBKVersion.version)")) - } + #expect(userAgent?.contains("GutenbergKit/\(GBKVersion.version)") == true) } } From d6ac4787946629851f0a579830ea64b92188f0bf Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:35:15 -0700 Subject: [PATCH 15/24] Fix tests --- .../GutenbergKitTests/GBWebViewTests.swift | 48 ++++--------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift index 0620acc8..983ec4e6 100644 --- a/ios/Tests/GutenbergKitTests/GBWebViewTests.swift +++ b/ios/Tests/GutenbergKitTests/GBWebViewTests.swift @@ -1,47 +1,19 @@ -import Foundation import Testing import WebKit @testable import GutenbergKit -@Suite("GBWebView Tests") struct GBWebViewTests { - - @Test("Application name for user agent is set correctly") + + @MainActor func testApplicationNameForUserAgent() async throws { - // Given - let webView = GBWebView() - - // When - webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" - - // Then - #expect(webView.applicationNameForUserAgent == "GutenbergKit/\(GBKVersion.version)") - } - - @Test("Version constant exists and is valid") - func testVersionConstantExists() async throws { - // Then - #expect(!GBKVersion.version.isEmpty) - #expect(GBKVersion.version.contains(".")) + let result = try await GBWebView().evaluateJavaScript("navigator.userAgent") + let string = try #require(result as? String) + + #expect(string.hasSuffix("GutenbergKit/\(GBKVersion.version)")) } - - @Test("Navigator user agent includes GutenbergKit identifier") - func testNavigatorUserAgentIncludesGutenbergKit() async throws { - // Given - let webView = GBWebView() - webView.applicationNameForUserAgent = "GutenbergKit/\(GBKVersion.version)" - - // Load a simple HTML page to ensure the WebView is ready - let html = "Test" - webView.loadHTMLString(html, baseURL: nil) - - // Wait for the page to load - try await Task.sleep(for: .milliseconds(500)) - - // When - evaluate navigator.userAgent in the WebView - let userAgent = try await webView.evaluateJavaScript("navigator.userAgent") as? String - - // Then - #expect(userAgent?.contains("GutenbergKit/\(GBKVersion.version)") == true) + + func testVersionConstantExists() { + #expect(GBKVersion.version.isEmpty, "Version constant should not be empty") + #expect(GBKVersion.version.contains("."), "Version should be in semantic versioning format") } } From 920788b8bbf2fbd2fd1e27ad9f4c5a2d4a82b4c0 Mon Sep 17 00:00:00 2001 From: David Calhoun