| Index: ios/chrome/browser/autofill/autofill_controller_js_unittest.mm
|
| diff --git a/ios/chrome/browser/autofill/autofill_controller_js_unittest.mm b/ios/chrome/browser/autofill/autofill_controller_js_unittest.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b2ecb6f49eb17893df3ec02c0a239306a49ba823
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/autofill/autofill_controller_js_unittest.mm
|
| @@ -0,0 +1,1796 @@
|
| +// Copyright 2013 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.
|
| +
|
| +#import <UIKit/UIKit.h>
|
| +
|
| +#include "base/format_macros.h"
|
| +#include "base/ios/ios_util.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "components/autofill/core/common/autofill_constants.h"
|
| +#include "ios/chrome/browser/web/chrome_web_test.h"
|
| +#import "ios/web/public/test/web_js_test.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "testing/gtest_mac.h"
|
| +
|
| +#if !defined(__has_feature) || !__has_feature(objc_arc)
|
| +#error "This file requires ARC support."
|
| +#endif
|
| +
|
| +// Unit tests for ios/chrome/browser/web/resources/autofill_controller.js
|
| +namespace {
|
| +
|
| +// Structure for getting element by name using JavaScripts.
|
| +struct ElementByName {
|
| + // The name of the element.
|
| + const char* element_name;
|
| + // The index in the elements that have |element_name|.
|
| + const int index;
|
| + // The option index if the element is a select, -1 otherwise.
|
| + const int option_index;
|
| +};
|
| +
|
| +// TODO(crbug.com/619982): MobileSafari/iOS10 corrected
|
| +// HTMLInputElement.maxLength with the specification
|
| +// ( https://bugs.webkit.org/show_bug.cgi?id=154906 ). Add support for old and
|
| +// new default maxLength value until we drop iOS 9.
|
| +NSString* GetDefaultMaxLengthString() {
|
| + return base::ios::IsRunningOnIOS10OrLater() ? @"-1" : @"524288";
|
| +}
|
| +NSNumber* GetDefaultMaxLength() {
|
| + return base::ios::IsRunningOnIOS10OrLater() ? @-1 : @524288;
|
| +}
|
| +
|
| +// Generates the JavaScript that gets an element by name.
|
| +NSString* GetElementByNameJavaScript(ElementByName element) {
|
| + NSString* query =
|
| + [NSString stringWithFormat:@"window.document.getElementsByName('%s')[%d]",
|
| + element.element_name, element.index];
|
| + if (element.option_index >= 0) {
|
| + query =
|
| + [query stringByAppendingFormat:@".options[%d]", element.option_index];
|
| + }
|
| + return query;
|
| +}
|
| +
|
| +// Generates an array of JavaScripts that get each element in |elements| by
|
| +// name.
|
| +NSArray* GetElementsByNameJavaScripts(const ElementByName elements[],
|
| + size_t elements_size) {
|
| + NSMutableArray* array = [NSMutableArray array];
|
| + for (size_t i = 0; i < elements_size; ++i) {
|
| + NSString* query = GetElementByNameJavaScript(elements[i]);
|
| + [array addObject:query];
|
| + }
|
| + return array;
|
| +}
|
| +
|
| +// clang-format off
|
| +NSString* kHTMLForTestingElements = @"<html><body>"
|
| + "<input type=hidden name='gl' value='us'>"
|
| + "<form name='testform'>"
|
| + " <input type=hidden name='hl' value='en'>"
|
| + " <input type='text' name='firstname'>"
|
| + " <input type='text' name='lastname'>"
|
| + " <input type='email' name='email'>"
|
| + " <input type='tel' name='phone'>"
|
| + " <input type='url' autocomplete='off' name='blog'>"
|
| + " <input type='number' name='expected number of clicks'>"
|
| + " <input type='password' autocomplete='off' name='pwd'>"
|
| + " <input type='checkbox' name='vehicle' value='Bike'>"
|
| + " <input type='checkbox' name='vehicle' value='Car'>"
|
| + " <input type='checkbox' name='vehicle' value='Rocket'>"
|
| + " <input type='radio' name='boolean' value='true'>"
|
| + " <input type='radio' name='boolean' value='false'>"
|
| + " <input type='radio' name='boolean' value='other'>"
|
| + " <label>State:"
|
| + " <select name='state'>"
|
| + " <option value='CA'>CA</option>"
|
| + " <option value='MA'>MA</option>"
|
| + " </select>"
|
| + " </label>"
|
| + " <label>Course:"
|
| + " <select name='course'>"
|
| + " <optgroup label='8.01 Physics I: Classical Mechanics'>"
|
| + " <option value='8.01.1'>Lecture 01: Powers of Ten"
|
| + " <option value='8.01.2'>Lecture 02: 1D Kinematics"
|
| + " <option value='8.01.3'>Lecture 03: Vectors"
|
| + " <optgroup label='8.02 Electricity and Magnestism'>"
|
| + " <option value='8.02.1'>Lecture 01: What holds our world together?"
|
| + " <option value='8.02.2'>Lecture 02: Electric Field"
|
| + " <option value='8.02.3'>Lecture 03: Electric Flux"
|
| + " </select>"
|
| + " </label>"
|
| + " <label>Cars:"
|
| + " <select name='cars' multiple>"
|
| + " <option value='volvo'>Volvo</option>"
|
| + " <option value='saab'>Saab</option>"
|
| + " <option value='opel'>Opel</option>"
|
| + " <option value='audi'>Audi</option>"
|
| + " </select>"
|
| + " </label>"
|
| + " <input type='submit' name='submit' value='Submit'>"
|
| + "</form>"
|
| + "</body></html>";
|
| +// clang-format on
|
| +
|
| +// A bit field mask to extract data from WebFormControlElement. They are from
|
| +// autofill_controller.js
|
| +enum ExtractMask {
|
| + EXTRACT_NONE = 0,
|
| + EXTRACT_VALUE = 1 << 0, // Extract value from WebFormControlElement.
|
| + EXTRACT_OPTION_TEXT = 1 << 1, // Extract option text from
|
| + // WebFormSelectElement. Only valid when
|
| + // |EXTRACT_VALUE| is set.
|
| + // This is used for form submission where
|
| + // human readable value is captured.
|
| + EXTRACT_OPTIONS = 1 << 2, // Extract options from
|
| + // WebFormControlElement.
|
| +};
|
| +
|
| +const ExtractMask kFormExtractMasks[] = {
|
| + EXTRACT_NONE, EXTRACT_VALUE, EXTRACT_OPTION_TEXT, EXTRACT_OPTIONS,
|
| +};
|
| +
|
| +// Gets the attributes to check for a mask in |kFormExtractMasks|.
|
| +NSArray* GetFormFieldAttributeListsToCheck(NSUInteger mask) {
|
| + if (!(mask & EXTRACT_VALUE)) {
|
| + return @[
|
| + @"name", @"form_control_type", @"autocomplete_attribute", @"max_length",
|
| + @"should_autocomplete", @"is_checkable"
|
| + ];
|
| + }
|
| +
|
| + if (mask & EXTRACT_OPTIONS) {
|
| + return @[
|
| + @"name", @"form_control_type", @"autocomplete_attribute", @"max_length",
|
| + @"should_autocomplete", @"is_checkable", @"value", @"option_values",
|
| + @"option_contents"
|
| + ];
|
| + }
|
| +
|
| + return @[
|
| + @"name", @"form_control_type", @"autocomplete_attribute", @"max_length",
|
| + @"should_autocomplete", @"is_checkable", @"value"
|
| + ];
|
| +}
|
| +
|
| +// ***** Clang-formatting is disabled for the following block of testdata *****
|
| +// clang-format off
|
| +
|
| +// Getters for form control element testing data. The returned data is
|
| +// an array consisting of an html fragment followed by an array
|
| +// of dictionaries containing the expected field attributes for elements in the
|
| +// given html fragment.
|
| +NSArray* GetTestFormInputElementWithLabelFromPrevious() {
|
| + return @[
|
| + @("* First name: "
|
| + "<INPUT type='text' name='firstname' value='John'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* First name:'", @"label",
|
| + @"'firstname'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromPreviousSpan() {
|
| + return @[
|
| + @("* Last name<span>:</span> "
|
| + "<INPUT type='text' name='lastname' value='John'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Last name:'", @"label",
|
| + @"'lastname'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromPreviousParagraph() {
|
| + return @[
|
| + @("<p>* Email:</p> "
|
| + "<INPUT type='email' name='email' value='john@example.com'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Email:'", @"label",
|
| + @"'email'", @"name",
|
| + @"'email'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'john@example.com'", @"value",
|
| + @"'john@example.com'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromPreviousLabel() {
|
| + return @[
|
| + @("<label>* Telephone: </label> "
|
| + "<INPUT type='tel' id='telephone' value='12345678'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Telephone:'", @"label",
|
| + @"'telephone'", @"name",
|
| + @"'tel'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'12345678'", @"value",
|
| + @"'12345678'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored() {
|
| + return @[
|
| + @("Other Text <label>* Blog:</label> "
|
| + "<INPUT type='url' autocomplete='off' value='www.jogh.blog'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Blog:'", @"label",
|
| + @"''", @"name",
|
| + @"'url'", @"form_control_type",
|
| + @"'off'", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"false", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'www.jogh.blog'", @"value",
|
| + @"'www.jogh.blog'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromPreviousTextSpanBr() {
|
| + return @[
|
| + @("* Expected visits<span>:</span> <br>"
|
| + "<INPUT type='number' name='expected number of clicks'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Expected visits:'", @"label",
|
| + @"'expected number of clicks'", @"name",
|
| + @"'number'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"''", @"value",
|
| + @"''", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan() {
|
| + return @[
|
| + @("Other <br> * Password<span>:</span> "
|
| + "<INPUT type='password' autocomplete='off' name='pwd'/>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Password:'", @"label",
|
| + @"'pwd'", @"name",
|
| + @"'password'", @"form_control_type",
|
| + @"'off'", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"false", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"''", @"value",
|
| + @"''", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromListItem() {
|
| + return @[
|
| + @("<LI>"
|
| + "<LABEL><EM>*</EM> Code:</LABEL>"
|
| + "<INPUT type='text' id='first code' value='415'/>"
|
| + "<INPUT type='text' id='middle code' value='555'/>"
|
| + "<INPUT type='text' id='last code' value='1212'/>"
|
| + "</LI>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Code:'", @"label",
|
| + @"'first code'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'415'", @"value",
|
| + @"'415'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Code:'", @"label",
|
| + @"'middle code'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'555'", @"value",
|
| + @"'555'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Code:'", @"label",
|
| + @"'last code'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'1212'", @"value",
|
| + @"'1212'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromTableColumnTD() {
|
| + return @[
|
| + @("<TABLE>"
|
| + "<TR>"
|
| + " <TD>* First name:</TD>"
|
| + " <TD><INPUT type='text' id='tabletdname' value='John'/></TD>"
|
| + "</TR>"
|
| + "<TR>"
|
| + " <TD>Email:</TD>"
|
| + " <TD><INPUT type='email' id='tabletdemail'"
|
| + " value='john@example.com'/></TD>"
|
| + "</TR>"
|
| + "</TABLE>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* First name:'", @"label",
|
| + @"'tabletdname'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'Email:'", @"label",
|
| + @"'tabletdemail'", @"name",
|
| + @"'email'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'john@example.com'", @"value",
|
| + @"'john@example.com'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromTableColumnTH() {
|
| + return @[
|
| + @("<TABLE>"
|
| + "<TR>"
|
| + " <TH>* First name:</TH>"
|
| + " <TD><INPUT type='text' name='nameintableth' value='John'/></TD>"
|
| + "</TR>"
|
| + "<TR>"
|
| + " <TD>Email:</TD>"
|
| + " <TD><INPUT type='email' id='emailtableth'"
|
| + " value='john@example.com'/></TD>"
|
| + "</TR>"
|
| + "</TABLE>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* First name:'", @"label",
|
| + @"'nameintableth'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'Email:'", @"label",
|
| + @"'emailtableth'", @"name",
|
| + @"'email'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'john@example.com'", @"value",
|
| + @"'john@example.com'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromTableNested() {
|
| + return @[
|
| + @("<TABLE>"
|
| + "<TR>"
|
| + " <TD><FONT>* First </FONT><FONT>name:</FONT></TD>"
|
| + " <TD><INPUT type='text' id='nametablenested' value='John'/></TD>"
|
| + "</TR>"
|
| + "</TABLE>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* First name:'", @"label",
|
| + @"'nametablenested'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromTableRow() {
|
| + return @[
|
| + @("<TABLE>"
|
| + "<TR>"
|
| + " <TD>* <FONT>First </FONT><FONT>name:</FONT></TD>"
|
| + "</TR>"
|
| + "<TR>"
|
| + " <TD><INPUT type='text' name='nametablerow' value='John'/></TD>"
|
| + "</TR>"
|
| + "</TABLE>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* First name:'", @"label",
|
| + @"'nametablerow'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromDivTable() {
|
| + return @[
|
| + @("<DIV>* First name:<BR>"
|
| + "<SPAN>"
|
| + "<INPUT type='text' name='namedivtable' value='John'>"
|
| + "</SPAN>"
|
| + "</DIV>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* First name:'", @"label",
|
| + @"'namedivtable'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'John'", @"value",
|
| + @"'John'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormInputElementWithLabelFromDefinitionList() {
|
| + return @[
|
| + @("<DL>"
|
| + " <DT>"
|
| + " <SPAN>"
|
| + " *"
|
| + " </SPAN>"
|
| + " <SPAN>"
|
| + " Favorite Sport"
|
| + " </SPAN>"
|
| + " </DT>"
|
| + " <DD>"
|
| + " <FONT>"
|
| + " <INPUT type='favorite sport' name='sport' value='Tennis'/>"
|
| + " </FONT>"
|
| + " </DD>"
|
| + " </DL>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'* Favorite Sport'", @"label",
|
| + @"'sport'", @"name",
|
| + @"'text'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + GetDefaultMaxLengthString(), @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"false", @"is_checkable",
|
| + @"'Tennis'", @"value",
|
| + @"'Tennis'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestInputRadio() {
|
| + return @[
|
| + @("<input type='radio' name='boolean' value='true'/> True"
|
| + "<input type='radio' name='boolean' value='false'/> False"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'True'", @"label",
|
| + @"'boolean'", @"name",
|
| + @"'radio'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"true", @"is_checkable",
|
| + @"'true'", @"value",
|
| + @"'true'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'False'", @"label",
|
| + @"'boolean'", @"name",
|
| + @"'radio'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"true", @"is_checkable",
|
| + @"'false'", @"value",
|
| + @"'false'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestInputCheckbox() {
|
| + return @[
|
| + @("<input type='checkbox' name='vehicle' value='Bike'> Bicycle"
|
| + "<input type='checkbox' name='vehicle' value='Car'> Automobile"
|
| + "<input type='checkbox' name='vehicle' value='Rocket'> Missile"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'Bicycle'", @"label",
|
| + @"'vehicle'", @"name",
|
| + @"'checkbox'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"true", @"is_checkable",
|
| + @"'Bike'", @"value",
|
| + @"'Bike'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'Automobile'", @"label",
|
| + @"'vehicle'", @"name",
|
| + @"'checkbox'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"true", @"is_checkable",
|
| + @"'Car'", @"value",
|
| + @"'Car'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil],
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'Missile'", @"label",
|
| + @"'vehicle'", @"name",
|
| + @"'checkbox'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"true", @"is_checkable",
|
| + @"'Rocket'", @"value",
|
| + @"'Rocket'", @"value_option_text",
|
| + @"undefined", @"option_values",
|
| + @"undefined", @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormSelectElement() {
|
| + return @[
|
| + @(" <label>State:"
|
| + " <select name='state'>"
|
| + " <option value='CA'>California</option>"
|
| + " <option value='TX'>Texas</option>"
|
| + " </select>"
|
| + " </label>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'State:'", @"label",
|
| + @"'state'", @"name",
|
| + @"'select-one'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"undefined", @"is_checkable",
|
| + @"'CA'", @"value",
|
| + @"'California'", @"value_option_text",
|
| + @[@"'CA'", @"'TX'"], @"option_values",
|
| + @[@"'California'", @"'Texas'"], @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +NSArray* GetTestFormSelectElementWithOptgroup() {
|
| + return @[
|
| + @(" <label>Course:"
|
| + " <select name='course'>"
|
| + " <optgroup label='8.01 Physics I: Classical Mechanics'>"
|
| + " <option value='8.01.1'>Lecture 01: Powers of Ten"
|
| + " <option value='8.01.2'>Lecture 02: 1D Kinematics"
|
| + " <option value='8.01.3'>Lecture 03: Vectors"
|
| + " <optgroup label='8.02 Electricity and Magnestism'>"
|
| + " <option value='8.02.1'>Lecture 01: What holds world together?"
|
| + " <option value='8.02.2'>Lecture 02: Electric Field"
|
| + " <option value='8.02.3'>Lecture 03: Electric Flux"
|
| + " </select>"
|
| + " </label>"),
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + @"'Course:'", @"label",
|
| + @"'course'", @"name",
|
| + @"'select-one'", @"form_control_type",
|
| + @"undefined", @"autocomplete_attribute",
|
| + @"undefined", @"max_length",
|
| + @"true", @"should_autocomplete",
|
| + @"undefined", @"is_checkable",
|
| + @"'8.01.1'", @"value",
|
| + @"'Lecture 01: Powers of Ten'", @"value_option_text",
|
| + @[@"'8.01.1'",
|
| + @"'8.01.2'",
|
| + @"'8.01.3'",
|
| + @"'8.02.1'",
|
| + @"'8.02.2'",
|
| + @"'8.02.3'"], @"option_values",
|
| + @[@"'Lecture 01: Powers of Ten'",
|
| + @"'Lecture 02: 1D Kinematics'",
|
| + @"'Lecture 03: Vectors'",
|
| + @"'Lecture 01: What holds world together?'",
|
| + @"'Lecture 02: Electric Field'",
|
| + @"'Lecture 03: Electric Flux'"], @"option_contents",
|
| + nil]];
|
| +}
|
| +
|
| +// clang-format on
|
| +
|
| +// Generates JavaScripts to check a JavaScripts object |results| with the
|
| +// expected values given in |expected|, which is a dictionary with string
|
| +// values for all the keys other than @"option_vaues" and @"option_contents";
|
| +// the values of @"option_vaues" and @"option_contents" are arrays of
|
| +// strings or undefined. Only attributes in |attributes_to_check| are checked.
|
| +// A different expected value is chosen in |expected| for different
|
| +// |extract_mask|.
|
| +NSString* GenerateElementItemVerifyingJavaScripts(
|
| + NSString* results,
|
| + NSUInteger extract_mask,
|
| + NSDictionary* expected,
|
| + NSArray* attributes_to_check) {
|
| + NSMutableArray* verifying_javascripts = [NSMutableArray array];
|
| +
|
| + for (NSString* attribute in attributes_to_check) {
|
| + if ([attribute isEqualToString:@"option_values"] ||
|
| + [attribute isEqualToString:@"option_contents"]) {
|
| + id expected_value = [expected objectForKey:attribute];
|
| + if ([expected_value isKindOfClass:[NSString class]]) {
|
| + [verifying_javascripts
|
| + addObject:[NSString
|
| + stringWithFormat:@"%@['%@']===%@", results, attribute,
|
| + [expected objectForKey:attribute]]];
|
| + } else {
|
| + for (NSUInteger i = 0; i < [(NSArray*)expected_value count]; ++i) {
|
| + [verifying_javascripts
|
| + addObject:[NSString
|
| + stringWithFormat:@"%@['%@'][%" PRIuNS "] === %@",
|
| + results, attribute, i,
|
| + [expected_value objectAtIndex:i]]];
|
| + }
|
| + }
|
| + } else {
|
| + NSString* expected_value = [expected objectForKey:attribute];
|
| + // Option text is used as value for extract_mask 1 << 1
|
| + if ((extract_mask & 1 << 1) && [attribute isEqualToString:@"value"])
|
| + expected_value = [expected objectForKey:@"value_option_text"];
|
| + [verifying_javascripts
|
| + addObject:[NSString stringWithFormat:@"%@['%@']===%@", results,
|
| + attribute, expected_value]];
|
| + }
|
| + }
|
| +
|
| + return [verifying_javascripts componentsJoinedByString:@"&&"];
|
| +}
|
| +
|
| +// Generates JavaScripts to check a JavaScripts array |results| with the
|
| +// expected values given in |expected|, which is an array of dictionaries; each
|
| +// dictionary is the expected values of the corresponding item in |results|.
|
| +// Only attributes in |attributes_to_check| are checked. A different expected
|
| +// value is chosen in |expected| for different |extract_mask|.
|
| +NSString* GenerateTestItemVerifyingJavaScripts(NSString* results,
|
| + NSUInteger extract_mask,
|
| + NSArray* expected,
|
| + NSArray* attributed_to_check) {
|
| + NSMutableArray* verifying_javascripts = [NSMutableArray array];
|
| +
|
| + NSUInteger controlCount = 0;
|
| + for (NSUInteger indexOfTestData = 0; indexOfTestData < [expected count];
|
| + ++indexOfTestData) {
|
| + NSArray* expectedData = [expected objectAtIndex:indexOfTestData];
|
| + for (NSUInteger i = 1; i < [expectedData count]; ++i, ++controlCount) {
|
| + NSDictionary* expected = [expectedData objectAtIndex:i];
|
| + NSString* itemVerifyingJavaScripts =
|
| + GenerateElementItemVerifyingJavaScripts(
|
| + [NSString stringWithFormat:@"%@['fields'][%" PRIuNS "]", results,
|
| + controlCount],
|
| + extract_mask, expected, attributed_to_check);
|
| + [verifying_javascripts addObject:itemVerifyingJavaScripts];
|
| + }
|
| + }
|
| + return [verifying_javascripts componentsJoinedByString:@"&&"];
|
| +}
|
| +
|
| +// Test fixture to test autofill controller.
|
| +class AutofillControllerJsTest : public web::WebJsTest<ChromeWebTest> {
|
| + public:
|
| + AutofillControllerJsTest()
|
| + : web::WebJsTest<ChromeWebTest>(@[ @"autofill_controller" ]) {}
|
| +
|
| + protected:
|
| + // Helper method that EXPECTs |javascript| evaluation on page
|
| + // |kHTMLForTestingElements| with expectation given by
|
| + // |elements_with_true_expected|.
|
| + void TestExecutingBooleanJavaScriptOnElement(
|
| + NSString* javascript,
|
| + const ElementByName elements_with_true_expected[],
|
| + size_t size_elements_with_true_expected);
|
| +
|
| + // Helper method that EXPECTs
|
| + // |__gCrWeb.autofill.webFormControlElementToFormField|. This method applies
|
| + // |__gCrWeb.autofill.webFormControlElementToFormField| on each element in
|
| + // |test_data| with all possible extract masks and verify the results.
|
| + void TestWebFormControlElementToFormField(NSArray* test_data,
|
| + NSString* tag_name);
|
| +
|
| + // Helper method for testing |javascripts_statement| that evalutate
|
| + // |attribute_name| of the elements in |test_data| which has tag name
|
| + // |tag_name|. EXPECTs JavaScript evaluation on
|
| + // "window.document.getElementsByTagName()"
|
| + void TestInputElementDataEvaluation(NSString* javascripts_statement,
|
| + NSString* attribute_name,
|
| + NSArray* test_data,
|
| + NSString* tag_name);
|
| +
|
| + // Helper method that EXPECTs |__gCrWeb.autofill.webFormElementToFormData| on
|
| + // a form element obtained by |get_form_element_javascripts|. The results
|
| + // are verified with |verifying_java_scripts|.
|
| + void TestWebFormElementToFormDataForOneForm(
|
| + NSString* get_form_element_javascripts,
|
| + NSUInteger extract_mask,
|
| + NSString* expected_result,
|
| + NSString* verifying_javascripts);
|
| +
|
| + // EXPECTs |__gCrWeb.autofill.webFormElementToFormData| on all the test data.
|
| + void TestWebFormElementToFormData(NSArray* test_items);
|
| +
|
| + // EXPECTs |__gCrWeb.autofill.extractNewForms| on |html|.
|
| + void TestExtractNewForms(NSString* html,
|
| + BOOL is_origin_window_location,
|
| + NSArray* expected_items);
|
| +};
|
| +
|
| +void AutofillControllerJsTest::TestExecutingBooleanJavaScriptOnElement(
|
| + NSString* javascript,
|
| + const ElementByName elements_with_true_expected[],
|
| + size_t size_elements_with_true_expected) {
|
| + // Elements in |kHTMLForTestingElements|.
|
| + const ElementByName elementsByName[] = {
|
| + {"hl", 0, -1},
|
| + {"firstname", 0, -1},
|
| + {"lastname", 0, -1},
|
| + {"email", 0, -1},
|
| + {"phone", 0, -1},
|
| + {"blog", 0, -1},
|
| + {"expected number of clicks", 0, -1},
|
| + {"pwd", 0, -1},
|
| + {"vehicle", 0, -1},
|
| + {"vehicle", 1, -1},
|
| + {"vehicle", 2, -1},
|
| + {"boolean", 0, -1},
|
| + {"boolean", 1, -1},
|
| + {"boolean", 2, -1},
|
| + {"state", 0, -1},
|
| + {"state", 0, 0},
|
| + {"state", 0, 1},
|
| + {"course", 0, -1},
|
| + {"course", 0, 0},
|
| + {"course", 0, 1},
|
| + {"course", 0, 2},
|
| + {"course", 0, 3},
|
| + {"course", 0, 4},
|
| + {"course", 0, 5},
|
| + {"cars", 0, -1},
|
| + {"cars", 0, 0},
|
| + {"cars", 0, 1},
|
| + {"cars", 0, 2},
|
| + {"cars", 0, 3},
|
| + {"submit", 0, -1},
|
| + };
|
| +
|
| + LoadHtmlAndInject(kHTMLForTestingElements);
|
| + ExecuteBooleanJavaScriptOnElementsAndCheck(
|
| + javascript,
|
| + GetElementsByNameJavaScripts(elementsByName, arraysize(elementsByName)),
|
| + GetElementsByNameJavaScripts(elements_with_true_expected,
|
| + size_elements_with_true_expected));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, HasTagName) {
|
| + const ElementByName elements_expecting_true[] = {
|
| + {"hl", 0, -1},
|
| + {"firstname", 0, -1},
|
| + {"lastname", 0, -1},
|
| + {"email", 0, -1},
|
| + {"phone", 0, -1},
|
| + {"blog", 0, -1},
|
| + {"expected number of clicks", 0, -1},
|
| + {"pwd", 0, -1},
|
| + {"vehicle", 0, -1},
|
| + {"vehicle", 1, -1},
|
| + {"vehicle", 2, -1},
|
| + {"boolean", 0, -1},
|
| + {"boolean", 1, -1},
|
| + {"boolean", 2, -1},
|
| + {"submit", 0, -1},
|
| + };
|
| +
|
| + TestExecutingBooleanJavaScriptOnElement(
|
| + @"__gCrWeb.autofill.hasTagName(%@, 'input')", elements_expecting_true,
|
| + arraysize(elements_expecting_true));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, CombineAndCollapseWhitespace) {
|
| + LoadHtmlAndInject(@"<html><body></body></html>");
|
| +
|
| + EXPECT_NSEQ(@"foobar", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace('"
|
| + @"foo', 'bar', false)"));
|
| + EXPECT_NSEQ(@"foo bar", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + @"'foo', 'bar', true)"));
|
| + EXPECT_NSEQ(@"foo bar", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + "'foo ', 'bar', false)"));
|
| + EXPECT_NSEQ(@"foo bar", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + "'foo', ' bar', false)"));
|
| + EXPECT_NSEQ(@"foo bar", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + "'foo', ' bar', true)"));
|
| + EXPECT_NSEQ(@"foo bar", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + "'foo ', ' bar', false)"));
|
| + EXPECT_NSEQ(@"foobar ", ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + "'foo', 'bar ', false)"));
|
| + EXPECT_NSEQ(@" foo bar",
|
| + ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.combineAndCollapseWhitespace("
|
| + "' foo', 'bar', true)"));
|
| +}
|
| +
|
| +void AutofillControllerJsTest::TestInputElementDataEvaluation(
|
| + NSString* javascripts_statement,
|
| + NSString* attribute_name,
|
| + NSArray* test_data,
|
| + NSString* tag_name) {
|
| + NSString* html_fragment = [test_data objectAtIndex:0U];
|
| + LoadHtmlAndInject(html_fragment);
|
| +
|
| + for (NSUInteger i = 1; i < [test_data count]; ++i) {
|
| + NSString* get_element_javascripts = [NSString
|
| + stringWithFormat:@"window.document.getElementsByTagName('%@')[%" PRIuNS
|
| + "]",
|
| + tag_name, i - 1];
|
| + id actual = ExecuteJavaScriptWithFormat(
|
| + @"%@(%@) === %@", javascripts_statement, get_element_javascripts,
|
| + [[test_data objectAtIndex:i] objectForKey:attribute_name]);
|
| + EXPECT_NSEQ(@YES, actual);
|
| + }
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromPrevious) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromPrevious", @"label",
|
| + GetTestFormInputElementWithLabelFromPrevious(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromPreviousSpan) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromPrevious", @"label",
|
| + GetTestFormInputElementWithLabelFromPreviousSpan(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromPreviousParagraph) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromPrevious", @"label",
|
| + GetTestFormInputElementWithLabelFromPreviousParagraph(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromPreviousLabel) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromPrevious", @"label",
|
| + GetTestFormInputElementWithLabelFromPreviousLabel(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromPreviousLabelOtherIgnored) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromPrevious", @"label",
|
| + GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored(),
|
| + @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromPreviousTextBrAndSpan) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromPrevious", @"label",
|
| + GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromListItem) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromListItem", @"label",
|
| + GetTestFormInputElementWithLabelFromListItem(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromTableColumnTD) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromTableColumn", @"label",
|
| + GetTestFormInputElementWithLabelFromTableColumnTD(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromTableColumnTH) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromTableColumn", @"label",
|
| + GetTestFormInputElementWithLabelFromTableColumnTH(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromTableColumnNested) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromTableColumn", @"label",
|
| + GetTestFormInputElementWithLabelFromTableNested(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromTableRow) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromTableRow", @"label",
|
| + GetTestFormInputElementWithLabelFromTableRow(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromDivTable) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromDivTable", @"label",
|
| + GetTestFormInputElementWithLabelFromDivTable(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelFromDefinitionList) {
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelFromDefinitionList", @"label",
|
| + GetTestFormInputElementWithLabelFromDefinitionList(), @"input");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, InferLabelForElement) {
|
| + NSArray* testingElements = @[
|
| + GetTestFormInputElementWithLabelFromPrevious(),
|
| + GetTestFormInputElementWithLabelFromPreviousSpan(),
|
| + GetTestFormInputElementWithLabelFromPreviousParagraph(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabel(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextSpanBr(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan(),
|
| + GetTestFormInputElementWithLabelFromListItem(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTD(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTH(),
|
| + GetTestFormInputElementWithLabelFromTableNested(),
|
| + GetTestFormInputElementWithLabelFromTableRow(),
|
| + GetTestFormInputElementWithLabelFromDivTable(),
|
| + GetTestFormInputElementWithLabelFromDefinitionList(), GetTestInputRadio(),
|
| + GetTestInputCheckbox()
|
| + ];
|
| + for (NSArray* testingElement in testingElements) {
|
| + TestInputElementDataEvaluation(@"__gCrWeb.autofill.inferLabelForElement",
|
| + @"label", testingElement, @"input");
|
| + }
|
| +
|
| + TestInputElementDataEvaluation(@"__gCrWeb.autofill.inferLabelForElement",
|
| + @"label", GetTestFormSelectElement(),
|
| + @"select");
|
| +
|
| + TestInputElementDataEvaluation(
|
| + @"__gCrWeb.autofill.inferLabelForElement", @"label",
|
| + GetTestFormSelectElementWithOptgroup(), @"select");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, IsAutofillableElement) {
|
| + const ElementByName elements_expecting_true[] = {
|
| + {"firstname", 0, -1}, {"lastname", 0, -1},
|
| + {"email", 0, -1}, {"phone", 0, -1},
|
| + {"blog", 0, -1}, {"expected number of clicks", 0, -1},
|
| + {"pwd", 0, -1}, {"vehicle", 0, -1},
|
| + {"vehicle", 1, -1}, {"vehicle", 2, -1},
|
| + {"boolean", 0, -1}, {"boolean", 1, -1},
|
| + {"boolean", 2, -1}, {"state", 0, -1},
|
| + {"course", 0, -1},
|
| + };
|
| +
|
| + TestExecutingBooleanJavaScriptOnElement(
|
| + @"__gCrWeb.autofill.isAutofillableElement(%@)", elements_expecting_true,
|
| + arraysize(elements_expecting_true));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, GetOptionStringsFromElement) {
|
| + ElementByName testing_elements[] = {
|
| + {"state", 0, -1}, {"course", 0, -1}, {"cars", 0, -1}};
|
| +
|
| + LoadHtmlAndInject(kHTMLForTestingElements);
|
| + ExecuteJavaScriptOnElementsAndCheck(
|
| + @"var field = {};"
|
| + "__gCrWeb.autofill.getOptionStringsFromElement(%@, field);"
|
| + "__gCrWeb.stringify(field);",
|
| + GetElementsByNameJavaScripts(testing_elements,
|
| + arraysize(testing_elements)),
|
| + @[
|
| + @("{\"option_values\":[\"CA\",\"MA\"],"
|
| + "\"option_contents\":[\"CA\",\"MA\"]}"),
|
| + @("{\"option_values\":["
|
| + "\"8.01.1\",\"8.01.2\",\"8.01.3\","
|
| + "\"8.02.1\",\"8.02.2\",\"8.02.3\"],"
|
| + "\"option_contents\":["
|
| + "\"Lecture 01: Powers of Ten\","
|
| + "\"Lecture 02: 1D Kinematics\","
|
| + "\"Lecture 03: Vectors\","
|
| + "\"Lecture 01: What holds our world together?\","
|
| + "\"Lecture 02: Electric Field\","
|
| + "\"Lecture 03: Electric Flux\""
|
| + "]}"),
|
| + @("{\"option_values\":[\"volvo\",\"saab\",\"opel\",\"audi\"],"
|
| + "\"option_contents\":[\"Volvo\",\"Saab\",\"Opel\",\"Audi\"]}")
|
| + ]);
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, FillFormField) {
|
| + LoadHtmlAndInject(kHTMLForTestingElements);
|
| +
|
| + // Test text and select elements of which the value should be changed.
|
| + const ElementByName elements[] = {
|
| + {"firstname", 0, -1}, {"state", 0, -1},
|
| + };
|
| + NSArray* values = @[
|
| + @"new name",
|
| + @"MA",
|
| + ];
|
| + for (size_t i = 0; i < arraysize(elements); ++i) {
|
| + NSString* get_element_javascript = GetElementByNameJavaScript(elements[i]);
|
| + NSString* new_value = [values objectAtIndex:i];
|
| + EXPECT_NSEQ(new_value,
|
| + ExecuteJavaScriptWithFormat(
|
| + @"var element=%@;var data={'value':'%@'};"
|
| + @"__gCrWeb.autofill.fillFormField(data, element);"
|
| + @"element.value",
|
| + get_element_javascript, new_value));
|
| + }
|
| +
|
| + // Test clickable elements, of which 'checked' should be updated.
|
| + ElementByName checkable_elements[] = {
|
| + {"vehicle", 0, -1}, {"vehicle", 1, -1}, {"vehicle", 2, -1},
|
| + {"boolean", 0, -1}, {"boolean", 1, -1}, {"boolean", 2, -1},
|
| + };
|
| + const bool final_is_checked_values[] = {
|
| + true, false, true, false, true, true,
|
| + };
|
| + for (size_t i = 0; i < arraysize(checkable_elements); ++i) {
|
| + NSString* get_element_javascript =
|
| + GetElementByNameJavaScript(checkable_elements[i]);
|
| + bool is_checked = final_is_checked_values[i];
|
| +
|
| + EXPECT_NSEQ(
|
| + @(is_checked),
|
| + ExecuteJavaScriptWithFormat(
|
| + @"var element=%@; var value=element.value; "
|
| + @"var data={'value':value,'is_checked':%@};"
|
| + @"__gCrWeb.autofill.fillFormField(data, element); element.checked",
|
| + get_element_javascript, is_checked ? @"true" : @"false"));
|
| + }
|
| +
|
| + // Test elements of which the value should not be changed.
|
| + ElementByName unchanged_elements[] = {
|
| + {"hl", 0, -1}, // hidden element
|
| + {"state", 0, 0}, // option element
|
| + {"state", 0, 1}, // option element
|
| + };
|
| + for (size_t i = 0; i < arraysize(unchanged_elements); ++i) {
|
| + NSString* get_element_javascript =
|
| + GetElementByNameJavaScript(unchanged_elements[i]);
|
| + NSString* actual = ExecuteJavaScriptWithFormat(
|
| + @"var element=%@;"
|
| + @"var oldValue=element.value; var data={'value':'new'};"
|
| + @"__gCrWeb.autofill.fillFormField(data, element);"
|
| + @"element.value === oldValue",
|
| + get_element_javascript);
|
| + EXPECT_NSEQ(@YES, actual);
|
| + }
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, IsTextInput) {
|
| + const ElementByName elements_expecting_true[] = {
|
| + {"firstname", 0, -1}, {"lastname", 0, -1},
|
| + {"email", 0, -1}, {"phone", 0, -1},
|
| + {"blog", 0, -1}, {"expected number of clicks", 0, -1},
|
| + {"pwd", 0, -1},
|
| + };
|
| +
|
| + TestExecutingBooleanJavaScriptOnElement(@"__gCrWeb.autofill.isTextInput(%@)",
|
| + elements_expecting_true,
|
| + arraysize(elements_expecting_true));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, IsSelectElement) {
|
| + const ElementByName elements_expecting_true[] = {
|
| + {"state", 0, -1}, {"course", 0, -1},
|
| + };
|
| +
|
| + TestExecutingBooleanJavaScriptOnElement(
|
| + @"__gCrWeb.autofill.isSelectElement(%@)", elements_expecting_true,
|
| + arraysize(elements_expecting_true));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, IsCheckableElement) {
|
| + const ElementByName elements_expecting_true[] = {
|
| + {"vehicle", 0, -1}, {"vehicle", 1, -1}, {"vehicle", 2, -1},
|
| + {"boolean", 0, -1}, {"boolean", 1, -1}, {"boolean", 2, -1},
|
| + };
|
| +
|
| + TestExecutingBooleanJavaScriptOnElement(
|
| + @"__gCrWeb.autofill.isCheckableElement(%@)", elements_expecting_true,
|
| + arraysize(elements_expecting_true));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, IsAutofillableInputElement) {
|
| + const ElementByName elements_expecting_true[] = {
|
| + {"firstname", 0, -1}, {"lastname", 0, -1},
|
| + {"email", 0, -1}, {"phone", 0, -1},
|
| + {"blog", 0, -1}, {"expected number of clicks", 0, -1},
|
| + {"pwd", 0, -1}, {"vehicle", 0, -1},
|
| + {"vehicle", 1, -1}, {"vehicle", 2, -1},
|
| + {"boolean", 0, -1}, {"boolean", 1, -1},
|
| + {"boolean", 2, -1},
|
| + };
|
| +
|
| + TestExecutingBooleanJavaScriptOnElement(
|
| + @"__gCrWeb.autofill.isAutofillableInputElement(%@)",
|
| + elements_expecting_true, arraysize(elements_expecting_true));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, ExtractAutofillableElements) {
|
| + LoadHtmlAndInject(kHTMLForTestingElements);
|
| + ElementByName expected_elements[] = {
|
| + {"firstname", 0, -1}, {"lastname", 0, -1},
|
| + {"email", 0, -1}, {"phone", 0, -1},
|
| + {"blog", 0, -1}, {"expected number of clicks", 0, -1},
|
| + {"pwd", 0, -1}, {"vehicle", 0, -1},
|
| + {"vehicle", 1, -1}, {"vehicle", 2, -1},
|
| + {"boolean", 0, -1}, {"boolean", 1, -1},
|
| + {"boolean", 2, -1}, {"state", 0, -1},
|
| + };
|
| + NSArray* expected = GetElementsByNameJavaScripts(
|
| + expected_elements, arraysize(expected_elements));
|
| +
|
| + NSString* parameter = @"window.document.getElementsByTagName('form')[0]";
|
| + for (NSUInteger index = 0; index < [expected count]; index++) {
|
| + EXPECT_NSEQ(@YES,
|
| + ExecuteJavaScriptWithFormat(
|
| + @"var controlElements="
|
| + "__gCrWeb.autofill.extractAutofillableElementsInForm(%@);"
|
| + "controlElements[%" PRIuNS "] === %@",
|
| + parameter, index, expected[index]));
|
| + }
|
| +}
|
| +
|
| +void AutofillControllerJsTest::TestWebFormControlElementToFormField(
|
| + NSArray* test_data,
|
| + NSString* tag_name) {
|
| + LoadHtmlAndInject([test_data firstObject]);
|
| +
|
| + for (NSUInteger i = 0; i < arraysize(kFormExtractMasks); ++i) {
|
| + ExtractMask extract_mask = kFormExtractMasks[i];
|
| + NSArray* attributes_to_check =
|
| + GetFormFieldAttributeListsToCheck(extract_mask);
|
| +
|
| + for (NSUInteger i = 1; i < [test_data count]; ++i) {
|
| + NSString* get_element_to_test =
|
| + [NSString stringWithFormat:@"var element = "
|
| + "window.document.getElementsByTagName('%"
|
| + "@')[%" PRIuNS "]",
|
| + tag_name, i - 1];
|
| + NSDictionary* expected = [test_data objectAtIndex:i];
|
| + // Generates JavaScripts to verify the results. Parameter |results| is
|
| + // @"field" as in the evaluation JavaScripts the results are returned in
|
| + // |field|.
|
| + NSString* verifying_javascripts = GenerateElementItemVerifyingJavaScripts(
|
| + @"field", extract_mask, expected, attributes_to_check);
|
| + EXPECT_NSEQ(@YES,
|
| + ExecuteJavaScriptWithFormat(
|
| + @"%@; var field = {};"
|
| + "__gCrWeb.autofill.webFormControlElementToFormField("
|
| + " element, %u, field);"
|
| + "%@",
|
| + get_element_to_test, extract_mask, verifying_javascripts))
|
| + << base::SysNSStringToUTF8([NSString
|
| + stringWithFormat:
|
| + @"webFormControlElementToFormField actual results are: "
|
| + @"%@, \n"
|
| + "expected to be verified by %@",
|
| + ExecuteJavaScriptWithFormat(
|
| + @"%@; var field = {};"
|
| + "__gCrWeb.autofill.webFormControlElementToFormField("
|
| + " element, %u, field);__gCrWeb.stringify(field);",
|
| + get_element_to_test, extract_mask),
|
| + verifying_javascripts]);
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, WebFormControlElementToFormField) {
|
| + NSArray* test_input_elements = @[
|
| + GetTestFormInputElementWithLabelFromPrevious(),
|
| + GetTestFormInputElementWithLabelFromPreviousSpan(),
|
| + GetTestFormInputElementWithLabelFromPreviousParagraph(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabel(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextSpanBr(),
|
| + GetTestFormInputElementWithLabelFromListItem(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTD(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTH(),
|
| + GetTestFormInputElementWithLabelFromTableNested(),
|
| + GetTestFormInputElementWithLabelFromTableRow(),
|
| + GetTestFormInputElementWithLabelFromDivTable(),
|
| + GetTestFormInputElementWithLabelFromDefinitionList(), GetTestInputRadio(),
|
| + GetTestInputCheckbox()
|
| + ];
|
| + for (NSArray* test_element in test_input_elements) {
|
| + TestWebFormControlElementToFormField(test_element, @"input");
|
| + }
|
| +
|
| + TestWebFormControlElementToFormField(GetTestFormSelectElement(), @"select");
|
| + TestWebFormControlElementToFormField(GetTestFormSelectElementWithOptgroup(),
|
| + @"select");
|
| +}
|
| +
|
| +void AutofillControllerJsTest::TestWebFormElementToFormDataForOneForm(
|
| + NSString* get_form_element_javascripts,
|
| + NSUInteger extract_mask,
|
| + NSString* expected_result,
|
| + NSString* verifying_javascripts) {
|
| + NSString* actual = ExecuteJavaScriptWithFormat(
|
| + @"var form={}; var field={};"
|
| + "(__gCrWeb.autofill.webFormElementToFormData("
|
| + "window, %@, null, %" PRIuNS ", form, field) === %@) && %@",
|
| + get_form_element_javascripts, extract_mask, expected_result,
|
| + verifying_javascripts);
|
| +
|
| + EXPECT_NSEQ(@YES, actual) << base::SysNSStringToUTF8([NSString
|
| + stringWithFormat:@"Actual:\n%@; expected to be verifyied by\n%@",
|
| + ExecuteJavaScriptWithFormat(
|
| + @"var form={};"
|
| + "__gCrWeb.autofill."
|
| + "webFormElementToFormData(window, %@, null,"
|
| + "%" PRIuNS ", form, null);"
|
| + "__gCrWeb.stringify(form);",
|
| + get_form_element_javascripts, extract_mask),
|
| + verifying_javascripts]);
|
| +}
|
| +
|
| +void AutofillControllerJsTest::TestWebFormElementToFormData(
|
| + NSArray* test_items) {
|
| + NSString* form_html_fragment =
|
| + @"<form name='TestForm' action='http://cnn.com' method='post'>";
|
| + for (NSUInteger i = 0; i < [test_items count]; ++i) {
|
| + form_html_fragment = [form_html_fragment
|
| + stringByAppendingString:[[test_items objectAtIndex:i]
|
| + objectAtIndex:0U]];
|
| + }
|
| + form_html_fragment = [form_html_fragment stringByAppendingString:@"</form>"];
|
| + LoadHtmlAndInject(form_html_fragment);
|
| +
|
| + NSString* parameter = @"document.getElementsByTagName('form')[0]";
|
| + for (NSUInteger extract_index = 0;
|
| + extract_index < arraysize(kFormExtractMasks); ++extract_index) {
|
| + NSString* expected_result = @"true";
|
| + // We don't verify 'action' here as action is generated as a complete url
|
| + // and here data url is used.
|
| + NSMutableArray* verifying_javascripts = [NSMutableArray
|
| + arrayWithObjects:@"form['name'] === 'TestForm'",
|
| + @"form['method'] === 'post'",
|
| + @"form['origin'] === window.location.href", nil];
|
| + ExtractMask extract_mask = kFormExtractMasks[extract_index];
|
| + [verifying_javascripts
|
| + addObject:GenerateTestItemVerifyingJavaScripts(
|
| + @"form", extract_mask, test_items,
|
| + GetFormFieldAttributeListsToCheck(extract_mask))];
|
| + TestWebFormElementToFormDataForOneForm(
|
| + parameter, extract_mask, expected_result,
|
| + [verifying_javascripts componentsJoinedByString:@"&&"]);
|
| + }
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, WebFormElementToFormData) {
|
| + NSArray* test_elements = @[
|
| + GetTestFormInputElementWithLabelFromPrevious(),
|
| + GetTestFormInputElementWithLabelFromPreviousSpan(),
|
| + GetTestFormInputElementWithLabelFromPreviousParagraph(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabel(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextSpanBr(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan(),
|
| + GetTestFormInputElementWithLabelFromListItem(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTD(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTH(),
|
| + GetTestFormInputElementWithLabelFromTableNested(),
|
| + GetTestFormInputElementWithLabelFromTableRow(),
|
| + GetTestFormInputElementWithLabelFromDivTable(),
|
| + GetTestFormInputElementWithLabelFromDefinitionList(), GetTestInputRadio(),
|
| + GetTestInputCheckbox(), GetTestFormSelectElement(),
|
| + GetTestFormSelectElementWithOptgroup()
|
| + ];
|
| + // Test a form that has a signle item in the array.
|
| + for (NSArray* testElement in test_elements) {
|
| + TestWebFormElementToFormData(@[ testElement ]);
|
| + }
|
| +
|
| + // Also test a form that has all the above items.
|
| + TestWebFormElementToFormData(test_elements);
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest,
|
| + DISABLED_WebFormElementToFormDataTooManyFields) {
|
| + NSString* html_fragment =
|
| + @"<FORM name='Test' action='http://c.com' method='post'>";
|
| + // In autofill_controller.js, the maximum number of parsable element is 100
|
| + // (__gCrWeb.autofill.MAX_PARSEABE_FIELDS = 100). Here an HTML page with 101
|
| + // elements is generated for testing.
|
| + for (NSUInteger index = 0; index < 101; ++index) {
|
| + html_fragment =
|
| + [html_fragment stringByAppendingFormat:@"<INPUT type='text'/>"];
|
| + }
|
| + html_fragment = [html_fragment stringByAppendingFormat:@"</FORM>"];
|
| +
|
| + LoadHtmlAndInject(html_fragment);
|
| + TestWebFormElementToFormDataForOneForm(
|
| + @"document.getElementsByTagName('form')[0]", 1, @"false", @"true");
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, WebFormElementToFormEmpty) {
|
| + NSString* html_fragment =
|
| + @"<FORM name='Test' action='http://c.com' method='post'>";
|
| + html_fragment = [html_fragment stringByAppendingFormat:@"</FORM>"];
|
| +
|
| + LoadHtmlAndInject(html_fragment);
|
| + TestWebFormElementToFormDataForOneForm(
|
| + @"document.getElementsByTagName('form')[0]", 1, @"false", @"true");
|
| +}
|
| +
|
| +void AutofillControllerJsTest::TestExtractNewForms(
|
| + NSString* html,
|
| + BOOL is_origin_window_location,
|
| + NSArray* expected_items) {
|
| + LoadHtmlAndInject(html);
|
| + // Generates verifying javascripts.
|
| + NSMutableArray* verifying_javascripts = [NSMutableArray array];
|
| + for (NSUInteger i = 0U; i < [expected_items count]; ++i) {
|
| + [verifying_javascripts
|
| + addObject:[NSString stringWithFormat:@"forms[%" PRIuNS
|
| + "]['name'] === 'TestForm'",
|
| + i]];
|
| + [verifying_javascripts
|
| + addObject:[NSString stringWithFormat:@"forms[%" PRIuNS
|
| + "]['method'] === 'post'",
|
| + i]];
|
| + if (is_origin_window_location) {
|
| + [verifying_javascripts
|
| + addObject:[NSString stringWithFormat:
|
| + @"forms[%" PRIuNS
|
| + "]['origin'] === window.location.href",
|
| + i]];
|
| + }
|
| + // This is the extract mask used by
|
| + // __gCrWeb.autofill.extractNewForms.
|
| + NSUInteger extract_mask = EXTRACT_VALUE | EXTRACT_OPTIONS;
|
| + [verifying_javascripts
|
| + addObject:GenerateTestItemVerifyingJavaScripts(
|
| + [NSString stringWithFormat:@"forms[%" PRIuNS "]", i],
|
| + extract_mask, [expected_items objectAtIndex:i],
|
| + // The relevant attributes for the extract mask
|
| + GetFormFieldAttributeListsToCheck(extract_mask))];
|
| + }
|
| +
|
| + NSString* actual = ExecuteJavaScriptWithFormat(
|
| + @"var forms = __gCrWeb.autofill.extractNewForms(%" PRIuS "); %@",
|
| + autofill::kRequiredFieldsForPredictionRoutines,
|
| + [verifying_javascripts componentsJoinedByString:@"&&"]);
|
| +
|
| + EXPECT_NSEQ(@YES, actual) << base::SysNSStringToUTF8([NSString
|
| + stringWithFormat:@"actually forms = %@, "
|
| + "but it is expected to be verified by %@",
|
| + ExecuteJavaScriptWithFormat(
|
| + @"var forms = __gCrWeb.autofill.extractNewForms("
|
| + "%" PRIuS "); __gCrWeb.stringify(forms)",
|
| + autofill::kRequiredFieldsForPredictionRoutines),
|
| + verifying_javascripts]);
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, ExtractFormsAndFormElements) {
|
| + NSArray* testFirstFormItems = @[
|
| + GetTestFormInputElementWithLabelFromPrevious(),
|
| + GetTestFormInputElementWithLabelFromPreviousSpan(),
|
| + GetTestFormInputElementWithLabelFromPreviousParagraph(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabel(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextSpanBr(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan(),
|
| + GetTestFormInputElementWithLabelFromListItem(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTD(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTH(),
|
| + GetTestFormInputElementWithLabelFromTableNested(),
|
| + GetTestFormInputElementWithLabelFromTableRow(),
|
| + GetTestFormInputElementWithLabelFromDivTable(),
|
| + GetTestFormInputElementWithLabelFromDefinitionList(), GetTestInputRadio(),
|
| + GetTestInputCheckbox()
|
| + ];
|
| + NSArray* testSecondFormItems = @[
|
| + GetTestFormInputElementWithLabelFromDivTable(), GetTestFormSelectElement(),
|
| + GetTestFormSelectElementWithOptgroup()
|
| + ];
|
| + NSArray* test_forms = @[ testFirstFormItems, testSecondFormItems ];
|
| +
|
| + NSString* html = @"<html><body>";
|
| + for (NSArray* testFormItems in test_forms) {
|
| + html = [html
|
| + stringByAppendingString:
|
| + @"<form name='TestForm' action='http://c.com' method='post'>"];
|
| + for (NSArray* testItem in testFormItems) {
|
| + html = [html stringByAppendingString:[testItem objectAtIndex:0U]];
|
| + }
|
| + html = [html stringByAppendingFormat:@"</form>"];
|
| + }
|
| + html = [html stringByAppendingFormat:@"</body></html>"];
|
| + TestExtractNewForms(html, true, test_forms);
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, ExtractFormsAndFormElementsNestedFrame) {
|
| + NSArray* testFirstFormItems = @[
|
| + GetTestFormInputElementWithLabelFromPrevious(),
|
| + GetTestFormInputElementWithLabelFromPreviousSpan(),
|
| + GetTestFormInputElementWithLabelFromPreviousParagraph(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabel(),
|
| + GetTestFormInputElementWithLabelFromPreviousLabelOtherIgnored(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextSpanBr(),
|
| + GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan(),
|
| + GetTestFormInputElementWithLabelFromListItem(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTD(),
|
| + GetTestFormInputElementWithLabelFromTableColumnTH(),
|
| + GetTestFormInputElementWithLabelFromTableNested(),
|
| + GetTestFormInputElementWithLabelFromTableRow(),
|
| + GetTestFormInputElementWithLabelFromDivTable(),
|
| + GetTestFormInputElementWithLabelFromDefinitionList(), GetTestInputRadio(),
|
| + GetTestInputCheckbox()
|
| + ];
|
| + NSArray* testSecondFormItems = @[
|
| + GetTestFormInputElementWithLabelFromDivTable(), GetTestFormSelectElement(),
|
| + GetTestFormSelectElementWithOptgroup()
|
| + ];
|
| + NSArray* test_forms = @[ testFirstFormItems, testSecondFormItems ];
|
| +
|
| + // Test an html that has nested frames.
|
| + NSString* nested_frame_html_fragment = @"<html><body>";
|
| + for (NSUInteger i = 0; i < [test_forms count]; ++i) {
|
| + NSArray* test_elements = [test_forms objectAtIndex:i];
|
| + NSString* form_string =
|
| + @"<form name='TestForm' action='http://c.com' method='post'>";
|
| + for (NSUInteger j = 0; j < [test_elements count]; ++j) {
|
| + form_string =
|
| + [form_string stringByAppendingString:[[test_elements objectAtIndex:j]
|
| + objectAtIndex:0U]];
|
| + }
|
| + form_string = [form_string stringByAppendingFormat:@"</form>"];
|
| +
|
| + if (i == 0) {
|
| + nested_frame_html_fragment =
|
| + [nested_frame_html_fragment stringByAppendingString:form_string];
|
| + } else {
|
| + nested_frame_html_fragment = [nested_frame_html_fragment
|
| + stringByAppendingString:
|
| + [NSString stringWithFormat:@"<iframe srcdoc=\"%@\"></iframe>",
|
| + form_string]];
|
| + }
|
| + }
|
| + nested_frame_html_fragment =
|
| + [nested_frame_html_fragment stringByAppendingString:@"</body></html>"];
|
| + TestExtractNewForms(nested_frame_html_fragment, false, test_forms);
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest,
|
| + ExtractFormsAndFormElementsWithFormAssociatedElementsOutOfForm) {
|
| + NSString* html = @"<html><body>"
|
| + "<form id='testform'></form>"
|
| + "1 <input type='text' name='name1' form='testform'></input>"
|
| + "2 <input type='text' name='name2' form='testform'></input>"
|
| + "3 <input type='text' name='name3' form='testform'></input>"
|
| + "4 <input type='text' name='name4' form='testform'></input>"
|
| + "</body></html>";
|
| + LoadHtmlAndInject(html);
|
| +
|
| + NSString* verifying_javascript = @"forms[0]['fields'][0]['name']==='name1' &&"
|
| + @"forms[0]['fields'][0]['label']==='1' &&"
|
| + @"forms[0]['fields'][1]['name']==='name2' &&"
|
| + @"forms[0]['fields'][1]['label']==='2' &&"
|
| + @"forms[0]['fields'][2]['name']==='name3' &&"
|
| + @"forms[0]['fields'][2]['label']==='3' &&"
|
| + @"forms[0]['fields'][3]['name']==='name4' &&"
|
| + @"forms[0]['fields'][3]['label']==='4'";
|
| + EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat(
|
| + @"var forms = "
|
| + "__gCrWeb.autofill.extractNewForms(1); %@",
|
| + verifying_javascript));
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, ExtractForms) {
|
| + NSString* html = @"<html><body>";
|
| + html =
|
| + [html stringByAppendingString:
|
| + @"<form name='TestForm' action='http://c.com' method='post'>"];
|
| + html = [html
|
| + stringByAppendingString:[GetTestFormInputElementWithLabelFromPrevious()
|
| + objectAtIndex:0U]];
|
| + html =
|
| + [html stringByAppendingString:[GetTestInputCheckbox() objectAtIndex:0U]];
|
| + html = [html stringByAppendingString:
|
| + [GetTestFormInputElementWithLabelFromTableColumnTH()
|
| + objectAtIndex:0U]];
|
| + html = [html stringByAppendingString:
|
| + [GetTestFormInputElementWithLabelFromPreviousTextBrAndSpan()
|
| + objectAtIndex:0U]];
|
| + html = [html
|
| + stringByAppendingString:[GetTestFormSelectElement() objectAtIndex:0U]];
|
| + html = [html stringByAppendingFormat:@"</form>"];
|
| + html = [html stringByAppendingFormat:@"</body></html>"];
|
| +
|
| + LoadHtmlAndInject(html);
|
| +
|
| + NSDictionary* expected = @{
|
| + @"name" : @"TestForm",
|
| + @"method" : @"post",
|
| + @"fields" : @[
|
| + @{
|
| + @"name" : @"firstname",
|
| + @"form_control_type" : @"text",
|
| + @"max_length" : GetDefaultMaxLength(),
|
| + @"should_autocomplete" : @true,
|
| + @"is_checkable" : @false,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"John",
|
| + @"label" : @"* First name:"
|
| + },
|
| + @{
|
| + @"name" : @"vehicle",
|
| + @"form_control_type" : @"checkbox",
|
| + @"should_autocomplete" : @true,
|
| + @"is_checkable" : @true,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"Bike",
|
| + @"label" : @"Bicycle"
|
| + },
|
| + @{
|
| + @"name" : @"vehicle",
|
| + @"form_control_type" : @"checkbox",
|
| + @"should_autocomplete" : @true,
|
| + @"is_checkable" : @true,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"Car",
|
| + @"label" : @"Automobile"
|
| + },
|
| + @{
|
| + @"name" : @"vehicle",
|
| + @"form_control_type" : @"checkbox",
|
| + @"should_autocomplete" : @true,
|
| + @"is_checkable" : @true,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"Rocket",
|
| + @"label" : @"Missile"
|
| + },
|
| + @{
|
| + @"name" : @"nameintableth",
|
| + @"form_control_type" : @"text",
|
| + @"max_length" : GetDefaultMaxLength(),
|
| + @"should_autocomplete" : @true,
|
| + @"is_checkable" : @false,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"John",
|
| + @"label" : @"* First name:"
|
| + },
|
| + @{
|
| + @"name" : @"emailtableth",
|
| + @"form_control_type" : @"email",
|
| + @"max_length" : GetDefaultMaxLength(),
|
| + @"should_autocomplete" : @true,
|
| + @"is_checkable" : @false,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"john@example.com",
|
| + @"label" : @"Email:"
|
| + },
|
| + @{
|
| + @"name" : @"pwd",
|
| + @"form_control_type" : @"password",
|
| + @"autocomplete_attribute" : @"off",
|
| + @"max_length" : GetDefaultMaxLength(),
|
| + @"should_autocomplete" : @false,
|
| + @"is_checkable" : @false,
|
| + @"is_focusable" : @true,
|
| + @"value" : @"",
|
| + @"label" : @"* Password:"
|
| + },
|
| + @{
|
| + @"name" : @"state",
|
| + @"form_control_type" : @"select-one",
|
| + @"is_focusable" : @1,
|
| + @"option_values" : @[ @"CA", @"TX" ],
|
| + @"option_contents" : @[ @"California", @"Texas" ],
|
| + @"should_autocomplete" : @1,
|
| + @"value" : @"CA",
|
| + @"label" : @"State:"
|
| + }
|
| + ]
|
| + };
|
| +
|
| + NSString* result = ExecuteJavaScriptWithFormat(
|
| + @"__gCrWeb.autofill.extractForms(%zu)",
|
| + autofill::kRequiredFieldsForPredictionRoutines);
|
| + NSDictionary* resultDict = [NSJSONSerialization
|
| + JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding]
|
| + options:0
|
| + error:nil];
|
| + ASSERT_NSNE(nil, resultDict);
|
| +
|
| + NSDictionary* forms = [resultDict[@"forms"] objectAtIndex:0];
|
| + [expected enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
|
| + EXPECT_NSEQ(forms[key], obj);
|
| + }];
|
| +
|
| + // Test with Object.prototype.toJSON override.
|
| + result = ExecuteJavaScriptWithFormat(
|
| + @"Object.prototype.toJSON=function(){return 'abcde';};"
|
| + "__gCrWeb.autofill.extractForms(%zu)",
|
| + autofill::kRequiredFieldsForPredictionRoutines);
|
| + resultDict = [NSJSONSerialization
|
| + JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding]
|
| + options:0
|
| + error:nil];
|
| + ASSERT_NSNE(nil, resultDict);
|
| +
|
| + forms = [resultDict[@"forms"] objectAtIndex:0];
|
| + [expected enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
|
| + EXPECT_NSEQ(forms[key], obj);
|
| + }];
|
| +
|
| + // Test with Array.prototype.toJSON override.
|
| + result = ExecuteJavaScriptWithFormat(
|
| + @"Array.prototype.toJSON=function(){return 'abcde';};"
|
| + "__gCrWeb.autofill.extractForms(%zu)",
|
| + autofill::kRequiredFieldsForPredictionRoutines);
|
| + resultDict = [NSJSONSerialization
|
| + JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding]
|
| + options:0
|
| + error:nil];
|
| + ASSERT_NSNE(nil, resultDict);
|
| +
|
| + forms = [resultDict[@"forms"] objectAtIndex:0];
|
| + [expected enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
|
| + EXPECT_NSEQ(forms[key], obj);
|
| + }];
|
| +}
|
| +
|
| +TEST_F(AutofillControllerJsTest, FillActiveFormField) {
|
| + LoadHtmlAndInject(kHTMLForTestingElements);
|
| +
|
| + NSString* newValue = @"new value";
|
| + EXPECT_NSEQ(newValue,
|
| + ExecuteJavaScriptWithFormat(
|
| + @"var element=document.getElementsByName('lastname')[0];"
|
| + "element.focus();"
|
| + "var data={\"name\":\"lastname\",\"value\":\"%@\"};"
|
| + "__gCrWeb.autofill.fillActiveFormField(data);"
|
| + "element.value",
|
| + newValue));
|
| +
|
| + EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat(
|
| + @"var element=document.getElementsByName('gl')[0];"
|
| + "element.focus();"
|
| + "var oldValue = element.value;"
|
| + "var data={\"name\":\"lastname\",\"value\":\"%@\"};"
|
| + "__gCrWeb.autofill.fillActiveFormField(data);"
|
| + "element.value === oldValue",
|
| + newValue))
|
| + << "A non-form element's value should changed.";
|
| +}
|
| +
|
| +// iOS version of FormAutofillTest.FormCache_ExtractNewForms from
|
| +// chrome/renderer/autofill/form_autofill_browsertest.cc
|
| +TEST_F(AutofillControllerJsTest, ExtractNewForms) {
|
| + NSArray* testCases = @[
|
| + // An empty form should not be extracted
|
| + @{
|
| + @"html" : @"<FORM name='TestForm' action='http://buh.com' method='post'>"
|
| + "</FORM>",
|
| + @"expected_forms" : @0
|
| + },
|
| + // A form with less than three fields with no autocomplete type(s) should
|
| + // not be extracted.
|
| + @{
|
| + @"html" : @"<FORM name='TestForm' action='http://buh.com' method='post'>"
|
| + " <INPUT type='name' id='firstname'/>"
|
| + "</FORM>",
|
| + @"expected_forms" : @0
|
| + },
|
| + // A form with less than three fields with at least one autocomplete type
|
| + // should be extracted.
|
| + @{
|
| + @"html" : @"<FORM name='TestForm' action='http://buh.com' method='post'>"
|
| + " <INPUT type='name' id='firstname'"
|
| + " autocomplete='given-name'/>"
|
| + "</FORM>",
|
| + @"expected_forms" : @1
|
| + },
|
| + // A form with three or more fields should be extracted.
|
| + @{
|
| + @"html" : @"<FORM name='TestForm' action='http://buh.com' method='post'>"
|
| + " <INPUT type='text' id='firstname'/>"
|
| + " <INPUT type='text' id='lastname'/>"
|
| + " <INPUT type='text' id='email'/>"
|
| + " <INPUT type='submit' value='Send'/>"
|
| + "</FORM>",
|
| + @"expected_forms" : @1
|
| + }
|
| + ];
|
| +
|
| + for (NSDictionary* testCase in testCases) {
|
| + LoadHtmlAndInject(testCase[@"html"]);
|
| +
|
| + NSString* result =
|
| + ExecuteJavaScriptWithFormat(@"__gCrWeb.autofill.extractForms(%zu)",
|
| + autofill::kRequiredFieldsForUpload);
|
| + NSDictionary* resultDict = [NSJSONSerialization
|
| + JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding]
|
| + options:0
|
| + error:nil];
|
| + ASSERT_NSNE(nil, resultDict);
|
| + NSUInteger expectedCount =
|
| + [testCase[@"expected_forms"] unsignedIntegerValue];
|
| + EXPECT_EQ(expectedCount, [resultDict[@"forms"] count])
|
| + << base::SysNSStringToUTF8(testCase[@"html"]);
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
|
|