// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/path_service.h" #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "cc/test/pixel_comparator.h" #include "cc/test/pixel_test_utils.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/common/content_paths.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "ui/base/ui_base_features.h" #include "ui/display/display_switches.h" #include "ui/gfx/image/image.h" #include "ui/gfx/skbitmap_operations.h" // To rebaseline this test on android: // 1. Run a CQ+1 dry run // 2. Click the failing android bot // 3. Find the failing content_browsertests step // 4. Click the "Deterministic failure" link for the failing test case // 5. Copy the "Actual pixels" data url and paste into browser // 6. Save the image into your chromium checkout in content/test/data/forms/ namespace content { class FormControlsBrowserTest : public ContentBrowserTest { public: FormControlsBrowserTest() = default; void SetUp() override { EnablePixelOutput(); ContentBrowserTest::SetUp(); } void SetUpCommandLine(base::CommandLine* command_line) override { ContentBrowserTest::SetUpCommandLine(command_line); // The --force-device-scale-factor flag helps make the pixel output of // different android trybots more similar. command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1.0"); feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); feature_list_->InitWithFeatures({features::kFormControlsRefresh}, {}); } void TearDown() override { feature_list_.reset(); } void AsyncSnapshotCallback(const gfx::Image& image) { got_snapshot_ = true; snapshot_ = image; } void RunFormControlsTest(const std::string& expected_filename, const std::string& body_html, int screenshot_width, int screenshot_height) { base::ScopedAllowBlockingForTesting allow_blocking; ASSERT_TRUE(features::IsFormControlsRefreshEnabled()); std::string url = "data:text/html,<!DOCTYPE html>" "<head>" // The <meta name=viewport> tag helps make the pixel output of // different android trybots more similar. " <meta name=\"viewport\" content=\"width=640, initial-scale=1, " " maximum-scale=1, minimum-scale=1\">" "</head>" "<body>" + body_html + "</body>"; ASSERT_TRUE(NavigateToURL(shell(), GURL(url))); RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From(shell() ->web_contents() ->GetRenderWidgetHostView() ->GetRenderWidgetHost()); CHECK(rwh); rwh->GetSnapshotFromBrowser( base::BindOnce(&FormControlsBrowserTest::AsyncSnapshotCallback, base::Unretained(this)), /* from_surface */ true); while (!got_snapshot_) base::RunLoop().RunUntilIdle(); SkBitmap bitmap = SkBitmapOperations::CreateTiledBitmap( *snapshot_.ToSkBitmap(), /* src_x */ 0, /* src_y */ 0, screenshot_width, screenshot_height); base::FilePath dir_test_data; ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &dir_test_data)); std::string filename_with_extension = expected_filename; #if defined(OS_ANDROID) filename_with_extension += "_android"; #endif filename_with_extension += ".png"; base::FilePath expected_path = dir_test_data.AppendASCII("forms").AppendASCII(filename_with_extension); SkBitmap expected_bitmap; ASSERT_TRUE(cc::ReadPNGFile(expected_path, &expected_bitmap)); EXPECT_TRUE(cc::MatchesBitmap( bitmap, expected_bitmap, #if defined(OS_MACOSX) // The Mac 10.12 trybot has more significant subpixel rendering // differences which we accommodate for here with a large avg/max // per-pixel error limit. // TODO(crbug.com/1037971): Remove this special case for mac once this // bug is resolved. cc::FuzzyPixelComparator(/* discard_alpha */ true, /* error_pixels_percentage_limit */ 7.f, /* small_error_pixels_percentage_limit */ 0.f, /* avg_abs_error_limit */ 16.f, /* max_abs_error_limit */ 79.f, /* small_error_threshold */ 0))); #else // We use a fuzzy comparator to accommodate for slight // differences between the kitkat and marshmallow trybots that aren't // visible to the human eye. We use a very low error limit because the // pixels that are different are very similar shades of color. cc::FuzzyPixelComparator(/* discard_alpha */ true, /* error_pixels_percentage_limit */ 6.f, /* small_error_pixels_percentage_limit */ 0.f, /* avg_abs_error_limit */ 4.f, /* max_abs_error_limit */ 4.f, /* small_error_threshold */ 0))); #endif } bool got_snapshot_ = false; gfx::Image snapshot_; std::unique_ptr<base::test::ScopedFeatureList> feature_list_; }; IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, Checkbox) { RunFormControlsTest( "form_controls_browsertest_checkbox", "<input type=checkbox>" "<input type=checkbox checked>" "<input type=checkbox disabled>" "<input type=checkbox checked disabled>" "<input type=checkbox id=\"indeterminate\">" "<script>" " document.getElementById('indeterminate').indeterminate = true" "</script>", /* screenshot_width */ 130, /* screenshot_height */ 40); } IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, Radio) { RunFormControlsTest( "form_controls_browsertest_radio", "<input type=radio>" "<input type=radio checked>" "<input type=radio disabled>" "<input type=radio checked disabled>" "<input type=radio id=\"indeterminate\">" "<script>" " document.getElementById('indeterminate').indeterminate = true" "</script>", /* screenshot_width */ 140, /* screenshot_height */ 40); } // TODO(jarhar): Add tests for other elements from // https://concrete-hardboard.glitch.me } // namespace content