1 // Copyright (c) 2015 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 "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/i18n/rtl.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "base/test/simple_test_clock.h"
17 #include "base/test/simple_test_tick_clock.h"
18 #include "build/build_config.h"
19 #include "chrome/app/chrome_command_ids.h"
20 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
21 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
22 #include "chrome/browser/command_updater.h"
23 #include "chrome/browser/command_updater_impl.h"
24 #include "chrome/browser/search_engines/template_url_service_factory_test_util.h"
25 #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
26 #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
27 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "chrome/test/base/testing_profile.h"
30 #include "chrome/test/views/chrome_views_test_base.h"
31 #include "components/omnibox/browser/omnibox_edit_model.h"
32 #include "components/omnibox/browser/test_location_bar_model.h"
33 #include "components/omnibox/common/omnibox_features.h"
34 #include "components/reputation/core/safety_tip_test_utils.h"
35 #include "content/public/browser/focused_node_details.h"
36 #include "content/public/test/browser_task_environment.h"
37 #include "content/public/test/mock_navigation_handle.h"
38 #include "content/public/test/test_renderer_host.h"
39 #include "content/public/test/web_contents_tester.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 #include "third_party/blink/public/common/input/web_input_event.h"
42 #include "third_party/blink/public/common/input/web_keyboard_event.h"
43 #include "third_party/blink/public/common/input/web_mouse_event.h"
44 #include "third_party/metrics_proto/omnibox_event.pb.h"
45 #include "ui/base/clipboard/clipboard.h"
46 #include "ui/base/clipboard/scoped_clipboard_writer.h"
47 #include "ui/base/ime/input_method.h"
48 #include "ui/base/ime/text_edit_commands.h"
49 #include "ui/events/event_utils.h"
50 #include "ui/events/keycodes/dom/dom_code.h"
51 #include "ui/gfx/animation/animation_container_element.h"
52 #include "ui/gfx/geometry/rect.h"
53 #include "ui/gfx/render_text.h"
54 #include "ui/gfx/render_text_test_api.h"
55 #include "ui/views/controls/textfield/textfield_test_api.h"
56
57 #if defined(OS_CHROMEOS)
58 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
59 #include "chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h"
60 #endif
61
62 using FeatureAndParams = base::test::ScopedFeatureList::FeatureAndParams;
63 using gfx::Range;
64 using metrics::OmniboxEventProto;
65
66 namespace {
67
68 class TestingOmniboxView;
69
70 void ExpectElidedToSimplifiedDomain(TestingOmniboxView* view,
71 const base::string16& scheme,
72 const base::string16& subdomain,
73 const base::string16& hostname_and_scheme,
74 const base::string16& path,
75 bool should_elide_to_registrable_domain);
76
77 void ExpectUnelidedFromSimplifiedDomain(gfx::RenderText* render_text,
78 const gfx::Range& display_url);
79
80 // TestingOmniboxView ---------------------------------------------------------
81
82 class TestingOmniboxView : public OmniboxViewViews {
83 public:
84 TestingOmniboxView(OmniboxEditController* controller,
85 TestLocationBarModel* location_bar_model,
86 std::unique_ptr<OmniboxClient> client);
87 TestingOmniboxView(const TestingOmniboxView&) = delete;
88 TestingOmniboxView& operator=(const TestingOmniboxView&) = delete;
89
90 using views::Textfield::GetRenderText;
91
92 void ResetEmphasisTestState();
93
94 void CheckUpdatePopupCallInfo(size_t call_count,
95 const base::string16& text,
96 const Range& selection_range);
97
98 void CheckUpdatePopupNotCalled();
99
scheme_range() const100 Range scheme_range() const { return scheme_range_; }
emphasis_range() const101 Range emphasis_range() const { return emphasis_range_; }
base_text_emphasis() const102 bool base_text_emphasis() const { return base_text_emphasis_; }
103
104 // Returns the latest color applied to |range| via ApplyColor(), or
105 // base::nullopt if no color has been applied to |range|.
106 base::Optional<SkColor> GetLatestColorForRange(const gfx::Range& range);
107
108 // OmniboxViewViews:
GetAccessibleNodeData(ui::AXNodeData * node_data)109 void GetAccessibleNodeData(ui::AXNodeData* node_data) override {}
110 void OnThemeChanged() override;
111
112 // In the simplified domain field trials, these methods advance through
113 // elision/unelision animations (triggered by hovering over the omnibox and
114 // interacting with the web contents, respectively) by |step_ms|.
115 void StepSimplifiedDomainHoverAnimation(int64_t step_ms);
116 void StepSimplifiedDomainInteractionAnimation(int64_t step_ms);
117
118 // Simulates a navigation and checks that the URL is elided to the simplified
119 // domain afterwards. This simulates a renderer-initiated navigation, in which
120 // the display URL is updated between DidStartNavigation() and
121 // DidFinishNavigation() calls.
122 void NavigateAndExpectElided(const GURL& url,
123 bool is_same_document,
124 const GURL& previous_url,
125 const base::string16& scheme,
126 const base::string16& subdomain,
127 const base::string16& hostname_and_scheme,
128 const base::string16& path,
129 bool should_elide_to_registrable_domain);
130
131 // Simluates a navigation and checks that the URL is unelided from the
132 // simplified domain afterwards. This simulates a renderer-initiated
133 // navigation, in which the display URL is updated between
134 // DidStartNavigation() and DidFinishNavigation() calls.
135 void NavigateAndExpectUnelided(const base::string16& url,
136 bool is_same_document,
137 const GURL& previous_url,
138 const base::string16& scheme);
139
140 using OmniboxView::OnInlineAutocompleteTextMaybeChanged;
141
142 private:
143 // OmniboxViewViews:
144 // There is no popup and it doesn't actually matter whether we change the
145 // visual style of the text, so these methods are all overridden merely to
146 // capture relevant state at the time of the call, to be checked by test code.
147 void UpdatePopup() override;
148 void SetEmphasis(bool emphasize, const Range& range) override;
149 void UpdateSchemeStyle(const Range& range) override;
150 void ApplyColor(SkColor color, const gfx::Range& range) override;
151
152 size_t update_popup_call_count_ = 0;
153 base::string16 update_popup_text_;
154 Range update_popup_selection_range_;
155
156 // Range of the last scheme logged by UpdateSchemeStyle().
157 Range scheme_range_;
158
159 // Range of the last text emphasized by SetEmphasis().
160 Range emphasis_range_;
161
162 // Stores the colors applied to ranges via ApplyColor(), in chronological
163 // order.
164 std::vector<std::pair<SkColor, gfx::Range>> range_colors_;
165
166 TestLocationBarModel* location_bar_model_;
167
168 // SetEmphasis() logs whether the base color of the text is emphasized.
169 bool base_text_emphasis_;
170 };
171
TestingOmniboxView(OmniboxEditController * controller,TestLocationBarModel * location_bar_model,std::unique_ptr<OmniboxClient> client)172 TestingOmniboxView::TestingOmniboxView(OmniboxEditController* controller,
173 TestLocationBarModel* location_bar_model,
174 std::unique_ptr<OmniboxClient> client)
175 : OmniboxViewViews(controller,
176 std::move(client),
177 false,
178 nullptr,
179 gfx::FontList()),
180 location_bar_model_(location_bar_model) {}
181
ResetEmphasisTestState()182 void TestingOmniboxView::ResetEmphasisTestState() {
183 base_text_emphasis_ = false;
184 emphasis_range_ = Range::InvalidRange();
185 scheme_range_ = Range::InvalidRange();
186 }
187
CheckUpdatePopupCallInfo(size_t call_count,const base::string16 & text,const Range & selection_range)188 void TestingOmniboxView::CheckUpdatePopupCallInfo(
189 size_t call_count,
190 const base::string16& text,
191 const Range& selection_range) {
192 EXPECT_EQ(call_count, update_popup_call_count_);
193 EXPECT_EQ(text, update_popup_text_);
194 EXPECT_EQ(selection_range, update_popup_selection_range_);
195 }
196
CheckUpdatePopupNotCalled()197 void TestingOmniboxView::CheckUpdatePopupNotCalled() {
198 EXPECT_EQ(update_popup_call_count_, 0U);
199 }
200
GetLatestColorForRange(const gfx::Range & range)201 base::Optional<SkColor> TestingOmniboxView::GetLatestColorForRange(
202 const gfx::Range& range) {
203 // Iterate backwards to get the most recently applied color for |range|.
204 for (auto range_color = range_colors_.rbegin();
205 range_color != range_colors_.rend(); range_color++) {
206 if (range == range_color->second)
207 return range_color->first;
208 }
209 return base::nullopt;
210 }
211
OnThemeChanged()212 void TestingOmniboxView::OnThemeChanged() {
213 // This method is overridden simply to expose this protected method for tests
214 // to call.
215 OmniboxViewViews::OnThemeChanged();
216 }
217
UpdatePopup()218 void TestingOmniboxView::UpdatePopup() {
219 ++update_popup_call_count_;
220 update_popup_text_ = GetText();
221 update_popup_selection_range_ = GetSelectedRange();
222
223 // The real view calls OmniboxEditModel::UpdateInput(), which sets input in
224 // progress and starts autocomplete. Triggering autocomplete and the popup is
225 // beyond the scope of this test, but setting input in progress is important
226 // for making some sequences (e.g. uneliding on taking an action) behave
227 // correctly.
228 model()->SetInputInProgress(true);
229 }
230
SetEmphasis(bool emphasize,const Range & range)231 void TestingOmniboxView::SetEmphasis(bool emphasize, const Range& range) {
232 if (range == Range::InvalidRange()) {
233 base_text_emphasis_ = emphasize;
234 return;
235 }
236
237 EXPECT_TRUE(emphasize);
238 emphasis_range_ = range;
239 }
240
UpdateSchemeStyle(const Range & range)241 void TestingOmniboxView::UpdateSchemeStyle(const Range& range) {
242 scheme_range_ = range;
243 }
244
ApplyColor(SkColor color,const gfx::Range & range)245 void TestingOmniboxView::ApplyColor(SkColor color, const gfx::Range& range) {
246 range_colors_.emplace_back(std::pair<SkColor, gfx::Range>(color, range));
247 OmniboxViewViews::ApplyColor(color, range);
248 }
249
StepSimplifiedDomainHoverAnimation(int64_t step_ms)250 void TestingOmniboxView::StepSimplifiedDomainHoverAnimation(int64_t step_ms) {
251 OmniboxViewViews::ElideAnimation* hover_animation =
252 GetHoverElideOrUnelideAnimationForTesting();
253 ASSERT_TRUE(hover_animation);
254 EXPECT_TRUE(hover_animation->IsAnimating());
255 gfx::AnimationContainerElement* hover_animation_as_element =
256 static_cast<gfx::AnimationContainerElement*>(
257 hover_animation->GetAnimationForTesting());
258 hover_animation_as_element->SetStartTime(base::TimeTicks());
259 hover_animation_as_element->Step(base::TimeTicks() +
260 base::TimeDelta::FromMilliseconds(step_ms));
261 }
262
StepSimplifiedDomainInteractionAnimation(int64_t step_ms)263 void TestingOmniboxView::StepSimplifiedDomainInteractionAnimation(
264 int64_t step_ms) {
265 OmniboxViewViews::ElideAnimation* interaction_animation =
266 GetElideAfterInteractionAnimationForTesting();
267 ASSERT_TRUE(interaction_animation);
268 EXPECT_TRUE(interaction_animation->IsAnimating());
269 gfx::AnimationContainerElement* interaction_animation_as_element =
270 static_cast<gfx::AnimationContainerElement*>(
271 interaction_animation->GetAnimationForTesting());
272 interaction_animation_as_element->SetStartTime(base::TimeTicks());
273 interaction_animation_as_element->Step(
274 base::TimeTicks() + base::TimeDelta::FromMilliseconds(step_ms));
275 }
276
NavigateAndExpectElided(const GURL & url,bool is_same_document,const GURL & previous_url,const base::string16 & scheme,const base::string16 & subdomain,const base::string16 & hostname_and_scheme,const base::string16 & path,bool should_elide_to_registrable_domain)277 void TestingOmniboxView::NavigateAndExpectElided(
278 const GURL& url,
279 bool is_same_document,
280 const GURL& previous_url,
281 const base::string16& scheme,
282 const base::string16& subdomain,
283 const base::string16& hostname_and_scheme,
284 const base::string16& path,
285 bool should_elide_to_registrable_domain) {
286 content::MockNavigationHandle navigation;
287 navigation.set_is_same_document(is_same_document);
288 navigation.set_url(url);
289 navigation.set_previous_url(previous_url);
290 DidStartNavigation(&navigation);
291 location_bar_model_->set_url(url);
292 location_bar_model_->set_url_for_display(base::ASCIIToUTF16(url.spec()));
293 model()->ResetDisplayTexts();
294 RevertAll();
295 navigation.set_has_committed(true);
296 DidFinishNavigation(&navigation);
297 ExpectElidedToSimplifiedDomain(this, scheme, subdomain, hostname_and_scheme,
298 path, should_elide_to_registrable_domain);
299 }
300
NavigateAndExpectUnelided(const base::string16 & url,bool is_same_document,const GURL & previous_url,const base::string16 & scheme)301 void TestingOmniboxView::NavigateAndExpectUnelided(
302 const base::string16& url,
303 bool is_same_document,
304 const GURL& previous_url,
305 const base::string16& scheme) {
306 content::MockNavigationHandle navigation;
307 navigation.set_is_same_document(is_same_document);
308 navigation.set_url(GURL(url));
309 navigation.set_previous_url(previous_url);
310 DidStartNavigation(&navigation);
311 location_bar_model_->set_url(GURL(url));
312 location_bar_model_->set_url_for_display(url);
313 model()->ResetDisplayTexts();
314 RevertAll();
315 navigation.set_has_committed(true);
316 DidFinishNavigation(&navigation);
317 ExpectUnelidedFromSimplifiedDomain(this->GetRenderText(),
318 gfx::Range(scheme.size(), url.size()));
319 }
320
321 // TODO(crbug.com/1112536): With RTL UI, the URL is sometimes off by one pixel
322 // of the right edge. Investigate if this is expected, otherwise replace this
323 // with equality checks in tests that use it. Checks |a| is within 1 of |b|.
CheckEqualsWithMarginOne(int a,int b)324 void CheckEqualsWithMarginOne(int a, int b) {
325 EXPECT_LE(std::abs(a - b), 1);
326 }
327
328 // Checks that |view|'s current display rect and offset does not display
329 // |path|, and also does not display |subdomain_and_scheme| if
330 // |should_elide_to_registrable_domain| is true.
331 //
332 // |subdomain_and_scheme| is assumed to be a prefix of |hostname_and_scheme|.
333 // |subdomain_and_scheme| and |subdomain| should include a trailing ".", and
334 // |path| should include a leading "/".
ExpectElidedToSimplifiedDomain(TestingOmniboxView * view,const base::string16 & scheme,const base::string16 & subdomain,const base::string16 & hostname_and_scheme,const base::string16 & path,bool should_elide_to_registrable_domain)335 void ExpectElidedToSimplifiedDomain(TestingOmniboxView* view,
336 const base::string16& scheme,
337 const base::string16& subdomain,
338 const base::string16& hostname_and_scheme,
339 const base::string16& path,
340 bool should_elide_to_registrable_domain) {
341 gfx::RenderText* render_text = view->GetRenderText();
342 gfx::Rect subdomain_and_scheme_rect;
343 for (const auto& rect : render_text->GetSubstringBounds(
344 gfx::Range(0, scheme.size() + subdomain.size()))) {
345 subdomain_and_scheme_rect.Union(rect);
346 }
347 gfx::Rect path_rect;
348 for (const auto& rect : render_text->GetSubstringBounds(
349 gfx::Range(hostname_and_scheme.size(),
350 hostname_and_scheme.size() + path.size()))) {
351 path_rect.Union(rect);
352 }
353 EXPECT_FALSE(render_text->display_rect().Contains(path_rect));
354 if (should_elide_to_registrable_domain) {
355 EXPECT_FALSE(
356 render_text->display_rect().Contains(subdomain_and_scheme_rect));
357 gfx::Rect registrable_domain_rect;
358 for (const auto& rect : render_text->GetSubstringBounds(gfx::Range(
359 scheme.size() + subdomain.size(), hostname_and_scheme.size()))) {
360 registrable_domain_rect.Union(rect);
361 }
362 EXPECT_TRUE(render_text->display_rect().Contains(registrable_domain_rect));
363 // The text should be scrolled to push the scheme and subdomain offscreen,
364 // so that the text starts at the registrable domain. Note that this code
365 // computes the expected offset by comparing x() values rather than
366 // comparing based on widths (for example, it wouldn't work to check that
367 // the display offset is equal to |subdomain_and_scheme_rect|'s width). This
368 // is because GetSubstringBounds() rounds outward, so the width of
369 // |subdomain_and_scheme_rect| could slightly overlap
370 // |registrable_domain_rect|.
371 // In the RTL UI case, the offset instead has to push the path offscreen to
372 // the right, so we check offset equals the width of the path rectangle.
373 if (base::i18n::IsRTL()) {
374 CheckEqualsWithMarginOne(path_rect.width(),
375 render_text->GetUpdatedDisplayOffset().x());
376 } else {
377 EXPECT_EQ(registrable_domain_rect.x() - subdomain_and_scheme_rect.x(),
378 -1 * render_text->GetUpdatedDisplayOffset().x());
379 }
380 // The scheme and subdomain should be transparent.
381 EXPECT_EQ(SK_ColorTRANSPARENT, view->GetLatestColorForRange(gfx::Range(
382 0, scheme.size() + subdomain.size())));
383 } else {
384 // When elision to registrable domain is disabled, the scheme should be
385 // hidden but the subdomain should not be.
386 EXPECT_FALSE(
387 render_text->display_rect().Contains(subdomain_and_scheme_rect));
388 gfx::Rect hostname_rect;
389 for (const auto& rect : render_text->GetSubstringBounds(
390 gfx::Range(scheme.size(), hostname_and_scheme.size()))) {
391 hostname_rect.Union(rect);
392 }
393 // The text should be scrolled to push the scheme offscreen, so that the
394 // text starts at the subdomain. As above, it's important to compute the
395 // expected offset with x() values instead of width()s, since the width()s
396 // of different adjacent substring bounds could overlap.
397 // In the RTL UI case, the offset instead has to push the path offscreen to
398 // the right, so we check offset equals the width of the path rectangle.
399 if (base::i18n::IsRTL()) {
400 CheckEqualsWithMarginOne(path_rect.width(),
401 render_text->GetUpdatedDisplayOffset().x());
402 } else {
403 EXPECT_EQ(hostname_rect.x() - subdomain_and_scheme_rect.x(),
404 -1 * render_text->GetUpdatedDisplayOffset().x());
405 }
406 // The scheme should be transparent.
407 EXPECT_EQ(SK_ColorTRANSPARENT,
408 view->GetLatestColorForRange(gfx::Range(0, scheme.size())));
409 }
410 // The path should be transparent.
411 EXPECT_EQ(SK_ColorTRANSPARENT,
412 view->GetLatestColorForRange(
413 gfx::Range(hostname_and_scheme.size(),
414 hostname_and_scheme.size() + path.size())));
415 }
416
417 // Checks that |render_text|'s current display rect and offset displays all of
418 // |display_url|, starting at the leading edge.
ExpectUnelidedFromSimplifiedDomain(gfx::RenderText * render_text,const gfx::Range & display_url)419 void ExpectUnelidedFromSimplifiedDomain(gfx::RenderText* render_text,
420 const gfx::Range& display_url) {
421 gfx::Rect unelided_rect;
422 for (const auto& rect : render_text->GetSubstringBounds(display_url)) {
423 unelided_rect.Union(rect);
424 }
425 EXPECT_TRUE(render_text->display_rect().Contains(unelided_rect));
426 // |display_url| should be at the leading edge of |render_text|'s display
427 // rect for LTR UI, or at the rightmost side of the omnibox for RTL UI.
428 if (base::i18n::IsRTL()) {
429 CheckEqualsWithMarginOne(
430 unelided_rect.x(),
431 render_text->display_rect().right() - unelided_rect.width());
432 } else {
433 EXPECT_EQ(unelided_rect.x(), render_text->display_rect().x());
434 }
435 }
436
437 // TestingOmniboxEditController -----------------------------------------------
438
439 class TestingOmniboxEditController : public ChromeOmniboxEditController {
440 public:
TestingOmniboxEditController(CommandUpdater * command_updater,LocationBarModel * location_bar_model)441 TestingOmniboxEditController(CommandUpdater* command_updater,
442 LocationBarModel* location_bar_model)
443 : ChromeOmniboxEditController(command_updater),
444 location_bar_model_(location_bar_model) {}
445 TestingOmniboxEditController(const TestingOmniboxEditController&) = delete;
446 TestingOmniboxEditController& operator=(const TestingOmniboxEditController&) =
447 delete;
448
set_omnibox_view(OmniboxViewViews * view)449 void set_omnibox_view(OmniboxViewViews* view) { omnibox_view_ = view; }
450
451 private:
452 // ChromeOmniboxEditController:
GetLocationBarModel()453 LocationBarModel* GetLocationBarModel() override {
454 return location_bar_model_;
455 }
GetLocationBarModel() const456 const LocationBarModel* GetLocationBarModel() const override {
457 return location_bar_model_;
458 }
UpdateWithoutTabRestore()459 void UpdateWithoutTabRestore() override {
460 // This is a minimal amount of what LocationBarView does. Not all tests
461 // set |omnibox_view_|.
462 if (omnibox_view_)
463 omnibox_view_->Update();
464 }
465
466 LocationBarModel* location_bar_model_;
467 OmniboxViewViews* omnibox_view_ = nullptr;
468 };
469
470 } // namespace
471
472 // OmniboxViewViewsTest -------------------------------------------------------
473
474 // Base class that ensures ScopedFeatureList is initialized first.
475 class OmniboxViewViewsTestBase : public ChromeViewsTestBase {
476 public:
OmniboxViewViewsTestBase(const std::vector<FeatureAndParams> & enabled_features,const std::vector<base::Feature> & disabled_features,bool is_rtl_ui_test=false)477 OmniboxViewViewsTestBase(
478 const std::vector<FeatureAndParams>& enabled_features,
479 const std::vector<base::Feature>& disabled_features,
480 bool is_rtl_ui_test = false) {
481 scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features,
482 disabled_features);
483 base::i18n::SetRTLForTesting(is_rtl_ui_test);
484 }
485
486 protected:
487 base::test::ScopedFeatureList scoped_feature_list_;
488 };
489
490 // The display URL used in simplified domain display tests.
491 const base::string16 kSimplifiedDomainDisplayUrl =
492 base::ASCIIToUTF16("https://foo.example.test/bar");
493 const base::string16 kSimplifiedDomainDisplayUrlHostnameAndScheme =
494 base::ASCIIToUTF16("https://foo.example.test");
495 const base::string16 kSimplifiedDomainDisplayUrlSubdomainAndScheme =
496 base::ASCIIToUTF16("https://foo.");
497 const base::string16 kSimplifiedDomainDisplayUrlSubdomain =
498 base::ASCIIToUTF16("foo.");
499 const base::string16 kSimplifiedDomainDisplayUrlPath =
500 base::ASCIIToUTF16("/bar");
501 const base::string16 kSimplifiedDomainDisplayUrlScheme =
502 base::ASCIIToUTF16("https://");
503
504 class OmniboxViewViewsTest : public OmniboxViewViewsTestBase {
505 public:
506 OmniboxViewViewsTest(const std::vector<FeatureAndParams>& enabled_features,
507 const std::vector<base::Feature>& disabled_features,
508 bool is_rtl_ui_test = false);
509
OmniboxViewViewsTest()510 OmniboxViewViewsTest()
511 : OmniboxViewViewsTest(std::vector<FeatureAndParams>(),
512 std::vector<base::Feature>()) {}
513 OmniboxViewViewsTest(const OmniboxViewViewsTest&) = delete;
514 OmniboxViewViewsTest& operator=(const OmniboxViewViewsTest&) = delete;
515
location_bar_model()516 TestLocationBarModel* location_bar_model() { return &location_bar_model_; }
command_updater()517 CommandUpdaterImpl* command_updater() { return &command_updater_; }
omnibox_view() const518 TestingOmniboxView* omnibox_view() const { return omnibox_view_; }
519
520 // TODO(tommycli): These base class accessors exist because Textfield and
521 // OmniboxView both hide member functions that were public in base classes.
522 // Remove these after we stop doing that.
omnibox_textfield() const523 views::Textfield* omnibox_textfield() const { return omnibox_view(); }
omnibox_textfield_view() const524 views::View* omnibox_textfield_view() const { return omnibox_view(); }
525
textfield_test_api()526 views::TextfieldTestApi* textfield_test_api() { return test_api_.get(); }
527
528 // Sets |new_text| as the omnibox text, and emphasizes it appropriately. If
529 // |accept_input| is true, pretends that the user has accepted this input
530 // (i.e. it's been navigated to).
531 void SetAndEmphasizeText(const std::string& new_text, bool accept_input);
532
IsCursorEnabled() const533 bool IsCursorEnabled() const {
534 return test_api_->GetRenderText()->cursor_enabled();
535 }
536
CreateMouseEvent(ui::EventType type,const gfx::Point & point,int event_flags=ui::EF_LEFT_MOUSE_BUTTON)537 ui::MouseEvent CreateMouseEvent(ui::EventType type,
538 const gfx::Point& point,
539 int event_flags = ui::EF_LEFT_MOUSE_BUTTON) {
540 return ui::MouseEvent(type, point, point, ui::EventTimeForNow(),
541 event_flags, event_flags);
542 }
543
544 protected:
profile()545 Profile* profile() { return profile_.get(); }
omnibox_edit_controller()546 TestingOmniboxEditController* omnibox_edit_controller() {
547 return &omnibox_edit_controller_;
548 }
549
550 // Updates the models' URL and display text to |new_url|.
UpdateDisplayURL(const base::string16 & new_url)551 void UpdateDisplayURL(const base::string16& new_url) {
552 location_bar_model()->set_url(GURL(new_url));
553 location_bar_model()->set_url_for_display(new_url);
554 omnibox_view()->model()->ResetDisplayTexts();
555 omnibox_view()->RevertAll();
556 }
557
558 // Sets up tests for the simplified domain field trials.
SetUpSimplifiedDomainTest()559 void SetUpSimplifiedDomainTest() {
560 UpdateDisplayURL(kSimplifiedDomainDisplayUrl);
561 // Call OnThemeChanged() to create the animations.
562 omnibox_view()->OnThemeChanged();
563 }
564
565 // testing::Test:
566 void SetUp() override;
567 void TearDown() override;
568
CreateEvent(ui::EventType type,int flags)569 ui::MouseEvent CreateEvent(ui::EventType type, int flags) {
570 return ui::MouseEvent(type, gfx::Point(0, 0), gfx::Point(),
571 ui::EventTimeForNow(), flags, 0);
572 }
573
574 private:
575 std::unique_ptr<TestingProfile> profile_;
576 std::unique_ptr<TemplateURLServiceFactoryTestUtil> util_;
577 CommandUpdaterImpl command_updater_;
578 TestLocationBarModel location_bar_model_;
579 TestingOmniboxEditController omnibox_edit_controller_;
580 content::RenderViewHostTestEnabler rvh_test_enabler_;
581
582 std::unique_ptr<views::Widget> widget_;
583
584 // Owned by |widget_|.
585 TestingOmniboxView* omnibox_view_;
586
587 std::unique_ptr<views::TextfieldTestApi> test_api_;
588 };
589
OmniboxViewViewsTest(const std::vector<FeatureAndParams> & enabled_features,const std::vector<base::Feature> & disabled_features,bool is_rtl_ui_test)590 OmniboxViewViewsTest::OmniboxViewViewsTest(
591 const std::vector<FeatureAndParams>& enabled_features,
592 const std::vector<base::Feature>& disabled_features,
593 bool is_rtl_ui_test)
594 : OmniboxViewViewsTestBase(enabled_features,
595 disabled_features,
596 is_rtl_ui_test),
597 command_updater_(nullptr),
598 omnibox_edit_controller_(&command_updater_, &location_bar_model_) {}
599
SetAndEmphasizeText(const std::string & new_text,bool accept_input)600 void OmniboxViewViewsTest::SetAndEmphasizeText(const std::string& new_text,
601 bool accept_input) {
602 omnibox_view()->ResetEmphasisTestState();
603 omnibox_view()->SetUserText(base::ASCIIToUTF16(new_text));
604 if (accept_input) {
605 // We don't need to actually navigate in this case (and doing so in a test
606 // would be difficult); it's sufficient to mark input as "no longer in
607 // progress", and the edit model will assume the current text is a URL.
608 omnibox_view()->model()->SetInputInProgress(false);
609 }
610 omnibox_view()->EmphasizeURLComponents();
611 }
612
SetUp()613 void OmniboxViewViewsTest::SetUp() {
614 ChromeViewsTestBase::SetUp();
615
616 profile_ = std::make_unique<TestingProfile>();
617 util_ = std::make_unique<TemplateURLServiceFactoryTestUtil>(profile_.get());
618
619 // We need a widget so OmniboxView can be correctly focused and unfocused.
620 widget_ = CreateTestWidget();
621 widget_->Show();
622
623 #if defined(OS_CHROMEOS)
624 chromeos::input_method::InitializeForTesting(
625 new chromeos::input_method::MockInputMethodManagerImpl);
626 #endif
627 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
628 profile_.get(),
629 base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor));
630 auto omnibox_view = std::make_unique<TestingOmniboxView>(
631 &omnibox_edit_controller_, location_bar_model(),
632 std::make_unique<ChromeOmniboxClient>(&omnibox_edit_controller_,
633 profile_.get()));
634 test_api_ = std::make_unique<views::TextfieldTestApi>(omnibox_view.get());
635 omnibox_view->Init();
636
637 omnibox_view_ = widget_->SetContentsView(std::move(omnibox_view));
638 }
639
TearDown()640 void OmniboxViewViewsTest::TearDown() {
641 // Clean ourselves up as the text input client.
642 if (omnibox_view_->GetInputMethod())
643 omnibox_view_->GetInputMethod()->DetachTextInputClient(omnibox_view_);
644
645 widget_.reset();
646 util_.reset();
647 profile_.reset();
648
649 #if defined(OS_CHROMEOS)
650 chromeos::input_method::Shutdown();
651 #endif
652 ChromeViewsTestBase::TearDown();
653 }
654
655 // Actual tests ---------------------------------------------------------------
656
657 // Checks that a single change of the text in the omnibox invokes
658 // only one call to OmniboxViewViews::UpdatePopup().
TEST_F(OmniboxViewViewsTest,UpdatePopupCall)659 TEST_F(OmniboxViewViewsTest, UpdatePopupCall) {
660 ui::KeyEvent char_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, 0,
661 ui::DomKey::FromCharacter('a'),
662 ui::EventTimeForNow());
663 omnibox_textfield()->InsertChar(char_event);
664 omnibox_view()->CheckUpdatePopupCallInfo(1, base::ASCIIToUTF16("a"),
665 Range(1));
666
667 char_event =
668 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_B, ui::DomCode::US_B, 0,
669 ui::DomKey::FromCharacter('b'), ui::EventTimeForNow());
670 omnibox_textfield()->InsertChar(char_event);
671 omnibox_view()->CheckUpdatePopupCallInfo(2, base::ASCIIToUTF16("ab"),
672 Range(2));
673
674 ui::KeyEvent pressed(ui::ET_KEY_PRESSED, ui::VKEY_BACK, 0);
675 omnibox_textfield()->OnKeyEvent(&pressed);
676 omnibox_view()->CheckUpdatePopupCallInfo(3, base::ASCIIToUTF16("a"),
677 Range(1));
678 }
679
680 // Test that text cursor is shown in the omnibox after entering any single
681 // character in NTP 'Search box'. Test for crbug.com/698172.
TEST_F(OmniboxViewViewsTest,EditTextfield)682 TEST_F(OmniboxViewViewsTest, EditTextfield) {
683 omnibox_textfield()->SetCursorEnabled(false);
684 ui::KeyEvent char_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, 0,
685 ui::DomKey::FromCharacter('a'),
686 ui::EventTimeForNow());
687 omnibox_textfield()->InsertChar(char_event);
688 EXPECT_TRUE(IsCursorEnabled());
689 }
690
691 // Test that the scheduled text edit command is cleared when Textfield receives
692 // a key press event. This ensures that the scheduled text edit command property
693 // is always in the correct state. Test for http://crbug.com/613948.
TEST_F(OmniboxViewViewsTest,ScheduledTextEditCommand)694 TEST_F(OmniboxViewViewsTest, ScheduledTextEditCommand) {
695 omnibox_textfield()->SetTextEditCommandForNextKeyEvent(
696 ui::TextEditCommand::MOVE_UP);
697 EXPECT_EQ(ui::TextEditCommand::MOVE_UP,
698 textfield_test_api()->scheduled_text_edit_command());
699
700 ui::KeyEvent up_pressed(ui::ET_KEY_PRESSED, ui::VKEY_UP, 0);
701 omnibox_textfield()->OnKeyEvent(&up_pressed);
702 EXPECT_EQ(ui::TextEditCommand::INVALID_COMMAND,
703 textfield_test_api()->scheduled_text_edit_command());
704 }
705
706 // Test that Shift+Up and Shift+Down are not captured and let selection mode
707 // take over. Test for crbug.com/863543 and crbug.com/892216.
TEST_F(OmniboxViewViewsTest,SelectWithShift_863543)708 TEST_F(OmniboxViewViewsTest, SelectWithShift_863543) {
709 location_bar_model()->set_url(GURL("http://www.example.com/?query=1"));
710 const base::string16 text =
711 base::ASCIIToUTF16("http://www.example.com/?query=1");
712 omnibox_view()->SetWindowTextAndCaretPos(text, 23U, false, false);
713
714 ui::KeyEvent shift_up_pressed(ui::ET_KEY_PRESSED, ui::VKEY_UP,
715 ui::EF_SHIFT_DOWN);
716 omnibox_textfield()->OnKeyEvent(&shift_up_pressed);
717
718 size_t start, end;
719 omnibox_view()->GetSelectionBounds(&start, &end);
720 EXPECT_EQ(23U, start);
721 EXPECT_EQ(0U, end);
722 omnibox_view()->CheckUpdatePopupNotCalled();
723
724 omnibox_view()->SetWindowTextAndCaretPos(text, 18U, false, false);
725
726 ui::KeyEvent shift_down_pressed(ui::ET_KEY_PRESSED, ui::VKEY_DOWN,
727 ui::EF_SHIFT_DOWN);
728 omnibox_textfield()->OnKeyEvent(&shift_down_pressed);
729
730 omnibox_view()->GetSelectionBounds(&start, &end);
731 EXPECT_EQ(18U, start);
732 EXPECT_EQ(31U, end);
733 omnibox_view()->CheckUpdatePopupNotCalled();
734 }
735
TEST_F(OmniboxViewViewsTest,OnBlur)736 TEST_F(OmniboxViewViewsTest, OnBlur) {
737 // Make the Omnibox very narrow (so it couldn't fit the whole string).
738 int kOmniboxWidth = 60;
739 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
740 render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
741 render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
742
743 // (In this example, uppercase Latin letters represent Hebrew letters.)
744 // The string |kContentsRtl| is equivalent to:
745 // RA.QWM/0123/abcd
746 // This is displayed as:
747 // 0123/MWQ.AR/abcd
748 // Enter focused mode, where the text should *not* be elided, and we expect
749 // SetWindowTextAndCaretPos to scroll such that the start of the string is
750 // on-screen. Because the domain is RTL, this scrolls to an offset greater
751 // than 0.
752 omnibox_textfield()->OnFocus();
753 const base::string16 kContentsRtl =
754 base::WideToUTF16(L"\x05e8\x05e2.\x05e7\x05d5\x05dd/0123/abcd");
755 omnibox_view()->SetWindowTextAndCaretPos(kContentsRtl, 0, false, false);
756 EXPECT_EQ(gfx::NO_ELIDE, render_text->elide_behavior());
757
758 // TODO(https://crbug.com/1094386): this assertion fails because
759 // EmphasizeURLComponents() sets the textfield's directionality to
760 // DIRECTIONALITY_AS_URL. This should be either fixed or the assertion
761 // removed.
762 //
763 // NOTE: Technically (depending on the font), this expectation could fail if
764 // the entire domain fits in 60 pixels. However, 60px is so small it should
765 // never happen with any font.
766 // EXPECT_GT(0, render_text->GetUpdatedDisplayOffset().x());
767
768 omnibox_view()->SelectAll(false);
769 EXPECT_TRUE(omnibox_view()->IsSelectAll());
770
771 // Now enter blurred mode, where the text should be elided to 60px. This means
772 // the string itself is truncated. Scrolling would therefore mean the text is
773 // off-screen. Ensure that the horizontal scrolling has been reset to 0.
774 omnibox_textfield()->OnBlur();
775 EXPECT_EQ(gfx::ELIDE_TAIL, render_text->elide_behavior());
776 EXPECT_EQ(0, render_text->GetUpdatedDisplayOffset().x());
777 EXPECT_FALSE(omnibox_view()->IsSelectAll());
778 }
779
780 // Verifies that https://crbug.com/45260 doesn't regress.
TEST_F(OmniboxViewViewsTest,RendererInitiatedFocusSelectsAllWhenStartingBlurred)781 TEST_F(OmniboxViewViewsTest,
782 RendererInitiatedFocusSelectsAllWhenStartingBlurred) {
783 location_bar_model()->set_url(GURL("about:blank"));
784 omnibox_view()->model()->ResetDisplayTexts();
785 omnibox_view()->RevertAll();
786
787 // Simulate a renderer-initated focus event. Expect that everything is
788 // selected now.
789 omnibox_view()->SetFocus(/*is_user_initiated=*/false);
790 EXPECT_TRUE(omnibox_view()->IsSelectAll());
791 }
792
793 // Verifies that https://crbug.com/924935 doesn't regress.
TEST_F(OmniboxViewViewsTest,RendererInitiatedFocusPreservesCursorWhenStartingFocused)794 TEST_F(OmniboxViewViewsTest,
795 RendererInitiatedFocusPreservesCursorWhenStartingFocused) {
796 // Simulate the user focusing the omnibox and typing something. This is just
797 // the test setup, not the actual focus event we are testing.
798 omnibox_view()->SetFocus(/*is_user_initiated*/ true);
799 omnibox_view()->SetTextAndSelectedRanges(base::ASCIIToUTF16("user text"),
800 {gfx::Range(9, 9)});
801 ASSERT_FALSE(omnibox_view()->IsSelectAll());
802 ASSERT_TRUE(omnibox_view()->SelectionAtEnd());
803
804 // Simulate a renderer-initated focus event. Expect the cursor position to be
805 // preserved, and that the omnibox did not select-all the text.
806 omnibox_view()->SetFocus(/*is_user_initiated=*/false);
807 EXPECT_FALSE(omnibox_view()->IsSelectAll());
808 EXPECT_TRUE(omnibox_view()->SelectionAtEnd());
809 }
810
TEST_F(OmniboxViewViewsTest,Emphasis)811 TEST_F(OmniboxViewViewsTest, Emphasis) {
812 constexpr struct {
813 const char* input;
814 bool expected_base_text_emphasized;
815 Range expected_emphasis_range;
816 Range expected_scheme_range;
817 } test_cases[] = {
818 {"data:text/html,Hello%20World", false, Range(0, 4), Range(0, 4)},
819 {"http://www.example.com/path/file.htm", false, Range(7, 22),
820 Range(0, 4)},
821 {"https://www.example.com/path/file.htm", false, Range(8, 23),
822 Range(0, 5)},
823 {"chrome-extension://ldfbacdbackkjhclmhnjabngnppnkagl", false,
824 Range::InvalidRange(), Range(0, 16)},
825 {"nosuchscheme://opaque/string", true, Range::InvalidRange(),
826 Range(0, 12)},
827 {"nosuchscheme:opaquestring", true, Range::InvalidRange(), Range(0, 12)},
828 {"host.com/path/file", false, Range(0, 8), Range::InvalidRange()},
829 {"This is plain text", true, Range::InvalidRange(),
830 Range::InvalidRange()},
831 };
832
833 for (const auto& test_case : test_cases) {
834 SCOPED_TRACE(test_case.input);
835
836 SetAndEmphasizeText(test_case.input, false);
837 EXPECT_EQ(test_case.expected_base_text_emphasized,
838 omnibox_view()->base_text_emphasis());
839 EXPECT_EQ(test_case.expected_emphasis_range,
840 omnibox_view()->emphasis_range());
841 EXPECT_FALSE(omnibox_view()->scheme_range().IsValid());
842
843 if (test_case.expected_scheme_range.IsValid()) {
844 SetAndEmphasizeText(test_case.input, true);
845 EXPECT_EQ(test_case.expected_base_text_emphasized,
846 omnibox_view()->base_text_emphasis());
847 EXPECT_EQ(test_case.expected_emphasis_range,
848 omnibox_view()->emphasis_range());
849 EXPECT_EQ(test_case.expected_scheme_range,
850 omnibox_view()->scheme_range());
851 }
852 }
853 }
854
TEST_F(OmniboxViewViewsTest,RevertOnBlur)855 TEST_F(OmniboxViewViewsTest, RevertOnBlur) {
856 location_bar_model()->set_url(GURL("https://example.com/"));
857 omnibox_view()->model()->ResetDisplayTexts();
858 omnibox_view()->RevertAll();
859
860 EXPECT_EQ(base::ASCIIToUTF16("https://example.com/"),
861 omnibox_view()->GetText());
862 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
863
864 // Set the view text without updating the model's user text. This usually
865 // occurs when the omnibox unapplies Steady State Elisions to temporarily show
866 // the full URL to the user.
867 omnibox_view()->SetWindowTextAndCaretPos(base::ASCIIToUTF16("view text"), 0,
868 false, false);
869 EXPECT_EQ(base::ASCIIToUTF16("view text"), omnibox_view()->GetText());
870 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
871
872 // Expect that on blur, we revert to the original text and are not in user
873 // input mode.
874 omnibox_textfield()->OnBlur();
875 EXPECT_EQ(base::ASCIIToUTF16("https://example.com/"),
876 omnibox_view()->GetText());
877 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
878
879 // Now set user text, which is reflected into the model as well.
880 omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
881 EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->GetText());
882 EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
883
884 // Expect that on blur, if the text has been edited, stay in user input mode.
885 omnibox_textfield()->OnBlur();
886 EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->GetText());
887 EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
888 }
889
TEST_F(OmniboxViewViewsTest,RevertOnEscape)890 TEST_F(OmniboxViewViewsTest, RevertOnEscape) {
891 location_bar_model()->set_url(GURL("https://permanent-text.com/"));
892 omnibox_view()->model()->ResetDisplayTexts();
893 omnibox_view()->RevertAll();
894
895 EXPECT_EQ(base::ASCIIToUTF16("https://permanent-text.com/"),
896 omnibox_view()->GetText());
897 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
898
899 omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
900 EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->GetText());
901 EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
902
903 // Expect that on Escape, the text is reverted to the permanent URL.
904 ui::KeyEvent escape(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
905 omnibox_textfield()->OnKeyEvent(&escape);
906
907 EXPECT_EQ(base::ASCIIToUTF16("https://permanent-text.com/"),
908 omnibox_view()->GetText());
909 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
910 }
911
TEST_F(OmniboxViewViewsTest,BackspaceExitsKeywordMode)912 TEST_F(OmniboxViewViewsTest, BackspaceExitsKeywordMode) {
913 omnibox_view()->SetUserText(base::UTF8ToUTF16("user text"));
914 omnibox_view()->model()->EnterKeywordModeForDefaultSearchProvider(
915 OmniboxEventProto::KEYBOARD_SHORTCUT);
916
917 ASSERT_EQ(base::UTF8ToUTF16("user text"), omnibox_view()->GetText());
918 ASSERT_TRUE(omnibox_view()->IsSelectAll());
919 ASSERT_FALSE(omnibox_view()->model()->keyword().empty());
920
921 // First backspace should clear the user text but not exit keyword mode.
922 ui::KeyEvent backspace(ui::ET_KEY_PRESSED, ui::VKEY_BACK, 0);
923 omnibox_textfield()->OnKeyEvent(&backspace);
924 EXPECT_TRUE(omnibox_view()->GetText().empty());
925 EXPECT_FALSE(omnibox_view()->model()->keyword().empty());
926
927 // Second backspace should exit keyword mode.
928 omnibox_textfield()->OnKeyEvent(&backspace);
929 EXPECT_TRUE(omnibox_view()->GetText().empty());
930 EXPECT_TRUE(omnibox_view()->model()->keyword().empty());
931 }
932
TEST_F(OmniboxViewViewsTest,BlurNeverExitsKeywordMode)933 TEST_F(OmniboxViewViewsTest, BlurNeverExitsKeywordMode) {
934 location_bar_model()->set_url(GURL());
935 omnibox_view()->model()->ResetDisplayTexts();
936 omnibox_view()->RevertAll();
937
938 // Enter keyword mode, but with no user text.
939 omnibox_view()->model()->EnterKeywordModeForDefaultSearchProvider(
940 OmniboxEventProto::KEYBOARD_SHORTCUT);
941 EXPECT_TRUE(omnibox_view()->GetText().empty());
942 EXPECT_FALSE(omnibox_view()->model()->keyword().empty());
943
944 // Expect that on blur, stay in keyword mode.
945 omnibox_textfield()->OnBlur();
946 EXPECT_TRUE(omnibox_view()->GetText().empty());
947 EXPECT_FALSE(omnibox_view()->model()->keyword().empty());
948 }
949
TEST_F(OmniboxViewViewsTest,PasteAndGoToUrlOrSearchCommand)950 TEST_F(OmniboxViewViewsTest, PasteAndGoToUrlOrSearchCommand) {
951 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
952 ui::ClipboardBuffer clipboard_buffer = ui::ClipboardBuffer::kCopyPaste;
953 command_updater()->UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, true);
954
955 // Test command is disabled for an empty clipboard.
956 clipboard->Clear(clipboard_buffer);
957 EXPECT_FALSE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
958
959 // Test input that's a valid URL.
960 base::string16 expected_text =
961 #if defined(OS_MAC)
962 base::ASCIIToUTF16("Pa&ste and Go to https://test.com");
963 #else
964 base::ASCIIToUTF16("Pa&ste and go to https://test.com");
965 #endif
966 ui::ScopedClipboardWriter(clipboard_buffer)
967 .WriteText(base::ASCIIToUTF16("https://test.com/"));
968 base::string16 returned_text =
969 omnibox_view()->GetLabelForCommandId(IDC_PASTE_AND_GO);
970 EXPECT_TRUE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
971 EXPECT_EQ(expected_text, returned_text);
972
973 // Test input that's URL-like. (crbug.com/980002).
974 expected_text =
975 #if defined(OS_MAC)
976 base::ASCIIToUTF16("Pa&ste and Go to test.com");
977 #else
978 base::ASCIIToUTF16("Pa&ste and go to test.com");
979 #endif
980 ui::ScopedClipboardWriter(clipboard_buffer)
981 .WriteText(base::ASCIIToUTF16("test.com"));
982 returned_text = omnibox_view()->GetLabelForCommandId(IDC_PASTE_AND_GO);
983 EXPECT_TRUE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
984 EXPECT_EQ(expected_text, returned_text);
985
986 // Test input that's search-like.
987 expected_text =
988 #if defined(OS_MAC)
989 base::WideToUTF16(
990 L"Pa&ste and Search for \x201Cthis is a test sentence\x201D");
991 #else
992 base::WideToUTF16(
993 L"Pa&ste and search for \x201Cthis is a test sentence\x201D");
994 #endif
995 ui::ScopedClipboardWriter(clipboard_buffer)
996 .WriteText(base::ASCIIToUTF16("this is a test sentence"));
997 returned_text = omnibox_view()->GetLabelForCommandId(IDC_PASTE_AND_GO);
998 EXPECT_TRUE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
999 EXPECT_EQ(expected_text, returned_text);
1000 }
1001
1002 // Verifies |OmniboxEditModel::State::needs_revert_and_select_all|, and verifies
1003 // a recent regression in this logic (see https://crbug.com/923290).
TEST_F(OmniboxViewViewsTest,SelectAllOnReactivateTabAfterDeleteAll)1004 TEST_F(OmniboxViewViewsTest, SelectAllOnReactivateTabAfterDeleteAll) {
1005 omnibox_edit_controller()->set_omnibox_view(omnibox_view());
1006
1007 auto web_contents1 =
1008 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
1009
1010 // Simulate a new tab with "about:blank".
1011 const GURL url_1("about:blank/");
1012 location_bar_model()->set_url(url_1);
1013 omnibox_view()->model()->ResetDisplayTexts();
1014 omnibox_view()->RevertAll();
1015 omnibox_view()->SaveStateToTab(web_contents1.get());
1016
1017 // Simulate creating another tab at "chrome://history". The second url should
1018 // be longer than the first (to trigger the bug).
1019 auto web_contents2 =
1020 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
1021 const GURL url_2("chrome://history/");
1022 EXPECT_GT(url_2.spec().size(), url_1.spec().size());
1023 // Notice the url is set before ResetDisplayTexts(), this matches what
1024 // actually happens in code.
1025 location_bar_model()->set_url(url_2);
1026 omnibox_view()->model()->ResetDisplayTexts();
1027 omnibox_view()->RevertAll();
1028
1029 // Delete all the text.
1030 omnibox_view()->SetUserText(base::string16());
1031 EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
1032
1033 // Switch back to the first url.
1034 location_bar_model()->set_url(url_1);
1035 omnibox_view()->SaveStateToTab(web_contents2.get());
1036 omnibox_view()->OnTabChanged(web_contents1.get());
1037
1038 // Switch back to the second url. Even though the text was deleted earlier,
1039 // the previous text (|url_2|) should be restored *and* all the text selected.
1040 location_bar_model()->set_url(url_2);
1041 omnibox_view()->SaveStateToTab(web_contents1.get());
1042 omnibox_view()->OnTabChanged(web_contents2.get());
1043 EXPECT_EQ(url_2, GURL(base::UTF16ToUTF8(omnibox_view()->GetText())));
1044 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1045 }
1046
TEST_F(OmniboxViewViewsTest,SelectAllDuringMouseDown)1047 TEST_F(OmniboxViewViewsTest, SelectAllDuringMouseDown) {
1048 omnibox_textfield()->OnMousePressed(
1049 CreateMouseEvent(ui::ET_MOUSE_PRESSED, {0, 0}));
1050 omnibox_view()->SetUserText(base::ASCIIToUTF16("abc"));
1051 ui::KeyEvent event_a(ui::ET_KEY_PRESSED, ui::VKEY_A, 0);
1052 EXPECT_FALSE(omnibox_view()->IsSelectAll());
1053 omnibox_textfield_view()->OnKeyPressed(event_a);
1054 // Normally SelectAll happens after OnMouseRelease. Verifying this happens
1055 // during OnKeyPress when the mouse is down.
1056 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1057 }
1058
TEST_F(OmniboxViewViewsTest,SetWindowTextAndCaretPos)1059 TEST_F(OmniboxViewViewsTest, SetWindowTextAndCaretPos) {
1060 // googl|e.com
1061 omnibox_view()->SetWindowTextAndCaretPos(base::UTF8ToUTF16("google.com"), 5,
1062 false, false);
1063 EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
1064 EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1065 (std::vector<Range>{{5, 5}}));
1066 }
1067
TEST_F(OmniboxViewViewsTest,OnInlineAutocompleteTextMaybeChanged)1068 TEST_F(OmniboxViewViewsTest, OnInlineAutocompleteTextMaybeChanged) {
1069 // No selection, google.com|
1070 omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1071 base::UTF8ToUTF16("google.com"), {{10, 10}}, 10);
1072 EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
1073 EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1074 (std::vector<Range>{{10, 10}}));
1075
1076 // Single selection, gmai[l.com]
1077 omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1078 base::UTF8ToUTF16("gmail.com"), {{9, 4}}, 4);
1079 EXPECT_EQ(base::ASCIIToUTF16("gmail.com"), omnibox_view()->GetText());
1080 EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1081 (std::vector<Range>{{9, 4}}));
1082
1083 // Multiselection, [go]ogl[e.com]
1084 omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1085 base::UTF8ToUTF16("google.com"), {{10, 5}, {0, 2}}, 3);
1086 EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
1087 EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1088 (std::vector<Range>{{10, 5}, {0, 2}}));
1089 }
1090
TEST_F(OmniboxViewViewsTest,OverflowingAutocompleteText)1091 TEST_F(OmniboxViewViewsTest, OverflowingAutocompleteText) {
1092 // Make the Omnibox narrow so it can't fit the entire string (~650px), but
1093 // wide enough to fit the user text (~65px).
1094 int kOmniboxWidth = 100;
1095 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1096 render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
1097
1098 omnibox_textfield()->OnFocus();
1099 omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1100 base::ASCIIToUTF16("user text. Followed by very long autocompleted text "
1101 "that is unlikely to fit in |kOmniboxWidth|"),
1102 {{94, 10}}, 10);
1103
1104 // NOTE: Technically (depending on the font), this expectation could fail if
1105 // 'user text' doesn't fit in 100px or the entire string fits in 100px.
1106 EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
1107 EXPECT_FALSE(omnibox_view()->IsSelectAll());
1108
1109 // On blur, the display should remain to the start of the text.
1110 omnibox_textfield()->OnBlur();
1111 EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
1112 EXPECT_FALSE(omnibox_view()->IsSelectAll());
1113 }
1114
TEST_F(OmniboxViewViewsTest,ElideAnimationDoesntStartIfNoVisibleChange)1115 TEST_F(OmniboxViewViewsTest, ElideAnimationDoesntStartIfNoVisibleChange) {
1116 SetUpSimplifiedDomainTest();
1117 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1118 OmniboxViewViews::ElideAnimation elide_animation(omnibox_view(), render_text);
1119 // Before any animation runs, the elide from rectangle is considered to be
1120 // render_text's DisplayRect, so set it manually to be the current URL length.
1121 gfx::Rect full_url_bounds;
1122 for (auto rect : render_text->GetSubstringBounds(
1123 gfx::Range(0, omnibox_view()->GetOmniboxTextLength()))) {
1124 full_url_bounds.Union(rect);
1125 }
1126 render_text->SetDisplayRect(full_url_bounds);
1127 // Start the animation, and have it animate to the current state.
1128 elide_animation.Start(
1129 gfx::Range(0,
1130 omnibox_view()->GetOmniboxTextLength()), /* elide_to_bounds */
1131 0, /* delay_ms */
1132 {gfx::Range(0, 0)}, /* ranges_surrounding_simplified_domain */
1133 SK_ColorBLACK, /* starting_color */
1134 SK_ColorBLACK); /* ending_color */
1135 // Animation shouldn't have been started.
1136 EXPECT_FALSE(elide_animation.IsAnimating());
1137 }
1138
1139 class OmniboxViewViewsClipboardTest
1140 : public OmniboxViewViewsTest,
1141 public ::testing::WithParamInterface<ui::TextEditCommand> {
1142 public:
SetUp()1143 void SetUp() override {
1144 OmniboxViewViewsTest::SetUp();
1145
1146 location_bar_model()->set_url(GURL("https://test.com/"));
1147 omnibox_view()->model()->ResetDisplayTexts();
1148 omnibox_view()->RevertAll();
1149 }
1150 };
1151
TEST_P(OmniboxViewViewsClipboardTest,ClipboardCopyOrCutURL)1152 TEST_P(OmniboxViewViewsClipboardTest, ClipboardCopyOrCutURL) {
1153 omnibox_view()->SelectAll(false);
1154 ASSERT_TRUE(omnibox_view()->IsSelectAll());
1155
1156 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1157 ui::ClipboardBuffer clipboard_buffer = ui::ClipboardBuffer::kCopyPaste;
1158
1159 clipboard->Clear(clipboard_buffer);
1160 ui::TextEditCommand clipboard_command = GetParam();
1161 textfield_test_api()->ExecuteTextEditCommand(clipboard_command);
1162
1163 base::string16 expected_text;
1164 if (clipboard_command == ui::TextEditCommand::COPY)
1165 expected_text = base::ASCIIToUTF16("https://test.com/");
1166 EXPECT_EQ(expected_text, omnibox_view()->GetText());
1167
1168 // Make sure the plain text format is available, but the HTML one isn't.
1169 EXPECT_TRUE(
1170 clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(),
1171 clipboard_buffer, /* data_dst = */ nullptr));
1172 EXPECT_FALSE(
1173 clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(),
1174 clipboard_buffer, /* data_dst = */ nullptr));
1175
1176 // Windows clipboard only supports text URLs.
1177 // Mac clipboard not reporting URL format available for some reason.
1178 // crbug.com/751031
1179 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
1180 EXPECT_TRUE(
1181 clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetUrlType(),
1182 clipboard_buffer, /* data_dst = */ nullptr));
1183 #endif
1184
1185 std::string read_from_clipboard;
1186 clipboard->ReadAsciiText(clipboard_buffer, /* data_dst = */ nullptr,
1187 &read_from_clipboard);
1188 EXPECT_EQ("https://test.com/", read_from_clipboard);
1189 }
1190
TEST_P(OmniboxViewViewsClipboardTest,ClipboardCopyOrCutUserText)1191 TEST_P(OmniboxViewViewsClipboardTest, ClipboardCopyOrCutUserText) {
1192 omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
1193 omnibox_view()->SelectAll(false);
1194 ASSERT_TRUE(omnibox_view()->IsSelectAll());
1195
1196 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1197 ui::ClipboardBuffer clipboard_buffer = ui::ClipboardBuffer::kCopyPaste;
1198
1199 clipboard->Clear(clipboard_buffer);
1200 ui::TextEditCommand clipboard_command = GetParam();
1201 textfield_test_api()->ExecuteTextEditCommand(clipboard_command);
1202
1203 if (clipboard_command == ui::TextEditCommand::CUT)
1204 EXPECT_EQ(base::string16(), omnibox_view()->GetText());
1205
1206 // Make sure HTML format isn't written. See
1207 // BookmarkNodeData::WriteToClipboard() for details.
1208 EXPECT_TRUE(
1209 clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(),
1210 clipboard_buffer, /* data_dst = */ nullptr));
1211 EXPECT_FALSE(
1212 clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(),
1213 clipboard_buffer, /* data_dst = */ nullptr));
1214
1215 std::string read_from_clipboard;
1216 clipboard->ReadAsciiText(clipboard_buffer, /* data_dst = */ nullptr,
1217 &read_from_clipboard);
1218 EXPECT_EQ("user text", read_from_clipboard);
1219 }
1220
1221 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsClipboardTest,
1222 OmniboxViewViewsClipboardTest,
1223 ::testing::Values(ui::TextEditCommand::COPY,
1224 ui::TextEditCommand::CUT));
1225
1226 class OmniboxViewViewsSteadyStateElisionsTest : public OmniboxViewViewsTest {
1227 public:
OmniboxViewViewsSteadyStateElisionsTest()1228 OmniboxViewViewsSteadyStateElisionsTest() : OmniboxViewViewsTest({}, {}) {}
1229
1230 protected:
1231 const int kCharacterWidth = 10;
1232 const GURL kFullUrl = GURL("https://www.example.com/");
1233
SetUp()1234 void SetUp() override {
1235 OmniboxViewViewsTest::SetUp();
1236
1237 // Advance 5 seconds from epoch so the time is not considered null.
1238 clock_.Advance(base::TimeDelta::FromSeconds(5));
1239 ui::SetEventTickClockForTesting(&clock_);
1240
1241 location_bar_model()->set_url(kFullUrl);
1242 location_bar_model()->set_url_for_display(
1243 base::ASCIIToUTF16("example.com"));
1244
1245 gfx::test::RenderTextTestApi render_text_test_api(
1246 omnibox_view()->GetRenderText());
1247 render_text_test_api.SetGlyphWidth(kCharacterWidth);
1248
1249 omnibox_view()->model()->ResetDisplayTexts();
1250 omnibox_view()->RevertAll();
1251 }
1252
TearDown()1253 void TearDown() override {
1254 ui::SetEventTickClockForTesting(nullptr);
1255 OmniboxViewViewsTest::TearDown();
1256 }
1257
BlurOmnibox()1258 void BlurOmnibox() {
1259 ASSERT_TRUE(omnibox_view()->HasFocus());
1260 omnibox_view()->GetFocusManager()->ClearFocus();
1261 ASSERT_FALSE(omnibox_view()->HasFocus());
1262 }
1263
ExpectFullUrlDisplayed()1264 void ExpectFullUrlDisplayed() {
1265 EXPECT_EQ(base::UTF8ToUTF16(kFullUrl.spec()), omnibox_view()->GetText());
1266 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
1267 }
1268
IsElidedUrlDisplayed()1269 bool IsElidedUrlDisplayed() {
1270 return omnibox_view()->GetText() == base::ASCIIToUTF16("example.com") &&
1271 !omnibox_view()->model()->user_input_in_progress();
1272 }
1273
1274 // Gets a point at |x_offset| from the beginning of the RenderText.
GetPointInTextAtXOffset(int x_offset)1275 gfx::Point GetPointInTextAtXOffset(int x_offset) {
1276 gfx::Rect bounds = omnibox_view()->GetRenderText()->display_rect();
1277 return gfx::Point(bounds.x() + x_offset, bounds.y() + bounds.height() / 2);
1278 }
1279
1280 // Sends a mouse down and mouse up event at |x_offset| pixels from the
1281 // beginning of the RenderText.
SendMouseClick(int x_offset)1282 void SendMouseClick(int x_offset) {
1283 gfx::Point point = GetPointInTextAtXOffset(x_offset);
1284 SendMouseClickAtPoint(point, 1);
1285 }
1286
1287 // Sends a mouse down and mouse up event at a point
1288 // beginning of the RenderText.
SendMouseClickAtPoint(gfx::Point point,int click_count,int event_flags=ui::EF_LEFT_MOUSE_BUTTON)1289 void SendMouseClickAtPoint(gfx::Point point,
1290 int click_count,
1291 int event_flags = ui::EF_LEFT_MOUSE_BUTTON) {
1292 auto mouse_pressed =
1293 CreateMouseEvent(ui::ET_MOUSE_PRESSED, point, event_flags);
1294 mouse_pressed.SetClickCount(click_count);
1295 omnibox_textfield()->OnMousePressed(mouse_pressed);
1296 auto mouse_released =
1297 CreateMouseEvent(ui::ET_MOUSE_RELEASED, point, event_flags);
1298 mouse_released.SetClickCount(click_count);
1299 omnibox_textfield()->OnMouseReleased(mouse_released);
1300 }
1301
1302 // Used to access members that are marked private in views::TextField.
clock()1303 base::SimpleTestTickClock* clock() { return &clock_; }
1304
1305 private:
1306 base::SimpleTestTickClock clock_;
1307 };
1308
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UrlStartsInElidedState)1309 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UrlStartsInElidedState) {
1310 EXPECT_TRUE(IsElidedUrlDisplayed());
1311 }
1312
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideOnArrowKey)1313 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideOnArrowKey) {
1314 SendMouseClick(0);
1315
1316 // Right key should unelide and move the cursor to the end.
1317 omnibox_textfield_view()->OnKeyPressed(
1318 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, 0));
1319 ExpectFullUrlDisplayed();
1320 size_t start, end;
1321 omnibox_view()->GetSelectionBounds(&start, &end);
1322 EXPECT_EQ(23U, start);
1323 EXPECT_EQ(23U, end);
1324
1325 // Blur to restore the elided URL, then click on the Omnibox again to refocus.
1326 BlurOmnibox();
1327 SendMouseClick(0);
1328
1329 // Left key should unelide and move the cursor to the beginning of the elided
1330 // part.
1331 omnibox_textfield_view()->OnKeyPressed(
1332 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LEFT, 0));
1333 ExpectFullUrlDisplayed();
1334 omnibox_view()->GetSelectionBounds(&start, &end);
1335 EXPECT_EQ(12U, start);
1336 EXPECT_EQ(12U, end);
1337 }
1338
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideOnHomeKey)1339 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideOnHomeKey) {
1340 SendMouseClick(0);
1341
1342 // Home key should unelide and move the cursor to the beginning of the full
1343 // unelided URL.
1344 omnibox_textfield_view()->OnKeyPressed(
1345 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_HOME, 0));
1346 ExpectFullUrlDisplayed();
1347 size_t start, end;
1348 omnibox_view()->GetSelectionBounds(&start, &end);
1349 EXPECT_EQ(0U, start);
1350 EXPECT_EQ(0U, end);
1351 }
1352
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideViaEndKeyWorksWithIntranetUrls)1353 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1354 UnelideViaEndKeyWorksWithIntranetUrls) {
1355 location_bar_model()->set_url(GURL("https://foobar/"));
1356 location_bar_model()->set_formatted_full_url(
1357 base::ASCIIToUTF16("https://foobar"));
1358 location_bar_model()->set_url_for_display(base::ASCIIToUTF16("foobar/"));
1359
1360 omnibox_view()->model()->ResetDisplayTexts();
1361 omnibox_view()->RevertAll();
1362
1363 SendMouseClick(0);
1364
1365 // End key should unelide and move the cursor to the end of the full URL.
1366 omnibox_textfield_view()->OnKeyPressed(
1367 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_END, 0));
1368
1369 EXPECT_EQ(base::ASCIIToUTF16("https://foobar"), omnibox_view()->GetText());
1370 EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
1371
1372 size_t start, end;
1373 omnibox_view()->GetSelectionBounds(&start, &end);
1374 EXPECT_EQ(14U, start);
1375 EXPECT_EQ(14U, end);
1376 }
1377
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,GestureTaps)1378 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, GestureTaps) {
1379 ui::GestureEvent tap_down(0, 0, 0, ui::EventTimeForNow(),
1380 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1381 omnibox_textfield()->OnGestureEvent(&tap_down);
1382
1383 // Select all on first tap.
1384 ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
1385 tap_details.set_tap_count(1);
1386 ui::GestureEvent tap(0, 0, 0, ui::EventTimeForNow(), tap_details);
1387 omnibox_textfield()->OnGestureEvent(&tap);
1388
1389 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1390 EXPECT_TRUE(IsElidedUrlDisplayed());
1391
1392 // Unelide on second tap (cursor placement).
1393 omnibox_textfield()->OnGestureEvent(&tap);
1394 ExpectFullUrlDisplayed();
1395 }
1396
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,FirstMouseClickFocusesOnly)1397 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, FirstMouseClickFocusesOnly) {
1398 EXPECT_FALSE(omnibox_view()->IsSelectAll());
1399
1400 SendMouseClick(0);
1401
1402 EXPECT_TRUE(IsElidedUrlDisplayed());
1403 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1404 EXPECT_TRUE(omnibox_view()->HasFocus());
1405 }
1406
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,NegligibleDragKeepsElisions)1407 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, NegligibleDragKeepsElisions) {
1408 gfx::Point click_point = GetPointInTextAtXOffset(2 * kCharacterWidth);
1409 omnibox_textfield()->OnMousePressed(
1410 CreateMouseEvent(ui::ET_MOUSE_PRESSED, click_point));
1411
1412 // Offset the drag and release point by an insignificant 2 px.
1413 gfx::Point drag_point = click_point;
1414 drag_point.Offset(2, 0);
1415 omnibox_textfield()->OnMouseDragged(
1416 CreateMouseEvent(ui::ET_MOUSE_DRAGGED, drag_point));
1417 omnibox_textfield()->OnMouseReleased(
1418 CreateMouseEvent(ui::ET_MOUSE_RELEASED, drag_point));
1419
1420 // Expect that after a negligible drag and release, everything is selected.
1421 EXPECT_TRUE(IsElidedUrlDisplayed());
1422 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1423 EXPECT_TRUE(omnibox_view()->HasFocus());
1424 }
1425
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,CaretPlacementByMouse)1426 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, CaretPlacementByMouse) {
1427 SendMouseClick(0);
1428
1429 // Advance the clock 5 seconds so the second click is not interpreted as a
1430 // double click.
1431 clock()->Advance(base::TimeDelta::FromSeconds(5));
1432
1433 // Second click should unelide only on mouse release.
1434 omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1435 ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1436 EXPECT_TRUE(IsElidedUrlDisplayed());
1437 omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1438 ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1439 ExpectFullUrlDisplayed();
1440
1441 // Verify the cursor position is https://www.ex|ample.com. It should be
1442 // between 'x' and 'a', because the click was after the second character of
1443 // the unelided text "example.com".
1444 size_t start, end;
1445 omnibox_view()->GetSelectionBounds(&start, &end);
1446 EXPECT_EQ(14U, start);
1447 EXPECT_EQ(14U, end);
1448 }
1449
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseDoubleClick)1450 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseDoubleClick) {
1451 SendMouseClick(4 * kCharacterWidth);
1452
1453 // Second click without advancing the clock should be a double-click, which
1454 // should do a single word selection and unelide the text on mousedown.
1455 omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1456 ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1457 ExpectFullUrlDisplayed();
1458
1459 // Verify that the selection is https://www.|example|.com, since the
1460 // double-click after the fourth character of the unelided text "example.com".
1461 size_t start, end;
1462 omnibox_view()->GetSelectionBounds(&start, &end);
1463 EXPECT_EQ(12U, start);
1464 EXPECT_EQ(19U, end);
1465 }
1466
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseSingleThenDoubleClick)1467 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseSingleThenDoubleClick) {
1468 EXPECT_TRUE(IsElidedUrlDisplayed());
1469 auto point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1470 SendMouseClickAtPoint(point, 1);
1471 EXPECT_TRUE(IsElidedUrlDisplayed());
1472 EXPECT_EQ(base::ASCIIToUTF16("example.com"), omnibox_view()->GetText());
1473
1474 // Verify that the whole full URL is selected.
1475 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1476
1477 // Advance the clock 5 seconds so the next click is not interpreted as a
1478 // double click.
1479 clock()->Advance(base::TimeDelta::FromSeconds(5));
1480
1481 // Double click
1482 SendMouseClickAtPoint(point, 1);
1483 ExpectFullUrlDisplayed();
1484 SendMouseClickAtPoint(point, 2);
1485 ExpectFullUrlDisplayed();
1486
1487 // Verify that the selection is https://www.|example|.com, since the
1488 // double-click after the fourth character of the unelided text "example.com".
1489 size_t start, end;
1490 omnibox_view()->GetSelectionBounds(&start, &end);
1491 EXPECT_EQ(12U, start);
1492 EXPECT_EQ(19U, end);
1493 }
1494
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseSingleThenRightClick)1495 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseSingleThenRightClick) {
1496 EXPECT_TRUE(IsElidedUrlDisplayed());
1497 auto point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1498 SendMouseClickAtPoint(point, 1);
1499 EXPECT_TRUE(IsElidedUrlDisplayed());
1500 EXPECT_EQ(base::ASCIIToUTF16("example.com"), omnibox_view()->GetText());
1501
1502 // Verify that the whole full URL is selected.
1503 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1504
1505 // Advance the clock 5 seconds so the next click is not interpreted as a
1506 // double click.
1507 clock()->Advance(base::TimeDelta::FromSeconds(5));
1508
1509 // Right click
1510 SendMouseClickAtPoint(point, 1, ui::EF_RIGHT_MOUSE_BUTTON);
1511 EXPECT_TRUE(IsElidedUrlDisplayed());
1512 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1513 EXPECT_TRUE(omnibox_view()->HasFocus());
1514 }
1515
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseTripleClick)1516 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseTripleClick) {
1517 auto point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1518 SendMouseClickAtPoint(point, 1);
1519 SendMouseClickAtPoint(point, 2);
1520 SendMouseClickAtPoint(point, 3);
1521
1522 ExpectFullUrlDisplayed();
1523
1524 // Verify that the whole full URL is selected.
1525 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1526 size_t start, end;
1527 omnibox_view()->GetSelectionBounds(&start, &end);
1528 EXPECT_EQ(0U, start);
1529 EXPECT_EQ(24U, end);
1530 }
1531
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseClickDrag)1532 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseClickDrag) {
1533 omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1534 ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1535 EXPECT_TRUE(IsElidedUrlDisplayed());
1536
1537 // Expect that during the drag, the URL is still elided.
1538 omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1539 ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1540 EXPECT_TRUE(IsElidedUrlDisplayed());
1541
1542 // Expect that ex|am|ple.com is the drag selected portion while dragging.
1543 size_t start, end;
1544 omnibox_view()->GetSelectionBounds(&start, &end);
1545 EXPECT_EQ(2U, start);
1546 EXPECT_EQ(4U, end);
1547
1548 omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1549 ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1550 ExpectFullUrlDisplayed();
1551
1552 // Expect that https://www.ex|am|ple.com is the selected portion after the
1553 // user releases the mouse.
1554 omnibox_view()->GetSelectionBounds(&start, &end);
1555 EXPECT_EQ(14U, start);
1556 EXPECT_EQ(16U, end);
1557 }
1558
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseClickDragToBeginningSelectingText)1559 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1560 MouseClickDragToBeginningSelectingText) {
1561 // Backwards drag-select this portion of the elided URL: |exam|ple.com
1562 omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1563 ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1564 omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1565 ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1566 omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1567 ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1568 ExpectFullUrlDisplayed();
1569
1570 // Since the selection did not look like a URL, expect the following selected
1571 // selected portion after the user releases the mouse:
1572 // https://www.|exam|ple.com
1573 size_t start, end;
1574 omnibox_view()->GetSelectionBounds(&start, &end);
1575 EXPECT_EQ(16U, start);
1576 EXPECT_EQ(12U, end);
1577 }
1578
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseClickDragToBeginningSelectingURL)1579 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1580 MouseClickDragToBeginningSelectingURL) {
1581 // Backwards drag-select this portion of the elided URL: |example.co|m
1582 omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1583 ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(10 * kCharacterWidth)));
1584 omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1585 ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1586 omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1587 ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1588 ExpectFullUrlDisplayed();
1589
1590 // Since the selection does look like a URL, expect the following selected
1591 // selected portion after the user releases the mouse:
1592 // |https://www.example.co|m
1593 size_t start, end;
1594 omnibox_view()->GetSelectionBounds(&start, &end);
1595 EXPECT_EQ(22U, start);
1596 EXPECT_EQ(0U, end);
1597 }
1598
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseDoubleClickDrag)1599 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseDoubleClickDrag) {
1600 // Expect that after a double-click after the third character of the elided
1601 // text, the text is unelided, and https://www.|example|.com is selected.
1602 SendMouseClick(4 * kCharacterWidth);
1603 omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1604 ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1605 ExpectFullUrlDisplayed();
1606 size_t start, end;
1607 omnibox_view()->GetSelectionBounds(&start, &end);
1608 EXPECT_EQ(12U, start);
1609 EXPECT_EQ(19U, end);
1610
1611 // Expect that negligible drags are ignored immediately after unelision, as
1612 // the text has likely shifted, and we don't want to accidentally change the
1613 // selection.
1614 gfx::Point drag_point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1615 drag_point.Offset(1, 1); // Offset test point one pixel in each dimension.
1616 omnibox_textfield()->OnMouseDragged(
1617 CreateMouseEvent(ui::ET_MOUSE_DRAGGED, drag_point));
1618 omnibox_view()->GetSelectionBounds(&start, &end);
1619 EXPECT_EQ(12U, start);
1620 EXPECT_EQ(19U, end);
1621
1622 // Expect that dragging to the fourth character of the full URL (between the
1623 // the 'p' and the 's' of https), will word-select the scheme, subdomain, and
1624 // domain, so the new selection will be |https://www.example|.com. The
1625 // expected selection is backwards, since we are dragging the mouse from the
1626 // domain to the scheme.
1627 omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1628 ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1629 ExpectFullUrlDisplayed();
1630 omnibox_view()->GetSelectionBounds(&start, &end);
1631 EXPECT_EQ(19U, start);
1632 EXPECT_EQ(0U, end);
1633
1634 // Expect the selection to stay the same after mouse-release.
1635 omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1636 ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1637 ExpectFullUrlDisplayed();
1638 omnibox_view()->GetSelectionBounds(&start, &end);
1639 EXPECT_EQ(19U, start);
1640 EXPECT_EQ(0U, end);
1641 }
1642
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,ReelideOnBlur)1643 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, ReelideOnBlur) {
1644 // Double-click should unelide the URL by making a partial selection.
1645 SendMouseClick(4 * kCharacterWidth);
1646 SendMouseClick(4 * kCharacterWidth);
1647 ExpectFullUrlDisplayed();
1648
1649 BlurOmnibox();
1650 EXPECT_TRUE(IsElidedUrlDisplayed());
1651 }
1652
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,DontReelideOnBlurIfEdited)1653 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, DontReelideOnBlurIfEdited) {
1654 // Double-click should unelide the URL by making a partial selection.
1655 SendMouseClick(4 * kCharacterWidth);
1656 SendMouseClick(4 * kCharacterWidth);
1657 ExpectFullUrlDisplayed();
1658
1659 // Since the domain word is selected, pressing 'a' should replace the domain.
1660 ui::KeyEvent char_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, 0,
1661 ui::DomKey::FromCharacter('a'),
1662 ui::EventTimeForNow());
1663 omnibox_textfield()->InsertChar(char_event);
1664 EXPECT_EQ(base::ASCIIToUTF16("https://www.a.com/"),
1665 omnibox_view()->GetText());
1666 EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
1667
1668 // Now that we've edited the text, blurring should not re-elide the URL.
1669 BlurOmnibox();
1670 EXPECT_EQ(base::ASCIIToUTF16("https://www.a.com/"),
1671 omnibox_view()->GetText());
1672 EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
1673 }
1674
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,DontReelideOnBlurIfWidgetDeactivated)1675 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1676 DontReelideOnBlurIfWidgetDeactivated) {
1677 SendMouseClick(0);
1678 SendMouseClick(0);
1679 ExpectFullUrlDisplayed();
1680
1681 // Create a different Widget that will take focus away from the test widget
1682 // containing our test Omnibox.
1683 std::unique_ptr<views::Widget> other_widget = CreateTestWidget();
1684 other_widget->Show();
1685 ExpectFullUrlDisplayed();
1686
1687 omnibox_view()->GetWidget()->Activate();
1688 ExpectFullUrlDisplayed();
1689 }
1690
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,SaveSelectAllOnBlurAndRefocus)1691 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, SaveSelectAllOnBlurAndRefocus) {
1692 SendMouseClick(0);
1693 EXPECT_TRUE(IsElidedUrlDisplayed());
1694 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1695
1696 // Blurring and refocusing should preserve a select-all state.
1697 BlurOmnibox();
1698 omnibox_view()->RequestFocus();
1699 EXPECT_TRUE(omnibox_view()->HasFocus());
1700 EXPECT_TRUE(IsElidedUrlDisplayed());
1701 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1702 }
1703
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideFromModel)1704 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideFromModel) {
1705 EXPECT_TRUE(IsElidedUrlDisplayed());
1706
1707 omnibox_view()->model()->Unelide();
1708 EXPECT_TRUE(omnibox_view()->IsSelectAll());
1709 size_t start, end;
1710 omnibox_view()->GetSelectionBounds(&start, &end);
1711 EXPECT_EQ(24U, start);
1712 EXPECT_EQ(0U, end);
1713 ExpectFullUrlDisplayed();
1714 }
1715
1716 // Returns true if |render_text|'s current display rect and offset display at
1717 // least part of |path_bounds|, but not the full |display_url|. This is useful
1718 // for checking the displayed text partway through an animation.
IsPartlyThroughSimplifiedDomainElision(gfx::RenderText * render_text,const base::string16 & display_url,const gfx::Range & path_bounds)1719 bool IsPartlyThroughSimplifiedDomainElision(gfx::RenderText* render_text,
1720 const base::string16& display_url,
1721 const gfx::Range& path_bounds) {
1722 // First check if all of |display_url| is showing; if it is, we aren't partly
1723 // elided.
1724 gfx::Rect unelided_rect;
1725 for (const auto& rect :
1726 render_text->GetSubstringBounds(gfx::Range(0, display_url.size()))) {
1727 unelided_rect.Union(rect);
1728 }
1729 if (render_text->display_rect().Contains(unelided_rect) &&
1730 render_text->GetUpdatedDisplayOffset().x() == 0) {
1731 return false;
1732 }
1733 // Now check if at least some of |path| is visible.
1734 gfx::Rect path_rect;
1735 for (const auto& rect : render_text->GetSubstringBounds(path_bounds)) {
1736 path_rect.Union(rect);
1737 }
1738 return render_text->display_rect().Intersects(path_rect);
1739 }
1740
1741 class OmniboxViewViewsNoSimplifiedDomainTest : public OmniboxViewViewsTest {
1742 public:
OmniboxViewViewsNoSimplifiedDomainTest()1743 OmniboxViewViewsNoSimplifiedDomainTest()
1744 : OmniboxViewViewsTest(
1745 {},
1746 {omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction,
1747 omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover}) {}
1748
1749 OmniboxViewViewsNoSimplifiedDomainTest(
1750 const OmniboxViewViewsNoSimplifiedDomainTest&) = delete;
1751 OmniboxViewViewsNoSimplifiedDomainTest& operator=(
1752 const OmniboxViewViewsNoSimplifiedDomainTest&) = delete;
1753 };
1754
1755 // Tests that when no simplified domain field trials are enabled, URL components
1756 // are not hidden. Regression test for https://crbug.com/1093748.
TEST_F(OmniboxViewViewsNoSimplifiedDomainTest,UrlNotSimplifiedByDefault)1757 TEST_F(OmniboxViewViewsNoSimplifiedDomainTest, UrlNotSimplifiedByDefault) {
1758 SetUpSimplifiedDomainTest();
1759 omnibox_view()->EmphasizeURLComponents();
1760 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
1761 omnibox_view()->GetRenderText(),
1762 gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
1763 }
1764
1765 class OmniboxViewViewsRevealOnHoverTest
1766 : public OmniboxViewViewsTest,
1767 public ::testing::WithParamInterface<std::pair<bool, bool>> {
1768 public:
OmniboxViewViewsRevealOnHoverTest()1769 OmniboxViewViewsRevealOnHoverTest()
1770 : OmniboxViewViewsTest(
1771 GetParam().first
1772 ? std::vector<FeatureAndParams>(
1773 {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
1774 {}},
1775 {omnibox::kMaybeElideToRegistrableDomain,
1776 // Ensure all domains are elidable by policy.
1777 {{"max_unelided_host_length", "0"}}}})
1778 : std::vector<FeatureAndParams>(
1779 {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
1780 {}}}),
1781 {},
1782 GetParam().second) {
1783 // The lookalike allowlist is used by the registrable-domain-elision code.
1784 reputation::InitializeBlankLookalikeAllowlistForTesting();
1785 }
1786
1787 OmniboxViewViewsRevealOnHoverTest(const OmniboxViewViewsRevealOnHoverTest&) =
1788 delete;
1789 OmniboxViewViewsRevealOnHoverTest& operator=(
1790 const OmniboxViewViewsRevealOnHoverTest&) = delete;
1791
1792 protected:
ShouldElideToRegistrableDomain()1793 bool ShouldElideToRegistrableDomain() { return GetParam().first; }
1794 };
1795
1796 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsRevealOnHoverTest,
1797 OmniboxViewViewsRevealOnHoverTest,
1798 ::testing::ValuesIn({std::make_pair(true, false),
1799 std::make_pair(false, false),
1800 std::make_pair(true, true),
1801 std::make_pair(false, true)}));
1802
1803 // Tests the field trial variation that shows a simplified domain by default and
1804 // reveals the unsimplified URL on hover.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverAndExit)1805 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExit) {
1806 SetUpSimplifiedDomainTest();
1807 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1808 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1809 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
1810 kSimplifiedDomainDisplayUrlSubdomain,
1811 kSimplifiedDomainDisplayUrlHostnameAndScheme,
1812 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
1813
1814 // As soon as the mouse hovers over the omnibox, the unelide animation should
1815 // start running.
1816 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
1817 OmniboxViewViews::ElideAnimation* hover_animation =
1818 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
1819 ASSERT_TRUE(hover_animation);
1820 EXPECT_TRUE(hover_animation->IsAnimating());
1821
1822 // Advance the clock through the animation.
1823 ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation(
1824 OmniboxFieldTrial::UnelideURLOnHoverThresholdMs()));
1825 // After the extended hover threshold has elapsed, the display text shouldn't
1826 // have changed yet.
1827 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1828 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
1829 kSimplifiedDomainDisplayUrlSubdomain,
1830 kSimplifiedDomainDisplayUrlHostnameAndScheme,
1831 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
1832
1833 // Now advance through the unelision and check the display text. We assume
1834 // that the animation takes less than 1 second.
1835 ASSERT_NO_FATAL_FAILURE(
1836 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1837 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
1838 render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
1839 EXPECT_FALSE(hover_animation->IsAnimating());
1840 // Check that the path and subdomain are not transparent.
1841 EXPECT_NE(SK_ColorTRANSPARENT,
1842 omnibox_view()->GetLatestColorForRange(
1843 gfx::Range(kSimplifiedDomainDisplayUrlHostnameAndScheme.size(),
1844 kSimplifiedDomainDisplayUrl.size())));
1845 EXPECT_NE(SK_ColorTRANSPARENT,
1846 omnibox_view()->GetLatestColorForRange(gfx::Range(
1847 0, kSimplifiedDomainDisplayUrlSubdomainAndScheme.size())));
1848
1849 // Now exit the mouse. At this point the elision animation should run.
1850 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_EXITED, {0, 0}));
1851 EXPECT_TRUE(hover_animation->IsAnimating());
1852 ASSERT_NO_FATAL_FAILURE(
1853 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1854 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1855 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
1856 kSimplifiedDomainDisplayUrlSubdomain,
1857 kSimplifiedDomainDisplayUrlHostnameAndScheme,
1858 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
1859 }
1860
1861 // Tests the field trial variation that shows a simplified domain by default and
1862 // reveals the unsimplified URL on hover, using an IDN url.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverAndExitIDN)1863 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExitIDN) {
1864 // The display URL used in simplified domain display tests.
1865 const base::string16 kSimplifiedDomainDisplayIDNUrl =
1866 base::UTF8ToUTF16("https://テスト.住所の例.test/bar");
1867 const base::string16 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme =
1868 base::UTF8ToUTF16("https://テスト.住所の例.test");
1869 const base::string16 kSimplifiedDomainDisplayIDNUrlSubdomainAndScheme =
1870 base::UTF8ToUTF16("https://テスト.");
1871 const base::string16 kSimplifiedDomainDisplayIDNUrlSubdomain =
1872 base::UTF8ToUTF16("テスト.");
1873 const base::string16 kSimplifiedDomainDisplayIDNUrlPath =
1874 base::UTF8ToUTF16("/bar");
1875 const base::string16 kSimplifiedDomainDisplayIDNUrlScheme =
1876 base::UTF8ToUTF16("https://");
1877 UpdateDisplayURL(kSimplifiedDomainDisplayIDNUrl);
1878 // Call OnThemeChanged() to create the animations.
1879 omnibox_view()->OnThemeChanged();
1880
1881 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1882 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1883 omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme,
1884 kSimplifiedDomainDisplayIDNUrlSubdomain,
1885 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme,
1886 kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain()));
1887
1888 // As soon as the mouse hovers over the omnibox, the unelide animation should
1889 // start running.
1890 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
1891 // Advance the clock through the animation.
1892 ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation(
1893 OmniboxFieldTrial::UnelideURLOnHoverThresholdMs()));
1894 // After the extended hover threshold has elapsed, the display text shouldn't
1895 // have changed yet.
1896 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1897 omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme,
1898 kSimplifiedDomainDisplayIDNUrlSubdomain,
1899 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme,
1900 kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain()));
1901
1902 // Now advance through the unelision and check the display text. We assume
1903 // that the animation takes less than 1 second.
1904 ASSERT_NO_FATAL_FAILURE(
1905 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1906 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
1907 render_text, gfx::Range(0, kSimplifiedDomainDisplayIDNUrl.size())));
1908 OmniboxViewViews::ElideAnimation* hover_animation =
1909 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
1910 ASSERT_TRUE(hover_animation);
1911 EXPECT_FALSE(hover_animation->IsAnimating());
1912 // Check that the path and subdomain are not transparent.
1913 EXPECT_NE(SK_ColorTRANSPARENT,
1914 omnibox_view()->GetLatestColorForRange(gfx::Range(
1915 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme.size(),
1916 kSimplifiedDomainDisplayIDNUrl.size())));
1917 EXPECT_NE(SK_ColorTRANSPARENT,
1918 omnibox_view()->GetLatestColorForRange(gfx::Range(
1919 0, kSimplifiedDomainDisplayIDNUrlSubdomainAndScheme.size())));
1920
1921 // Now exit the mouse. At this point the elision animation should run.
1922 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_EXITED, {0, 0}));
1923 EXPECT_TRUE(hover_animation->IsAnimating());
1924 ASSERT_NO_FATAL_FAILURE(
1925 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1926 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1927 omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme,
1928 kSimplifiedDomainDisplayIDNUrlSubdomain,
1929 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme,
1930 kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain()));
1931 }
1932
1933 // Tests the field trial variation that shows a simplified domain by default
1934 // using a private registry (https://publicsuffix.org/list/). Private registries
1935 // should be ignored when computing the simplified domain, to avoid creating
1936 // incentives for malicious sites to add themselves to the Public Suffix List.
TEST_P(OmniboxViewViewsRevealOnHoverTest,PrivateRegistry)1937 TEST_P(OmniboxViewViewsRevealOnHoverTest, PrivateRegistry) {
1938 // This test is only applicable when we elide to the registrable domain;
1939 // otherwise private vs public registries are irrelevant.
1940 if (!ShouldElideToRegistrableDomain())
1941 return;
1942
1943 const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrl =
1944 base::UTF8ToUTF16("https://foo.blogspot.com/bar");
1945 const base::string16
1946 kSimplifiedDomainDisplayPrivateRegistryUrlHostnameAndScheme =
1947 base::UTF8ToUTF16("https://foo.blogspot.com");
1948 const base::string16
1949 kSimplifiedDomainDisplayPrivateRegistryUrlSubdomainAndScheme =
1950 base::UTF8ToUTF16("https://foo.");
1951 const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrlSubdomain =
1952 base::UTF8ToUTF16("foo.");
1953 const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrlPath =
1954 base::UTF8ToUTF16("/bar");
1955 const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrlScheme =
1956 base::UTF8ToUTF16("https://");
1957 UpdateDisplayURL(kSimplifiedDomainDisplayPrivateRegistryUrl);
1958 // Call OnThemeChanged() to create the animations.
1959 omnibox_view()->OnThemeChanged();
1960
1961 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1962 omnibox_view(), kSimplifiedDomainDisplayPrivateRegistryUrlScheme,
1963 kSimplifiedDomainDisplayPrivateRegistryUrlSubdomain,
1964 kSimplifiedDomainDisplayPrivateRegistryUrlHostnameAndScheme,
1965 kSimplifiedDomainDisplayPrivateRegistryUrlPath,
1966 ShouldElideToRegistrableDomain()));
1967 }
1968
1969 // Tests the field trial variation that shows a simplified domain by default and
1970 // reveals the unsimplified URL on hover, using a URL where the path contains
1971 // the domain name.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverAndExitDomainInPath)1972 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExitDomainInPath) {
1973 // The display URL used in simplified domain display tests.
1974 const base::string16 kSimplifiedDomainDisplayRepeatedUrl =
1975 base::UTF8ToUTF16("https://ex.example.test/example.test");
1976 const base::string16 kSimplifiedDomainDisplayRepeatedUrlHostnameAndScheme =
1977 base::UTF8ToUTF16("https://ex.example.test");
1978 const base::string16 kSimplifiedDomainDisplayRepeatedUrlSubdomainAndScheme =
1979 base::UTF8ToUTF16("https://ex.");
1980 const base::string16 kSimplifiedDomainDisplayRepeatedUrlSubdomain =
1981 base::UTF8ToUTF16("ex.");
1982 const base::string16 kSimplifiedDomainDisplayRepeatedUrlPath =
1983 base::UTF8ToUTF16("/example.test");
1984 const base::string16 kSimplifiedDomainDisplayRepeatedUrlScheme =
1985 base::UTF8ToUTF16("https://");
1986 location_bar_model()->set_url(GURL(kSimplifiedDomainDisplayRepeatedUrl));
1987 location_bar_model()->set_url_for_display(
1988 kSimplifiedDomainDisplayRepeatedUrl);
1989 omnibox_view()->model()->ResetDisplayTexts();
1990 omnibox_view()->RevertAll();
1991 // Call OnThemeChanged() to create the animations.
1992 omnibox_view()->OnThemeChanged();
1993
1994 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1995 omnibox_view(), kSimplifiedDomainDisplayRepeatedUrlScheme,
1996 kSimplifiedDomainDisplayRepeatedUrlSubdomain,
1997 kSimplifiedDomainDisplayRepeatedUrlHostnameAndScheme,
1998 kSimplifiedDomainDisplayRepeatedUrlPath,
1999 ShouldElideToRegistrableDomain()));
2000 }
2001
2002 class OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest
2003 : public OmniboxViewViewsTest,
2004 public ::testing::WithParamInterface<std::pair<bool, bool>> {
2005 public:
OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest()2006 OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest()
2007 : OmniboxViewViewsTest(
2008 GetParam().first
2009 ? std::vector<FeatureAndParams>(
2010 {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2011 {}},
2012 {omnibox::
2013 kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2014 {}},
2015 {omnibox::kMaybeElideToRegistrableDomain,
2016 // Ensure all domains are elidable by policy.
2017 {{"max_unelided_host_length", "0"}}}})
2018 : std::vector<FeatureAndParams>(
2019 {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2020 {}},
2021 {omnibox::
2022 kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2023 {}}}),
2024 {},
2025 GetParam().second) {
2026 // The lookalike allowlist is used by the registrable-domain-elision code.
2027 reputation::InitializeBlankLookalikeAllowlistForTesting();
2028 }
2029
2030 OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest(
2031 const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete;
2032 OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest& operator=(
2033 const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete;
2034
2035 protected:
ShouldElideToRegistrableDomain()2036 bool ShouldElideToRegistrableDomain() { return GetParam().first; }
2037 };
2038
2039 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2040 OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2041 ::testing::ValuesIn({std::make_pair(true, false),
2042 std::make_pair(false, false),
2043 std::make_pair(true, true),
2044 std::make_pair(false, true)}));
2045
2046 // Tests the field trial variation that shows the simplified domain when the
2047 // user interacts with the page and brings back the URL when the user hovers
2048 // over the omnibox.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,UserInteractionAndHover)2049 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2050 UserInteractionAndHover) {
2051 SetUpSimplifiedDomainTest();
2052
2053 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2054 /*is_same_document=*/false, GURL(),
2055 kSimplifiedDomainDisplayUrlScheme);
2056
2057 // Simulate a user interaction and check that the fade-out animation runs.
2058 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2059 // Advance the clock through the fade-out animation; we assume that it takes
2060 // less than 1s.
2061 ASSERT_NO_FATAL_FAILURE(
2062 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2063 /*step_ms=*/1000));
2064 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2065 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2066 kSimplifiedDomainDisplayUrlSubdomain,
2067 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2068 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2069
2070 // A second user interaction should not run the animation again.
2071 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2072 EXPECT_FALSE(omnibox_view()
2073 ->GetElideAfterInteractionAnimationForTesting()
2074 ->IsAnimating());
2075
2076 // The URL should come back on hover.
2077 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2078 ASSERT_NO_FATAL_FAILURE(
2079 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2080 // The hover should bring back the full URL, including scheme and trivial
2081 // subdomains.
2082 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2083 omnibox_view()->GetRenderText(),
2084 gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
2085 // The path and scheme/subdomain should not be transparent.
2086 EXPECT_NE(SK_ColorTRANSPARENT,
2087 omnibox_view()->GetLatestColorForRange(
2088 gfx::Range(kSimplifiedDomainDisplayUrlHostnameAndScheme.size(),
2089 kSimplifiedDomainDisplayUrl.size())));
2090 EXPECT_NE(SK_ColorTRANSPARENT,
2091 omnibox_view()->GetLatestColorForRange(gfx::Range(
2092 0, kSimplifiedDomainDisplayUrlSubdomainAndScheme.size())));
2093 }
2094
2095 // Tests that the hide-on-interaction simplified domain field trial handles
2096 // intermediate states during a navigation properly. This test simulates a
2097 // browser-initiated navigation in which the URL updates before the navigation
2098 // commits.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,BrowserInitiatedNavigation)2099 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2100 BrowserInitiatedNavigation) {
2101 SetUpSimplifiedDomainTest();
2102
2103 ASSERT_NO_FATAL_FAILURE(omnibox_view()->NavigateAndExpectUnelided(
2104 kSimplifiedDomainDisplayUrl,
2105 /*is_same_document=*/false, GURL(), kSimplifiedDomainDisplayUrlScheme));
2106
2107 // Before a user interaction triggers elision, a browser-initiated navigation
2108 // should show the full URL (minus scheme and trivial subdomain) throughout
2109 // the navigation.
2110
2111 // Set a longer URL to ensure that the full URL stays visible even if it's
2112 // longer than the previous URL.
2113 const base::string16 kUrlSuffix = base::ASCIIToUTF16("/foobar");
2114 UpdateDisplayURL(kSimplifiedDomainDisplayUrl + kUrlSuffix);
2115 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2116 omnibox_view()->GetRenderText(),
2117 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2118 kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2119
2120 {
2121 // In this test, we create MockNavigationHandles here instead of using the
2122 // NavigateAndExpect* helpers because those helpers simulate
2123 // renderer-initiated navigations, where the display URL isn't updated until
2124 // just before DidFinishNavigation.
2125 content::MockNavigationHandle navigation;
2126 navigation.set_is_renderer_initiated(false);
2127
2128 omnibox_view()->DidStartNavigation(&navigation);
2129 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2130 omnibox_view()->GetRenderText(),
2131 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2132 kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2133
2134 omnibox_view()->DidFinishNavigation(&navigation);
2135 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2136 omnibox_view()->GetRenderText(),
2137 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2138 kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2139 OmniboxViewViews::ElideAnimation* elide_animation =
2140 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2141 EXPECT_FALSE(elide_animation);
2142 }
2143
2144 // Simulate a user interaction and advance all the way through the animation
2145 // until the URL is elided to the simplified domain.
2146 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2147 ASSERT_NO_FATAL_FAILURE(
2148 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2149 /*step_ms=*/1000));
2150 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2151 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2152 kSimplifiedDomainDisplayUrlSubdomain,
2153 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2154 kSimplifiedDomainDisplayUrlPath + kUrlSuffix,
2155 ShouldElideToRegistrableDomain()));
2156
2157 // Begin simulating a browser-initiated navigation, in which the URL is
2158 // updated before DidStartNavigation() runs.
2159 UpdateDisplayURL(kSimplifiedDomainDisplayUrl + kUrlSuffix);
2160 // Ideally we would actually be unelided at this point, when a
2161 // browser-initiated navigation has begun. But EmphasizeURLComponents()
2162 // doesn't know which type of navigation is in progress, so this is the best
2163 // we can do.
2164 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2165 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2166 kSimplifiedDomainDisplayUrlSubdomain,
2167 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2168 kSimplifiedDomainDisplayUrlPath + kUrlSuffix,
2169 ShouldElideToRegistrableDomain()));
2170 {
2171 content::MockNavigationHandle navigation;
2172 navigation.set_is_renderer_initiated(false);
2173
2174 // Once the navigation starts and we know that it's a cross-document
2175 // navigation, the URL should be unelided.
2176 omnibox_view()->DidStartNavigation(&navigation);
2177 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2178 omnibox_view()->GetRenderText(),
2179 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2180 kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2181
2182 omnibox_view()->DidFinishNavigation(&navigation);
2183 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2184 omnibox_view()->GetRenderText(),
2185 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2186 kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2187 OmniboxViewViews::ElideAnimation* elide_animation =
2188 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2189 EXPECT_FALSE(elide_animation);
2190 }
2191 }
2192
2193 // Tests that the hide-on-interaction simplified domain field trial handles
2194 // non-committed navigations properly.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,NonCommittedNavigations)2195 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2196 NonCommittedNavigations) {
2197 SetUpSimplifiedDomainTest();
2198
2199 ASSERT_NO_FATAL_FAILURE(omnibox_view()->NavigateAndExpectUnelided(
2200 kSimplifiedDomainDisplayUrl,
2201 /*is_same_document=*/false, GURL(), kSimplifiedDomainDisplayUrlScheme));
2202 // Simulate a user interaction to elide the URL.
2203 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2204 ASSERT_NO_FATAL_FAILURE(
2205 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2206 /*step_ms=*/1000));
2207 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2208 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2209 kSimplifiedDomainDisplayUrlSubdomain,
2210 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2211 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2212
2213 // When a renderer-initiated navigation finishes without committing, the URL
2214 // should remain elided; we don't update the display URL until the navigation
2215 // commits.
2216 {
2217 content::MockNavigationHandle navigation;
2218 navigation.set_is_renderer_initiated(true);
2219 navigation.set_has_committed(false);
2220 omnibox_view()->DidStartNavigation(&navigation);
2221 omnibox_view()->DidFinishNavigation(&navigation);
2222 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2223 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2224 kSimplifiedDomainDisplayUrlSubdomain,
2225 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2226 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2227 }
2228
2229 // When a browser-initiated navigation finishes without committing, the URL
2230 // updates before commit, so we should reset back to the on-page-load state if
2231 // the navigation doesn't eventually commit.
2232 content::MockNavigationHandle navigation;
2233 navigation.set_is_renderer_initiated(false);
2234 navigation.set_has_committed(false);
2235 omnibox_view()->DidStartNavigation(&navigation);
2236 omnibox_view()->DidFinishNavigation(&navigation);
2237 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2238 omnibox_view()->GetRenderText(),
2239 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2240 kSimplifiedDomainDisplayUrl.size())));
2241 }
2242
2243 // Tests that mouse clicks do not count as user interactions and do not elide
2244 // the URL.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,MouseClick)2245 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, MouseClick) {
2246 SetUpSimplifiedDomainTest();
2247
2248 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2249 /*is_same_document=*/false, GURL(),
2250 kSimplifiedDomainDisplayUrlScheme);
2251
2252 // Simulate a mouse click and check that the fade-out animation does not run.
2253 blink::WebMouseEvent event;
2254 event.SetType(blink::WebInputEvent::Type::kMouseDown);
2255 omnibox_view()->DidGetUserInteraction(event);
2256 OmniboxViewViews::ElideAnimation* elide_animation =
2257 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2258 EXPECT_FALSE(elide_animation);
2259 }
2260
2261 // Tests that focusing an editable node does count as a user interaction and
2262 // elides the URL.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,FocusingEditableNode)2263 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2264 FocusingEditableNode) {
2265 SetUpSimplifiedDomainTest();
2266
2267 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2268 /*is_same_document=*/false, GURL(),
2269 kSimplifiedDomainDisplayUrlScheme);
2270
2271 // Focusing a non-editable node should not run the fade-out animation.
2272 content::FocusedNodeDetails details;
2273 details.is_editable_node = false;
2274 details.focus_type = blink::mojom::FocusType::kMouse;
2275 omnibox_view()->OnFocusChangedInPage(&details);
2276 OmniboxViewViews::ElideAnimation* elide_animation =
2277 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2278 EXPECT_FALSE(elide_animation);
2279
2280 // Focusing via keypress should not run the fade-out animation.
2281 details.is_editable_node = true;
2282 details.focus_type = blink::mojom::FocusType::kForward;
2283 omnibox_view()->OnFocusChangedInPage(&details);
2284 elide_animation =
2285 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2286 EXPECT_FALSE(elide_animation);
2287
2288 // Other ways that an element can be focused, such as element.focus() in
2289 // JavaScript, have a focus type of kNone and should not run the fade-out
2290 // animation.
2291 details.is_editable_node = true;
2292 details.focus_type = blink::mojom::FocusType::kNone;
2293 omnibox_view()->OnFocusChangedInPage(&details);
2294 elide_animation =
2295 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2296 EXPECT_FALSE(elide_animation);
2297
2298 // Focusing an editable node should run the fade-out animation.
2299 details.is_editable_node = true;
2300 details.focus_type = blink::mojom::FocusType::kMouse;
2301 omnibox_view()->OnFocusChangedInPage(&details);
2302 elide_animation =
2303 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2304 ASSERT_TRUE(elide_animation);
2305 EXPECT_TRUE(elide_animation->IsAnimating());
2306 }
2307
2308 // Tests that simplified domain elisions are re-applied when the omnibox's
2309 // bounds change.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,BoundsChanged)2310 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, BoundsChanged) {
2311 SetUpSimplifiedDomainTest();
2312
2313 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2314 /*is_same_document=*/false, GURL(),
2315 kSimplifiedDomainDisplayUrlScheme);
2316
2317 // After the bounds change, the URL should remain unelided.
2318 omnibox_view()->OnBoundsChanged(gfx::Rect());
2319 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2320 omnibox_view()->GetRenderText(),
2321 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2322 kSimplifiedDomainDisplayUrl.size())));
2323
2324 // Hover over the omnibox and change the bounds during the animation. The
2325 // animation should be cancelled and immediately transition back to the
2326 // unelided URL.
2327 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2328 OmniboxViewViews::ElideAnimation* unelide_animation =
2329 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2330 ASSERT_TRUE(unelide_animation);
2331 EXPECT_TRUE(unelide_animation->IsAnimating());
2332 omnibox_view()->OnBoundsChanged(gfx::Rect());
2333 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2334 omnibox_view()->GetRenderText(),
2335 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2336 kSimplifiedDomainDisplayUrl.size())));
2337
2338 // Simulate a user interaction and change the bounds during the animation. The
2339 // animation should be cancelled and immediately transition to the animation's
2340 // end state (simplified domain).
2341 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2342 OmniboxViewViews::ElideAnimation* elide_animation =
2343 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2344 ASSERT_TRUE(elide_animation);
2345 EXPECT_TRUE(elide_animation->IsAnimating());
2346 omnibox_view()->OnBoundsChanged(gfx::Rect());
2347 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2348 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2349 kSimplifiedDomainDisplayUrlSubdomain,
2350 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2351 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2352 }
2353
2354 // Tests that simplified domain elisions are re-applied when the omnibox's
2355 // bounds change when only reveal-on-hover is enabled.
TEST_P(OmniboxViewViewsRevealOnHoverTest,BoundsChanged)2356 TEST_P(OmniboxViewViewsRevealOnHoverTest, BoundsChanged) {
2357 SetUpSimplifiedDomainTest();
2358
2359 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2360 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2361 kSimplifiedDomainDisplayUrlSubdomain,
2362 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2363 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2364
2365 // After the bounds change, the URL should remain elided.
2366 omnibox_view()->OnBoundsChanged(gfx::Rect());
2367 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2368 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2369 kSimplifiedDomainDisplayUrlSubdomain,
2370 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2371 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2372
2373 // Hover over the omnibox and change the bounds during the animation. The
2374 // animation should be cancelled and immediately transition back to the
2375 // simplified domain.
2376 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2377 OmniboxViewViews::ElideAnimation* unelide_animation =
2378 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2379 ASSERT_TRUE(unelide_animation);
2380 EXPECT_TRUE(unelide_animation->IsAnimating());
2381 omnibox_view()->OnBoundsChanged(gfx::Rect());
2382 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2383 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2384 kSimplifiedDomainDisplayUrlSubdomain,
2385 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2386 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2387 }
2388
2389 // Tests that simplified domain hover duration histogram is recorded correctly.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverHistogram)2390 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverHistogram) {
2391 base::SimpleTestClock clock;
2392 constexpr int kHoverTimeMs = 1000;
2393 SetUpSimplifiedDomainTest();
2394 clock.SetNow(base::Time::Now());
2395 omnibox_view()->clock_ = &clock;
2396
2397 // Hover over the omnibox and then exit and check that the histogram is
2398 // recorded correctly.
2399 {
2400 base::HistogramTester histograms;
2401 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2402 OmniboxViewViews::ElideAnimation* unelide_animation =
2403 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2404 ASSERT_TRUE(unelide_animation);
2405 EXPECT_TRUE(unelide_animation->IsAnimating());
2406 clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs / 2));
2407 // Call OnMouseMoved() again halfway through the hover time to ensure that
2408 // the histogram is only recorded once per continuous hover.
2409 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2410 clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs / 2));
2411 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2412 auto samples = histograms.GetAllSamples("Omnibox.HoverTime");
2413 ASSERT_EQ(1u, samples.size());
2414 histograms.ExpectTimeBucketCount(
2415 "Omnibox.HoverTime", base::TimeDelta::FromMilliseconds(kHoverTimeMs),
2416 1);
2417
2418 // Focusing the omnibox while not hovering should not record another sample.
2419 omnibox_view()->OnFocus();
2420 samples = histograms.GetAllSamples("Omnibox.HoverTime");
2421 ASSERT_EQ(1u, samples.size());
2422 }
2423
2424 // Hover over the omnibox and then focus it, and check that the histogram is
2425 // recorded correctly.
2426 {
2427 base::HistogramTester histograms;
2428 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2429 OmniboxViewViews::ElideAnimation* unelide_animation =
2430 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2431 ASSERT_TRUE(unelide_animation);
2432 EXPECT_TRUE(unelide_animation->IsAnimating());
2433 clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs));
2434 omnibox_view()->OnFocus();
2435 auto samples = histograms.GetAllSamples("Omnibox.HoverTime");
2436 ASSERT_EQ(1u, samples.size());
2437 histograms.ExpectTimeBucketCount(
2438 "Omnibox.HoverTime", base::TimeDelta::FromMilliseconds(kHoverTimeMs),
2439 1);
2440
2441 // Moving the mouse, focusing again, and exiting from the omnibox after
2442 // focusing it should not record any more samples.
2443 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2444 omnibox_view()->OnFocus();
2445 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2446 samples = histograms.GetAllSamples("Omnibox.HoverTime");
2447 ASSERT_EQ(1u, samples.size());
2448
2449 // Hovering and exiting again should record another sample.
2450 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2451 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2452 samples = histograms.GetAllSamples("Omnibox.HoverTime");
2453 ASSERT_EQ(2u, samples.size());
2454 }
2455
2456 // Hovering over the omnibox while focused should not record a histogram,
2457 // because no elide animation happens while focused.
2458 {
2459 base::HistogramTester histograms;
2460 omnibox_view()->RequestFocus();
2461 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2462 OmniboxViewViews::ElideAnimation* unelide_animation =
2463 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2464 ASSERT_TRUE(unelide_animation);
2465 EXPECT_FALSE(unelide_animation->IsAnimating());
2466 clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs));
2467 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2468 auto samples = histograms.GetAllSamples("Omnibox.HoverTime");
2469 ASSERT_EQ(0u, samples.size());
2470 }
2471 }
2472
2473 // Tests that the simplified domain animation doesn't crash when it's cancelled.
2474 // Regression test for https://crbug.com/1103738.
TEST_P(OmniboxViewViewsRevealOnHoverTest,CancellingAnimationDoesNotCrash)2475 TEST_P(OmniboxViewViewsRevealOnHoverTest, CancellingAnimationDoesNotCrash) {
2476 SetUpSimplifiedDomainTest();
2477
2478 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2479 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2480 kSimplifiedDomainDisplayUrlSubdomain,
2481 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2482 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2483
2484 // Hover over the omnibox to begin the unelision animation, then change the
2485 // URL such that the current animation would go out of bounds if it continued
2486 // running.
2487 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2488 // Step through the animation partially so that it has a nonzero current
2489 // value. (A zero current value causes an early return that circumvents the
2490 // crash we are regression-testing.)
2491 ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation(
2492 OmniboxFieldTrial::UnelideURLOnHoverThresholdMs() + 1));
2493
2494 // Stopping the animation after changing the underlying display text should
2495 // not crash.
2496 UpdateDisplayURL(base::ASCIIToUTF16("https://foo.test"));
2497 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting()->Stop();
2498 }
2499
2500 // Tests scheme and trivial subdomain elision when simplified domain field
2501 // trials are enabled.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,SchemeAndTrivialSubdomainElision)2502 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2503 SchemeAndTrivialSubdomainElision) {
2504 // Use custom setup code instead of SetUpSimplifiedDomainTest() to use a URL
2505 // with a "www." prefix (a trivial subdomain).
2506 const base::string16 kFullUrl =
2507 base::ASCIIToUTF16("https://www.example.test/foo");
2508 constexpr size_t kSchemeAndSubdomainSize = 12; // "https://www."
2509 UpdateDisplayURL(kFullUrl);
2510 omnibox_view()->OnThemeChanged();
2511
2512 omnibox_view()->NavigateAndExpectUnelided(kFullUrl,
2513 /*is_same_document=*/false, GURL(),
2514 base::ASCIIToUTF16("htpts://www."));
2515 EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2516 gfx::Range(0, kSchemeAndSubdomainSize)));
2517
2518 // Hovering before user interaction should bring back the scheme and trivial
2519 // subdomain.
2520 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2521 ASSERT_NO_FATAL_FAILURE(
2522 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2523 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2524 omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size())));
2525 EXPECT_NE(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2526 gfx::Range(0, kSchemeAndSubdomainSize)));
2527
2528 // After mousing out, the scheme should fade out again.
2529 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2530 ASSERT_NO_FATAL_FAILURE(
2531 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2532 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2533 omnibox_view()->GetRenderText(),
2534 gfx::Range(kSchemeAndSubdomainSize, kSimplifiedDomainDisplayUrl.size())));
2535 EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2536 gfx::Range(0, kSchemeAndSubdomainSize)));
2537
2538 // Simulate a user interaction and check that the URL gets elided to the
2539 // simplified domain.
2540 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2541 ASSERT_NO_FATAL_FAILURE(
2542 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2543 /*step_ms=*/1000));
2544 // Use should_elide_to_registrable_domain=true here regardless of how the
2545 // field trial is set because the "www." should be elided as a trivial
2546 // subdomain.
2547 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2548 omnibox_view(), base::ASCIIToUTF16("https://"),
2549 base::ASCIIToUTF16("www."),
2550 base::ASCIIToUTF16("https://www.example.test"),
2551 base::ASCIIToUTF16("/foo"),
2552 /* should_elide_to_registrable_domain=*/true));
2553
2554 // Do another hover and check that the URL gets unelided to the full URL.
2555 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2556 ASSERT_NO_FATAL_FAILURE(
2557 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2558 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2559 omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size())));
2560 EXPECT_NE(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2561 gfx::Range(0, kSchemeAndSubdomainSize)));
2562
2563 // And after another mouse exit, the URL should go back to the simplified
2564 // domain.
2565 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2566 ASSERT_NO_FATAL_FAILURE(
2567 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2568 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2569 omnibox_view(), base::ASCIIToUTF16("https://"),
2570 base::ASCIIToUTF16("www."),
2571 base::ASCIIToUTF16("https://www.example.test"),
2572 base::ASCIIToUTF16("/foo"),
2573 /* should_elide_to_registrable_domain=*/true));
2574 EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2575 gfx::Range(0, kSchemeAndSubdomainSize)));
2576 }
2577
2578 class OmniboxViewViewsHideOnInteractionTest
2579 : public OmniboxViewViewsTest,
2580 public ::testing::WithParamInterface<std::pair<bool, bool>> {
2581 public:
OmniboxViewViewsHideOnInteractionTest()2582 OmniboxViewViewsHideOnInteractionTest()
2583 : OmniboxViewViewsTest(
2584 GetParam().first
2585 ? std::vector<FeatureAndParams>(
2586 {{omnibox::
2587 kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2588 {}},
2589 {omnibox::kMaybeElideToRegistrableDomain,
2590 // Ensure all domains are elidable by policy.
2591 {{"max_unelided_host_length", "0"}}}})
2592 : std::vector<FeatureAndParams>(
2593 {{omnibox::
2594 kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2595 {}}}),
2596 {},
2597 GetParam().second) {
2598 // The lookalike allowlist is used by the registrable-domain-elision code.
2599 reputation::InitializeBlankLookalikeAllowlistForTesting();
2600 }
2601
2602 OmniboxViewViewsHideOnInteractionTest(
2603 const OmniboxViewViewsHideOnInteractionTest&) = delete;
2604 OmniboxViewViewsHideOnInteractionTest& operator=(
2605 const OmniboxViewViewsHideOnInteractionTest&) = delete;
2606
2607 protected:
ShouldElideToRegistrableDomain()2608 bool ShouldElideToRegistrableDomain() { return GetParam().first; }
2609 };
2610
2611 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionTest,
2612 OmniboxViewViewsHideOnInteractionTest,
2613 ::testing::ValuesIn({std::make_pair(true, false),
2614 std::make_pair(false, false),
2615 std::make_pair(true, true),
2616 std::make_pair(false, true)}));
2617
2618 // Tests the the "Always Show Full URLs" option works with the field trial
2619 // variation that shows a simplified domain when the user interacts with the
2620 // page.
TEST_P(OmniboxViewViewsHideOnInteractionTest,AlwaysShowFullURLs)2621 TEST_P(OmniboxViewViewsHideOnInteractionTest, AlwaysShowFullURLs) {
2622 // This test does setup itself and doesn't call SetUpSimplifiedDomainTest()
2623 // because SetUpSimplifiedDomainTest() uses a URL with a foo.example.test
2624 // hostname, and in this test we want to use a "www." subdomain to test that
2625 // the URL is displayed properly when trivial subdomain elision is disabled.
2626 const base::string16 kFullUrl =
2627 base::ASCIIToUTF16("https://www.example.test/foo");
2628 UpdateDisplayURL(kFullUrl);
2629 omnibox_view()->OnThemeChanged();
2630
2631 // Enable the "Always show full URLs" setting.
2632 location_bar_model()->set_should_prevent_elision(true);
2633 omnibox_view()->OnShouldPreventElisionChanged();
2634 std::unique_ptr<content::WebContents> web_contents =
2635 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2636 omnibox_view()->OnTabChanged(web_contents.get());
2637 EXPECT_EQ(kFullUrl, omnibox_view()->GetText());
2638 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2639 omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size())));
2640
2641 // When the Always Show Full URLs pref is enabled, the omnibox view won't
2642 // observe user interactions and elide the URL.
2643 EXPECT_FALSE(omnibox_view()->web_contents());
2644 OmniboxViewViews::ElideAnimation* elide_animation =
2645 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2646 EXPECT_FALSE(elide_animation);
2647 }
2648
2649 // Tests the the "Always Show Full URLs" option works with the field trial
2650 // variation that shows a simplified domain until the user hovers over the
2651 // omnibox.
TEST_P(OmniboxViewViewsRevealOnHoverTest,AlwaysShowFullURLs)2652 TEST_P(OmniboxViewViewsRevealOnHoverTest, AlwaysShowFullURLs) {
2653 SetUpSimplifiedDomainTest();
2654
2655 // Enable the "Always show full URLs" setting.
2656 location_bar_model()->set_should_prevent_elision(true);
2657 omnibox_view()->OnShouldPreventElisionChanged();
2658
2659 // After a hover, there should be no animations running.
2660 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2661 OmniboxViewViews::ElideAnimation* elide_animation =
2662 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2663 EXPECT_FALSE(elide_animation);
2664 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2665 elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2666 EXPECT_FALSE(elide_animation);
2667 }
2668
2669 // This test fixture enables the reveal-on-hover simplified domain field trial,
2670 // and the hide-on-interaction variation when the parameter is true.
2671 class OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest
2672 : public OmniboxViewViewsTest,
2673 public ::testing::WithParamInterface<std::pair<bool, bool>> {
2674 public:
OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest()2675 OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest()
2676 : OmniboxViewViewsTest(
2677 GetParam().first
2678 ? std::vector<FeatureAndParams>(
2679 {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2680 {}},
2681 {omnibox::
2682 kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2683 {}}})
2684 : std::vector<FeatureAndParams>(
2685 {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2686 {}}}),
2687 {omnibox::kMaybeElideToRegistrableDomain},
2688 GetParam().second) {}
2689
2690 OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest(
2691 const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) =
2692 delete;
2693 OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest& operator=(
2694 const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) =
2695 delete;
2696
2697 protected:
IsHideOnInteractionEnabled()2698 bool IsHideOnInteractionEnabled() { return GetParam().first; }
2699 };
2700
2701 INSTANTIATE_TEST_SUITE_P(
2702 OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
2703 OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
2704 ::testing::ValuesIn({std::make_pair(true, false),
2705 std::make_pair(false, false),
2706 std::make_pair(true, true),
2707 std::make_pair(false, true)}));
2708
2709 // Tests that unsetting the "Always show full URLs" option begins showing/hiding
2710 // the full URL appropriately when simplified domain field trials are enabled.
2711 // This test has kMaybeElideToRegistrableDomain disabled so that we can check
2712 // that www is elided when the option is unset but other subdomains are not.
TEST_P(OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,UnsetAlwaysShowFullURLs)2713 TEST_P(OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
2714 UnsetAlwaysShowFullURLs) {
2715 // This test does setup itself and doesn't call SetUpSimplifiedDomainTest()
2716 // because SetUpSimplifiedDomainTest() uses a URL with a foo.example.test
2717 // hostname, and in this test we want to use a "www." subdomain to test that
2718 // the URL is displayed properly when trivial subdomain elision is disabled.
2719 const base::string16 kFullUrl =
2720 base::ASCIIToUTF16("https://www.example.test/foo");
2721 UpdateDisplayURL(kFullUrl);
2722 omnibox_view()->OnThemeChanged();
2723 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
2724
2725 // Enable the "Always show full URLs" setting.
2726 location_bar_model()->set_should_prevent_elision(true);
2727 omnibox_view()->OnShouldPreventElisionChanged();
2728 std::unique_ptr<content::WebContents> web_contents =
2729 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2730 omnibox_view()->OnTabChanged(web_contents.get());
2731 EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo"),
2732 omnibox_view()->GetText());
2733
2734 // Now toggle the preference and check that the animations run as expected.
2735 location_bar_model()->set_should_prevent_elision(false);
2736 location_bar_model()->set_url_for_display(
2737 base::ASCIIToUTF16("https://www.example.test/foo"));
2738 omnibox_view()->OnShouldPreventElisionChanged();
2739 // When simplified domain field trials are enabled, LocationBarModelImpl
2740 // doesn't do any elision, leaving it all up to OmniboxViewViews, so the text
2741 // returned from LocationBarModelImpl is the same even though the preference
2742 // has changed.
2743 EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo"),
2744 omnibox_view()->GetText());
2745 if (IsHideOnInteractionEnabled()) {
2746 ExpectUnelidedFromSimplifiedDomain(
2747 render_text,
2748 gfx::Range(std::string("https://www.").size(), kFullUrl.size()));
2749 // Simulate a user interaction and check the fade-out animation.
2750 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2751 OmniboxViewViews::ElideAnimation* elide_animation =
2752 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2753 ASSERT_TRUE(elide_animation);
2754 EXPECT_TRUE(elide_animation->IsAnimating());
2755 } else {
2756 // Even though kMaybeElideToRegistrableDomain is disabled, we expect to be
2757 // elided to the registrable domain because the www subdomain is considered
2758 // trivial.
2759 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2760 omnibox_view(), base::ASCIIToUTF16("https://"),
2761 base::ASCIIToUTF16("www."),
2762 base::ASCIIToUTF16("https://www.example.test"),
2763 base::ASCIIToUTF16("/foo"),
2764 true /* should elide to registrable domain */));
2765 }
2766 // Simulate a hover event and check the elide/unelide animations. This
2767 // should happen the same regardless of whether hide-on-interaction is
2768 // enabled.
2769 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2770 ASSERT_NO_FATAL_FAILURE(
2771 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2772 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2773 OmniboxViewViews::ElideAnimation* elide_animation =
2774 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2775 ASSERT_TRUE(elide_animation);
2776 EXPECT_TRUE(elide_animation->IsAnimating());
2777 }
2778
2779 // Tests that in the hide-on-interaction field trial, the omnibox is reset to
2780 // the local bounds on tab change when the new text is not eligible for
2781 // simplified domain elision.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,TabChangeWhenNotEligibleForEliding)2782 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2783 TabChangeWhenNotEligibleForEliding) {
2784 SetUpSimplifiedDomainTest();
2785
2786 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2787 /*is_same_document=*/false, GURL(),
2788 kSimplifiedDomainDisplayUrlScheme);
2789
2790 // Simulate a user interaction and advance through the animation to elide the
2791 // URL.
2792 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2793 ASSERT_NO_FATAL_FAILURE(
2794 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2795 /*step_ms=*/1000));
2796 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2797 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2798 kSimplifiedDomainDisplayUrlSubdomain,
2799 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2800 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2801
2802 // Change the tab and set state such that the current text is not eligible for
2803 // simplified domain eliding (specifically, use an ftp:// URL; only http/https
2804 // URLs are eligible for eliding). The omnibox should take up the full local
2805 // bounds and be reset to tail-eliding behavior, just as if the above
2806 // simplified domain elision had not happened.
2807 UpdateDisplayURL(base::ASCIIToUTF16("ftp://foo.example.test"));
2808 std::unique_ptr<content::WebContents> web_contents =
2809 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2810 omnibox_view()->SaveStateToTab(web_contents.get());
2811 omnibox_view()->OnTabChanged(web_contents.get());
2812
2813 EXPECT_EQ(gfx::ELIDE_TAIL, omnibox_view()->GetRenderText()->elide_behavior());
2814 EXPECT_EQ(base::ASCIIToUTF16("ftp://foo.example.test"),
2815 omnibox_view()->GetRenderText()->GetDisplayText());
2816
2817 // Change the tab and simulate user input in progress. In this case, the
2818 // omnibox should take up the full local bounds but should not be reset to
2819 // tail-eliding behavior, because it should always be in NO_ELIDE mode when
2820 // editing.
2821 UpdateDisplayURL(kSimplifiedDomainDisplayUrl);
2822 omnibox_view()->Focus();
2823 omnibox_view()->model()->SetInputInProgress(true);
2824 std::unique_ptr<content::WebContents> web_contents2 =
2825 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2826 omnibox_view()->SaveStateToTab(web_contents2.get());
2827 omnibox_view()->OnTabChanged(web_contents2.get());
2828
2829 EXPECT_EQ(gfx::NO_ELIDE, omnibox_view()->GetRenderText()->elide_behavior());
2830 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2831 omnibox_view()->GetRenderText(),
2832 gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
2833 }
2834
2835 // Tests that in the simplified domain field trials, non-http/https and
2836 // localhost URLs are not elided.
TEST_P(OmniboxViewViewsRevealOnHoverTest,UrlsNotEligibleForEliding)2837 TEST_P(OmniboxViewViewsRevealOnHoverTest, UrlsNotEligibleForEliding) {
2838 const base::string16 kTestCases[] = {
2839 // Various URLs that aren't eligible for simplified domain eliding.
2840 base::ASCIIToUTF16("ftp://foo.bar.test/baz"),
2841 base::ASCIIToUTF16("javascript:alert(1)"),
2842 base::ASCIIToUTF16("data:text/html,hello"),
2843 base::ASCIIToUTF16("http://localhost:4000/foo"),
2844 // A smoke test to check that the test code results in
2845 // the URL being elided properly when eligible.
2846 kSimplifiedDomainDisplayUrl,
2847 };
2848
2849 for (const auto& test_case : kTestCases) {
2850 UpdateDisplayURL(test_case);
2851 omnibox_view()->OnThemeChanged();
2852
2853 if (test_case == kSimplifiedDomainDisplayUrl) {
2854 // This case is the smoke test to check that the test setup does properly
2855 // elide URLs that are eligible for eliding.
2856 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2857 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2858 kSimplifiedDomainDisplayUrlSubdomain,
2859 kSimplifiedDomainDisplayUrlHostnameAndScheme,
2860 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2861 } else {
2862 EXPECT_EQ(gfx::ELIDE_TAIL,
2863 omnibox_view()->GetRenderText()->elide_behavior());
2864 EXPECT_EQ(test_case, omnibox_view()->GetRenderText()->GetDisplayText());
2865 EXPECT_EQ(0,
2866 omnibox_view()->GetRenderText()->GetUpdatedDisplayOffset().x());
2867 }
2868 }
2869 }
2870
2871 // Tests that in the hide-on-interaction field trial, when the path changes
2872 // while being elided, the animation is stopped.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,PathChangeDuringAnimation)2873 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2874 PathChangeDuringAnimation) {
2875 SetUpSimplifiedDomainTest();
2876
2877 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2878 /*is_same_document=*/false, GURL(),
2879 kSimplifiedDomainDisplayUrlScheme);
2880
2881 // Simulate a user interaction and check that the fade-out animation runs.
2882 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2883 OmniboxViewViews::ElideAnimation* elide_animation =
2884 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2885 EXPECT_TRUE(elide_animation->IsAnimating());
2886
2887 // Change the path and check that the animation is cancelled.
2888 UpdateDisplayURL(base::ASCIIToUTF16("foo.example.test/bar#bar"));
2889 omnibox_view()->model()->ResetDisplayTexts();
2890 omnibox_view()->RevertAll();
2891 EXPECT_FALSE(elide_animation->IsAnimating());
2892 }
2893
2894 // Tests that vertical and horizontal positioning doesn't change when eliding
2895 // to/from simplified domain. Regression test for https://crbug.com/1101674.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,VerticalAndHorizontalPosition)2896 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2897 VerticalAndHorizontalPosition) {
2898 SetUpSimplifiedDomainTest();
2899 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
2900
2901 const gfx::Rect& original_display_rect = render_text->display_rect();
2902
2903 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2904 /*is_same_document=*/false, GURL(),
2905 kSimplifiedDomainDisplayUrlScheme);
2906
2907 // After a navigation, the URL should not be elided to the simplified domain,
2908 // and the display rect (including vertical and horizontal position) should be
2909 // unchanged.
2910 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2911 omnibox_view()->GetRenderText(),
2912 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2913 kSimplifiedDomainDisplayUrl.size())));
2914 EXPECT_EQ(original_display_rect, render_text->display_rect());
2915
2916 // Simulate a user interaction to elide to simplified domain and advance
2917 // through the animation; the vertical position should still be unchanged, and
2918 // the text should still start at the some position (the same x value).
2919 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2920 ASSERT_NO_FATAL_FAILURE(
2921 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2922 /*step_ms=*/1000));
2923 const gfx::Rect& elided_display_rect = render_text->display_rect();
2924 EXPECT_EQ(original_display_rect.y(), elided_display_rect.y());
2925 EXPECT_EQ(original_display_rect.height(), elided_display_rect.height());
2926 EXPECT_EQ(original_display_rect.x(), elided_display_rect.x());
2927
2928 // Now hover over the omnibox to trigger an unelide and check that the display
2929 // rect (including vertical and horizontal position) is back to what it was
2930 // originally.
2931 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2932 ASSERT_NO_FATAL_FAILURE(
2933 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2934 const gfx::Rect& unelided_display_rect = render_text->display_rect();
2935 EXPECT_EQ(original_display_rect, unelided_display_rect);
2936 }
2937
2938 // Tests that modifier keys don't count as user interactions in the
2939 // hide-on-interaction field trial.
TEST_P(OmniboxViewViewsHideOnInteractionTest,ModifierKeys)2940 TEST_P(OmniboxViewViewsHideOnInteractionTest, ModifierKeys) {
2941 SetUpSimplifiedDomainTest();
2942 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
2943
2944 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2945 /*is_same_document=*/false, GURL(),
2946 kSimplifiedDomainDisplayUrlScheme);
2947
2948 // Simulate a user interaction with a modifier key and check that the elide
2949 // animation doesn't run.
2950 blink::WebKeyboardEvent event(
2951 blink::WebInputEvent::Type::kRawKeyDown,
2952 blink::WebInputEvent::kControlKey,
2953 blink::WebInputEvent::GetStaticTimeStampForTests());
2954 omnibox_view()->DidGetUserInteraction(event);
2955 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2956 render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2957 kSimplifiedDomainDisplayUrl.size())));
2958 OmniboxViewViews::ElideAnimation* elide_animation =
2959 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2960 EXPECT_FALSE(elide_animation);
2961 }
2962
2963 // Tests that in the hide-on-interaction field trial, the URL is unelided when
2964 // navigating to an error page.
TEST_P(OmniboxViewViewsHideOnInteractionTest,ErrorPageNavigation)2965 TEST_P(OmniboxViewViewsHideOnInteractionTest, ErrorPageNavigation) {
2966 SetUpSimplifiedDomainTest();
2967 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2968 /*is_same_document=*/false, GURL(),
2969 kSimplifiedDomainDisplayUrlScheme);
2970
2971 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2972 /*is_same_document=*/false, GURL(),
2973 kSimplifiedDomainDisplayUrlScheme);
2974 // Simulate a user interaction to elide to the simplified domain.
2975 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2976 OmniboxViewViews::ElideAnimation* elide_animation =
2977 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2978 ASSERT_TRUE(elide_animation);
2979 EXPECT_TRUE(elide_animation->IsAnimating());
2980
2981 // Now simulate a navigation to an error page and check that the URL is
2982 // unelided.
2983 content::MockNavigationHandle navigation;
2984 navigation.set_url(GURL(kSimplifiedDomainDisplayUrl));
2985 navigation.set_is_error_page(true);
2986 omnibox_view()->DidStartNavigation(&navigation);
2987 omnibox_view()->DidFinishNavigation(&navigation);
2988 ExpectUnelidedFromSimplifiedDomain(
2989 omnibox_view()->GetRenderText(),
2990 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2991 kSimplifiedDomainDisplayUrl.size()));
2992 }
2993
2994 // Tests that in the hide-on-interaction field trial, the URL is simplified on
2995 // cross-document main-frame navigations, but not on same-document navigations.
TEST_P(OmniboxViewViewsHideOnInteractionTest,SameDocNavigations)2996 TEST_P(OmniboxViewViewsHideOnInteractionTest, SameDocNavigations) {
2997 SetUpSimplifiedDomainTest();
2998 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2999 /*is_same_document=*/false, GURL(),
3000 kSimplifiedDomainDisplayUrlScheme);
3001 const base::string16 kUrlSuffix = base::ASCIIToUTF16("/foobar");
3002
3003 // On a same-document navigation before the URL has been simplified, the URL
3004 // should remain unsimplified after the navigation finishes.
3005
3006 {
3007 // Set a longer URL to ensure that the full URL stays visible even if it's
3008 // longer than the previous URL.
3009 omnibox_view()->NavigateAndExpectUnelided(
3010 kSimplifiedDomainDisplayUrl + kUrlSuffix, /*is_same_document=*/true,
3011 GURL(), kSimplifiedDomainDisplayUrlScheme);
3012 OmniboxViewViews::ElideAnimation* elide_animation =
3013 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3014 EXPECT_FALSE(elide_animation);
3015 }
3016
3017 // Simulate a user interaction to elide to the simplified domain.
3018 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3019 OmniboxViewViews::ElideAnimation* elide_animation =
3020 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3021 ASSERT_TRUE(elide_animation);
3022 EXPECT_TRUE(elide_animation->IsAnimating());
3023
3024 // On a cross-document main-frame navigation, the unsimplified URL should
3025 // remain visible.
3026 {
3027 omnibox_view()->NavigateAndExpectUnelided(
3028 kSimplifiedDomainDisplayUrl, /*is_same_document=*/false, GURL(),
3029 kSimplifiedDomainDisplayUrlScheme);
3030 OmniboxViewViews::ElideAnimation* elide_animation =
3031 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3032 EXPECT_FALSE(elide_animation);
3033 }
3034
3035 // Simulate another user interaction to elide to the simplified domain, and
3036 // advance the clock all the way through the animation.
3037 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3038 ASSERT_NO_FATAL_FAILURE(
3039 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3040 /*step_ms=*/1000));
3041 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3042 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3043 kSimplifiedDomainDisplayUrlSubdomain,
3044 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3045 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3046
3047 // On same-document main-frame fragment navigation, the URL should remain
3048 // elided to the simplified domain.
3049 {
3050 omnibox_view()->NavigateAndExpectElided(
3051 GURL(kSimplifiedDomainDisplayUrl + base::ASCIIToUTF16("#foobar")),
3052 /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl),
3053 kSimplifiedDomainDisplayUrlScheme, kSimplifiedDomainDisplayUrlSubdomain,
3054 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3055 kSimplifiedDomainDisplayUrlPath + base::ASCIIToUTF16("#foobar"),
3056 ShouldElideToRegistrableDomain());
3057 OmniboxViewViews::ElideAnimation* elide_animation =
3058 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3059 ASSERT_TRUE(elide_animation);
3060 EXPECT_FALSE(elide_animation->IsAnimating());
3061 }
3062
3063 // On same-document main-frame non-fragment navigation, the URL shouldn't
3064 // remain elided to the simplified domain.
3065 {
3066 omnibox_view()->NavigateAndExpectUnelided(
3067 kSimplifiedDomainDisplayUrl + kUrlSuffix, /*is_same_document=*/true,
3068 GURL(kSimplifiedDomainDisplayUrl), kSimplifiedDomainDisplayUrlScheme);
3069 OmniboxViewViews::ElideAnimation* elide_animation =
3070 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3071 EXPECT_FALSE(elide_animation);
3072 }
3073 }
3074
3075 // Tests that in the hide-on-interaction field trial, a same-document navigation
3076 // cancels a currently-running animation and goes straight to the end state
3077 // (elided to the simplified domain).
TEST_P(OmniboxViewViewsHideOnInteractionTest,SameDocNavigationDuringAnimation)3078 TEST_P(OmniboxViewViewsHideOnInteractionTest,
3079 SameDocNavigationDuringAnimation) {
3080 SetUpSimplifiedDomainTest();
3081 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3082 gfx::Range path_bounds(
3083 kSimplifiedDomainDisplayUrl.find(kSimplifiedDomainDisplayUrlPath),
3084 kSimplifiedDomainDisplayUrl.size());
3085
3086 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3087 /*is_same_document=*/false, GURL(),
3088 kSimplifiedDomainDisplayUrlScheme);
3089
3090 // Simulate a user interaction to begin animating to the simplified domain.
3091 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3092
3093 // Advance the clock by 1ms until the full URL is no longer showing, but we
3094 // haven't finished eliding to the simplified domain yet. After a
3095 // same-document navigation, we check that the URL has gone straight to the
3096 // end state. In other words, a same-document navigation will cancel a
3097 // currently-running animation but should end up where the animation was
3098 // targeting.
3099 bool is_midway_through_elision = false;
3100 uint32_t step_ms = 1;
3101 while (!is_midway_through_elision) {
3102 ASSERT_NO_FATAL_FAILURE(
3103 omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3104 is_midway_through_elision = IsPartlyThroughSimplifiedDomainElision(
3105 render_text, kSimplifiedDomainDisplayUrl, path_bounds);
3106 }
3107
3108 omnibox_view()->NavigateAndExpectElided(
3109 GURL(kSimplifiedDomainDisplayUrl),
3110 /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl),
3111 kSimplifiedDomainDisplayUrlScheme, kSimplifiedDomainDisplayUrlSubdomain,
3112 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3113 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain());
3114
3115 OmniboxViewViews::ElideAnimation* elide_animation =
3116 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3117 ASSERT_TRUE(elide_animation);
3118 EXPECT_FALSE(elide_animation->IsAnimating());
3119 }
3120
3121 // Tests that gradient mask is set correctly.
TEST_P(OmniboxViewViewsHideOnInteractionTest,GradientMask)3122 TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMask) {
3123 if (base::i18n::IsRTL()) {
3124 // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
3125 // implemented for RTL UI.
3126 return;
3127 }
3128 SetUpSimplifiedDomainTest();
3129 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3130 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3131 /*is_same_document=*/false, GURL(),
3132 kSimplifiedDomainDisplayUrlScheme);
3133
3134 // Simulate a user interaction to begin animating to the simplified domain.
3135 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3136 // Advance the clock by 1ms until the full size gradient has been added.
3137 uint32_t step_ms = 1;
3138 int max_gradient_width = OmniboxViewViews::kSmoothingGradientMaxWidth - 1;
3139 while (omnibox_view()->elide_animation_smoothing_rect_right_.width() <
3140 max_gradient_width) {
3141 ASSERT_NO_FATAL_FAILURE(
3142 omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3143 }
3144 // If we are eliding from the left, the other side gradient should also be
3145 // full size at this point, otherwise it should be 0.
3146 if (ShouldElideToRegistrableDomain()) {
3147 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(),
3148 max_gradient_width);
3149 } else {
3150 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0);
3151 }
3152
3153 // Get a bounding box for the unelided section of the URL.
3154 std::vector<gfx::Range> ranges_surrounding_simplified_domain;
3155 gfx::Range simplified_range = omnibox_view()->GetSimplifiedDomainBounds(
3156 &ranges_surrounding_simplified_domain);
3157 gfx::Rect simplified_rect;
3158 for (auto rect : render_text->GetSubstringBounds(simplified_range)) {
3159 simplified_rect.Union(rect - render_text->GetLineOffset(0));
3160 }
3161
3162 // Advance the animation until both gradients start shrinking.
3163 while (omnibox_view()->elide_animation_smoothing_rect_left_.width() ==
3164 max_gradient_width ||
3165 omnibox_view()->elide_animation_smoothing_rect_right_.width() ==
3166 max_gradient_width) {
3167 ASSERT_NO_FATAL_FAILURE(
3168 omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3169 }
3170 int offset = omnibox_view()
3171 ->GetElideAfterInteractionAnimationForTesting()
3172 ->GetCurrentOffsetForTesting();
3173 gfx::Rect display_rect = render_text->display_rect();
3174 // Check the expected size and positions for both gradients.
3175 EXPECT_TRUE(omnibox_view()->elide_animation_smoothing_rect_left_.width() ==
3176 simplified_rect.x() + offset - 1 ||
3177 omnibox_view()->elide_animation_smoothing_rect_left_.width() ==
3178 0);
3179 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.x(),
3180 display_rect.x());
3181 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(),
3182 display_rect.right() - (simplified_rect.right() + offset) - 1);
3183 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.x() - 1,
3184 simplified_rect.right() + offset);
3185 }
3186
3187 // Tests that gradient mask is reset when animation is stopped.
TEST_P(OmniboxViewViewsHideOnInteractionTest,GradientMaskResetAfterStop)3188 TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMaskResetAfterStop) {
3189 if (base::i18n::IsRTL()) {
3190 // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
3191 // implemented for RTL UI.
3192 return;
3193 }
3194 SetUpSimplifiedDomainTest();
3195 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3196 /*is_same_document=*/false, GURL(),
3197 kSimplifiedDomainDisplayUrlScheme);
3198
3199 // Simulate a user interaction to begin animating to the simplified domain.
3200 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3201 // Advance animation so it sets the gradient mask, then stop it.
3202 ASSERT_NO_FATAL_FAILURE(
3203 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3204 /*step_ms=*/1000));
3205 omnibox_view()->GetElideAfterInteractionAnimationForTesting()->Stop();
3206
3207 // Both gradient mask rectangles should have a width of 0 once the animation
3208 // has stopped.
3209 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0);
3210 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), 0);
3211 }
3212
3213 // Tests that in the hide-on-interaction field trial, a second user interaction
3214 // does not interfere with an animation that is currently running. This is
3215 // similar to SameDocNavigationDuringAnimation except that this test checks that
3216 // a second user interaction (rather than a same-doc navigation) lets the
3217 // animation proceed undisturbed.
TEST_P(OmniboxViewViewsHideOnInteractionTest,UserInteractionDuringAnimation)3218 TEST_P(OmniboxViewViewsHideOnInteractionTest, UserInteractionDuringAnimation) {
3219 SetUpSimplifiedDomainTest();
3220 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3221 gfx::Range path_bounds(
3222 kSimplifiedDomainDisplayUrl.find(kSimplifiedDomainDisplayUrlPath),
3223 kSimplifiedDomainDisplayUrl.size());
3224 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3225 /*is_same_document=*/false, GURL(),
3226 kSimplifiedDomainDisplayUrlScheme);
3227
3228 // Simulate a user interaction to begin animating to the simplified domain.
3229 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3230
3231 // Advance the clock by 1ms until the full URL is no longer showing, but we
3232 // haven't finished eliding to the simplified domain yet. After a subsequent
3233 // user interaction, we check that the URL is still in the same state (midway
3234 // through elision) and that the animation is still running undisturbed. In
3235 // other words, a second user interaction shouldn't change anything when an
3236 // animation is in progress.
3237 bool is_midway_through_elision = false;
3238 uint32_t step_ms = 0;
3239 while (!is_midway_through_elision) {
3240 ASSERT_NO_FATAL_FAILURE(
3241 omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3242 is_midway_through_elision = IsPartlyThroughSimplifiedDomainElision(
3243 render_text, kSimplifiedDomainDisplayUrl, path_bounds);
3244 }
3245 double animation_value = omnibox_view()
3246 ->GetElideAfterInteractionAnimationForTesting()
3247 ->GetAnimationForTesting()
3248 ->GetCurrentValue();
3249
3250 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3251 OmniboxViewViews::ElideAnimation* elide_animation =
3252 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3253 ASSERT_TRUE(elide_animation);
3254 EXPECT_TRUE(elide_animation->IsAnimating());
3255 EXPECT_EQ(animation_value,
3256 elide_animation->GetAnimationForTesting()->GetCurrentValue());
3257 // The current display text should reflect that the animation in progress: the
3258 // full display URL shouldn't be still visible, but we haven't necessarily
3259 // reached the end state (just the simplified domain visible) yet.
3260 EXPECT_TRUE(IsPartlyThroughSimplifiedDomainElision(
3261 render_text, kSimplifiedDomainDisplayUrl, path_bounds));
3262 }
3263
3264 // Tests that in the hide-on-interaction field trial, the path is not re-shown
3265 // on subframe navigations.
TEST_P(OmniboxViewViewsHideOnInteractionTest,SubframeNavigations)3266 TEST_P(OmniboxViewViewsHideOnInteractionTest, SubframeNavigations) {
3267 SetUpSimplifiedDomainTest();
3268 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3269 /*is_same_document=*/false, GURL(),
3270 kSimplifiedDomainDisplayUrlScheme);
3271
3272 // Simulate a user interaction to elide to the simplified domain, and advance
3273 // the clock all the way through the animation.
3274 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3275 ASSERT_NO_FATAL_FAILURE(
3276 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3277 /*step_ms=*/1000));
3278 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3279 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3280 kSimplifiedDomainDisplayUrlSubdomain,
3281 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3282 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3283
3284 // On a subframe navigation, the URL should remain elided to a simplified
3285 // domain.
3286 {
3287 content::MockNavigationHandle navigation;
3288 navigation.set_is_same_document(false);
3289 std::unique_ptr<content::WebContents> web_contents =
3290 content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
3291 content::RenderFrameHostTester::For(web_contents->GetMainFrame())
3292 ->InitializeRenderFrameIfNeeded();
3293 content::RenderFrameHost* subframe =
3294 content::RenderFrameHostTester::For(web_contents->GetMainFrame())
3295 ->AppendChild("subframe");
3296 navigation.set_render_frame_host(subframe);
3297 omnibox_view()->DidStartNavigation(&navigation);
3298 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3299 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3300 kSimplifiedDomainDisplayUrlSubdomain,
3301 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3302 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3303 omnibox_view()->DidFinishNavigation(&navigation);
3304 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3305 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3306 kSimplifiedDomainDisplayUrlSubdomain,
3307 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3308 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3309 }
3310 }
3311
3312 // Tests that in the reveal-on-hover field trial variation, domains are aligned
3313 // to the right (truncated from the left) if the omnibox is too narrow to fit
3314 // the whole domain.
TEST_P(OmniboxViewViewsRevealOnHoverTest,SimplifiedDomainElisionWithNarrowOmnibox)3315 TEST_P(OmniboxViewViewsRevealOnHoverTest,
3316 SimplifiedDomainElisionWithNarrowOmnibox) {
3317 const int kOmniboxWidth = 60;
3318 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3319 gfx::Rect current_bounds = omnibox_view()->GetLocalBounds();
3320 gfx::Rect bounds(current_bounds.x(), current_bounds.y(), kOmniboxWidth,
3321 current_bounds.height());
3322 omnibox_view()->SetBoundsRect(bounds);
3323 SetUpSimplifiedDomainTest();
3324
3325 ASSERT_EQ(kSimplifiedDomainDisplayUrl, render_text->GetDisplayText());
3326
3327 // The omnibox should contain a substring of the domain, aligned to the right.
3328 gfx::Rect hostname_bounds;
3329 for (const auto& rect : render_text->GetSubstringBounds(
3330 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3331 kSimplifiedDomainDisplayUrlHostnameAndScheme.size()))) {
3332 hostname_bounds.Union(rect);
3333 }
3334 EXPECT_LT(hostname_bounds.x(), omnibox_view()->GetLocalBounds().x());
3335 EXPECT_FALSE(omnibox_view()->GetLocalBounds().Contains(hostname_bounds));
3336
3337 // No hover animations should run when the omnibox is too narrow to fit the
3338 // simplified domain.
3339
3340 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3341 OmniboxViewViews::ElideAnimation* elide_animation =
3342 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
3343 ASSERT_TRUE(elide_animation);
3344 EXPECT_FALSE(elide_animation->IsAnimating());
3345
3346 omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3347 elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
3348 ASSERT_TRUE(elide_animation);
3349 EXPECT_FALSE(elide_animation->IsAnimating());
3350 }
3351
3352 // Tests that in the reveal-on-hover and hide-on-interaction field trial
3353 // variation, domains are aligned to the right (truncated from the left) if the
3354 // omnibox is too narrow to fit the whole domain.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,SimplifiedDomainElisionWithNarrowOmnibox)3355 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3356 SimplifiedDomainElisionWithNarrowOmnibox) {
3357 const int kOmniboxWidth = 60;
3358 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3359 gfx::Rect current_bounds = omnibox_view()->GetLocalBounds();
3360 gfx::Rect bounds(current_bounds.x(), current_bounds.y(), kOmniboxWidth,
3361 current_bounds.height());
3362 omnibox_view()->SetBoundsRect(bounds);
3363 SetUpSimplifiedDomainTest();
3364
3365 content::MockNavigationHandle navigation;
3366 navigation.set_is_same_document(false);
3367 omnibox_view()->DidFinishNavigation(&navigation);
3368
3369 ASSERT_EQ(kSimplifiedDomainDisplayUrl, render_text->GetDisplayText());
3370
3371 // The omnibox should contain a substring of the domain, aligned to the right.
3372 gfx::Rect hostname_bounds;
3373 for (const auto& rect : render_text->GetSubstringBounds(
3374 gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3375 kSimplifiedDomainDisplayUrlHostnameAndScheme.size()))) {
3376 hostname_bounds.Union(rect);
3377 }
3378 EXPECT_LT(hostname_bounds.x(), omnibox_view()->GetLocalBounds().x());
3379 EXPECT_FALSE(omnibox_view()->GetLocalBounds().Contains(hostname_bounds));
3380 }
3381
3382 // Tests that in the hide-on-interaction field trial variation, the path is
3383 // faded out after omnibox focus and blur.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,HideOnInteractionAfterFocusAndBlur)3384 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3385 HideOnInteractionAfterFocusAndBlur) {
3386 SetUpSimplifiedDomainTest();
3387 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3388 /*is_same_document=*/false, GURL(),
3389 kSimplifiedDomainDisplayUrlScheme);
3390 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3391
3392 // Simulate a user interaction to fade out the path.
3393 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3394 ASSERT_NO_FATAL_FAILURE(
3395 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3396 /*step_ms=*/1000));
3397 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3398 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3399 kSimplifiedDomainDisplayUrlSubdomain,
3400 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3401 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3402
3403 // After focus, the URL should be fully unelided.
3404 omnibox_view()->OnFocus();
3405 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3406 render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
3407 EXPECT_NE(SK_ColorTRANSPARENT,
3408 omnibox_view()->GetLatestColorForRange(
3409 gfx::Range(0, omnibox_view()->GetText().size())));
3410 EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3411 kSimplifiedDomainDisplayUrlHostnameAndScheme.size()),
3412 omnibox_view()->emphasis_range());
3413
3414 // After blur, the URL should return to the same state as page load: only
3415 // scheme and trivial subdomains elided.
3416 omnibox_view()->OnBlur();
3417 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3418 render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3419 kSimplifiedDomainDisplayUrl.size())));
3420 EXPECT_NE(SK_ColorTRANSPARENT,
3421 omnibox_view()->GetLatestColorForRange(
3422 gfx::Range(0, omnibox_view()->GetText().size())));
3423 EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3424 kSimplifiedDomainDisplayUrlHostnameAndScheme.size()),
3425 omnibox_view()->emphasis_range());
3426
3427 // After a post-blur user interaction, the URL should animate to the
3428 // simplified domain.
3429 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3430 OmniboxViewViews::ElideAnimation* elide_animation =
3431 omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3432 EXPECT_TRUE(elide_animation->IsAnimating());
3433 }
3434
3435 // Tests that in the hide-on-interaction field trial variation, the URL is
3436 // aligned as appropriate for LTR and RTL UIs during the different stages
3437 // of elision.
3438 // Regression test for crbug.com/1114332
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,URLPositionWithHideOnInteraction)3439 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3440 URLPositionWithHideOnInteraction) {
3441 SetUpSimplifiedDomainTest();
3442 gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3443 // Initially the display rect of the render text matches the omnibox bounds,
3444 // store a copy of it.
3445 gfx::Rect omnibox_bounds(render_text->display_rect());
3446
3447 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3448 /*is_same_document=*/false, GURL(),
3449 kSimplifiedDomainDisplayUrlScheme);
3450
3451 // Simulate a user interaction to fade out the path.
3452 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3453 ASSERT_NO_FATAL_FAILURE(
3454 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3455 /*step_ms=*/1000));
3456 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3457 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3458 kSimplifiedDomainDisplayUrlSubdomain,
3459 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3460 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3461
3462 // Check the URL is right aligned if the UI is RTL, or left aligned if it is
3463 // LTR.
3464 if (base::i18n::IsRTL()) {
3465 EXPECT_EQ(render_text->display_rect().x(),
3466 omnibox_bounds.right() - render_text->display_rect().width());
3467 } else {
3468 EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x());
3469 }
3470
3471 // Call OnFocus to trigger unelision.
3472 omnibox_view()->OnFocus();
3473 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3474 render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
3475
3476 // Check alignment again
3477 if (base::i18n::IsRTL()) {
3478 EXPECT_EQ(render_text->display_rect().x(),
3479 omnibox_bounds.right() - render_text->display_rect().width());
3480 } else {
3481 EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x());
3482 }
3483
3484 // Call OnBlur to return to the state on page load.
3485 omnibox_view()->OnBlur();
3486 ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3487 render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3488 kSimplifiedDomainDisplayUrl.size())));
3489
3490 // Check alignment again
3491 if (base::i18n::IsRTL()) {
3492 EXPECT_EQ(render_text->display_rect().x(),
3493 omnibox_bounds.right() - render_text->display_rect().width());
3494 } else {
3495 EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x());
3496 }
3497 }
3498
3499 // Tests that the last gradient mask from a previous animation is no longer
3500 // visible when starting a new animation.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,NoStaleGradientMask)3501 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3502 NoStaleGradientMask) {
3503 if (base::i18n::IsRTL()) {
3504 // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
3505 // implemented for RTL UI.
3506 return;
3507 }
3508 SetUpSimplifiedDomainTest();
3509 omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3510 /*is_same_document=*/false, GURL(),
3511 kSimplifiedDomainDisplayUrlScheme);
3512
3513 // Simulate a user interaction to begin animating to the simplified domain.
3514 omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3515 ASSERT_NO_FATAL_FAILURE(
3516 omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3517 /*step_ms=*/1000));
3518
3519 // Hover over the omnibox to trigger unelide animation.
3520 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3521 ASSERT_NO_FATAL_FAILURE(
3522 omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
3523
3524 // Both gradient mask rectangles will be full sized at this point
3525 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(),
3526 OmniboxViewViews::kSmoothingGradientMaxWidth - 1);
3527 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(),
3528 OmniboxViewViews::kSmoothingGradientMaxWidth - 1);
3529
3530 // Select the text in the omnibox, then click on the page, this will trigger
3531 // an elision with no animation.
3532 omnibox_view()->SelectAll(false);
3533 blink::WebMouseEvent event;
3534 event.SetType(blink::WebInputEvent::Type::kMouseDown);
3535 omnibox_view()->DidGetUserInteraction(event);
3536
3537 // Hover over the omnibox to trigger the unelide animation.
3538 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3539
3540 // Even though the unelide animation hasn't advanced, the gradient mask
3541 // rectangles should have been reset.
3542 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0);
3543 EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), 0);
3544 }
3545
3546 // Tests that in the reveal-on-hover field trial variation (without
3547 // hide-on-interaction), the path is faded back in after focus, then blur, then
3548 // hover.
3549 // TODO(crbug.com/1115551): Test is flaky.
TEST_P(OmniboxViewViewsRevealOnHoverTest,DISABLED_AfterBlur)3550 TEST_P(OmniboxViewViewsRevealOnHoverTest, DISABLED_AfterBlur) {
3551 SetUpSimplifiedDomainTest();
3552
3553 // Focus and blur the omnibox, then hover over it. The URL should unelide.
3554 omnibox_view()->OnFocus();
3555 omnibox_view()->OnBlur();
3556 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3557 omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3558 kSimplifiedDomainDisplayUrlSubdomain,
3559 kSimplifiedDomainDisplayUrlHostnameAndScheme,
3560 kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3561 omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3562 OmniboxViewViews::ElideAnimation* elide_animation =
3563 omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
3564 ASSERT_TRUE(elide_animation);
3565 EXPECT_TRUE(elide_animation->IsAnimating());
3566 }
3567
3568 // Tests that registrable domain elision properly handles the case when the
3569 // registrable domain appears as a subdomain, e.g. test.com.test.com.
TEST_P(OmniboxViewViewsRevealOnHoverTest,RegistrableDomainRepeated)3570 TEST_P(OmniboxViewViewsRevealOnHoverTest, RegistrableDomainRepeated) {
3571 // This test only applies when the URL is elided to the registrable domain.
3572 if (!ShouldElideToRegistrableDomain())
3573 return;
3574
3575 const base::string16 kRepeatedRegistrableDomainUrl =
3576 base::ASCIIToUTF16("https://example.com.example.com/foo");
3577 gfx::Range registrable_domain_and_path_range(
3578 20 /* "https://www.example.com." */,
3579 kRepeatedRegistrableDomainUrl.size());
3580
3581 UpdateDisplayURL(kRepeatedRegistrableDomainUrl);
3582 // Call OnThemeChanged() to create the animations.
3583 omnibox_view()->OnThemeChanged();
3584
3585 ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3586 omnibox_view(), base::ASCIIToUTF16("https://"),
3587 base::ASCIIToUTF16("example.com."),
3588 base::ASCIIToUTF16("https://example.com.example.com"),
3589 base::ASCIIToUTF16("/foo"), ShouldElideToRegistrableDomain()));
3590
3591 // Check that the domain is elided up to the second instance of "example.com",
3592 // not the first.
3593 gfx::Rect registrable_domain_and_path;
3594 for (const auto& rect : omnibox_view()->GetRenderText()->GetSubstringBounds(
3595 registrable_domain_and_path_range)) {
3596 registrable_domain_and_path.Union(rect);
3597 }
3598 EXPECT_EQ(omnibox_view()->GetRenderText()->display_rect().x(),
3599 registrable_domain_and_path.x());
3600 }
3601