| // Copyright 2018 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 "third_party/blink/renderer/core/html/lazy_load_frame_observer.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <tuple> |
| |
| #include "base/optional.h" |
| #include "third_party/blink/public/platform/web_effective_connection_type.h" |
| #include "third_party/blink/renderer/core/dom/element.h" |
| #include "third_party/blink/renderer/core/exported/web_view_impl.h" |
| #include "third_party/blink/renderer/core/frame/local_frame_view.h" |
| #include "third_party/blink/renderer/core/frame/settings.h" |
| #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" |
| #include "third_party/blink/renderer/core/html_names.h" |
| #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_compositor.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_request.h" |
| #include "third_party/blink/renderer/core/testing/sim/sim_test.h" |
| #include "third_party/blink/renderer/platform/geometry/float_rect.h" |
| #include "third_party/blink/renderer/platform/network/network_state_notifier.h" |
| #include "third_party/blink/renderer/platform/testing/histogram_tester.h" |
| #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" |
| #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" |
| #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" |
| #include "third_party/blink/renderer/platform/wtf/vector.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| constexpr std::pair<WebEffectiveConnectionType, const char*> |
| kVisibleLoadTimeAboveTheFoldHistogramNames[] = { |
| {WebEffectiveConnectionType::kTypeSlow2G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.AboveTheFold.Slow2G"}, |
| {WebEffectiveConnectionType::kType2G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.AboveTheFold.2G"}, |
| {WebEffectiveConnectionType::kType3G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.AboveTheFold.3G"}, |
| {WebEffectiveConnectionType::kType4G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.AboveTheFold.4G"}, |
| }; |
| |
| constexpr std::pair<WebEffectiveConnectionType, const char*> |
| kVisibleLoadTimeBelowTheFoldHistogramNames[] = { |
| {WebEffectiveConnectionType::kTypeSlow2G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.BelowTheFold.Slow2G"}, |
| {WebEffectiveConnectionType::kType2G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.BelowTheFold.2G"}, |
| {WebEffectiveConnectionType::kType3G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.BelowTheFold.3G"}, |
| {WebEffectiveConnectionType::kType4G, |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.BelowTheFold.4G"}, |
| }; |
| |
| constexpr std::pair<WebEffectiveConnectionType, const char*> |
| kInitialDeferralActionHistogramNames[] = { |
| {WebEffectiveConnectionType::kTypeUnknown, |
| "Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction.Unknown"}, |
| {WebEffectiveConnectionType::kTypeOffline, |
| "Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction.Offline"}, |
| {WebEffectiveConnectionType::kTypeSlow2G, |
| "Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction.Slow2G"}, |
| {WebEffectiveConnectionType::kType2G, |
| "Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction.2G"}, |
| {WebEffectiveConnectionType::kType3G, |
| "Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction.3G"}, |
| {WebEffectiveConnectionType::kType4G, |
| "Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction.4G"}, |
| }; |
| |
| // Convenience enums to make it easy to access the appropriate value of the |
| // tuple parameters in the parameterized tests below, e.g. so that |
| // std::get<LazyFrameLoadingFeatureStatus>(GetParam()) can be used instead of |
| // std::get<0>(GetParam()) if they were just booleans. |
| enum class LazyFrameLoadingFeatureStatus { kDisabled, kEnabled }; |
| enum class LazyFrameVisibleLoadTimeFeatureStatus { kDisabled, kEnabled }; |
| |
| class LazyLoadFramesParamsTest |
| : public SimTest, |
| public ::testing::WithParamInterface< |
| std::tuple<LazyFrameLoadingFeatureStatus, |
| LazyFrameVisibleLoadTimeFeatureStatus, |
| WebEffectiveConnectionType>> { |
| public: |
| static constexpr int kViewportWidth = 800; |
| static constexpr int kViewportHeight = 600; |
| |
| LazyLoadFramesParamsTest() |
| : scoped_lazy_frame_loading_for_test_( |
| std::get<LazyFrameLoadingFeatureStatus>(GetParam()) == |
| LazyFrameLoadingFeatureStatus::kEnabled), |
| scoped_automatic_lazy_frame_loading_for_test_( |
| std::get<LazyFrameLoadingFeatureStatus>(GetParam()) == |
| LazyFrameLoadingFeatureStatus::kEnabled), |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false), |
| scoped_lazy_frame_visible_load_time_metrics_for_test_( |
| std::get<LazyFrameVisibleLoadTimeFeatureStatus>(GetParam()) == |
| LazyFrameVisibleLoadTimeFeatureStatus::kEnabled) {} |
| |
| void SetUp() override { |
| GetNetworkStateNotifier().SetNetworkConnectionInfoOverride( |
| true /*on_line*/, kWebConnectionTypeWifi, |
| std::get<WebEffectiveConnectionType>(GetParam()), |
| 1000 /*http_rtt_msec*/, 100 /*max_bandwidth_mbps*/); |
| |
| SimTest::SetUp(); |
| WebView().MainFrameWidget()->Resize( |
| gfx::Size(kViewportWidth, kViewportHeight)); |
| |
| Settings& settings = WebView().GetPage()->GetSettings(); |
| |
| // These should match the values that would be returned by |
| // GetLoadingDistanceThreshold(). |
| settings.SetLazyFrameLoadingDistanceThresholdPxUnknown(200); |
| settings.SetLazyFrameLoadingDistanceThresholdPxOffline(300); |
| settings.SetLazyFrameLoadingDistanceThresholdPxSlow2G(400); |
| settings.SetLazyFrameLoadingDistanceThresholdPx2G(500); |
| settings.SetLazyFrameLoadingDistanceThresholdPx3G(600); |
| settings.SetLazyFrameLoadingDistanceThresholdPx4G(700); |
| settings.SetLazyLoadEnabled( |
| RuntimeEnabledFeatures::LazyFrameLoadingEnabled()); |
| } |
| |
| int GetLoadingDistanceThreshold() const { |
| static constexpr int kDistanceThresholdByEffectiveConnectionType[] = { |
| 200, 300, 400, 500, 600, 700}; |
| return kDistanceThresholdByEffectiveConnectionType[static_cast<int>( |
| std::get<WebEffectiveConnectionType>(GetParam()))]; |
| } |
| |
| void ExpectVisibleLoadTimeHistogramSamplesIfApplicable( |
| int expected_above_the_fold_count, |
| int expected_below_the_fold_count) { |
| if (!RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled()) { |
| // Expect zero samples if the visible load time metrics feature is |
| // disabled. |
| expected_above_the_fold_count = 0; |
| expected_below_the_fold_count = 0; |
| } |
| |
| for (const auto& pair : kVisibleLoadTimeAboveTheFoldHistogramNames) { |
| histogram_tester()->ExpectTotalCount( |
| pair.second, |
| std::get<WebEffectiveConnectionType>(GetParam()) == pair.first |
| ? expected_above_the_fold_count |
| : 0); |
| } |
| for (const auto& pair : kVisibleLoadTimeBelowTheFoldHistogramNames) { |
| histogram_tester()->ExpectTotalCount( |
| pair.second, |
| std::get<WebEffectiveConnectionType>(GetParam()) == pair.first |
| ? expected_below_the_fold_count |
| : 0); |
| } |
| } |
| |
| void ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction action, |
| int expected_count) { |
| for (const auto& pair : kInitialDeferralActionHistogramNames) { |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled() && |
| std::get<WebEffectiveConnectionType>(GetParam()) == pair.first) { |
| histogram_tester()->ExpectUniqueSample( |
| pair.second, static_cast<int>(action), expected_count); |
| } else { |
| histogram_tester()->ExpectTotalCount(pair.second, 0); |
| } |
| } |
| } |
| |
| void ExpectLoadStartedAfterDeferredSamplesIfApplicable(int expected_count) { |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| histogram_tester()->ExpectUniqueSample( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", |
| static_cast<int>(std::get<WebEffectiveConnectionType>(GetParam())), |
| expected_count); |
| } else { |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| } |
| } |
| |
| void ExpectVisibleAfterDeferredSamplesIfApplicable(int expected_count) { |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled() && |
| RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled()) { |
| histogram_tester()->ExpectUniqueSample( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", |
| static_cast<int>(std::get<WebEffectiveConnectionType>(GetParam())), |
| expected_count); |
| } else { |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| } |
| |
| HistogramTester* histogram_tester() { return &histogram_tester_; } |
| |
| // Convenience function to load a page with a cross origin frame far down the |
| // page such that it's not near the viewport. |
| std::unique_ptr<SimRequest> LoadPageWithCrossOriginFrameFarFromViewport() { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| std::unique_ptr<SimRequest> child_frame_resource; |
| |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // This SimRequest needs to be created now if the frame won't actually be |
| // lazily loaded. Otherwise, it'll be defined later to ensure that the |
| // subframe resource isn't requested until the page is scrolled down. |
| child_frame_resource.reset( |
| new SimRequest("https://crossorigin.com/subframe.html", "text/html")); |
| } |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 400px; height: 400px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // If the child frame is being lazy loaded, then the body's load event |
| // should have already fired. |
| EXPECT_EQ(RuntimeEnabledFeatures::LazyFrameLoadingEnabled(), |
| ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| |
| if (!child_frame_resource) { |
| child_frame_resource.reset( |
| new SimRequest("https://crossorigin.com/subframe.html", "text/html")); |
| } |
| |
| return child_frame_resource; |
| } |
| |
| private: |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test_; |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test_; |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_; |
| ScopedLazyFrameVisibleLoadTimeMetricsForTest |
| scoped_lazy_frame_visible_load_time_metrics_for_test_; |
| |
| HistogramTester histogram_tester_; |
| }; |
| |
| TEST_P(LazyLoadFramesParamsTest, SameOriginFrame) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://example.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://example.com/subframe.html' |
| style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| for (const auto& pair : kInitialDeferralActionHistogramNames) |
| histogram_tester()->ExpectTotalCount(pair.second, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, AboveTheFoldFrame) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight - 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // The child frame is visible, but hasn't finished loading yet, so no visible |
| // load time samples should have been recorded yet. |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| child_frame_resource.Complete(""); |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(1, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction:: |
| kLoadedNearOrInViewport, |
| 1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, BelowTheFoldButNearViewportFrame) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| |
| // The frame is below the fold, but hasn't been scrolled down to yet, so there |
| // should be no samples in any of the below the fold visible load time |
| // histograms yet. |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| // Scroll down until the child frame is visible. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 1); |
| |
| // The frame finished loading before it became visible, so there should be no |
| // samples in the VisibleBeforeLoaded histogram. |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction:: |
| kLoadedNearOrInViewport, |
| 1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, HiddenAndTinyFrames) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| |
| SimRequest display_none_frame_resource( |
| "https://crossorigin.com/display_none.html", "text/html"); |
| SimRequest visibility_hidden_frame_resource( |
| "https://crossorigin.com/visibility_hidden.html", "text/html"); |
| SimRequest tiny_frame_resource("https://crossorigin.com/tiny.html", |
| "text/html"); |
| SimRequest tiny_width_frame_resource( |
| "https://crossorigin.com/tiny_width.html", "text/html"); |
| SimRequest tiny_height_frame_resource( |
| "https://crossorigin.com/tiny_height.html", "text/html"); |
| SimRequest off_screen_left_frame_resource( |
| "https://crossorigin.com/off_screen_left.html", "text/html"); |
| SimRequest off_screen_top_frame_resource( |
| "https://crossorigin.com/off_screen_top.html", "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <head><style> |
| /* Chrome by default sets borders for iframes, so explicitly specify |
| * no borders, padding, or margins here so that the dimensions of the |
| * tiny frames aren't artifically inflated past the dimensions that |
| * the lazy loading logic considers "tiny". */ |
| iframe { border-style: none; padding: 0px; margin: 0px; } |
| </style></head> |
| |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx'></div> |
| <iframe src='https://crossorigin.com/display_none.html' |
| style='display: none;' |
| onload='console.log("display none element onload");'></iframe> |
| <iframe src='https://crossorigin.com/visibility_hidden.html' |
| style='visibility:hidden;width:100px;height:100px;' |
| onload='console.log("visibility hidden element onload");'></iframe> |
| <iframe src='https://crossorigin.com/tiny.html' |
| style='width: 4px; height: 4px;' |
| onload='console.log("tiny element onload");'></iframe> |
| <iframe src='https://crossorigin.com/tiny_width.html' |
| style='width: 0px; height: 50px;' |
| onload='console.log("tiny width element onload");'></iframe> |
| <iframe src='https://crossorigin.com/tiny_height.html' |
| style='width: 50px; height: 0px;' |
| onload='console.log("tiny height element onload");'></iframe> |
| <iframe src='https://crossorigin.com/off_screen_left.html' |
| style='position:relative;right:9000px;width:50px;height:50px;' |
| onload='console.log("off screen left element onload");'></iframe> |
| <iframe src='https://crossorigin.com/off_screen_top.html' |
| style='position:relative;bottom:9000px;width:50px;height:50px;' |
| onload='console.log("off screen top element onload");'></iframe> |
| </body> |
| )HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| display_none_frame_resource.Complete(""); |
| visibility_hidden_frame_resource.Complete(""); |
| tiny_frame_resource.Complete(""); |
| tiny_width_frame_resource.Complete(""); |
| tiny_height_frame_resource.Complete(""); |
| off_screen_left_frame_resource.Complete(""); |
| off_screen_top_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("display none element onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("visibility hidden element onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("tiny element onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("tiny width element onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("tiny height element onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("off screen left element onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("off screen top element onload")); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| // Scroll down to where the hidden frames are. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, kViewportHeight + GetLoadingDistanceThreshold()), |
| mojom::blink::ScrollType::kProgrammatic); |
| |
| // All of the frames on the page are hidden or tiny, so no visible load time |
| // samples should have been recorded for them. |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kLoadedHidden, 7); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, LoadCrossOriginFrameFarFromViewport) { |
| std::unique_ptr<SimRequest> child_frame_resource = |
| LoadPageWithCrossOriginFrameFarFromViewport(); |
| |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // If LazyFrameLoading is enabled, then scroll down near the child frame to |
| // cause the child frame to start loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| |
| child_frame_resource->Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| // Scroll down so that the child frame is visible. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, GetLoadingDistanceThreshold() + 150), |
| mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 1); |
| |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| ExpectVisibleAfterDeferredSamplesIfApplicable(1); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| CrossOriginFrameFarFromViewportBecomesVisibleBeforeFinishedLoading) { |
| std::unique_ptr<SimRequest> child_frame_resource = |
| LoadPageWithCrossOriginFrameFarFromViewport(); |
| |
| // Scroll down so that the child frame is visible. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, GetLoadingDistanceThreshold() + 150), |
| mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| if (RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled()) { |
| // Even though the child frame hasn't loaded yet, a sample should still have |
| // been recorded for VisibleBeforeLoaded. |
| histogram_tester()->ExpectUniqueSample( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", |
| static_cast<int>(std::get<WebEffectiveConnectionType>(GetParam())), 1); |
| } else { |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| } |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| ExpectVisibleAfterDeferredSamplesIfApplicable(1); |
| |
| child_frame_resource->Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 1); |
| |
| // The samples recorded for VisibleBeforeLoaded should be unchanged. |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", |
| RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled() ? 1 : 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| ExpectVisibleAfterDeferredSamplesIfApplicable(1); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, NestedFrameInCrossOriginFrameFarFromViewport) { |
| std::unique_ptr<SimRequest> child_frame_resource = |
| LoadPageWithCrossOriginFrameFarFromViewport(); |
| |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // If LazyFrameLoading is enabled, then scroll down near the child frame to |
| // cause the child frame to start loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| // There's another nested cross origin iframe inside the first child frame, |
| // even further down such that it's not near the viewport. It should start |
| // loading immediately, even if LazyFrameLoading is enabled, since it's nested |
| // inside a frame that was previously deferred. |
| SimRequest nested_frame_resource("https://test.com/", "text/html"); |
| child_frame_resource->Complete(String::Format( |
| "<div style='height: %dpx;'></div>" |
| "<iframe src='https://test.com/' style='width: 200px; height: 200px;'>" |
| "</iframe>", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| nested_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| |
| // The child frame isn't visible, so no visible load time samples should have |
| // been recorded. |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, AboutBlankChildFrameNavigation) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='BodyOnload()'> |
| <script> |
| function BodyOnload() { |
| console.log('main body onload'); |
| document.getElementsByTagName('iframe')[0].src = |
| 'https://crossorigin.com/subframe.html'; |
| } |
| </script> |
| |
| <div style='height: %dpx;'></div> |
| <iframe |
| style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_EQ(1, static_cast<int>(std::count(ConsoleMessages().begin(), |
| ConsoleMessages().end(), |
| "child frame element onload"))); |
| |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // If LazyFrameLoading is enabled, then scroll down near the child frame to |
| // cause the child frame to start loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_EQ(2, static_cast<int>(std::count(ConsoleMessages().begin(), |
| ConsoleMessages().end(), |
| "child frame element onload"))); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| int expected_histogram_count = 0; |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) |
| expected_histogram_count = 1; |
| |
| for (const auto& pair : kInitialDeferralActionHistogramNames) { |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled() && |
| std::get<WebEffectiveConnectionType>(GetParam()) == pair.first) { |
| histogram_tester()->ExpectTotalCount(pair.second, 1); |
| } else { |
| histogram_tester()->ExpectTotalCount(pair.second, 0); |
| } |
| } |
| |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", |
| expected_histogram_count); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, JavascriptStringFrameUrl) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='javascript:"Hello World!";' |
| style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| for (const auto& pair : kInitialDeferralActionHistogramNames) |
| histogram_tester()->ExpectTotalCount(pair.second, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| CrossOriginFrameFarFromViewportWithLoadingAttributeEager) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' loading='eager' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| for (const auto& pair : kInitialDeferralActionHistogramNames) |
| histogram_tester()->ExpectTotalCount(pair.second, 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| LoadSameOriginFrameFarFromViewportWithLoadingAttributeLazy) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| base::Optional<SimRequest> child_frame_resource; |
| |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // This SimRequest needs to be created now if the frame won't actually be |
| // lazily loaded. Otherwise, it'll be defined later to ensure that the |
| // subframe resource isn't requested until the page is scrolled down. |
| child_frame_resource.emplace("https://example.com/subframe.html", |
| "text/html"); |
| } |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://example.com/subframe.html' |
| style='width: 400px; height: 400px;' loading='lazy' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // If the child frame is being lazy loaded, then the body's load event |
| // should have already fired. |
| EXPECT_EQ(RuntimeEnabledFeatures::LazyFrameLoadingEnabled(), |
| ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.LoadStartedAfterBeingDeferred", 0); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| |
| if (!child_frame_resource) { |
| child_frame_resource.emplace("https://example.com/subframe.html", |
| "text/html"); |
| } |
| |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // If LazyFrameLoading is enabled, then scroll down near the child frame to |
| // cause the child frame to start loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| |
| child_frame_resource->Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| // Scroll down so that the child frame is visible. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, GetLoadingDistanceThreshold() + 150), |
| mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 1); |
| |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| ExpectVisibleAfterDeferredSamplesIfApplicable(1); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| LoadCrossOriginFrameFarFromViewportThenSetLoadingAttributeEager) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| base::Optional<SimRequest> child_frame_resource; |
| |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // This SimRequest needs to be created now if the frame won't actually be |
| // lazily loaded. Otherwise, it'll be defined later to ensure that the |
| // subframe resource isn't requested until the page is scrolled down. |
| child_frame_resource.emplace("https://crossorigin.com/subframe.html", |
| "text/html"); |
| } |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe id='child_frame' src='https://crossorigin.com/subframe.html' |
| style='width: 400px; height: 400px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // If the child frame is being lazy loaded, then the body's load event |
| // should have already fired. |
| EXPECT_EQ(RuntimeEnabledFeatures::LazyFrameLoadingEnabled(), |
| ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| if (!child_frame_resource) { |
| child_frame_resource.emplace("https://crossorigin.com/subframe.html", |
| "text/html"); |
| } |
| |
| Element* child_frame_element = GetDocument().getElementById("child_frame"); |
| ASSERT_TRUE(child_frame_element); |
| child_frame_element->setAttribute(html_names::kLoadingAttr, "eager"); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| |
| child_frame_resource->Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| |
| ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0); |
| |
| histogram_tester()->ExpectTotalCount( |
| "Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0); |
| |
| ExpectInitialDeferralActionHistogramSamplesIfApplicable( |
| LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1); |
| ExpectLoadStartedAfterDeferredSamplesIfApplicable(1); |
| histogram_tester()->ExpectTotalCount( |
| "Blink.LazyLoad.CrossOriginFrames.VisibleAfterBeingDeferred", 0); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| NestedFrameWithLazyLoadAttributeOnInFrameWithNoLoadingAttribute) { |
| std::unique_ptr<SimRequest> child_frame_resource = |
| LoadPageWithCrossOriginFrameFarFromViewport(); |
| |
| if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| // If LazyFrameLoading is enabled, then scroll down near the child frame to |
| // cause the child frame to start loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| // There's another nested cross origin iframe inside the first child frame, |
| // even further down such that it's not near the viewport. If LazyLoad is |
| // enabled, it should be deferred even though it's nested inside a frame that |
| // was previously deferred, because it has the attribute loading=lazy. |
| base::Optional<SimRequest> nested_frame_resource; |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) |
| nested_frame_resource.emplace("https://test.com/", "text/html"); |
| |
| child_frame_resource->Complete( |
| String::Format("<div style='height: %dpx;'></div>" |
| "<iframe src='https://test.com/' loading='lazy'" |
| " style='width: 200px; height: 200px;'>" |
| "</iframe>", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| nested_frame_resource->Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| NestedFrameWithLazyLoadAttributeOnInFrameWithLoadingAttributeEager) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' loading='eager' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| |
| // There's another nested cross origin iframe inside the first child frame, |
| // even further down such that it's not near the viewport. If LazyLoad is |
| // enabled, it should be deferred because it has the attribute loading=lazy, |
| // even though it's nested inside a frame that has the attribute |
| // loading=eager. |
| base::Optional<SimRequest> nested_frame_resource; |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) |
| nested_frame_resource.emplace("https://test.com/", "text/html"); |
| |
| child_frame_resource.Complete( |
| String::Format("<div style='height: %dpx;'></div>" |
| "<iframe src='https://test.com/' loading='lazy'" |
| " style='width: 200px; height: 200px;'>" |
| "</iframe>", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) { |
| nested_frame_resource->Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| } |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| |
| TEST_P(LazyLoadFramesParamsTest, |
| NestedFrameWithLazyLoadAttributeOffInFrameWithLoadingAttributeEager) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' loading='eager' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // There's another nested cross origin iframe inside the first child frame, |
| // even further down such that it's not near the viewport. Since it has the |
| // attribute loading=eager, it shouldn't be deferred. Note that this also |
| // matches the default behavior that would happen if the load attribute was |
| // omitted on the nested iframe entirely. |
| SimRequest nested_frame_resource("https://test.com/", "text/html"); |
| |
| child_frame_resource.Complete( |
| String::Format("<div style='height: %dpx;'></div>" |
| "<iframe src='https://test.com/' loading='eager'" |
| " style='width: 200px; height: 200px;'>" |
| "</iframe>", |
| kViewportHeight + GetLoadingDistanceThreshold() + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| nested_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| LazyFrameLoading, |
| LazyLoadFramesParamsTest, |
| ::testing::Combine( |
| ::testing::Values(LazyFrameLoadingFeatureStatus::kDisabled, |
| LazyFrameLoadingFeatureStatus::kEnabled), |
| ::testing::Values(LazyFrameVisibleLoadTimeFeatureStatus::kDisabled, |
| LazyFrameVisibleLoadTimeFeatureStatus::kEnabled), |
| ::testing::Values(WebEffectiveConnectionType::kTypeUnknown, |
| WebEffectiveConnectionType::kTypeOffline, |
| WebEffectiveConnectionType::kTypeSlow2G, |
| WebEffectiveConnectionType::kType2G, |
| WebEffectiveConnectionType::kType3G, |
| WebEffectiveConnectionType::kType4G))); |
| |
| class LazyLoadFramesTest : public SimTest { |
| public: |
| static constexpr int kViewportWidth = 800; |
| static constexpr int kViewportHeight = 600; |
| static constexpr int kLoadingDistanceThresholdPx = 1000; |
| |
| void SetUp() override { |
| GetNetworkStateNotifier().SetSaveDataEnabledOverride(false); |
| GetNetworkStateNotifier().SetNetworkConnectionInfoOverride( |
| true /*on_line*/, kWebConnectionTypeWifi, |
| WebEffectiveConnectionType::kType4G, 1000 /*http_rtt_msec*/, |
| 100 /*max_bandwidth_mbps*/); |
| |
| SimTest::SetUp(); |
| WebView().MainFrameWidget()->Resize( |
| gfx::Size(kViewportWidth, kViewportHeight)); |
| |
| Settings& settings = WebView().GetPage()->GetSettings(); |
| settings.SetLazyFrameLoadingDistanceThresholdPx4G( |
| kLoadingDistanceThresholdPx); |
| settings.SetLazyLoadEnabled(true); |
| } |
| |
| void TearDown() override { |
| GetNetworkStateNotifier().SetSaveDataEnabledOverride(false); |
| SimTest::TearDown(); |
| } |
| |
| void TestCrossOriginFrameIsImmediatelyLoaded(const char* iframe_attributes) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' %s |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + kLoadingDistanceThresholdPx + 100, |
| iframe_attributes)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| child_frame_resource.Complete(""); |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| |
| void TestCrossOriginFrameIsLazilyLoaded(const char* iframe_attributes) { |
| SimRequest main_resource("https://example.com/", "text/html"); |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' |
| style='width: 200px; height: 200px;' %s |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + kLoadingDistanceThresholdPx + 100, |
| iframe_attributes)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // The body's load event should have already fired. |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| // Scroll down near the child frame to cause the child frame to start |
| // loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| |
| void TestLazyLoadUsedInPageReload(const char* iframe_attributes, |
| bool is_deferral_expected_on_reload) { |
| HistogramTester histogram_tester; |
| ConsoleMessages().clear(); |
| |
| SimRequest main_resource("https://example.com/", "text/html"); |
| MainFrame().StartReload(WebFrameLoadType::kReload); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe src='https://crossorigin.com/subframe.html' %s |
| style='width: 400px; height: 400px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| LazyLoadFramesTest::kViewportHeight + |
| LazyLoadFramesTest::kLoadingDistanceThresholdPx + 100, |
| iframe_attributes)); |
| |
| if (is_deferral_expected_on_reload) { |
| // The body's load event should have already fired. |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| child_frame_resource.Complete(""); |
| test::RunPendingTasks(); |
| |
| // Scroll down near the child frame to cause the child frame to start |
| // loading. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, LazyLoadFramesTest::kViewportHeight + |
| LazyLoadFramesTest::kLoadingDistanceThresholdPx), |
| mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| histogram_tester.ExpectTotalCount( |
| "Blink.VisibleLoadTime.LazyLoadEligibleFrames.BelowTheFold.4G", 1); |
| } else { |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| child_frame_resource.Complete(""); |
| } |
| test::RunPendingTasks(); |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| }; |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadFrameUnsetLoadingAttributeWithoutAutomatic) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(false); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| SimRequest main_resource("https://example.com/", "text/html"); |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe id='child_frame' src='https://crossorigin.com/subframe.html' |
| loading='lazy' style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + kLoadingDistanceThresholdPx + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // The body's load event should have already fired. |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| Element* child_frame_element = GetDocument().getElementById("child_frame"); |
| ASSERT_TRUE(child_frame_element); |
| child_frame_element->removeAttribute(html_names::kLoadingAttr); |
| |
| test::RunPendingTasks(); |
| |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadFrameUnsetLoadingAttributeWithAutomatic) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| SimRequest main_resource("https://example.com/", "text/html"); |
| LoadURL("https://example.com/"); |
| |
| main_resource.Complete(String::Format( |
| R"HTML( |
| <body onload='console.log("main body onload");'> |
| <div style='height: %dpx;'></div> |
| <iframe id='child_frame' src='https://crossorigin.com/subframe.html' |
| loading='lazy' style='width: 200px; height: 200px;' |
| onload='console.log("child frame element onload");'></iframe> |
| </body>)HTML", |
| kViewportHeight + kLoadingDistanceThresholdPx + 100)); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| // The body's load event should have already fired. |
| EXPECT_TRUE(ConsoleMessages().Contains("main body onload")); |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| Element* child_frame_element = GetDocument().getElementById("child_frame"); |
| ASSERT_TRUE(child_frame_element); |
| child_frame_element->removeAttribute(html_names::kLoadingAttr); |
| |
| test::RunPendingTasks(); |
| |
| EXPECT_FALSE(ConsoleMessages().Contains("child frame element onload")); |
| |
| SimRequest child_frame_resource("https://crossorigin.com/subframe.html", |
| "text/html"); |
| |
| // The iframe should still be deferred because automatic lazy loading is |
| // enabled. Scroll down until it is visible. |
| GetDocument().View()->LayoutViewport()->SetScrollOffset( |
| ScrollOffset(0, 150), mojom::blink::ScrollType::kProgrammatic); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| child_frame_resource.Complete(""); |
| |
| Compositor().BeginFrame(); |
| test::RunPendingTasks(); |
| |
| EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload")); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenDisabledAndAttrLazy) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(false); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(false); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsImmediatelyLoaded("loading='lazy'"); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAttrLazy) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(false); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsLazilyLoaded("loading='lazy'"); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAttrEager) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(false); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsImmediatelyLoaded("loading='eager'"); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAutomaticAndAttrLazy) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsLazilyLoaded("loading='lazy'"); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAutomaticAndAttrEager) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsImmediatelyLoaded("loading='eager'"); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAutomaticRestrictedAndAttrLazy) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| true); |
| |
| TestCrossOriginFrameIsLazilyLoaded("loading='lazy'"); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAutomaticRestrictedAndAttrEager) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| true); |
| |
| GetNetworkStateNotifier().SetSaveDataEnabledOverride(true); |
| TestCrossOriginFrameIsImmediatelyLoaded("loading='eager'"); |
| EXPECT_FALSE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeLazy)); |
| EXPECT_TRUE(GetDocument().IsUseCounted( |
| WebFeature::kLazyLoadFrameLoadingAttributeEager)); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAutomaticDisabled) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(false); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsImmediatelyLoaded(""); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenAutomaticEnabled) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| false); |
| |
| TestCrossOriginFrameIsLazilyLoaded(""); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenDataSaverDisabledAndRestricted) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| true); |
| |
| TestCrossOriginFrameIsImmediatelyLoaded(""); |
| } |
| |
| TEST_F(LazyLoadFramesTest, LazyLoadWhenDataSaverEnabledAndRestricted) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test_( |
| true); |
| |
| GetNetworkStateNotifier().SetSaveDataEnabledOverride(true); |
| TestCrossOriginFrameIsLazilyLoaded(""); |
| } |
| |
| // Frames with loading=lazy should be deferred irrespective of disable |
| // lazyload-on reload feature state. |
| TEST_F(LazyLoadFramesTest, NoAutoLazyLoadOnReload_DeferredForAttributeLazy) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test( |
| false); |
| ScopedAutoLazyLoadOnReloadsForTest scoped_auto_lazy_load_on_reloads_for_test( |
| false); |
| ScopedLazyFrameVisibleLoadTimeMetricsForTest |
| scoped_lazy_frame_visible_load_time_metrics_for_test(true); |
| |
| TestCrossOriginFrameIsLazilyLoaded("loading='lazy'"); |
| TestLazyLoadUsedInPageReload("loading='lazy'", true); |
| } |
| |
| // Frames with loading=lazy should be deferred irrespective of disable |
| // lazyload-on reload feature state. |
| TEST_F(LazyLoadFramesTest, AutoLazyLoadOnReload_DeferredForAttributeLazy) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test( |
| false); |
| ScopedAutoLazyLoadOnReloadsForTest scoped_auto_lazy_load_on_reloads_for_test( |
| true); |
| ScopedLazyFrameVisibleLoadTimeMetricsForTest |
| scoped_lazy_frame_visible_load_time_metrics_for_test(true); |
| |
| TestCrossOriginFrameIsLazilyLoaded("loading='lazy'"); |
| TestLazyLoadUsedInPageReload("loading='lazy'", true); |
| } |
| |
| TEST_F(LazyLoadFramesTest, NoAutoLazyLoadOnReload_NotDeferredForAttributeAuto) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test( |
| false); |
| ScopedAutoLazyLoadOnReloadsForTest scoped_auto_lazy_load_on_reloads_for_test( |
| false); |
| ScopedLazyFrameVisibleLoadTimeMetricsForTest |
| scoped_lazy_frame_visible_load_time_metrics_for_test(true); |
| |
| TestCrossOriginFrameIsLazilyLoaded(""); |
| TestLazyLoadUsedInPageReload("", false); |
| } |
| |
| TEST_F(LazyLoadFramesTest, AutoLazyLoadOnReload_DeferredForAttributeAuto) { |
| ScopedLazyFrameLoadingForTest scoped_lazy_frame_loading_for_test(true); |
| ScopedAutomaticLazyFrameLoadingForTest |
| scoped_automatic_lazy_frame_loading_for_test(true); |
| ScopedRestrictAutomaticLazyFrameLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_frame_loading_to_data_saver_for_test( |
| false); |
| ScopedAutoLazyLoadOnReloadsForTest scoped_auto_lazy_load_on_reloads_for_test( |
| true); |
| ScopedLazyFrameVisibleLoadTimeMetricsForTest |
| scoped_lazy_frame_visible_load_time_metrics_for_test(true); |
| |
| TestCrossOriginFrameIsLazilyLoaded(""); |
| TestLazyLoadUsedInPageReload("", true); |
| } |
| |
| } // namespace |
| |
| } // namespace blink |