From 0faac20b04a0fc235680aaa94ba1dc0ab96a2c5e Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Fri, 29 Apr 2022 10:11:42 +0300 Subject: [PATCH] Bootstrap custom version of the app for UI tests --- ElementX.xcodeproj/project.pbxproj | 14 +++--- ElementX/Sources/AppDelegate.swift | 8 ++-- ElementX/Sources/UITestsAppCoordinator.swift | 47 ++++++++++++++++++++ ElementX/Sources/UITestsRootView.swift | 27 +++++++++++ UITests/Sources/Application.swift | 16 ++++++- UITests/Sources/ElementXUITests.swift | 12 ----- UITests/Sources/LoginScreenUITests.swift | 12 +++++ 7 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 ElementX/Sources/UITestsAppCoordinator.swift create mode 100644 ElementX/Sources/UITestsRootView.swift delete mode 100644 UITests/Sources/ElementXUITests.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index d31fec154..3cb31494e 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -20,11 +20,12 @@ 1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */; }; 12F70C493FB69F4D7E9A37EA /* NavigationRouterStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29EBCBFEC6FD0941749404D /* NavigationRouterStore.swift */; }; 15FEC447B7FEA62F418732AC /* ToastActivityPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E09C9DFFE9A897E439D770C5 /* ToastActivityPresenter.swift */; }; + 1852F961281BBF2C003984A9 /* UITestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1852F960281BBF2C003984A9 /* UITestsAppCoordinator.swift */; }; + 1852F965281BC327003984A9 /* UITestsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1852F964281BC327003984A9 /* UITestsRootView.swift */; }; 1999ECC6777752A2616775CF /* MemberDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */; }; 1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; }; 1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; }; 1F3232BD368DF430AB433907 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */; }; - 20563476E4766B9C3035E461 /* ElementXUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A069578069541F94F2AF016C /* ElementXUITests.swift */; }; 224A55EEAEECF5336B14A4A5 /* EmoteRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2DF459F1737A594667CC46 /* EmoteRoomMessage.swift */; }; 22DADD537401E79D66132134 /* NavigationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4173A48FD8542CD4AD3645C /* NavigationRouter.swift */; }; 24906A1E82D0046655958536 /* MessageComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CF12478983A5EB390FB26 /* MessageComposer.swift */; }; @@ -193,6 +194,8 @@ 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; 16DC8C5B2991724903F1FA6A /* AppIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = AppIcon.pdf; sourceTree = ""; }; 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = ""; }; + 1852F960281BBF2C003984A9 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = ""; }; + 1852F964281BC327003984A9 /* UITestsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsRootView.swift; sourceTree = ""; }; 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+Untranslated.swift"; sourceTree = ""; }; 1A2082B5226B2A3A4D0798B6 /* LoginScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenModels.swift; sourceTree = ""; }; 1A63815AD6A5C306453342F2 /* ImageRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItem.swift; sourceTree = ""; }; @@ -336,7 +339,6 @@ 9C5E81214D27A6B898FC397D /* ElementX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ElementX.entitlements; sourceTree = ""; }; 9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModel.swift; sourceTree = ""; }; A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelProtocol.swift; sourceTree = ""; }; - A069578069541F94F2AF016C /* ElementXUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementXUITests.swift; sourceTree = ""; }; A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineItem.swift; sourceTree = ""; }; A2B6433F516F1E6DFA0E2D89 /* vls */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vls; path = vls.lproj/Localizable.strings; sourceTree = ""; }; A436057DBEA1A23CA8CB1FD7 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = ""; }; @@ -739,7 +741,6 @@ isa = PBXGroup; children = ( 7D0CBC76C80E04345E11F2DB /* Application.swift */, - A069578069541F94F2AF016C /* ElementXUITests.swift */, 4D6E4C37E9F0E53D3DF951AC /* HomeScreenUITests.swift */, 1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */, 086B997409328F091EBA43CE /* RoomScreenUITests.swift */, @@ -890,8 +891,10 @@ E68740F873AB18A5C26844EA /* Sources */ = { isa = PBXGroup; children = ( - CF3EDF23226895776553F04A /* AppCoordinator.swift */, EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */, + CF3EDF23226895776553F04A /* AppCoordinator.swift */, + 1852F960281BBF2C003984A9 /* UITestsAppCoordinator.swift */, + 1852F964281BC327003984A9 /* UITestsRootView.swift */, 337015ADFBA3AB96660DB3A6 /* Generated */, C0937E3B06A8F0E2DB7C8241 /* Other */, E59565F441830B19DBAE567C /* Screens */, @@ -1207,6 +1210,7 @@ A636D4900E0D98ED91536482 /* AppCoordinator.swift in Sources */, 2FE4EEF780553B25A446BBFB /* AppDelegate.swift in Sources */, 90EB25D13AE6EEF034BDE9D2 /* Assets.swift in Sources */, + 1852F961281BBF2C003984A9 /* UITestsAppCoordinator.swift in Sources */, 3ED2725734568F6B8CC87544 /* AttributedStringBuilder.swift in Sources */, A6DEC1ADEC8FEEC206A0FA37 /* AttributedStringBuilderProtocol.swift in Sources */, A69B7B421C28C6CDEBBD0613 /* AuthenticationCoordinator.swift in Sources */, @@ -1238,6 +1242,7 @@ D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */, 2D8A687149E46B8C8B989561 /* KeychainController.swift in Sources */, 277D2531C70F207A2F9F5906 /* KeychainControllerProtocol.swift in Sources */, + 1852F965281BC327003984A9 /* UITestsRootView.swift in Sources */, 539F448EC0250880703775DE /* LabelledActivityIndicatorView.swift in Sources */, D826154612415D2A3BB6EBF3 /* ListTableViewAdapter.swift in Sources */, A941EAD7F407F2ED6DA54A31 /* LoginScreen.swift in Sources */, @@ -1319,7 +1324,6 @@ buildActionMask = 2147483647; files = ( 7405B4824D45BA7C3D943E76 /* Application.swift in Sources */, - 20563476E4766B9C3035E461 /* ElementXUITests.swift in Sources */, 9DC5FB22B8F86C3B51E907C1 /* HomeScreenUITests.swift in Sources */, 5C8AFBF168A41E20835F3B86 /* LoginScreenUITests.swift in Sources */, 2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */, diff --git a/ElementX/Sources/AppDelegate.swift b/ElementX/Sources/AppDelegate.swift index c57b0f48f..36a0ff963 100644 --- a/ElementX/Sources/AppDelegate.swift +++ b/ElementX/Sources/AppDelegate.swift @@ -10,7 +10,7 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - private var appCoordinator: AppCoordinator! + private var appCoordinator: Coordinator! func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { @@ -27,11 +27,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } if isRunningUITests { - // Bootstrap a different version of the application - return true + appCoordinator = UITestsAppCoordinator() + } else { + appCoordinator = AppCoordinator() } - appCoordinator = AppCoordinator() appCoordinator.start() return true } diff --git a/ElementX/Sources/UITestsAppCoordinator.swift b/ElementX/Sources/UITestsAppCoordinator.swift new file mode 100644 index 000000000..d044b8dab --- /dev/null +++ b/ElementX/Sources/UITestsAppCoordinator.swift @@ -0,0 +1,47 @@ +// +// UITestsAppCoordinator.swift +// ElementX +// +// Created by Stefan Ceriu on 29/04/2022. +// Copyright © 2022 element.io. All rights reserved. +// + +import UIKit +import SwiftUI + +class UITestsAppCoordinator: Coordinator { + private let window: UIWindow + private let mainNavigationController: UINavigationController + + var childCoordinators: [Coordinator] = [] + + init() { + mainNavigationController = UINavigationController() + window = UIWindow(frame: UIScreen.main.bounds) + window.rootViewController = mainNavigationController + + let screens = mockScreens() + let rootView = UITestsRootView(mockCoordinators: screens) { id in + guard let coordinator = screens.filter({ $0.id == id }).first else { + fatalError() + } + + self.mainNavigationController.pushViewController(coordinator.coordinator.toPresentable(), animated: true) + } + + mainNavigationController.setViewControllers([UIHostingController(rootView: rootView)], animated: false) + } + + func start() { + window.makeKeyAndVisible() + } + + private func mockScreens() -> [MockScreens] { + [MockScreens(id: "Login screen", coordinator: LoginScreenCoordinator(parameters: .init()))] + } +} + +struct MockScreens: Identifiable { + let id: String + let coordinator: Presentable +} diff --git a/ElementX/Sources/UITestsRootView.swift b/ElementX/Sources/UITestsRootView.swift new file mode 100644 index 000000000..94b033323 --- /dev/null +++ b/ElementX/Sources/UITestsRootView.swift @@ -0,0 +1,27 @@ +// +// UITestsRootView.swift +// ElementX +// +// Created by Stefan Ceriu on 29/04/2022. +// Copyright © 2022 element.io. All rights reserved. +// + +import SwiftUI + +struct UITestsRootView: View { + + let mockCoordinators: [MockScreens] + var selectionCallback: ((String) -> Void)? + + var body: some View { + NavigationView { + List(mockCoordinators) { coordinator in + Button(coordinator.id) { + selectionCallback?(coordinator.id) + } + } + .listStyle(.plain) + } + .navigationTitle("Screens") + } +} diff --git a/UITests/Sources/Application.swift b/UITests/Sources/Application.swift index 8ddab7dbc..b35db0cec 100644 --- a/UITests/Sources/Application.swift +++ b/UITests/Sources/Application.swift @@ -9,9 +9,23 @@ import XCTest struct Application { - func launch() { + static func launch() -> XCUIApplication { let app = XCUIApplication() app.launchEnvironment = ["IS_RUNNING_UI_TESTS": "1"] app.launch() + return app + } +} + +extension XCUIApplication { + func goToScreenWithIdentifier(_ identifier: String) { + let button = self.buttons[identifier] + let lastLabel = staticTexts["lastItem"] + + while !button.isHittable && !lastLabel.isHittable { + self.tables.firstMatch.swipeUp() + } + + button.tap() } } diff --git a/UITests/Sources/ElementXUITests.swift b/UITests/Sources/ElementXUITests.swift deleted file mode 100644 index 87ea4b8c2..000000000 --- a/UITests/Sources/ElementXUITests.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// ElementXUITests.swift -// ElementXUITests -// -// Created by Stefan Ceriu on 11.02.2022. -// - -import XCTest - -class ElementXUITests: XCTestCase { - -} diff --git a/UITests/Sources/LoginScreenUITests.swift b/UITests/Sources/LoginScreenUITests.swift index e6085fff9..f2dec43e5 100644 --- a/UITests/Sources/LoginScreenUITests.swift +++ b/UITests/Sources/LoginScreenUITests.swift @@ -15,3 +15,15 @@ // import XCTest + +class LoginScreenUITests: XCTestCase { + func testInitialStateComponents() { + let app = Application.launch() + app.goToScreenWithIdentifier("Login screen") + + XCTAssert(app.staticTexts["Login"].exists) + XCTAssert(app.buttons["Login"].exists) + XCTAssert(app.textFields["Username"].exists) + XCTAssert(app.secureTextFields["Password"].exists) + } +}