blob: 3476548135e509d4951aabe6f85744cdcaea78ed [file] [log] [blame]
paulmeyera41de3b2016-05-05 16:30:181// Copyright 2016 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/command_line.h"
6#include "base/strings/utf_string_conversions.h"
Makoto Shimazu3266e2f52017-10-31 04:30:077#include "build/build_config.h"
paulmeyera41de3b2016-05-05 16:30:188#include "content/browser/web_contents/web_contents_impl.h"
9#include "content/public/browser/notification_types.h"
10#include "content/public/common/content_switches.h"
paulmeyer3ac612d2016-09-30 19:21:0611#include "content/public/test/browser_test_utils.h"
paulmeyera41de3b2016-05-05 16:30:1812#include "content/public/test/content_browser_test.h"
13#include "content/public/test/content_browser_test_utils.h"
paulmeyerda992f52017-01-27 17:11:2814#include "content/public/test/find_test_utils.h"
paulmeyera41de3b2016-05-05 16:30:1815#include "content/public/test/test_navigation_observer.h"
16#include "content/public/test/test_utils.h"
17#include "content/shell/browser/shell.h"
paulmeyerc8cb7cb2016-06-07 01:14:1918#include "content/test/content_browser_test_utils_internal.h"
paulmeyera41de3b2016-05-05 16:30:1819#include "net/dns/mock_host_resolver.h"
20#include "third_party/WebKit/public/web/WebFindOptions.h"
21
22namespace content {
23
24namespace {
25
26const int kInvalidId = -1;
27
paulmeyera41de3b2016-05-05 16:30:1828} // namespace
29
paulmeyerc8cb7cb2016-06-07 01:14:1930class FindRequestManagerTest : public ContentBrowserTest,
31 public testing::WithParamInterface<bool> {
paulmeyera41de3b2016-05-05 16:30:1832 public:
33 FindRequestManagerTest()
34 : normal_delegate_(nullptr),
35 last_request_id_(0) {}
36 ~FindRequestManagerTest() override {}
37
38 void SetUpOnMainThread() override {
39 host_resolver()->AddRule("*", "127.0.0.1");
40 ASSERT_TRUE(embedded_test_server()->Start());
41
42 // Swap the WebContents's delegate for our test delegate.
43 normal_delegate_ = contents()->GetDelegate();
44 contents()->SetDelegate(&test_delegate_);
45 }
46
47 void TearDownOnMainThread() override {
48 // Swap the WebContents's delegate back to its usual delegate.
49 contents()->SetDelegate(normal_delegate_);
50 }
51
paulmeyerc8cb7cb2016-06-07 01:14:1952#if !defined(OS_ANDROID)
paulmeyera41de3b2016-05-05 16:30:1853 void SetUpCommandLine(base::CommandLine* command_line) override {
54 IsolateAllSitesForTesting(command_line);
55 }
paulmeyerc8cb7cb2016-06-07 01:14:1956#endif
paulmeyera41de3b2016-05-05 16:30:1857
58 protected:
paulmeyerc8cb7cb2016-06-07 01:14:1959 // Navigates to |url| and waits for it to finish loading.
paulmeyera41de3b2016-05-05 16:30:1860 void LoadAndWait(const std::string& url) {
61 TestNavigationObserver navigation_observer(contents());
62 NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url));
paulmeyerda992f52017-01-27 17:11:2863 ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
paulmeyera41de3b2016-05-05 16:30:1864 }
65
paulmeyerc8cb7cb2016-06-07 01:14:1966 // Loads a multi-frame page. The page will have a full binary frame tree of
67 // height |height|. If |cross_process| is true, child frames will be loaded
68 // cross-process.
69 void LoadMultiFramePage(int height, bool cross_process) {
70 LoadAndWait("/find_in_page_multi_frame.html");
paulmeyer74f68c92016-08-12 22:34:1371 FrameTreeNode* root = contents()->GetFrameTree()->root();
paulmeyerc8cb7cb2016-06-07 01:14:1972 LoadMultiFramePageChildFrames(height, cross_process, root);
73 }
74
75 // Reloads the child frame cross-process.
76 void MakeChildFrameCrossProcess() {
paulmeyer74f68c92016-08-12 22:34:1377 FrameTreeNode* root = contents()->GetFrameTree()->root();
78 FrameTreeNode* child = root->child_at(0);
79 GURL url(embedded_test_server()->GetURL(
80 "b.com", child->current_url().path()));
paulmeyerc8cb7cb2016-06-07 01:14:1981
82 TestNavigationObserver observer(shell()->web_contents());
paulmeyerc8cb7cb2016-06-07 01:14:1983 NavigateFrameToURL(child, url);
84 EXPECT_EQ(url, observer.last_navigation_url());
85 EXPECT_TRUE(observer.last_navigation_succeeded());
86 }
87
paulmeyera41de3b2016-05-05 16:30:1888 void Find(const std::string& search_text,
89 const blink::WebFindOptions& options) {
paulmeyer2f06e612016-08-10 17:39:0290 delegate()->UpdateLastRequest(++last_request_id_);
91 contents()->Find(last_request_id_,
paulmeyera41de3b2016-05-05 16:30:1892 base::UTF8ToUTF16(search_text),
93 options);
94 }
95
paulmeyer74f68c92016-08-12 22:34:1396 WebContentsImpl* contents() const {
97 return static_cast<WebContentsImpl*>(shell()->web_contents());
paulmeyera41de3b2016-05-05 16:30:1898 }
99
paulmeyerda992f52017-01-27 17:11:28100 FindTestWebContentsDelegate* delegate() const {
101 return static_cast<FindTestWebContentsDelegate*>(contents()->GetDelegate());
paulmeyera41de3b2016-05-05 16:30:18102 }
103
104 int last_request_id() const {
105 return last_request_id_;
106 }
107
108 private:
paulmeyerc8cb7cb2016-06-07 01:14:19109 // Helper function for LoadMultiFramePage. Loads child frames until the frame
110 // tree rooted at |root| is a full binary tree of height |height|.
111 void LoadMultiFramePageChildFrames(int height,
112 bool cross_process,
113 FrameTreeNode* root) {
114 if (height == 0)
115 return;
116
117 std::string hostname = root->current_origin().host();
118 if (cross_process)
119 hostname.insert(0, 1, 'a');
120 GURL url(embedded_test_server()->GetURL(hostname,
121 "/find_in_page_multi_frame.html"));
122
123 TestNavigationObserver observer(shell()->web_contents());
124
125 FrameTreeNode* child = root->child_at(0);
126 NavigateFrameToURL(child, url);
127 EXPECT_TRUE(observer.last_navigation_succeeded());
128 LoadMultiFramePageChildFrames(height - 1, cross_process, child);
129
130 child = root->child_at(1);
131 NavigateFrameToURL(child, url);
132 EXPECT_TRUE(observer.last_navigation_succeeded());
133 LoadMultiFramePageChildFrames(height - 1, cross_process, child);
134 }
135
paulmeyerda992f52017-01-27 17:11:28136 FindTestWebContentsDelegate test_delegate_;
paulmeyera41de3b2016-05-05 16:30:18137 WebContentsDelegate* normal_delegate_;
138
139 // The ID of the last find request requested.
140 int last_request_id_;
141
142 DISALLOW_COPY_AND_ASSIGN(FindRequestManagerTest);
143};
144
paulmeyerc8cb7cb2016-06-07 01:14:19145// Frames are made cross-process when the test param is set to
146// true. Cross-process frames are not used on android.
147#if defined(OS_ANDROID)
148INSTANTIATE_TEST_CASE_P(
149 FindRequestManagerTests, FindRequestManagerTest, testing::Values(false));
150#else
151INSTANTIATE_TEST_CASE_P(
152 FindRequestManagerTests, FindRequestManagerTest, testing::Bool());
153#endif
paulmeyera41de3b2016-05-05 16:30:18154
torne65fee8192016-10-25 12:09:03155// TODO(crbug.com/615291): These tests frequently fail on Android.
156#if defined(OS_ANDROID)
paulmeyercc9a00f92016-07-06 13:44:27157#define MAYBE(x) DISABLED_##x
paulmeyerc8cb7cb2016-06-07 01:14:19158#else
paulmeyercc9a00f92016-07-06 13:44:27159#define MAYBE(x) x
paulmeyerc8cb7cb2016-06-07 01:14:19160#endif
161
162
163// Tests basic find-in-page functionality (such as searching forward and
paulmeyera41de3b2016-05-05 16:30:18164// backward) and check for correct results at each step.
paulmeyercc9a00f92016-07-06 13:44:27165IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(Basic)) {
paulmeyera41de3b2016-05-05 16:30:18166 LoadAndWait("/find_in_page.html");
paulmeyerc8cb7cb2016-06-07 01:14:19167 if (GetParam())
168 MakeChildFrameCrossProcess();
paulmeyera41de3b2016-05-05 16:30:18169
170 blink::WebFindOptions options;
171 Find("result", options);
paulmeyer2f06e612016-08-10 17:39:02172 delegate()->WaitForFinalReply();
paulmeyera41de3b2016-05-05 16:30:18173
174 FindResults results = delegate()->GetFindResults();
175 EXPECT_EQ(last_request_id(), results.request_id);
176 EXPECT_EQ(19, results.number_of_matches);
177 EXPECT_EQ(1, results.active_match_ordinal);
178
Blink Reformat1c4d759e2017-04-09 16:34:54179 options.find_next = true;
paulmeyera41de3b2016-05-05 16:30:18180 for (int i = 2; i <= 10; ++i) {
181 Find("result", options);
paulmeyer2f06e612016-08-10 17:39:02182 delegate()->WaitForFinalReply();
paulmeyera41de3b2016-05-05 16:30:18183
184 results = delegate()->GetFindResults();
185 EXPECT_EQ(last_request_id(), results.request_id);
186 EXPECT_EQ(19, results.number_of_matches);
187 EXPECT_EQ(i, results.active_match_ordinal);
188 }
189
190 options.forward = false;
191 for (int i = 9; i >= 5; --i) {
192 Find("result", options);
paulmeyer2f06e612016-08-10 17:39:02193 delegate()->WaitForFinalReply();
paulmeyera41de3b2016-05-05 16:30:18194
195 results = delegate()->GetFindResults();
196 EXPECT_EQ(last_request_id(), results.request_id);
197 EXPECT_EQ(19, results.number_of_matches);
198 EXPECT_EQ(i, results.active_match_ordinal);
199 }
200}
201
202// Tests searching for a word character-by-character, as would typically be done
203// by a user typing into the find bar.
paulmeyercc9a00f92016-07-06 13:44:27204IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(CharacterByCharacter)) {
paulmeyera41de3b2016-05-05 16:30:18205 LoadAndWait("/find_in_page.html");
paulmeyerc8cb7cb2016-06-07 01:14:19206 if (GetParam())
207 MakeChildFrameCrossProcess();
paulmeyera41de3b2016-05-05 16:30:18208
209 blink::WebFindOptions default_options;
210 Find("r", default_options);
211 Find("re", default_options);
212 Find("res", default_options);
213 Find("resu", default_options);
214 Find("resul", default_options);
215 Find("result", default_options);
paulmeyer2f06e612016-08-10 17:39:02216 delegate()->WaitForFinalReply();
paulmeyera41de3b2016-05-05 16:30:18217
218 FindResults results = delegate()->GetFindResults();
219 EXPECT_EQ(last_request_id(), results.request_id);
220 EXPECT_EQ(19, results.number_of_matches);
221 EXPECT_EQ(1, results.active_match_ordinal);
222}
223
rjkroege4096df62016-12-16 00:49:08224// TODO(crbug.com/615291): This test frequently fails on Android.
225// TODO(crbug.com/674742): This test is flaky on Win
226#if defined(OS_ANDROID) || defined(OS_WIN)
227#define MAYBE_RapidFire DISABLED_RapidFire
228#else
229#define MAYBE_RapidFire RapidFire
230#endif
231
paulmeyerc8cb7cb2016-06-07 01:14:19232// Tests sending a large number of find requests subsequently.
rjkroege4096df62016-12-16 00:49:08233IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE_RapidFire) {
paulmeyera41de3b2016-05-05 16:30:18234 LoadAndWait("/find_in_page.html");
paulmeyerc8cb7cb2016-06-07 01:14:19235 if (GetParam())
236 MakeChildFrameCrossProcess();
paulmeyera41de3b2016-05-05 16:30:18237
238 blink::WebFindOptions options;
239 Find("result", options);
240
Blink Reformat1c4d759e2017-04-09 16:34:54241 options.find_next = true;
paulmeyera41de3b2016-05-05 16:30:18242 for (int i = 2; i <= 1000; ++i)
243 Find("result", options);
paulmeyer2f06e612016-08-10 17:39:02244 delegate()->WaitForFinalReply();
paulmeyera41de3b2016-05-05 16:30:18245
246 FindResults results = delegate()->GetFindResults();
247 EXPECT_EQ(last_request_id(), results.request_id);
248 EXPECT_EQ(19, results.number_of_matches);
249 EXPECT_EQ(last_request_id() % results.number_of_matches,
250 results.active_match_ordinal);
251}
252
paulmeyerc8cb7cb2016-06-07 01:14:19253// Tests removing a frame during a find session.
mek98430952016-11-29 01:34:46254// TODO(crbug.com/657331): Test is flaky on all platforms.
255IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, DISABLED_RemoveFrame) {
paulmeyerc8cb7cb2016-06-07 01:14:19256 LoadMultiFramePage(2 /* height */, GetParam() /* cross_process */);
257
258 blink::WebFindOptions options;
259 Find("result", options);
paulmeyerdc6a6442016-08-19 16:48:28260 delegate()->WaitForFinalReply();
Blink Reformat1c4d759e2017-04-09 16:34:54261 options.find_next = true;
paulmeyerc8cb7cb2016-06-07 01:14:19262 options.forward = false;
263 Find("result", options);
264 Find("result", options);
265 Find("result", options);
266 Find("result", options);
267 Find("result", options);
paulmeyer2f06e612016-08-10 17:39:02268 delegate()->WaitForFinalReply();
paulmeyerc8cb7cb2016-06-07 01:14:19269
270 FindResults results = delegate()->GetFindResults();
271 EXPECT_EQ(last_request_id(), results.request_id);
272 EXPECT_EQ(21, results.number_of_matches);
273 EXPECT_EQ(17, results.active_match_ordinal);
274
275 // Remove a frame.
paulmeyer74f68c92016-08-12 22:34:13276 FrameTreeNode* root = contents()->GetFrameTree()->root();
paulmeyerc8cb7cb2016-06-07 01:14:19277 root->RemoveChild(root->child_at(0));
278
279 // The number of matches and active match ordinal should update automatically
280 // to exclude the matches from the removed frame.
281 results = delegate()->GetFindResults();
paulmeyerc8cb7cb2016-06-07 01:14:19282 EXPECT_EQ(12, results.number_of_matches);
283 EXPECT_EQ(8, results.active_match_ordinal);
paulmeyer3ac612d2016-09-30 19:21:06284}
paulmeyerc8cb7cb2016-06-07 01:14:19285
paulmeyer3ac612d2016-09-30 19:21:06286// Tests adding a frame during a find session.
mek98430952016-11-29 01:34:46287// TODO(crbug.com/657331): Test is flaky on all platforms.
288IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, DISABLED_AddFrame) {
paulmeyer3ac612d2016-09-30 19:21:06289 LoadMultiFramePage(2 /* height */, GetParam() /* cross_process */);
290
291 blink::WebFindOptions options;
292 Find("result", options);
Blink Reformat1c4d759e2017-04-09 16:34:54293 options.find_next = true;
paulmeyer3ac612d2016-09-30 19:21:06294 Find("result", options);
295 Find("result", options);
296 Find("result", options);
297 Find("result", options);
298 delegate()->WaitForFinalReply();
299
300 FindResults results = delegate()->GetFindResults();
301 EXPECT_EQ(last_request_id(), results.request_id);
302 EXPECT_EQ(21, results.number_of_matches);
303 EXPECT_EQ(5, results.active_match_ordinal);
304
305 // Add a frame. It contains 5 new matches.
306 std::string url = embedded_test_server()->GetURL(
307 GetParam() ? "b.com" : "a.com", "/find_in_simple_page.html").spec();
308 std::string script = std::string() +
309 "var frame = document.createElement('iframe');" +
310 "frame.src = '" + url + "';" +
311 "document.body.appendChild(frame);";
312 delegate()->MarkNextReply();
313 ASSERT_TRUE(ExecuteScript(shell(), script));
314 delegate()->WaitForNextReply();
315
316 // The number of matches should update automatically to include the matches
317 // from the newly added frame.
318 results = delegate()->GetFindResults();
319 EXPECT_EQ(26, results.number_of_matches);
320 EXPECT_EQ(5, results.active_match_ordinal);
321}
322
323// Tests adding a frame during a find session where there were previously no
324// matches.
325IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(AddFrameAfterNoMatches)) {
326 TestNavigationObserver navigation_observer(contents());
327 NavigateToURL(shell(), GURL("about:blank"));
328 EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
329
330 blink::WebFindOptions default_options;
331 Find("result", default_options);
332 delegate()->WaitForFinalReply();
333
334 // Initially, there are no matches on the page.
335 FindResults results = delegate()->GetFindResults();
336 EXPECT_EQ(last_request_id(), results.request_id);
337 EXPECT_EQ(0, results.number_of_matches);
338 EXPECT_EQ(0, results.active_match_ordinal);
339
340 // Add a frame. It contains 5 new matches.
341 std::string url =
342 embedded_test_server()->GetURL("/find_in_simple_page.html").spec();
343 std::string script = std::string() +
344 "var frame = document.createElement('iframe');" +
345 "frame.src = '" + url + "';" +
346 "document.body.appendChild(frame);";
347 delegate()->MarkNextReply();
348 ASSERT_TRUE(ExecuteScript(shell(), script));
349 delegate()->WaitForNextReply();
350
351 // The matches from the new frame should be found automatically, and the first
352 // match in the frame should be activated.
353 results = delegate()->GetFindResults();
354 EXPECT_EQ(5, results.number_of_matches);
355 EXPECT_EQ(1, results.active_match_ordinal);
356}
357
358// Tests a frame navigating to a different page during a find session.
359IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(NavigateFrame)) {
360 LoadMultiFramePage(2 /* height */, GetParam() /* cross_process */);
361
362 blink::WebFindOptions options;
363 Find("result", options);
Blink Reformat1c4d759e2017-04-09 16:34:54364 options.find_next = true;
paulmeyer3ac612d2016-09-30 19:21:06365 options.forward = false;
366 Find("result", options);
367 Find("result", options);
368 Find("result", options);
369 delegate()->WaitForFinalReply();
370
371 FindResults results = delegate()->GetFindResults();
372 EXPECT_EQ(last_request_id(), results.request_id);
373 EXPECT_EQ(21, results.number_of_matches);
374 EXPECT_EQ(19, results.active_match_ordinal);
375
376 // Navigate one of the empty frames to a page with 5 matches.
377 FrameTreeNode* root =
378 static_cast<WebContentsImpl*>(shell()->web_contents())->
379 GetFrameTree()->root();
380 GURL url(embedded_test_server()->GetURL(
381 GetParam() ? "b.com" : "a.com", "/find_in_simple_page.html"));
382 delegate()->MarkNextReply();
383 TestNavigationObserver navigation_observer(contents());
384 NavigateFrameToURL(root->child_at(0)->child_at(1)->child_at(0), url);
385 EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
386 delegate()->WaitForNextReply();
387
388 // The navigation results in an extra reply before the one we care about. This
389 // extra reply happens because the RenderFrameHost changes before it navigates
390 // (because the navigation is cross-origin). The first reply will not change
391 // the number of matches because the frame that is navigating was empty
392 // before.
393 if (delegate()->GetFindResults().number_of_matches == 21) {
394 delegate()->MarkNextReply();
395 delegate()->WaitForNextReply();
396 }
397
398 // The number of matches and the active match ordinal should update
399 // automatically to include the new matches.
400 results = delegate()->GetFindResults();
401 EXPECT_EQ(26, results.number_of_matches);
402 EXPECT_EQ(24, results.active_match_ordinal);
paulmeyerc8cb7cb2016-06-07 01:14:19403}
404
405// Tests Searching in a hidden frame. Matches in the hidden frame should be
406// ignored.
paulmeyercc9a00f92016-07-06 13:44:27407IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(HiddenFrame)) {
paulmeyerc8cb7cb2016-06-07 01:14:19408 LoadAndWait("/find_in_hidden_frame.html");
409
410 blink::WebFindOptions default_options;
411 Find("hello", default_options);
paulmeyer2f06e612016-08-10 17:39:02412 delegate()->WaitForFinalReply();
paulmeyerc8cb7cb2016-06-07 01:14:19413 FindResults results = delegate()->GetFindResults();
414
415 EXPECT_EQ(last_request_id(), results.request_id);
416 EXPECT_EQ(1, results.number_of_matches);
417 EXPECT_EQ(1, results.active_match_ordinal);
418}
419
paulmeyer74f68c92016-08-12 22:34:13420// Tests that new matches can be found in dynamically added text.
421IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(FindNewMatches)) {
422 LoadAndWait("/find_in_dynamic_page.html");
423
424 blink::WebFindOptions options;
425 Find("result", options);
Blink Reformat1c4d759e2017-04-09 16:34:54426 options.find_next = true;
paulmeyer74f68c92016-08-12 22:34:13427 Find("result", options);
428 Find("result", options);
429 delegate()->WaitForFinalReply();
430
431 FindResults results = delegate()->GetFindResults();
432 EXPECT_EQ(last_request_id(), results.request_id);
433 EXPECT_EQ(3, results.number_of_matches);
434 EXPECT_EQ(3, results.active_match_ordinal);
435
436 // Dynamically add new text to the page. This text contains 5 new matches for
437 // "result".
438 ASSERT_TRUE(ExecuteScript(contents()->GetMainFrame(), "addNewText()"));
439
440 Find("result", options);
441 delegate()->WaitForFinalReply();
442
443 results = delegate()->GetFindResults();
444 EXPECT_EQ(last_request_id(), results.request_id);
445 EXPECT_EQ(8, results.number_of_matches);
446 EXPECT_EQ(4, results.active_match_ordinal);
447}
448
Makoto Shimazu3266e2f52017-10-31 04:30:07449// TODO(crbug.com/615291): These tests frequently fail on Android.
450// TODO(crbug.com/779912): Flaky timeout on Win7 (dbg).
451#if defined(OS_ANDROID) || (defined(OS_WIN) && !defined(NDEBUG))
452#define MAYBE_FindInPage_Issue627799 DISABLED_FindInPage_Issue627799
453#else
454#define MAYBE_FindInPage_Issue627799 FindInPage_Issue627799
455#endif
456
457IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE_FindInPage_Issue627799) {
paulmeyerdc6a6442016-08-19 16:48:28458 LoadAndWait("/find_in_long_page.html");
459
460 blink::WebFindOptions options;
461 Find("42", options);
462 delegate()->WaitForFinalReply();
463
464 FindResults results = delegate()->GetFindResults();
465 EXPECT_EQ(last_request_id(), results.request_id);
466 EXPECT_EQ(970, results.number_of_matches);
467 EXPECT_EQ(1, results.active_match_ordinal);
468
469 delegate()->StartReplyRecord();
Blink Reformat1c4d759e2017-04-09 16:34:54470 options.find_next = true;
paulmeyerdc6a6442016-08-19 16:48:28471 options.forward = false;
472 Find("42", options);
473 delegate()->WaitForFinalReply();
474
475 // This is the crux of the issue that this test guards against. Searching
476 // across the frame boundary should not cause the frame to be re-scoped. If
477 // the re-scope occurs, then we will see the number of matches change in one
478 // of the recorded find replies.
479 for (auto& reply : delegate()->GetReplyRecord()) {
480 EXPECT_EQ(last_request_id(), reply.request_id);
481 EXPECT_TRUE(reply.number_of_matches == kInvalidId ||
482 reply.number_of_matches == results.number_of_matches);
483 }
484}
485
paulmeyerd3b32d52016-09-07 22:24:55486IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(FindInPage_Issue644448)) {
487 TestNavigationObserver navigation_observer(contents());
488 NavigateToURL(shell(), GURL("about:blank"));
489 EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
490
491 blink::WebFindOptions default_options;
492 Find("result", default_options);
493 delegate()->WaitForFinalReply();
494
495 // Initially, there are no matches on the page.
496 FindResults results = delegate()->GetFindResults();
497 EXPECT_EQ(last_request_id(), results.request_id);
498 EXPECT_EQ(0, results.number_of_matches);
499 EXPECT_EQ(0, results.active_match_ordinal);
500
501 // Load a page with matches.
502 LoadAndWait("/find_in_simple_page.html");
503
504 Find("result", default_options);
505 delegate()->WaitForFinalReply();
506
507 // There should now be matches found. When the bug was present, there were
508 // still no matches found.
509 results = delegate()->GetFindResults();
510 EXPECT_EQ(last_request_id(), results.request_id);
511 EXPECT_EQ(5, results.number_of_matches);
paulmeyerd3b32d52016-09-07 22:24:55512}
513
paulmeyerc8cb7cb2016-06-07 01:14:19514#if defined(OS_ANDROID)
515// Tests requesting find match rects.
paulmeyercc9a00f92016-07-06 13:44:27516IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(FindMatchRects)) {
paulmeyerc8cb7cb2016-06-07 01:14:19517 LoadAndWait("/find_in_page.html");
518
519 blink::WebFindOptions default_options;
520 Find("result", default_options);
paulmeyer2f06e612016-08-10 17:39:02521 delegate()->WaitForFinalReply();
paulmeyerc8cb7cb2016-06-07 01:14:19522 EXPECT_EQ(19, delegate()->GetFindResults().number_of_matches);
523
524 // Request the find match rects.
525 contents()->RequestFindMatchRects(-1);
526 delegate()->WaitForMatchRects();
527 const std::vector<gfx::RectF>& rects = delegate()->find_match_rects();
528
529 // The first match should be active.
530 EXPECT_EQ(rects[0], delegate()->active_match_rect());
531
532 // All results after the first two should be between them in find-in-page
533 // coordinates. This is because results 2 to 19 are inside an iframe located
534 // between results 0 and 1. This applies to the fixed div too.
535 EXPECT_LT(rects[0].y(), rects[1].y());
536 for (int i = 2; i < 19; ++i) {
537 EXPECT_LT(rects[0].y(), rects[i].y());
538 EXPECT_GT(rects[1].y(), rects[i].y());
539 }
540
541 // Result 3 should be below results 2 and 4. This is caused by the CSS
542 // transform in the containing div. If the transform doesn't work then result
543 // 3 will be between results 2 and 4.
544 EXPECT_GT(rects[3].y(), rects[2].y());
545 EXPECT_GT(rects[3].y(), rects[4].y());
546
547 // Results 6, 7, 8 and 9 should be one below the other in that same order. If
548 // overflow:scroll is not properly handled then result 8 would be below result
549 // 9 or result 7 above result 6 depending on the scroll.
550 EXPECT_LT(rects[6].y(), rects[7].y());
551 EXPECT_LT(rects[7].y(), rects[8].y());
552 EXPECT_LT(rects[8].y(), rects[9].y());
553
554 // Results 11, 12, 13 and 14 should be between results 10 and 15, as they are
555 // inside the table.
556 EXPECT_GT(rects[11].y(), rects[10].y());
557 EXPECT_GT(rects[12].y(), rects[10].y());
558 EXPECT_GT(rects[13].y(), rects[10].y());
559 EXPECT_GT(rects[14].y(), rects[10].y());
560 EXPECT_LT(rects[11].y(), rects[15].y());
561 EXPECT_LT(rects[12].y(), rects[15].y());
562 EXPECT_LT(rects[13].y(), rects[15].y());
563 EXPECT_LT(rects[14].y(), rects[15].y());
564
565 // Result 11 should be above results 12, 13 and 14 as it's in the table
566 // header.
567 EXPECT_LT(rects[11].y(), rects[12].y());
568 EXPECT_LT(rects[11].y(), rects[13].y());
569 EXPECT_LT(rects[11].y(), rects[14].y());
570
571 // Result 11 should also be right of results 12, 13 and 14 because of the
572 // colspan.
573 EXPECT_GT(rects[11].x(), rects[12].x());
574 EXPECT_GT(rects[11].x(), rects[13].x());
575 EXPECT_GT(rects[11].x(), rects[14].x());
576
577 // Result 12 should be left of results 11, 13 and 14 in the table layout.
578 EXPECT_LT(rects[12].x(), rects[11].x());
579 EXPECT_LT(rects[12].x(), rects[13].x());
580 EXPECT_LT(rects[12].x(), rects[14].x());
581
582 // Results 13, 12 and 14 should be one above the other in that order because
583 // of the rowspan and vertical-align: middle by default.
584 EXPECT_LT(rects[13].y(), rects[12].y());
585 EXPECT_LT(rects[12].y(), rects[14].y());
586
587 // Result 16 should be below result 15.
588 EXPECT_GT(rects[15].y(), rects[14].y());
589
590 // Result 18 should be normalized with respect to the position:relative div,
591 // and not it's immediate containing div. Consequently, result 18 should be
592 // above result 17.
593 EXPECT_GT(rects[17].y(), rects[18].y());
594}
595
596// Tests activating the find match nearest to a given point.
paulmeyercc9a00f92016-07-06 13:44:27597IN_PROC_BROWSER_TEST_F(FindRequestManagerTest,
598 MAYBE(ActivateNearestFindMatch)) {
paulmeyerc8cb7cb2016-06-07 01:14:19599 LoadAndWait("/find_in_page.html");
600
601 blink::WebFindOptions default_options;
602 Find("result", default_options);
paulmeyer2f06e612016-08-10 17:39:02603 delegate()->WaitForFinalReply();
paulmeyerc8cb7cb2016-06-07 01:14:19604 EXPECT_EQ(19, delegate()->GetFindResults().number_of_matches);
605
606 // Get the find match rects.
607 contents()->RequestFindMatchRects(-1);
608 delegate()->WaitForMatchRects();
609 const std::vector<gfx::RectF>& rects = delegate()->find_match_rects();
610
611 // Activate matches via points inside each of the find match rects, in an
612 // arbitrary order. Check that the correct match becomes active after each
613 // activation.
614 int order[19] =
615 {11, 13, 2, 0, 16, 5, 7, 10, 6, 1, 15, 14, 9, 17, 18, 3, 8, 12, 4};
616 for (int i = 0; i < 19; ++i) {
paulmeyer2f06e612016-08-10 17:39:02617 delegate()->MarkNextReply();
paulmeyerc8cb7cb2016-06-07 01:14:19618 contents()->ActivateNearestFindResult(
619 rects[order[i]].CenterPoint().x(), rects[order[i]].CenterPoint().y());
620 delegate()->WaitForNextReply();
621 EXPECT_EQ(order[i] + 1, delegate()->GetFindResults().active_match_ordinal);
622 }
623}
624#endif // defined(OS_ANDROID)
paulmeyera41de3b2016-05-05 16:30:18625
626} // namespace content