diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj
index 2c2d75243..7557c7556 100644
--- a/FlowCrypt.xcodeproj/project.pbxproj
+++ b/FlowCrypt.xcodeproj/project.pbxproj
@@ -1070,7 +1070,6 @@
isa = PBXGroup;
children = (
D2F18469244DB8F6000CC5D1 /* SnapshotHelper.swift */,
- D2F18467244B0F35000CC5D1 /* AppTestHelper.swift */,
9FDF3651235A1EDE00614596 /* XCUIApplicationBuilder.swift */,
9FDF364F235A1D3F00614596 /* UITestHelper.swift */,
9F228BA523C673AD005D2CB6 /* Springboard.swift */,
@@ -1417,6 +1416,7 @@
9FDF364C235A1CCD00614596 /* SignInImapTest.swift */,
D2F18463244B0C63000CC5D1 /* SignInGoogleTest.swift */,
D216D05D242D32EA0083EDD6 /* TestCredentials.swift */,
+ D2F18467244B0F35000CC5D1 /* AppTestHelper.swift */,
9FDF3645235A1B0100614596 /* Info.plist */,
9F2F212A26B305420044E144 /* test-ci-secrets.json */,
9F228BA723C673C2005D2CB6 /* Resources */,
diff --git a/FlowCrypt.xcodeproj/xcshareddata/xcschemes/FlowCryptUITests.xcscheme b/FlowCrypt.xcodeproj/xcshareddata/xcschemes/FlowCryptUITests.xcscheme
index b1302a697..0f443212d 100644
--- a/FlowCrypt.xcodeproj/xcshareddata/xcschemes/FlowCryptUITests.xcscheme
+++ b/FlowCrypt.xcodeproj/xcshareddata/xcschemes/FlowCryptUITests.xcscheme
@@ -44,6 +44,9 @@
reference = "container:FlowCryptUITests/Gmail.xctestplan"
default = "YES">
+
+
[AttContext] in
+ let attachmentContext = messageContexts.flatMap { msgContext -> [AttachmentContext] in
guard let parts = msgContext.msg.attachments() as? [MCOIMAPPart] else { assertionFailure(); return [] }
- return parts.map { part in AttContext(path: msgContext.path, msg: msgContext.msg, part: part) }
+ return parts.map { part in AttachmentContext(path: msgContext.path, msg: msgContext.msg, part: part) }
}
- guard attContext.isNotEmpty else {
- throw BackupError.missedAttributes
+ // in case there are no attachments return empty data
+ guard attachmentContext.isNotEmpty else {
+ return Data()
}
- let dataArr = try attContext.map { attContext -> Data in
- try awaitPromise(self.fetchMsgAttribute(
+ let dataArr = try attachmentContext.map { attContext -> Data in
+ try awaitPromise(self.fetchMsgAttachment(
in: attContext.path,
msgUid: attContext.msg.uid,
part: attContext.part
@@ -77,7 +80,7 @@ extension Imap: BackupProvider {
}
}
- private func fetchMsgAttribute(in folder: String, msgUid: UInt32, part: MCOIMAPPart) -> Promise {
+ private func fetchMsgAttachment(in folder: String, msgUid: UInt32, part: MCOIMAPPart) -> Promise {
Promise { [weak self] resolve, reject in
guard let self = self else { return reject(AppErr.nilSelf) }
self.imapSess?
@@ -88,7 +91,7 @@ extension Imap: BackupProvider {
encoding: part.encoding
)
.start(self.finalize("fetchMsgAtt", resolve, reject, retry: {
- self.fetchMsgAttribute(in: folder, msgUid: msgUid, part: part)
+ self.fetchMsgAttachment(in: folder, msgUid: msgUid, part: part)
}))
}
}
@@ -122,7 +125,7 @@ private struct MsgContext {
let msg: MCOIMAPMessage
}
-private struct AttContext {
+private struct AttachmentContext {
let path: String
let msg: MCOIMAPMessage
let part: MCOIMAPPart
diff --git a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift
index 8f75d74cb..cf5814959 100644
--- a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift
+++ b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift
@@ -17,6 +17,7 @@ extension Imap {
let imapSession = dataService.imapSession(),
let smtpSession = dataService.smtpSession()
else { return }
+ logger.logInfo("Create new imap and smtp session")
createNewConnection(
imapSession: imapSession,
diff --git a/FlowCrypt/Functionality/Mail Provider/MessagesList Provider/Model/MessageLabel.swift b/FlowCrypt/Functionality/Mail Provider/MessagesList Provider/Model/MessageLabel.swift
index 6d803dc8c..5b4b83bdc 100644
--- a/FlowCrypt/Functionality/Mail Provider/MessagesList Provider/Model/MessageLabel.swift
+++ b/FlowCrypt/Functionality/Mail Provider/MessagesList Provider/Model/MessageLabel.swift
@@ -83,7 +83,7 @@ extension MessageLabelType {
case .label("submited"): return MCOMessageFlag.submitted.rawValue
case .none: return 0
default:
- assertionFailure("This label \(self) is not supported by this provider")
+ debugPrint("This label \(self) is not supported by this provider")
return 0
}
}
diff --git a/FlowCryptUI/Cell Nodes/ButtonCellNode.swift b/FlowCryptUI/Cell Nodes/ButtonCellNode.swift
index 346bceba1..beafd7a64 100644
--- a/FlowCryptUI/Cell Nodes/ButtonCellNode.swift
+++ b/FlowCryptUI/Cell Nodes/ButtonCellNode.swift
@@ -13,7 +13,7 @@ public final class ButtonCellNode: CellNode {
let title: NSAttributedString
let insets: UIEdgeInsets
let color: UIColor?
-
+
public init(
title: NSAttributedString,
insets: UIEdgeInsets,
@@ -24,7 +24,7 @@ public final class ButtonCellNode: CellNode {
self.color = color
}
}
-
+
private var onTap: (() -> Void)?
public lazy var button = ButtonNode { [weak self] in
self?.onTap?()
@@ -41,7 +41,7 @@ public final class ButtonCellNode: CellNode {
.withAlphaComponent(alpha)
}
}
-
+
public init(input: Input, action: (() -> Void)?) {
onTap = action
self.insets = input.insets
diff --git a/FlowCryptUI/Cell Nodes/TextCellNode.swift b/FlowCryptUI/Cell Nodes/TextCellNode.swift
index 40c752611..e8574c6fc 100644
--- a/FlowCryptUI/Cell Nodes/TextCellNode.swift
+++ b/FlowCryptUI/Cell Nodes/TextCellNode.swift
@@ -56,7 +56,7 @@ public final class TextCellNode: CellNode {
? [textNode, spinner]
: [textNode]
)
-
+
return spec
}
}
diff --git a/FlowCryptUI/Nodes/AttachmentNode.swift b/FlowCryptUI/Nodes/AttachmentNode.swift
index 2b99d4cc8..4492019c6 100644
--- a/FlowCryptUI/Nodes/AttachmentNode.swift
+++ b/FlowCryptUI/Nodes/AttachmentNode.swift
@@ -15,15 +15,15 @@ public final class AttachmentNode: CellNode {
self.size = size
}
}
-
+
private let titleNode = ASTextNode()
private let subtitleNode = ASTextNode2()
private let imageNode = ASImageNode()
private let buttonNode = ASButtonNode()
private let borderNode = ASDisplayNode()
-
+
private var onDownloadTap: (() -> Void)?
-
+
public init(
input: Input,
onDownloadTap: (() -> Void)?
@@ -38,20 +38,19 @@ public final class AttachmentNode: CellNode {
imageNode.tintColor = .gray
buttonNode.tintColor = .gray
-
+
imageNode.image = UIImage(named: "paperclip")?.tinted(.gray)
buttonNode.setImage(UIImage(named: "download")?.tinted(.gray), for: .normal)
titleNode.attributedText = input.name
subtitleNode.attributedText = input.size
-
+
buttonNode.addTarget(self, action: #selector(onDownloadButtonTap), forControlEvents: .touchUpInside)
-
}
-
+
@objc private func onDownloadButtonTap() {
onDownloadTap?()
}
-
+
public override func layoutSpecThatFits(_: ASSizeRange) -> ASLayoutSpec {
let verticalStack = ASStackLayoutSpec.vertical()
verticalStack.spacing = 3
@@ -59,7 +58,7 @@ public final class AttachmentNode: CellNode {
verticalStack.style.flexGrow = 1.0
verticalStack.children = [titleNode, subtitleNode]
-
+
let finalSpec = ASStackLayoutSpec(
direction: .horizontal,
spacing: 10,
@@ -69,7 +68,7 @@ public final class AttachmentNode: CellNode {
)
let borderInset = UIEdgeInsets.side(8)
-
+
let resultSpec = ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 8 + borderInset.top,
@@ -79,7 +78,7 @@ public final class AttachmentNode: CellNode {
),
child: finalSpec
)
-
+
return ASOverlayLayoutSpec(
child: resultSpec,
overlay: ASInsetLayoutSpec(
diff --git a/FlowCryptUI/Nodes/TableNode.swift b/FlowCryptUI/Nodes/TableNode.swift
index 9c46f56c9..51ec6894d 100644
--- a/FlowCryptUI/Nodes/TableNode.swift
+++ b/FlowCryptUI/Nodes/TableNode.swift
@@ -57,7 +57,7 @@ public extension UIViewController {
width: tableNode.frame.size.width,
height: max(height, 0)
)
-
+
return size
}
}
diff --git a/FlowCryptUI/Nodes/TextFieldNode.swift b/FlowCryptUI/Nodes/TextFieldNode.swift
index c678e2896..2d1b99a71 100644
--- a/FlowCryptUI/Nodes/TextFieldNode.swift
+++ b/FlowCryptUI/Nodes/TextFieldNode.swift
@@ -121,7 +121,7 @@ public final class TextFieldNode: ASDisplayNode {
private var textFiledAction: TextFieldAction?
private var onToolbarDoneAction: (() -> Void)?
-
+
public init(preferredHeight: CGFloat?, action: TextFieldAction? = nil, accessibilityIdentifier: String?) {
super.init()
addSubnode(node)
diff --git a/FlowCryptUI/Views/NavigationBarActionButton.swift b/FlowCryptUI/Views/NavigationBarActionButton.swift
index 6e8bdc959..5e67af80a 100644
--- a/FlowCryptUI/Views/NavigationBarActionButton.swift
+++ b/FlowCryptUI/Views/NavigationBarActionButton.swift
@@ -15,13 +15,14 @@ public final class NavigationBarActionButton: UIBarButtonItem {
private var onAction: (() -> Void)?
- public convenience init(_ image: UIImage?, action: (() -> Void)?) {
+ public convenience init(_ image: UIImage?, action: (() -> Void)?, accessibilityIdentifier: String? = nil) {
self.init()
onAction = action
customView = LeftAlignedIconButton(type: .system).with {
$0.setImage(image, for: .normal)
$0.frame.size = Constants.buttonSize
$0.addTarget(self, action: #selector(tap), for: .touchUpInside)
+ $0.accessibilityIdentifier = accessibilityIdentifier
}
}
diff --git a/FlowCryptUI/Views/NavigationBarItemsView.swift b/FlowCryptUI/Views/NavigationBarItemsView.swift
index 6e50300c4..d2bf89a77 100644
--- a/FlowCryptUI/Views/NavigationBarItemsView.swift
+++ b/FlowCryptUI/Views/NavigationBarItemsView.swift
@@ -56,7 +56,7 @@ public final class NavigationBarItemsView: UIBarButtonItem {
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
-
+
public override var isEnabled: Bool {
didSet {
customView?.alpha = isEnabled ? 1 : 0.5
diff --git a/FlowCryptUITests/Resources/AppTestHelper.swift b/FlowCryptUITests/AppTestHelper.swift
similarity index 86%
rename from FlowCryptUITests/Resources/AppTestHelper.swift
rename to FlowCryptUITests/AppTestHelper.swift
index ce5852c73..e5d749e4d 100644
--- a/FlowCryptUITests/Resources/AppTestHelper.swift
+++ b/FlowCryptUITests/AppTestHelper.swift
@@ -6,8 +6,8 @@
// Copyright © 2020 FlowCrypt Limited. All rights reserved.
//
-import XCTest
import FlowCryptCommon
+import XCTest
protocol AppTest {
var app: XCUIApplication! { get set }
@@ -44,6 +44,14 @@ extension AppTest {
var passPhraseTextField: XCUIElement {
app.tables.secureTextFields["Enter your pass phrase"]
}
+
+ var navigationBackButton: XCUIElement {
+ app.navigationBars.buttons["arrow left c"]
+ }
+
+ var setupUseAnotherAccount: XCUIElement {
+ app.tables.buttons["Use Another Account"]
+ }
}
// MARK: - Actions
@@ -64,15 +72,12 @@ extension AppTest {
}
func tapOnCompose() {
- let plusButton = app.buttons["tap"]
+ let plusButton = app.buttons["+"]
if plusButton.exists {
plusButton.tap()
} else {
- // for iPhone X
- XCUIDevice.shared.orientation = .landscapeLeft
- app.buttons["+"].tap()
- XCUIDevice.shared.orientation = .portrait
+ logger.logError("+ does not exist")
}
wait(0.2)
}
@@ -95,21 +100,17 @@ extension AppTest {
_ = app.keys["\n"]
}
}
-
+
func logOutIfNeeded() {
logger.logInfo("Log out if needed")
-
- // Check which screen we are now
- guard menuButton.exists else {
- logger.logInfo("Already logged out")
- return
- }
-
+
if menuButton.exists {
logger.logInfo("User is logged in. Try to log out")
menuButton.tap()
tapOnMenu(folder: "Log out")
} else {
+ logger.logInfo("No menu button")
+
let otherAccountButton = app.tables.buttons["Use Another Account"]
if otherAccountButton.exists {
logger.logInfo("Try to use another account")
diff --git a/FlowCryptUITests/Resources/UserCredentials.swift b/FlowCryptUITests/Resources/UserCredentials.swift
index 0d04bd6e2..1ca2985ce 100644
--- a/FlowCryptUITests/Resources/UserCredentials.swift
+++ b/FlowCryptUITests/Resources/UserCredentials.swift
@@ -18,11 +18,23 @@ struct UserCredentials: Codable, Equatable {
static var empty = UserCredentials(email: "", password: "", pass: "", recovery: "", privateKey: "")
/// ci.tests.gmail@flowcrypt.dev
+ /// default Gmail account
static var gmailDev: UserCredentials = .user(with: "ci.tests.gmail@flowcrypt.dev")
-
+
/// default@flowcrypt.test
- static var imapDev: UserCredentials = .user(with: "default@flowcrypt.test")
-
+ /// default IMAP/SMTP account
+ static let imapDev = UserCredentials.user(with: "default@flowcrypt.test")
+
+ /// den@flowcrypt.test
+ /// user without messages
+ static let imapDen = UserCredentials.user(with: "den@flowcrypt.test")
+
+ /// has_msgs_no_backups@flowcrypt.test
+ /// user with messages but without any backups
+ static let imapHasMessagesNoBackups = UserCredentials.user(with: "has_msgs_no_backups@flowcrypt.test")
+}
+
+extension UserCredentials {
static func user(with email: String) -> UserCredentials {
Credentials.default
.users
diff --git a/FlowCryptUITests/SignInGoogleTest.swift b/FlowCryptUITests/SignInGoogleTest.swift
index 8887eb4ee..f99cbecf0 100644
--- a/FlowCryptUITests/SignInGoogleTest.swift
+++ b/FlowCryptUITests/SignInGoogleTest.swift
@@ -6,8 +6,8 @@
// Copyright © 2020 FlowCrypt Limited. All rights reserved.
//
-import XCTest
import FlowCryptCommon
+import XCTest
class SignInGoogleTest: XCTestCase, AppTest {
var app: XCUIApplication!
@@ -19,7 +19,7 @@ class SignInGoogleTest: XCTestCase, AppTest {
.setupRegion()
.build()
.launched()
-
+
logger.logInfo("Wait for launch")
wait(10)
}
@@ -27,47 +27,47 @@ class SignInGoogleTest: XCTestCase, AppTest {
private var gmailAlert: XCUIElement {
Springboard.springboard.alerts.element
}
-
+
private var gmailLoginButton: XCUIElement {
app.tables.buttons["Continue with Gmail"]
}
-
+
private var findTextFieldForGmailWebView: XCUIElement? {
logger.logInfo("Try to find text field for gmail web view")
return app.webViews.textFields.firstMatch
}
-
+
func test_1_successful_login() {
logOutIfNeeded()
wait(2)
startGmailLoginFlow()
wait(5)
-
+
let user = UserCredentials.gmailDev
-
+
enterUserCredentials(for: user)
wait(5)
enterUserDevCredentials(for: user)
wait(5)
}
-
+
private func startGmailLoginFlow() {
// Tap on Gmail login
gmailLoginButton.tap()
wait(5)
-
+
// Wait for user alert and continue
guard gmailAlert.exists else {
assertionFailure("Gmail alert is missing")
return
}
-
+
logger.logInfo("Gmail alert is on the screen")
-
+
gmailAlert.buttons["Continue"].tap()
wait(3)
}
-
+
private func enterUserCredentials(for user: UserCredentials) {
// Try to find first text field in gmail web view
logger.logInfo("Try to find text field for gmail web view")
@@ -78,21 +78,21 @@ class SignInGoogleTest: XCTestCase, AppTest {
}
textField.tap()
wait(0.2)
-
+
textField.typeText(user.email)
goKeyboardButton.tap()
}
-
+
private func enterUserDevCredentials(for user: UserCredentials) {
let mainWebView = app.webViews.otherElements["main"]
-
+
let userNameTextField = mainWebView.children(matching: .textField).element
userNameTextField.tap()
userNameTextField.typeText(user.email)
-
+
app.toolbars.matching(identifier: "Toolbar").buttons["Next"].tap()
app.typeText(user.password)
-
+
wait(2)
goKeyboardButton.tap()
wait(3)
diff --git a/FlowCryptUITests/SignInImapTest.swift b/FlowCryptUITests/SignInImapTest.swift
index 11b8f8a64..adbd2829f 100644
--- a/FlowCryptUITests/SignInImapTest.swift
+++ b/FlowCryptUITests/SignInImapTest.swift
@@ -6,43 +6,313 @@
// Copyright © 2019 FlowCrypt Limited. All rights reserved.
//
-import XCTest
import FlowCryptCommon
+import XCTest
/// make ui_tests_imap
class SignInImapTest: XCTestCase, AppTest {
var app: XCUIApplication!
-
+
override func setUp() {
continueAfterFailure = false
-
+
logger.logInfo("Start App")
-
+
app = XCUIApplicationBuilder()
.setupRegion()
.build()
.addSnapshot()
.launched()
-
+
logger.logInfo("Wait for launch")
wait(10)
}
-}
-// MARK: - Tests
-extension SignInImapTest {
// login -> approve -> backups found -> enter pass phrase -> main flow
func test_1_successful_login_imap() {
let user = UserCredentials.imapDev
loginWithImap(user)
-
+
passPhraseTextField.tap()
passPhraseTextField.typeText(user.pass)
goKeyboardButton.tap()
-
+
wait(4)
XCTAssert(app.buttons["+"].exists)
}
+
+ // restart app -> loads inbox
+ func test_2_restart_load_inbox() {
+ let application = XCUIApplication()
+ wait(2)
+ application.buttons["+"].tap()
+
+ wait(0.3)
+
+ application.typeText("test@test.com")
+ application.tables.textFields["Subject"].tap()
+ wait(3)
+ application.tables.textFields["Subject"].tap()
+
+ application.typeText("ios")
+
+ snapshot("compose")
+ navigationBackButton.tap()
+ wait(1)
+
+ tapOnCell()
+ snapshot("message")
+ navigationBackButton.tap()
+
+ wait(1)
+
+ menuButton.tap()
+ snapshot("menu")
+
+ tapOnMenu(folder: "Settings")
+ snapshot("settings")
+ }
+
+ // restart app -> loads inbox -> verify messages
+ func test_3_restart_contains_emails() {
+ let app = XCUIApplication()
+
+ let tablesQuery = app.tables
+ let cellsQuery = tablesQuery.cells
+
+ // open first message
+ cellsQuery.otherElements.containing(.staticText, identifier:"Jun 07").staticTexts["denbond7@flowcrypt.test"].tap()
+ navigationBackButton.tap()
+
+ // message > 5mb
+ cellsQuery.otherElements.containing(.staticText, identifier:"...").staticTexts["denbond7@flowcrypt.test"].tap()
+ wait(0.5)
+
+ cellsQuery.otherElements.containing(.staticText, identifier:"encrypted message with missing key error").staticTexts["denbond7@flowcrypt.test"].tap()
+ tablesQuery.textViews.textViews["Could not decrypt:"].tap()
+ navigationBackButton.tap()
+
+ // open 3d message
+ cellsQuery.otherElements.containing(.staticText, identifier:"Simple encrypted message").staticTexts["denbond7@flowcrypt.test"].tap()
+ let textView = tablesQuery.children(matching: .cell)
+ .element(boundBy: 2)
+ .children(matching: .other)
+ .element
+ .children(matching: .other)
+ .element
+ .children(matching: .textView)
+ .element
+ textView.children(matching: .textView)["Simple encrypted text"].tap()
+ navigationBackButton.tap()
+
+ // open 4th message
+ cellsQuery.otherElements.containing(.staticText, identifier:"Simple encrypted message + pub key").staticTexts["denbond7@flowcrypt.test"].tap()
+ textView.children(matching: .textView)["It's an encrypted message with my pub key"].tap()
+ navigationBackButton.tap()
+
+ // open message with attachment
+ cellsQuery.otherElements.containing(.staticText, identifier:"Simple encrypted message + attachment").staticTexts["denbond7@flowcrypt.test"].tap()
+ tablesQuery.staticTexts["android.png.pgp"].tap()
+ wait(1)
+ cellsQuery.otherElements.containing(.staticText, identifier:"denbond7@flowcrypt.test").children(matching: .button).element.tap()
+ navigationBackButton.tap()
+
+ tablesQuery.staticTexts["Simple encrypted message + attachment"].tap()
+ textView.children(matching: .textView)["It's an encrypted message with one encrypted attachment."].tap()
+ }
+
+ // restart app -> search functionality
+ func test_4_restart_search() {
+ // search
+ let inboxNavigationBar = app.navigationBars["Inbox"]
+ let searchButton = inboxNavigationBar.buttons["search icn"]
+ let tablesQuery = app.tables
+
+ searchButton.tap()
+
+ let searchNavigationBar = app.navigationBars["Search"]
+ let searchTextField = searchNavigationBar.searchFields["Search"]
+
+ searchTextField.tap()
+ wait(1)
+ searchTextField.typeText("search")
+
+ // Verify result with "search"
+ let denBondMessage = tablesQuery.staticTexts["denbond7@flowcrypt.test"]
+ denBondMessage.tap()
+ // Search in subject
+ tablesQuery.staticTexts["Search"].tap()
+ let textView = tablesQuery.children(matching: .cell).element(boundBy: 2).children(matching: .other).element.children(matching: .other).element.children(matching: .textView).element
+ // body
+ textView.children(matching: .textView)["Search in the body"].tap()
+ // email in recipient
+ denBondMessage.tap()
+ // go back to search controller
+ navigationBackButton.tap()
+ searchTextField.tap()
+
+ // clear previous result
+ let clearTextButton = searchTextField.buttons["Clear text"]
+ clearTextButton.tap()
+
+ // ESPRESSO
+ searchTextField.tap()
+ searchTextField.typeText("espresso")
+
+ let espresso = tablesQuery.staticTexts["'espresso' in a subject"]
+ espresso.tap()
+ espresso.tap()
+ textView.children(matching: .textView)["Some text"].tap()
+ navigationBackButton.tap()
+
+ let cellsQuery = tablesQuery.cells
+ cellsQuery.otherElements.containing(.staticText, identifier:"Message").staticTexts["denbond7@flowcrypt.test"].tap()
+ tablesQuery.staticTexts["Message"].tap()
+ textView.children(matching: .textView)["The message with 'espresso' in a body"].tap()
+ navigationBackButton.tap()
+ clearTextButton.tap()
+
+ // ANDROID
+ searchTextField.tap()
+ searchTextField.typeText("android")
+ cellsQuery.otherElements.containing(.staticText, identifier:"Standard message + one attachment").staticTexts["denbond7@flowcrypt.test"].tap()
+ navigationBackButton.tap()
+ cellsQuery.otherElements.containing(.staticText, identifier:"With android in subject").staticTexts["denbond7@flowcrypt.test"].tap()
+ navigationBackButton.tap()
+ cellsQuery.otherElements.containing(.staticText, identifier:"with that text in body").staticTexts["denbond7@flowcrypt.test"].tap()
+ navigationBackButton.tap()
+ cellsQuery.otherElements.containing(.staticText, identifier:"Honor reply-to address").staticTexts["denbond7@flowcrypt.test"].tap()
+ navigationBackButton.tap()
+ cellsQuery.otherElements.containing(.staticText, identifier:"Simple encrypted message + attachment").staticTexts["denbond7@flowcrypt.test"].tap()
+ navigationBackButton.tap()
+ app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element(boundBy: 0).children(matching: .other).element.children(matching: .table).element.tap()
+ navigationBackButton.tap()
+ }
+
+ func test_5_restart_folders() {
+ let app = XCUIApplication()
+ let tablesQuery = app.tables
+
+ let menuButton = app.navigationBars["Inbox"].buttons["menu icn"]
+ menuButton.tap()
+ wait(1)
+ tablesQuery.cells.otherElements.containing(.staticText, identifier:"...").staticTexts["denbond7@flowcrypt.test"].tap()
+ menuButton.tap()
+
+ tablesQuery.staticTexts["Junk"].tap()
+ tablesQuery.staticTexts["Junk is empty"].tap()
+ app.navigationBars["Junk"].buttons["menu icn"].tap()
+
+ tablesQuery.staticTexts["Drafts"].tap()
+ tablesQuery.staticTexts["Drafts is empty"].tap()
+ app.navigationBars["Drafts"].buttons["menu icn"].tap()
+
+ tablesQuery.staticTexts["Trash"].tap()
+ tablesQuery.staticTexts["Standard message - plaintext"].tap()
+ navigationBackButton.tap()
+ app.navigationBars["Trash"].buttons["menu icn"].tap()
+
+ tablesQuery.staticTexts["Sent"].tap()
+ tablesQuery.staticTexts["Sent is empty"].tap()
+ app.navigationBars["Sent"].buttons["menu icn"].tap()
+
+ tablesQuery.staticTexts["Inbox"].tap()
+ menuButton.tap()
+ }
+
+ func test_6_restart_settings() {
+ let app = XCUIApplication()
+ let tablesQuery = app.tables
+
+ menuButton.tap()
+ wait(1)
+
+ tablesQuery.staticTexts["Settings"].tap()
+ tablesQuery.staticTexts["Backups"].tap()
+ tablesQuery.staticTexts["Security and Privacy"].tap()
+ tablesQuery.staticTexts["Contacts"].tap()
+
+ app.navigationBars["Contacts"].staticTexts["Contacts"].tap()
+ navigationBackButton.tap()
+
+ tablesQuery.staticTexts["Keys"].tap()
+ wait(1)
+ tablesQuery.cells.firstMatch.tap()
+ tablesQuery.buttons["Show public key"].tap()
+
+ // part of public key
+ let searchText = "nxjMEYIq7phYJKwYBBAHaRw8BAQdAat45rrh"
+ let predicate = NSPredicate(format: "label CONTAINS[c] %@", searchText)
+ tablesQuery.containing(predicate)
+
+ navigationBackButton.tap()
+
+ tablesQuery.buttons["Show key details"].tap()
+ tablesQuery.staticTexts["Longid: 225F8023C20D0957"].tap()
+ tablesQuery.staticTexts["Longid: 4F1458BD22B7BB53"].tap()
+
+ navigationBackButton.tap()
+ tablesQuery.buttons["Copy to clipboard"].tap()
+ tablesQuery.buttons["Share"].tap()
+ app.navigationBars["UIActivityContentView"].buttons["Close"].tap()
+ tablesQuery.buttons["Show private key"].tap()
+
+ navigationBackButton.tap()
+
+ app.navigationBars["Keys"].buttons["Add"].tap()
+ XCTAssert(tablesQuery.buttons["Load From File"].exists)
+ navigationBackButton.tap()
+ navigationBackButton.tap()
+
+ tablesQuery.staticTexts["Notifications"].tap()
+ tablesQuery.staticTexts["Legal"].tap()
+
+ let collectionViewsQuery = app.collectionViews
+ collectionViewsQuery.staticTexts["Terms"].tap()
+ collectionViewsQuery.staticTexts["License"].tap()
+ collectionViewsQuery.staticTexts["Sources"].tap()
+ app.navigationBars["Legal"].buttons["arrow left c"].tap()
+ tablesQuery.staticTexts["Experimental"].tap()
+ }
+
+ // login -> cancel
+ func test_7_login_cancel() {
+ let user = UserCredentials.imapDev
+ loginWithImap(user)
+
+ passPhraseTextField.swipeUp()
+ tapUseAnotherAccountAndVerify()
+ }
+
+ // login with user without key backups and emails
+ // login -> no messages
+ func test_8_login_no_messages() {
+ verifyFlowWithNoBackups(for: .imapDen)
+ }
+
+ func test_9_has_msgs_no_backups() {
+ verifyFlowWithNoBackups(for: .imapHasMessagesNoBackups)
+ }
+
+ // login with wrong pass phrase
+ func test_10_login_bad_pass_phrase() {
+ let user = UserCredentials.imapDev
+ loginWithImap(user)
+
+ let tablesQuery = app.tables
+ XCTAssert(tablesQuery.staticTexts["Remember pass phrase temporarily"].exists)
+
+ passPhraseTextField.typeText(user.pass + "wrong")
+ tapOnGoButton()
+ wait(2)
+
+ let errorAlert = app.alerts["Error"]
+ XCTAssert(errorAlert.exists, "Error alert is missing after entering wrong pass phrase")
+ XCTAssert(errorAlert.scrollViews.otherElements.staticTexts["Wrong pass phrase, please try again"].exists)
+ errorAlert.scrollViews.otherElements.buttons["OK"].tap()
+ wait(0.2)
+ app.tables.buttons["Use Another Account"].tap()
+ }
}
// MARK: - Convenience
@@ -50,78 +320,102 @@ extension SignInImapTest {
private var toolbarDoneButton: XCUIElement {
app.toolbars["Toolbar"].buttons["Done"]
}
-
+
private func loginWithImap(_ user: UserCredentials) {
logger.logInfo("Login with \(user.email)")
-
+
// other account
logOutIfNeeded()
wait(0.3)
-
+
logger.logInfo("Use other email provider")
let otherEmailButton = app.tables.buttons["Other email provider"]
otherEmailButton.tap()
-
+
logger.logInfo("Fill all user credentials")
-
+
// email
let emailTextField = app.tables.textFields["Email"]
emailTextField.tap()
emailTextField.typeText(user.email)
wait(1)
-
+
// move focus to username
goKeyboardButton.tap()
wait(1)
-
+
// move focus to password
goKeyboardButton.tap()
app.typeText(user.password)
-
+
// move focus to imap server (filled)
goKeyboardButton.tap()
-
+
// move focus to imap port
goKeyboardButton.tap()
-
+
// move focus to imap security type. Set none
toolbarDoneButton.tap()
app.pickerWheels["none"].tap()
toolbarDoneButton.tap()
-
+
// move to smtp type
let smtpType = app.tables.textFields["SMTP type"]
smtpType.tap()
app.pickerWheels["none"].tap()
toolbarDoneButton.tap()
-
+
app.tables.buttons["Connect"].tap()
-
+
logger.logInfo("Try to connect")
wait(10)
}
+
+ private func verifyFlowWithNoBackups(for user: UserCredentials) {
+ loginWithImap(user)
+
+ let tablesQuery = app.tables
+
+ let noBackupsLabel = tablesQuery.staticTexts["No backups found on account: \n\(user.email)"]
+ let importMyKeyButton = tablesQuery.buttons["Import my key"]
+ let createNewKeyButton = tablesQuery.buttons["Create a new key"]
+
+ XCTAssert(noBackupsLabel.exists)
+ XCTAssert(importMyKeyButton.exists)
+ XCTAssert(createNewKeyButton.exists)
+ XCTAssert(setupUseAnotherAccount.exists)
+
+ importMyKeyButton.tap()
+ navigationBackButton.tap()
+
+ createNewKeyButton.tap()
+ navigationBackButton.tap()
+
+ importMyKeyButton.tap()
+
+ let loadFromFileButton = tablesQuery.buttons["Load From File"]
+ XCTAssert(loadFromFileButton.exists)
+
+ let loadFromClipboard = tablesQuery.buttons["Load From Clipboard"]
+ XCTAssert(loadFromClipboard.exists)
+ navigationBackButton.tap()
+
+ XCTAssert(noBackupsLabel.exists)
+
+ tapUseAnotherAccountAndVerify()
+ }
+
+ private func tapUseAnotherAccountAndVerify() {
+ setupUseAnotherAccount.tap()
+
+ wait(1)
+ XCTAssert(app.tables.buttons["Other email provider"].exists)
+ }
}
-//extension SignInImapTest {
-// // log in -> approve -> no backups -> switch email
-// func test_1_login_no_backups() {
-// // login with user without key backup
-//
-// login(UserCredentials.noKeyBackUp)
-//
-// // retry
-// let buttons = app.alerts.scrollViews.otherElements.buttons
-// buttons["Retry"].tap()
-// wait(1)
-//
-// // switch to a new account
-// buttons["Use other account"].tap()
-// wait(2)
-//
-// // login
-// test_6_login_good_pass()
-// }
-//
+// Currently disabled tests
+// UI tests which can make changes on remote server are currently disabled
+
// func test_2_login_no_backups_generate() {
// // log in -> approve -> no backups -> generate pubkey -> weak pass phrase
// login(UserCredentials.noKeyBackUp)
@@ -188,90 +482,7 @@ extension SignInImapTest {
// }
// }
//
-// // log in -> cancel for gmail
-// func test_3_login_cancel_gmail() {
-// logOutIfNeeded()
-// snapshot("splash")
-//
-// app.tables.buttons["gmail"].tap()
-// wait(1)
-//
-// snapshot("auth")
-// }
-//
-// // log in -> cancel
-// func test_4_login_cancel() {
-// login(user)
-//
-// let useAnotherAccountButton = app.tables.buttons["Use Another Account"]
-// useAnotherAccountButton.tap()
-//
-// wait(1)
-// XCTAssert(app.tables.buttons["Other email provider"].exists)
-// }
-//
-// // log in -> approve -> bad pass phrase
-// func test_5_login_bad_pass() {
-// login(user)
-//
-// passPhraseTextField.tap()
-// passPhraseTextField.typeText(user.pass + "wrong")
-// tapOnGoButton()
-//
-// wait(0.2)
-// let errorAlert = app.alerts["Error"]
-// XCTAssert(errorAlert.exists, "Error alert is missing after entering wrong pass phrase")
-// errorAlert.scrollViews.otherElements.buttons["OK"].tap()
-// wait(0.2)
-//
-// app.tables.buttons["Use Another Account"].tap()
-// }
-//
-// // log in -> approve -> loaded 1 backup -> good pass phrase -> inbox
-// func test_6_login_good_pass() {
-// login(user)
-//
-// passPhraseTextField.tap()
-// passPhraseTextField.typeText(user.pass)
-//
-// snapshot("recover")
-// tapOnGoButton()
-//
-// wait(1)
-// XCTAssert(app.navigationBars["Inbox"].exists, "Could not login")
-// }
-//
-// // restart app -> loads inbox
-// func test_7_restart_app_load_inbox() {
-// wait(1)
-// XCTAssert(app.navigationBars["Inbox"].exists, "Inbox is not found after restarting the app")
-// snapshot("inbox")
-//
-// tapOnCompose()
-// wait(0.3)
-//
-// app.typeText("ElonMusk@gmail.com")
-// app.tables.textFields["Subject"].tap()
-//
-// app.tables.textFields["Subject"].tap()
-// app.typeText("SpaceX")
-//
-// snapshot("compose")
-// app.navigationBars.buttons["arrow left c"].tap()
-// wait(1)
-//
-// tapOnCell()
-// snapshot("message")
-// app.navigationBars.buttons["arrow left c"].tap()
-//
-// wait(1)
-//
-// menuButton.tap()
-// snapshot("menu")
-//
-// tapOnMenu(folder: "Settings")
-// snapshot("settings")
-// }
+
//
// // send new msg -> inbox -> switch to sent -> open sent msg and verify content, recipient, subject
// func test_8_send_message() {
@@ -315,7 +526,7 @@ extension SignInImapTest {
//
// tapOnCell()
// let buttons = app.navigationBars.buttons
-// let backButton = buttons["arrow left c"]
+// let backButton = navigationBackButton
//
// wait(3)
// // Verify buttons in Trash folder
@@ -358,7 +569,3 @@ extension SignInImapTest {
// XCTAssert(errorAlert.exists)
// }
//}
-
-/*
- log in -> approve -> no backups -> generate pubkey -> switch accounts
- */
diff --git a/FlowCryptUITests/TestCredentials.swift b/FlowCryptUITests/TestCredentials.swift
index 9a716b012..ed340114c 100644
--- a/FlowCryptUITests/TestCredentials.swift
+++ b/FlowCryptUITests/TestCredentials.swift
@@ -6,8 +6,8 @@
// Copyright © 2020 FlowCrypt Limited. All rights reserved.
//
-import XCTest
import FlowCryptCommon
+import XCTest
public let logger = Logger.nested("UI Tests")
diff --git a/Scripts/format.sh b/Scripts/format.sh
index 6c64824c0..70d38b478 100755
--- a/Scripts/format.sh
+++ b/Scripts/format.sh
@@ -13,7 +13,7 @@ fi
if which swiftformat >/dev/null; then
echo "Start formatting"
# swiftlint autocorrect --path .
- swiftformat "FlowCrypt" \
+ swiftformat "FlowCrypt", "FlowCryptUITests" \
--rules trailingSpace \
--rules blankLinesAtEndOfScope \
--rules consecutiveBlankLines \