zitare-native/Tests/UnitTests/DeepLinkRouterTests.swift
Till dd10f85cca ζ-1 abgeschlossen: DeepLinkRouter + Web-Header-Hide
- 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>
2026-05-14 13:06:37 +02:00

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)
}
}