| // Copyright 2020 The Cobalt Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "cobalt/cssom/percentage_value.h" | |
| #include "cobalt/cssom/testing/mock_css_parser.h" // nogncheck | |
| #include "cobalt/dom/document.h" | |
| #include "cobalt/dom/dom_stat_tracker.h" | |
| #include "cobalt/dom/element.h" | |
| #include "cobalt/dom/html_element_context.h" | |
| #include "cobalt/dom/testing/fake_exception_state.h" | |
| #include "cobalt/dom/testing/mock_layout_boxes.h" | |
| #include "cobalt/dom/testing/stub_environment_settings.h" | |
| #include "testing/gmock/include/gmock/gmock.h" | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| using cobalt::cssom::PercentageValue; | |
| using cobalt::cssom::PropertyListValue; | |
| using cobalt::dom::testing::MockLayoutBoxes; | |
| using ::testing::NiceMock; | |
| using ::testing::_; | |
| using ::testing::Return; | |
| namespace cobalt { | |
| namespace dom { | |
| class MockDocumentObserver : public DocumentObserver { | |
| public: | |
| MOCK_METHOD0(OnLoad, void()); | |
| MOCK_METHOD0(OnMutation, void()); | |
| MOCK_METHOD0(OnFocusChanged, void()); | |
| }; | |
| class IntersectionCallbackMock { | |
| public: | |
| MOCK_METHOD2( | |
| NativeIntersectionObserverCallback, | |
| void(const IntersectionObserver::IntersectionObserverEntrySequence&, | |
| const scoped_refptr<IntersectionObserver>&)); | |
| }; | |
| class IntersectionObserverTest : public ::testing::Test { | |
| protected: | |
| IntersectionObserverTest() | |
| : dom_stat_tracker_(new DomStatTracker("IntersectionObserverTest")), | |
| html_element_context_(&environment_settings_, NULL, NULL, &css_parser_, | |
| NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | |
| NULL, NULL, NULL, NULL, dom_stat_tracker_.get(), | |
| "", base::kApplicationStateStarted, NULL, NULL), | |
| document_(new Document(&html_element_context_)) {} | |
| scoped_refptr<Document> document() { return document_; } | |
| scoped_refptr<IntersectionObserver> CreateIntersectionObserver(); | |
| void CreateDocumentWithTwoChildrenAndMockLayoutBoxes(); | |
| private: | |
| std::unique_ptr<DomStatTracker> dom_stat_tracker_; | |
| testing::StubEnvironmentSettings environment_settings_; | |
| NiceMock<cssom::testing::MockCSSParser> css_parser_; | |
| testing::FakeExceptionState exception_state_; | |
| HTMLElementContext html_element_context_; | |
| scoped_refptr<Document> document_; | |
| IntersectionCallbackMock callback_mock_; | |
| }; | |
| scoped_refptr<IntersectionObserver> | |
| IntersectionObserverTest::CreateIntersectionObserver() { | |
| // The intersection observer constructor will use the mock css parser to parse | |
| // the root margin property value. Because "ParsePropertyValue()"" returns a | |
| // "PropertyValue", which is not a built-in type, we must set a default | |
| // action and return type here. | |
| std::unique_ptr<PropertyListValue::Builder> builder( | |
| new PropertyListValue::Builder()); | |
| builder->push_back(new PercentageValue(0.0f)); | |
| scoped_refptr<PropertyListValue> property_list_value = | |
| new PropertyListValue(std::move(builder)); | |
| ON_CALL(css_parser_, ParsePropertyValue(_, _, _)) | |
| .WillByDefault(Return(property_list_value)); | |
| return new IntersectionObserver( | |
| document_, &css_parser_, | |
| base::Bind(&IntersectionCallbackMock::NativeIntersectionObserverCallback, | |
| base::Unretained(&callback_mock_)), | |
| &exception_state_); | |
| } | |
| void IntersectionObserverTest:: | |
| CreateDocumentWithTwoChildrenAndMockLayoutBoxes() { | |
| scoped_refptr<HTMLElement> first_child_element_ = | |
| document_->CreateElement("div")->AsHTMLElement(); | |
| document_->AppendChild(first_child_element_); | |
| scoped_refptr<HTMLElement> second_child_element_ = | |
| document_->CreateElement("div")->AsHTMLElement(); | |
| first_child_element_->AppendChild(second_child_element_); | |
| std::unique_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes); | |
| document_->document_element()->AsHTMLElement()->set_layout_boxes( | |
| std::unique_ptr<LayoutBoxes>(layout_boxes.release())); | |
| } | |
| TEST_F(IntersectionObserverTest, RegisterIntersectionObserverForTarget) { | |
| CreateDocumentWithTwoChildrenAndMockLayoutBoxes(); | |
| NiceMock<MockDocumentObserver> document_observer; | |
| document()->AddObserver(&document_observer); | |
| std::unique_ptr<ElementIntersectionObserverModule> | |
| element_intersection_observer_module = | |
| std::make_unique<ElementIntersectionObserverModule>( | |
| document()->last_element_child()); | |
| // Treat the second child element as an intersection observer target | |
| // (the first child element is the same as the document element). | |
| // When the observer is registered, it should record a mutation on the | |
| // document and invalidate the layout boxes up to the document element. | |
| EXPECT_NE(document()->document_element()->AsHTMLElement()->layout_boxes(), | |
| nullptr); | |
| EXPECT_CALL(document_observer, OnMutation()).Times(1); | |
| scoped_refptr<IntersectionObserver> intersection_observer = | |
| CreateIntersectionObserver(); | |
| element_intersection_observer_module->RegisterIntersectionObserverForTarget( | |
| intersection_observer); | |
| EXPECT_EQ(document()->document_element()->AsHTMLElement()->layout_boxes(), | |
| nullptr); | |
| } | |
| } // namespace dom | |
| } // namespace cobalt |