blob: c0df8ff759dcc4d41fc07f8c688a1fec5ef71bcf [file] [log] [blame]
// Copyright 2015 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 "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-blink.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.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/url_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace {
const char kExtensionFeaturesHistogramName[] =
"Blink.UseCounter.Extensions.Features";
const char kExtensionUrl[] = "chrome-extension://dummysite/";
int GetPageVisitsBucketforHistogram(const std::string& histogram_name) {
if (histogram_name.find("CSS") == std::string::npos)
return static_cast<int>(blink::mojom::WebFeature::kPageVisits);
// For CSS histograms, the page visits bucket should be 1.
return static_cast<int>(
blink::mojom::blink::CSSSampleId::kTotalPagesMeasured);
}
} // namespace
namespace blink {
using WebFeature = mojom::WebFeature;
class UseCounterHelperTest : public testing::Test {
public:
UseCounterHelperTest() : dummy_(std::make_unique<DummyPageHolder>()) {
Page::InsertOrdinaryPageForTesting(&dummy_->GetPage());
}
int ToSampleId(CSSPropertyID property) const {
return static_cast<int>(GetCSSSampleId(property));
}
bool IsInternal(CSSPropertyID property) const {
return CSSProperty::Get(property).IsInternal();
}
protected:
LocalFrame* GetFrame() { return &dummy_->GetFrame(); }
void SetIsViewSource() { dummy_->GetDocument().SetIsViewSource(true); }
void SetURL(const KURL& url) { dummy_->GetDocument().SetURL(url); }
Document& GetDocument() { return dummy_->GetDocument(); }
std::unique_ptr<DummyPageHolder> dummy_;
HistogramTester histogram_tester_;
void UpdateAllLifecyclePhases(Document& document) {
document.View()->UpdateAllLifecyclePhasesForTest();
}
};
TEST_F(UseCounterHelperTest, RecordingExtensions) {
const std::string histogram = kExtensionFeaturesHistogramName;
constexpr auto item = mojom::WebFeature::kFetch;
constexpr auto second_item = WebFeature::kFetchBodyStream;
const std::string url = kExtensionUrl;
UseCounterHelper::Context context = UseCounterHelper::kExtensionContext;
int page_visits_bucket = GetPageVisitsBucketforHistogram(histogram);
UseCounterHelper use_counter0(context, UseCounterHelper::kCommited);
// Test recording a single (arbitrary) counter
EXPECT_FALSE(use_counter0.HasRecordedMeasurement(item));
use_counter0.RecordMeasurement(item, *GetFrame());
EXPECT_TRUE(use_counter0.HasRecordedMeasurement(item));
histogram_tester_.ExpectUniqueSample(histogram, static_cast<int>(item), 1);
// Test that repeated measurements have no effect
use_counter0.RecordMeasurement(item, *GetFrame());
histogram_tester_.ExpectUniqueSample(histogram, static_cast<int>(item), 1);
// Test recording a different sample
EXPECT_FALSE(use_counter0.HasRecordedMeasurement(second_item));
use_counter0.RecordMeasurement(second_item, *GetFrame());
EXPECT_TRUE(use_counter0.HasRecordedMeasurement(second_item));
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 1);
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(second_item),
1);
histogram_tester_.ExpectTotalCount(histogram, 2);
// After a page load, the histograms will be updated, even when the URL
// scheme is internal
UseCounterHelper use_counter1(context);
SetURL(url_test_helpers::ToKURL(url));
use_counter1.DidCommitLoad(GetFrame());
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 1);
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(second_item),
1);
histogram_tester_.ExpectBucketCount(histogram, page_visits_bucket, 1);
histogram_tester_.ExpectTotalCount(histogram, 3);
// Now a repeat measurement should get recorded again, exactly once
EXPECT_FALSE(use_counter1.HasRecordedMeasurement(item));
use_counter1.RecordMeasurement(item, *GetFrame());
use_counter1.RecordMeasurement(item, *GetFrame());
EXPECT_TRUE(use_counter1.HasRecordedMeasurement(item));
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 2);
histogram_tester_.ExpectTotalCount(histogram, 4);
}
TEST_F(UseCounterHelperTest, CSSSelectorPseudoWhere) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoWhere;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>.a+:where(.b, .c+.d) { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoIs));
}
/*
* Counter-specific tests
*
* NOTE: Most individual UseCounters don't need dedicated test cases. They are
* "tested" by analyzing the data they generate including on some known pages.
* Feel free to add tests for counters where the triggering logic is
* non-trivial, but it's not required. Manual analysis is necessary to trust the
* data anyway, real-world pages are full of edge-cases and surprises that you
* won't find in unit testing anyway.
*/
TEST_F(UseCounterHelperTest, CSSSelectorPseudoAnyLink) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoAnyLink;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>:any-link { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSSelectorPseudoWebkitAnyLink) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoWebkitAnyLink;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>:-webkit-any-link { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSTypedOMStylePropertyMap) {
UseCounterHelper use_counter;
WebFeature feature = WebFeature::kCSSTypedOMStylePropertyMap;
EXPECT_FALSE(GetDocument().IsUseCounted(feature));
GetDocument().CountUse(feature);
EXPECT_TRUE(GetDocument().IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSSelectorPseudoIs) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoIs;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>.a+:is(.b, .c+.d) { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoWhere));
}
TEST_F(UseCounterHelperTest, CSSSelectorPseudoDir) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoDir;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>:dir(ltr) { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageColumnIndefiniteWidth) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-columns: 50%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight1) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-rows: 50%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight2) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-rows: 50% 50%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight3) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-rows: 100% 100%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight4) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-rows: minmax(50%, "
"100%);'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight5) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; max-height: 0; grid-template-rows: "
"100%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight6) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-rows: 100%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight7) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-rows: minmax(100%, "
"100%);'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSFlexibleBox) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSFlexibleBox;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: flex;'>flexbox</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSFlexibleBoxInline) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSFlexibleBox;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-flex;'>flexbox</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSFlexibleBoxButton) {
// LayoutButton is a subclass of LayoutFlexibleBox, however we don't want it
// to be counted as usage of flexboxes as it's an implementation detail.
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSFlexibleBox;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML("<button>button</button>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
class DeprecationTest : public testing::Test {
public:
DeprecationTest()
: dummy_(std::make_unique<DummyPageHolder>()),
deprecation_(dummy_->GetPage().GetDeprecation()),
use_counter_(dummy_->GetDocument().Loader()->GetUseCounterHelper()) {
Page::InsertOrdinaryPageForTesting(&dummy_->GetPage());
}
protected:
LocalFrame* GetFrame() { return &dummy_->GetFrame(); }
std::unique_ptr<DummyPageHolder> dummy_;
Deprecation& deprecation_;
UseCounterHelper& use_counter_;
};
TEST_F(DeprecationTest, InspectorDisablesDeprecation) {
// The specific feature we use here isn't important.
WebFeature feature =
WebFeature::kCSSSelectorInternalMediaControlsOverlayCastButton;
CSSPropertyID property = CSSPropertyID::kFontWeight;
EXPECT_FALSE(deprecation_.IsSuppressed(property));
deprecation_.MuteForInspector();
Deprecation::WarnOnDeprecatedProperties(GetFrame(), property);
EXPECT_FALSE(deprecation_.IsSuppressed(property));
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_FALSE(use_counter_.HasRecordedMeasurement(feature));
deprecation_.MuteForInspector();
Deprecation::WarnOnDeprecatedProperties(GetFrame(), property);
EXPECT_FALSE(deprecation_.IsSuppressed(property));
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_FALSE(use_counter_.HasRecordedMeasurement(feature));
deprecation_.UnmuteForInspector();
Deprecation::WarnOnDeprecatedProperties(GetFrame(), property);
EXPECT_FALSE(deprecation_.IsSuppressed(property));
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_FALSE(use_counter_.HasRecordedMeasurement(feature));
deprecation_.UnmuteForInspector();
Deprecation::WarnOnDeprecatedProperties(GetFrame(), property);
// TODO: use the actually deprecated property to get a deprecation message.
EXPECT_FALSE(deprecation_.IsSuppressed(property));
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_TRUE(use_counter_.HasRecordedMeasurement(feature));
}
TEST_F(UseCounterHelperTest, CSSUnknownNamespacePrefixInSelector) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSUnknownNamespacePrefixInSelector;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(R"HTML(
<style>
@namespace svg url(http://www.w3.org/2000/svg);
svg|a {}
a {}
</style>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML("<style>foo|a {}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSSelectorHostContextInLiveProfile) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorHostContextInLiveProfile;
document.body()->setInnerHTML(R"HTML(
<div id="parent">
<div id="host"></div>
</div>
)HTML");
Element* host = document.getElementById("host");
ASSERT_TRUE(host);
ShadowRoot& shadow_root =
host->AttachShadowRootInternal(ShadowRootType::kOpen);
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
shadow_root.setInnerHTML(R"HTML(
<style>
:host-context(#parent) span {
color: green
}
</style>
<span></span>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSSelectorHostContextInSnapshotProfile) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorHostContextInSnapshotProfile;
document.body()->setInnerHTML(R"HTML(
<div id="parent">
<div id="host"></div>
</div>
)HTML");
Element* host = document.getElementById("host");
ASSERT_TRUE(host);
ShadowRoot& shadow_root =
host->AttachShadowRootInternal(ShadowRootType::kOpen);
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
shadow_root.setInnerHTML("<span></span>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
Element* span = shadow_root.QuerySelector(":host-context(#parent) span");
EXPECT_TRUE(span);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, UniqueCSSSampleIds) {
HashSet<int> ids;
for (CSSPropertyID property : CSSPropertyIDList()) {
if (IsInternal(property))
continue;
EXPECT_FALSE(ids.Contains(ToSampleId(property)));
ids.insert(ToSampleId(property));
}
for (CSSPropertyID property : kCSSPropertyAliasList) {
EXPECT_FALSE(ids.Contains(ToSampleId(property)));
ids.insert(ToSampleId(property));
}
}
TEST_F(UseCounterHelperTest, MaximumCSSSampleId) {
int max_sample_id = 0;
for (CSSPropertyID property : CSSPropertyIDList()) {
if (IsInternal(property))
continue;
max_sample_id = std::max(max_sample_id, ToSampleId(property));
}
for (CSSPropertyID property : kCSSPropertyAliasList)
max_sample_id = std::max(max_sample_id, ToSampleId(property));
EXPECT_EQ(static_cast<int>(mojom::blink::CSSSampleId::kMaxValue),
max_sample_id);
}
TEST_F(UseCounterHelperTest, CSSMarkerPseudoElementUA) {
// Check that UA styles for list markers are not counted.
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kHasMarkerPseudoElement;
EXPECT_FALSE(document.IsUseCounted(feature));
document.body()->setInnerHTML(R"HTML(
<style>
li::before {
content: "[before]";
display: list-item;
}
</style>
<ul>
<li style="list-style: decimal outside"></li>
<li style="list-style: decimal inside"></li>
<li style="list-style: disc outside"></li>
<li style="list-style: disc inside"></li>
<li style="list-style: '- ' outside"></li>
<li style="list-style: '- ' inside"></li>
<li style="list-style: linear-gradient(blue, cyan) outside"></li>
<li style="list-style: linear-gradient(blue, cyan) inside"></li>
<li style="list-style: none outside"></li>
<li style="list-style: none inside"></li>
</ul>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterHelperTest, CSSMarkerPseudoElementAuthor) {
// Check that author styles for list markers are counted.
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kHasMarkerPseudoElement;
EXPECT_FALSE(document.IsUseCounted(feature));
document.body()->setInnerHTML(R"HTML(
<style>
li::marker {
color: blue;
}
</style>
<ul>
<li></li>
</ul>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
} // namespace blink