mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
test(ios): remove redundant root tabs source guards (#130012)
This commit is contained in:
committed by
GitHub
parent
ff73ba5f56
commit
bddd0aaa6f
@@ -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<Leading: View, Accessory: View>: 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()
|
||||
|
||||
Reference in New Issue
Block a user