Skip to content

Commit

Permalink
Merge branch 'ad-blocking-via-dns-ios-440'
Browse files Browse the repository at this point in the history
  • Loading branch information
buggmagnet committed Jan 24, 2024
2 parents f4d2f44 + 3a5ba4a commit f4ec9f8
Show file tree
Hide file tree
Showing 20 changed files with 318 additions and 22 deletions.
8 changes: 7 additions & 1 deletion ios/Configurations/UITests.xcconfig.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

// Pin code of the iOS device under test
MULLVAD_IOS_DEVICE_PIN_CODE =

// Ad serving domain used when testing ad blocking. Not that we are assuming there's an HTTP server running on the host.
MULLVAD_AD_SERVING_DOMAIN =

// Mullvad accounts used by UI tests
MULLVAD_NO_TIME_ACCOUNT_NUMBER =
MULLVAD_HAS_TIME_ACCOUNT_NUMBER =
MULLVAD_FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER =
MULLVAD_FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER =

26 changes: 23 additions & 3 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -568,13 +568,18 @@
7AF9BE902A39F26000DBFEDB /* Collection+Sorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF9BE8F2A39F26000DBFEDB /* Collection+Sorting.swift */; };
7AF9BE952A40461100DBFEDB /* RelayFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF9BE942A40461100DBFEDB /* RelayFilterView.swift */; };
7AF9BE972A41C71F00DBFEDB /* RelayFilterChipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF9BE962A41C71F00DBFEDB /* RelayFilterChipView.swift */; };
850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DA2B503D7700EF8C96 /* RelayTests.swift */; };
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */; };
850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */; };
850201E12B51389500EF8C96 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201E02B51389500EF8C96 /* BaseUITestCase.swift */; };
850201E32B51A93C00EF8C96 /* SettingsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201E22B51A93C00EF8C96 /* SettingsPage.swift */; };
852969282B4D9C1F007EAD4C /* AccountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969272B4D9C1F007EAD4C /* AccountTests.swift */; };
852969332B4E9232007EAD4C /* Page.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969322B4E9232007EAD4C /* Page.swift */; };
852969352B4E9270007EAD4C /* LoginPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969342B4E9270007EAD4C /* LoginPage.swift */; };
852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0B311D2B303A0D004B12E0 /* AccessbilityIdentifier.swift */; };
8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */; };
8529693C2B4F0257007EAD4C /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8529693B2B4F0257007EAD4C /* Alert.swift */; };
85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */; };
A900E9B82ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */; };
A900E9BA2ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */; };
A900E9BC2ACC609200C95F67 /* DevicesProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */; };
Expand Down Expand Up @@ -1720,7 +1725,11 @@
7AF9BE8F2A39F26000DBFEDB /* Collection+Sorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Sorting.swift"; sourceTree = "<group>"; };
7AF9BE942A40461100DBFEDB /* RelayFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayFilterView.swift; sourceTree = "<group>"; };
7AF9BE962A41C71F00DBFEDB /* RelayFilterChipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayFilterChipView.swift; sourceTree = "<group>"; };
850201DA2B503D7700EF8C96 /* RelayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayTests.swift; sourceTree = "<group>"; };
850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationPage.swift; sourceTree = "<group>"; };
850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControlPage.swift; sourceTree = "<group>"; };
850201E02B51389500EF8C96 /* BaseUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; };
850201E22B51A93C00EF8C96 /* SettingsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPage.swift; sourceTree = "<group>"; };
852969252B4D9C1F007EAD4C /* MullvadVPNUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadVPNUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
852969272B4D9C1F007EAD4C /* AccountTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTests.swift; sourceTree = "<group>"; };
852969302B4D9E70007EAD4C /* MullvadVPNUITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MullvadVPNUITests.xctestplan; sourceTree = "<group>"; };
Expand All @@ -1730,6 +1739,7 @@
852969382B4ED818007EAD4C /* UITests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UITests.xcconfig; sourceTree = "<group>"; };
852969392B4F0238007EAD4C /* TermsOfServicePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfServicePage.swift; sourceTree = "<group>"; };
8529693B2B4F0257007EAD4C /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; };
85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIElementQuery+Extensions.swift"; sourceTree = "<group>"; };
A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountsProxy+Stubs.swift"; sourceTree = "<group>"; };
A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RESTRequestExecutor+Stubs.swift"; sourceTree = "<group>"; };
A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DevicesProxy+Stubs.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2937,6 +2947,7 @@
58CE5E62224146200008646E /* MullvadVPN */,
58D0C79423F1CE7000FE9BA7 /* MullvadVPNScreenshots */,
58B0A2A1238EE67E00BC001D /* MullvadVPNTests */,
852969262B4D9C1F007EAD4C /* MullvadVPNUITests */,
58D223F4294C8FF00029F5F8 /* MullvadLogging */,
581943F228F8014500B0CB5E /* MullvadTypes */,
06799ABD28F98E1D00ACD94E /* MullvadREST */,
Expand All @@ -2952,7 +2963,6 @@
58C7A4432A863F490060C66F /* PacketTunnelCoreTests */,
7A88DCCF2A8FABBE00D2FF0E /* Routing */,
7A88DCDD2A8FABBE00D2FF0E /* RoutingTests */,
852969262B4D9C1F007EAD4C /* MullvadVPNUITests */,
58CE5E61224146200008646E /* Products */,
584F991F2902CBDD001F858D /* Frameworks */,
);
Expand Down Expand Up @@ -3333,17 +3343,22 @@
852969312B4E9220007EAD4C /* Pages */,
852969272B4D9C1F007EAD4C /* AccountTests.swift */,
850201E02B51389500EF8C96 /* BaseUITestCase.swift */,
850201DA2B503D7700EF8C96 /* RelayTests.swift */,
85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */,
);
path = MullvadVPNUITests;
sourceTree = "<group>";
};
852969312B4E9220007EAD4C /* Pages */ = {
isa = PBXGroup;
children = (
852969322B4E9232007EAD4C /* Page.swift */,
8529693B2B4F0257007EAD4C /* Alert.swift */,
852969342B4E9270007EAD4C /* LoginPage.swift */,
852969322B4E9232007EAD4C /* Page.swift */,
850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */,
850201E22B51A93C00EF8C96 /* SettingsPage.swift */,
852969392B4F0238007EAD4C /* TermsOfServicePage.swift */,
8529693B2B4F0257007EAD4C /* Alert.swift */,
850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */,
);
path = Pages;
sourceTree = "<group>";
Expand Down Expand Up @@ -5202,11 +5217,16 @@
buildActionMask = 2147483647;
files = (
8529693C2B4F0257007EAD4C /* Alert.swift in Sources */,
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */,
850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */,
852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */,
852969352B4E9270007EAD4C /* LoginPage.swift in Sources */,
850201E12B51389500EF8C96 /* BaseUITestCase.swift in Sources */,
850201E32B51A93C00EF8C96 /* SettingsPage.swift in Sources */,
852969282B4D9C1F007EAD4C /* AccountTests.swift in Sources */,
85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */,
8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */,
850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */,
852969332B4E9232007EAD4C /* Page.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
10 changes: 10 additions & 0 deletions ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum AccessibilityIdentifier: String {
case alertOkButton
case applyButton
case cancelButton
case connectionPanelButton
case collapseButton
case deleteButton
case disconnectButton
Expand Down Expand Up @@ -47,9 +48,18 @@ public enum AccessibilityIdentifier: String {
case alertTitle
case loginView
case termsOfServiceView
case selectLocationView
case selectLocationTableView
case settingsTableView
case tunnelControlView

// Other UI elements
case connectionPanelInAddressRow
case connectionPanelOutAddressRow
case customSwitch
case dnsContentBlockersHeaderView
case loginTextField
case selectLocationSearchTextField

// DNS settings
case dnsSettings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ final class CustomDNSDataSource: UITableViewDiffableDataSource<

header.titleLabel.text = title
header.accessibilityCustomActionName = title
header.accessibilityIdentifier = .dnsContentBlockersHeaderView

header.infoButtonHandler = { [weak self] in
self?.delegate?.showInfo(for: .contentBlockers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ final class SelectLocationViewController: UIViewController {
tableView.estimatedRowHeight = 53
tableView.indicatorStyle = .white
tableView.keyboardDismissMode = .onDrag
tableView.accessibilityIdentifier = .selectLocationTableView
}

private func setUpTopContent() {
Expand Down Expand Up @@ -167,6 +168,7 @@ final class SelectLocationViewController: UIViewController {
value: "Search for...",
comment: ""
)
searchBar.searchTextField.accessibilityIdentifier = .selectLocationSearchTextField

UITextField.SearchTextFieldAppearance.inactive.apply(to: searchBar)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class SettingsViewController: UITableViewController, SettingsDataSourceDelegate
})
)

tableView.accessibilityIdentifier = .settingsTableView
tableView.backgroundColor = .secondaryColor
tableView.separatorColor = .secondaryColor
tableView.rowHeight = UITableView.automaticDimension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class ConnectionPanelView: UIView {
inAddressRow.translatesAutoresizingMaskIntoConstraints = false
outAddressRow.translatesAutoresizingMaskIntoConstraints = false

inAddressRow.accessibilityIdentifier = .connectionPanelInAddressRow
outAddressRow.accessibilityIdentifier = .connectionPanelOutAddressRow

inAddressRow.title = NSLocalizedString(
"IN_ADDRESS_LABEL",
tableName: "ConnectionPanel",
Expand Down Expand Up @@ -285,6 +288,8 @@ class ConnectionPanelCollapseButton: CustomButton {
imageAlignment = .trailing
inlineImageSpacing = 0

accessibilityIdentifier = .connectionPanelButton

updateButtonImage()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ final class TunnelControlView: UIView {
backgroundColor = .clear
directionalLayoutMargins = UIMetrics.contentLayoutMargins
accessibilityContainerType = .semanticGroup
accessibilityIdentifier = .tunnelControlView

addSubviews()
addButtonHandlers()
Expand Down
2 changes: 2 additions & 0 deletions ios/MullvadVPN/Views/CustomSwitch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class CustomSwitch: UISwitch {
onTintColor = .clear
overrideUserInterfaceStyle = .light

accessibilityIdentifier = .customSwitch

updateThumbColor(isOn: isOn, animated: false)

addTarget(self, action: #selector(valueChanged(_:)), for: .valueChanged)
Expand Down
27 changes: 24 additions & 3 deletions ios/MullvadVPNUITests/BaseUITestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,31 @@ import Foundation
import XCTest

class BaseUITestCase: XCTestCase {
public static let defaultTimeout = 10.0

// swiftlint:disable force_cast
let noTimeAccountNumber = Bundle(for: AccountTests.self).infoDictionary?["MullvadNoTimeAccountNumber"] as! String
let hasTimeAccountNumber = Bundle(for: AccountTests.self).infoDictionary?["MullvadHasTimeAccountNumber"] as! String
let fiveWireGuardKeysAccountNumber = Bundle(for: AccountTests.self)
let noTimeAccountNumber = Bundle(for: BaseUITestCase.self)
.infoDictionary?["MullvadNoTimeAccountNumber"] as! String
let hasTimeAccountNumber = Bundle(for: BaseUITestCase.self)
.infoDictionary?["MullvadHasTimeAccountNumber"] as! String
let fiveWireGuardKeysAccountNumber = Bundle(for: BaseUITestCase.self)
.infoDictionary?["MullvadFiveWireGuardKeysAccountNumber"] as! String
let iOSDevicePinCode = Bundle(for: BaseUITestCase.self)
.infoDictionary?["MullvadIOSDevicePinCode"] as! String
let adServingDomain = Bundle(for: BaseUITestCase.self)
.infoDictionary?["MullvadAdServingDomain"] as! String
// swiftlint:enable force_cast

/// Handle iOS add VPN configuration permission alert - allow and enter device PIN code
func allowAddVPNConfigurations() {
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

let alertAllowButton = springboard.buttons.element(boundBy: 0)
if alertAllowButton.waitForExistence(timeout: Self.defaultTimeout) {
alertAllowButton.tap()
}

_ = springboard.buttons["1"].waitForExistence(timeout: Self.defaultTimeout)
springboard.typeText(iOSDevicePinCode)
}
}
4 changes: 4 additions & 0 deletions ios/MullvadVPNUITests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MullvadAdServingDomain</key>
<string>$(MULLVAD_AD_SERVING_DOMAIN)</string>
<key>MullvadFiveWireGuardKeysAccountNumber</key>
<string>$(MULLVAD_FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER)</string>
<key>MullvadHasTimeAccountNumber</key>
<string>$(MULLVAD_HAS_TIME_ACCOUNT_NUMBER)</string>
<key>MullvadIOSDevicePinCode</key>
<string>$(MULLVAD_IOS_DEVICE_PIN_CODE)</string>
<key>MullvadNoTimeAccountNumber</key>
<string>$(MULLVAD_NO_TIME_ACCOUNT_NUMBER)</string>
</dict>
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadVPNUITests/Pages/Alert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Alert: Page {
}

@discardableResult func tapOkay() -> Self {
app.buttons[AccessibilityIdentifier.alertOkButton.rawValue].tap()
app.buttons[AccessibilityIdentifier.alertOkButton].tap()
return self
}
}
8 changes: 4 additions & 4 deletions ios/MullvadVPNUITests/Pages/LoginPage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ class LoginPage: Page {
}

@discardableResult public func tapAccountNumberTextField() -> Self {
app.textFields[AccessibilityIdentifier.loginTextField.rawValue].tap()
app.textFields[AccessibilityIdentifier.loginTextField].tap()
return self
}

@discardableResult public func tapAccountNumberSubmitButton() -> Self {
app.buttons[AccessibilityIdentifier.loginTextFieldButton.rawValue].tap()
app.buttons[AccessibilityIdentifier.loginTextFieldButton].tap()
return self
}

@discardableResult public func verifyDeviceLabelShown() -> Self {
XCTAssertTrue(
app.staticTexts[AccessibilityIdentifier.headerDeviceNameLabel.rawValue]
.waitForExistence(timeout: defaultTimeout)
app.staticTexts[AccessibilityIdentifier.headerDeviceNameLabel]
.waitForExistence(timeout: BaseUITestCase.defaultTimeout)
)

return self
Expand Down
17 changes: 8 additions & 9 deletions ios/MullvadVPNUITests/Pages/Page.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@ import XCTest
class Page {
let app: XCUIApplication
var pageAccessibilityIdentifier: AccessibilityIdentifier?
let defaultTimeout = 10.0

init(_ app: XCUIApplication) {
@discardableResult init(_ app: XCUIApplication) {
self.app = app
}

public func enterText(_ text: String) -> Self {
app.typeText(text)
return self
}

public func waitForPageToBeShown() {
if let pageAccessibilityIdentifier = self.pageAccessibilityIdentifier {
XCTAssert(
self.app.otherElements[pageAccessibilityIdentifier.rawValue]
.waitForExistence(timeout: defaultTimeout)
self.app.otherElements[pageAccessibilityIdentifier]
.waitForExistence(timeout: BaseUITestCase.defaultTimeout)
)
}
}

@discardableResult public func enterText(_ text: String) -> Self {
app.typeText(text)
return self
}
}
34 changes: 34 additions & 0 deletions ios/MullvadVPNUITests/Pages/SelectLocationPage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// SelectLocationPage.swift
// MullvadVPNUITests
//
// Created by Niklas Berglund on 2024-01-11.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import Foundation
import XCTest

class SelectLocationPage: Page {
@discardableResult override init(_ app: XCUIApplication) {
super.init(app)

self.pageAccessibilityIdentifier = .selectLocationView
}

@discardableResult func tapLocationCell(withName name: String) -> Self {
app.tables[AccessibilityIdentifier.selectLocationTableView].cells.staticTexts[name].tap()
return self
}

@discardableResult func tapLocationCellExpandButton(withName name: String) -> Self {
let table = app.tables[AccessibilityIdentifier.selectLocationTableView]
let matchingCells = table.cells.containing(.any, identifier: name)
let buttons = matchingCells.buttons
let expandButton = buttons[AccessibilityIdentifier.collapseButton]

expandButton.tap()

return self
}
}
Loading

0 comments on commit f4ec9f8

Please sign in to comment.