Skip to content
2 changes: 1 addition & 1 deletion FlowCrypt.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,6 @@
isa = PBXGroup;
children = (
D2F18469244DB8F6000CC5D1 /* SnapshotHelper.swift */,
D2F18467244B0F35000CC5D1 /* AppTestHelper.swift */,
9FDF3651235A1EDE00614596 /* XCUIApplicationBuilder.swift */,
9FDF364F235A1D3F00614596 /* UITestHelper.swift */,
9F228BA523C673AD005D2CB6 /* Springboard.swift */,
Expand Down Expand Up @@ -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 */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
reference = "container:FlowCryptUITests/Gmail.xctestplan"
default = "YES">
</TestPlanReference>
<TestPlanReference
reference = "container:FlowCryptUITests/Imap.xctestplan">
</TestPlanReference>
</TestPlans>
<Testables>
<TestableReference
Expand Down
5 changes: 0 additions & 5 deletions FlowCrypt/Controllers/Setup/SetupEKMKeyViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ final class SetupEKMKeyViewController: SetupCreatePassphraseAbstractViewControll
self.shouldStorePassPhrase = false
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
setupUI()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ final class SetupGenerateKeyViewController: SetupCreatePassphraseAbstractViewCon
)
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
setupUI()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ extension SideMenuNavigationController: UINavigationControllerDelegate {
let navigationButton: UIBarButtonItem
switch viewControllers.firstIndex(of: viewController) {
case 0:
navigationButton = NavigationBarActionButton(UIImage(named: "menu_icn"), action: nil)
navigationButton = NavigationBarActionButton(UIImage(named: "menu_icn"), action: nil, accessibilityIdentifier: "menu")
default:
navigationButton = NavigationBarActionButton(UIImage(named: "arrow-left-c"), action: nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,24 @@ extension Imap: BackupProvider {
return msgs.map { msg in MsgContext(path: uidsContext.path, msg: msg) }
}

// in case there are no messages return empty data
// user will be prompted to create new backup
guard messageContexts.isNotEmpty else {
throw BackupError.missedMessages
return Data()
}

let attContext = messageContexts.flatMap { msgContext -> [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
Expand All @@ -77,7 +80,7 @@ extension Imap: BackupProvider {
}
}

private func fetchMsgAttribute(in folder: String, msgUid: UInt32, part: MCOIMAPPart) -> Promise<Data> {
private func fetchMsgAttachment(in folder: String, msgUid: UInt32, part: MCOIMAPPart) -> Promise<Data> {
Promise<Data> { [weak self] resolve, reject in
guard let self = self else { return reject(AppErr.nilSelf) }
self.imapSess?
Expand All @@ -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)
}))
}
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
6 changes: 3 additions & 3 deletions FlowCryptUI/Cell Nodes/ButtonCellNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public final class ButtonCellNode: CellNode {
let title: NSAttributedString
let insets: UIEdgeInsets
let color: UIColor?

public init(
title: NSAttributedString,
insets: UIEdgeInsets,
Expand All @@ -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?()
Expand All @@ -41,7 +41,7 @@ public final class ButtonCellNode: CellNode {
.withAlphaComponent(alpha)
}
}

public init(input: Input, action: (() -> Void)?) {
onTap = action
self.insets = input.insets
Expand Down
2 changes: 1 addition & 1 deletion FlowCryptUI/Cell Nodes/TextCellNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public final class TextCellNode: CellNode {
? [textNode, spinner]
: [textNode]
)

return spec
}
}
Expand Down
21 changes: 10 additions & 11 deletions FlowCryptUI/Nodes/AttachmentNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)?
Expand All @@ -38,28 +38,27 @@ 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
verticalStack.style.flexShrink = 1.0
verticalStack.style.flexGrow = 1.0

verticalStack.children = [titleNode, subtitleNode]

let finalSpec = ASStackLayoutSpec(
direction: .horizontal,
spacing: 10,
Expand All @@ -69,7 +68,7 @@ public final class AttachmentNode: CellNode {
)

let borderInset = UIEdgeInsets.side(8)

let resultSpec = ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 8 + borderInset.top,
Expand All @@ -79,7 +78,7 @@ public final class AttachmentNode: CellNode {
),
child: finalSpec
)

return ASOverlayLayoutSpec(
child: resultSpec,
overlay: ASInsetLayoutSpec(
Expand Down
2 changes: 1 addition & 1 deletion FlowCryptUI/Nodes/TableNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public extension UIViewController {
width: tableNode.frame.size.width,
height: max(height, 0)
)

return size
}
}
2 changes: 1 addition & 1 deletion FlowCryptUI/Nodes/TextFieldNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion FlowCryptUI/Views/NavigationBarActionButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
2 changes: 1 addition & 1 deletion FlowCryptUI/Views/NavigationBarItemsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
// Copyright © 2020 FlowCrypt Limited. All rights reserved.
//

import XCTest
import FlowCryptCommon
import XCTest

protocol AppTest {
var app: XCUIApplication! { get set }
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand All @@ -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")
Expand Down
18 changes: 15 additions & 3 deletions FlowCryptUITests/Resources/UserCredentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading