fix: unify navigation context and feedback across tools
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
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 == .systemRed)
|
||||
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 == SunsetPalette.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(shortcut: GlobalShortcut(defaults: defaults, action: {}))
|
||||
let window = try #require(controller.window)
|
||||
let views = descendants(try #require(window.contentView))
|
||||
let recorder = try #require(views.compactMap { $0 as? NSButton }.first {
|
||||
$0.accessibilityLabel() == "Record global shortcut"
|
||||
})
|
||||
let error = try #require(views.compactMap { $0 as? NSTextField }.first {
|
||||
$0.accessibilityLabel() == "Shortcut 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 == SunsetPalette.secondaryText)
|
||||
}
|
||||
Reference in New Issue
Block a user