From bddd0aaa6f64d3235d9e69abb9f1920d967a66e8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 26 Aug 2026 01:56:59 -0700 Subject: [PATCH] test(ios): remove redundant root tabs source guards (#130012) --- apps/ios/Tests/RootTabsSourceGuardTests.swift | 495 +----------------- 1 file changed, 8 insertions(+), 487 deletions(-) diff --git a/apps/ios/Tests/RootTabsSourceGuardTests.swift b/apps/ios/Tests/RootTabsSourceGuardTests.swift index 14c35a53d89a..1b3cd65b804d 100644 --- a/apps/ios/Tests/RootTabsSourceGuardTests.swift +++ b/apps/ios/Tests/RootTabsSourceGuardTests.swift @@ -48,113 +48,6 @@ struct RootTabsSourceGuardTests { #expect(startupTask.contains("self.appDelegate.scenePhaseChanged(self.scenePhase)")) } - @Test func `i pad split stays integrated while compact drawer uses one local shell`() throws { - let source = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) - let splitContent = try Self.extract( - source, - from: "private func sidebarNavigationSplitContent(sidebarWidth: CGFloat) -> some View", - to: "private func sidebarDrawerContent(") - let drawerContent = try Self.extract( - source, - from: "private func sidebarDrawerContent(", - to: "private var sidebarDetailShell: some View") - - #expect(!source.contains("@State private var splitColumnVisibility: NavigationSplitViewVisibility")) - #expect(!source.contains("Self.sidebarSplitColumnVisibility(isSidebarVisible:")) - #expect(!source.contains("self.syncSidebarVisibility(from: visibility)")) - #expect(splitContent.contains("HStack(spacing: 0)")) - #expect(splitContent.contains("self.sidebarColumn")) - #expect(splitContent.contains(".frame(width: sidebarWidth, alignment: .topLeading)")) - #expect(splitContent.contains(".overlay(alignment: .trailing)")) - #expect(splitContent.contains("self.sidebarVerticalSeparator")) - #expect(splitContent.contains("self.sidebarDetailNavigationShell")) - #expect(splitContent.contains(".animation(self.sidebarAnimation, value: self.isSidebarVisible)")) - #expect(!splitContent.contains("NavigationSplitView")) - #expect(!splitContent.contains("self.collapsedSidebarRail")) - #expect(!source.contains("Self.sidebarCollapsedRailWidth")) - - #expect(drawerContent.contains("RootSidebarDrawer(")) - #expect(drawerContent.contains("isPresented: self.isSidebarVisible")) - #expect(drawerContent.contains("self.isSidebarDetailRootVisible && self.sidebarNavigationPath.isEmpty")) - #expect(drawerContent.contains("onShow: self.showSidebar")) - #expect(drawerContent.contains("onHide: self.hideSidebar")) - #expect(drawerContent.contains("self.sidebarColumn(drawerSafeAreaInsets: safeAreaInsets)")) - #expect(drawerContent.contains("self.sidebarDetailNavigationShell")) - #expect(!drawerContent.contains("NavigationSplitView")) - #expect(!source.contains("sidebarDrawerContentSurface")) - #expect(!source.contains("sidebarDrawerContentCard")) - } - - @Test func `unified root shell removes phone tab chrome`() throws { - let rootSource = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) - let chatSource = try String(contentsOf: Self.chatProTabSourceURL(), encoding: .utf8) - - #expect(!rootSource.contains("TabView(")) - #expect(!rootSource.contains("AppTab")) - #expect(!rootSource.contains("RootTabsPhoneControlHub")) - #expect(!rootSource.contains("PhoneTabSettingsHost")) - #expect(!rootSource.contains("tabViewBottomAccessory")) - #expect(!rootSource.contains("PhoneVoiceTabAccessory")) - #expect(chatSource.contains("talkControl: Self.shouldExposeCaptureControl(")) - #expect(chatSource.contains("private var talkControl: OpenClawChatTalkControl")) - #expect(chatSource.contains("self.appModel.setTalkEnabled(!self.appModel.talkMode.isEnabled)")) - } - - @Test func `composer mic keeps voice notes behind its long press menu`() throws { - let controls = try String(contentsOf: Self.cleanChatComposerControlsSourceURL(), encoding: .utf8) - let composer = try String(contentsOf: Self.sharedChatComposerSourceURL(), encoding: .utf8) - let chat = try String(contentsOf: Self.chatProTabSourceURL(), encoding: .utf8) - - #expect(controls.contains("Label(\"Record Voice Note\", systemImage: \"waveform\")")) - #expect(controls.contains("primaryAction:")) - #expect(controls.contains("struct OpenClawChatMicButton: View")) - #expect(controls.contains("private var isDictationActionEnabled: Bool")) - #expect(controls.contains("isDictationActive: self.dictationControl?.isActive == true")) - #expect(composer.contains("if self.dictationControl != nil || self.voiceNoteControl != nil")) - #expect(composer.contains("isRealtimeTalkActive: self.talkControl?.isEnabled == true")) - #expect(composer.contains("voiceNoteControl: self.voiceNoteControl")) - #expect(composer.contains("embedded: true")) - #expect(chat.contains("voiceNoteControl: self.voiceNoteControl")) - #expect(!chat.contains("OpenClawVoiceNoteButton(")) - } - - @Test func `sidebar keeps navigation model destination only`() throws { - let rootSource = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) - let source = try String(contentsOf: Self.rootSidebarSourceURL(), encoding: .utf8) - let navigationSource = try String(contentsOf: Self.rootTabsNavigationSourceURL(), encoding: .utf8) - - #expect(rootSource.contains("RootSidebar(")) - #expect(source.contains("ForEach(self.pinnedPages)")) - #expect(source.contains("destinations: RootTabs.pinnableSidebarPages.filter(self.isDestinationAvailable)")) - #expect(source.contains("ForEach(self.destinations)")) - #expect(source.contains("private var brandHeader: some View")) - #expect(source.contains("private var agentsSection: some View")) - #expect(source.contains("static func shownAgentCount(configured: Int, total: Int) -> Int")) - #expect(source.contains("ChatSessionSidebarModel.workSubtitle(for: session)")) - #expect(source.contains("private var homeRow: some View")) - #expect(source.contains("RootTabs.pinnedSidebarPages(from: self.pinnedPagesStorage)")) - #expect(source.contains("struct RootSidebarPagesEditor: View")) - #expect(source.contains("private var gatewayStatusTitle: String")) - #expect(source.contains("private var gatewayStatusColor: Color")) - #expect(source.contains("private var sessionsSection: some View")) - #expect(source.contains("private var pagesSection: some View")) - #expect(!source.contains("attentionSection")) - #expect(source.contains("private func badgeCount(for destination: RootTabs.SidebarDestination) -> Int")) - #expect(source.contains("private var footer: some View")) - #expect(source.contains("TextField(\"\", text: self.$searchText)")) - #expect(source.contains("commandSessionActions(")) - #expect(source.contains("1 / self.displayScale")) - #expect(!source.contains("UIScreen.main.scale")) - #expect(navigationSource.contains("static let sidebarDestinations")) - #expect(!navigationSource.contains("SidebarGroup")) - #expect(!navigationSource.contains("title: \"AGENT\"")) - #expect(navigationSource.contains("case settings")) - #expect(!navigationSource.contains("case settingsChannels")) - #expect(!navigationSource.contains("case settingsApprovals")) - #expect(!navigationSource.contains("case settingsPrivacy")) - #expect(!navigationSource.contains("phoneControlGroups")) - } - @Test func `sidebar refresh generations keep dashboard independent from roster replacements`() throws { let source = try String(contentsOf: Self.rootSidebarModelSourceURL(), encoding: .utf8) let refresh = try Self.extract( @@ -255,150 +148,6 @@ struct RootTabsSourceGuardTests { #expect(defaultSession.contains("sessions.first { $0.key == mainKey }")) } - @Test func `sidebar routes use destination headers instead of repeated product branding`() throws { - let rootSource = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) - let agentOverviewSource = try String(contentsOf: Self.agentProTabOverviewSourceURL(), encoding: .utf8) - let docsSource = try String(contentsOf: Self.docsSourceURL(), encoding: .utf8) - let sidebarDetail = try Self.extract( - rootSource, - from: "private var sidebarDetail: some View", - to: "private var sidebarDetailNavigationShell: some View") - - #expect(!sidebarDetail.contains("headerTitle: \"Chat\"")) - #expect(!sidebarDetail.contains("showsAgentBadge: false")) - #expect(sidebarDetail.contains("headerTitle: \"Overview\"")) - #expect(sidebarDetail.contains("headerTitle: \"Agents\"")) - #expect(sidebarDetail.contains("headerTitle: \"Instances\"")) - #expect(!sidebarDetail.contains("headerTitle: \"Nodes\"")) - #expect(sidebarDetail.contains("directRoute: .agents")) - #expect(sidebarDetail.contains("directRoute: .instances")) - #expect(sidebarDetail.contains("directRoute: .dreaming")) - #expect(sidebarDetail.contains("directRoute: .usage")) - #expect(sidebarDetail.contains("directRoute: .cron")) - #expect(!sidebarDetail.contains("initialRoute: .nodes")) - #expect(!sidebarDetail.contains("initialRoute: .usage")) - #expect(!sidebarDetail.contains("initialRoute: .cron")) - #expect(sidebarDetail.contains("headerTitle: \"Dreaming\"")) - #expect(sidebarDetail.contains("headerTitle: \"Usage\"")) - #expect(sidebarDetail.contains("headerTitle: \"Automations\"")) - #expect(!sidebarDetail.contains("headerTitle: \"OpenClaw\"")) - #expect(agentOverviewSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(agentOverviewSource.contains("title: .localized(self.headerTitle)")) - #expect(!agentOverviewSource.contains("Text(\"OpenClaw\")")) - #expect(docsSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(docsSource.contains("title: \"Docs\"")) - #expect(!docsSource.contains("Text(\"OpenClaw Docs\")")) - } - - @Test func `agents direct route keeps single sidebar control`() throws { - let source = try String(contentsOf: Self.agentProTabSourceURL(), encoding: .utf8) - let destinationsSource = try String(contentsOf: Self.agentProTabDestinationsSourceURL(), encoding: .utf8) - let nodesSource = try String(contentsOf: Self.agentProNodesDestinationSourceURL(), encoding: .utf8) - let dreamingSource = try String(contentsOf: Self.agentProDreamingDestinationSourceURL(), encoding: .utf8) - - #expect(source - .contains("route != .agents && self.directHeaderSidebarAction(for: route) != nil ? .hidden : .visible")) - #expect(destinationsSource.contains(".navigationTitle(self.headerTitle)")) - #expect(destinationsSource.contains(".searchable(text: self.$agentSearchText")) - #expect(destinationsSource.contains("ToolbarItemGroup(placement: .topBarTrailing)")) - #expect(!destinationsSource.contains(".toolbar(.hidden, for: .navigationBar)")) - #expect(destinationsSource.contains("self.directHeaderSidebarAction(for: .instances)")) - #expect(destinationsSource.contains("self.directHeaderSidebarAction(for: .dreaming)")) - #expect(destinationsSource.contains("self.directHeader(\n for: .usage")) - #expect(destinationsSource.contains("self.directHeader(\n for: .cron")) - #expect(destinationsSource.contains("self.directRoute == route ? self.headerSidebarAction : nil")) - #expect(nodesSource.contains("OpenClawSidebarHeaderLeadingSlot(action: headerSidebarAction)")) - #expect(dreamingSource.contains("OpenClawSidebarHeaderLeadingSlot(action: headerSidebarAction)")) - } - - @Test func `iOS 26 chrome uses native glass while content cards stay quiet`() throws { - let rootSource = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) - let appSource = try String(contentsOf: Self.openClawAppSourceURL(), encoding: .utf8) - let componentsSource = try String(contentsOf: Self.proComponentsSourceURL(), encoding: .utf8) - let cardSurface = try Self.extract( - componentsSource, - from: "private struct ProPanelSurfaceModifier: ViewModifier", - to: "struct ProIconBadge: View") - - #expect(!rootSource.contains(".openClawTabBarBehavior()")) - #expect(!rootSource.contains("TabView(")) - #expect(appSource.contains(".preferredColorScheme(self.appearanceModel.preference.colorScheme)")) - #expect(!appSource.contains("overrideUserInterfaceStyle")) - #expect(!componentsSource.contains("tabBarMinimizeBehavior")) - #expect(componentsSource.contains(".buttonStyle(.glassProminent)")) - #expect(componentsSource.contains(".buttonStyle(.glass)")) - #expect(componentsSource.contains("GlassEffectContainer(spacing: 8)")) - #expect(componentsSource.contains("if #available(iOS 26.0, *)")) - #expect(componentsSource.contains(".buttonStyle(.borderedProminent)")) - #expect(componentsSource.contains(".buttonStyle(.bordered)")) - #expect(componentsSource.contains("struct OpenClawNoticeBanner: View")) - #expect(!cardSurface.contains("glassEffect")) - } - - @Test func `professional layout avoids nested pills and card stacks`() throws { - let componentsSource = try String(contentsOf: Self.proComponentsSourceURL(), encoding: .utf8) - let agentSource = try String(contentsOf: Self.agentProTabOverviewSourceURL(), encoding: .utf8) - let agentDestinationsSource = try String( - contentsOf: Self.agentProTabDestinationsSourceURL(), - encoding: .utf8) - let settingsSource = try String(contentsOf: Self.settingsProTabSectionsSourceURL(), encoding: .utf8) - let overviewSource = try String(contentsOf: Self.commandCenterSourceURL(), encoding: .utf8) - let overviewRowsSource = try String(contentsOf: Self.commandCenterSupportSourceURL(), encoding: .utf8) - let gatewayStatus = try Self.extract( - componentsSource, - from: "struct OpenClawGatewayCompactPill: View", - to: "struct ProMetricTile: View") - let agentFilterMenu = try Self.extract( - agentSource, - from: "var agentFilterMenu: some View", - to: "var agentFiltersActive: Bool") - let agentRow = try Self.extract( - agentSource, - from: "func agentRow(_ agent: AgentSummary) -> some View", - to: "func headerIconButton(") - let settingsList = try Self.extract( - settingsSource, - from: "var settingsListSection: some View", - to: "func settingsListRow(") - let settingsRow = try Self.extract( - settingsSource, - from: "func settingsListRow(", - to: "func destination(for route:") - let appearanceScreen = try Self.extract( - settingsSource, - from: "private struct AppearanceSettingsScreen: View", - to: "extension SettingsProTab") - #expect(gatewayStatus.contains("OpenClawStatusBadge(label: .verbatim(self.title), tone: self.tone)")) - #expect(!gatewayStatus.contains("ProCapsule(")) - #expect(!gatewayStatus.contains("Capsule()")) - #expect(agentDestinationsSource.contains("List {")) - #expect(agentDestinationsSource.contains(".searchable(text: self.$agentSearchText")) - #expect( - agentFilterMenu.contains("Picker(selection: self.$agentRosterFilter)") - && agentFilterMenu.contains("Text(\"Agent status\")")) - #expect(!agentFilterMenu.contains(".pickerStyle(.segmented)")) - #expect(agentFilterMenu.contains("agent-status-filter-menu")) - #expect(!agentRow.contains("agentMetric")) - #expect(!agentRow.contains("chevron.right")) - #expect(agentRow.contains("Image(systemName: \"checkmark\")")) - #expect(agentRow.contains("agentAccessibilityLabel")) - #expect(settingsList.contains("Text(\"Device\")")) - #expect(settingsList.contains(".font(OpenClawType.captionSemiBold)")) - #expect(!settingsList.contains("ProCard(")) - #expect(settingsRow.contains("NavigationLink(value: route)")) - #expect(!settingsRow.contains("chevron.right")) - #expect(settingsSource.contains("settings-appearance-row")) - #expect(appearanceScreen.contains("AppearanceSettingsScreen")) - #expect(!appearanceScreen.contains(".pickerStyle(.segmented)")) - #expect(!overviewSource.contains("ProCapsule(")) - #expect(overviewSource.contains("value: self.gatewayConnectionText")) - #expect(overviewSource.contains("switch self.gatewayDisplayState")) - #expect(overviewSource.contains("case .connecting:")) - #expect(overviewSource.contains("case .error:")) - #expect(!overviewRowsSource.contains("private var rowFill")) - #expect(overviewRowsSource.matches(of: /.contentShape\(Rectangle\(\)\)/).count >= 2) - } - @Test func `settings about page shows concise public device details`() throws { let settingsSource = try String(contentsOf: Self.settingsProTabSectionsSourceURL(), encoding: .utf8) let supportSource = try String(contentsOf: Self.settingsProTabSupportSourceURL(), encoding: .utf8) @@ -457,50 +206,6 @@ struct RootTabsSourceGuardTests { #expect(skillsSource.contains("distinguishPreDispatchRouteChange: true")) } - @Test func `routed headers use shared adaptive layout`() throws { - let componentsSource = try String(contentsOf: Self.proComponentsSourceURL(), encoding: .utf8) - let featureChromeSource = try String(contentsOf: Self.iPadSidebarScreenChromeSourceURL(), encoding: .utf8) - let docsSource = try String(contentsOf: Self.docsSourceURL(), encoding: .utf8) - let overviewSource = try String(contentsOf: Self.commandCenterSourceURL(), encoding: .utf8) - let chatSource = try String(contentsOf: Self.chatProTabSourceURL(), encoding: .utf8) - let agentOverviewSource = try String(contentsOf: Self.agentProTabOverviewSourceURL(), encoding: .utf8) - let settingsSource = try String(contentsOf: Self.settingsProTabSourceURL(), encoding: .utf8) - - #expect(componentsSource.contains("struct OpenClawAdaptiveHeaderRow: View")) - #expect(componentsSource.contains("ViewThatFits(in: .horizontal)")) - #expect(componentsSource.contains("private var stackedLayout: some View")) - #expect(componentsSource.contains(".layoutPriority(1)")) - #expect(componentsSource.contains(".fixedSize(horizontal: true, vertical: false)")) - #expect(featureChromeSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(featureChromeSource.contains("if !self.usesNativeNavigationChrome")) - #expect(!featureChromeSource.contains("if self.headerSidebarAction != nil")) - #expect(docsSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(docsSource.contains("if !self.usesNativeNavigationChrome")) - #expect(overviewSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(overviewSource.matches(of: /if !self\.usesNativeNavigationChrome/).count == 2) - #expect(chatSource.contains(".navigationTitle(self.showsAgentBadge ? \"\" : self.headerDisplayTitle)")) - #expect(chatSource.contains("self.headerAgentIdentity")) - #expect(!chatSource.contains("headerAgentModelPicker")) - #expect(chatSource.contains(".sharedBackgroundVisibility(.hidden)")) - #expect(chatSource.contains("OpenClawSidebarToolbarItem(")) - #expect(componentsSource.contains("struct OpenClawSidebarToolbarItem: ToolbarContent")) - #expect(componentsSource.contains(".sharedBackgroundVisibility(.hidden)")) - #expect(!chatSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(agentOverviewSource.contains("OpenClawAdaptiveHeaderRow(")) - #expect(settingsSource.contains("OpenClawSidebarToolbarItem(")) - #expect(!settingsSource.contains("ToolbarItem(placement: .topBarTrailing)")) - } - - @Test func `chat keeps layered canvas behind soft native scroll edges`() throws { - let source = try String(contentsOf: Self.chatProTabSourceURL(), encoding: .utf8) - - #expect(source.contains("drawsBackground: true")) - #expect(source.contains("content.scrollEdgeEffectStyle(.soft, for: .vertical)")) - #expect(!source.contains(".background(Color(uiColor: .systemBackground))")) - } -} - -extension RootTabsSourceGuardTests { @Test func `workboard uses real gateway methods`() throws { let source = try String(contentsOf: Self.iPadWorkboardScreenSourceURL(), encoding: .utf8) @@ -577,62 +282,6 @@ extension RootTabsSourceGuardTests { + " let response = try JSONDecoder().decode(IPadSkillProposalManifest.self")) } - @Test func `compact task rows keep phone native actions`() throws { - let source = try Self.iPadTaskFeatureScreensSource() - let compactControls = try Self.extract( - source, - from: "private var compactQueueControls: some View", - to: "private var compactRefreshButton: some View") - - #expect(source.contains("struct IPadWorkboardQueueRow")) - #expect(source.contains("private var actionMenuItems: some View")) - #expect(source.components(separatedBy: ".contextMenu {").count - 1 >= 2) - #expect(source.components(separatedBy: ".swipeActions(edge: .leading").count - 1 >= 2) - #expect(source.components(separatedBy: ".swipeActions(edge: .trailing").count - 1 >= 2) - #expect(source.contains("@State private var presentedProposalRoute: IPadSkillProposalSheetRoute?")) - #expect(source.contains(".sheet(item: self.$presentedProposalRoute)")) - #expect(source.contains("private func selectProposal(")) - #expect(!source.contains("proposalSheetPresented")) - #expect(source.contains("self.presentedSheet = .card(card)")) - #expect(!source.contains("Label(\"Gateway\", systemImage: \"network\")")) - #expect(!source.contains("Button(\"Gateway\")")) - #expect(!source.contains("actionTitle: self.canRead ? nil : \"Gateway\"")) - #expect(!source.contains("Workboard offline")) - #expect(!source.contains("Workshop offline")) - #expect(!source.contains("Connect gateway to")) - #expect(source.contains("private var compactRefreshButton: some View")) - #expect(source.contains("private var compactBoardScopeMenu: some View")) - #expect(source.contains("Color(uiColor: .secondarySystemGroupedBackground)")) - #expect(source.contains(".allowsHitTesting(false)")) - #expect(compactControls.contains("self.compactRefreshButton")) - #expect(compactControls.contains("self.compactBoardScopeMenu")) - #expect(!compactControls.contains("Self.workboardSubtitle(")) - #expect(!compactControls.contains("Label(\"Refresh\"")) - #expect(compactControls.contains("Label(\"Dispatch\"")) - } - - @Test func `skill workshop uses kanban lanes on wide I pad`() throws { - let source = try String(contentsOf: Self.iPadSkillWorkshopScreenSourceURL(), encoding: .utf8) - let content = try Self.extract( - source, - from: "private var proposalContent: some View", - to: "private var proposalBoard: some View") - let board = try Self.extract( - source, - from: "private var proposalBoard: some View", - to: "private var proposalList: some View") - - #expect(content.contains("if self.isCompactWidth")) - #expect(content.contains("self.proposalList")) - #expect(content.contains("self.proposalBoard")) - #expect(!content.contains("self.proposalDetail")) - #expect(board.contains("ScrollView(.horizontal)")) - #expect(board.contains("IPadSkillProposalKanbanColumn(")) - #expect(source.contains("private struct IPadSkillProposalKanbanCard")) - #expect(source.contains("static let defaultProposalStatusBoardLanes")) - #expect(source.contains("private func proposals(forLaneStatus status: String)")) - } - @Test func `activity screen stays split from task feature screens`() throws { let taskSource = try Self.iPadTaskFeatureScreensSource() let activitySource = try String(contentsOf: Self.iPadActivityScreenSourceURL(), encoding: .utf8) @@ -654,6 +303,7 @@ extension RootTabsSourceGuardTests { let chromeSource = try String(contentsOf: Self.iPadSidebarScreenChromeSourceURL(), encoding: .utf8) let featureSource = try Self.iPadTaskFeatureScreensSource() let rootSource = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) + let docsSource = try String(contentsOf: Self.docsSourceURL(), encoding: .utf8) #expect(chromeSource.contains("let gatewayAction: (() -> Void)?")) #expect(chromeSource.contains("private var gatewayPill: some View")) @@ -662,29 +312,19 @@ extension RootTabsSourceGuardTests { #expect(chromeSource.contains(".openClawGlassButton()")) #expect(chromeSource.contains(".accessibilityHint(\"Opens Settings / Gateway\")")) #expect(featureSource.matches(of: /gatewayAction: self\.openSettings/).count == 2) - #expect(rootSource.contains("IPadActivityScreen(")) #expect(rootSource - .matches(of: /IPadActivityScreen\([\s\S]*?openSettings: \{ self\.selectSidebarDestination\(\.gateway\) \}/) + .matches( + of: /IPad(?:Activity|Workboard|SkillWorkshop)Screen\([\s\S]*?openSettings: \{ self\.selectSidebarDestination\(\.gateway\) \}/) + .count == 3) + #expect(rootSource + .matches(of: /OpenClawDocsScreen\([\s\S]*?gatewayAction: \{ self\.selectSidebarDestination\(\.gateway\) \}/) .count == 1) + #expect(docsSource.contains("Button(action: gatewayAction)")) } - @Test func `routed gateway pills open gateway settings`() throws { + @Test func `approval notification routing suppresses the active prompt and preserves navigation history`() throws { let rootSource = try String(contentsOf: Self.rootTabsSourceURL(), encoding: .utf8) - let agentSource = try String(contentsOf: Self.agentProTabSourceURL(), encoding: .utf8) - let agentOverviewSource = try String(contentsOf: Self.agentProTabOverviewSourceURL(), encoding: .utf8) - let overviewSource = try String(contentsOf: Self.commandCenterSourceURL(), encoding: .utf8) - let chatSource = try String(contentsOf: Self.chatProTabSourceURL(), encoding: .utf8) - let docsSource = try String(contentsOf: Self.docsSourceURL(), encoding: .utf8) let settingsTabSource = try String(contentsOf: Self.settingsProTabSourceURL(), encoding: .utf8) - let settingsSource = try String(contentsOf: Self.settingsProTabSectionsSourceURL(), encoding: .utf8) - let notificationGuidanceSource = try String( - contentsOf: Self.notificationPermissionGuidanceDialogSourceURL(), - encoding: .utf8) - let settingsRoutePattern = try Regex( - #"case \.settings:[\s\S]*?SettingsProTab\("# - + #"[\s\S]*?headerSidebarAction: self\.sidebarHeaderAction,"# - + #"[\s\S]*?ownsNavigationStack: false"# - + #"[\s\S]*?onRouteChange: handleSettingsRouteChange"#) let approvalSuppression = try Self.extract( rootSource, from: "private var activeExecApprovalPromptSuppression: NodeAppModel.ExecApprovalInboxKey?", @@ -708,46 +348,6 @@ extension RootTabsSourceGuardTests { let ownedNavigation = try #require( approvalNotificationsRoute.range(of: "self.navigationPath.append(.notifications)")) - #expect(rootSource.matches(of: /openSettings: \{ self\.selectSidebarDestination\(\.gateway\) \}/).count >= 2) - #expect(!rootSource.contains("openVoiceSettings:")) - #expect(rootSource.matches(of: /gatewayAction: \{ self\.selectSidebarDestination\(\.gateway\) \}/).count == 3) - #expect(!rootSource.contains("showGatewayActions")) - #expect(!rootSource.contains("gatewayActionsDialog")) - #expect(overviewSource.contains("Button(action: self.openSettings)")) - #expect(overviewSource.contains(".accessibilityHint(\"Opens gateway settings\")")) - #expect(agentSource.contains("let openSettings: (() -> Void)?")) - #expect(agentOverviewSource.contains("OpenClawGatewayCompactPill()")) - #expect(agentOverviewSource.contains("Button(action: openSettings)")) - #expect(rootSource - .matches(of: /AgentProTab\([\s\S]*?openSettings: \{ self\.selectSidebarDestination\(\.gateway\) \}/) - .count >= 3) - #expect(chatSource.contains("let openSettings: (() -> Void)?")) - #expect(!chatSource.contains("private var connectionStatusButton: some View")) - #expect(!chatSource.contains("private var connectionPill: some View")) - #expect(chatSource.contains("private var gatewayAvatarStatusDot: some View")) - #expect(chatSource.contains(".fill(self.gatewayStatusColor)")) - #expect(chatSource.contains("private var showsExpandedGatewayStatus: Bool")) - #expect(chatSource.contains("Self.gatewayStatusShouldExpand(")) - #expect(chatSource.contains(".accessibilityIdentifier(\"chat-gateway-status\")")) - #expect(chatSource.contains(".accessibilityIdentifier(\"chat-gateway-settings\")")) - #expect(chatSource.contains("composerChrome: .clean")) - #expect(docsSource.contains("let gatewayAction: (() -> Void)?")) - #expect(docsSource.contains(".buttonBorderShape(.capsule)")) - #expect(docsSource.contains(".openClawGlassButton()")) - #expect(settingsSource.contains("NavigationLink(value: SettingsRoute.gateway)")) - #expect(rootSource.contains("case .settings:")) - #expect(rootSource.matches(of: settingsRoutePattern).count >= 1) - #expect(rootSource - .contains( - "directRoute: self.selectedSettingsRoute ?? self.selectedSidebarDestination.settingsRoute ?? .gateway")) - #expect(rootSource.contains("ownsNavigationStack: false")) - #expect(rootSource.contains("@State private var sidebarNavigationPath: [SettingsRoute] = []")) - #expect(rootSource.contains("NavigationStack(path: self.$sidebarNavigationPath)")) - #expect(rootSource.contains("self.sidebarNavigationPath.removeAll()")) - #expect(rootSource.contains("directRoute: selectedSettingsRoute")) - #expect(rootSource.contains("@State private var selectedSettingsRouteRequestID: Int = 0")) - #expect(rootSource.contains("@State private var activeSettingsRoute: SettingsRoute?")) - #expect(rootSource.contains("self.selectedSettingsRouteRequestID &+= 1")) #expect(rootSource.contains("@State private var suppressedExecApprovalForNotificationSettings")) #expect(rootSource.contains( "private var activeExecApprovalPromptSuppression: NodeAppModel.ExecApprovalInboxKey?")) @@ -787,13 +387,6 @@ extension RootTabsSourceGuardTests { #expect(rootSource.contains("private func handleSettingsRouteChange(_ route: SettingsRoute?)")) #expect(settingsTabSource.contains("let onRouteChange: ((SettingsRoute?) -> Void)?")) #expect(settingsTabSource.contains("self.onRouteChange?(self.navigationPath.last)")) - #expect(notificationGuidanceSource.contains("onSuppressFuture")) - #expect(notificationGuidanceSource.contains("suppressFuture: true")) - #expect(notificationGuidanceSource.contains("Text(\"Don't show again\")")) - #expect(rootSource.contains("private func selectSettingsRoute(_ route: SettingsRoute)")) - #expect(settingsSource.contains("title: \"Channels\"")) - #expect(settingsSource.contains("route: .channels")) - #expect(docsSource.contains(".accessibilityHint(\"Opens Settings / Gateway\")")) } @Test func `push enrollment stays behind notification disclosure flow`() throws { @@ -1477,13 +1070,6 @@ extension RootTabsSourceGuardTests { .appendingPathComponent("Sources/Chat/IOSGatewayChatTransport.swift") } - private static func proComponentsSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Design/OpenClawProComponents.swift") - } - private static func commandCenterSourceURL() -> URL { URL(fileURLWithPath: #filePath) .deletingLastPathComponent() @@ -1498,48 +1084,6 @@ extension RootTabsSourceGuardTests { .appendingPathComponent("Sources/Design/CommandCenterSupport.swift") } - private static func agentProTabSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Design/AgentProTab.swift") - } - - private static func agentProTabOverviewSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Design/AgentProTab+Overview.swift") - } - - private static func agentProTabDestinationsSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Design/AgentProTab+Destinations.swift") - } - - private static func agentProNodesDestinationSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Design/AgentProNodesDestination.swift") - } - - private static func agentProDreamingDestinationSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Design/AgentProDreamingDestination.swift") - } - - private static func rootTabsNavigationSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/RootTabsNavigation.swift") - } - private static func iPadSidebarFeatureScreensSourceURL() -> URL { URL(fileURLWithPath: #filePath) .deletingLastPathComponent() @@ -1650,13 +1194,6 @@ extension RootTabsSourceGuardTests { .appendingPathComponent("Sources/OpenClawApp.swift") } - private static func notificationPermissionGuidanceDialogSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Sources/Gateway/NotificationPermissionGuidanceDialog.swift") - } - static func settingsProTabActionsSourceURL() -> URL { URL(fileURLWithPath: #filePath) .deletingLastPathComponent() @@ -1730,22 +1267,6 @@ extension RootTabsSourceGuardTests { .appendingPathComponent("Sources/Design/SettingsSkillsDestination.swift") } - private static func sharedChatComposerSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift") - } - - private static func cleanChatComposerControlsSourceURL() -> URL { - URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("shared/OpenClawKit/Sources/OpenClawChatUI/CleanChatComposerControls.swift") - } - private static func xcodeProjectSourceURL() -> URL { URL(fileURLWithPath: #filePath) .deletingLastPathComponent()