diff --git a/Erik.podspec b/Erik.podspec index efe7301..c98e4c2 100644 --- a/Erik.podspec +++ b/Erik.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.name = "Erik" - s.version = "1.1.0" + s.version = "1.1.1" s.summary = "A headless browser written in Swift" s.description = <<-DESC Erik is an headless browser based on WebKit and HTML parser Kanna. diff --git a/Erik.xcodeproj/project.pbxproj b/Erik.xcodeproj/project.pbxproj index 9b4eee1..876bea0 100644 --- a/Erik.xcodeproj/project.pbxproj +++ b/Erik.xcodeproj/project.pbxproj @@ -239,12 +239,12 @@ isa = PBXNativeTarget; buildConfigurationList = C42828EB1BF9EDE1005EC7C3 /* Build configuration list for PBXNativeTarget "Erik" */; buildPhases = ( - BF088855B5DAF2A7EA705BA7 /* Check Pods Manifest.lock */, + BF088855B5DAF2A7EA705BA7 /* [CP] Check Pods Manifest.lock */, C42828D21BF9EDE1005EC7C3 /* Sources */, C42828D31BF9EDE1005EC7C3 /* Frameworks */, C42828D41BF9EDE1005EC7C3 /* Headers */, C42828D51BF9EDE1005EC7C3 /* Resources */, - 73264931D890451C857818B9 /* Copy Pods Resources */, + 73264931D890451C857818B9 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -259,12 +259,12 @@ isa = PBXNativeTarget; buildConfigurationList = C42828EE1BF9EDE1005EC7C3 /* Build configuration list for PBXNativeTarget "ErikTests" */; buildPhases = ( - FBE78F4AB43A129B1FEC79DD /* Check Pods Manifest.lock */, + FBE78F4AB43A129B1FEC79DD /* [CP] Check Pods Manifest.lock */, C42828DD1BF9EDE1005EC7C3 /* Sources */, C42828DE1BF9EDE1005EC7C3 /* Frameworks */, C42828DF1BF9EDE1005EC7C3 /* Resources */, - 0FCD568CDAC88AC57710E176 /* Embed Pods Frameworks */, - 62E60B9AE07D42A5E0ED97AE /* Copy Pods Resources */, + 0FCD568CDAC88AC57710E176 /* [CP] Embed Pods Frameworks */, + 62E60B9AE07D42A5E0ED97AE /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -280,12 +280,12 @@ isa = PBXNativeTarget; buildConfigurationList = C43178841BFA3E1A00C04250 /* Build configuration list for PBXNativeTarget "ErikOSX" */; buildPhases = ( - EA074855D0C7C0EB242B62F3 /* Check Pods Manifest.lock */, + EA074855D0C7C0EB242B62F3 /* [CP] Check Pods Manifest.lock */, C431787A1BFA3E1A00C04250 /* Sources */, C431787B1BFA3E1A00C04250 /* Frameworks */, C431787C1BFA3E1A00C04250 /* Headers */, C431787D1BFA3E1A00C04250 /* Resources */, - DA257F49A8A64F396E1DB044 /* Copy Pods Resources */, + DA257F49A8A64F396E1DB044 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -300,12 +300,12 @@ isa = PBXNativeTarget; buildConfigurationList = C4D50DEF1BFB58EE0053B624 /* Build configuration list for PBXNativeTarget "ErikOSXTests" */; buildPhases = ( - 6A78CCAB86D8196708AB81E9 /* Check Pods Manifest.lock */, + 6A78CCAB86D8196708AB81E9 /* [CP] Check Pods Manifest.lock */, C4D50DE31BFB58EE0053B624 /* Sources */, C4D50DE41BFB58EE0053B624 /* Frameworks */, C4D50DE51BFB58EE0053B624 /* Resources */, - 7138017D10AC0A7C8C7B29FF /* Embed Pods Frameworks */, - 31AD1E205B85890FF10084EE /* Copy Pods Resources */, + 7138017D10AC0A7C8C7B29FF /* [CP] Embed Pods Frameworks */, + 31AD1E205B85890FF10084EE /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -395,14 +395,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0FCD568CDAC88AC57710E176 /* Embed Pods Frameworks */ = { + 0FCD568CDAC88AC57710E176 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Embed Pods Frameworks"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -410,14 +410,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ErikTests/Pods-ErikTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 31AD1E205B85890FF10084EE /* Copy Pods Resources */ = { + 31AD1E205B85890FF10084EE /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -425,14 +425,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ErikOSXTests/Pods-ErikOSXTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 62E60B9AE07D42A5E0ED97AE /* Copy Pods Resources */ = { + 62E60B9AE07D42A5E0ED97AE /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -440,29 +440,29 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ErikTests/Pods-ErikTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 6A78CCAB86D8196708AB81E9 /* Check Pods Manifest.lock */ = { + 6A78CCAB86D8196708AB81E9 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 7138017D10AC0A7C8C7B29FF /* Embed Pods Frameworks */ = { + 7138017D10AC0A7C8C7B29FF /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Embed Pods Frameworks"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -470,14 +470,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ErikOSXTests/Pods-ErikOSXTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 73264931D890451C857818B9 /* Copy Pods Resources */ = { + 73264931D890451C857818B9 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -485,29 +485,29 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Erik/Pods-Erik-resources.sh\"\n"; showEnvVarsInLog = 0; }; - BF088855B5DAF2A7EA705BA7 /* Check Pods Manifest.lock */ = { + BF088855B5DAF2A7EA705BA7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - DA257F49A8A64F396E1DB044 /* Copy Pods Resources */ = { + DA257F49A8A64F396E1DB044 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -515,34 +515,34 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ErikOSX/Pods-ErikOSX-resources.sh\"\n"; showEnvVarsInLog = 0; }; - EA074855D0C7C0EB242B62F3 /* Check Pods Manifest.lock */ = { + EA074855D0C7C0EB242B62F3 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - FBE78F4AB43A129B1FEC79DD /* Check Pods Manifest.lock */ = { + FBE78F4AB43A129B1FEC79DD /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/Erik/Erik.swift b/Erik/Erik.swift index 6d60521..a00be75 100644 --- a/Erik/Erik.swift +++ b/Erik/Erik.swift @@ -29,7 +29,7 @@ public enum ErikError: ErrorType { // Error provided by javascript case JavaScriptError(message: String) // A timeout occurs - case TimeOutError + case TimeOutError(time: NSTimeInterval) // No content returned case NoContent // HTML is not parsable @@ -46,6 +46,8 @@ public class Erik { public var layoutEngine: LayoutEngine public var htmlParser: HTMLParser + public var noContentPattern: String? = "" + // Init the headless browser public init(webView: WKWebView? = nil) { if let view = webView { @@ -133,6 +135,11 @@ public class Erik { return } + if let pattern = noContentPattern where html.rangeOfString(pattern, options: .RegularExpressionSearch) != nil { + completionHandler?(nil, ErikError.NoContent) + return + } + guard error == nil else { completionHandler?(nil, error) return @@ -216,4 +223,3 @@ extension Erik { } } - \ No newline at end of file diff --git a/Erik/LayoutEngine.swift b/Erik/LayoutEngine.swift index 8f04851..aa128a9 100644 --- a/Erik/LayoutEngine.swift +++ b/Erik/LayoutEngine.swift @@ -47,8 +47,57 @@ public typealias LayoutEngine = protocol let JavascriptErrorHandler = "erikError" let JavascriptEndHandler = "erikEnd" +public protocol Navigable { + var navigate: Bool {get set} +} + import WebKit public class WebKitLayoutEngine: NSObject, LayoutEngine { + + public enum PageLoadedPolicy { + // `webView.loading` + case loading + // `webView.estimatedProgress` + case estimatedProgress + // `webView.estimatedProgress` + case navigationDelegate + // `navigationDelegate` + + var continueCondition: (WebKitLayoutEngine) -> Bool { + switch self { + case .loading: + return { return $0.webView.loading } + case .estimatedProgress: + return { engine in + let estimatedProgress = engine.webView.estimatedProgress + if engine.firstPageLoaded { + return estimatedProgress != 1.0 + } + return estimatedProgress != 1.0 && estimatedProgress != 0.0 + } + case .navigationDelegate: + return { engine in + if let delegate = engine.navigable { + assert(engine.navigable as? WKNavigationDelegate === engine.webView.navigationDelegate) + return delegate.navigate + } + assertionFailure("No navigation deletage found") + return false + } + } + } + } + + public var pageLoadedPolicy: PageLoadedPolicy = .loading { + didSet { + if self.pageLoadedPolicy == .navigationDelegate { + assert(navigable != nil) // a delegate is already set in webview, cannot use this method + } + } + } + private var navigable: Navigable? + public var pageLoadTimeout: NSTimeInterval = 20 + public private(set) var firstPageLoaded = false public var javaScriptQueue: Queue = Queue(name: "ErikJavaScript", kind: .Serial) public var callBackQueue: Queue = Queue(name: "ErikCallBack", kind: .Serial) @@ -62,6 +111,16 @@ public class WebKitLayoutEngine: NSObject, LayoutEngine { super.init() self.webView.configuration.userContentController.addScriptMessageHandler(self, name: JavascriptErrorHandler) self.webView.configuration.userContentController.addScriptMessageHandler(self, name: JavascriptEndHandler) + + if self.webView.navigationDelegate == nil { + let delegate = LayoutEngineNavigationDelegate() + self.webView.navigationDelegate = delegate + self.navigable = delegate + self.pageLoadedPolicy = .navigationDelegate + } else if let navigable = webView.navigationDelegate as? Navigable { + self.navigable = navigable + self.pageLoadedPolicy = .navigationDelegate + } } convenience init(frame: CGRect = CGRect(x: 0, y: 0, width: 1024, height: 768)) { @@ -69,6 +128,35 @@ public class WebKitLayoutEngine: NSObject, LayoutEngine { } } +// MARK: WKNavigationDelegate +public class LayoutEngineNavigationDelegate: NSObject, WKNavigationDelegate, Navigable { + + public var navigate: Bool = false + public var lastError: ErrorType? + + public func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) { + //self.navigate = true + decisionHandler(WKNavigationActionPolicy.Allow) + } + + public func webView(webView: WKWebView, didCommitNavigation navigation: WKNavigation) { + // self.navigate = true + } + + public func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { + self.navigate = false + } + + public func webView(webView: WKWebView, didFailNavigation navigation: WKNavigation!, withError error: NSError) { + self.navigate = false + self.lastError = error + } + + @available(OSX 10.11, *) + public func webViewWebContentProcessDidTerminate(webView: WKWebView) { + self.navigate = false + } +} // MARK: URLBrowser extension WebKitLayoutEngine { @@ -76,9 +164,12 @@ extension WebKitLayoutEngine { public func browseURL(URL: NSURL, completionHandler: ((AnyObject?, ErrorType?) -> Void)?) { let request = NSURLRequest(URL: URL) self.browseURL(request, completionHandler: completionHandler) + } public func browseURL(URLRequest: NSURLRequest, completionHandler: ((AnyObject?, ErrorType?) -> Void)?) { + firstPageLoaded = true + navigable?.navigate = true webView.loadRequest(URLRequest) self.currentContent(completionHandler) } @@ -116,19 +207,29 @@ extension WebKitLayoutEngine { } public func currentContent(completionHandler: ((AnyObject?, ErrorType?) -> Void)?) { - handleLoadRequestCompletion { - self.handleHTML(completionHandler) + handleLoadRequestCompletion { error in + if let error = error { + self.callBackQueue.asyncOrCurrent { + completionHandler?(nil, error) + } + } else { + self.handleHTML(completionHandler) + } } } - - private func handleLoadRequestCompletion(completionHandler: () -> Void) { + + private func handleLoadRequestCompletion(completionHandler: (ErrorType?) -> Void) { // wait load finish - while(webView.loading) { + let condition = pageLoadedPolicy.continueCondition + let max = NSDate().timeIntervalSince1970 + pageLoadTimeout + while(condition(self)) { + if pageLoadTimeout > 0 && NSDate().timeIntervalSince1970 > max { + completionHandler(ErikError.TimeOutError(time: pageLoadTimeout)) + return + } NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture()) } - // XXX maybe use instead WKNavigationDelegate#webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) - // or notification on loading - completionHandler() + completionHandler(nil) } private func handleHTML(completionHandler: ((AnyObject?, ErrorType?) -> Void)?) { @@ -215,8 +316,8 @@ extension WebKitLayoutEngine { completionHandler?(object, e) // must not be called return } - - if self.wait(key, time: self.javaScriptWaitTime) { + let timeout = self.javaScriptWaitTime + if self.wait(key, time: timeout) { if let errorMessage = self.getbox(key) { completionHandler?(object, ErikError.JavaScriptError(message: "\(errorMessage)")) } @@ -226,7 +327,7 @@ extension WebKitLayoutEngine { self.removebox(key) } else { - completionHandler?(object, ErikError.TimeOutError) + completionHandler?(object, ErikError.TimeOutError(time: timeout)) } } } diff --git a/ErikTests/ErikTests.swift b/ErikTests/ErikTests.swift index cbaa572..d1b7753 100644 --- a/ErikTests/ErikTests.swift +++ b/ErikTests/ErikTests.swift @@ -12,21 +12,22 @@ import Eki import FileKit import BrightFutures - - - let url = NSURL(string:"https://www.google.com")! +let PageLoadedPolicy = WebKitLayoutEngine.PageLoadedPolicy.navigationDelegate + +#if os(OSX) +let googleFormSelector = "f" +#elseif os(iOS) +let googleFormSelector = "gs" +#endif class ErikTests: XCTestCase { - - #if os(OSX) - let googleFormSelector = "f" - #elseif os(iOS) - let googleFormSelector = "gs" - #endif + override func setUp() { super.setUp() + + (Erik.sharedInstance.layoutEngine as? WebKitLayoutEngine)?.pageLoadedPolicy = PageLoadedPolicy } override func tearDown() { @@ -80,12 +81,12 @@ class ErikTests: XCTestCase { XCTFail("\(error)") } - else if let doc = obj { + else if let docVisit = obj { visitExpectation.fulfill() //print(doc) // do a google search - for input in doc.querySelectorAll("input[name='q']") { + if let input = docVisit.querySelector("input[name='q']") { inputExpectation.fulfill() print(input) @@ -95,58 +96,69 @@ class ErikTests: XCTestCase { Erik.currentContent { (obj, err) -> Void in if let error = err { print(error) - XCTFail("\(error)") } else if let doc = obj { if let input2 = doc.querySelector("input[name='q']") { print(input2) - XCTAssertEqual(value, input2["value"]) - } - } - else { - XCTFail("not parsable") - } - - for input in doc.querySelectorAll("form[name='\(self.googleFormSelector)']") { - submitExpectation.fulfill() - if let form = input as? Form { - form.submit() + let currentValue = input2["value"] + XCTAssertEqual(value, currentValue) } else { - XCTFail("\(input) not a form") + XCTFail("input not found ") } - - - Erik.currentContent { (obj, err) -> Void in - if let error = err { - print(error) - XCTFail("\(error)") + let gSelector = "form[name='\(googleFormSelector)']" + if let form = doc.querySelector(gSelector) as? Form { + submitExpectation.fulfill() + + form.submit() + + Erik.currentContent { (obj, err) -> Void in + if let error = err { + print(error) + XCTFail("\(error)") + } + else if let docSubmit = obj { + print(docSubmit) + currentContentExpectation.fulfill() + + XCTAssertNotEqual(url, Erik.url) + + XCTAssertNotNil("\(Erik.url)".rangeOfString(value!)) + } } - else if let doc = obj { - print(doc) - currentContentExpectation.fulfill() + + + } else { + if let _ = docVisit.querySelector("form[name='\(googleFormSelector)']") as? Form { - XCTAssertNotEqual(url, Erik.url) + XCTFail("Form found before js, not after ") + } else { - XCTAssertNotNil("\(Erik.url)".rangeOfString(value!)) + XCTFail("Form not found ") } } + + } + else { + XCTFail("no doc") } - } + + } else { + print(docVisit) + XCTFail("not input") } - - } + } - self.waitForExpectationsWithTimeout(20, handler: { error in + self.waitForExpectationsWithTimeout(30, handler: { error in XCTAssertNil(error, "Oh, we got timeout") }) } - + func testJavascriptError() { let visitExpectation = self.expectationWithDescription("visit") @@ -263,26 +275,46 @@ class ErikTests: XCTestCase { func testContentAtStart() { let expectation = self.expectationWithDescription("start content") - let erik = Erik() - erik.currentContent {(obj, err) -> Void in + let browser = Erik() + (browser.layoutEngine as? WebKitLayoutEngine)?.pageLoadedPolicy = PageLoadedPolicy + browser.noContentPattern = nil + browser.currentContent {(obj, err) -> Void in + if let _ = obj { + expectation.fulfill() // there is content + } + else if let error = err { + XCTFail("\(error)") + } + } + + self.waitForExpectationsWithTimeout(20, handler: { error in + XCTAssertNil(error, "Oh, we got timeout") + }) + } + + func testContentAtStartNoContent() { + let expectation = self.expectationWithDescription("start content") + let browser = Erik() + (browser.layoutEngine as? WebKitLayoutEngine)?.pageLoadedPolicy = PageLoadedPolicy + browser.currentContent {(obj, err) -> Void in if let _ = obj { - expectation.fulfill() // currently there is always a content + XCTFail("Must have no content") } else if let error = err { switch error { case ErikError.NoContent: - // expectation.fulfill() + expectation.fulfill() break default : print(error) + XCTFail("Wrong error type \(error)") break } - XCTFail("Wrong error type \(error)") } - + } - self.waitForExpectationsWithTimeout(100, handler: { error in + self.waitForExpectationsWithTimeout(20, handler: { error in XCTAssertNil(error, "Oh, we got timeout") }) } @@ -310,6 +342,7 @@ class ErikTests: XCTestCase { let visitExpectation = self.expectationWithDescription("visit") let browser = Erik() + (browser.layoutEngine as? WebKitLayoutEngine)?.pageLoadedPolicy = PageLoadedPolicy var future: Future = browser.visitURLFuture(url) @@ -328,7 +361,7 @@ class ErikTests: XCTestCase { XCTAssertEqual(value, input2["value"]) } - if let form = document.querySelector("form[name=\"\(self.googleFormSelector)\"]") as? Form { + if let form = document.querySelector("form[name=\"\(googleFormSelector)\"]") as? Form { form.submit() } diff --git a/Podfile b/Podfile index d9f4b17..0a87db1 100644 --- a/Podfile +++ b/Podfile @@ -7,11 +7,12 @@ def dependency_pods pod 'Kanna' pod 'Eki' pod 'BrightFutures' + pod 'Result', '2.1.2' end def testing_pods dependency_pods - pod 'FileKit' + pod 'FileKit', '2.0.0' end target 'Erik' do