Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: avoid duplicated declaration error on xml generation. #4615

Merged
merged 4 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import kotlin.coroutines.resume


private const val GET_HTML_SCRIPT = """
(function() {
const blacklistedTags = ['script', 'style', 'head', 'meta'];
const blackListedTagsSelector = blacklistedTags.join(',');

(function() {
// Clone the entire document
var clonedDoc = document.documentElement.cloneNode(true);

Expand Down
60 changes: 55 additions & 5 deletions detox/ios/Detox/Utilities/ViewHierarchyGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import UIKit
import WebKit

private let GET_HTML_SCRIPT = """
(function() {
const blacklistedTags = ['script', 'style', 'head', 'meta'];
const blackListedTagsSelector = blacklistedTags.join(',');

(function() {
// Clone the entire document
var clonedDoc = document.documentElement.cloneNode(true);

Expand Down 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))
}
}
}
11 changes: 11 additions & 0 deletions detox/test/e2e/06.device.view-hierarchy.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const {expectViewHierarchySnapshotToMatch} = require("./utils/snapshot");

const jestExpect = require('expect').default;

describe('generate view hierarchy', () => {
beforeAll(async () => {
await device.launchApp();
Expand All @@ -26,4 +28,13 @@ describe('generate view hierarchy', () => {
const hierarchy = await device.generateViewHierarchyXml();
await expectViewHierarchySnapshotToMatch(hierarchy, `view-hierarchy-web-view`);
});

it('generateViewHierarchyXml() - should generate consistent consecutive view hierarchies', async () => {
await element(by.text('WebView')).tap();

const hierarchy1 = await device.generateViewHierarchyXml();
const hierarchy2 = await device.generateViewHierarchyXml();

jestExpect(hierarchy1).toEqual(hierarchy2);
});
});
Loading