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?
The most straightforward way to test the delegate methods is to simply call them.
The trick here is to pass the arguments that allow the unit tests to validate the behaviour, and for this you can use test doubles.
For the particular case of the navigation policy delegate method, you can use a Fake, by subclassing WKNavigationAction
, and pass an instance of that class as input argument to the delegate method:
final class FakeNavigationAction: WKNavigationAction {
let urlRequest: URLRequest
var receivedPolicy: WKNavigationActionPolicy?
override var request: URLRequest { urlRequest }
init(urlRequest: URLRequest) {
self.urlRequest = urlRequest
super.init()
}
convenience init(url: URL) {
self.init(urlRequest: URLRequest(url: url))
}
func decisionHandler(_ policy: WKNavigationActionPolicy) { self.receivedPolicy = policy }
}
Later on, in the unit test:
// setup
let testURL = URL(string: "https://my-approved-url")!
let testAction = FakeNavigationAction(url: testURL)
// act
controller.webView(webView, decidePolicyFor: testAction, decisionHandler: testAction.decisionHandler)
// assert
XCTAssertEqual(testAction.receivedPolicy, b: .cancel)
Another approach would be to swizzle the getter for request
, since WKNavigationAction
is an Objective-C class, however that's more of a hacky solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With