Skip to content

Commit

Permalink
fix(iOS): wait for webview to load before injecting JS to extract html.
Browse files Browse the repository at this point in the history
  • Loading branch information
asafkorem committed Oct 19, 2024
1 parent 7e084fa commit a41ea1e
Showing 1 changed file with 54 additions and 4 deletions.
58 changes: 54 additions & 4 deletions detox/ios/Detox/Utilities/ViewHierarchyGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,23 @@ struct ViewHierarchyGenerator {

@MainActor
private static func getHtmlFromWebView(_ webView: WKWebView) async -> String {
await withCheckedContinuation { continuation in
let handler = WebViewHandler()

do {
try await handler.waitForPageLoad(webView)
} catch {
print("Error waiting for page to load: \(error)")
return "<!-- Error loading page -->"
}

return await withCheckedContinuation { continuation in
webView.evaluateJavaScript(GET_HTML_SCRIPT) { result, error in
if let html = result as? String {
continuation.resume(returning: html)
} else if let error = error {
print("Error extracting HTML: \(error)")
continuation.resume(returning: "<!-- Error loading HTML -->")
continuation.resume(returning: "<!-- Error loading HTML: \(error) -->")
} else {
continuation.resume(returning: "html is empty")
continuation.resume(returning: "<!--- HTML is empty -->")
}
}
}
Expand Down Expand Up @@ -171,3 +179,45 @@ struct ViewHierarchyGenerator {
.joined()
}
}

@MainActor
class WebViewHandler: NSObject, WKNavigationDelegate {
private var loadCompletion: ((Result<Void, Error>) -> Void)?

enum WebViewError: Error {
case timeout
}

func waitForPageLoad(_ webView: WKWebView, timeoutAfter seconds: TimeInterval = 10) async throws {
webView.navigationDelegate = self

if !webView.isLoading {
return
}

return try await withCheckedThrowingContinuation { continuation in
let task = Task {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
loadCompletion?(.failure(WebViewError.timeout))
}

self.loadCompletion = { result in
task.cancel()
self.loadCompletion = nil
continuation.resume(with: result)
}
}
}

nonisolated func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
Task { @MainActor in
loadCompletion?(.success(()))
}
}

nonisolated func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
Task { @MainActor in
loadCompletion?(.failure(error))
}
}
}

0 comments on commit a41ea1e

Please sign in to comment.