Third reland of Add LayoutInstabilityTest.OOPIFSubframeWeighting.
Refactor test to focus on subframe; print window width/height. Bug: 943668 Change-Id: I28f9c66350f709fa792b242334d117255c36dc1e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2227184 Reviewed-by: Steve Kobes <skobes@chromium.org> Commit-Queue: Annie Sullivan <sullivan@chromium.org> Cr-Commit-Position: refs/heads/master@{#774591}
This commit is contained in:

committed by
Commit Bot

parent
c0ea25a2f9
commit
e1f9cdbe64
chrome/browser/page_load_metrics/integration_tests
@ -1,4 +1,5 @@
|
||||
<script src="resources/testharness.js"></script>
|
||||
<script src="/script/async_buffer.js"></script>
|
||||
<script>
|
||||
// Tell testharness.js to not wait for 'real' tests; we only want
|
||||
// testharness.js for its assertion helpers.
|
||||
@ -6,52 +7,6 @@ setup({'output': false});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// 'AsyncBuffer' serves as a helper to buffer LCP reports asynchronously.
|
||||
class AsyncBuffer {
|
||||
constructor() {
|
||||
// 'pending' is an array that will buffer entries reported through the
|
||||
// PerformanceObserver and can be collected with 'pop'.
|
||||
this.pending = [];
|
||||
|
||||
// 'resolve_fn' is a reference to the 'resolve' function of a
|
||||
// Promise that blocks for new entries to arrive via 'push()'. Calling
|
||||
// the function resolves the promise and unblocks calls to 'pop()'.
|
||||
this.resolve_fn = null;
|
||||
}
|
||||
|
||||
// Concatenates the given 'entries' list to this AsyncBuffer.
|
||||
push(entries) {
|
||||
if (entries.length == 0) {
|
||||
throw new Error("Must not push an empty list of entries!");
|
||||
}
|
||||
this.pending = this.pending.concat(entries);
|
||||
|
||||
// If there are calls to 'pop' that are blocked waiting for items, signal
|
||||
// that they can continue.
|
||||
if (this.resolve_fn != null) {
|
||||
this.resolve_fn();
|
||||
this.resolve_fn = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes the current pending entries from this AsyncBuffer. If there are no
|
||||
// entries queued already, this will block until some show up.
|
||||
async pop() {
|
||||
if (this.pending.length == 0) {
|
||||
// Need to instantiate a promise to block on. The next call to 'push'
|
||||
// will resolve the promise once it has queued the entries.
|
||||
await new Promise(resolve => {
|
||||
this.resolve_fn = resolve;
|
||||
});
|
||||
}
|
||||
assert_true(this.pending.length > 0);
|
||||
|
||||
const result = this.pending;
|
||||
this.pending = [];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const buffer = new AsyncBuffer();
|
||||
const po = new PerformanceObserver(entryList => {
|
||||
buffer.push(entryList.getEntries());
|
||||
|
32
chrome/browser/page_load_metrics/integration_tests/data/layout-instability/main_frame.html
Normal file
32
chrome/browser/page_load_metrics/integration_tests/data/layout-instability/main_frame.html
Normal file
@ -0,0 +1,32 @@
|
||||
<script>
|
||||
// This debugging statement is to help catch issues with tests failing due
|
||||
// to window sizes on different bots being different.
|
||||
console.log('Main Frame widthxheight = ', window.innerWidth, 'x', window.innerHeight);
|
||||
|
||||
function resolveAfterIframeLoad(iframe) {
|
||||
return new Promise(resolve => {
|
||||
iframe.addEventListener('load', function() {
|
||||
return resolve(true);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const wait_for_iframe_load = async () => {
|
||||
let iframe = document.getElementById('i');
|
||||
if (iframe.contentWindow.document.readyState == 'complete') {
|
||||
return true;
|
||||
}
|
||||
await resolveAfterIframeLoad(iframe);
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#i {
|
||||
border: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: pink;
|
||||
}
|
||||
</style>
|
||||
<iframe id="i" width="400" height="300" src="sub_frame.html"></iframe>
|
49
chrome/browser/page_load_metrics/integration_tests/data/layout-instability/sub_frame.html
Normal file
49
chrome/browser/page_load_metrics/integration_tests/data/layout-instability/sub_frame.html
Normal file
@ -0,0 +1,49 @@
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/script/async_buffer.js"></script>
|
||||
|
||||
<script>
|
||||
var buffer = new AsyncBuffer();
|
||||
const po = new PerformanceObserver(entryList => {
|
||||
buffer.push(entryList.getEntries());
|
||||
});
|
||||
po.observe({type: 'layout-shift', buffered: true});
|
||||
|
||||
const block_for_next_cls = async () => {
|
||||
return buffer.pop().then(seen_events => {
|
||||
// This test case assumes each CLS entry is handled before the next could
|
||||
// possibly be generated.
|
||||
return seen_events[0].value;
|
||||
});
|
||||
};
|
||||
|
||||
const run_test = async () => {
|
||||
shiftFrame();
|
||||
const cls_0 = await block_for_next_cls();
|
||||
unshiftFrame();
|
||||
const cls_1 = await block_for_next_cls();
|
||||
|
||||
// Now that we've run through the scenario and collected our measurements,
|
||||
// return them in a structure that the C++ side can easily query.
|
||||
let output = [
|
||||
{'score': cls_0},
|
||||
{'score': cls_1}
|
||||
];
|
||||
return output;
|
||||
};
|
||||
|
||||
function shiftFrame() {
|
||||
document.getElementById('j').style.top = '60px';
|
||||
}
|
||||
function unshiftFrame() {
|
||||
document.getElementById('j').style.top = '';
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
#j {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
background-color: purple;
|
||||
}
|
||||
</style>
|
||||
<div id="j"></div>
|
@ -0,0 +1,50 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
// 'AsyncBuffer' serves as a helper to buffer PerformanceObserver reports
|
||||
// asynchronously.
|
||||
class AsyncBuffer {
|
||||
constructor() {
|
||||
// 'pending' is an array that will buffer entries reported through the
|
||||
// PerformanceObserver and can be collected with 'pop'.
|
||||
this.pending = [];
|
||||
|
||||
// 'resolve_fn' is a reference to the 'resolve' function of a
|
||||
// Promise that blocks for new entries to arrive via 'push()'. Calling
|
||||
// the function resolves the promise and unblocks calls to 'pop()'.
|
||||
this.resolve_fn = null;
|
||||
}
|
||||
|
||||
// Concatenates the given 'entries' list to this AsyncBuffer.
|
||||
push(entries) {
|
||||
if (entries.length == 0) {
|
||||
throw new Error("Must not push an empty list of entries!");
|
||||
}
|
||||
this.pending = this.pending.concat(entries);
|
||||
|
||||
// If there are calls to 'pop' that are blocked waiting for items, signal
|
||||
// that they can continue.
|
||||
if (this.resolve_fn != null) {
|
||||
this.resolve_fn();
|
||||
this.resolve_fn = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes the current pending entries from this AsyncBuffer. If there are no
|
||||
// entries queued already, this will block until some show up.
|
||||
async pop() {
|
||||
if (this.pending.length == 0) {
|
||||
// Need to instantiate a promise to block on. The next call to 'push'
|
||||
// will resolve the promise once it has queued the entries.
|
||||
await new Promise(resolve => {
|
||||
this.resolve_fn = resolve;
|
||||
});
|
||||
}
|
||||
assert_true(this.pending.length > 0);
|
||||
|
||||
const result = this.pending;
|
||||
this.pending = [];
|
||||
return result;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include "chrome/browser/page_load_metrics/integration_tests/metric_integration_test.h"
|
||||
|
||||
#include "base/test/trace_event_analyzer.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "services/metrics/public/cpp/ukm_builders.h"
|
||||
@ -135,3 +136,59 @@ IN_PROC_BROWSER_TEST_F(LayoutInstabilityTest, Sources_Enclosure) {
|
||||
IN_PROC_BROWSER_TEST_F(LayoutInstabilityTest, Sources_MaxImpact) {
|
||||
RunWPT("sources-maximpact.html", true);
|
||||
}
|
||||
|
||||
// Fails on Windows 7 only.
|
||||
#if defined(OS_WIN)
|
||||
#define MAYBE_OOPIFSubframeWeighting DISABLED_OOPIFSubframeWeighting
|
||||
#else
|
||||
#define MAYBE_OOPIFSubframeWeighting OOPIFSubframeWeighting
|
||||
#endif
|
||||
IN_PROC_BROWSER_TEST_F(LayoutInstabilityTest, MAYBE_OOPIFSubframeWeighting) {
|
||||
Start();
|
||||
StartTracing({"loading"});
|
||||
Load("/layout-instability/main_frame.html");
|
||||
|
||||
content::EvalJsResult load_result =
|
||||
EvalJs(web_contents()->GetAllFrames()[0], "wait_for_iframe_load()");
|
||||
EXPECT_EQ("", load_result.error);
|
||||
content::EvalJsResult result =
|
||||
EvalJs(web_contents()->GetAllFrames()[1], "run_test()");
|
||||
EXPECT_EQ("", result.error);
|
||||
|
||||
// Verify that the JS API yielded two CLS reports for the subframe.
|
||||
const auto& list = result.value.GetList();
|
||||
EXPECT_EQ(2ul, list.size());
|
||||
base::Optional<double> cls_first_value = list[0].FindDoublePath("score");
|
||||
EXPECT_EQ(0.4 * (60.0 / 400.0), cls_first_value)
|
||||
<< "The first shift value should be 300 * (100 + 60) * (60 / 400) / "
|
||||
"(default viewport size 800 * 600)";
|
||||
base::Optional<double> cls_second_value = list[1].FindDoublePath("score");
|
||||
EXPECT_EQ(0.4 * (60.0 / 400.0), cls_second_value)
|
||||
<< "The second shift value should be 300 * (100 + 60) * (60 / 400) / "
|
||||
"(default viewport size 800 * 600)";
|
||||
|
||||
// Need to navigate away from the test html page to force metrics to get
|
||||
// flushed/synced.
|
||||
ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
|
||||
|
||||
// Check Trace Events.
|
||||
std::unique_ptr<TraceAnalyzer> analyzer = StopTracingAndAnalyze();
|
||||
TraceEventVector events;
|
||||
analyzer->FindEvents(Query::EventNameIs("LayoutShift"), &events);
|
||||
EXPECT_EQ(2ul, events.size());
|
||||
std::unique_ptr<Value> data;
|
||||
events[0]->GetArgAsValue("data", &data);
|
||||
EXPECT_EQ(0.4 * (60.0 / 400.0), *data->FindDoubleKey("score"));
|
||||
events[1]->GetArgAsValue("data", &data);
|
||||
EXPECT_EQ(0.4 * (60.0 / 400.0), *data->FindDoubleKey("score"));
|
||||
|
||||
// Check UKM.
|
||||
ExpectUKMPageLoadMetricNear(
|
||||
PageLoad::kLayoutInstability_CumulativeShiftScoreName,
|
||||
LayoutShiftUkmValue(0.03), 1);
|
||||
|
||||
// Check UMA.
|
||||
ExpectUniqueUMAPageLoadMetricNear(
|
||||
"PageLoad.LayoutInstability.CumulativeShiftScore",
|
||||
LayoutShiftUmaValue(0.03));
|
||||
}
|
||||
|
Reference in New Issue
Block a user