- DeepLinkRouter als pure-Logic-Enum aus RootView extrahiert (resolveToWebURL, isExplorePath, route) - 11 DeepLinkRouterTests grün: custom-scheme, https passthrough, Erkunden-vs-Lesen-Routing, Substring-Guard - WebShellScripts.hideWebHeader: WKUserScript injiziert at document.start CSS, das den zitare-Web-Header (body header:has(a.brand)) ausblendet. Native TabBar übernimmt globale Navigation, Content bleibt sichtbar. - Simulator-Verifikation: Quote rendert ohne doppelte Nav-Leiste, 17 (UI + Unit) Tests grün Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.3 KiB
Swift
90 lines
3.3 KiB
Swift
import XCTest
|
|
@testable import ZitareNative
|
|
|
|
final class DeepLinkRouterTests: XCTestCase {
|
|
let base = URL(string: "https://zitare.mana.how")!
|
|
|
|
// MARK: - resolveToWebURL
|
|
|
|
func test_resolve_customSchemeQuote() throws {
|
|
let url = try XCTUnwrap(URL(string: "zitare://quote/spitteler-schweizer-bleiben"))
|
|
let resolved = DeepLinkRouter.resolveToWebURL(url, base: base)
|
|
XCTAssertEqual(resolved.absoluteString, "https://zitare.mana.how/q/spitteler-schweizer-bleiben")
|
|
}
|
|
|
|
func test_resolve_customSchemeAuthor() throws {
|
|
let url = try XCTUnwrap(URL(string: "zitare://author/spitteler"))
|
|
let resolved = DeepLinkRouter.resolveToWebURL(url, base: base)
|
|
XCTAssertEqual(resolved.absoluteString, "https://zitare.mana.how/a/spitteler")
|
|
}
|
|
|
|
func test_resolve_customSchemeCollection() throws {
|
|
let url = try XCTUnwrap(URL(string: "zitare://collection/schweizer-stimmen"))
|
|
let resolved = DeepLinkRouter.resolveToWebURL(url, base: base)
|
|
XCTAssertEqual(resolved.absoluteString, "https://zitare.mana.how/c/schweizer-stimmen")
|
|
}
|
|
|
|
func test_resolve_unknownCustomSchemeFallsBackToBase() throws {
|
|
let url = try XCTUnwrap(URL(string: "zitare://unknown/foo"))
|
|
let resolved = DeepLinkRouter.resolveToWebURL(url, base: base)
|
|
XCTAssertEqual(resolved.absoluteString, "https://zitare.mana.how")
|
|
}
|
|
|
|
func test_resolve_httpsPassesThrough() throws {
|
|
let url = try XCTUnwrap(URL(string: "https://zitare.com/q/keller-werke"))
|
|
let resolved = DeepLinkRouter.resolveToWebURL(url, base: base)
|
|
XCTAssertEqual(resolved.absoluteString, "https://zitare.com/q/keller-werke")
|
|
}
|
|
|
|
// MARK: - isExplorePath
|
|
|
|
func test_explore_root() {
|
|
XCTAssertTrue(DeepLinkRouter.isExplorePath("/explore"))
|
|
}
|
|
|
|
func test_explore_subpaths() {
|
|
for path in [
|
|
"/region/schweiz",
|
|
"/thema/philosophie",
|
|
"/rolle/schriftsteller",
|
|
"/epoche/moderne",
|
|
"/sprache/de",
|
|
"/search",
|
|
"/t/eigenstaendigkeit"
|
|
] {
|
|
XCTAssertTrue(DeepLinkRouter.isExplorePath(path), "expected \(path) → explore")
|
|
}
|
|
}
|
|
|
|
func test_read_paths_are_not_explore() {
|
|
for path in ["/", "/q/spitteler-x", "/a/spitteler", "/c/schweizer", "/heute", "/random"] {
|
|
XCTAssertFalse(DeepLinkRouter.isExplorePath(path), "expected \(path) → read")
|
|
}
|
|
}
|
|
|
|
func test_explore_prefix_not_substring() {
|
|
// `/region` matcht, aber `/regions/...` darf NICHT matchen
|
|
XCTAssertTrue(DeepLinkRouter.isExplorePath("/region"))
|
|
XCTAssertTrue(DeepLinkRouter.isExplorePath("/region/schweiz"))
|
|
XCTAssertFalse(DeepLinkRouter.isExplorePath("/regions-overview"))
|
|
}
|
|
|
|
// MARK: - route (one-shot)
|
|
|
|
func test_route_customQuote_goesToRead() throws {
|
|
let result = try DeepLinkRouter.route(
|
|
XCTUnwrap(URL(string: "zitare://quote/x")),
|
|
base: base
|
|
)
|
|
XCTAssertEqual(result.url.path, "/q/x")
|
|
XCTAssertFalse(result.isExplore)
|
|
}
|
|
|
|
func test_route_httpsExplorePath_goesToExplore() throws {
|
|
let result = try DeepLinkRouter.route(
|
|
XCTUnwrap(URL(string: "https://zitare.mana.how/region/schweiz")),
|
|
base: base
|
|
)
|
|
XCTAssertTrue(result.isExplore)
|
|
}
|
|
}
|