Commit c326228d authored by Scott Little's avatar Scott Little Committed by Commit Bot

Rewrite LazyLoad BrowserTests to reduce flakiness.

Previously, these tests would occasionally flake while waiting for the
scroll offset to update. This CL rewrites these tests to remove this
dependency on RenderFrameSubmissionObserver::WaitForScrollOffset.

This CL also changes these tests to use JavaScript promises to
communicate with the page instead of polling the console output in order
to improve readability of the tests.

Fixed: 1035057
Change-Id: I845d0f821bdc4ee604a9432a90f5e4a100187c97
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2166633
Commit-Queue: Scott Little <sclittle@chromium.org>
Reviewed-by: default avatarrajendrant <rajendrant@chromium.org>
Cr-Commit-Position: refs/heads/master@{#762789}
parent 52f3b67e
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h" #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h" #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
#include "content/public/test/browser_test_base.h" #include "content/public/test/browser_test_base.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "net/dns/mock_host_resolver.h" #include "net/dns/mock_host_resolver.h"
#include "net/nqe/effective_connection_type.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h" #include "net/test/embedded_test_server/http_response.h"
...@@ -41,7 +43,14 @@ class LazyLoadBrowserTest : public InProcessBrowserTest { ...@@ -41,7 +43,14 @@ class LazyLoadBrowserTest : public InProcessBrowserTest {
void SetUp() override { void SetUp() override {
scoped_feature_list_.InitWithFeaturesAndParameters( scoped_feature_list_.InitWithFeaturesAndParameters(
{{features::kLazyImageLoading, {{features::kLazyImageLoading,
{{"lazy_image_first_k_fully_load", "4G:0"}}}}, {{"lazy_image_first_k_fully_load",
base::StringPrintf("%s:0,%s:0,%s:0,%s:0,%s:0,%s:0",
net::kEffectiveConnectionTypeUnknown,
net::kEffectiveConnectionTypeOffline,
net::kEffectiveConnectionTypeSlow2G,
net::kEffectiveConnectionType2G,
net::kEffectiveConnectionType3G,
net::kEffectiveConnectionType4G)}}}},
{}); {});
InProcessBrowserTest::SetUp(); InProcessBrowserTest::SetUp();
} }
...@@ -53,17 +62,49 @@ class LazyLoadBrowserTest : public InProcessBrowserTest { ...@@ -53,17 +62,49 @@ class LazyLoadBrowserTest : public InProcessBrowserTest {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
void ScrollToAndWaitForScroll(unsigned int scroll_offset) { content::EvalJsResult WaitForElementLoad(content::WebContents* contents,
ASSERT_TRUE(content::ExecuteScript( const char* element_id) {
browser()->tab_strip_model()->GetActiveWebContents(), return content::EvalJs(contents, base::StringPrintf(R"JS(
base::StringPrintf("window.scrollTo(0, %d);", scroll_offset))); new Promise((resolve, reject) => {
content::RenderFrameSubmissionObserver observer( let e = document.getElementById('%s');
browser()->tab_strip_model()->GetActiveWebContents()); if (loaded_ids.includes(e.id)) {
observer.WaitForScrollOffset(gfx::Vector2dF(0, scroll_offset)); resolve(true);
} else {
e.addEventListener('load', function() {
resolve(true);
});
}
});)JS",
element_id));
}
content::EvalJsResult ScrollToAndWaitForElementLoad(
content::WebContents* contents,
const char* element_id) {
return content::EvalJs(contents, base::StringPrintf(R"JS(
new Promise((resolve, reject) => {
let e = document.getElementById('%s');
e.scrollIntoView();
if (loaded_ids.includes(e.id)) {
resolve(true);
} else {
e.addEventListener('load', function() {
resolve(true);
});
}
});)JS",
element_id));
}
content::EvalJsResult IsElementLoaded(content::WebContents* contents,
const char* element_id) {
return content::EvalJs(
contents, base::StringPrintf("loaded_ids.includes('%s');", element_id));
} }
// Sets up test pages with in-viewport and below-viewport cross-origin frames. // Sets up test pages with in-viewport and below-viewport cross-origin frames.
void SetUpLazyLoadFrameTestPage() { void SetUpLazyLoadFrameTestPage() {
base::ScopedAllowBlockingForTesting scoped_allow_blocking;
cross_origin_server_.ServeFilesFromSourceDirectory(GetChromeTestDataDir()); cross_origin_server_.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(cross_origin_server_.Start()); ASSERT_TRUE(cross_origin_server_.Start());
...@@ -76,37 +117,37 @@ class LazyLoadBrowserTest : public InProcessBrowserTest { ...@@ -76,37 +117,37 @@ class LazyLoadBrowserTest : public InProcessBrowserTest {
if (request.relative_url == "/mainpage.html") { if (request.relative_url == "/mainpage.html") {
response->set_content(base::StringPrintf( response->set_content(base::StringPrintf(
R"HTML( R"HTML(
<body onload="on_load('document')"> <body>
<script> <script>
function on_load(msg) { let loaded_ids = new Array();
console.log("LAZY_LOAD CONSOLE", msg, "ON_LOAD FOR TEST");
}
</script> </script>
<iframe src="http://bar.com:%d/simple.html?auto" <iframe id="atf_auto" src="http://bar.com:%d/simple.html?auto"
width="100" height="100" width="100" height="100"
onload="on_load('in-viewport iframe')"></iframe> onload="loaded_ids.push(this.id); console.log(this.id);">
<iframe src="http://bar.com:%d/simple.html?lazy" </iframe>
<iframe id="atf_lazy" src="http://bar.com:%d/simple.html?lazy"
width="100" height="100" loading="lazy" width="100" height="100" loading="lazy"
onload="on_load('in-viewport loading=lazy iframe')"> onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe> </iframe>
<iframe src="http://bar.com:%d/simple.html?eager" <iframe id="atf_eager" src="http://bar.com:%d/simple.html?eager"
width="100" height="100" loading="eager" width="100" height="100" loading="eager"
onload="on_load('in-viewport loading=eager iframe')"> onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe> </iframe>
<div style="height:11000px;"></div> <div style="height:11000px;"></div>
Below the viewport cross-origin iframe <br> Below the viewport cross-origin iframes <br>
<iframe src="http://bar.com:%d/simple.html?auto&belowviewport" <iframe id="btf_auto" src="http://bar.com:%d/simple.html?auto&belowviewport"
width="100" height="100" width="100" height="100"
onload="on_load('below-viewport iframe')"></iframe> onload="loaded_ids.push(this.id); console.log(this.id);">
<iframe src="http://bar.com:%d/simple.html?lazy&belowviewport" </iframe>
<iframe id="btf_lazy" src="http://bar.com:%d/simple.html?lazy&belowviewport"
width="100" height="100" loading="lazy" width="100" height="100" loading="lazy"
onload="on_load('below-viewport loading=lazy iframe')"> onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe> </iframe>
<iframe src="http://bar.com:%d/simple.html?eager&belowviewport" <iframe id="btf_eager" src="http://bar.com:%d/simple.html?eager&belowviewport"
width="100" height="100" loading="eager" width="100" height="100" loading="eager"
onload="on_load('below-viewport loading=eager iframe')"> onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe> </iframe>
</body>)HTML", </body>)HTML",
cross_origin_port, cross_origin_port, cross_origin_port, cross_origin_port, cross_origin_port, cross_origin_port,
...@@ -164,88 +205,50 @@ IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest, CSSPseudoBackgroundImageLoaded) { ...@@ -164,88 +205,50 @@ IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest, CSSPseudoBackgroundImageLoaded) {
IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest, IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest,
LazyLoadImage_DeferredAndLoadedOnScroll) { LazyLoadImage_DeferredAndLoadedOnScroll) {
EnableDataSaver(true); EnableDataSaver(true);
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url(embedded_test_server()->GetURL("/lazyload/img.html")); GURL test_url(embedded_test_server()->GetURL("/lazyload/img.html"));
auto* contents = browser()->OpenURL(content::OpenURLParams( auto* contents = browser()->OpenURL(content::OpenURLParams(
test_url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB, test_url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_TYPED, false)); ui::PAGE_TRANSITION_TYPED, false));
content::ConsoleObserverDelegate console_observer( ASSERT_TRUE(content::WaitForLoadStop(contents));
contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
contents->SetDelegate(&console_observer); EXPECT_EQ(true, WaitForElementLoad(contents, "atf_auto"));
EXPECT_EQ(true, WaitForElementLoad(contents, "atf_lazy"));
EXPECT_EQ(true, WaitForElementLoad(contents, "atf_eager"));
EXPECT_EQ(true, WaitForElementLoad(contents, "btf_eager"));
// Wait for the four images (3 in-viewport, 1 eager below-viewport) and the
// document to load.
while (console_observer.messages().size() < 5) {
base::RunLoop().RunUntilIdle();
}
console_observer.Wait();
EXPECT_THAT(
console_observer.messages(),
testing::UnorderedElementsAre(
"LAZY_LOAD CONSOLE document ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport img ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport loading=lazy img ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport loading=eager img ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE below-viewport loading=eager img ON_LOAD FOR "
"TEST"));
// Scroll down and verify the below-viewport images load.
ScrollToAndWaitForScroll(10000);
while (console_observer.messages().size() < 7) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
}
const auto messages = console_observer.messages(); EXPECT_EQ(false, IsElementLoaded(contents, "btf_auto"));
EXPECT_THAT(messages, EXPECT_EQ(false, IsElementLoaded(contents, "btf_lazy"));
testing::Contains(
"LAZY_LOAD CONSOLE below-viewport img ON_LOAD FOR TEST")); EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_auto"));
EXPECT_THAT(messages, testing::Contains("LAZY_LOAD CONSOLE below-viewport " EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_lazy"));
"loading=lazy img ON_LOAD FOR TEST"));
} }
// Disabled due to flakiness (crbug.com/1035057)
IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest, IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest,
DISABLED_LazyLoadFrame_DeferredAndLoadedOnScroll) { LazyLoadFrame_DeferredAndLoadedOnScroll) {
EnableDataSaver(true); EnableDataSaver(true);
SetUpLazyLoadFrameTestPage(); SetUpLazyLoadFrameTestPage();
GURL test_url(embedded_test_server()->GetURL("/mainpage.html")); GURL test_url(embedded_test_server()->GetURL("/mainpage.html"));
auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
content::ConsoleObserverDelegate console_observer(
contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
contents->SetDelegate(&console_observer);
ui_test_utils::NavigateToURL(browser(), test_url); ui_test_utils::NavigateToURL(browser(), test_url);
auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_EQ(true, WaitForElementLoad(contents, "atf_auto"));
EXPECT_EQ(true, WaitForElementLoad(contents, "atf_lazy"));
EXPECT_EQ(true, WaitForElementLoad(contents, "atf_eager"));
EXPECT_EQ(true, WaitForElementLoad(contents, "btf_eager"));
// Wait for the four iframes (3 in-viewport, 1 eager below-viewport) and the
// document to load.
while (console_observer.messages().size() < 5) {
base::RunLoop().RunUntilIdle();
}
console_observer.Wait();
EXPECT_THAT(
console_observer.messages(),
testing::UnorderedElementsAre(
"LAZY_LOAD CONSOLE document ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport iframe ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport loading=lazy iframe ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport loading=eager iframe ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE below-viewport loading=eager iframe ON_LOAD FOR "
"TEST"));
// Scroll down and verify the below-viewport iframes load.
ScrollToAndWaitForScroll(10000);
while (console_observer.messages().size() < 7) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
}
const auto messages = console_observer.messages(); EXPECT_EQ(false, IsElementLoaded(contents, "btf_auto"));
EXPECT_THAT(messages, EXPECT_EQ(false, IsElementLoaded(contents, "btf_lazy"));
testing::Contains(
"LAZY_LOAD CONSOLE below-viewport iframe ON_LOAD FOR TEST")); EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_auto"));
EXPECT_THAT(messages, EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_lazy"));
testing::Contains("LAZY_LOAD CONSOLE below-viewport "
"loading=lazy iframe ON_LOAD FOR TEST"));
} }
// Tests that need to verify lazyload should be disabled in certain cases. // Tests that need to verify lazyload should be disabled in certain cases.
...@@ -267,79 +270,51 @@ class LazyLoadDisabledBrowserTest : public LazyLoadBrowserTest { ...@@ -267,79 +270,51 @@ class LazyLoadDisabledBrowserTest : public LazyLoadBrowserTest {
void VerifyLazyLoadFrameBehavior( void VerifyLazyLoadFrameBehavior(
content::WebContents* web_contents, content::WebContents* web_contents,
ExpectedLazyLoadAction expected_lazy_load_action) { ExpectedLazyLoadAction expected_lazy_load_action) {
content::ConsoleObserverDelegate console_observer( EXPECT_TRUE(content::WaitForLoadStop(web_contents));
web_contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
web_contents->SetDelegate(&console_observer); EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_auto"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_lazy"));
std::vector<std::string> expected_console_messages{ EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_eager"));
"LAZY_LOAD CONSOLE document ON_LOAD FOR TEST", EXPECT_EQ(true, WaitForElementLoad(web_contents, "btf_eager"));
"LAZY_LOAD CONSOLE in-viewport iframe ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport loading=lazy iframe ON_LOAD FOR " base::RunLoop().RunUntilIdle();
"TEST",
"LAZY_LOAD CONSOLE in-viewport loading=eager iframe ON_LOAD FOR "
"TEST",
"LAZY_LOAD CONSOLE below-viewport loading=eager iframe ON_LOAD FOR "
"TEST"};
switch (expected_lazy_load_action) { switch (expected_lazy_load_action) {
case ExpectedLazyLoadAction::kOff: case ExpectedLazyLoadAction::kOff:
expected_console_messages.push_back( EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
"LAZY_LOAD CONSOLE below-viewport loading=lazy iframe ON_LOAD FOR " EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_lazy"));
"TEST"); break;
ABSL_FALLTHROUGH_INTENDED;
case ExpectedLazyLoadAction::kExplicitOnly: case ExpectedLazyLoadAction::kExplicitOnly:
expected_console_messages.push_back( EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
"LAZY_LOAD CONSOLE below-viewport iframe ON_LOAD FOR TEST"); EXPECT_EQ(false, IsElementLoaded(web_contents, "btf_lazy"));
break; break;
} }
// Wait for the expected elements and the document to load.
while (console_observer.messages().size() <
expected_console_messages.size()) {
base::RunLoop().RunUntilIdle();
}
console_observer.Wait();
EXPECT_THAT(console_observer.messages(),
testing::UnorderedElementsAreArray(expected_console_messages));
} }
void VerifyLazyLoadImageBehavior( void VerifyLazyLoadImageBehavior(
content::WebContents* web_contents, content::WebContents* web_contents,
ExpectedLazyLoadAction expected_lazy_load_action) { ExpectedLazyLoadAction expected_lazy_load_action) {
content::ConsoleObserverDelegate console_observer( ASSERT_TRUE(content::WaitForLoadStop(web_contents));
web_contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
web_contents->SetDelegate(&console_observer); EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_auto"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_lazy"));
std::vector<std::string> expected_console_messages{ EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_eager"));
"LAZY_LOAD CONSOLE document ON_LOAD FOR TEST", EXPECT_EQ(true, WaitForElementLoad(web_contents, "btf_eager"));
"LAZY_LOAD CONSOLE in-viewport img ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE in-viewport loading=lazy img ON_LOAD FOR TEST", base::RunLoop().RunUntilIdle();
"LAZY_LOAD CONSOLE in-viewport loading=eager img ON_LOAD FOR TEST",
"LAZY_LOAD CONSOLE below-viewport loading=eager img ON_LOAD FOR "
"TEST"};
switch (expected_lazy_load_action) { switch (expected_lazy_load_action) {
case ExpectedLazyLoadAction::kOff: case ExpectedLazyLoadAction::kOff:
expected_console_messages.push_back( EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
"LAZY_LOAD CONSOLE below-viewport loading=lazy img ON_LOAD FOR " EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_lazy"));
"TEST");
ABSL_FALLTHROUGH_INTENDED;
case ExpectedLazyLoadAction::kExplicitOnly:
expected_console_messages.push_back(
"LAZY_LOAD CONSOLE below-viewport img ON_LOAD FOR TEST");
break; break;
}
EXPECT_THAT(console_observer.messages(), testing::UnorderedElementsAre());
// Wait for the expected elements and the document to load. case ExpectedLazyLoadAction::kExplicitOnly:
while (console_observer.messages().size() < EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
expected_console_messages.size()) { EXPECT_EQ(false, IsElementLoaded(web_contents, "btf_lazy"));
base::RunLoop().RunUntilIdle(); break;
} }
console_observer.Wait();
EXPECT_THAT(console_observer.messages(),
testing::UnorderedElementsAreArray(expected_console_messages));
} }
}; };
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<body onload="on_load('document')"> <body>
<script> <script>
function on_load(msg) { loaded_ids = new Array();
console.log("LAZY_LOAD CONSOLE", msg, "ON_LOAD FOR TEST");
}
</script> </script>
In the viewport image <br> In the viewport images <br>
<img src="images/fruit1.jpg?auto" <img id="atf_auto" src="images/fruit1.jpg?auto"
onload="on_load('in-viewport img')"> onload="loaded_ids.push(this.id); console.log(this.id);">
<img src="images/fruit1.jpg?lazy" loading="lazy" <img id="atf_lazy" src="images/fruit1.jpg?lazy" loading="lazy"
onload="on_load('in-viewport loading=lazy img')"> onload="loaded_ids.push(this.id); console.log(this.id);">
<img src="images/fruit1.jpg?eager" loading="eager" <img id="atf_eager" src="images/fruit1.jpg?eager" loading="eager"
onload="on_load('in-viewport loading=eager img')"> onload="loaded_ids.push(this.id); console.log(this.id);">
<div style="height:11000px;"></div> <div style="height:11000px;"></div>
Below the viewport images <br> Below the viewport images <br>
<img src="images/fruit2.jpg?auto" <img id="btf_auto" src="images/fruit2.jpg?auto"
onload="on_load('below-viewport img')"> onload="loaded_ids.push(this.id); console.log(this.id);">
<img src="images/fruit2.jpg?lazy" loading="lazy" <img id="btf_lazy" src="images/fruit2.jpg?lazy" loading="lazy"
onload="on_load('below-viewport loading=lazy img')"> onload="loaded_ids.push(this.id); console.log(this.id);">
<img src="images/fruit2.jpg?eager" loading="eager" <img id="btf_eager" src="images/fruit2.jpg?eager" loading="eager"
onload="on_load('below-viewport loading=eager img')"> onload="loaded_ids.push(this.id); console.log(this.id);">
</body> </body>
</html> </html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment