Commit fcb2adf4 authored by Yao Xiao's avatar Yao Xiao Committed by Commit Bot

Mark the element on viewport resize disqualified to become overlay-popup-ad

- If there is a small overlay in the page (e.g. sticky ad on the side),
and the user shrinks the viewport to make the overlay centered &
relatively large, we don't want to consider it to be a "popup".
- Changed all relevant tests to promise_test for better readability.
- Removed most waitings in web_tests by disabling the frequency capping.
- A bugfix: It was a no-op to compare last_detection_main_frame_size_
and main_frame_size after setting them equal. This patch moves the
setting after the comparison.
- An improvement/fix: for the current overlay candidate, always check
element->IsAdRelated() in each detection, and update its ad status if it
becomes an ad.

Bug: 1032681
Change-Id: If1d945be69d51289cf3314b5700e265772f0087e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2291211Reviewed-by: default avatarStefan Zager <szager@chromium.org>
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790113}
parent ffaa6833
......@@ -18,6 +18,8 @@ namespace blink {
namespace {
static bool g_frequency_capping_enabled = true;
constexpr base::TimeDelta kFireInterval = base::TimeDelta::FromSeconds(1);
constexpr double kLargeAdSizeToViewportSizeThreshold = 0.1;
......@@ -73,7 +75,8 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
}
base::Time current_time = base::Time::Now();
if (started_detection_ && current_time < last_detection_time_ + kFireInterval)
if (started_detection_ && g_frequency_capping_enabled &&
current_time < last_detection_time_ + kFireInterval)
return;
TRACE_EVENT0("blink,benchmark",
......@@ -83,7 +86,6 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
last_detection_time_ = current_time;
IntSize main_frame_size = main_frame->GetMainFrameViewportSize();
last_detection_main_frame_size_ = main_frame_size;
if (main_frame_size != last_detection_main_frame_size_) {
// Reset the candidate when the the viewport size has changed. Changing
......@@ -92,6 +94,14 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
// could have happened is that the element no longer covers the center,
// but still exists (e.g. a sticky ad at the top).
candidate_id_ = kInvalidDOMNodeId;
// Reset |content_has_been_stable_| to so that the current hit-test element
// will be marked unqualified. We don't want to consider an overlay as a
// popup if it wasn't counted before and only satisfies the conditions later
// due to viewport size change.
content_has_been_stable_ = false;
last_detection_main_frame_size_ = main_frame_size;
}
// We want to explicitly prevent mid-roll ads from being categorized as
......@@ -111,14 +121,14 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
DOMNodeId element_id = DOMNodeIds::IdForNode(element);
// Skip considering the overlay for a pop-up candidate if we haven't seen or
// have just seen the first meaningful paint. If we have just seen the first
// meaningful paint, however, we would consider future overlays for pop-up
// candidates.
if (!main_content_has_loaded_) {
// have just seen the first meaningful paint, or if the viewport size has just
// changed. If we have just seen the first meaningful paint, however, we
// would consider future overlays for pop-up candidates.
if (!content_has_been_stable_) {
if (!PaintTiming::From(*main_frame->GetDocument())
.FirstMeaningfulPaint()
.is_null()) {
main_content_has_loaded_ = true;
content_has_been_stable_ = true;
}
last_unqualified_element_id_ = element_id;
......@@ -145,11 +155,18 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
candidate_is_ad_ = false;
}
if (!is_new_element)
if (element_id == last_unqualified_element_id_)
return;
if (element_id == last_unqualified_element_id_)
if (!is_new_element) {
// Potentially update the ad status of the candidate from non-ad to ad.
// Ad tagging could occur after the initial painting (e.g. at loading time),
// and we are making the best effort to catch it.
if (element->IsAdRelated())
candidate_is_ad_ = true;
return;
}
if (!element->GetLayoutObject())
return;
......@@ -184,6 +201,11 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
}
}
// static
void OverlayInterstitialAdDetector::DisableFrequencyCappingForTesting() {
g_frequency_capping_enabled = false;
}
void OverlayInterstitialAdDetector::OnPopupDetected(LocalFrame* main_frame,
bool is_ad) {
if (!popup_detected_) {
......
......@@ -53,11 +53,13 @@ class CORE_EXPORT OverlayInterstitialAdDetector {
void MaybeFireDetection(LocalFrame* main_frame);
static void DisableFrequencyCappingForTesting();
private:
void OnPopupDetected(LocalFrame* main_frame, bool is_ad);
bool started_detection_ = false;
bool main_content_has_loaded_ = false;
bool content_has_been_stable_ = false;
// The following members are valid only when |started_detection_| is true.
base::Time last_detection_time_;
......
......@@ -3381,6 +3381,10 @@ bool Internals::isTrackingOcclusionForIFrame(HTMLIFrameElement* iframe) const {
return remote_frame->View()->NeedsOcclusionTracking();
}
void Internals::DisableFrequencyCappingForOverlayPopupDetection() const {
OverlayInterstitialAdDetector::DisableFrequencyCappingForTesting();
}
void Internals::addEmbedderCustomElementName(const AtomicString& name,
ExceptionState& exception_state) {
CustomElement::AddEmbedderCustomElementNameForTesting(name, exception_state);
......
......@@ -582,6 +582,8 @@ class Internals final : public ScriptWrappable {
bool isSiteIsolated(HTMLIFrameElement* iframe) const;
bool isTrackingOcclusionForIFrame(HTMLIFrameElement* iframe) const;
void DisableFrequencyCappingForOverlayPopupDetection() const;
void addEmbedderCustomElementName(const AtomicString& name, ExceptionState&);
LocalFrame* GetFrame() const;
......
......@@ -406,6 +406,11 @@
// instances that track visibility.
boolean isTrackingOcclusionForIFrame(HTMLIFrameElement iframe);
// Disable the frequency capping for overlay popup detection. This
// eliminates the need to for waitings in web tests to trigger a detection
// event.
void DisableFrequencyCappingForOverlayPopupDetection();
// Declare that the given |name| is in use by the embedder via the custom
// element mechanism.
[RaisesException] void addEmbedderCustomElementName(DOMString name);
......
......@@ -539,9 +539,6 @@ crbug.com/1092121 fast/css/large-list-of-rules-crash.html [ Slow ]
crbug.com/1042205 virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/paint2d-filter.https.html [ Slow ]
# Slow is the intended behavior
crbug.com/1048136 http/tests/subresource_filter/overlay-popup-non-ad-followed-by-ad.html [ Slow ]
crbug.com/1093849 external/wpt/dom/nodes/Element-classlist.html [ Slow ]
crbug.com/1093853 external/wpt/dom/ranges/Range-surroundContents.html [ Slow ]
......
......@@ -33,31 +33,39 @@ p {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
document.body.style.overflow = "hidden";
document.body.style.overflow = "hidden";
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate. Expect that the use counter
// kOverlayPopupAd is recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, true);
});
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate.
await forceLayoutUpdate();
// Expect the OverlayPopupAd UseCounter.
if (!internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test UseCounter for overlay-popup-ad when the frame has position:absolute and the <body> has overflow:hidden.");
</script>
......
......@@ -43,44 +43,52 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Ensure a user gesture happened in the main frame.
if (window.eventSender) {
eventSender.mouseMoveTo(1, 1);
eventSender.mouseDown(1, 1);
eventSender.mouseUp(1, 1);
}
// Ensure a user gesture happened in the main frame.
if (window.eventSender) {
eventSender.mouseMoveTo(1, 1);
eventSender.mouseDown(1, 1);
eventSender.mouseUp(1, 1);
}
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate.
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is not recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, false);
});
});
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate's dismissal.
await forceLayoutUpdate();
// Expect no OverlayPopupAd UseCounter as the popup was created with user
// gesture.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test overlay-popup-ad when the frame itself has a fixed position and it's created with user gesture. In this case, we expect no use counter for kOverlayPopupAd.");
</script>
......
......@@ -43,37 +43,44 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate.
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, true);
});
});
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate's dismissal.
await forceLayoutUpdate();
// Expect the OverlayPopupAd UseCounter.
if (!internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test UseCounter for overlay-popup-ad when the frame itself has a fixed position.");
</script>
......
......@@ -43,37 +43,44 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate.
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, true);
});
});
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate's dismissal.
await forceLayoutUpdate();
// Expect the OverlayPopupAd UseCounter.
if (!internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test UseCounter for overlay-popup-ad when the frame's outer div has a fixed position.");
</script>
......
......@@ -43,37 +43,45 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate.
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is not recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, false);
});
});
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate's dismissal.
await forceLayoutUpdate();
// Expect that the use counter kOverlayPopupAd is not recorded, as the
// ad size is too small relative to the viewport size.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test overlay-popup-ad when the frame itself has a fixed position and the size is less than 10% of the viewport size. In this case, we expect no use counter for kOverlayPopupAd.");
</script>
......
......@@ -44,41 +44,48 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// would have been aware of the first meaningful paint (hadn't we skipped
// the detection in fullscreen video scenario).
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Create the overlay pop-up ad.
appendAdFrameTo(document.body);
// Create the overlay pop-up ad.
appendAdFrameTo(document.body);
// After 1500ms, force a layout update so that the interstitial detector
// would have been aware of the overlay candidate (if we hadn't skipped
// the detection during a fullscreen video scenario).
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector would have
// been aware of the overlay candidate (hadn't we skipped the detection in
// fullscreen video scenario).
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector would have been aware of the overlay candidate's
// dismissal (if we hadn't skipped the detection during a fullscreen
// video scenario). Expect that the use counter kOverlayPopupAd is
// NOT recorded, because there was a dominant video element and we
// skipped the detection.
verifyOverlayPopupUseCounterAfter1500ms(t, false);
});
});
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector would have
// been aware of the overlay candidate's dismissal (hadn't we skipped the
// detection in fullscreen video scenario).
await forceLayoutUpdate();
// Expect that the use counter kOverlayPopupAd is not recorded, as we
// skipped all previous detection due to there was a fullscreen video
// element.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test that we will skip the overlay-popup-ad detection if there's a dominant video element in the page.");
</script>
......
<!DOCTYPE html>
<html>
<head>
<style>
div {
width: 100vw;
height: 100vh;
}
iframe {
position: fixed;
margin-left: 0vw;
width: 100px;
height: 100px;
border: 0px;
}
p {
position: fixed;
}
div.bottom {
position: absolute;
top: 10000px;
left: 0px;
width: 1px;
height: 1px;
}
</style>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
</head>
<body marginwidth="0" marginheight="0">
<!-- To trigger the first contentful paint at the very start -->
<p>some content</p>
<!-- To contain the overlay popup -->
<div></div>
<!-- To be positioned further down in the main page to make the page scrollable -->
<div class="bottom"></div>
<script>
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Make the page unscrollable so that future overlay candidates can be
// determined immediately rather than at dismissal time.
document.body.style.overflow = "hidden";
// Force a layout update, so that the interstitial detector is aware of
// the current viewport size.
await forceLayoutUpdate();
// Expect no OverlayPopupAd usage, as the ad frame is not in the center of
// the viewport.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
// Resize the window to to make the overlay iframe centered and large
// relative to the viewport.
testRunner.useUnfortunateSynchronousResizeMode();
testRunner.waitUntilDone();
window.resizeTo(150, 150);
// Force a layout update, so that the interstitial detector
// is aware of the updated viewport size, and the overlay ad iframe.
await forceLayoutUpdate();
// Expect no OverlayPopupAd usage, as the viewport has just been resized
// so we have skipped this detection.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
// Force a layout update, to trigger another detection event.
await forceLayoutUpdate();
// Expect no OverlayPopupAd usage, as the overlay has been marked
// unqualified.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
// Create another overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// Force a layout update so that the interstitial detector is aware of
// the new overlay ad iframe.
await forceLayoutUpdate();
// Expect OverlayPopupAd usage due to the appearance of the new overlay.
if (!internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
}, "Test overlay-popup-ad when the ad appears before (no use counter) & after (use counter) resizing the viewport.");
</script>
</body>
</html>
......@@ -44,32 +44,46 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'alpha.png' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["alpha.png"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Create the overlay pop-up ad.
promise_test(() => {
return new Promise(async (resolve, reject) => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// Create the overlay pop-up ad, and wait for image load so that the ad
// status are propagated.
await new Promise(resolve => {
let ad_img = document.createElement('img');
ad_img.addEventListener('load', () => {
resolve();
});
ad_img.src = "resources/alpha.png";
document.getElementsByTagName('div')[0].appendChild(ad_img);
});
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('img')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of the
// overlay candidate.
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, true);
});
});
// Hide the pop-up.
document.getElementsByTagName('img')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of the
// overlay candidate's dismissal.
await forceLayoutUpdate();
// Expect the OverlayPopupAd UseCounter.
if (!internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
});
}, "Test UseCounter for overlay-popup-ad when the image itself has a fixed position.");
</script>
......
......@@ -47,6 +47,7 @@ div.bottom {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
promise_test(() => {
......@@ -65,17 +66,15 @@ promise_test(() => {
let form = document.createElement('form');
document.getElementsByTagName('div')[0].appendChild(form);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
await timeout(1500);
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate.
await forceLayoutUpdate();
// Hide the pop-up.
document.getElementsByTagName('form')[0].style.display = 'none';
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate's dismissal.
await timeout(1500);
// Force a layout update, so that the interstitial detector is aware of
// the overlay candidate's dismissal.
await forceLayoutUpdate();
// Expect use counter kOverlayPopup.
......@@ -91,17 +90,15 @@ promise_test(() => {
// Create the overlay pop-up ad.
appendAdFrameTo(document.getElementsByTagName('div')[0]);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay ad candidate.
await timeout(1500);
// Force a layout update, so that the interstitial detector is aware of
// the overlay ad candidate.
await forceLayoutUpdate();
// Hide the pop-up ad.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay ad candidate's dismissal.
await timeout(1500);
// Force a layout update, so that the interstitial detector is aware of
// the overlay ad candidate's dismissal.
await forceLayoutUpdate();
// Expect use counter kOverlayPopupAd.
......
......@@ -26,33 +26,44 @@ p {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
// Create the overlay pop-up ad.
let ad_frame = appendAdFrameTo(document.body);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate. However, since it's the first time
// the detector is aware of first meaningful paint, the overlay will only be
// considered for prestitials rather than for pop-ups.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is not recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, false);
});
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// Create the overlay pop-up ad.
let ad_frame = appendAdFrameTo(document.body);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint and the prestitial.
await timeout(1500);
await forceLayoutUpdate();
// Ensure the detection is triggered at least once after the first
// meaningful paint is seen.
await forceLayoutUpdate();
// Hide the pop-up.
document.getElementsByTagName('iframe')[0].style.display = 'none';
// Force a layout update, so that the interstitial detector is aware of
// the overlay ad candidate's dismissal.
await forceLayoutUpdate();
// Expect no kOverlayPopupAd UseCounter as the candidate is considered to
// be 'prestitial' instead of 'pop-up'.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test overlay-prestitial-ad when the frame itself has a fixed position. In this case we expect no use counter for kOverlayPopupAd.");
</script>
......
......@@ -54,43 +54,51 @@ p {
if (window.testRunner) {
// Inject a subresource filter to mark 'overlay-interstitial-ad-testharness.js' as a would be disallowed resource.
testRunner.setDisallowedSubresourcePathSuffixes(["overlay-interstitial-ad-testharness.js"], false /* block_subresources */);
internals.DisableFrequencyCappingForOverlayPopupDetection();
}
async_test(t => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = t.step_func(() => {
promise_test(() => {
return new Promise((resolve, reject) => {
let ad_script = document.createElement("script");
ad_script.async = false;
ad_script.src = "resources/overlay-interstitial-ad-testharness.js";
ad_script.onload = async() => {
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the first meaningful paint, and future overlay candidates
// will be considered for pop-ups rather than for prestitials.
await timeout(1500);
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial detector is
// aware of the first meaningful paint, and future overlay candidates will
// be considered for pop-ups rather than for prestitials.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Create the parallax-ad, which is under the "content" div and above
// the "empty" div.
appendAdFrameTo(document.body);
// Create the parallax-ad, which is below the "content" div and above the
// "empty" div.
appendAdFrameTo(document.body);
// Scroll down to the position where the parallax-ad is no longer
// covered by "content1" and becomes visible.
window.scrollTo(0, document.documentElement.clientHeight);
// Scroll down to the position where the parallax-ad is no longer covered
// by "content1" and becomes visible.
window.scrollTo(0, document.documentElement.clientHeight);
// After 1500ms, force a layout update so that the interstitial detector
// is aware of the overlay candidate.
verifyOverlayPopupUseCounterAfter1500ms(t, false,
() => {
// Scroll further down to the position where the parallax-ad is
// covered by "content2" and becomes invisible again.
window.scrollTo(0, document.documentElement.clientHeight * 2);
// Force a layout update, so that the interstitial detector is aware of
// the overlay ad candidate.
await forceLayoutUpdate();
// After 1500ms, force a layout update so that the interstitial
// detector is aware of the overlay candidate's dismissal. Expect
// that the use counter kOverlayPopupAd is not recorded.
verifyOverlayPopupUseCounterAfter1500ms(t, false);
});
});
// Scroll further down to the position where the parallax-ad is covered by
// "content2" and becomes invisible again.
window.scrollTo(0, document.documentElement.clientHeight * 2);
// Force a layout update, so that the interstitial detector is aware of
// the overlay ad candidate's dismissal.
await forceLayoutUpdate();
// Expect no kOverlayPopupAd UseCounter as the scroll offset has changed
// since the candidate's appearance.
if (internals.isUseCounted(document, kOverlayPopupAd)) {
reject();
}
resolve();
};
document.body.appendChild(ad_script);
});
document.body.appendChild(ad_script);
}, "Test parallax-ad while scrolling over the page. In this case, we expect no use counter for kOverlayPopupAd.");
</script>
......
......@@ -12,34 +12,6 @@ function forceLayoutUpdate() {
return new Promise((resolve) => requestAnimationFrame(() => { setTimeout(() => { resolve(); }) }));
}
// TODO(yaoxia): For those tests that still depend on this function, we'd want
// to convert them use Promise and async/await for better readability.
function verifyOverlayPopupUseCounterAfter1500ms(
test, expect_use_counter, post_verify_callback) {
// Force a lifecycle update after 1500ms, so that the final stable layout
// can be captured.
setTimeout(
test.step_func(() => {
requestAnimationFrame(test.step_func(() => {
setTimeout(test.step_func(() => {
// This code runs immediately after the lifecycle update.
if (self.internals) {
assert_equals(
internals.isUseCounted(document, kOverlayPopupAd),
expect_use_counter);
}
if (post_verify_callback !== undefined) {
post_verify_callback();
} else {
test.done();
}
}));
}));
}),
1500);
}
function appendAdFrameTo(parent) {
let ad_frame = document.createElement('iframe');
parent.appendChild(ad_frame);
......
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