Unit testing WKNavigationDelegate functions swift

1.1k Views Asked by At

I have a UIViewController that implements some WKNavigationDelegate functions, and I want to unit test the logic in these functions. Here's an example:

func webView(_ webView: WKWebView,
             decidePolicyFor navigationAction: WKNavigationAction,
             decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    guard let url = navigationAction.request.url else {
        decisionHandler(.cancel)
        return
    }

    if url.absoluteString != "https://my-approved-url" {
        decisionHandler(.cancel)
        return
    }
    decisionHandler(.allow)
}

I'd like my unit test to make sure decisionHandler is called with the right WKNavigationActionPolicy based on the request.url of the WKNavigationAction.

I can't figure out how to test this function, however. Calling .load() on the webview does not trigger the delegate functions when I'm running my test project. I have also tried to call this function directly to test it, but it doesn't seem to be possible to instantiate a new WKNavigationAction of my own (.request is read-only).

What is the right way to unit test logic in WKNavigationDelegate functions?

1

There are 1 best solutions below

1
On BEST ANSWER

Your second approach of directly calling the delegate method is the better approach as you are not relying on any behavior of WebKit in your unit tests.

The problem of not being able to instantiate a WKNavigationAction can be solved by subclassing. Create a MockNavigationAction which returns the desired request you need for testing like so:

final class MockNavigationAction: WKNavigationAction {
    var mockedRequest: URLRequest!
    override var request: URLRequest {
        return mockedRequest
    }

And then in your unit test call the delegate method directly:

func test_AllowsCorrectURL() {
    let sut = ViewController()
    let action = MockNavigationAction()
    action.mockedRequest = URLRequest(url: URL(string: "https://my-approved-url")!)
    let allowExpectation = expectation(description: "Allows action")
    sut.webView(WKWebView(), decidePolicyFor: action) { policy in
        XCTAssertEqual(policy, .allow)
        allowExpectation.fulfill()
    }
    waitForExpectations(timeout: 1.0)
}