import AppKit import ConjureKit import Testing @testable import Conjure @MainActor private func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap { descendants($0) } } @Test @MainActor func uninstallFilteringPreservesDiscoveryStateAndCheckedFiles() throws { _ = NSApplication.shared let controller = UninstallReviewController( application: Application(url: URL(fileURLWithPath: "/Applications/Example.app"), name: "Example"), uninstaller: ApplicationUninstaller()) let views = descendants(controller.view) let filter = try #require(views.compactMap { $0 as? NSSearchField }.first) let status = try #require(views.compactMap { $0 as? NSTextField }.first { $0.accessibilityLabel() == "Uninstall selection and progress" }) let table = try #require(views.compactMap { $0 as? NSTableView }.first) let remove = try #require(views.compactMap { $0 as? NSButton }.first { $0.keyEquivalent == "\r" }) func filterBy(_ query: String) { filter.stringValue = query controller.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: filter)) } let loading = status.stringValue filterBy("cache") #expect(status.stringValue == loading) #expect(!remove.isEnabled) struct ScanFailure: LocalizedError { var errorDescription: String? { "Access denied by the filesystem" } } controller.applyDiscoveryResult(.failure(ScanFailure())) let failure = status.stringValue #expect(failure.contains(ScanFailure().localizedDescription)) #expect(status.textColor == ThemePalette.error) filterBy("different") #expect(status.stringValue == failure) #expect(!remove.isEnabled) let candidate = UninstallCandidate(url: URL(fileURLWithPath: "/tmp/example-cache"), size: 1024, isSelectable: true, defaultSelected: true, reason: nil) controller.applyDiscoveryResult(.success([candidate])) filterBy("") let counts = status.stringValue #expect(status.textColor == ThemePalette.secondaryText) #expect(remove.isEnabled) #expect(table.numberOfRows == 1) filterBy("no-match") #expect(table.numberOfRows == 0) #expect(remove.isEnabled) filterBy("") #expect(status.stringValue == counts) #expect(table.numberOfRows == 1) _ = controller.control(filter, textView: NSTextView(), doCommandBy: #selector(NSResponder.insertNewline(_:))) #expect(!remove.isEnabled) } @Test @MainActor func shortcutModifierGuidanceDoesNotAppearAsAnError() throws { _ = NSApplication.shared let suite = "Conjure.ToolFeedbackTests.\(UUID().uuidString)" let defaults = try #require(UserDefaults(suiteName: suite)) defer { defaults.removePersistentDomain(forName: suite) } let controller = SettingsWindowController(shortcuts: GlobalShortcuts(defaults: defaults, action: { _ in })) let window = try #require(controller.window) let views = descendants(try #require(window.contentView)) let recorder = try #require(views.compactMap { $0 as? NSButton }.first { $0.action == NSSelectorFromString("beginRecording") }) let error = try #require(views.compactMap { $0 as? NSTextField }.first { $0.accessibilityLabel() == "Settings feedback" }) let status = try #require(views.compactMap { $0 as? NSTextField }.first { $0.accessibilityLabel() == "Global shortcut registration status" }) recorder.performClick(nil) defer { window.close() } #expect(window.firstResponder === recorder) let modifier = try #require(NSEvent.keyEvent(with: .flagsChanged, location: .zero, modifierFlags: .command, timestamp: 1, windowNumber: window.windowNumber, context: nil, characters: "", charactersIgnoringModifiers: "", isARepeat: false, keyCode: 55)) recorder.flagsChanged(with: modifier) #expect(error.stringValue.isEmpty) #expect(status.textColor == ThemePalette.secondaryText) }