blob: 54c5c592f8115247d0f647a6f08a04309da06495 [file] [log] [blame] [edit]
// Copyright (C) 2024 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
// FIXME: Remove !SWIFT_WEBKIT_TOOLCHAIN once Swift toolchain is fixed (see webkit.org/b/307344).
#if ENABLE_SWIFTUI && canImport(Testing) && compiler(>=6.2) && !SWIFT_WEBKIT_TOOLCHAIN
import SwiftUI
import Observation
import Testing
@_spi(Private) @_spi(Testing) import WebKit
@_spi(Private) import _WebKit_SwiftUI
// MARK: Supporting test types
@MainActor
fileprivate class TestNavigationDecider: WebPage.NavigationDeciding {
init() {
(self.navigationActionStream, self.navigationActionContinuation) = AsyncStream.makeStream(of: WebPage.NavigationAction.self)
(self.navigationResponseStream, self.navigationResponseContinuation) = AsyncStream.makeStream(of: WebPage.NavigationResponse.self)
}
let navigationActionStream: AsyncStream<WebPage.NavigationAction>
private let navigationActionContinuation: AsyncStream<WebPage.NavigationAction>.Continuation
let navigationResponseStream: AsyncStream<WebPage.NavigationResponse>
private let navigationResponseContinuation: AsyncStream<WebPage.NavigationResponse>.Continuation
var preferencesMutation: (inout WebPage.NavigationPreferences) -> Void = { _ in }
func decidePolicy(for action: WebPage.NavigationAction, preferences: inout WebPage.NavigationPreferences) async -> WKNavigationActionPolicy {
preferencesMutation(&preferences)
navigationActionContinuation.yield(action)
return .allow
}
func decidePolicy(for response: WebPage.NavigationResponse) async -> WKNavigationResponsePolicy {
navigationResponseContinuation.yield(response)
return .allow
}
}
// MARK: Tests
@MainActor
struct WebPageTests {
@Test
func observableProperties() async throws {
let page = WebPage()
let html = """
<html>
<head>
<title>Title</title>
</head>
<body></body>
</html>
"""
#expect(page.url == nil)
#expect(page.title == "")
#expect(!page.isLoading)
#expect(page.estimatedProgress == 0.0)
#expect(page.serverTrust == nil)
#expect(!page.hasOnlySecureContent)
#expect(page.themeColor == nil)
// FIXME: (283456) Make this test more comprehensive once Observation supports observing a stream of changes to properties.
}
@Test
func decidePolicyForNavigationActionFragment() async throws {
let decider = TestNavigationDecider()
let page = WebPage(navigationDecider: decider)
let html = "<script>window.location.href='#fragment';</script>"
let baseURL = URL(string: "http://webkit.org")!
page.load(html: html, baseURL: baseURL)
let actions = await Array(decider.navigationActionStream.prefix(2))
#expect(actions[0].request.url!.absoluteString == "http://webkit.org/")
#expect(actions[1].request.url!.absoluteString == "http://webkit.org/#fragment")
}
@Test
func javaScriptEvaluation() async throws {
let page = WebPage()
let arguments = [
"a": 1,
"b": 2,
]
let result = try await page.callJavaScript("return a + b;", arguments: arguments) as! Int
#expect(result == 3)
let nilResult = try await page.callJavaScript("console.log('hi')")
#expect(nilResult == nil)
}
@Test
func decidePolicyForNavigationResponse() async throws {
let decider = TestNavigationDecider()
let page = WebPage(navigationDecider: decider)
let simpleURL = Bundle.testResources.url(forResource: "simple", withExtension: "html")!
let request = URLRequest(url: simpleURL)
page.load(request)
let responses = await Array(decider.navigationResponseStream.prefix(1))
#expect(responses[0].response.url!.absoluteString == simpleURL.absoluteString)
}
}
#endif