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

Side by Side Diff: chrome/browser/password_manager/credential_manager_browsertest.cc

Issue 2947413002: Restrict CM API interface request and message dispatch. (Closed)
Patch Set: Address nit from clamy@. Created 3 years, 5 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/macros.h" 5 #include "base/macros.h"
6 #include "base/stl_util.h" 6 #include "base/stl_util.h"
7 #include "base/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
8 #include "chrome/browser/password_manager/password_manager_test_base.h" 10 #include "chrome/browser/password_manager/password_manager_test_base.h"
9 #include "chrome/browser/password_manager/password_store_factory.h" 11 #include "chrome/browser/password_manager/password_store_factory.h"
10 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/profiles/profile_io_data.h" 13 #include "chrome/browser/profiles/profile_io_data.h"
12 #include "chrome/browser/ui/browser.h" 14 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/passwords/passwords_model_delegate.h" 15 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/test/base/ui_test_utils.h" 17 #include "chrome/test/base/ui_test_utils.h"
15 #include "components/password_manager/core/browser/password_bubble_experiment.h" 18 #include "components/password_manager/core/browser/password_bubble_experiment.h"
16 #include "components/password_manager/core/browser/test_password_store.h" 19 #include "components/password_manager/core/browser/test_password_store.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_observer.h"
17 #include "content/public/test/browser_test.h" 22 #include "content/public/test/browser_test.h"
18 #include "content/public/test/browser_test_utils.h" 23 #include "content/public/test/browser_test_utils.h"
19 #include "net/dns/mock_host_resolver.h" 24 #include "net/dns/mock_host_resolver.h"
20 25
21 namespace { 26 namespace {
22 27
23 class CredentialManagerBrowserTest : public PasswordManagerBrowserTestBase { 28 class CredentialManagerBrowserTest : public PasswordManagerBrowserTestBase {
24 public: 29 public:
25 CredentialManagerBrowserTest() = default; 30 CredentialManagerBrowserTest() = default;
26 31
27 void SetUpOnMainThread() override { 32 void SetUpOnMainThread() override {
28 PasswordManagerBrowserTestBase::SetUpOnMainThread(); 33 PasswordManagerBrowserTestBase::SetUpOnMainThread();
29 // Redirect all requests to localhost. 34 // Redirect all requests to localhost.
30 host_resolver()->AddRule("*", "127.0.0.1"); 35 host_resolver()->AddRule("*", "127.0.0.1");
31 } 36 }
32 37
33 bool IsShowingAccountChooser() { 38 bool IsShowingAccountChooser() {
34 return PasswordsModelDelegateFromWebContents(WebContents())-> 39 return PasswordsModelDelegateFromWebContents(WebContents())->GetState() ==
35 GetState() == password_manager::ui::CREDENTIAL_REQUEST_STATE; 40 password_manager::ui::CREDENTIAL_REQUEST_STATE;
36 } 41 }
37 42
38 // Similarly to PasswordManagerBrowserTestBase::NavigateToFile this is a 43 // Similarly to PasswordManagerBrowserTestBase::NavigateToFile this is a
39 // wrapper around ui_test_utils::NavigateURL that waits until DidFinishLoad() 44 // wrapper around ui_test_utils::NavigateURL that waits until DidFinishLoad()
40 // fires. Different to NavigateToFile this method allows passing a test_server 45 // fires. Different to NavigateToFile this method allows passing a test_server
41 // and modifications to the hostname. 46 // and modifications to the hostname.
42 void NavigateToURL(const net::EmbeddedTestServer& test_server, 47 void NavigateToURL(const net::EmbeddedTestServer& test_server,
43 const std::string& hostname, 48 const std::string& hostname,
44 const std::string& relative_url) { 49 const std::string& relative_url) {
45 NavigationObserver observer(WebContents()); 50 NavigationObserver observer(WebContents());
46 GURL url = test_server.GetURL(hostname, relative_url); 51 GURL url = test_server.GetURL(hostname, relative_url);
47 ui_test_utils::NavigateToURL(browser(), url); 52 ui_test_utils::NavigateToURL(browser(), url);
48 observer.Wait(); 53 observer.Wait();
49 } 54 }
50 55
56 // Triggers a call to `navigator.credentials.get` to retrieve passwords, waits
57 // for success, and ASSERTs that |expect_has_results| is satisfied.
58 void TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(
59 content::WebContents* web_contents,
60 bool expect_has_results) {
61 bool result = false;
62 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
63 web_contents,
64 "navigator.credentials.get({password: true}).then(c => {"
65 " window.domAutomationController.send(!!c);"
66 "});",
67 &result));
68 ASSERT_EQ(expect_has_results, result);
69 }
70
71 // Schedules a call to be made to navigator.credentials.store() in the
72 // `unload` handler to save a credential with |username| and |password|.
73 void ScheduleNavigatorStoreCredentialAtUnload(
74 content::WebContents* web_contents,
75 const char* username,
76 const char* password) {
77 ASSERT_TRUE(content::ExecuteScript(
78 web_contents,
79 base::StringPrintf(
80 "window.addEventListener(\"unload\", () => {"
81 " var c = new PasswordCredential({ id: '%s', password: '%s' });"
82 " navigator.credentials.store(c);"
83 "});",
84 username, password)));
85 }
86
87 // Tests that when navigator.credentials.store() is called in an `unload`
88 // handler before a same-RenderFrame navigation, the request is guaranteed to
89 // be serviced in the context of the initial document.
90 //
91 // If |preestablish_mojo_pipe| is set, then the CredentialManagerClient will
92 // establish the Mojo connection to the CredentialManagerImpl ahead of time,
93 // instead of letting the Mojo connection be established on-demand when the
94 // call to store() triggered from the unload handler.
95 void TestStoreInUnloadHandlerForSameSiteNavigation(
96 bool preestablish_mojo_pipe) {
97 // Use URLs that differ on subdomains so we can tell which one was used for
98 // saving, but they still belong to the same SiteInstance, so they will be
99 // renderered in the same RenderFrame (in the same process).
100 const GURL a_url1 = https_test_server().GetURL("foo.a.com", "/title1.html");
101 const GURL a_url2 = https_test_server().GetURL("bar.a.com", "/title2.html");
102
103 // Navigate to a mostly empty page.
104 ui_test_utils::NavigateToURL(browser(), a_url1);
105
106 ChromePasswordManagerClient* client =
107 ChromePasswordManagerClient::FromWebContents(WebContents());
108
109 if (preestablish_mojo_pipe) {
110 EXPECT_FALSE(client->has_binding_for_credential_manager());
111 ASSERT_NO_FATAL_FAILURE(
112 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(
113 WebContents(), false));
114 EXPECT_TRUE(client->has_binding_for_credential_manager());
115 }
116
117 // Schedule storing a credential on the `unload` event.
118 ASSERT_NO_FATAL_FAILURE(ScheduleNavigatorStoreCredentialAtUnload(
119 WebContents(), "user", "hunter2"));
120
121 // Trigger a same-site navigation carried out in the same RenderFrame.
122 content::RenderFrameHost* old_rfh = WebContents()->GetMainFrame();
123 ui_test_utils::NavigateToURL(browser(), a_url2);
124 ASSERT_EQ(old_rfh, WebContents()->GetMainFrame());
125
126 // Ensure that the old document no longer has a Mojo connection to the
127 // CredentialManagerImpl, nor can it get one later.
128 //
129 // The sequence of events for same-RFH navigations is as follows:
130 // 1.) FrameHostMsg_DidStartProvisionalLoad
131 // 2.) FrameLoader::PrepareForCommit
132 // 2.1) Document::Shutdown (old Document)
133 // 3.) FrameHostMsg_DidCommitProvisionalLoad (new load)
134 // ... loading ...
135 // 4.) FrameHostMsg_DidStopLoading
136 // 5.) content::WaitForLoadStop inside NavigateToURL returns
137 // 6.) NavigateToURL returns
138 //
139 // After Step 2.1, the old Document cannot issue a new Mojo InterfaceRequest
140 // anymore. Plus, because the AssociatedInterfaceRegistry, through which the
141 // associated interface to the CredentialManagerImpl is retrieved, is itself
142 // Channel-associated, any InterfaceRequest messages that may have been
143 // issued before or during Step 2.1, will be guaranteed to arrive to the
144 // browser side before FrameHostMsg_DidCommitProvisionalLoad in Step 3.
145 //
146 // Hence it is sufficient to check that the Mojo connection is closed now.
147 EXPECT_FALSE(client->has_binding_for_credential_manager());
148
149 // Ensure that the navigator.credentials.store() call was serviced in the
150 // context of the old URL, |a_url|.
151 //
152 // The CredentialManager Mojo interface is Channel-associated, so message
153 // ordering with legacy IPC messages is preserved. Therefore, servicing the
154 // store() called from the `unload` handler, triggered from
155 // FrameLoader::PrepareForCommit, will be serviced before
156 // FrameHostMsg_DidCommitProvisionalLoad, thus before DidFinishNavigation,
157 ASSERT_TRUE(client->was_store_ever_called());
158
159 BubbleObserver prompt_observer(WebContents());
160 prompt_observer.WaitForSavePrompt();
161 ASSERT_TRUE(prompt_observer.IsShowingSavePrompt());
162 prompt_observer.AcceptSavePrompt();
163
164 WaitForPasswordStore();
165
166 password_manager::TestPasswordStore* test_password_store =
167 static_cast<password_manager::TestPasswordStore*>(
168 PasswordStoreFactory::GetForProfile(
169 browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
170 .get());
171
172 ASSERT_EQ(1u, test_password_store->stored_passwords().size());
173 autofill::PasswordForm signin_form =
174 test_password_store->stored_passwords().begin()->second[0];
175 EXPECT_EQ(base::ASCIIToUTF16("user"), signin_form.username_value);
176 EXPECT_EQ(base::ASCIIToUTF16("hunter2"), signin_form.password_value);
177 EXPECT_EQ(a_url1.GetOrigin(), signin_form.origin);
178 }
179
180 // Tests the when navigator.credentials.store() is called in an `unload`
181 // handler before a cross-site transfer navigation, the request is ignored.
182 //
183 // If |preestablish_mojo_pipe| is set, then the CredentialManagerClient will
184 // establish the Mojo connection to the CredentialManagerImpl ahead of time,
185 // instead of letting the Mojo connection be established on-demand when the
186 // call to store() triggered from the unload handler.
187 void TestStoreInUnloadHandlerForCrossSiteNavigation(
188 bool preestablish_mojo_pipe) {
189 const GURL a_url = https_test_server().GetURL("a.com", "/title1.html");
190 const GURL b_url = https_test_server().GetURL("b.com", "/title2.html");
191
192 // Navigate to a mostly empty page.
193 ui_test_utils::NavigateToURL(browser(), a_url);
194
195 ChromePasswordManagerClient* client =
196 ChromePasswordManagerClient::FromWebContents(WebContents());
197
198 if (preestablish_mojo_pipe) {
199 EXPECT_FALSE(client->has_binding_for_credential_manager());
200 ASSERT_NO_FATAL_FAILURE(
201 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(
202 WebContents(), false));
203 EXPECT_TRUE(client->has_binding_for_credential_manager());
204 }
205
206 // Schedule storing a credential on the `unload` event.
207 ASSERT_NO_FATAL_FAILURE(ScheduleNavigatorStoreCredentialAtUnload(
208 WebContents(), "user", "hunter2"));
209
210 // Trigger a cross-site navigation that is carried out in a new renderer,
211 // and which will swap out the old RenderFrameHost.
212 content::RenderFrameDeletedObserver rfh_destruction_observer(
213 WebContents()->GetMainFrame());
214 ui_test_utils::NavigateToURL(browser(), b_url);
215
216 // Ensure that the navigator.credentials.store() call is never serviced.
217 // The sufficient conditions for this are:
218 // -- The swapped out RFH is destroyed, so the RenderFrame cannot
219 // establish a new Mojo connection to CredentialManagerImpl anymore.
220 // -- There is no already existing Mojo connection to CredentialManagerImpl
221 // either, which could be used to call store() in the future.
222 // -- There have not been any calls to store() in the past.
223 rfh_destruction_observer.WaitUntilDeleted();
224 EXPECT_FALSE(client->has_binding_for_credential_manager());
225 EXPECT_FALSE(client->was_store_ever_called());
226 }
227
51 private: 228 private:
52 DISALLOW_COPY_AND_ASSIGN(CredentialManagerBrowserTest); 229 DISALLOW_COPY_AND_ASSIGN(CredentialManagerBrowserTest);
53 }; 230 };
54 231
55 // Tests. 232 // Tests.
56 233
57 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, 234 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest,
58 AccountChooserWithOldCredentialAndNavigation) { 235 AccountChooserWithOldCredentialAndNavigation) {
59 // Save credentials with 'skip_zero_click'. 236 // Save credentials with 'skip_zero_click'.
60 scoped_refptr<password_manager::TestPasswordStore> password_store = 237 scoped_refptr<password_manager::TestPasswordStore> password_store =
61 static_cast<password_manager::TestPasswordStore*>( 238 static_cast<password_manager::TestPasswordStore*>(
62 PasswordStoreFactory::GetForProfile( 239 PasswordStoreFactory::GetForProfile(
63 browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS).get()); 240 browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
241 .get());
64 autofill::PasswordForm signin_form; 242 autofill::PasswordForm signin_form;
65 signin_form.signon_realm = embedded_test_server()->base_url().spec(); 243 signin_form.signon_realm = embedded_test_server()->base_url().spec();
66 signin_form.password_value = base::ASCIIToUTF16("password"); 244 signin_form.password_value = base::ASCIIToUTF16("password");
67 signin_form.username_value = base::ASCIIToUTF16("user"); 245 signin_form.username_value = base::ASCIIToUTF16("user");
68 signin_form.origin = embedded_test_server()->base_url(); 246 signin_form.origin = embedded_test_server()->base_url();
69 signin_form.skip_zero_click = true; 247 signin_form.skip_zero_click = true;
70 password_store->AddLogin(signin_form); 248 password_store->AddLogin(signin_form);
71 249
72 NavigateToFile("/password/password_form.html"); 250 NavigateToFile("/password/password_form.html");
73 std::string fill_password = 251 std::string fill_password =
74 "document.getElementById('username_field').value = 'user';" 252 "document.getElementById('username_field').value = 'user';"
75 "document.getElementById('password_field').value = 'password';"; 253 "document.getElementById('password_field').value = 'password';";
76 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_password)); 254 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_password));
77 255
78 // Call the API to trigger the notification to the client. 256 // Call the API to trigger the notification to the client.
79 ASSERT_TRUE(content::ExecuteScript( 257 ASSERT_TRUE(content::ExecuteScript(
80 RenderViewHost(), 258 RenderViewHost(),
81 "navigator.credentials.get({password: true})" 259 "navigator.credentials.get({password: true})"
82 ".then(cred => window.location = '/password/done.html')")); 260 ".then(cred => window.location = '/password/done.html')"));
83 // Mojo calls from the renderer are asynchronous. 261 // Mojo calls from the renderer are asynchronous.
84 BubbleObserver(WebContents()).WaitForAccountChooser(); 262 BubbleObserver(WebContents()).WaitForAccountChooser();
85 PasswordsModelDelegateFromWebContents(WebContents())->ChooseCredential( 263 PasswordsModelDelegateFromWebContents(WebContents())
86 signin_form, 264 ->ChooseCredential(
87 password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD); 265 signin_form,
266 password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
88 267
89 NavigationObserver observer(WebContents()); 268 NavigationObserver observer(WebContents());
90 observer.SetPathToWaitFor("/password/done.html"); 269 observer.SetPathToWaitFor("/password/done.html");
91 observer.Wait(); 270 observer.Wait();
92 271
93 // Verify that the form's 'skip_zero_click' is updated and not overwritten 272 // Verify that the form's 'skip_zero_click' is updated and not overwritten
94 // by the autofill password manager on successful login. 273 // by the autofill password manager on successful login.
95 WaitForPasswordStore(); 274 WaitForPasswordStore();
96 password_manager::TestPasswordStore::PasswordMap passwords_map = 275 password_manager::TestPasswordStore::PasswordMap passwords_map =
97 password_store->stored_passwords(); 276 password_store->stored_passwords();
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 NavigationObserver observer(WebContents()); 417 NavigationObserver observer(WebContents());
239 observer.SetPathToWaitFor("/password/done.html"); 418 observer.SetPathToWaitFor("/password/done.html");
240 observer.Wait(); 419 observer.Wait();
241 420
242 BubbleObserver prompt_observer(WebContents()); 421 BubbleObserver prompt_observer(WebContents());
243 // The autofill password manager shouldn't react to the successful login 422 // The autofill password manager shouldn't react to the successful login
244 // because it was suppressed when the site got the credential back. 423 // because it was suppressed when the site got the credential back.
245 EXPECT_FALSE(prompt_observer.IsShowingSavePrompt()); 424 EXPECT_FALSE(prompt_observer.IsShowingSavePrompt());
246 } 425 }
247 426
427 // Regression test for https://crbug.com/736357.
428 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest,
429 StoreInUnloadHandler_SameSite_OnDemandMojoPipe) {
430 TestStoreInUnloadHandlerForSameSiteNavigation(
431 false /* preestablish_mojo_pipe */);
432 }
433
434 // Regression test for https://crbug.com/736357.
435 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest,
436 StoreInUnloadHandler_SameSite_PreestablishedPipe) {
437 TestStoreInUnloadHandlerForSameSiteNavigation(
438 true /* preestablish_mojo_pipe */);
439 }
440 // Regression test for https://crbug.com/736357.
441 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest,
442 StoreInUnloadHandler_CrossSite_OnDemandMojoPipe) {
443 TestStoreInUnloadHandlerForCrossSiteNavigation(
444 false /* preestablish_mojo_pipe */);
445 }
446
447 // Regression test for https://crbug.com/736357.
448 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest,
449 StoreInUnloadHandler_CrossSite_PreestablishedPipe) {
450 TestStoreInUnloadHandlerForCrossSiteNavigation(
451 true /* preestablish_mojo_pipe */);
452 }
453
454 // Regression test for https://crbug.com/736357.
455 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest,
456 MojoConnectionRecreatedAfterNavigation) {
457 const GURL a_url1 = https_test_server().GetURL("a.com", "/title1.html");
458 const GURL a_url2 = https_test_server().GetURL("a.com", "/title2.html");
459 const GURL a_url2_ref = https_test_server().GetURL("a.com", "/title2.html#r");
460 const GURL b_url = https_test_server().GetURL("b.com", "/title2.html#ref");
461
462 // Enable 'auto signin' for the profile.
463 password_bubble_experiment::RecordAutoSignInPromptFirstRunExperienceWasShown(
464 browser()->profile()->GetPrefs());
465
466 // Navigate to a mostly empty page.
467 ui_test_utils::NavigateToURL(browser(), a_url1);
468
469 ChromePasswordManagerClient* client =
470 ChromePasswordManagerClient::FromWebContents(WebContents());
471
472 // Store a credential, and expect it to establish the Mojo connection.
473 EXPECT_FALSE(client->has_binding_for_credential_manager());
474 EXPECT_FALSE(client->was_store_ever_called());
475
476 ASSERT_TRUE(content::ExecuteScript(
477 WebContents(),
478 "var c = new PasswordCredential({ id: 'user', password: 'hunter2' });"
479 "navigator.credentials.store(c);"));
480
481 BubbleObserver prompt_observer(WebContents());
482 prompt_observer.WaitForSavePrompt();
483 ASSERT_TRUE(prompt_observer.IsShowingSavePrompt());
484 prompt_observer.AcceptSavePrompt();
485 WaitForPasswordStore();
486
487 EXPECT_TRUE(client->has_binding_for_credential_manager());
488 EXPECT_TRUE(client->was_store_ever_called());
489
490 // Trigger a same-site navigation.
491 content::RenderFrameHost* old_rfh = WebContents()->GetMainFrame();
492 ui_test_utils::NavigateToURL(browser(), a_url2);
493 ASSERT_EQ(old_rfh, WebContents()->GetMainFrame());
494
495 // Expect the Mojo connection closed.
496 EXPECT_FALSE(client->has_binding_for_credential_manager());
497
498 // Calling navigator.credentials.get() again should re-establish the Mojo
499 // connection and succeed.
500 ASSERT_NO_FATAL_FAILURE(
501 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(),
502 true));
503 EXPECT_TRUE(client->has_binding_for_credential_manager());
504
505 // Same-document navigation. Call to get() succeeds.
506 ui_test_utils::NavigateToURL(browser(), a_url2_ref);
507 ASSERT_EQ(old_rfh, WebContents()->GetMainFrame());
508 EXPECT_TRUE(client->has_binding_for_credential_manager());
509 ASSERT_NO_FATAL_FAILURE(
510 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(),
511 true));
512
513 // Cross-site navigation. Call to get() succeeds without results.
514 ui_test_utils::NavigateToURL(browser(), b_url);
515 ASSERT_NO_FATAL_FAILURE(
516 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(),
517 false));
518
519 // Trigger a cross-site navigation back. Call to get() should still succeed,
520 // and once again with results.
521 ui_test_utils::NavigateToURL(browser(), a_url1);
522 ASSERT_NO_FATAL_FAILURE(
523 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(),
524 true));
525 }
526
248 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, SaveViaAPIAndAutofill) { 527 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, SaveViaAPIAndAutofill) {
249 NavigateToFile("/password/password_form.html"); 528 NavigateToFile("/password/password_form.html");
250 529
251 ASSERT_TRUE(content::ExecuteScript( 530 ASSERT_TRUE(content::ExecuteScript(
252 RenderViewHost(), 531 RenderViewHost(),
253 "document.getElementById('input_submit_button').addEventListener('click'," 532 "document.getElementById('input_submit_button').addEventListener('click',"
254 "function(event) {" 533 "function(event) {"
255 "var c = new PasswordCredential({ id: 'user', password: 'API' });" 534 "var c = new PasswordCredential({ id: 'user', password: 'API' });"
256 "navigator.credentials.store(c);" 535 "navigator.credentials.store(c);"
257 "});")); 536 "});"));
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 628
350 // Reload the page and make sure it's autofilled. 629 // Reload the page and make sure it's autofilled.
351 NavigateToFile("/password/password_form.html"); 630 NavigateToFile("/password/password_form.html");
352 WaitForElementValue("username_field", "user"); 631 WaitForElementValue("username_field", "user");
353 content::SimulateMouseClickAt( 632 content::SimulateMouseClickAt(
354 WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1)); 633 WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1));
355 WaitForElementValue("password_field", "12345"); 634 WaitForElementValue("password_field", "12345");
356 } 635 }
357 636
358 } // namespace 637 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698