Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp

Issue 2023093003: Upgrade in-document custom elements when an element is defined. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix ASAN failure in test helper. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..11b541c21f0016dc65897956b73ef75e67f03fb9
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
@@ -0,0 +1,319 @@
+// Copyright 2016 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 "core/dom/custom/CustomElementsRegistry.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/ScriptValue.h"
+#include "core/dom/Document.h"
+#include "core/dom/Element.h"
+#include "core/dom/ElementRegistrationOptions.h"
+#include "core/dom/custom/CustomElementDefinition.h"
+#include "core/dom/custom/CustomElementDefinitionBuilder.h"
+#include "core/dom/custom/CustomElementDescriptor.h"
+#include "core/dom/custom/CustomElementTestHelpers.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/dom/shadow/ShadowRootInit.h"
+#include "core/html/HTMLDocument.h"
+#include "core/testing/DummyPageHolder.h"
+#include "platform/ScriptForbiddenScope.h"
+#include "platform/heap/Handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "wtf/text/AtomicString.h"
+#include <memory>
+
+namespace blink {
+
+class CustomElementsRegistryTestBase : public ::testing::Test {
+protected:
+ virtual Document& document() = 0;
+ virtual CustomElementsRegistry& registry() = 0;
+
+ void collectCandidates(
+ const CustomElementDescriptor& desc,
+ HeapVector<Member<Element>>* elements)
+ {
+ registry().collectCandidates(desc, elements);
+ }
+};
+
+class CustomElementsRegistryTest : public CustomElementsRegistryTestBase {
+protected:
+ void SetUp() override
+ {
+ CustomElementsRegistryTestBase::SetUp();
+
+ m_document = HTMLDocument::create();
+ m_document->appendChild(CreateElement("html").inDocument(m_document));
+
+ m_registry = CustomElementsRegistry::create(m_document);
+ }
+
+ void TearDown() override
+ {
+ m_document = nullptr;
+ m_registry = nullptr;
+ CustomElementsRegistryTestBase::TearDown();
+ }
+
+ Document& document() override { return *m_document; }
+ CustomElementsRegistry& registry() override { return *m_registry; }
+
+private:
+ Persistent<Document> m_document;
+ Persistent<CustomElementsRegistry> m_registry;
+};
+
+class CustomElementsRegistryFrameTest : public CustomElementsRegistryTestBase {
+protected:
+ void SetUp() override
+ {
+ CustomElementsRegistryTestBase::SetUp();
+ m_page.reset(DummyPageHolder::create(IntSize(1, 1)).leakPtr());
+ }
+
+ void TearDown() override
+ {
+ m_page = nullptr;
+ CustomElementsRegistryTestBase::TearDown();
+ }
+
+ Document& document() override { return m_page->document(); }
+
+ CustomElementsRegistry& registry() override
+ {
+ return *m_page->frame().localDOMWindow()->customElements();
+ }
+
+ ScriptState* scriptState()
+ {
+ return ScriptState::forMainWorld(&m_page->frame());
+ }
+
+ ShadowRoot* attachShadowTo(Element* element)
+ {
+ NonThrowableExceptionState noExceptions;
+ ShadowRootInit shadowRootInit;
+ return
+ element->attachShadow(scriptState(), shadowRootInit, noExceptions);
+ }
+
+private:
+ std::unique_ptr<DummyPageHolder> m_page;
+};
+
+TEST_F(
+ CustomElementsRegistryTest,
+ collectCandidates_shouldNotIncludeElementsRemovedFromDocument)
+{
+ Element* element = CreateElement("a-a").inDocument(&document());
+ registry().addCandidate(element);
+
+ HeapVector<Member<Element>> elements;
+ collectCandidates(
+ CustomElementDescriptor("a-a", "a-a"),
+ &elements);
+
+ EXPECT_TRUE(elements.isEmpty())
+ << "no candidates should have been found, but we have "
+ << elements.size();
+ EXPECT_FALSE(elements.contains(element))
+ << "the out-of-document candidate should not have been found";
+}
+
+TEST_F(
+ CustomElementsRegistryTest,
+ collectCandidates_shouldNotIncludeElementsInDifferentDocument)
+{
+ Element* element = CreateElement("a-a").inDocument(&document());
+ registry().addCandidate(element);
+
+ Document* otherDocument = HTMLDocument::create();
+ otherDocument->appendChild(element);
+ EXPECT_EQ(otherDocument, element->ownerDocument())
+ << "sanity: another document should have adopted an element on append";
+
+ HeapVector<Member<Element>> elements;
+ collectCandidates(
+ CustomElementDescriptor("a-a", "a-a"),
+ &elements);
+
+ EXPECT_TRUE(elements.isEmpty())
+ << "no candidates should have been found, but we have "
+ << elements.size();
+ EXPECT_FALSE(elements.contains(element))
+ << "the adopted-away candidate should not have been found";
+}
+
+TEST_F(
+ CustomElementsRegistryTest,
+ collectCandidates_shouldOnlyIncludeCandidatesMatchingDescriptor)
+{
+ CustomElementDescriptor descriptor("hello-world", "hello-world");
+
+ // Does not match: namespace is not HTML
+ Element* elementA = CreateElement("hello-world")
+ .inDocument(&document())
+ .inNamespace("data:text/date,1981-03-10");
+ // Matches
+ Element* elementB = CreateElement("hello-world").inDocument(&document());
+ // Does not match: local name is not hello-world
+ Element* elementC = CreateElement("button")
+ .inDocument(&document())
+ .withIsAttribute("hello-world");
+ document().documentElement()->appendChild(elementA);
+ elementA->appendChild(elementB);
+ elementA->appendChild(elementC);
+
+ registry().addCandidate(elementA);
+ registry().addCandidate(elementB);
+ registry().addCandidate(elementC);
+
+ HeapVector<Member<Element>> elements;
+ collectCandidates(descriptor, &elements);
+
+ EXPECT_EQ(1u, elements.size())
+ << "only one candidates should have been found";
+ EXPECT_EQ(elementB, elements[0])
+ << "the matching element should have been found";
+}
+
+TEST_F(CustomElementsRegistryTest, collectCandidates_oneCandidate)
+{
+ Element* element = CreateElement("a-a").inDocument(&document());
+ registry().addCandidate(element);
+ document().documentElement()->appendChild(element);
+
+ HeapVector<Member<Element>> elements;
+ collectCandidates(
+ CustomElementDescriptor("a-a", "a-a"),
+ &elements);
+
+ EXPECT_EQ(1u, elements.size())
+ << "exactly one candidate should have been found";
+ EXPECT_TRUE(elements.contains(element))
+ << "the candidate should be the element that was added";
+}
+
+TEST_F(CustomElementsRegistryTest, collectCandidates_shouldBeInDocumentOrder)
+{
+ CreateElement factory = CreateElement("a-a");
+ factory.inDocument(&document());
+ Element* elementA = factory.withId("a");
+ Element* elementB = factory.withId("b");
+ Element* elementC = factory.withId("c");
+
+ registry().addCandidate(elementB);
+ registry().addCandidate(elementA);
+ registry().addCandidate(elementC);
+
+ document().documentElement()->appendChild(elementA);
+ elementA->appendChild(elementB);
+ document().documentElement()->appendChild(elementC);
+
+ HeapVector<Member<Element>> elements;
+ collectCandidates(
+ CustomElementDescriptor("a-a", "a-a"),
+ &elements);
+
+ EXPECT_EQ(elementA, elements[0].get());
+ EXPECT_EQ(elementB, elements[1].get());
+ EXPECT_EQ(elementC, elements[2].get());
+}
+
+class TestCustomElementDefinition : public CustomElementDefinition {
+ WTF_MAKE_NONCOPYABLE(TestCustomElementDefinition);
+public:
+ TestCustomElementDefinition(const CustomElementDescriptor& descriptor)
+ : CustomElementDefinition(descriptor)
+ {
+ }
+
+ ~TestCustomElementDefinition() override = default;
+
+ ScriptValue getConstructorForScript() override
+ {
+ return ScriptValue();
+ }
+
+ bool runConstructor(Element* element) override
+ {
+ if (constructionStack().isEmpty()
+ || constructionStack().last() != element)
+ return false;
+ constructionStack().last().clear();
+ return true;
+ }
+};
+
+// Classes which use trace macros cannot be local because of the
+// traceImpl template.
+class LogUpgradeDefinition : public TestCustomElementDefinition {
+ WTF_MAKE_NONCOPYABLE(LogUpgradeDefinition);
+public:
+ LogUpgradeDefinition(const CustomElementDescriptor& descriptor)
+ : TestCustomElementDefinition(descriptor)
+ {
+ }
+
+ DEFINE_INLINE_VIRTUAL_TRACE()
+ {
+ TestCustomElementDefinition::trace(visitor);
+ visitor->trace(m_element);
+ }
+
+ // TODO(dominicc): Make this class collect a vector of what's
+ // upgraded; it will be useful in more tests.
+ Member<Element> m_element;
+ uint32_t m_invocationCount;
+
+ bool runConstructor(Element* element) override
+ {
+ m_invocationCount++;
+ m_element = element;
+ return TestCustomElementDefinition::runConstructor(element);
+ }
+};
+
+class LogUpgradeBuilder final : public CustomElementDefinitionBuilder {
+ STACK_ALLOCATED();
+ WTF_MAKE_NONCOPYABLE(LogUpgradeBuilder);
+public:
+ LogUpgradeBuilder() { }
+
+ bool checkConstructorIntrinsics() override { return true; }
+ bool checkConstructorNotRegistered() override { return true; }
+ bool checkPrototype() override { return true; }
+ CustomElementDefinition* build(
+ const CustomElementDescriptor& descriptor) {
+ return new LogUpgradeDefinition(descriptor);
+ }
+};
+
+TEST_F(CustomElementsRegistryFrameTest, define_upgradesInDocumentElements)
+{
+ ScriptForbiddenScope doNotRelyOnScript;
+
+ Element* element = CreateElement("a-a").inDocument(&document());
+ document().documentElement()->appendChild(element);
+
+ LogUpgradeBuilder builder;
+ NonThrowableExceptionState shouldNotThrow;
+ registry().define(
+ "a-a",
+ builder,
+ ElementRegistrationOptions(),
+ shouldNotThrow);
+ LogUpgradeDefinition* definition =
+ static_cast<LogUpgradeDefinition*>(registry().definitionForName("a-a"));
+ EXPECT_EQ(1u, definition->m_invocationCount)
+ << "defining the element should have 'upgraded' the existing element";
+ EXPECT_EQ(element, definition->m_element)
+ << "the existing a-a element should have been upgraded";
+}
+
+// TODO(dominicc): Add tests which adjust the "is" attribute when type
+// extensions are implemented.
+
+} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.cpp ('k') | third_party/WebKit/Source/core/frame/FrameHost.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698