Skip to content

Commit

Permalink
UI Tests: Permissions (#2625)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/1199230911884351/1205717021705373/f

Description: Adds a series of UI tests for permissions
  • Loading branch information
Halle authored and diegoreymendez committed Apr 18, 2024
1 parent 2653194 commit 2d8c80b
Show file tree
Hide file tree
Showing 17 changed files with 693 additions and 23 deletions.
4 changes: 4 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3324,6 +3324,7 @@
EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; };
EE3424602BA0853900173B1B /* VPNUninstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE34245D2BA0853900173B1B /* VPNUninstaller.swift */; };
EE3424612BA0853900173B1B /* VPNUninstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE34245D2BA0853900173B1B /* VPNUninstaller.swift */; };
EE42CBCC2BC8004700AD411C /* PermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE42CBCB2BC8004700AD411C /* PermissionsTests.swift */; };
EE54F7B32BBFEA49006218DB /* BookmarksAndFavoritesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE54F7B22BBFEA48006218DB /* BookmarksAndFavoritesTests.swift */; };
EE66418C2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; };
EE66418D2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; };
Expand Down Expand Up @@ -4819,6 +4820,7 @@
EE0429DF2BA31D2F009EB20F /* FindInPageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindInPageTests.swift; sourceTree = "<group>"; };
EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = "<group>"; };
EE34245D2BA0853900173B1B /* VPNUninstaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNUninstaller.swift; sourceTree = "<group>"; };
EE42CBCB2BC8004700AD411C /* PermissionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionsTests.swift; sourceTree = "<group>"; };
EE54F7B22BBFEA48006218DB /* BookmarksAndFavoritesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksAndFavoritesTests.swift; sourceTree = "<group>"; };
EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift"; sourceTree = "<group>"; };
EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6622,6 +6624,7 @@
EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */,
EE02D41B2BB460A600DBE6B3 /* BrowsingHistoryTests.swift */,
EE0429DF2BA31D2F009EB20F /* FindInPageTests.swift */,
EE42CBCB2BC8004700AD411C /* PermissionsTests.swift */,
EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */,
7B4CE8E626F02134009134B1 /* TabBarTests.swift */,
);
Expand Down Expand Up @@ -12381,6 +12384,7 @@
EEC7BE2E2BC6C09500F86835 /* AddressBarKeyboardShortcutsTests.swift in Sources */,
EE54F7B32BBFEA49006218DB /* BookmarksAndFavoritesTests.swift in Sources */,
EE02D4222BB4611A00DBE6B3 /* TestsURLExtension.swift in Sources */,
EE42CBCC2BC8004700AD411C /* PermissionsTests.swift in Sources */,
7B4CE8E726F02135009134B1 /* TabBarTests.swift in Sources */,
EEBCE6832BA463DD00B9DF00 /* NSImageExtensions.swift in Sources */,
EEBCE6822BA444FA00B9DF00 /* XCUIElementExtension.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ final class AddressBarButtonsViewController: NSViewController {
return permissionAuthorizationPopover ?? {
let popover = PermissionAuthorizationPopover()
self.permissionAuthorizationPopover = popover
popover.setAccessibilityIdentifier("AddressBarButtonsViewController.permissionAuthorizationPopover")
return popover
}()
}
Expand Down
4 changes: 4 additions & 0 deletions DuckDuckGo/NavigationBar/View/NavigationBar.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@
<userDefinedRuntimeAttribute type="image" keyPath="disabledImage" value="Geolocation-Icon"/>
<userDefinedRuntimeAttribute type="image" keyPath="mutedImage" value="Geolocation-Icon"/>
</userDefinedRuntimeAttributes>
<accessibility identifier="NavigationBarViewController.geolocationPermissionButton"/>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="uao-nC-0co" userLabel="Microphone Button" customClass="PermissionButton" customModule="DuckDuckGo_Privacy_Browser" customModuleProvider="target">
<rect key="frame" x="32" y="0.0" width="32" height="32"/>
Expand All @@ -747,6 +748,7 @@
<userDefinedRuntimeAttribute type="image" keyPath="disabledImage" value="Microphone-Icon"/>
<userDefinedRuntimeAttribute type="image" keyPath="mutedImage" value="Microphone-Icon"/>
</userDefinedRuntimeAttributes>
<accessibility identifier="NavigationBarViewController.microphonePermissionButton"/>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="C2L-f9-L3r" userLabel="Camera Button" customClass="PermissionButton" customModule="DuckDuckGo_Privacy_Browser" customModuleProvider="target">
<rect key="frame" x="64" y="0.0" width="32" height="32"/>
Expand All @@ -770,6 +772,7 @@
<userDefinedRuntimeAttribute type="image" keyPath="disabledImage" value="Camera-Tab-Blocked"/>
<userDefinedRuntimeAttribute type="image" keyPath="mutedImage" value="Camera-Icon"/>
</userDefinedRuntimeAttributes>
<accessibility identifier="NavigationBarViewController.cameraPermissionButton"/>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qqY-h9-UQ7" userLabel="Popups Button" customClass="PermissionButton" customModule="DuckDuckGo_Privacy_Browser" customModuleProvider="target">
<rect key="frame" x="96" y="0.0" width="32" height="32"/>
Expand All @@ -789,6 +792,7 @@
<color key="value" name="ButtonMouseDownColor"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<accessibility identifier="NavigationBarViewController.popupsPermissionButton"/>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gGA-Yv-pnz" userLabel="External Scheme Button" customClass="PermissionButton" customModule="DuckDuckGo_Privacy_Browser" customModuleProvider="target">
<rect key="frame" x="128" y="0.0" width="32" height="32"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ final class PermissionAuthorizationViewController: NSViewController {
} else {
denyButton.title = UserText.permissionPopoverDenyButton
}
denyButton.setAccessibilityIdentifier("PermissionAuthorizationViewController.denyButton")
}

private func updateText() {
Expand Down Expand Up @@ -116,6 +117,7 @@ final class PermissionAuthorizationViewController: NSViewController {
buttonsBottomConstraint.isActive = !learnMoreBottomConstraint.isActive
linkButton.title = UserText.permissionPopupLearnMoreLink
allowButton.title = UserText.permissionPopupAllowButton
allowButton.setAccessibilityIdentifier("PermissionAuthorizationViewController.allowButton")
}

@IBAction func alwaysAllowLabelClick(_ sender: Any) {
Expand Down
5 changes: 5 additions & 0 deletions DuckDuckGo/Permissions/View/PermissionButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,23 @@ final class PermissionButton: AddressBarButton {
case .active:
self.image = activeImage ?? defaultImage
self.normalTintColor = activeTintColor
self.setAccessibilityValue("active")
case .paused:
self.image = mutedImage ?? defaultImage
self.normalTintColor = mutedTintColor
self.setAccessibilityValue("paused")
case .disabled, .denied, .revoking:
self.image = disabledImage ?? defaultImage
self.normalTintColor = disabledTintColor
self.setAccessibilityValue("disabled-denied-revoking")
case .requested:
self.image = defaultImage
self.normalTintColor = defaultTint
self.setAccessibilityValue("requested")
case .inactive:
self.image = inactiveImage ?? defaultImage
self.normalTintColor = inactiveTintColor ?? defaultTint
self.setAccessibilityValue("inactive")
}
self.isHidden = isHidden
}
Expand Down
12 changes: 11 additions & 1 deletion DuckDuckGo/Permissions/View/PermissionContextMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ final class PermissionContextMenu: NSMenu {
setupOtherPermissionMenuItems(for: remainingPermission)
setupPopupsPermissionsMenuItems()
addPersistenceItems()
self.setAccessibilityIdentifier("PermissionContextMenu")
}

private func setupCameraPermissionsMenuItems(_ permissions: Permissions) -> Permissions {
Expand Down Expand Up @@ -279,6 +280,8 @@ private extension NSMenuItem {
if isChecked {
item.state = .on
}
item.setAccessibilityIdentifier("PermissionContextMenu.alwaysAllow")
item.setAccessibilityValue(item.state == .on ? "selected" : "unselected")
return item
}

Expand All @@ -299,6 +302,8 @@ private extension NSMenuItem {
if isChecked {
item.state = .on
}
item.setAccessibilityIdentifier("PermissionContextMenu.alwaysAsk")
item.setAccessibilityValue(item.state == .on ? "selected" : "unselected")
return item
}

Expand All @@ -312,6 +317,8 @@ private extension NSMenuItem {
if isChecked {
item.state = .on
}
item.setAccessibilityIdentifier("PermissionContextMenu.alwaysDeny")
item.setAccessibilityValue(item.state == .on ? "selected" : "unselected")
return item
}

Expand All @@ -325,7 +332,10 @@ private extension NSMenuItem {
permission.localizedDescription,
Bundle.main.displayName ?? "DuckDuckGo")
}
return NSMenuItem(title: title, action: nil, keyEquivalent: "")
let item = NSMenuItem(title: title, action: nil, keyEquivalent: "")
item.setAccessibilityIdentifier("PermissionContextMenu.permissionDisabled")
item.setAccessibilityValue(item.state == .on ? "selected" : "unselected")
return item
}

static func openSystemPreferences(for permission: PermissionType, target: PermissionContextMenu) -> NSMenuItem {
Expand Down
1 change: 1 addition & 0 deletions UITests/AddressBarKeyboardShortcutsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class AddressBarKeyboardShortcutsTests: XCTestCase {

private var addressBarTextField: XCUIElement!
override class func setUp() {
UITests.firstRun()
UITests.setAutocompleteToggleBeforeTestcaseRuns(false) // We don't want changes in the address bar that we don't create
}

Expand Down
1 change: 1 addition & 0 deletions UITests/AutocompleteTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AutocompleteTests: XCTestCase {
private var siteTitleForHistorySite: String!

override class func setUp() {
UITests.firstRun()
UITests.setAutocompleteToggleBeforeTestcaseRuns(true) // These tests require autocomplete to be on
}

Expand Down
7 changes: 6 additions & 1 deletion UITests/BookmarksAndFavoritesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ class BookmarksAndFavoritesTests: XCTestCase {
private var showBookmarksBarPopup: XCUIElement!
private var showFavoritesPreferenceToggle: XCUIElement!

override class func setUp() {
UITests.firstRun()
}

override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
Expand Down Expand Up @@ -595,7 +599,8 @@ class BookmarksAndFavoritesTests: XCTestCase {
// This test uses coordinates (instead of accessibility IDs) to address the elements of the right click. As the writer of this test, I see this
// as a fragile test hook. However, I think it is preferable to making changes to the UI element it tests for this test alone. The reason is
// that the bookmark item on the bookmark bar isn't yet an accessibility-enabled UI element and doesn't appear to have a natural anchor point
// from which we can set its accessibility values without redesigning it. However, redesigning a road-tested UI element for a single test isn't a
// from which we can set its accessibility values without redesigning it. However, redesigning a road-tested UI element for a single test isn't
// a
// good idea, since the road-testing is also (valuable) testing and we don't want a single test to be the driver of a possible behavioral
// change in existing interface.
//
Expand Down
4 changes: 4 additions & 0 deletions UITests/BookmarksBarTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class BookmarksBarTests: XCTestCase {
private var addressBarTextField: XCUIElement!
private let titleStringLength = 12

override class func setUp() {
UITests.firstRun()
}

override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
Expand Down
4 changes: 4 additions & 0 deletions UITests/BrowsingHistoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class BrowsingHistoryTests: XCTestCase {
private var addressBarTextField: XCUIElement!
private let lengthForRandomPageTitle = 8

override class func setUp() {
UITests.firstRun()
}

override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
Expand Down
13 changes: 13 additions & 0 deletions UITests/Common/UITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,17 @@ enum UITests {
openVanillaBrowser.clickAfterExistenceTestSucceeds()
app.typeKey("w", modifierFlags: [.command, .option])
}

/// Avoid some first-run states that we aren't testing.
static func firstRun() {
let notificationCenter = XCUIApplication(bundleIdentifier: "com.apple.UserNotificationCenter")
if notificationCenter.exists { // If tests-server is asking for network permissions, deny them.
notificationCenter.typeKey(.escape, modifierFlags: [])
}
let app = XCUIApplication()
app.launch()
app.typeKey("n", modifierFlags: .command)
app.typeKey("w", modifierFlags: [.command, .option])
app.terminate()
}
}
14 changes: 14 additions & 0 deletions UITests/Common/XCUIElementExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ extension XCUIElement {
}
}

/// Check for the existence of the address bar and type a URL into it if it passes. Although it doesn't really make sense to restrict its usage to
/// the address bar, it is only foreseen and recommended for use with the address bar.
/// - Parameters:
/// - url: The URL to be typed into the address bar (or other element, for which use with this function should be seen as experimental)
/// - pressingEnter: If the `enter` key should not be pressed after typing this URL in, set this optional parameter to `false`, otherwise it
/// will be pressed.
func typeURLAfterExistenceTestSucceeds(_ url: URL, pressingEnter: Bool = true) {
XCTAssertTrue(
self.waitForExistence(timeout: UITests.Timeouts.elementExistence),
"The element \(self.debugDescription) didn't load with the expected title in a reasonable timeframe."
)
self.typeURL(url, pressingEnter: pressingEnter)
}

func clickAfterExistenceTestSucceeds() {
XCTAssertTrue(
self.waitForExistence(timeout: UITests.Timeouts.elementExistence),
Expand Down
Loading

0 comments on commit 2d8c80b

Please sign in to comment.