1 // Copyright 2014 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 "third_party/blink/renderer/core/html/forms/text_control_element.h"
6
7 #include <memory>
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "third_party/blink/renderer/core/dom/document.h"
10 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
11 #include "third_party/blink/renderer/core/dom/text.h"
12 #include "third_party/blink/renderer/core/editing/frame_selection.h"
13 #include "third_party/blink/renderer/core/editing/position.h"
14 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
15 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
16 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
17 #include "third_party/blink/renderer/core/loader/empty_clients.h"
18 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
19 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
20
21 namespace blink {
22
23 class TextControlElementTest : public testing::Test {
24 protected:
25 void SetUp() override;
26
Page() const27 DummyPageHolder& Page() const { return *dummy_page_holder_; }
GetDocument() const28 Document& GetDocument() const { return *document_; }
TextControl() const29 TextControlElement& TextControl() const { return *text_control_; }
Input() const30 HTMLInputElement& Input() const { return *input_; }
31
UpdateAllLifecyclePhases()32 void UpdateAllLifecyclePhases() {
33 GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
34 }
35
36 private:
37 std::unique_ptr<DummyPageHolder> dummy_page_holder_;
38
39 Persistent<Document> document_;
40 Persistent<TextControlElement> text_control_;
41 Persistent<HTMLInputElement> input_;
42 };
43
SetUp()44 void TextControlElementTest::SetUp() {
45 Page::PageClients page_clients;
46 FillWithEmptyClients(page_clients);
47 dummy_page_holder_ =
48 std::make_unique<DummyPageHolder>(IntSize(800, 600), &page_clients);
49
50 document_ = &dummy_page_holder_->GetDocument();
51 document_->documentElement()->setInnerHTML(
52 "<body><textarea id=textarea></textarea><input id=input /></body>");
53 UpdateAllLifecyclePhases();
54 text_control_ = ToTextControl(document_->getElementById("textarea"));
55 text_control_->focus();
56 input_ = To<HTMLInputElement>(document_->getElementById("input"));
57 }
58
TEST_F(TextControlElementTest,SetSelectionRange)59 TEST_F(TextControlElementTest, SetSelectionRange) {
60 EXPECT_EQ(0u, TextControl().selectionStart());
61 EXPECT_EQ(0u, TextControl().selectionEnd());
62
63 TextControl().SetInnerEditorValue("Hello, text form.");
64 EXPECT_EQ(0u, TextControl().selectionStart());
65 EXPECT_EQ(0u, TextControl().selectionEnd());
66
67 TextControl().SetSelectionRange(1, 3);
68 EXPECT_EQ(1u, TextControl().selectionStart());
69 EXPECT_EQ(3u, TextControl().selectionEnd());
70 }
71
TEST_F(TextControlElementTest,SetSelectionRangeDoesNotCauseLayout)72 TEST_F(TextControlElementTest, SetSelectionRangeDoesNotCauseLayout) {
73 Input().focus();
74 Input().setValue("Hello, input form.");
75 Input().SetSelectionRange(1, 1);
76
77 // Force layout if document().updateStyleAndLayoutIgnorePendingStylesheets()
78 // is called.
79 GetDocument().body()->AppendChild(GetDocument().createTextNode("foo"));
80 unsigned start_layout_count = Page().GetFrameView().LayoutCountForTesting();
81 EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
82 Input().SetSelectionRange(2, 2);
83 EXPECT_EQ(start_layout_count, Page().GetFrameView().LayoutCountForTesting());
84 }
85
TEST_F(TextControlElementTest,IndexForPosition)86 TEST_F(TextControlElementTest, IndexForPosition) {
87 Input().setValue("Hello");
88 HTMLElement* inner_editor = Input().InnerEditorElement();
89 EXPECT_EQ(5u, TextControlElement::IndexForPosition(
90 inner_editor,
91 Position(inner_editor, PositionAnchorType::kAfterAnchor)));
92 }
93
TEST_F(TextControlElementTest,ReadOnlyAttributeChangeEditability)94 TEST_F(TextControlElementTest, ReadOnlyAttributeChangeEditability) {
95 Input().setAttribute(html_names::kStyleAttr, "all:initial");
96 Input().setAttribute(html_names::kReadonlyAttr, "");
97 UpdateAllLifecyclePhases();
98 EXPECT_EQ(EUserModify::kReadOnly,
99 Input().InnerEditorElement()->GetComputedStyle()->UserModify());
100
101 Input().removeAttribute(html_names::kReadonlyAttr);
102 UpdateAllLifecyclePhases();
103 EXPECT_EQ(EUserModify::kReadWritePlaintextOnly,
104 Input().InnerEditorElement()->GetComputedStyle()->UserModify());
105 }
106
TEST_F(TextControlElementTest,DisabledAttributeChangeEditability)107 TEST_F(TextControlElementTest, DisabledAttributeChangeEditability) {
108 Input().setAttribute(html_names::kStyleAttr, "all:initial");
109 Input().setAttribute(html_names::kDisabledAttr, "");
110 UpdateAllLifecyclePhases();
111 EXPECT_EQ(EUserModify::kReadOnly,
112 Input().InnerEditorElement()->GetComputedStyle()->UserModify());
113
114 Input().removeAttribute(html_names::kDisabledAttr);
115 UpdateAllLifecyclePhases();
116 EXPECT_EQ(EUserModify::kReadWritePlaintextOnly,
117 Input().InnerEditorElement()->GetComputedStyle()->UserModify());
118 }
119
120 } // namespace blink
121