Commit 3b105fc4 authored by Viktor Semeniuk's avatar Viktor Semeniuk Committed by Commit Bot

[iOS][Password Check] Copy website, username, password

This change adds possibility to copy website, username and password to
the pasteboard. Before copying password reauth is required.

Bug: 1122993
Change-Id: Ib41c1bb77b335a91ca54d0d6dada850a727fcb79
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2379739
Commit-Queue: Viktor Semeniuk <vsemeniuk@google.com>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804740}
parent a26a8be6
...@@ -26,6 +26,7 @@ source_set("password_details") { ...@@ -26,6 +26,7 @@ source_set("password_details") {
"//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/table_view", "//ios/chrome/browser/ui/table_view",
"//ios/chrome/browser/ui/util",
"//ios/chrome/common/ui/colors", "//ios/chrome/common/ui/colors",
"//ios/chrome/common/ui/reauthentication", "//ios/chrome/common/ui/reauthentication",
"//ios/chrome/common/ui/util", "//ios/chrome/common/ui/util",
...@@ -41,6 +42,8 @@ source_set("password_details_ui") { ...@@ -41,6 +42,8 @@ source_set("password_details_ui") {
"password_details.mm", "password_details.mm",
"password_details_consumer.h", "password_details_consumer.h",
"password_details_handler.h", "password_details_handler.h",
"password_details_menu_item.h",
"password_details_menu_item.mm",
"password_details_table_view_constants.h", "password_details_table_view_constants.h",
"password_details_table_view_constants.mm", "password_details_table_view_constants.mm",
"password_details_table_view_controller.h", "password_details_table_view_controller.h",
...@@ -92,6 +95,7 @@ source_set("unit_tests") { ...@@ -92,6 +95,7 @@ source_set("unit_tests") {
"//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/main:test_support", "//ios/chrome/browser/main:test_support",
"//ios/chrome/browser/passwords", "//ios/chrome/browser/passwords",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/settings/cells", "//ios/chrome/browser/ui/settings/cells",
"//ios/chrome/browser/ui/table_view:test_support", "//ios/chrome/browser/ui/table_view:test_support",
"//ios/chrome/browser/ui/table_view/cells", "//ios/chrome/browser/ui/table_view/cells",
......
...@@ -35,9 +35,6 @@ struct PasswordForm; ...@@ -35,9 +35,6 @@ struct PasswordForm;
// Delegate. // Delegate.
@property(nonatomic, weak) id<PasswordDetailsCoordinatorDelegate> delegate; @property(nonatomic, weak) id<PasswordDetailsCoordinatorDelegate> delegate;
// Dispatcher.
@property(nonatomic, weak) id<ApplicationCommands> dispatcher;
@end @end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_H_ #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_H_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h" #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h" #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
#import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/commands/open_new_tab_command.h" #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h"
...@@ -52,6 +53,9 @@ ...@@ -52,6 +53,9 @@
// The action sheet coordinator, if one is currently being shown. // The action sheet coordinator, if one is currently being shown.
@property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator; @property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator;
// Dispatcher.
@property(nonatomic, weak) id<ApplicationCommands, BrowserCommands> dispatcher;
@end @end
@implementation PasswordDetailsCoordinator @implementation PasswordDetailsCoordinator
...@@ -75,6 +79,8 @@ ...@@ -75,6 +79,8 @@
_password = password; _password = password;
_manager = manager; _manager = manager;
_reauthenticationModule = reauthModule; _reauthenticationModule = reauthModule;
_dispatcher = static_cast<id<BrowserCommands, ApplicationCommands>>(
browser->GetCommandDispatcher());
} }
return self; return self;
} }
...@@ -92,7 +98,7 @@ ...@@ -92,7 +98,7 @@
self.mediator.consumer = self.viewController; self.mediator.consumer = self.viewController;
self.viewController.handler = self; self.viewController.handler = self;
self.viewController.delegate = self.mediator; self.viewController.delegate = self.mediator;
self.viewController.commandsDispatcher = self.dispatcher; self.viewController.commandsHandler = self.dispatcher;
self.viewController.reauthModule = self.reauthenticationModule; self.viewController.reauthModule = self.reauthenticationModule;
[self.baseNavigationController pushViewController:self.viewController [self.baseNavigationController pushViewController:self.viewController
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_MENU_ITEM_H_
#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_MENU_ITEM_H_
#import <UIKit/UIKit.h>
// Menu item which holds item type. Possible types |website|, |username| or
// |password|.
@interface PasswordDetailsMenuItem : UIMenuItem
@property(nonatomic, assign) NSInteger itemType;
@end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_MENU_ITEM_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_menu_item.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation PasswordDetailsMenuItem
@end
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
delegate; delegate;
// Dispatcher for this ViewController. // Dispatcher for this ViewController.
@property(nonatomic, weak) id<ApplicationCommands> commandsDispatcher; @property(nonatomic, weak) id<ApplicationCommands, BrowserCommands>
commandsHandler;
// Module containing the reauthentication mechanism for interactions // Module containing the reauthentication mechanism for interactions
// with password. // with password.
......
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h"
#import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/commands/open_new_tab_command.h" #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_handler.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_handler.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_menu_item.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_delegate.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
...@@ -240,6 +242,10 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -240,6 +242,10 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
switch (itemType) { switch (itemType) {
case ItemTypeWebsite: case ItemTypeWebsite:
case ItemTypeUsername: case ItemTypeUsername:
[self ensureContextMenuShownForItemType:itemType
tableView:tableView
atIndexPath:indexPath];
break;
case ItemTypeChangePasswordRecommendation: case ItemTypeChangePasswordRecommendation:
break; break;
case ItemTypePassword: { case ItemTypePassword: {
...@@ -249,18 +255,22 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -249,18 +255,22 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
TableViewTextEditCell* textFieldCell = TableViewTextEditCell* textFieldCell =
base::mac::ObjCCastStrict<TableViewTextEditCell>(cell); base::mac::ObjCCastStrict<TableViewTextEditCell>(cell);
[textFieldCell.textField becomeFirstResponder]; [textFieldCell.textField becomeFirstResponder];
} else {
[self ensureContextMenuShownForItemType:itemType
tableView:tableView
atIndexPath:indexPath];
} }
break; break;
} }
case ItemTypeChangePasswordButton: case ItemTypeChangePasswordButton:
if (!self.tableView.editing) { if (!self.tableView.editing) {
DCHECK(self.commandsDispatcher); DCHECK(self.commandsHandler);
DCHECK(self.password.changePasswordURL.is_valid()); DCHECK(self.password.changePasswordURL.is_valid());
OpenNewTabCommand* command = [OpenNewTabCommand OpenNewTabCommand* command = [OpenNewTabCommand
commandWithURLFromChrome:self.password.changePasswordURL]; commandWithURLFromChrome:self.password.changePasswordURL];
UmaHistogramEnumeration("PasswordManager.BulkCheck.UserAction", UmaHistogramEnumeration("PasswordManager.BulkCheck.UserAction",
PasswordCheckInteraction::kChangePassword); PasswordCheckInteraction::kChangePassword);
[self.commandsDispatcher closeSettingsUIAndOpenURL:command]; [self.commandsHandler closeSettingsUIAndOpenURL:command];
} }
break; break;
} }
...@@ -276,6 +286,27 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -276,6 +286,27 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
return NO; return NO;
} }
// If the context menu is not shown for a given item type, constructs that
// menu and shows it. This method should only be called for item types
// representing the cells with the site, username and password.
- (void)ensureContextMenuShownForItemType:(NSInteger)itemType
tableView:(UITableView*)tableView
atIndexPath:(NSIndexPath*)indexPath {
UIMenuController* menu = [UIMenuController sharedMenuController];
if (![menu isMenuVisible]) {
menu.menuItems = [self getMenuItemsFor:itemType];
if (@available(iOS 13, *)) {
[menu showMenuFromView:tableView
rect:[tableView rectForRowAtIndexPath:indexPath]];
} else {
[menu setTargetRect:[tableView rectForRowAtIndexPath:indexPath]
inView:tableView];
[menu setMenuVisible:YES animated:YES];
}
}
}
#pragma mark - UITableViewDataSource #pragma mark - UITableViewDataSource
- (UITableViewCell*)tableView:(UITableView*)tableView - (UITableViewCell*)tableView:(UITableView*)tableView
...@@ -284,8 +315,9 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -284,8 +315,9 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
cellForRowAtIndexPath:indexPath]; cellForRowAtIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath]; NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
cell.tag = itemType;
switch (itemType) { switch (itemType) {
case ItemTypePassword: { case ItemTypePassword: {
TableViewTextEditCell* textFieldCell = TableViewTextEditCell* textFieldCell =
...@@ -379,8 +411,16 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -379,8 +411,16 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
return; return;
[strongSelf logPasswordSettingsReauthResult:result]; [strongSelf logPasswordSettingsReauthResult:result];
if (result == ReauthenticationResult::kFailure) if (result == ReauthenticationResult::kFailure) {
if (reason == ReauthenticationReasonCopy) {
[strongSelf
showToast:
l10n_util::GetNSString(
IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE)
forSuccess:NO];
}
return; return;
}
[strongSelf showPasswordFor:reason]; [strongSelf showPasswordFor:reason];
}; };
...@@ -407,9 +447,14 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -407,9 +447,14 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
UmaHistogramEnumeration("PasswordManager.BulkCheck.UserAction", UmaHistogramEnumeration("PasswordManager.BulkCheck.UserAction",
PasswordCheckInteraction::kShowPassword); PasswordCheckInteraction::kShowPassword);
break; break;
case ReauthenticationReasonCopy: case ReauthenticationReasonCopy: {
// TODO:(crbug.com/1075494) - Implement copy password functionality. UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
generalPasteboard.string = self.password.password;
[self showToast:l10n_util::GetNSString(
IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)
forSuccess:YES];
break; break;
}
case ReauthenticationReasonEdit: case ReauthenticationReasonEdit:
// Called super because we want to update only |tableView.editing|. // Called super because we want to update only |tableView.editing|.
[super editButtonPressed]; [super editButtonPressed];
...@@ -434,6 +479,18 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -434,6 +479,18 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
} }
} }
// Shows a snack bar with |message| and provides haptic feedback. The haptic
// feedback is either for success or for error, depending on |success|.
- (void)showToast:(NSString*)message forSuccess:(BOOL)success {
TriggerHapticFeedbackForNotification(success
? UINotificationFeedbackTypeSuccess
: UINotificationFeedbackTypeError);
[self.commandsHandler showSnackbarWithMessage:message
buttonText:nil
messageAction:nil
completionAction:nil];
}
- (void)passwordEditingConfirmed { - (void)passwordEditingConfirmed {
self.password.password = self.passwordTextItem.textFieldValue; self.password.password = self.passwordTextItem.textFieldValue;
[self.delegate passwordDetailsViewController:self [self.delegate passwordDetailsViewController:self
...@@ -473,6 +530,58 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) { ...@@ -473,6 +530,58 @@ typedef NS_ENUM(NSInteger, ReauthenticationReason) {
} }
} }
// Returns an array of UIMenuItems to display in a context menu on the site
// cell.
- (NSArray*)getMenuItemsFor:(NSInteger)itemType {
PasswordDetailsMenuItem* copyOption = [[PasswordDetailsMenuItem alloc]
initWithTitle:l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_COPY_MENU_ITEM)
action:@selector(copyPasswordDetails:)];
copyOption.itemType = itemType;
return @[ copyOption ];
}
// Copies the password information to system pasteboard and shows a toast of
// success/failure.
- (void)copyPasswordDetails:(id)sender {
UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
UIMenuController* menu = base::mac::ObjCCastStrict<UIMenuController>(sender);
PasswordDetailsMenuItem* menuItem =
base::mac::ObjCCastStrict<PasswordDetailsMenuItem>(
menu.menuItems.firstObject);
NSString* message = nil;
switch (menuItem.itemType) {
case ItemTypeWebsite:
generalPasteboard.string = self.password.website;
message =
l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_WAS_COPIED_MESSAGE);
break;
case ItemTypeUsername:
generalPasteboard.string = self.password.username;
message =
l10n_util::GetNSString(IDS_IOS_SETTINGS_USERNAME_WAS_COPIED_MESSAGE);
break;
case ItemTypePassword:
[self attemptToShowPasswordFor:ReauthenticationReasonCopy];
return;
}
[self showToast:message forSuccess:YES];
}
#pragma mark - UIResponder
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == @selector(copyPasswordDetails:)) {
return YES;
}
return NO;
}
#pragma mark - Metrics #pragma mark - Metrics
// Logs metrics for the given reauthentication |result| (success, failure or // Logs metrics for the given reauthentication |result| (success, failure or
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/password_form.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/ui/commands/snackbar_commands.h"
#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h"
...@@ -39,6 +40,10 @@ constexpr char kUsername[] = "test@egmail.com"; ...@@ -39,6 +40,10 @@ constexpr char kUsername[] = "test@egmail.com";
constexpr char kPassword[] = "test"; constexpr char kPassword[] = "test";
} }
@interface PasswordDetailsTableViewController (Test)
- (void)copyPasswordDetails:(id)sender;
@end
// Test class that conforms to PasswordDetailsHanler in order to test the // Test class that conforms to PasswordDetailsHanler in order to test the
// presenter methods are called correctly. // presenter methods are called correctly.
@interface FakePasswordDetailsHandler : NSObject <PasswordDetailsHandler> @interface FakePasswordDetailsHandler : NSObject <PasswordDetailsHandler>
...@@ -86,6 +91,30 @@ constexpr char kPassword[] = "test"; ...@@ -86,6 +91,30 @@ constexpr char kPassword[] = "test";
@end @end
@interface FakeSnackbarImplementation : NSObject <SnackbarCommands>
@property(nonatomic, assign) NSString* snackbarMessage;
@end
@implementation FakeSnackbarImplementation
- (void)showSnackbarMessage:(MDCSnackbarMessage*)message {
}
- (void)showSnackbarMessage:(MDCSnackbarMessage*)message
bottomOffset:(CGFloat)offset {
}
- (void)showSnackbarWithMessage:(NSString*)messageText
buttonText:(NSString*)buttonText
messageAction:(void (^)(void))messageAction
completionAction:(void (^)(BOOL))completionAction {
self.snackbarMessage = messageText;
}
@end
// Unit tests for PasswordIssuesTableViewController. // Unit tests for PasswordIssuesTableViewController.
class PasswordDetailsTableViewControllerTest class PasswordDetailsTableViewControllerTest
: public ChromeTableViewControllerTest { : public ChromeTableViewControllerTest {
...@@ -95,6 +124,7 @@ class PasswordDetailsTableViewControllerTest ...@@ -95,6 +124,7 @@ class PasswordDetailsTableViewControllerTest
delegate_ = [[FakePasswordDetailsDelegate alloc] init]; delegate_ = [[FakePasswordDetailsDelegate alloc] init];
reauthentication_module_ = [[MockReauthenticationModule alloc] init]; reauthentication_module_ = [[MockReauthenticationModule alloc] init];
reauthentication_module_.expectedResult = ReauthenticationResult::kSuccess; reauthentication_module_.expectedResult = ReauthenticationResult::kSuccess;
snack_bar_ = [[FakeSnackbarImplementation alloc] init];
} }
ChromeTableViewController* InstantiateController() override { ChromeTableViewController* InstantiateController() override {
...@@ -104,6 +134,7 @@ class PasswordDetailsTableViewControllerTest ...@@ -104,6 +134,7 @@ class PasswordDetailsTableViewControllerTest
controller.handler = handler_; controller.handler = handler_;
controller.delegate = delegate_; controller.delegate = delegate_;
controller.reauthModule = reauthentication_module_; controller.reauthModule = reauthentication_module_;
controller.commandsHandler = snack_bar_;
return controller; return controller;
} }
...@@ -174,8 +205,12 @@ class PasswordDetailsTableViewControllerTest ...@@ -174,8 +205,12 @@ class PasswordDetailsTableViewControllerTest
FakePasswordDetailsHandler* handler() { return handler_; } FakePasswordDetailsHandler* handler() { return handler_; }
FakePasswordDetailsDelegate* delegate() { return delegate_; } FakePasswordDetailsDelegate* delegate() { return delegate_; }
MockReauthenticationModule* reauth() { return reauthentication_module_; } MockReauthenticationModule* reauth() { return reauthentication_module_; }
FakeSnackbarImplementation* snack_bar() {
return (FakeSnackbarImplementation*)snack_bar_;
}
private: private:
id snack_bar_;
FakePasswordDetailsHandler* handler_; FakePasswordDetailsHandler* handler_;
FakePasswordDetailsDelegate* delegate_; FakePasswordDetailsDelegate* delegate_;
MockReauthenticationModule* reauthentication_module_; MockReauthenticationModule* reauthentication_module_;
...@@ -396,3 +431,89 @@ TEST_F(PasswordDetailsTableViewControllerTest, TestBlockedOrigin) { ...@@ -396,3 +431,89 @@ TEST_F(PasswordDetailsTableViewControllerTest, TestBlockedOrigin) {
[passwordDetails editButtonPressed]; [passwordDetails editButtonPressed];
EXPECT_TRUE(passwordDetails.tableView.editing); EXPECT_TRUE(passwordDetails.tableView.editing);
} }
// Tests copy website works as intended.
TEST_F(PasswordDetailsTableViewControllerTest, CopySite) {
SetPassword();
PasswordDetailsTableViewController* passwordDetails =
base::mac::ObjCCastStrict<PasswordDetailsTableViewController>(
controller());
[passwordDetails tableView:passwordDetails.tableView
didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
UIMenuController* menu = [UIMenuController sharedMenuController];
EXPECT_EQ(1u, menu.menuItems.count);
[passwordDetails copyPasswordDetails:menu];
UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
EXPECT_NSEQ(@"http://www.example.com/", generalPasteboard.string);
EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_WAS_COPIED_MESSAGE),
snack_bar().snackbarMessage);
}
// Tests copy username works as intended.
TEST_F(PasswordDetailsTableViewControllerTest, CopyUsername) {
SetPassword();
PasswordDetailsTableViewController* passwordDetails =
base::mac::ObjCCastStrict<PasswordDetailsTableViewController>(
controller());
[passwordDetails tableView:passwordDetails.tableView
didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
UIMenuController* menu = [UIMenuController sharedMenuController];
EXPECT_EQ(1u, menu.menuItems.count);
[passwordDetails copyPasswordDetails:menu];
UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
EXPECT_NSEQ(@"test@egmail.com", generalPasteboard.string);
EXPECT_NSEQ(
l10n_util::GetNSString(IDS_IOS_SETTINGS_USERNAME_WAS_COPIED_MESSAGE),
snack_bar().snackbarMessage);
}
// Tests copy password works as intended when reauth was successful.
TEST_F(PasswordDetailsTableViewControllerTest, CopyPasswordSuccess) {
SetPassword();
PasswordDetailsTableViewController* passwordDetails =
base::mac::ObjCCastStrict<PasswordDetailsTableViewController>(
controller());
[passwordDetails tableView:passwordDetails.tableView
didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
UIMenuController* menu = [UIMenuController sharedMenuController];
EXPECT_EQ(1u, menu.menuItems.count);
[passwordDetails copyPasswordDetails:menu];
UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
EXPECT_NSEQ(@"test", generalPasteboard.string);
EXPECT_NSEQ(
l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY),
reauth().localizedReasonForAuthentication);
EXPECT_NSEQ(
l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE),
snack_bar().snackbarMessage);
}
// Tests copy password works as intended.
TEST_F(PasswordDetailsTableViewControllerTest, CopyPasswordFail) {
SetPassword();
PasswordDetailsTableViewController* passwordDetails =
base::mac::ObjCCastStrict<PasswordDetailsTableViewController>(
controller());
reauth().expectedResult = ReauthenticationResult::kFailure;
[passwordDetails tableView:passwordDetails.tableView
didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
UIMenuController* menu = [UIMenuController sharedMenuController];
EXPECT_EQ(1u, menu.menuItems.count);
[passwordDetails copyPasswordDetails:menu];
EXPECT_NSEQ(
l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE),
snack_bar().snackbarMessage);
}
...@@ -114,7 +114,6 @@ ...@@ -114,7 +114,6 @@
password:form password:form
reauthModule:self.reauthModule reauthModule:self.reauthModule
passwordCheckManager:_manager]; passwordCheckManager:_manager];
self.passwordDetails.dispatcher = self.dispatcher;
self.passwordDetails.delegate = self; self.passwordDetails.delegate = self;
[self.passwordDetails start]; [self.passwordDetails start];
} }
......
...@@ -1312,7 +1312,6 @@ std::vector<std::unique_ptr<autofill::PasswordForm>> CopyOf( ...@@ -1312,7 +1312,6 @@ std::vector<std::unique_ptr<autofill::PasswordForm>> CopyOf(
password:form password:form
reauthModule:_reauthenticationModule reauthModule:_reauthenticationModule
passwordCheckManager:_passwordCheck.get()]; passwordCheckManager:_passwordCheck.get()];
self.passwordDetailsCoordinator.dispatcher = self.dispatcher;
self.passwordDetailsCoordinator.delegate = self; self.passwordDetailsCoordinator.delegate = self;
[self.passwordDetailsCoordinator start]; [self.passwordDetailsCoordinator start];
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment