blob: 3cdf716f661fed886096c639221029a7f4d9601c [file] [log] [blame]
// Copyright 2018 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 "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/media_list_or_string.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_css_style_sheet.h"
#include "third_party/blink/renderer/core/css/css_rule_list.h"
#include "third_party/blink/renderer/core/css/css_style_sheet_init.h"
#include "third_party/blink/renderer/core/css/media_list.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
class CSSStyleSheetTest : public PageTestBase {
protected:
void SetUp() override {
PageTestBase::SetUp();
RuntimeEnabledFeatures::SetConstructableStylesheetsEnabled(true);
}
class FunctionForTest : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
ScriptValue* output) {
FunctionForTest* self =
MakeGarbageCollected<FunctionForTest>(script_state, output);
return self->BindToV8Function();
}
FunctionForTest(ScriptState* script_state, ScriptValue* output)
: ScriptFunction(script_state), output_(output) {}
private:
ScriptValue Call(ScriptValue value) override {
DCHECK(!value.IsEmpty());
*output_ = value;
return value;
}
ScriptValue* output_;
};
};
TEST_F(CSSStyleSheetTest, ConstructorWithoutRuntimeFlagThrowsException) {
DummyExceptionStateForTesting exception_state;
RuntimeEnabledFeatures::SetConstructableStylesheetsEnabled(false);
EXPECT_EQ(CSSStyleSheet::Create(GetDocument(), CSSStyleSheetInit::Create(),
exception_state),
nullptr);
ASSERT_TRUE(exception_state.HadException());
}
TEST_F(CSSStyleSheetTest,
CSSStyleSheetConstructionWithNonEmptyCSSStyleSheetInit) {
DummyExceptionStateForTesting exception_state;
CSSStyleSheetInit* init = CSSStyleSheetInit::Create();
init->setMedia(MediaListOrString::FromString("screen, print"));
init->setTitle("test");
init->setAlternate(true);
init->setDisabled(true);
CSSStyleSheet* sheet =
CSSStyleSheet::Create(GetDocument(), init, exception_state);
ASSERT_FALSE(exception_state.HadException());
EXPECT_TRUE(sheet->href().IsNull());
EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
EXPECT_EQ(sheet->ownerNode(), nullptr);
EXPECT_EQ(sheet->ownerRule(), nullptr);
EXPECT_EQ(sheet->media()->length(), 2U);
EXPECT_EQ(sheet->media()->mediaText(), init->media().GetAsString());
EXPECT_EQ(sheet->title(), init->title());
EXPECT_TRUE(sheet->AlternateFromConstructor());
EXPECT_TRUE(sheet->disabled());
EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
ASSERT_FALSE(exception_state.HadException());
}
TEST_F(CSSStyleSheetTest, CreateEmptyCSSStyleSheetWithEmptyCSSStyleSheetInit) {
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
scope.GetScriptState(), CSSStyleSheetInit::Create(), exception_state);
ASSERT_FALSE(exception_state.HadException());
EXPECT_TRUE(sheet->href().IsNull());
EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
EXPECT_EQ(sheet->ownerNode(), nullptr);
EXPECT_EQ(sheet->ownerRule(), nullptr);
EXPECT_EQ(sheet->media()->length(), 0U);
EXPECT_EQ(sheet->title(), StringImpl::empty_);
EXPECT_FALSE(sheet->AlternateFromConstructor());
EXPECT_FALSE(sheet->disabled());
EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
ASSERT_FALSE(exception_state.HadException());
}
TEST_F(CSSStyleSheetTest,
CreateEmptyCSSStyleSheetWithNonEmptyCSSStyleSheetInit) {
CSSStyleSheetInit* init = CSSStyleSheetInit::Create();
init->setMedia(MediaListOrString::FromString("screen, print"));
init->setTitle("test");
init->setAlternate(true);
init->setDisabled(true);
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
scope.GetScriptState(), init, exception_state);
ASSERT_FALSE(exception_state.HadException());
EXPECT_TRUE(sheet->href().IsNull());
EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
EXPECT_EQ(sheet->ownerNode(), nullptr);
EXPECT_EQ(sheet->ownerRule(), nullptr);
EXPECT_EQ(sheet->media()->length(), 2U);
EXPECT_EQ(sheet->media()->mediaText(), init->media().GetAsString());
EXPECT_EQ(sheet->title(), init->title());
EXPECT_TRUE(sheet->AlternateFromConstructor());
EXPECT_TRUE(sheet->disabled());
ASSERT_FALSE(exception_state.HadException());
}
TEST_F(CSSStyleSheetTest,
CreateCSSStyleSheetWithEmptyCSSStyleSheetInitAndText) {
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
ScriptPromise promise = GetDocument().createCSSStyleSheet(
scope.GetScriptState(), "", CSSStyleSheetInit::Create(), exception_state);
EXPECT_FALSE(promise.IsEmpty());
ASSERT_FALSE(exception_state.HadException());
ScriptValue on_fulfilled, on_rejected;
promise.Then(
FunctionForTest::CreateFunction(scope.GetScriptState(), &on_fulfilled),
FunctionForTest::CreateFunction(scope.GetScriptState(), &on_rejected));
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
CSSStyleSheet* sheet = V8CSSStyleSheet::ToImplWithTypeCheck(
scope.GetIsolate(), on_fulfilled.V8Value());
EXPECT_TRUE(sheet->href().IsNull());
EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
EXPECT_EQ(sheet->ownerNode(), nullptr);
EXPECT_EQ(sheet->ownerRule(), nullptr);
EXPECT_EQ(sheet->media()->length(), 0U);
EXPECT_EQ(sheet->title(), StringImpl::empty_);
EXPECT_FALSE(sheet->AlternateFromConstructor());
EXPECT_FALSE(sheet->disabled());
EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
ASSERT_FALSE(exception_state.HadException());
}
TEST_F(CSSStyleSheetTest,
CreateCSSStyleSheetWithNonEmptyCSSStyleSheetInitAndText) {
String styleText[2] = {".red { color: red; }",
".red + span + span { color: red; }"};
CSSStyleSheetInit* init = CSSStyleSheetInit::Create();
init->setMedia(MediaListOrString::FromString("screen, print"));
init->setTitle("test");
init->setAlternate(true);
init->setDisabled(true);
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
ScriptPromise promise = GetDocument().createCSSStyleSheet(
scope.GetScriptState(), styleText[0] + styleText[1], init,
exception_state);
EXPECT_FALSE(promise.IsEmpty());
ASSERT_FALSE(exception_state.HadException());
ScriptValue on_fulfilled, on_rejected;
promise.Then(
FunctionForTest::CreateFunction(scope.GetScriptState(), &on_fulfilled),
FunctionForTest::CreateFunction(scope.GetScriptState(), &on_rejected));
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
CSSStyleSheet* sheet = V8CSSStyleSheet::ToImplWithTypeCheck(
scope.GetIsolate(), on_fulfilled.V8Value());
EXPECT_TRUE(sheet->href().IsNull());
EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
EXPECT_EQ(sheet->ownerNode(), nullptr);
EXPECT_EQ(sheet->ownerRule(), nullptr);
EXPECT_EQ(sheet->media()->length(), 2U);
EXPECT_EQ(sheet->media()->mediaText(), init->media().GetAsString());
EXPECT_EQ(sheet->title(), init->title());
EXPECT_TRUE(sheet->AlternateFromConstructor());
EXPECT_TRUE(sheet->disabled());
EXPECT_EQ(sheet->cssRules(exception_state)->length(), 2U);
EXPECT_EQ(sheet->cssRules(exception_state)->item(0)->cssText(), styleText[0]);
EXPECT_EQ(sheet->cssRules(exception_state)->item(1)->cssText(), styleText[1]);
ASSERT_FALSE(exception_state.HadException());
}
} // namespace blink