blob: 47c39b739ea16a544db0e2f1fd67343bb7362253 [file] [log] [blame]
// Copyright 2015 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 <stddef.h>
#import <Foundation/Foundation.h>
#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
#import "ios/web/public/test/web_test_with_web_state.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Struct for isTextField() test data.
struct TextFieldTestElement {
// The element name.
const char* element_name;
// The index of this element in those that have the same name.
const int element_index;
// True if this is expected to be a text field.
const bool expected_is_text_field;
};
// Struct for stringify() test data.
struct TestScriptAndExpectedValue {
NSString* test_script;
id expected_value;
};
} // namespace
namespace web {
// Test fixture to test common.js.
typedef web::WebTestWithWebState CommonJsTest;
// Tests __gCrWeb.common.isTextField JavaScript API.
TEST_F(CommonJsTest, IsTestField) {
LoadHtml(@"<html><body>"
"<input type='text' name='firstname'>"
"<input type='text' name='lastname'>"
"<input type='email' name='email'>"
"<input type='tel' name='phone'>"
"<input type='url' name='blog'>"
"<input type='number' name='expected number of clicks'>"
"<input type='password' 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'>"
"<select name='state'>"
" <option value='CA'>CA</option>"
" <option value='MA'>MA</option>"
"</select>"
"<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>"
"<input type='submit' name='submit' value='Submit'>"
"</body></html>");
static const struct TextFieldTestElement testElements[] = {
{"firstname", 0, true},
{"lastname", 0, true},
{"email", 0, true},
{"phone", 0, true},
{"blog", 0, true},
{"expected number of clicks", 0, true},
{"pwd", 0, true},
{"vehicle", 0, false},
{"vehicle", 1, false},
{"vehicle", 2, false},
{"boolean", 0, false},
{"boolean", 1, false},
{"boolean", 2, false},
{"state", 0, false},
{"cars", 0, false},
{"submit", 0, false}};
for (size_t i = 0; i < base::size(testElements); ++i) {
TextFieldTestElement element = testElements[i];
id result = ExecuteJavaScript([NSString
stringWithFormat:@"__gCrWeb.common.isTextField("
"window.document.getElementsByName('%s')[%d])",
element.element_name, element.element_index]);
EXPECT_NSEQ(element.expected_is_text_field ? @YES : @NO, result)
<< element.element_name << " with index " << element.element_index
<< " isTextField(): " << element.expected_is_text_field;
}
}
// Tests __gCrWeb.stringify JavaScript API.
TEST_F(CommonJsTest, Stringify) {
TestScriptAndExpectedValue test_data[] = {
// Stringify a string that contains various characters that must
// be escaped.
{@"__gCrWeb.stringify('a\\u000a\\t\\b\\\\\\\"Z')",
@"\"a\\n\\t\\b\\\\\\\"Z\""},
// Stringify a number.
{@"__gCrWeb.stringify(77.7)", @"77.7"},
// Stringify an array.
{@"__gCrWeb.stringify(['a','b'])", @"[\"a\",\"b\"]"},
// Stringify an object.
{@"__gCrWeb.stringify({'a':'b','c':'d'})", @"{\"a\":\"b\",\"c\":\"d\"}"},
// Stringify a hierarchy of objects and arrays.
{@"__gCrWeb.stringify([{'a':['b','c'],'d':'e'},'f'])",
@"[{\"a\":[\"b\",\"c\"],\"d\":\"e\"},\"f\"]"},
// Stringify null.
{@"__gCrWeb.stringify(null)", @"null"},
// Stringify an object with a toJSON function.
{@"temp = [1,2];"
"temp.toJSON = function (key) {return undefined};"
"__gCrWeb.stringify(temp)",
@"[1,2]"},
// Stringify an object with a toJSON property that is not a function.
{@"temp = [1,2];"
"temp.toJSON = 42;"
"__gCrWeb.stringify(temp)",
@"[1,2]"},
// Stringify an undefined object.
{@"__gCrWeb.stringify(undefined)", @"undefined"},
};
for (size_t i = 0; i < base::size(test_data); i++) {
TestScriptAndExpectedValue& data = test_data[i];
// Load a sample HTML page. As a side-effect, loading HTML via
// |webController_| will also inject web_bundle.js.
LoadHtml(@"<p>");
id result = ExecuteJavaScript(data.test_script);
EXPECT_NSEQ(data.expected_value, result)
<< " in test " << i << ": "
<< base::SysNSStringToUTF8(data.test_script);
}
}
TEST_F(CommonJsTest, RemoveQueryAndReferenceFromURL) {
struct TestData {
NSString* input_url;
NSString* expected_output;
} test_data[] = {
{@"http://foo1.com/bar", @"http://foo1.com/bar"},
{@"http://foo2.com/bar#baz", @"http://foo2.com/bar"},
{@"http://foo3.com/bar?baz", @"http://foo3.com/bar"},
// Order of fragment and query string does not matter.
{@"http://foo4.com/bar#baz?blech", @"http://foo4.com/bar"},
{@"http://foo5.com/bar?baz#blech", @"http://foo5.com/bar"},
// Truncates on the first fragment mark.
{@"http://foo6.com/bar/#baz#blech", @"http://foo6.com/bar/"},
// Poorly formed URLs are normalized.
{@"http:///foo7.com//bar?baz", @"http://foo7.com//bar"},
// Non-http protocols.
{@"data:abc", @"data:abc"},
{@"javascript:login()", @"javascript:login()"},
};
for (size_t i = 0; i < base::size(test_data); i++) {
LoadHtml(@"<p>");
TestData& data = test_data[i];
id result = ExecuteJavaScript(
[NSString stringWithFormat:
@"__gCrWeb.common.removeQueryAndReferenceFromURL('%@')",
data.input_url]);
EXPECT_NSEQ(data.expected_output, result)
<< " in test " << i << ": " << base::SysNSStringToUTF8(data.input_url);
}
}
TEST_F(CommonJsTest, IsSameOrigin) {
TestScriptAndExpectedValue test_data[] = {
{@"'', ''", @NO},
{@"'http://abc.com', ''", @NO},
{@"'', 'http://abc.com'", @NO},
{@"'http://abc.com', 'http://abc.com'", @YES},
{@"'http://abc.com', 'https://abc.com'", @NO},
{@"'http://abc.com', 'http://abc.com:123'", @NO},
{@"'http://abc.com', 'http://def.com'", @NO},
{@"'http://abc.com/def', 'http://abc.com/xyz'", @YES}};
for (size_t i = 0; i < base::size(test_data); i++) {
TestScriptAndExpectedValue& data = test_data[i];
LoadHtml(@"<p>");
id result = ExecuteJavaScript(
[NSString stringWithFormat:@"__gCrWeb.common.isSameOrigin(%@)",
data.test_script]);
EXPECT_NSEQ(data.expected_value, result)
<< " in test " << i << ": "
<< base::SysNSStringToUTF8(data.test_script);
}
}
} // namespace web