parent
1c3af347e4
commit
66b70da874
|
|
@ -151,4 +151,47 @@ class DispatchQueue__Tests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 5)
|
||||
}
|
||||
|
||||
// MARK: Once
|
||||
|
||||
func test__Once__Single_Dispatch() {
|
||||
let token = 3
|
||||
var dispatchCount = 0
|
||||
|
||||
// Does dispatch the given action
|
||||
DispatchQueue.once(token: token) {
|
||||
dispatchCount = 1
|
||||
}
|
||||
|
||||
XCTAssertEqual(dispatchCount, 1)
|
||||
|
||||
// Does not dispatch again for the same token
|
||||
DispatchQueue.once(token: token) {
|
||||
dispatchCount = 2
|
||||
}
|
||||
|
||||
XCTAssertEqual(dispatchCount, 1)
|
||||
}
|
||||
|
||||
func test__Once__Multiple_Dispatches() {
|
||||
let token1 = 4
|
||||
var didDispatch1 = false
|
||||
|
||||
// Does dispatch the given action
|
||||
DispatchQueue.once(token: token1) {
|
||||
didDispatch1 = true
|
||||
}
|
||||
|
||||
XCTAssertTrue(didDispatch1)
|
||||
|
||||
// Dispatch for a different token
|
||||
let token2 = 6
|
||||
var didDispatch2 = false
|
||||
|
||||
DispatchQueue.once(token: token2) {
|
||||
didDispatch2 = true
|
||||
}
|
||||
|
||||
XCTAssertTrue(didDispatch2)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,6 +210,34 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
XCTAssertEqual(count, 1)
|
||||
}
|
||||
|
||||
func test__Configure_Web_View__Called_Again_With_Reset() {
|
||||
let exp0 = expectation(description: "configure webview 0")
|
||||
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{action: \"showReCaptcha\"}")
|
||||
manager.validate(on: presenterView) { _ in
|
||||
XCTFail("should not call completion")
|
||||
}
|
||||
|
||||
// Configure Webview
|
||||
manager.configureWebView { _ in
|
||||
manager.webView.evaluateJavaScript("execute();") { XCTAssertNil($1) }
|
||||
exp0.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 10)
|
||||
|
||||
// Reset and ensure it calls again
|
||||
let exp1 = expectation(description: "configure webview 1")
|
||||
|
||||
manager.configureWebView { _ in
|
||||
manager.webView.evaluateJavaScript("execute();") { XCTAssertNil($1) }
|
||||
exp1.fulfill()
|
||||
}
|
||||
|
||||
manager.reset()
|
||||
waitForExpectations(timeout: 10)
|
||||
}
|
||||
|
||||
// MARK: Stop
|
||||
|
||||
func test__Stop() {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ extension DispatchQueue {
|
|||
/// Stores the last call times for a given context
|
||||
private static var lastDebounceCallTimes = [AnyHashable: DispatchTime]()
|
||||
|
||||
/// Dispatched actions' token storage
|
||||
private static var onceTokenStorage = Set<AnyHashable>()
|
||||
|
||||
/// An object representing a context if none is given
|
||||
private static let nilContext = UUID()
|
||||
|
||||
|
|
@ -61,4 +64,21 @@ extension DispatchQueue {
|
|||
DispatchQueue.lastDebounceCallTimes.removeValue(forKey: context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
- parameters:
|
||||
- token: The control token for each dispatched action
|
||||
- action: The closure to be executed
|
||||
|
||||
Dispatch the action only once for each given token
|
||||
*/
|
||||
static func once(token: AnyHashable, action: () -> Void) {
|
||||
guard !onceTokenStorage.contains(token) else { return }
|
||||
|
||||
defer { objc_sync_exit(self) }
|
||||
objc_sync_enter(self)
|
||||
|
||||
onceTokenStorage.insert(token)
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ internal class ReCaptchaWebViewManager {
|
|||
/// Configures the webview for display when required
|
||||
var configureWebView: ((WKWebView) -> Void)?
|
||||
|
||||
/// The dispatch token used to ensure `configureWebView` is only called once.
|
||||
var configureWebViewDispatchToken = UUID()
|
||||
|
||||
/// If the ReCaptcha should be reset when it errors
|
||||
var shouldResetOnError = true
|
||||
|
||||
|
|
@ -152,6 +155,7 @@ internal class ReCaptchaWebViewManager {
|
|||
webview.accessibilityIdentifier = "webview"
|
||||
webview.accessibilityTraits = UIAccessibilityTraitLink
|
||||
webview.isHidden = true
|
||||
print("HIDDEN")
|
||||
|
||||
return webview
|
||||
}()
|
||||
|
|
@ -211,6 +215,7 @@ internal class ReCaptchaWebViewManager {
|
|||
*/
|
||||
func reset() {
|
||||
didFinishLoading = false
|
||||
configureWebViewDispatchToken = UUID()
|
||||
webviewDelegate.reset()
|
||||
|
||||
webView.evaluateJavaScript(Constants.ResetCommand) { [weak self] _, error in
|
||||
|
|
@ -277,8 +282,7 @@ fileprivate extension ReCaptchaWebViewManager {
|
|||
}
|
||||
|
||||
case .showReCaptcha:
|
||||
// Ensures `configureWebView` won't get called multiple times in a short period
|
||||
DispatchQueue.main.debounce(interval: 1) { [weak self] in
|
||||
DispatchQueue.once(token: configureWebViewDispatchToken) { [weak self] in
|
||||
guard let `self` = self else { return }
|
||||
self.configureWebView?(self.webView)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue