diff --git a/OONIProbeUITests/OoniRunViewUITests.swift b/OONIProbeUITests/OoniRunViewUITests.swift new file mode 100644 index 000000000..7c13b28e2 --- /dev/null +++ b/OONIProbeUITests/OoniRunViewUITests.swift @@ -0,0 +1,218 @@ +import Foundation +import XCTest + +/// This class runs the UI tests for the OONI Run view. +/// +/// The OONI Run view is the view that is shown when the user taps on a deeplink +/// that opens the OONI Probe app and starts a test. +/// +/// The tests are performed by simulating the launch of the app from Safari using +/// a deeplink. +/// +/// - seealso: [Reference thread](https://forums.developer.apple.com/forums/thread/25355?answerId=711988022#711988022) +/// +/// The class is part of the OONI Probe UI tests suite. +/// +class OoniRunViewUITests: XCTestCase { + + let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "2.0.0" + + func test_noInputs() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=web_connectivity&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Web Connectivity Test") + XCTAssertEqual(app.staticTexts["OONIRun.Paragraph"].label, "You are about to run an OONI Probe test.") + app.terminate() + } + + func test_emptyInputs() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=web_connectivity&ta=%7B%22urls%22%3A%5B%5D%7D&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Web Connectivity Test") + XCTAssertEqual(app.staticTexts["OONIRun.Paragraph"].label, "You are about to run an OONI Probe test.") + app.terminate() + } + + func test_openPartialInputs() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=web_connectivity&ta=%7B%22urls%22%3A%5B%22http%3A%2F%2F%22%5D%7D&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Web Connectivity Test") + XCTAssertTrue(app.staticTexts["http://"].exists) + app.terminate() + } + + func skipped_openValidUrls() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=web_connectivity&ta=%7B%22urls%22%3A%5B%22http%3A%2F%2Fwww.google.it%22%2C%22https%3A%2F%2Frun.ooni.io%2F%22%5D%7D&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Web Connectivity Test") + XCTAssertTrue(app.staticTexts["http://www.google.it"].exists) + XCTAssertTrue(app.staticTexts["https://run.ooni.io/"].exists) + app.terminate() + } + + func test_openMalformedUrl() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=web_connectivity&ta=%7B%22urls%22%3A%5B%22http%3A%2F%2Fwww.google.it%22%2C%22https%3A%2F%2Frun.ooni.io&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + + XCTAssertTrue(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].exists) + XCTAssertEqual(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].label, "Close") + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Invalid parameter") + app.terminate() + } + + func test_openNdt() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=ndt&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "NDT Speed Test") + app.terminate() + } + + func test_openDash() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=dash&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "DASH Streaming Test") + app.terminate() + } + + func test_openHttpInvalidRequestLine() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=http_invalid_request_line&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "HTTP Invalid Request Line Test") + app.terminate() + } + + func test_openHttpHeaderFieldManipulation() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=http_header_field_manipulation&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + checkRunButtonIsDisplayed(app: app) + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "HTTP Header Field Manipulation Test") + app.terminate() + } + + func test_openInvalidTestName() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?tn=antani&mv=" + appVersion) + + let _ = app.wait(for: .runningForeground, timeout: 5) + + XCTAssertTrue(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].exists) + XCTAssertEqual(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].label, "Close") + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Invalid parameter") + app.terminate() + } + + func test_openOutdatedVersion() { + let app = XCUIApplication() + + launchUrlFromSafari("ooni://nettest?mv=2100.01.01&tn=dash") + + let _ = app.wait(for: .runningForeground, timeout: 5) + + XCTAssertTrue(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].exists) + XCTAssertEqual(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].label, "Update") + XCTAssertEqual(app.staticTexts["OONIRun.Title"].label, "Out of date") + app.terminate() + } + + private func checkRunButtonIsDisplayed(app: XCUIApplication) { + XCTAssertTrue(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].waitForExistence(timeout: 50)) + XCTAssertEqual(app.buttons[NSLocalizedString("OONIRun.Run", comment: "")].label, "Run") + } + + /// Launch the OONI Probe app from Safari. + /// This method is used to simulate the launch of the app from a deeplink. + /// + /// - seealso: [Reference thread](https://forums.developer.apple.com/forums/thread/25355?answerId=711988022#711988022) + /// + /// - Parameter urlString: The deeplink URL + private func launchUrlFromSafari(_ urlString: String) { + + let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari") + + safari.launch() + + // Make sure Safari is really running before asserting + + XCTAssert(safari.wait(for: .runningForeground, timeout: 5)) + + // Type the deeplink and execute it + + let firstLaunchContinueButton = safari.buttons["Continue"] + + if firstLaunchContinueButton.exists { + + firstLaunchContinueButton.tap() + + } + + safari.textFields["Address"].tap() + + let keyboardTutorialButton = safari.buttons["Continue"].firstMatch + + if keyboardTutorialButton.exists { + + keyboardTutorialButton.tap() + + } + + safari.typeText(urlString) + + safari.buttons["go"].tap() + + let openButton = safari.buttons["Open"] + + let _ = openButton.waitForExistence(timeout: 2) + + if openButton.exists { + + openButton.tap() + + } + } + + +} diff --git a/Podfile.lock b/Podfile.lock index f35c0367f..d7085ab34 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -113,4 +113,5 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 3df4eef5a3f5aeba6a6df642bb5d669cff0662b0 + COCOAPODS: 1.15.2 diff --git a/ooniprobe.xcodeproj/project.pbxproj b/ooniprobe.xcodeproj/project.pbxproj index e2c145b1a..d3087c9e4 100644 --- a/ooniprobe.xcodeproj/project.pbxproj +++ b/ooniprobe.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 17E7EDC021BFEE0C001961C7 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E7EDBF21BFEE0C001961C7 /* SnapshotHelper.swift */; }; 526C702A25C99AB200C7A164 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 526C702925C99AB100C7A164 /* Colors.xcassets */; }; 58E18F9EBF4FAD4EFCE020F3 /* Pods_ooniprobe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB32DF3D6FC174AA1AF76009 /* Pods_ooniprobe.framework */; }; + 793587BA2B852EDD00038F88 /* OoniRunViewUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 793587B92B852EDD00038F88 /* OoniRunViewUITests.swift */; }; 7940AA8B28117E9000C0EB5D /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7940AA8A28117E9000C0EB5D /* ShareViewController.swift */; }; 7940AA8E28117E9000C0EB5D /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7940AA8C28117E9000C0EB5D /* MainInterface.storyboard */; }; 7940AA9228117E9000C0EB5D /* share.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7940AA8828117E9000C0EB5D /* share.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -218,6 +219,7 @@ 17E7EDBF21BFEE0C001961C7 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotHelper.swift; path = fastlane/SnapshotHelper.swift; sourceTree = SOURCE_ROOT; }; 526C702925C99AB100C7A164 /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; 588219FACC9F793A15BDEA33 /* Pods_OONIProbeUnitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OONIProbeUnitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 793587B92B852EDD00038F88 /* OoniRunViewUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OoniRunViewUITests.swift; sourceTree = ""; }; 7940AA8828117E9000C0EB5D /* share.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = share.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7940AA8A28117E9000C0EB5D /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; 7940AA8D28117E9000C0EB5D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; @@ -583,6 +585,7 @@ 17E7EDBF21BFEE0C001961C7 /* SnapshotHelper.swift */, 17E7EDB721BFEDD1001961C7 /* OONIProbeUITests.swift */, 17E7EDB921BFEDD1001961C7 /* Info.plist */, + 793587B92B852EDD00038F88 /* OoniRunViewUITests.swift */, ); path = OONIProbeUITests; sourceTree = ""; @@ -1517,6 +1520,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 793587BA2B852EDD00038F88 /* OoniRunViewUITests.swift in Sources */, 17E7EDB821BFEDD1001961C7 /* OONIProbeUITests.swift in Sources */, 17E7EDC021BFEE0C001961C7 /* SnapshotHelper.swift in Sources */, ); diff --git a/ooniprobe.xcodeproj/xcshareddata/xcschemes/OONIProbeUnitTests.xcscheme b/ooniprobe.xcodeproj/xcshareddata/xcschemes/OONIProbeUnitTests.xcscheme index eccabcc7e..5f848a71b 100644 --- a/ooniprobe.xcodeproj/xcshareddata/xcschemes/OONIProbeUnitTests.xcscheme +++ b/ooniprobe.xcodeproj/xcshareddata/xcschemes/OONIProbeUnitTests.xcscheme @@ -5,6 +5,18 @@ + + + + + + + +