darthtrevino
darthtrevino

Reputation: 2235

UIWebView won't load content

I'm making a class that will act as a facade into script loading. This class will interact with a headless UIWebView loaded with HTML&JS files on disk.

I'm currently doing all of my execution in the unit testing environment, and it looks like the UIWebView refuses to load anything. Here's what my code looks like:

WebView Init

self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,0,0)];
self.webView.delegate = self;
[self loadScriptingCore];

Script Loader:

- (void)loadScriptingCore
{
    NSURLRequest *loadRequest = [NSURLRequest requestWithURL:[self scriptingCoreIndex]];
    [self.webView loadRequest:loadRequest];
    NSLog([self inspectDom]);
}

- (NSURL *) scriptingCoreIndex  
{
    NSString *indexPath = [[NSBundle mainBundle] pathForResource:@"scripting-core" ofType:@"html" inDirectory:@"www"];
    NSLog([NSString stringWithFormat:@"Scripting Core Index: %@", indexPath]);
    return [NSURL fileURLWithPath:indexPath];
}

- (NSString *)inspectDom
{
    return [self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.outerHTML;"];
}

HTML

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Scripting Core</title>
</head>
<body>
   <div id="element">
       Hello
    </div>
</body>
</html>

The inspectDom method only ever returns

<html><head></head><body></body></html>

Thich indicates to me that nothing ever happens to the webView. Additionally, the delegate methods don't webViewDidStartLoad, webViewDidFinishLoad and webViewDidFailLoad appear to be firing.

Any suggestions would be appreciated

Thanks!

Upvotes: 0

Views: 971

Answers (3)

Victor Bogdan
Victor Bogdan

Reputation: 2050

In Swift, if you're still using UIWebView, and you want to test its content after calling load(data: ...), you can try the following:

class TestCase: XCTestCase {
  var testDelegate: TestDelegate()
  lazy var loadExpectation: XCTestExpectation = { return self.expectation(description: "waiting") }()

  func testSomething() {
    testDelegate.expectation = loadExpectation

    webViewUnderTest.delegate = testDelegate
    webViewUnderTest.load(data: ...)

    waitForExpectations(timeout: 5) { (error) in
      dump(error)
    }

    assert(...)
  }
}

class TestDelegate: NSObject, UIWebViewDelegate {
  var expectation: XCTestExpectation?

  func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
      return true
  }

  func webViewDidFinishLoad(_ webView: UIWebView) {
      expectation?.fulfill()
  }
}

Upvotes: 0

darthtrevino
darthtrevino

Reputation: 2235

The gist of the problem for the tests is that UIWebView loading is asynchronous. I experimented with [NSThread sleepForTimeInterval] after firing the request, but that was not sufficient. Apparently the main thread needed to be alive for the UIWebView to load asynchronously.

I was able to get my unit tests to pass by using this Async testing mechanism:

https://github.com/akisute/SenAsyncTestCase

This code uses the NSRunLoop to spin the run loop while keeping the main thread alive - sort of like a pseudo-sleep. Adding a 1/10th of a second wait in my test, after the script load was requested, resulted in the DOM being correctly loaded and the delegate events firing.

[self waitForTimeout: 0.1];

Upvotes: 2

DontTurnAround
DontTurnAround

Reputation: 684

Make sure in your @ implementation that you set the class as a delegate

@implementation myclass:parent <UIWebViewDelegate>

And what is the output of NSLog([NSString stringWithFormat:@"Scripting Core Index: %@", indexPath]);?

Upvotes: 0

Related Questions