blob: 44dffc4bd13086346e44e726e15794a3e17291bf [file] [log] [blame]
// Copyright (c) 2017 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 "components/autofill/content/renderer/form_autofill_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/test/render_view_test.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebElementCollection.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebSelectElement.h"
using blink::WebDocument;
using blink::WebElement;
using blink::WebFormControlElement;
using blink::WebFormElement;
using blink::WebInputElement;
using blink::WebLocalFrame;
using blink::WebSelectElement;
using blink::WebString;
using blink::WebVector;
struct AutofillFieldUtilCase {
const char* description;
const char* html;
const char* expected_label;
};
const char kElevenChildren[] =
"<div id='target'>"
"<div>child0</div>"
"<div>child1</div>"
"<div>child2</div>"
"<div>child3</div>"
"<div>child4</div>"
"<div>child5</div>"
"<div>child6</div>"
"<div>child7</div>"
"<div>child8</div>"
"<div>child9</div>"
"<div>child10</div>"
"</div>";
const char kElevenChildrenExpected[] =
"child0child1child2child3child4child5child6child7child8";
const char kElevenChildrenNested[] =
"<div id='target'>"
"<div>child0"
"<div>child1"
"<div>child2"
"<div>child3"
"<div>child4"
"<div>child5"
"<div>child6"
"<div>child7"
"<div>child8"
"<div>child9"
"<div>child10"
"</div></div></div></div></div></div></div></div></div></div></div></div>";
// Take 10 elements -1 for target element, -1 as text is a leaf element.
const char kElevenChildrenNestedExpected[] = "child0child1child2child3child4";
const char kSkipElement[] =
"<div id='target'>"
"<div>child0</div>"
"<div class='skip'>child1</div>"
"<div>child2</div>"
"</div>";
// TODO(crbug.com/796918): Should be child0child2
const char kSkipElementExpected[] = "child0";
const char kDivTableExample1[] =
"<div>"
"<div>label</div><div><input id='target'/></div>"
"</div>";
const char kDivTableExample1Expected[] = "label";
const char kDivTableExample2[] =
"<div>"
"<div>label</div>"
"<div>should be skipped<input/></div>"
"<div><input id='target'/></div>"
"</div>";
const char kDivTableExample2Expected[] = "label";
const char kDivTableExample3[] =
"<div>"
"<div>should be skipped<input/></div>"
"<div>label</div>"
"<div><input id='target'/></div>"
"</div>";
const char kDivTableExample3Expected[] = "label";
const char kDivTableExample4[] =
"<div>"
"<div>should be skipped<input/></div>"
"label"
"<div><input id='target'/></div>"
"</div>";
// TODO(crbug.com/796918): Should be label
const char kDivTableExample4Expected[] = "";
const char kDivTableExample5[] =
"<div>"
"<div>label<div><input id='target'/></div>behind</div>"
"</div>";
// TODO(crbug.com/796918): Should be label
const char kDivTableExample5Expected[] = "labelbehind";
const char kDivTableExample6[] =
"<div>"
"<div>label<div><div>-<div><input id='target'/></div></div>"
"</div>";
// TODO(crbug.com/796918): Should be "label" or "label-"
const char kDivTableExample6Expected[] = "";
class FormAutofillUtilsTest : public content::RenderViewTest {
public:
FormAutofillUtilsTest() : content::RenderViewTest() {}
~FormAutofillUtilsTest() override {}
};
TEST_F(FormAutofillUtilsTest, FindChildTextTest) {
static const AutofillFieldUtilCase test_cases[] = {
{"simple test", "<div id='target'>test</div>", "test"},
{"Concatenate test", "<div id='target'><span>one</span>two</div>",
"onetwo"},
// TODO(crbug.com/796918): should be "onetwo"
{"Ignore input", "<div id='target'>one<input value='test'/>two</div>",
"one"},
{"Trim", "<div id='target'> one<span>two </span></div>", "onetwo"},
{"eleven children", kElevenChildren, kElevenChildrenExpected},
// TODO(crbug.com/796918): Depth is only 5 elements
{"eleven children nested", kElevenChildrenNested,
kElevenChildrenNestedExpected},
};
for (auto test_case : test_cases) {
SCOPED_TRACE(test_case.description);
LoadHTML(test_case.html);
WebLocalFrame* web_frame = GetMainFrame();
ASSERT_NE(nullptr, web_frame);
WebElement target = web_frame->GetDocument().GetElementById("target");
ASSERT_FALSE(target.IsNull());
EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label),
autofill::form_util::FindChildText(target));
}
}
TEST_F(FormAutofillUtilsTest, FindChildTextSkipElementTest) {
static const AutofillFieldUtilCase test_cases[] = {
{"Skip div element", kSkipElement, kSkipElementExpected},
};
for (auto test_case : test_cases) {
SCOPED_TRACE(test_case.description);
LoadHTML(test_case.html);
WebLocalFrame* web_frame = GetMainFrame();
ASSERT_NE(nullptr, web_frame);
WebElement target = web_frame->GetDocument().GetElementById("target");
ASSERT_FALSE(target.IsNull());
WebVector<WebElement> web_to_skip =
web_frame->GetDocument().QuerySelectorAll("div[class='skip']");
std::set<blink::WebNode> to_skip;
for (size_t i = 0; i < web_to_skip.size(); ++i) {
to_skip.insert(web_to_skip[i]);
}
EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label),
autofill::form_util::FindChildTextWithIgnoreListForTesting(
target, to_skip));
}
}
TEST_F(FormAutofillUtilsTest, InferLabelForElementTest) {
std::vector<base::char16> stop_words;
stop_words.push_back(static_cast<base::char16>('-'));
static const AutofillFieldUtilCase test_cases[] = {
{"DIV table test 1", kDivTableExample1, kDivTableExample1Expected},
{"DIV table test 2", kDivTableExample2, kDivTableExample2Expected},
{"DIV table test 3", kDivTableExample3, kDivTableExample3Expected},
{"DIV table test 4", kDivTableExample4, kDivTableExample4Expected},
{"DIV table test 5", kDivTableExample5, kDivTableExample5Expected},
{"DIV table test 6", kDivTableExample6, kDivTableExample6Expected},
};
for (auto test_case : test_cases) {
SCOPED_TRACE(test_case.description);
LoadHTML(test_case.html);
WebLocalFrame* web_frame = GetMainFrame();
ASSERT_NE(nullptr, web_frame);
WebElement target = web_frame->GetDocument().GetElementById("target");
ASSERT_FALSE(target.IsNull());
const WebFormControlElement form_target =
target.ToConst<WebFormControlElement>();
ASSERT_FALSE(form_target.IsNull());
EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label),
autofill::form_util::InferLabelForElementForTesting(form_target,
stop_words));
}
}