Move Browser Plugin loadabort tests from content_browsertests to browser_tests.
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_host_browsertest.cc
blobd494d0536866e7a0debb204638876a790db6dd2d
1 // Copyright 2012 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.
5 #include "base/memory/singleton.h"
6 #include "base/run_loop.h"
7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
11 #include "content/browser/browser_plugin/browser_plugin_guest.h"
12 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
13 #include "content/browser/browser_plugin/test_browser_plugin_guest.h"
14 #include "content/browser/browser_plugin/test_guest_manager.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/common/browser_plugin/browser_plugin_messages.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_widget_host_view.h"
24 #include "content/public/browser/web_contents_observer.h"
25 #include "content/public/common/drop_data.h"
26 #include "content/public/common/url_constants.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "content/public/test/content_browser_test.h"
29 #include "content/public/test/content_browser_test_utils.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "content/shell/browser/shell_browser_context.h"
33 #include "net/base/net_util.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35 #include "net/test/embedded_test_server/http_request.h"
36 #include "net/test/embedded_test_server/http_response.h"
37 #include "net/test/spawned_test_server/spawned_test_server.h"
38 #include "third_party/WebKit/public/web/WebInputEvent.h"
40 using base::ASCIIToUTF16;
41 using blink::WebInputEvent;
42 using blink::WebMouseEvent;
43 using content::BrowserPluginEmbedder;
44 using content::BrowserPluginGuest;
45 using content::BrowserPluginHostFactory;
46 using content::WebContentsImpl;
48 const char kHTMLForGuest[] =
49 "data:text/html,<html><body>hello world</body></html>";
51 const char kHTMLForGuestAcceptDrag[] =
52 "data:text/html,<html><body>"
53 "<script>"
54 "function dropped() {"
55 " document.title = \"DROPPED\";"
56 "}"
57 "</script>"
58 "<textarea id=\"text\" style=\"width:100%; height: 100%\""
59 " ondrop=\"dropped();\">"
60 "</textarea>"
61 "</body></html>";
63 namespace content {
65 class TestBrowserPluginEmbedder : public BrowserPluginEmbedder {
66 public:
67 TestBrowserPluginEmbedder(WebContentsImpl* web_contents)
68 : BrowserPluginEmbedder(web_contents) {
71 virtual ~TestBrowserPluginEmbedder() {}
73 WebContentsImpl* web_contents() const {
74 return static_cast<WebContentsImpl*>(BrowserPluginEmbedder::web_contents());
77 private:
78 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginEmbedder);
81 // Test factory for creating test instances of BrowserPluginEmbedder and
82 // BrowserPluginGuest.
83 class TestBrowserPluginHostFactory : public BrowserPluginHostFactory {
84 public:
85 virtual BrowserPluginGuest* CreateBrowserPluginGuest(
86 int instance_id,
87 WebContentsImpl* web_contents) OVERRIDE {
88 return new TestBrowserPluginGuest(instance_id, web_contents);
91 // Also keeps track of number of instances created.
92 virtual BrowserPluginEmbedder* CreateBrowserPluginEmbedder(
93 WebContentsImpl* web_contents) OVERRIDE {
95 return new TestBrowserPluginEmbedder(web_contents);
98 // Singleton getter.
99 static TestBrowserPluginHostFactory* GetInstance() {
100 return Singleton<TestBrowserPluginHostFactory>::get();
103 protected:
104 TestBrowserPluginHostFactory() {}
105 virtual ~TestBrowserPluginHostFactory() {}
107 private:
108 // For Singleton.
109 friend struct DefaultSingletonTraits<TestBrowserPluginHostFactory>;
111 scoped_refptr<MessageLoopRunner> message_loop_runner_;
113 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginHostFactory);
116 class BrowserPluginHostTest : public ContentBrowserTest {
117 public:
118 BrowserPluginHostTest()
119 : test_embedder_(NULL),
120 test_guest_(NULL),
121 test_guest_manager_(NULL) {}
123 virtual void SetUp() OVERRIDE {
124 // Override factory to create tests instances of BrowserPlugin*.
125 BrowserPluginEmbedder::set_factory_for_testing(
126 TestBrowserPluginHostFactory::GetInstance());
127 BrowserPluginGuest::set_factory_for_testing(
128 TestBrowserPluginHostFactory::GetInstance());
129 ContentBrowserTest::SetUp();
131 virtual void TearDown() OVERRIDE {
132 BrowserPluginEmbedder::set_factory_for_testing(NULL);
133 BrowserPluginGuest::set_factory_for_testing(NULL);
135 ContentBrowserTest::TearDown();
138 static void SimulateSpaceKeyPress(WebContents* web_contents) {
139 SimulateKeyPress(web_contents,
140 ui::VKEY_SPACE,
141 false, // control.
142 false, // shift.
143 false, // alt.
144 false); // command.
147 static void SimulateTabKeyPress(WebContents* web_contents) {
148 SimulateKeyPress(web_contents,
149 ui::VKEY_TAB,
150 false, // control.
151 false, // shift.
152 false, // alt.
153 false); // command.
156 // Executes the JavaScript synchronously and makes sure the returned value is
157 // freed properly.
158 void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) {
159 scoped_ptr<base::Value> value =
160 content::ExecuteScriptAndGetValue(rfh, jscript);
163 // This helper method does the following:
164 // 1. Start the test server and navigate the shell to |embedder_url|.
165 // 2. Execute custom pre-navigation |embedder_code| if provided.
166 // 3. Navigate the guest to the |guest_url|.
167 // 4. Verify that the guest has been created and has completed loading.
168 void StartBrowserPluginTest(const std::string& embedder_url,
169 const std::string& guest_url,
170 bool is_guest_data_url,
171 const std::string& embedder_code) {
172 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
173 GURL test_url(embedded_test_server()->GetURL(embedder_url));
174 NavigateToURL(shell(), test_url);
176 WebContentsImpl* embedder_web_contents = static_cast<WebContentsImpl*>(
177 shell()->web_contents());
178 static_cast<ShellBrowserContext*>(
179 embedder_web_contents->GetBrowserContext())->
180 set_guest_manager_for_testing(
181 TestGuestManager::GetInstance());
182 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
183 embedder_web_contents->GetRenderViewHost());
184 RenderFrameHost* rfh = embedder_web_contents->GetMainFrame();
185 // Focus the embedder.
186 rvh->Focus();
187 // Activative IME.
188 rvh->SetInputMethodActive(true);
190 // Allow the test to do some operations on the embedder before we perform
191 // the first navigation of the guest.
192 if (!embedder_code.empty())
193 ExecuteSyncJSFunction(rfh, embedder_code);
195 if (!is_guest_data_url) {
196 test_url = embedded_test_server()->GetURL(guest_url);
197 ExecuteSyncJSFunction(
198 rfh, base::StringPrintf("SetSrc('%s');", test_url.spec().c_str()));
199 } else {
200 ExecuteSyncJSFunction(
201 rfh, base::StringPrintf("SetSrc('%s');", guest_url.c_str()));
204 test_embedder_ = static_cast<TestBrowserPluginEmbedder*>(
205 embedder_web_contents->GetBrowserPluginEmbedder());
206 ASSERT_TRUE(test_embedder_);
208 test_guest_manager_ =
209 static_cast<TestGuestManager*>(
210 embedder_web_contents->GetBrowserContext()->GetGuestManager());
212 WebContentsImpl* test_guest_web_contents =
213 test_guest_manager_->WaitForGuestAdded();
215 test_guest_ = static_cast<TestBrowserPluginGuest*>(
216 test_guest_web_contents->GetBrowserPluginGuest());
217 test_guest_->WaitForLoadStop();
220 TestBrowserPluginEmbedder* test_embedder() const { return test_embedder_; }
221 TestBrowserPluginGuest* test_guest() const { return test_guest_; }
222 TestGuestManager* test_guest_manager() const {
223 return test_guest_manager_;
226 private:
227 TestBrowserPluginEmbedder* test_embedder_;
228 TestBrowserPluginGuest* test_guest_;
229 TestGuestManager* test_guest_manager_;
230 DISALLOW_COPY_AND_ASSIGN(BrowserPluginHostTest);
233 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AdvanceFocus) {
234 const char kEmbedderURL[] = "/browser_plugin_focus.html";
235 const char* kGuestURL = "/browser_plugin_focus_child.html";
236 StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
238 SimulateMouseClick(test_embedder()->web_contents(), 0,
239 blink::WebMouseEvent::ButtonLeft);
240 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
241 // Wait until we focus into the guest.
242 test_guest()->WaitForFocus();
244 // TODO(fsamuel): A third Tab key press should not be necessary.
245 // The browser plugin will take keyboard focus but it will not
246 // focus an initial element. The initial element is dependent
247 // upon tab direction which WebKit does not propagate to the plugin.
248 // See http://crbug.com/147644.
249 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
250 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
251 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
252 test_guest()->WaitForAdvanceFocus();
255 // This test opens a page in http and then opens another page in https, forcing
256 // a RenderViewHost swap in the web_contents. We verify that the embedder in the
257 // web_contents gets cleared properly.
258 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderChangedAfterSwap) {
259 net::SpawnedTestServer https_server(
260 net::SpawnedTestServer::TYPE_HTTPS,
261 net::SpawnedTestServer::kLocalhost,
262 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
263 ASSERT_TRUE(https_server.Start());
265 // 1. Load an embedder page with one guest in it.
266 const char kEmbedderURL[] = "/browser_plugin_embedder.html";
267 StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
269 // 2. Navigate to a URL in https, so we trigger a RenderViewHost swap.
270 GURL test_https_url(https_server.GetURL(
271 "files/browser_plugin_title_change.html"));
272 content::WindowedNotificationObserver swap_observer(
273 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
274 content::Source<WebContents>(test_embedder()->web_contents()));
275 NavigateToURL(shell(), test_https_url);
276 swap_observer.Wait();
278 TestBrowserPluginEmbedder* test_embedder_after_swap =
279 static_cast<TestBrowserPluginEmbedder*>(
280 static_cast<WebContentsImpl*>(shell()->web_contents())->
281 GetBrowserPluginEmbedder());
282 // Verify we have a no embedder in web_contents (since the new page doesn't
283 // have any browser plugin).
284 ASSERT_TRUE(!test_embedder_after_swap);
285 ASSERT_NE(test_embedder(), test_embedder_after_swap);
288 // This test opens two pages in http and there is no RenderViewHost swap,
289 // therefore the embedder created on first page navigation stays the same in
290 // web_contents.
291 // Failing flakily on Windows: crbug.com/308405
292 #if defined(OS_WIN)
293 #define MAYBE_EmbedderSameAfterNav DISABLED_EmbedderSameAfterNav
294 #else
295 #define MAYBE_EmbedderSameAfterNav EmbedderSameAfterNav
296 #endif
297 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, MAYBE_EmbedderSameAfterNav) {
298 const char kEmbedderURL[] = "/browser_plugin_embedder.html";
299 StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
300 WebContentsImpl* embedder_web_contents = test_embedder()->web_contents();
302 // Navigate to another page in same host and port, so RenderViewHost swap
303 // does not happen and existing embedder doesn't change in web_contents.
304 GURL test_url_new(embedded_test_server()->GetURL(
305 "/browser_plugin_title_change.html"));
306 const base::string16 expected_title = ASCIIToUTF16("done");
307 content::TitleWatcher title_watcher(shell()->web_contents(), expected_title);
308 NavigateToURL(shell(), test_url_new);
309 VLOG(0) << "Start waiting for title";
310 base::string16 actual_title = title_watcher.WaitAndGetTitle();
311 EXPECT_EQ(expected_title, actual_title);
312 VLOG(0) << "Done navigating to second page";
314 TestBrowserPluginEmbedder* test_embedder_after_nav =
315 static_cast<TestBrowserPluginEmbedder*>(
316 embedder_web_contents->GetBrowserPluginEmbedder());
317 // Embedder must not change in web_contents.
318 ASSERT_EQ(test_embedder_after_nav, test_embedder());
321 // This tests verifies that reloading the embedder does not crash the browser
322 // and that the guest is reset.
323 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DISABLED_ReloadEmbedder) {
324 const char kEmbedderURL[] = "/browser_plugin_embedder.html";
325 StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
326 RenderFrameHost* rfh = test_embedder()->web_contents()->GetMainFrame();
328 // Change the title of the page to 'modified' so that we know that
329 // the page has successfully reloaded when it goes back to 'embedder'
330 // in the next step.
332 const base::string16 expected_title = ASCIIToUTF16("modified");
333 content::TitleWatcher title_watcher(test_embedder()->web_contents(),
334 expected_title);
336 ExecuteSyncJSFunction(rfh,
337 base::StringPrintf("SetTitle('%s');", "modified"));
339 base::string16 actual_title = title_watcher.WaitAndGetTitle();
340 EXPECT_EQ(expected_title, actual_title);
343 // Reload the embedder page, and verify that the reload was successful.
344 // Then navigate the guest to verify that the browser process does not crash.
346 const base::string16 expected_title = ASCIIToUTF16("embedder");
347 content::TitleWatcher title_watcher(test_embedder()->web_contents(),
348 expected_title);
350 test_embedder()->web_contents()->GetController().Reload(false);
351 base::string16 actual_title = title_watcher.WaitAndGetTitle();
352 EXPECT_EQ(expected_title, actual_title);
354 ExecuteSyncJSFunction(
355 test_embedder()->web_contents()->GetMainFrame(),
356 base::StringPrintf("SetSrc('%s');", kHTMLForGuest));
358 WebContentsImpl* test_guest_web_contents = static_cast<WebContentsImpl*>(
359 test_guest_manager()->WaitForGuestAdded());
360 TestBrowserPluginGuest* new_test_guest =
361 static_cast<TestBrowserPluginGuest*>(
362 test_guest_web_contents->GetBrowserPluginGuest());
363 ASSERT_TRUE(new_test_guest != NULL);
365 // Wait for the guest to send an UpdateRectMsg, meaning it is ready.
366 new_test_guest->WaitForUpdateRectMsg();
370 // Always failing in the win7 try bot. See http://crbug.com/181107.
371 // Times out on the Mac. See http://crbug.com/297576.
372 #if defined(OS_WIN) || defined(OS_MACOSX)
373 #define MAYBE_AcceptDragEvents DISABLED_AcceptDragEvents
374 #else
375 #define MAYBE_AcceptDragEvents AcceptDragEvents
376 #endif
378 // Tests that a drag-n-drop over the browser plugin in the embedder happens
379 // correctly.
380 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, MAYBE_AcceptDragEvents) {
381 const char kEmbedderURL[] = "/browser_plugin_dragging.html";
382 StartBrowserPluginTest(
383 kEmbedderURL, kHTMLForGuestAcceptDrag, true, std::string());
385 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
386 test_embedder()->web_contents()->GetRenderViewHost());
387 RenderFrameHost* rfh = test_embedder()->web_contents()->GetMainFrame();
389 // Get a location in the embedder outside of the plugin.
390 base::ListValue *start, *end;
391 scoped_ptr<base::Value> value =
392 content::ExecuteScriptAndGetValue(rfh, "dragLocation()");
393 ASSERT_TRUE(value->GetAsList(&start) && start->GetSize() == 2);
394 double start_x, start_y;
395 ASSERT_TRUE(start->GetDouble(0, &start_x) && start->GetDouble(1, &start_y));
397 // Get a location in the embedder that falls inside the plugin.
398 value = content::ExecuteScriptAndGetValue(rfh, "dropLocation()");
399 ASSERT_TRUE(value->GetAsList(&end) && end->GetSize() == 2);
400 double end_x, end_y;
401 ASSERT_TRUE(end->GetDouble(0, &end_x) && end->GetDouble(1, &end_y));
403 DropData drop_data;
404 GURL url = GURL("https://www.domain.com/index.html");
405 drop_data.url = url;
407 // Pretend that the URL is being dragged over the embedder. Start the drag
408 // from outside the plugin, then move the drag inside the plugin and drop.
409 // This should trigger appropriate messages from the embedder to the guest,
410 // and end with a drop on the guest. The guest changes title when a drop
411 // happens.
412 const base::string16 expected_title = ASCIIToUTF16("DROPPED");
413 content::TitleWatcher title_watcher(test_guest()->web_contents(),
414 expected_title);
416 rvh->DragTargetDragEnter(drop_data, gfx::Point(start_x, start_y),
417 gfx::Point(start_x, start_y), blink::WebDragOperationEvery, 0);
418 rvh->DragTargetDragOver(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y),
419 blink::WebDragOperationEvery, 0);
420 rvh->DragTargetDrop(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y), 0);
422 base::string16 actual_title = title_watcher.WaitAndGetTitle();
423 EXPECT_EQ(expected_title, actual_title);
426 // This test verifies that round trip postMessage works as expected.
427 // 1. The embedder posts a message 'testing123' to the guest.
428 // 2. The guest receives and replies to the message using the event object's
429 // source object: event.source.postMessage('foobar', '*')
430 // 3. The embedder receives the message and uses the event's source
431 // object to do one final reply: 'stop'
432 // 4. The guest receives the final 'stop' message.
433 // 5. The guest acks the 'stop' message with a 'stop_ack' message.
434 // 6. The embedder changes its title to 'main guest' when it sees the 'stop_ack'
435 // message.
436 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, PostMessage) {
437 const char* kTesting = "testing123";
438 const char* kEmbedderURL = "/browser_plugin_embedder.html";
439 const char* kGuestURL = "/browser_plugin_post_message_guest.html";
440 StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
441 RenderFrameHost* rfh = test_embedder()->web_contents()->GetMainFrame();
443 const base::string16 expected_title = ASCIIToUTF16("main guest");
444 content::TitleWatcher title_watcher(test_embedder()->web_contents(),
445 expected_title);
447 // By the time we get here 'contentWindow' should be ready because the
448 // guest has completed loading.
449 ExecuteSyncJSFunction(
450 rfh, base::StringPrintf("PostMessage('%s, false');", kTesting));
452 // The title will be updated to "main guest" at the last stage of the
453 // process described above.
454 base::string16 actual_title = title_watcher.WaitAndGetTitle();
455 EXPECT_EQ(expected_title, actual_title);
459 // This is the same as BrowserPluginHostTest.PostMessage but also
460 // posts a message to an iframe.
461 // TODO(fsamuel): This test should replace the previous test once postMessage
462 // iframe targeting is fixed (see http://crbug.com/153701).
463 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DISABLED_PostMessageToIFrame) {
464 const char* kTesting = "testing123";
465 const char* kEmbedderURL = "/browser_plugin_embedder.html";
466 const char* kGuestURL = "/browser_plugin_post_message_guest.html";
467 StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
468 RenderFrameHost* rfh = test_embedder()->web_contents()->GetMainFrame();
470 const base::string16 expected_title = ASCIIToUTF16("main guest");
471 content::TitleWatcher title_watcher(test_embedder()->web_contents(),
472 expected_title);
474 ExecuteSyncJSFunction(
475 rfh, base::StringPrintf("PostMessage('%s, false');", kTesting));
477 // The title will be updated to "main guest" at the last stage of the
478 // process described above.
479 base::string16 actual_title = title_watcher.WaitAndGetTitle();
480 EXPECT_EQ(expected_title, actual_title);
483 content::TitleWatcher ready_watcher(test_embedder()->web_contents(),
484 ASCIIToUTF16("ready"));
486 RenderFrameHost* guest_rfh =
487 test_guest()->web_contents()->GetMainFrame();
488 GURL test_url = embedded_test_server()->GetURL(
489 "/browser_plugin_post_message_guest.html");
490 ExecuteSyncJSFunction(
491 guest_rfh,
492 base::StringPrintf(
493 "CreateChildFrame('%s');", test_url.spec().c_str()));
495 base::string16 actual_title = ready_watcher.WaitAndGetTitle();
496 EXPECT_EQ(ASCIIToUTF16("ready"), actual_title);
498 content::TitleWatcher iframe_watcher(test_embedder()->web_contents(),
499 ASCIIToUTF16("iframe"));
500 ExecuteSyncJSFunction(
501 rfh, base::StringPrintf("PostMessage('%s', true);", kTesting));
503 // The title will be updated to "iframe" at the last stage of the
504 // process described above.
505 actual_title = iframe_watcher.WaitAndGetTitle();
506 EXPECT_EQ(ASCIIToUTF16("iframe"), actual_title);
510 // This test verifies that if a browser plugin is hidden before navigation,
511 // the guest starts off hidden.
512 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, HiddenBeforeNavigation) {
513 const char* kEmbedderURL = "/browser_plugin_embedder.html";
514 const std::string embedder_code =
515 "document.getElementById('plugin').style.visibility = 'hidden'";
516 StartBrowserPluginTest(
517 kEmbedderURL, kHTMLForGuest, true, embedder_code);
518 EXPECT_FALSE(test_guest()->visible());
521 // This test verifies that if a browser plugin is focused before navigation then
522 // the guest starts off focused.
523 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusBeforeNavigation) {
524 const char* kEmbedderURL = "/browser_plugin_embedder.html";
525 const std::string embedder_code =
526 "document.getElementById('plugin').focus();";
527 StartBrowserPluginTest(
528 kEmbedderURL, kHTMLForGuest, true, embedder_code);
529 RenderFrameHost* guest_rfh = test_guest()->web_contents()->GetMainFrame();
530 // Verify that the guest is focused.
531 scoped_ptr<base::Value> value =
532 content::ExecuteScriptAndGetValue(guest_rfh, "document.hasFocus()");
533 bool result = false;
534 ASSERT_TRUE(value->GetAsBoolean(&result));
535 EXPECT_TRUE(result);
538 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusTracksEmbedder) {
539 const char* kEmbedderURL = "/browser_plugin_embedder.html";
540 StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
541 // Blur the embedder.
542 test_embedder()->web_contents()->GetRenderViewHost()->Blur();
543 // Ensure that the guest is also blurred.
544 test_guest()->WaitForBlur();
547 // This test verifies that if IME is enabled in the embedder, it is also enabled
548 // in the guest.
549 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, VerifyInputMethodActive) {
550 const char* kEmbedderURL = "/browser_plugin_embedder.html";
551 StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
552 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
553 test_guest()->web_contents()->GetRenderViewHost());
554 EXPECT_TRUE(rvh->input_method_active());
557 // This test exercises the following scenario:
558 // 1. An <input> in guest has focus.
559 // 2. User takes focus to embedder by clicking e.g. an <input> in embedder.
560 // 3. User brings back the focus directly to the <input> in #1.
562 // Now we need to make sure TextInputTypeChange fires properly for the guest's
563 // view (RenderWidgetHostViewGuest) upon step #3. This test ensures that,
564 // otherwise IME doesn't work after step #3.
565 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusRestored) {
566 const char kEmbedderURL[] = "/browser_plugin_embedder.html";
567 const char kGuestHTML[] = "data:text/html,"
568 "<html><body><input id=\"input1\"></body>"
569 "<script>"
570 "var i = document.getElementById(\"input1\");"
571 "document.body.addEventListener(\"click\", function(e) {"
572 " i.focus();"
573 "});"
574 "i.addEventListener(\"focus\", function(e) {"
575 " document.title = \"FOCUS\";"
576 "});"
577 "i.addEventListener(\"blur\", function(e) {"
578 " document.title = \"BLUR\";"
579 "});"
580 "</script>"
581 "</html>";
582 StartBrowserPluginTest(kEmbedderURL, kGuestHTML, true,
583 "document.getElementById(\"plugin\").focus();");
585 ASSERT_TRUE(test_embedder());
586 const char *kTitles[3] = {"FOCUS", "BLUR", "FOCUS"};
587 gfx::Point kClickPoints[3] = {
588 gfx::Point(20, 20), gfx::Point(700, 20), gfx::Point(20, 20)
591 for (int i = 0; i < 3; ++i) {
592 base::string16 expected_title = base::UTF8ToUTF16(kTitles[i]);
593 content::TitleWatcher title_watcher(test_guest()->web_contents(),
594 expected_title);
595 SimulateMouseClickAt(test_embedder()->web_contents(), 0,
596 blink::WebMouseEvent::ButtonLeft,
597 kClickPoints[i]);
598 base::string16 actual_title = title_watcher.WaitAndGetTitle();
599 EXPECT_EQ(expected_title, actual_title);
601 TestBrowserPluginGuest* guest = test_guest();
602 ASSERT_TRUE(guest);
603 ui::TextInputType text_input_type = guest->last_text_input_type();
604 ASSERT_TRUE(text_input_type != ui::TEXT_INPUT_TYPE_NONE);
607 // Tests input method.
608 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, InputMethod) {
609 const char kEmbedderURL[] = "/browser_plugin_embedder.html";
610 const char kGuestHTML[] = "data:text/html,"
611 "<html><body><input id=\"input1\">"
612 "<input id=\"input2\"></body>"
613 "<script>"
614 "var i = document.getElementById(\"input1\");"
615 "i.oninput = function() {"
616 " document.title = i.value;"
618 "</script>"
619 "</html>";
620 StartBrowserPluginTest(kEmbedderURL, kGuestHTML, true,
621 "document.getElementById(\"plugin\").focus();");
623 RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
624 test_embedder()->web_contents()->GetRenderViewHost());
625 RenderFrameHost* guest_rfh = test_guest()->web_contents()->GetMainFrame();
627 std::vector<blink::WebCompositionUnderline> underlines;
629 // An input field in browser plugin guest gets focus and given some user
630 // input via IME.
632 ExecuteSyncJSFunction(guest_rfh,
633 "document.getElementById('input1').focus();");
634 base::string16 expected_title = base::UTF8ToUTF16("InputTest123");
635 content::TitleWatcher title_watcher(test_guest()->web_contents(),
636 expected_title);
637 embedder_rvh->Send(
638 new ViewMsg_ImeSetComposition(
639 test_embedder()->web_contents()->GetRoutingID(),
640 expected_title,
641 underlines,
642 12, 12));
643 base::string16 actual_title = title_watcher.WaitAndGetTitle();
644 EXPECT_EQ(expected_title, actual_title);
646 // A composition is committed via IME.
648 base::string16 expected_title = base::UTF8ToUTF16("InputTest456");
649 content::TitleWatcher title_watcher(test_guest()->web_contents(),
650 expected_title);
651 embedder_rvh->Send(
652 new ViewMsg_ImeConfirmComposition(
653 test_embedder()->web_contents()->GetRoutingID(),
654 expected_title,
655 gfx::Range(),
656 true));
657 base::string16 actual_title = title_watcher.WaitAndGetTitle();
658 EXPECT_EQ(expected_title, actual_title);
660 // IME composition starts, but focus moves out, then the composition will
661 // be committed and get cancel msg.
663 ExecuteSyncJSFunction(guest_rfh,
664 "document.getElementById('input1').value = '';");
665 base::string16 composition = base::UTF8ToUTF16("InputTest789");
666 content::TitleWatcher title_watcher(test_guest()->web_contents(),
667 composition);
668 embedder_rvh->Send(
669 new ViewMsg_ImeSetComposition(
670 test_embedder()->web_contents()->GetRoutingID(),
671 composition,
672 underlines,
673 12, 12));
674 base::string16 actual_title = title_watcher.WaitAndGetTitle();
675 EXPECT_EQ(composition, actual_title);
676 // Moving focus causes IME cancel, and the composition will be committed
677 // in input1, not in input2.
678 ExecuteSyncJSFunction(guest_rfh,
679 "document.getElementById('input2').focus();");
680 test_guest()->WaitForImeCancel();
681 scoped_ptr<base::Value> value =
682 content::ExecuteScriptAndGetValue(
683 guest_rfh, "document.getElementById('input1').value");
684 std::string result;
685 ASSERT_TRUE(value->GetAsString(&result));
686 EXPECT_EQ(base::UTF16ToUTF8(composition), result);
688 // Tests ExtendSelectionAndDelete message works in browser_plugin.
690 // Set 'InputTestABC' in input1 and put caret at 6 (after 'T').
691 ExecuteSyncJSFunction(guest_rfh,
692 "var i = document.getElementById('input1');"
693 "i.focus();"
694 "i.value = 'InputTestABC';"
695 "i.selectionStart=6;"
696 "i.selectionEnd=6;");
697 base::string16 expected_value = base::UTF8ToUTF16("InputABC");
698 content::TitleWatcher title_watcher(test_guest()->web_contents(),
699 expected_value);
700 // Delete 'Test' in 'InputTestABC', as the caret is after 'T':
701 // delete before 1 character ('T') and after 3 characters ('est').
702 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
703 test_embedder()->web_contents()->GetFocusedFrame());
704 rfh->ExtendSelectionAndDelete(1, 3);
705 base::string16 actual_title = title_watcher.WaitAndGetTitle();
706 EXPECT_EQ(expected_value, actual_title);
707 scoped_ptr<base::Value> value =
708 content::ExecuteScriptAndGetValue(
709 guest_rfh, "document.getElementById('input1').value");
710 std::string actual_value;
711 ASSERT_TRUE(value->GetAsString(&actual_value));
712 EXPECT_EQ(base::UTF16ToUTF8(expected_value), actual_value);
716 } // namespace content