Skip to content

Commit

Permalink
fix: invalidate load timer on another error happens
Browse files Browse the repository at this point in the history
  • Loading branch information
CAMOBAP committed Aug 18, 2024
1 parent 6ec4eb8 commit 3a3112f
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 9 deletions.
17 changes: 17 additions & 0 deletions Example/HCaptcha_Tests/Core/HCaptchaWebViewManager__Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -633,4 +633,21 @@ class HCaptchaWebViewManager__Tests: XCTestCase {

waitForExpectations(timeout: 10)
}

func test__HTML_Load_Error_Timeout() {
let exp = expectation(description: "didLoad never called")

let manager = HCaptchaWebViewManager(html: "<html>", apiKey: apiKey, loadingTimeout: 0.5)
manager.shouldResetOnError = false
manager.configureWebView { _ in
XCTFail("should not ask to configure the webview")
}

manager.validate(on: presenterView, resetOnError: false) { response in
XCTAssertEqual(HCaptchaError.htmlLoadError, response.error)
exp.fulfill()
}

waitForExpectations(timeout: 10)
}
}
7 changes: 4 additions & 3 deletions Example/HCaptcha_Tests/Helpers/HCaptchaConfig+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ extension HCaptchaConfig {
host: String? = nil,
theme: String = "\"light\"",
customTheme: String? = nil,
locale: Locale? = nil) throws {
locale: Locale? = nil,
loadingTimeout: TimeInterval = 5.0) throws {

try self.init(html: html,
apiKey: apiKey,
Expand All @@ -43,7 +44,8 @@ extension HCaptchaConfig {
host: host,
theme: theme,
customTheme: customTheme,
locale: locale)
locale: locale,
loadingTimeout: loadingTimeout)
}

init(apiKey: String = "some-api-key",
Expand All @@ -57,6 +59,5 @@ extension HCaptchaConfig {
host: host,
customTheme: customTheme,
locale: locale)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ extension HCaptchaWebViewManager {
html: String,
apiKey: String,
passiveApiKey: Bool = false,
endpoint: URL,
endpoint: URL = URL(string: "https://api.hcaptcha.com")!,
size: HCaptchaSize = .invisible,
orientation: HCaptchaOrientation = .portrait,
rqdata: String? = nil,
theme: String = "light",
customTheme: String? = nil,
urlOpener: HCaptchaURLOpener = HCapchaAppURLOpener()
urlOpener: HCaptchaURLOpener = HCapchaAppURLOpener(),
loadingTimeout: TimeInterval = 5
) {
let localhost = URL(string: "http://localhost")!

Expand All @@ -72,7 +73,8 @@ extension HCaptchaWebViewManager {
rqdata: rqdata,
endpoint: endpoint,
theme: theme,
customTheme: customTheme)
customTheme: customTheme,
loadingTimeout: loadingTimeout)

self.init(
config: config,
Expand Down
9 changes: 7 additions & 2 deletions HCaptcha/Classes/HCaptchaConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,12 @@ struct HCaptchaConfig: CustomDebugStringConvertible {
/// Custom theme JSON string.
let customTheme: String?

/// locale: A locale value to translate HCaptcha into a different language
/// A locale value to translate HCaptcha into a different language
let locale: Locale?

/// A time before throw the `.htmlLoadError` if HCaptcha is not loaded
let loadingTimeout: TimeInterval

/// Return actual theme value based on init params. It must return valid JS object.
var actualTheme: String {
self.customTheme ?? "\"\(theme)\""
Expand Down Expand Up @@ -205,7 +208,8 @@ struct HCaptchaConfig: CustomDebugStringConvertible {
host: String?,
theme: String,
customTheme: String?,
locale: Locale?) throws {
locale: Locale?,
loadingTimeout: TimeInterval = 5.0) throws {
guard let apiKey = apiKey ?? infoPlistKey else {
throw HCaptchaError.apiKeyNotFound
}
Expand Down Expand Up @@ -243,6 +247,7 @@ struct HCaptchaConfig: CustomDebugStringConvertible {
self.theme = theme
self.customTheme = customTheme
self.locale = locale
self.loadingTimeout = loadingTimeout
}

/**
Expand Down
10 changes: 9 additions & 1 deletion HCaptcha/Classes/HCaptchaWebViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ internal class HCaptchaWebViewManager: NSObject {
/// Keep error If it happens before validate call
fileprivate var lastError: HCaptchaError?

/// Timeout to throw `.htmlLoadError` if no `didLoad` called
fileprivate let loadingTimeout: TimeInterval

/// The webview that executes JS code
lazy var webView: WKWebView = {
let debug = Log.minLevel == .debug
Expand Down Expand Up @@ -133,6 +136,7 @@ internal class HCaptchaWebViewManager: NSObject {
self.urlOpener = urlOpener
self.baseURL = config.baseURL
self.passiveApiKey = config.passiveApiKey
self.loadingTimeout = config.loadingTimeout
super.init()
self.decoder = HCaptchaDecoder { [weak self] result in
self?.handle(result: result)
Expand Down Expand Up @@ -260,6 +264,8 @@ fileprivate extension HCaptchaWebViewManager {
}

private func handle(error: HCaptchaError) {
loadingTimer?.invalidate()
loadingTimer = nil
if error == .sessionTimeout {
if shouldResetOnError, let view = webView.superview {
reset()
Expand Down Expand Up @@ -338,7 +344,7 @@ fileprivate extension HCaptchaWebViewManager {
webView.navigationDelegate = self
}
loadingTimer?.invalidate()
loadingTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false, block: { _ in
loadingTimer = Timer.scheduledTimer(withTimeInterval: self.loadingTimeout, repeats: false, block: { _ in
self.handle(error: .htmlLoadError)
self.loadingTimer = nil
})
Expand All @@ -360,6 +366,8 @@ fileprivate extension HCaptchaWebViewManager {
Log.debug("WebViewManager.executeJS: \(command)")
guard didLoad else {
if let error = lastError {
loadingTimer?.invalidate()
loadingTimer = nil
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
Log.debug("WebViewManager complete with pendingError: \(error)")
Expand Down

0 comments on commit 3a3112f

Please sign in to comment.