| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 | |
| 33 #include "FrameTestHelpers.h" | |
| 34 #include "URLTestHelpers.h" | |
| 35 #include "WebDOMEvent.h" | |
| 36 #include "WebDOMEventListener.h" | |
| 37 #include "WebDOMMutationEvent.h" | |
| 38 #include "WebDocument.h" | |
| 39 #include "WebElement.h" | |
| 40 #include "WebFrame.h" | |
| 41 #include "WebScriptSource.h" | |
| 42 #include "WebView.h" | |
| 43 #include <gtest/gtest.h> | |
| 44 #include <public/Platform.h> | |
| 45 #include <public/WebUnitTestSupport.h> | |
| 46 | |
| 47 using namespace WebKit; | |
| 48 | |
| 49 namespace { | |
| 50 | |
| 51 class TestWebDOMEventListener : public WebDOMEventListener { | |
| 52 public: | |
| 53 TestWebDOMEventListener() { } | |
| 54 virtual ~TestWebDOMEventListener() { } | |
| 55 | |
| 56 virtual void handleEvent(const WebDOMEvent& event) OVERRIDE | |
| 57 { | |
| 58 m_events.push_back(event); | |
| 59 } | |
| 60 | |
| 61 size_t eventCount() const { return m_events.size(); } | |
| 62 | |
| 63 WebDOMEvent eventAt(int index) const { return m_events.at(index); } | |
| 64 | |
| 65 void clearEvents() { m_events.clear(); } | |
| 66 | |
| 67 private: | |
| 68 std::vector<WebDOMEvent> m_events; | |
| 69 }; | |
| 70 | |
| 71 class WebDOMEventListenerTest : public testing::Test { | |
| 72 public: | |
| 73 WebDOMEventListenerTest() | |
| 74 : m_webView(0) | |
| 75 { | |
| 76 } | |
| 77 | |
| 78 virtual void SetUp() OVERRIDE | |
| 79 { | |
| 80 std::string baseURL("http://www.example.com/"); | |
| 81 std::string fileName("listener/mutation_event_listener.html"); | |
| 82 bool executeScript = true; | |
| 83 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL
.c_str()), WebString::fromUTF8(fileName.c_str())); | |
| 84 m_webView = FrameTestHelpers::createWebViewAndLoad(baseURL + fileName, e
xecuteScript); | |
| 85 } | |
| 86 | |
| 87 virtual void TearDown() OVERRIDE | |
| 88 { | |
| 89 m_webView->close(); | |
| 90 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); | |
| 91 } | |
| 92 | |
| 93 WebFrame* mainFrame() const | |
| 94 { | |
| 95 return m_webView->mainFrame(); | |
| 96 } | |
| 97 | |
| 98 WebDocument document() const | |
| 99 { | |
| 100 return mainFrame()->document(); | |
| 101 } | |
| 102 | |
| 103 void executeScript(const char* code) | |
| 104 { | |
| 105 mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(code))); | |
| 106 } | |
| 107 | |
| 108 | |
| 109 static WebString GetNodeID(const WebNode& node) | |
| 110 { | |
| 111 if (node.nodeType() != WebNode::ElementNode) | |
| 112 return WebString(); | |
| 113 WebElement element = node.toConst<WebElement>(); | |
| 114 return element.getAttribute("id"); | |
| 115 } | |
| 116 | |
| 117 protected: | |
| 118 WebView* m_webView; | |
| 119 }; | |
| 120 | |
| 121 | |
| 122 // Tests that the right mutation events are fired when a node is added/removed. | |
| 123 // Note that the DOMSubtreeModified event is fairly vage, it only tells you | |
| 124 // something changed for the target node. | |
| 125 TEST_F(WebDOMEventListenerTest, NodeAddedRemovedMutationEvent) | |
| 126 { | |
| 127 TestWebDOMEventListener eventListener; | |
| 128 document().addEventListener("DOMSubtreeModified", &eventListener, false); | |
| 129 | |
| 130 // Test adding a node. | |
| 131 executeScript("addElement('newNode')"); | |
| 132 ASSERT_EQ(1U, eventListener.eventCount()); | |
| 133 WebDOMEvent event = eventListener.eventAt(0); | |
| 134 ASSERT_TRUE(event.isMutationEvent()); | |
| 135 // No need to check any of the MutationEvent, WebKit does not set any. | |
| 136 EXPECT_EQ("DIV", event.target().nodeName()); | |
| 137 EXPECT_EQ("topDiv", GetNodeID(event.target())); | |
| 138 eventListener.clearEvents(); | |
| 139 | |
| 140 // Test removing a node. | |
| 141 executeScript("removeNode('div1')"); | |
| 142 ASSERT_EQ(1U, eventListener.eventCount()); | |
| 143 event = eventListener.eventAt(0); | |
| 144 ASSERT_TRUE(event.isMutationEvent()); | |
| 145 EXPECT_EQ("DIV", event.target().nodeName()); | |
| 146 EXPECT_EQ("topDiv", GetNodeID(event.target())); | |
| 147 } | |
| 148 | |
| 149 // Tests the right mutation event is fired when a text node is modified. | |
| 150 TEST_F(WebDOMEventListenerTest, TextNodeModifiedMutationEvent) | |
| 151 { | |
| 152 TestWebDOMEventListener eventListener; | |
| 153 document().addEventListener("DOMSubtreeModified", &eventListener, false); | |
| 154 executeScript("changeText('div2', 'Hello')"); | |
| 155 ASSERT_EQ(1U, eventListener.eventCount()); | |
| 156 WebDOMEvent event = eventListener.eventAt(0); | |
| 157 ASSERT_TRUE(event.isMutationEvent()); | |
| 158 ASSERT_EQ(WebNode::TextNode, event.target().nodeType()); | |
| 159 } | |
| 160 | |
| 161 // Tests the right mutation events are fired when an attribute is added/removed. | |
| 162 TEST_F(WebDOMEventListenerTest, AttributeMutationEvent) | |
| 163 { | |
| 164 TestWebDOMEventListener eventListener; | |
| 165 document().addEventListener("DOMSubtreeModified", &eventListener, false); | |
| 166 executeScript("document.getElementById('div2').setAttribute('myAttr'," | |
| 167 "'some value')"); | |
| 168 ASSERT_EQ(1U, eventListener.eventCount()); | |
| 169 WebDOMEvent event = eventListener.eventAt(0); | |
| 170 ASSERT_TRUE(event.isMutationEvent()); | |
| 171 EXPECT_EQ("DIV", event.target().nodeName()); | |
| 172 EXPECT_EQ("div2", GetNodeID(event.target())); | |
| 173 eventListener.clearEvents(); | |
| 174 | |
| 175 executeScript("document.getElementById('div2').removeAttribute('myAttr')"); | |
| 176 ASSERT_EQ(1U, eventListener.eventCount()); | |
| 177 event = eventListener.eventAt(0); | |
| 178 ASSERT_TRUE(event.isMutationEvent()); | |
| 179 EXPECT_EQ("DIV", event.target().nodeName()); | |
| 180 EXPECT_EQ("div2", GetNodeID(event.target())); | |
| 181 } | |
| 182 | |
| 183 // Tests destroying WebDOMEventListener and triggering events, we shouldn't | |
| 184 // crash. | |
| 185 TEST_F(WebDOMEventListenerTest, FireEventDeletedListener) | |
| 186 { | |
| 187 TestWebDOMEventListener* eventListener = new TestWebDOMEventListener(); | |
| 188 document().addEventListener("DOMSubtreeModified", eventListener, false); | |
| 189 delete eventListener; | |
| 190 executeScript("addElement('newNode')"); // That should fire an event. | |
| 191 } | |
| 192 | |
| 193 // Tests registering several events on the same WebDOMEventListener and | |
| 194 // triggering events. | |
| 195 TEST_F(WebDOMEventListenerTest, SameListenerMultipleEvents) | |
| 196 { | |
| 197 TestWebDOMEventListener eventListener; | |
| 198 const WebString kDOMSubtreeModifiedType("DOMSubtreeModified"); | |
| 199 const WebString kDOMNodeRemovedType("DOMNodeRemoved"); | |
| 200 document().addEventListener(kDOMSubtreeModifiedType, &eventListener, false); | |
| 201 WebElement div1Elem = document().getElementById("div1"); | |
| 202 div1Elem.addEventListener(kDOMNodeRemovedType, &eventListener, false); | |
| 203 | |
| 204 // Trigger a DOMSubtreeModified event by adding a node. | |
| 205 executeScript("addElement('newNode')"); | |
| 206 ASSERT_EQ(1U, eventListener.eventCount()); | |
| 207 WebDOMEvent event = eventListener.eventAt(0); | |
| 208 ASSERT_TRUE(event.isMutationEvent()); | |
| 209 EXPECT_EQ("DIV", event.target().nodeName()); | |
| 210 EXPECT_EQ("topDiv", GetNodeID(event.target())); | |
| 211 eventListener.clearEvents(); | |
| 212 | |
| 213 // Trigger for both event listener by removing the div1 node. | |
| 214 executeScript("removeNode('div1')"); | |
| 215 ASSERT_EQ(2U, eventListener.eventCount()); | |
| 216 // Not sure if the order of the events is important. Assuming no specific | |
| 217 // order. | |
| 218 WebString type1 = eventListener.eventAt(0).type(); | |
| 219 WebString type2 = eventListener.eventAt(1).type(); | |
| 220 EXPECT_TRUE(type1 == kDOMSubtreeModifiedType || type1 == kDOMNodeRemovedType
); | |
| 221 EXPECT_TRUE(type2 == kDOMSubtreeModifiedType || type2 == kDOMNodeRemovedType
); | |
| 222 EXPECT_TRUE(type1 != type2); | |
| 223 } | |
| 224 | |
| 225 // Tests removing event listeners. | |
| 226 TEST_F(WebDOMEventListenerTest, RemoveEventListener) | |
| 227 { | |
| 228 TestWebDOMEventListener eventListener; | |
| 229 const WebString kDOMSubtreeModifiedType("DOMSubtreeModified"); | |
| 230 // Adding twice the same listener for the same event, should be supported. | |
| 231 document().addEventListener(kDOMSubtreeModifiedType, &eventListener, false); | |
| 232 document().addEventListener(kDOMSubtreeModifiedType, &eventListener, false); | |
| 233 | |
| 234 // Add a node, that should trigger 2 events. | |
| 235 executeScript("addElement('newNode')"); | |
| 236 EXPECT_EQ(2U, eventListener.eventCount()); | |
| 237 eventListener.clearEvents(); | |
| 238 | |
| 239 // Remove one listener and trigger an event again. | |
| 240 document().removeEventListener( | |
| 241 kDOMSubtreeModifiedType, &eventListener, false); | |
| 242 executeScript("addElement('newerNode')"); | |
| 243 EXPECT_EQ(1U, eventListener.eventCount()); | |
| 244 eventListener.clearEvents(); | |
| 245 | |
| 246 // Remove the last listener and trigger yet another event. | |
| 247 document().removeEventListener( | |
| 248 kDOMSubtreeModifiedType, &eventListener, false); | |
| 249 executeScript("addElement('newererNode')"); | |
| 250 EXPECT_EQ(0U, eventListener.eventCount()); | |
| 251 } | |
| 252 | |
| 253 } // namespace | |
| OLD | NEW |