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

Side by Side 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: Address feedback. Created 4 years, 6 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/dom/custom/CustomElementsRegistry.h"
6
7 #include "bindings/core/v8/ExceptionState.h"
8 #include "core/dom/Document.h"
9 #include "core/dom/Element.h"
10 #include "core/dom/ElementRegistrationOptions.h"
11 #include "core/dom/custom/CustomElementDefinition.h"
12 #include "core/dom/custom/CustomElementDefinitionBuilder.h"
13 #include "core/dom/custom/CustomElementDescriptor.h"
14 #include "core/dom/custom/CustomElementTestHelpers.h"
15 #include "core/dom/shadow/ShadowRoot.h"
16 #include "core/dom/shadow/ShadowRootInit.h"
17 #include "core/html/HTMLDocument.h"
18 #include "core/testing/DummyPageHolder.h"
19 #include "platform/ScriptForbiddenScope.h"
20 #include "platform/heap/Handle.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "wtf/text/AtomicString.h"
23 #include <memory>
24
25 namespace blink {
26
27 class CustomElementsRegistryTestBase : public ::testing::Test {
28 protected:
29 virtual Document& document() = 0;
30 virtual CustomElementsRegistry& registry() = 0;
31
32 void collectCandidates(
33 const CustomElementDescriptor& desc,
34 HeapVector<Member<Element>>* elements)
35 {
36 registry().collectCandidates(desc, elements);
37 }
38 };
39
40 class CustomElementsRegistryTest : public CustomElementsRegistryTestBase {
41 protected:
42 void SetUp() override
43 {
44 CustomElementsRegistryTestBase::SetUp();
45
46 m_document = HTMLDocument::create();
47 m_document->appendChild(CreateElement("html").inDocument(m_document));
48
49 m_registry = CustomElementsRegistry::create(m_document);
50 }
51
52 void TearDown() override
53 {
54 m_document = nullptr;
55 m_registry = nullptr;
56 CustomElementsRegistryTestBase::TearDown();
57 }
58
59 Document& document() override { return *m_document; }
60 CustomElementsRegistry& registry() override { return *m_registry; }
61
62 private:
63 Persistent<Document> m_document;
64 Persistent<CustomElementsRegistry> m_registry;
65 };
66
67 class CustomElementsRegistryFrameTest : public CustomElementsRegistryTestBase {
68 protected:
69 void SetUp() override
70 {
71 CustomElementsRegistryTestBase::SetUp();
72 m_page.reset(DummyPageHolder::create(IntSize(1, 1)).leakPtr());
73 }
74
75 void TearDown() override
76 {
77 m_page = nullptr;
78 CustomElementsRegistryTestBase::TearDown();
79 }
80
81 Document& document() override { return m_page->document(); }
82
83 CustomElementsRegistry& registry() override
84 {
85 return *m_page->frame().localDOMWindow()->customElements();
86 }
87
88 ScriptState* scriptState()
89 {
90 return ScriptState::forMainWorld(&m_page->frame());
91 }
92
93 ShadowRoot* attachShadowTo(Element* element)
94 {
95 NonThrowableExceptionState noExceptions;
96 ShadowRootInit shadowRootInit;
97 return
98 element->attachShadow(scriptState(), shadowRootInit, noExceptions);
99 }
100
101 private:
102 std::unique_ptr<DummyPageHolder> m_page;
103 };
104
105 TEST_F(
106 CustomElementsRegistryTest,
107 collectCandidates_shouldNotIncludeElementsRemovedFromDocument)
108 {
109 Element* element = CreateElement("a-a").inDocument(&document());
110 registry().addCandidate(element);
111
112 HeapVector<Member<Element>> elements;
113 collectCandidates(
114 CustomElementDescriptor("a-a", "a-a"),
115 &elements);
116
117 EXPECT_TRUE(elements.isEmpty())
118 << "no candidates should have been found, but we have "
119 << elements.size();
120 EXPECT_FALSE(elements.contains(element))
121 << "the out-of-document candidate should not have been found";
122 }
123
124 TEST_F(
125 CustomElementsRegistryTest,
126 collectCandidates_shouldNotIncludeElementsInDifferentDocument)
127 {
128 Element* element = CreateElement("a-a").inDocument(&document());
129 registry().addCandidate(element);
130
131 Document* otherDocument = HTMLDocument::create();
132 otherDocument->appendChild(element);
133 EXPECT_EQ(otherDocument, element->ownerDocument())
134 << "sanity: another document should have adopted an element on append";
135
136 HeapVector<Member<Element>> elements;
137 collectCandidates(
138 CustomElementDescriptor("a-a", "a-a"),
139 &elements);
140
141 EXPECT_TRUE(elements.isEmpty())
142 << "no candidates should have been found, but we have "
143 << elements.size();
144 EXPECT_FALSE(elements.contains(element))
145 << "the adopted-away candidate should not have been found";
146 }
147
148 TEST_F(
149 CustomElementsRegistryTest,
150 collectCandidates_shouldOnlyIncludeCandidatesMatchingDescriptor)
151 {
152 CustomElementDescriptor descriptor("hello-world", "hello-world");
153
154 // Does not match: namespace is not HTML
155 Element* elementA = CreateElement("hello-world")
156 .inDocument(&document())
157 .inNamespace("data:text/date,1981-03-10");
158 // Matches
159 Element* elementB = CreateElement("hello-world").inDocument(&document());
160 // Does not match: local name is not hello-world
161 Element* elementC = CreateElement("button")
162 .inDocument(&document())
163 .withIsAttribute("hello-world");
164 document().documentElement()->appendChild(elementA);
165 elementA->appendChild(elementB);
166 elementA->appendChild(elementC);
167
168 registry().addCandidate(elementA);
169 registry().addCandidate(elementB);
170 registry().addCandidate(elementC);
171
172 HeapVector<Member<Element>> elements;
173 collectCandidates(descriptor, &elements);
174
175 EXPECT_EQ(1u, elements.size())
176 << "only one candidates should have been found";
177 EXPECT_EQ(elementB, elements[0])
178 << "the matching element should have been found";
179 }
180
181 TEST_F(CustomElementsRegistryTest, collectCandidates_oneCandidate)
182 {
183 Element* element = CreateElement("a-a").inDocument(&document());
184 registry().addCandidate(element);
185 document().documentElement()->appendChild(element);
186
187 HeapVector<Member<Element>> elements;
188 collectCandidates(
189 CustomElementDescriptor("a-a", "a-a"),
190 &elements);
191
192 EXPECT_EQ(1u, elements.size())
193 << "exactly one candidate should have been found";
194 EXPECT_TRUE(elements.contains(element))
195 << "the candidate should be the element that was added";
196 }
197
198 TEST_F(CustomElementsRegistryTest, collectCandidates_shouldBeInDocumentOrder)
199 {
200 CreateElement& factory = CreateElement("a-a").inDocument(&document());
201 Element* elementA = factory.withId("a");
202 Element* elementB = factory.withId("b");
203 Element* elementC = factory.withId("c");
204
205 registry().addCandidate(elementB);
206 registry().addCandidate(elementA);
207 registry().addCandidate(elementC);
208
209 document().documentElement()->appendChild(elementA);
210 elementA->appendChild(elementB);
211 document().documentElement()->appendChild(elementC);
212
213 HeapVector<Member<Element>> elements;
214 collectCandidates(
215 CustomElementDescriptor("a-a", "a-a"),
216 &elements);
217
218 EXPECT_EQ(elementA, elements[0].get());
219 EXPECT_EQ(elementB, elements[1].get());
220 EXPECT_EQ(elementC, elements[2].get());
221 }
222
223 class TestCustomElementDefinition : public CustomElementDefinition {
224 WTF_MAKE_NONCOPYABLE(TestCustomElementDefinition);
225 public:
226 TestCustomElementDefinition(const CustomElementDescriptor& descriptor)
227 : CustomElementDefinition(descriptor)
228 {
229 }
230
231 virtual ~TestCustomElementDefinition() = default;
232
233 bool runConstructor(Element* element) override
234 {
235 if (constructionStack().isEmpty()
236 || constructionStack().last() != element)
237 return false;
238 constructionStack().last().clear();
239 return true;
240 }
241 };
242
243 // Classes which use trace macros cannot be local because of the
244 // traceImpl template.
245 class LogUpgradeDefinition : public TestCustomElementDefinition {
246 WTF_MAKE_NONCOPYABLE(LogUpgradeDefinition);
247 public:
248 LogUpgradeDefinition(const CustomElementDescriptor& descriptor)
249 : TestCustomElementDefinition(descriptor)
250 {
251 }
252
253 DEFINE_INLINE_VIRTUAL_TRACE()
254 {
255 TestCustomElementDefinition::trace(visitor);
256 visitor->trace(m_element);
257 }
258
259 // TODO(dominicc): Make this class collect a vector of what's
260 // upgraded; it will be useful in more tests.
261 Member<Element> m_element;
262 uint32_t m_invocationCount;
263
264 bool runConstructor(Element* element) override
265 {
266 m_invocationCount++;
267 m_element = element;
268 return TestCustomElementDefinition::runConstructor(element);
269 }
270 };
271
272 class LogUpgradeBuilder final : public CustomElementDefinitionBuilder {
273 STACK_ALLOCATED();
274 WTF_MAKE_NONCOPYABLE(LogUpgradeBuilder);
275 public:
276 LogUpgradeBuilder() { }
277
278 bool checkConstructorIntrinsics() override { return true; }
279 bool checkConstructorNotRegistered() override { return true; }
280 bool checkPrototype() override { return true; }
281 CustomElementDefinition* build(
282 const CustomElementDescriptor& descriptor) {
283 return new LogUpgradeDefinition(descriptor);
284 }
285 };
286
287 TEST_F(CustomElementsRegistryFrameTest, define_upgradesInDocumentElements)
288 {
289 ScriptForbiddenScope doNotRelyOnScript;
290
291 Element* element = CreateElement("a-a").inDocument(&document());
292 document().documentElement()->appendChild(element);
293
294 LogUpgradeBuilder builder;
295 NonThrowableExceptionState shouldNotThrow;
296 registry().define(
297 "a-a",
298 builder,
299 ElementRegistrationOptions(),
300 shouldNotThrow);
301 LogUpgradeDefinition* definition =
302 static_cast<LogUpgradeDefinition*>(registry().definitionForName("a-a"));
303 EXPECT_EQ(1u, definition->m_invocationCount)
304 << "defining the element should have 'upgraded' the existing element";
305 EXPECT_EQ(element, definition->m_element)
306 << "the existing a-a element should have been upgraded";
307 }
308
309 // TODO(dominicc): Add tests which adjust the "is" attribute when type
310 // extensions are implemented.
311
312 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698