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 @@
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.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_factory.h"
......@@ -26,6 +27,7 @@
#include "content/public/test/browser_test_base.h"
#include "content/public/test/browser_test_utils.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/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
......@@ -41,7 +43,14 @@ class LazyLoadBrowserTest : public InProcessBrowserTest {
void SetUp() override {
scoped_feature_list_.InitWithFeaturesAndParameters(
{{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();
}
......@@ -53,17 +62,49 @@ class LazyLoadBrowserTest : public InProcessBrowserTest {
base::RunLoop().RunUntilIdle();
}
void ScrollToAndWaitForScroll(unsigned int scroll_offset) {
ASSERT_TRUE(content::ExecuteScript(
browser()->tab_strip_model()->GetActiveWebContents(),
base::StringPrintf("window.scrollTo(0, %d);", scroll_offset)));
content::RenderFrameSubmissionObserver observer(
browser()->tab_strip_model()->GetActiveWebContents());
observer.WaitForScrollOffset(gfx::Vector2dF(0, scroll_offset));
content::EvalJsResult WaitForElementLoad(content::WebContents* contents,
const char* element_id) {
return content::EvalJs(contents, base::StringPrintf(R"JS(
new Promise((resolve, reject) => {
let e = document.getElementById('%s');
if (loaded_ids.includes(e.id)) {
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.
void SetUpLazyLoadFrameTestPage() {
base::ScopedAllowBlockingForTesting scoped_allow_blocking;
cross_origin_server_.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(cross_origin_server_.Start());
......@@ -76,37 +117,37 @@ class LazyLoadBrowserTest : public InProcessBrowserTest {
if (request.relative_url == "/mainpage.html") {
response->set_content(base::StringPrintf(
R"HTML(
<body onload="on_load('document')">
<body>
<script>
function on_load(msg) {
console.log("LAZY_LOAD CONSOLE", msg, "ON_LOAD FOR TEST");
}
let loaded_ids = new Array();
</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"
onload="on_load('in-viewport iframe')"></iframe>
<iframe src="http://bar.com:%d/simple.html?lazy"
onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe>
<iframe id="atf_lazy" src="http://bar.com:%d/simple.html?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 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"
onload="on_load('in-viewport loading=eager iframe')">
onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe>
<div style="height:11000px;"></div>
Below the viewport cross-origin iframe <br>
<iframe src="http://bar.com:%d/simple.html?auto&belowviewport"
Below the viewport cross-origin iframes <br>
<iframe id="btf_auto" src="http://bar.com:%d/simple.html?auto&belowviewport"
width="100" height="100"
onload="on_load('below-viewport iframe')"></iframe>
<iframe src="http://bar.com:%d/simple.html?lazy&belowviewport"
onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe>
<iframe id="btf_lazy" src="http://bar.com:%d/simple.html?lazy&belowviewport"
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 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"
onload="on_load('below-viewport loading=eager iframe')">
onload="loaded_ids.push(this.id); console.log(this.id);">
</iframe>
</body>)HTML",
cross_origin_port, cross_origin_port, cross_origin_port,
......@@ -164,88 +205,50 @@ IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest, CSSPseudoBackgroundImageLoaded) {
IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest,
LazyLoadImage_DeferredAndLoadedOnScroll) {
EnableDataSaver(true);
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url(embedded_test_server()->GetURL("/lazyload/img.html"));
auto* contents = browser()->OpenURL(content::OpenURLParams(
test_url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_TYPED, false));
content::ConsoleObserverDelegate console_observer(
contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
contents->SetDelegate(&console_observer);
ASSERT_TRUE(content::WaitForLoadStop(contents));
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();
}
const auto messages = console_observer.messages();
EXPECT_THAT(messages,
testing::Contains(
"LAZY_LOAD CONSOLE below-viewport img ON_LOAD FOR TEST"));
EXPECT_THAT(messages, testing::Contains("LAZY_LOAD CONSOLE below-viewport "
"loading=lazy img ON_LOAD FOR TEST"));
EXPECT_EQ(false, IsElementLoaded(contents, "btf_auto"));
EXPECT_EQ(false, IsElementLoaded(contents, "btf_lazy"));
EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_auto"));
EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_lazy"));
}
// Disabled due to flakiness (crbug.com/1035057)
IN_PROC_BROWSER_TEST_F(LazyLoadBrowserTest,
DISABLED_LazyLoadFrame_DeferredAndLoadedOnScroll) {
LazyLoadFrame_DeferredAndLoadedOnScroll) {
EnableDataSaver(true);
SetUpLazyLoadFrameTestPage();
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);
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();
}
const auto messages = console_observer.messages();
EXPECT_THAT(messages,
testing::Contains(
"LAZY_LOAD CONSOLE below-viewport iframe ON_LOAD FOR TEST"));
EXPECT_THAT(messages,
testing::Contains("LAZY_LOAD CONSOLE below-viewport "
"loading=lazy iframe ON_LOAD FOR TEST"));
EXPECT_EQ(false, IsElementLoaded(contents, "btf_auto"));
EXPECT_EQ(false, IsElementLoaded(contents, "btf_lazy"));
EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_auto"));
EXPECT_EQ(true, ScrollToAndWaitForElementLoad(contents, "btf_lazy"));
}
// Tests that need to verify lazyload should be disabled in certain cases.
......@@ -267,79 +270,51 @@ class LazyLoadDisabledBrowserTest : public LazyLoadBrowserTest {
void VerifyLazyLoadFrameBehavior(
content::WebContents* web_contents,
ExpectedLazyLoadAction expected_lazy_load_action) {
content::ConsoleObserverDelegate console_observer(
web_contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
web_contents->SetDelegate(&console_observer);
std::vector<std::string> expected_console_messages{
"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"};
EXPECT_TRUE(content::WaitForLoadStop(web_contents));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_auto"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_lazy"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_eager"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "btf_eager"));
base::RunLoop().RunUntilIdle();
switch (expected_lazy_load_action) {
case ExpectedLazyLoadAction::kOff:
expected_console_messages.push_back(
"LAZY_LOAD CONSOLE below-viewport loading=lazy iframe ON_LOAD FOR "
"TEST");
ABSL_FALLTHROUGH_INTENDED;
EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_lazy"));
break;
case ExpectedLazyLoadAction::kExplicitOnly:
expected_console_messages.push_back(
"LAZY_LOAD CONSOLE below-viewport iframe ON_LOAD FOR TEST");
EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
EXPECT_EQ(false, IsElementLoaded(web_contents, "btf_lazy"));
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(
content::WebContents* web_contents,
ExpectedLazyLoadAction expected_lazy_load_action) {
content::ConsoleObserverDelegate console_observer(
web_contents, "LAZY_LOAD CONSOLE * ON_LOAD FOR TEST");
web_contents->SetDelegate(&console_observer);
std::vector<std::string> expected_console_messages{
"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"};
ASSERT_TRUE(content::WaitForLoadStop(web_contents));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_auto"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_lazy"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "atf_eager"));
EXPECT_EQ(true, WaitForElementLoad(web_contents, "btf_eager"));
base::RunLoop().RunUntilIdle();
switch (expected_lazy_load_action) {
case ExpectedLazyLoadAction::kOff:
expected_console_messages.push_back(
"LAZY_LOAD CONSOLE below-viewport loading=lazy img ON_LOAD FOR "
"TEST");
ABSL_FALLTHROUGH_INTENDED;
case ExpectedLazyLoadAction::kExplicitOnly:
expected_console_messages.push_back(
"LAZY_LOAD CONSOLE below-viewport img ON_LOAD FOR TEST");
EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_lazy"));
break;
}
EXPECT_THAT(console_observer.messages(), testing::UnorderedElementsAre());
// Wait for the expected elements and the document to load.
while (console_observer.messages().size() <
expected_console_messages.size()) {
base::RunLoop().RunUntilIdle();
case ExpectedLazyLoadAction::kExplicitOnly:
EXPECT_EQ(true, IsElementLoaded(web_contents, "btf_auto"));
EXPECT_EQ(false, IsElementLoaded(web_contents, "btf_lazy"));
break;
}
console_observer.Wait();
EXPECT_THAT(console_observer.messages(),
testing::UnorderedElementsAreArray(expected_console_messages));
}
};
......
<!DOCTYPE html>
<html>
<body onload="on_load('document')">
<body>
<script>
function on_load(msg) {
console.log("LAZY_LOAD CONSOLE", msg, "ON_LOAD FOR TEST");
}
loaded_ids = new Array();
</script>
In the viewport image <br>
<img src="images/fruit1.jpg?auto"
onload="on_load('in-viewport img')">
<img src="images/fruit1.jpg?lazy" loading="lazy"
onload="on_load('in-viewport loading=lazy img')">
<img src="images/fruit1.jpg?eager" loading="eager"
onload="on_load('in-viewport loading=eager img')">
In the viewport images <br>
<img id="atf_auto" src="images/fruit1.jpg?auto"
onload="loaded_ids.push(this.id); console.log(this.id);">
<img id="atf_lazy" src="images/fruit1.jpg?lazy" loading="lazy"
onload="loaded_ids.push(this.id); console.log(this.id);">
<img id="atf_eager" src="images/fruit1.jpg?eager" loading="eager"
onload="loaded_ids.push(this.id); console.log(this.id);">
<div style="height:11000px;"></div>
Below the viewport images <br>
<img src="images/fruit2.jpg?auto"
onload="on_load('below-viewport img')">
<img src="images/fruit2.jpg?lazy" loading="lazy"
onload="on_load('below-viewport loading=lazy img')">
<img src="images/fruit2.jpg?eager" loading="eager"
onload="on_load('below-viewport loading=eager img')">
<img id="btf_auto" src="images/fruit2.jpg?auto"
onload="loaded_ids.push(this.id); console.log(this.id);">
<img id="btf_lazy" src="images/fruit2.jpg?lazy" loading="lazy"
onload="loaded_ids.push(this.id); console.log(this.id);">
<img id="btf_eager" src="images/fruit2.jpg?eager" loading="eager"
onload="loaded_ids.push(this.id); console.log(this.id);">
</body>
</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