Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ final class AttachmentViewController: UIViewController {
NavigationBarItemsView.Input(
image: UIImage(named: "download")?.tinted(.gray),
title: "save".localized,
accessibilityId: "aid-save-attachment-to-device",
onTap: { [weak self] in self?.downloadAttachment() }
)
]
Expand Down
27 changes: 15 additions & 12 deletions FlowCrypt/Controllers/Compose/ComposeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,18 +280,21 @@ extension ComposeViewController {
navigationItem.rightBarButtonItem = NavigationBarItemsView(
with: [
NavigationBarItemsView.Input(
image: UIImage(named: "help_icn"),
action: (self, #selector(handleInfoTap))
),
image: UIImage(named: "help_icn")
) { [weak self] in
self?.handleInfoTap()
},
NavigationBarItemsView.Input(
image: UIImage(named: "paperclip"),
action: (self, #selector(handleAttachTap))
),
image: UIImage(named: "paperclip")
) { [weak self] in
self?.handleAttachTap()
},
NavigationBarItemsView.Input(
image: UIImage(named: "android-send"),
action: (self, #selector(handleSendTap)),
accessibilityLabel: "send"
)
accessibilityId: "aid-compose-send"
) { [weak self] in
self?.handleSendTap()
}
]
)
}
Expand Down Expand Up @@ -386,15 +389,15 @@ extension ComposeViewController {
// MARK: - Handle actions

extension ComposeViewController {
@objc private func handleInfoTap() {
private func handleInfoTap() {
showToast("Please email us at human@flowcrypt.com for help")
}

@objc private func handleAttachTap() {
private func handleAttachTap() {
openAttachmentsInputSourcesSheet()
}

@objc private func handleSendTap() {
private func handleSendTap() {
Task {
do {
let key = try await prepareSigningKey()
Expand Down
8 changes: 4 additions & 4 deletions FlowCrypt/Controllers/Inbox/InboxViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ extension InboxViewController {
private func setupNavigationBar() {
navigationItem.rightBarButtonItem = NavigationBarItemsView(
with: [
NavigationBarItemsView.Input(image: UIImage(named: "help_icn"), action: (self, #selector(handleInfoTap))),
NavigationBarItemsView.Input(image: UIImage(named: "search_icn"), action: (self, #selector(handleSearchTap)))
NavigationBarItemsView.Input(image: UIImage(named: "help_icn")) { [weak self] in self?.handleInfoTap() },
NavigationBarItemsView.Input(image: UIImage(named: "search_icn")) { [weak self] in self?.handleSearchTap() }
]
)
}
Expand Down Expand Up @@ -317,12 +317,12 @@ extension InboxViewController {

// MARK: - Action handlers
extension InboxViewController {
@objc private func handleInfoTap() {
private func handleInfoTap() {
#warning("ToDo")
showToast("Email us at human@flowcrypt.com")
}

@objc private func handleSearchTap() {
private func handleSearchTap() {
let viewController = SearchViewController(appContext: appContext, folderPath: viewModel.path)
navigationController?.pushViewController(viewController, animated: false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ final class ContactDetailViewController: TableNodeViewController {
private func setupNavigationBarItems() {
navigationItem.rightBarButtonItem = NavigationBarItemsView(
with: [
.init(image: UIImage(systemName: "trash"), action: (self, #selector(handleRemoveAction)))
.init(image: UIImage(systemName: "trash")) { [weak self] in self?.handleRemoveAction() }
]
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,29 @@ final class ContactKeyDetailViewController: TableNodeViewController {
private func setupNavigationBarItems() {
navigationItem.rightBarButtonItem = NavigationBarItemsView(
with: [
.init(image: UIImage(named: "share"), action: (self, #selector(handleSaveAction))),
.init(image: UIImage(named: "copy"), action: (self, #selector(handleCopyAction))),
.init(image: UIImage(systemName: "trash"), action: (self, #selector(handleRemoveAction)))
.init(image: UIImage(named: "share")) { [weak self] in self?.handleSaveAction() },
.init(image: UIImage(named: "copy")) { [weak self] in self?.handleCopyAction() },
.init(image: UIImage(systemName: "trash")) { [weak self] in self?.handleRemoveAction() }
]
)
}
}

extension ContactKeyDetailViewController {
@objc private final func handleSaveAction() {
private final func handleSaveAction() {
let vc = UIActivityViewController(
activityItems: [pubKey.armored],
applicationActivities: nil
)
present(vc, animated: true, completion: nil)
}

@objc private final func handleCopyAction() {
private final func handleCopyAction() {
UIPasteboard.general.string = pubKey.armored
showToast("contact_detail_copy".localized)
}

@objc private final func handleRemoveAction() {
private final func handleRemoveAction() {
navigationController?.popViewController(animated: true) { [weak self] in
guard let self = self else { return }
self.action?(.delete(self.pubKey))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ extension SideMenuNavigationController: UINavigationControllerDelegate {
case 0:
navigationButton = NavigationBarActionButton(UIImage(named: "menu_icn"), action: nil, accessibilityIdentifier: "menu")
default:
navigationButton = NavigationBarActionButton(UIImage(named: "arrow-left-c"), action: nil)
navigationButton = .defaultBackButton()
}

navigationItem.hidesBackButton = true
Expand All @@ -182,7 +182,7 @@ extension SideMenuNavigationController: UINavigationControllerDelegate {
sideMenu?.allowPanGesture = false
sideMenu?.allowLeftSwipe = false
interactivePopGestureRecognizer?.isEnabled = true
navigationButton = NavigationBarActionButton(UIImage(named: "arrow-left-c")) { [weak self] in
navigationButton = .defaultBackButton { [weak self] in
guard let self = self else { return }
if let viewController = self.viewControllers.compactMap({ $0 as? NavigationChildController }).last {
viewController.handleBackButtonTap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,19 @@ extension MainNavigationController: UINavigationControllerDelegate {
return
}

viewController.navigationItem.leftBarButtonItem = NavigationBarActionButton(UIImage(named: "arrow-left-c"), action: nil)
viewController.navigationItem.leftBarButtonItem = .defaultBackButton()
}

func navigationController(_: UINavigationController, didShow viewController: UIViewController, animated _: Bool) {
guard shouldShowBackButton(for: viewController) else { return }

let navigationButton = NavigationBarActionButton(UIImage(named: "arrow-left-c")) { [weak self] in
viewController.navigationItem.leftBarButtonItem = .defaultBackButton { [weak self] in
guard let self = self else { return }
if let viewController = self.viewControllers.compactMap({ $0 as? NavigationChildController }).last {
viewController.handleBackButtonTap()
} else {
self.popViewController(animated: true)
}
}

viewController.navigationItem.leftBarButtonItem = navigationButton
}

private func shouldShowBackButton(for viewController: UIViewController) -> Bool {
Expand Down Expand Up @@ -82,3 +79,13 @@ extension UINavigationController {
}
}
}

extension UIBarButtonItem {
static func defaultBackButton(with action: (() -> Void)? = nil) -> NavigationBarActionButton {
NavigationBarActionButton(
UIImage(named: "arrow-left-c"),
action: action,
accessibilityIdentifier: "aid-back-button"
)
}
}
4 changes: 2 additions & 2 deletions FlowCrypt/Controllers/Threads/ThreadDetailsDecorator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private func makeEncryptionBadge(_ input: ThreadDetailsViewController.Input) ->
icon: icon,
text: NSAttributedString.text(from: text, style: .regular(12), color: .white),
color: color,
textAccessibilityIdentifier: "encryptionBadge"
textAccessibilityIdentifier: "aid-encryption-badge"
)
}

Expand All @@ -115,6 +115,6 @@ private func makeSignatureBadge(_ input: ThreadDetailsViewController.Input) -> B
icon: signature.icon,
text: NSAttributedString.text(from: signature.message, style: .regular(12), color: .white),
color: signature.color,
textAccessibilityIdentifier: "signatureBadge"
textAccessibilityIdentifier: "aid-signature-badge"
)
}
34 changes: 20 additions & 14 deletions FlowCryptUI/Cell Nodes/ThreadMessageInfoCellNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public final class ThreadMessageInfoCellNode: CellNode {
automaticallyManagesSubnodes = true

senderNode.attributedText = input.sender
senderNode.accessibilityIdentifier = "messageSenderLabel"
senderNode.accessibilityIdentifier = "aid-message-sender-label"

dateNode.attributedText = input.date

Expand All @@ -206,27 +206,33 @@ public final class ThreadMessageInfoCellNode: CellNode {
recipientButtonNode.contentSpacing = 4

recipientButtonNode.addTarget(self, action: #selector(onRecipientsNodeTap), forControlEvents: .touchUpInside)
recipientButtonNode.accessibilityIdentifier = "messageRecipientButton"
recipientButtonNode.accessibilityIdentifier = "aid-message-recipients-tappable-area"
}

private func setupReplyNode() {
setup(buttonNode: replyNode,
with: input.replyImage,
action: #selector(onReplyNodeTap),
accessibilityIdentifier: "replyButton")
setup(
buttonNode: replyNode,
with: input.replyImage,
action: #selector(onReplyNodeTap),
accessibilityIdentifier: "aid-reply-button"
)
}

private func setupMenuNode() {
setup(buttonNode: menuNode,
with: input.menuImage,
action: #selector(onMenuNodeTap),
accessibilityIdentifier: "messageMenuButton")
setup(
buttonNode: menuNode,
with: input.menuImage,
action: #selector(onMenuNodeTap),
accessibilityIdentifier: "aid-message-menu-button"
)
}

private func setup(buttonNode node: ASButtonNode,
with image: UIImage?,
action: Selector,
accessibilityIdentifier: String) {
private func setup(
buttonNode node: ASButtonNode,
with image: UIImage?,
action: Selector,
accessibilityIdentifier: String
) {
node.setImage(image, for: .normal)
node.imageNode.imageModificationBlock = ASImageNodeTintColorModificationBlock(input.buttonColor)
node.addTarget(self, action: action, forControlEvents: .touchUpInside)
Expand Down
6 changes: 3 additions & 3 deletions FlowCryptUI/Nodes/AttachmentNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public final class AttachmentNode: CellNode {
self.index = index
}

var cellIdentifier: String { "attachmentCell\(index)" }
var titleLabelIdentifier: String { "attachmentTitleLabel\(index)" }
var deleteButtonIdentifier: String { "attachmentDeleteButton\(index)" }
var cellIdentifier: String { "aid-attachment-cell-\(index)" }
var titleLabelIdentifier: String { "aid-attachment-title-label-\(index)" }
var deleteButtonIdentifier: String { "aid-attachment-delete-button-\(index)" }
}

private let titleNode = ASTextNode()
Expand Down
1 change: 1 addition & 0 deletions FlowCryptUI/Views/NavigationBarActionButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public final class NavigationBarActionButton: UIBarButtonItem {
$0.frame.size = Constants.buttonSize
$0.addTarget(self, action: #selector(tap), for: .touchUpInside)
$0.accessibilityIdentifier = accessibilityIdentifier
$0.isAccessibilityElement = true
}
}

Expand Down
19 changes: 6 additions & 13 deletions FlowCryptUI/Views/NavigationBarItemsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,19 @@ public final class NavigationBarItemsView: UIBarButtonItem {

public struct Input {
let image: UIImage?
@available(*, deprecated, message: "Use onTap closure instead")
let action: TargetAction?
let title: String?
let accessibilityLabel: String?
let accessibilityId: String?
let onTap: (() -> Void)?

public init(
image: UIImage?,
action: (target: Any?, selector: Selector)? = nil,
title: String? = nil,
accessibilityLabel: String? = nil,
accessibilityId: String? = nil,
onTap: (() -> Void)? = nil
) {
self.image = image
self.action = action
self.title = title
self.accessibilityLabel = accessibilityLabel
self.accessibilityId = accessibilityId
self.onTap = onTap
}
}
Expand All @@ -53,12 +49,9 @@ public final class NavigationBarItemsView: UIBarButtonItem {
$0.imageView?.frame.size = Constants.buttonSize
$0.setImage(value.element.image, for: .normal)
$0.setTitle(value.element.title, for: .normal)
$0.accessibilityLabel = self.accessibilityLabel
if let action = value.element.action {
$0.addTarget(action.target, action: action.selector, for: .touchUpInside)
} else if value.element.onTap != nil {
$0.addTarget(self, action: #selector(self.handleTap(with:)), for: .touchUpInside)
}
$0.accessibilityIdentifier = value.element.accessibilityId
$0.isAccessibilityElement = true
$0.addTarget(self, action: #selector(self.handleTap(with:)), for: .touchUpInside)
}
}

Expand Down
20 changes: 16 additions & 4 deletions appium/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
5. restart terminal
6. `nvm install 16` - installs NodeJS 16 and sets it as default
7. `cd ~/git/flowcrypt-ios/appium && npm install`
8. use Visual Studio Code IDE for editting appium tests - be sure to open it using `File` -> `Open Workspace from File` -> `Core/flowcrypt-mobile-core.code-workspace` (don't simply open the project as a folder, because advanced IDE functionality will be missing)

## Building app for testing

Run this in `flowcrypt-ios` folder: `bundle exec fastlane build`. This will produce folder `appium/FlowCrypt.app` that contains the built app.
1. Manually compile build from the current code:
- run `bundle exec fastlane build` in `flowcrypt-ios` folder
- it will produce `appium/FlowCrypt.app` for testing
2. Use the latest simulator build:
- copy `FlowCrypt.app` from `/DerivedData/FlowCrypt-.../Build/Products/Debug-iphonesimulator` (In Xcode open Products folder -> FlowCrypt -> Show in Finder).
Comment on lines 14 to +19
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like you need to take both step 1 and then step 2 in sequence. Which is not true. These two are two alternative approaches, and should be documented as such.


## Run tests

Expand All @@ -24,10 +28,18 @@ To run a particular test:

To run all tests: `npm run-script test.live.all` or `npm run-script test.mock.all`

## Write and debug tests
Tips for debugging:
- Remove contents of `appium/tmp` before test execution.
- Execute tests and check `appium/tmp` for troubleshooting.
- You can change log level to debug/error inside `appium/config/wdio.shared.conf.js`. `logLevel: 'debug'`.
- You can inspect accessibility identifiers of ui elements with `appium-inspector`.
- if appium doesn't even start simulator where it used to work, try deleting node_modules folder and running `npm install`. Also check your nodejs version is 16 with `node --version`

## Inspect accessibility identifiers
1. Install `https://github.com/appium/appium-inspector`. Releases `https://github.com/appium/appium-inspector/releases`
2. Download `appium-inspector.dmg`.
3. Before openning package run `xattr -cr appium-inspector.dmg` on downloaded file.
3. Before opening package run `xattr -cr appium-inspector.dmg` on downloaded file.
4. Allow access in `System Prefferences -> Privacy Tab -> Accessibility`
5. Use next capabilities for `Appium Inspector`
`
Expand All @@ -46,4 +58,4 @@ To run all tests: `npm run-script test.live.all` or `npm run-script test.mock.al
}
`
6. Remote host - `127.0.0.1`, Port - `4723`, Path - `/wd/hub`
7. Run `Start Session`
7. Run `Start Session`
2 changes: 1 addition & 1 deletion appium/config/wdio.shared.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ exports.config = {
requires: ['tsconfig-paths/register']
},
sync: true,
logLevel: 'silent',
logLevel: 'info',
deprecationWarnings: true,
bail: 0,
waitforTimeout: 15000,
Expand Down
6 changes: 3 additions & 3 deletions appium/tests/screenobjects/attachment.screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import BaseScreen from './base.screen';
import ElementHelper from "../helpers/ElementHelper";

const SELECTORS = {
BACK_BTN: '~arrow left c',
SAVE_BTN: '-ios class chain:**/XCUIElementTypeButton[`label == "Save"`]',
CANCEL_BTN: '~Cancel',
BACK_BTN: '~aid-back-button',
SAVE_BTN: '~aid-save-attachment-to-device',
CANCEL_BTN: '~Cancel', // can't change aid for UIDocumentPickerViewController
};

class AttachmentScreen extends BaseScreen {
Expand Down
2 changes: 1 addition & 1 deletion appium/tests/screenobjects/contact-public-key.screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import BaseScreen from './base.screen';
import ElementHelper from "../helpers/ElementHelper";

const SELECTORS = {
BACK_BTN: '~arrow left c',
BACK_BTN: '~aid-back-button',
KEY: '~Key',
PUBLIC_KEY: '-ios class chain:**/XCUIElementTypeOther/XCUIElementTypeStaticText[2]',
FINGERPRINT_VALUE: '~fingerprintValue',
Expand Down
Loading