Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1069)

Side by Side Diff: ios/chrome/browser/ui/settings/passwords_settings_egtest.mm

Issue 2846253002: Add EGTests for passwords settings on iOS (Closed)
Patch Set: Fix buildfiles Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/callback.h"
6 #include "base/mac/foundation_util.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/time/time.h"
10 #include "components/autofill/core/common/password_form.h"
11 #include "components/keyed_service/core/service_access_type.h"
12 #include "components/password_manager/core/browser/password_store.h"
13 #include "components/password_manager/core/common/password_manager_pref_names.h"
14 #include "components/prefs/pref_service.h"
15 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
16 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
17 #import "ios/chrome/browser/ui/settings/password_details_collection_view_control ler_for_testing.h"
18 #import "ios/chrome/browser/ui/settings/reauthentication_module.h"
19 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
20 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
21 #import "ios/chrome/browser/ui/util/top_view_controller.h"
22 #include "ios/chrome/grit/ios_strings.h"
23 #import "ios/chrome/test/app/chrome_test_util.h"
24 #include "ios/chrome/test/earl_grey/accessibility_util.h"
25 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
26 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
27 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
28 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
29 #include "ui/base/l10n/l10n_util.h"
30 #include "url/gurl.h"
31
32 #if !defined(__has_feature) || !__has_feature(objc_arc)
33 #error "This file requires ARC support."
34 #endif
35
36 // This test complements
37 // password_details_collection_view_controller_unittest.mm. Very simple
38 // integration tests and features which are not currently unittestable should
39 // go here, the rest into the unittest.
40 // This test only uses the new UI which allows viewing passwords.
41 // TODO(crbug.com/159166): Remove the above sentence once the new UI is the
42 // default one.
43
44 using autofill::PasswordForm;
45 using chrome_test_util::ButtonWithAccessibilityLabel;
46 using chrome_test_util::ButtonWithAccessibilityLabelId;
47 using chrome_test_util::NavigationBarDoneButton;
48
49 namespace {
50
51 // Matcher for the Settings button in the tools menu.
52 id<GREYMatcher> SettingsButton() {
sdefresne 2017/05/02 15:30:08 baxley: are those helper methods (used only once)
baxley 2017/05/02 16:20:41 I think some of these fall under the category of a
vabr (Chromium) 2017/05/03 05:41:37 Thanks for raising this and for the detailed answe
53 return grey_accessibilityID(kToolsMenuSettingsId);
54 }
55
56 // Matcher for the Save Passwords cell on the main Settings screen.
57 id<GREYMatcher> PasswordsButton() {
58 return ButtonWithAccessibilityLabelId(IDS_IOS_SAVE_PASSWORDS);
59 }
60
61 // Matcher for a password entry for |username|.
62 id<GREYMatcher> Entry(NSString* username) {
63 return ButtonWithAccessibilityLabel(username);
64 }
65
66 // Matcher for the Edit button in Save Passwords view.
67 id<GREYMatcher> EditButton() {
68 return ButtonWithAccessibilityLabelId(IDS_IOS_NAVIGATION_BAR_EDIT_BUTTON);
69 }
70
71 // Matcher for the Copy password button in Password Details view.
72 id<GREYMatcher> CopyPasswordButton() {
73 return ButtonWithAccessibilityLabelId(IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON);
74 }
75
76 } // namespace
77
78 @interface MockReauthenticationModule : NSObject<ReauthenticationProtocol>
79
80 @property(nonatomic, assign) BOOL shouldSucceed;
81
82 @end
83
84 @implementation MockReauthenticationModule
85
86 @synthesize shouldSucceed = _shouldSucceed;
87
88 - (BOOL)canAttemptReauth {
89 return YES;
90 }
91
92 - (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason
93 handler:(void (^)(BOOL success))
94 showCopyPasswordsHandler {
95 showCopyPasswordsHandler(_shouldSucceed);
96 }
97
98 @end
99
100 // Various tests for the Save Passwords section of the settings.
101 @interface PasswordsSettingsTestCase : ChromeTestCase
102 @end
103
104 @implementation PasswordsSettingsTestCase
105
106 // Return pref for saving passwords back to the passed value and restores the
107 // experimental flag for viewing passwords.
108 - (void)passwordsTearDown:(BOOL)defaultPasswordManagementSetting
109 :(NSString*)oldExperiment {
110 ios::ChromeBrowserState* browserState =
111 chrome_test_util::GetOriginalBrowserState();
112 PrefService* preferences = browserState->GetPrefs();
113 preferences->SetBoolean(
114 password_manager::prefs::kPasswordManagerSavingEnabled,
115 defaultPasswordManagementSetting);
116
117 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
118 [defaults setObject:oldExperiment forKey:@"EnableViewCopyPasswords"];
119 }
120
121 // Sets the preference to allow saving passwords and activates the flag to use
122 // the new UI for viewing passwords in settings. Also, ensures that original
123 // state is restored after the test ends.
124 - (void)scopedEnablePasswordManagementAndViewingUI {
125 // Retrieve the original preference state.
126 ios::ChromeBrowserState* browserState =
127 chrome_test_util::GetOriginalBrowserState();
128 PrefService* preferences = browserState->GetPrefs();
129 bool defaultPasswordManagerSavingPref = preferences->GetBoolean(
130 password_manager::prefs::kPasswordManagerSavingEnabled);
131
132 // Retrieve the experiment setting.
133 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
134 NSString* oldSetting = [defaults stringForKey:@"EnableViewCopyPasswords"];
135
136 // Ensure restoring that on tear-down.
137 __weak PasswordsSettingsTestCase* weakSelf = self;
138 [self setTearDownHandler:^{
139 [weakSelf passwordsTearDown:defaultPasswordManagerSavingPref:oldSetting];
140 }];
141
142 // Enable saving.
143 preferences->SetBoolean(
144 password_manager::prefs::kPasswordManagerSavingEnabled, true);
145
146 // Enable viewing passwords in settings.
147 [defaults setObject:@"Enabled" forKey:@"EnableViewCopyPasswords"];
148 }
149
150 - (scoped_refptr<password_manager::PasswordStore>)passwordStore {
151 // ServiceAccessType governs behaviour in Incognito: only modifications with
152 // EXPLICIT_ACCESS, which correspond to user's explicit gesture, succeed.
153 // This test does not deal with Incognito, so the value of the argument is
154 // irrelevant.
155 return IOSChromePasswordStoreFactory::GetForBrowserState(
156 chrome_test_util::GetOriginalBrowserState(),
157 ServiceAccessType::EXPLICIT_ACCESS);
158 }
159
160 // Saves an example form in the store.
161 - (void)saveExamplePasswordForm {
162 PasswordForm example;
163 example.username_value = base::ASCIIToUTF16("user");
164 example.password_value = base::ASCIIToUTF16("password");
165 example.origin = GURL("https://example.com");
166 example.signon_realm = example.origin.spec();
167
168 [self passwordStore]->AddLogin(example);
169 // Allow the PasswordStore to process this on the DB thread.
170 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
171 }
172
173 // Removes all credentials stored.
174 - (void)clearPasswordStore {
175 [self passwordStore]->RemoveLoginsCreatedBetween(base::Time(), base::Time(),
176 base::Closure());
177 // Allow the PasswordStore to process this on the DB thread.
178 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
179 }
180
181 // Opens the passwords page from the NTP. It requires no menus to be open.
182 - (void)openPasswordSettings {
183 // Open settings and verify data in the view controller.
184 [ChromeEarlGreyUI openToolsMenu];
185 [[EarlGrey selectElementWithMatcher:SettingsButton()]
186 performAction:grey_tap()];
187 [[EarlGrey selectElementWithMatcher:PasswordsButton()]
188 performAction:grey_tap()];
189
190 // Wait for UI components to finish loading.
191 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
192 }
193
194 // Tap back arrow, to get one level higher in settings.
195 - (void)tapBackArrow {
196 [[EarlGrey
197 selectElementWithMatcher:grey_allOf(
198 grey_accessibilityID(@"ic_arrow_back"),
199 grey_accessibilityTrait(
200 UIAccessibilityTraitButton),
201 nil)] performAction:grey_tap()];
202
203 // Wait for UI components to finish loading.
204 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
205 }
206
207 // Tap Edit in any settings view.
208 - (void)tapEdit {
209 [[EarlGrey selectElementWithMatcher:EditButton()] performAction:grey_tap()];
210
211 // Wait for UI components to finish loading.
212 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
213 }
214
215 // Tap Done in any settings view.
216 - (void)tapDone {
217 [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
218 performAction:grey_tap()];
219
220 // Wait for UI components to finish loading.
221 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
222 }
223
224 // Verifies the UI elements are accessible on the Passwords page.
225 // TODO(crbug.com/159166): This differs from testAccessibilityOnPasswords in
226 // settings_egtest.mm in that here this tests the new UI (for viewing
227 // passwords), where in settings_egtest.mm the default (old) UI is tested.
228 // Once the new is the default, just remove the test in settings_egtest.mm.
229 - (void)testAccessibilityOnPasswords {
230 [self scopedEnablePasswordManagementAndViewingUI];
231
232 // Saving a form is needed for using the "password details" view.
233 [self saveExamplePasswordForm];
234
235 [self openPasswordSettings];
236 chrome_test_util::VerifyAccessibilityForCurrentScreen();
237
238 [self tapEdit];
239 chrome_test_util::VerifyAccessibilityForCurrentScreen();
240 [self tapDone];
241
242 // Inspect "password details" view.
243 [[EarlGrey selectElementWithMatcher:Entry(@"https://example.com, user")]
244 performAction:grey_tap()];
245 chrome_test_util::VerifyAccessibilityForCurrentScreen();
246 [self tapBackArrow];
247
248 [self tapBackArrow];
249 [self tapDone];
250 [self clearPasswordStore];
251 }
252
253 // Checks that attempts to copy a password provide appropriate feedback,
254 // both when reauthentication succeeds and when it fails.
255 - (void)testCopyPasswordToast {
256 [self scopedEnablePasswordManagementAndViewingUI];
257
258 // Saving a form is needed for using the "password details" view.
259 [self saveExamplePasswordForm];
260
261 [self openPasswordSettings];
262
263 [[EarlGrey selectElementWithMatcher:Entry(@"https://example.com, user")]
264 performAction:grey_tap()];
265
266 // Get the PasswordDetailsCollectionViewController and replace the
267 // reauthentication module with a fake one to avoid being blocked with a
268 // reauth prompt.
269 MockReauthenticationModule* reauth =
sdefresne 2017/05/02 15:30:08 I think that the styleguide discourage uses of abb
vabr (Chromium) 2017/05/03 05:41:37 Good point, done.
270 [[MockReauthenticationModule alloc] init];
271 SettingsNavigationController* snc =
272 base::mac::ObjCCastStrict<SettingsNavigationController>(
273 top_view_controller::TopPresentedViewController());
274 PasswordDetailsCollectionViewController* pdcvc =
275 base::mac::ObjCCastStrict<PasswordDetailsCollectionViewController>(
276 snc.topViewController);
277 [pdcvc setReauthenticationModule:reauth];
278
279 // Check the snackbar in case of successful reauthentication.
280 reauth.shouldSucceed = YES;
281 [[EarlGrey selectElementWithMatcher:CopyPasswordButton()]
282 performAction:grey_tap()];
283 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
284 NSString* snackbarLabel =
285 l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE);
286 [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
287 assertWithMatcher:grey_notNil()];
288
289 // Check the snackbar in case of failed reauthentication.
290 reauth.shouldSucceed = NO;
291 [[EarlGrey selectElementWithMatcher:CopyPasswordButton()]
292 performAction:grey_tap()];
293 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
294 snackbarLabel =
295 l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE);
296 [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
297 assertWithMatcher:grey_notNil()];
298
299 [self tapBackArrow];
300 [self tapBackArrow];
301 [self tapDone];
302 [self clearPasswordStore];
303 }
304
305 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698