Commit b3215e7a authored by dpapad's avatar dpapad Committed by Commit Bot

WebUI: Auto-generate test_util.m.js instead of forking.

Specifically:
 - Deleting checked-in, settings/test_util.m.js
 - Auto-generate equivalent file at the correct location (one level up)
 - Update chrome://test references
 - Update BUILD.gn deps to depend on the js_modulizer() target, and
   ensure the generated file is available in test bots (via |data| deps)
 - Update test_data_source.cc to also look at gen/chrome/test/data/webui/
   when processing chrome://test requests

Bug: 965770
Change-Id: I6243986b3297fbb949220034fe88622adc320fa2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1742832Reviewed-by: default avatarRebekah Potter <rbpotter@chromium.org>
Commit-Queue: Rebekah Potter <rbpotter@chromium.org>
Commit-Queue: Demetrios Papadopoulos <dpapad@chromium.org>
Auto-Submit: Demetrios Papadopoulos <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685275}
parent db763329
......@@ -72,11 +72,22 @@ GURL TestDataSource::GetURLForPath(const std::string& path) {
void TestDataSource::ReadFile(
const std::string& path,
const content::URLDataSource::GotDataCallback& callback) {
if (test_data_.empty()) {
CHECK(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_));
CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_));
if (src_root_.empty()) {
base::FilePath test_data;
CHECK(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
src_root_ = test_data.Append(FILE_PATH_LITERAL("webui"));
}
base::FilePath root = test_data_.Append(FILE_PATH_LITERAL("webui"));
if (gen_root_.empty()) {
std::string gen_path = "gen/chrome/test/data/webui/";
#if defined(OS_WIN)
base::ReplaceChars(gen_path, "//", "\\", &gen_path);
#endif
base::FilePath exe_dir;
base::PathService::Get(base::DIR_EXE, &exe_dir);
gen_root_ = exe_dir.AppendASCII(gen_path);
}
std::string content;
GURL url = GetURLForPath(path);
......@@ -85,17 +96,27 @@ void TestDataSource::ReadFile(
base::CompareCase::INSENSITIVE_ASCII)) {
std::string js_path = url.query().substr(strlen(kModuleQuery));
base::FilePath file_path =
root.Append(base::FilePath::FromUTF8Unsafe(js_path));
src_root_.Append(base::FilePath::FromUTF8Unsafe(js_path));
// Do some basic validation of the JS file path provided in the query.
CHECK_EQ(file_path.Extension(), FILE_PATH_LITERAL(".js"));
CHECK(base::PathExists(file_path))
<< url.spec() << "=" << file_path.value();
content = "<script type=\"module\" src=\"" + js_path + "\"></script>";
} else {
// Try the |src_root_| folder first.
base::FilePath file_path =
root.Append(base::FilePath::FromUTF8Unsafe(path));
CHECK(base::ReadFileToString(file_path, &content))
<< url.spec() << "=" << file_path.value();
src_root_.Append(base::FilePath::FromUTF8Unsafe(path));
if (base::PathExists(file_path)) {
CHECK(base::ReadFileToString(file_path, &content))
<< url.spec() << "=" << file_path.value();
} else {
// Then try the |gen_root_| folder, covering cases where the test file is
// generated at build time.
base::FilePath file_path =
gen_root_.Append(base::FilePath::FromUTF8Unsafe(path));
CHECK(base::ReadFileToString(file_path, &content))
<< url.spec() << "=" << file_path.value();
}
}
scoped_refptr<base::RefCountedString> response =
......
......@@ -39,8 +39,8 @@ class TestDataSource : public content::URLDataSource {
void ReadFile(const std::string& path,
const content::URLDataSource::GotDataCallback& callback);
base::FilePath test_data_;
base::FilePath source_root_;
base::FilePath src_root_;
base::FilePath gen_root_;
DISALLOW_COPY_AND_ASSIGN(TestDataSource);
};
......
......@@ -1406,6 +1406,7 @@ if (!is_android) {
"//chrome/test/data/webui:browser_tests_js_mojo_lite_webui",
"//chrome/test/data/webui:browser_tests_js_webui",
]
data += [ "$root_gen_dir/chrome/test/data/webui/test_util.m.js" ]
}
if (!is_fuchsia) {
......@@ -5416,6 +5417,7 @@ if (!is_android) {
if (include_js_tests) {
deps += [ "//chrome/test/data/webui:interactive_ui_tests_js_webui" ]
data += [ "$root_gen_dir/chrome/test/data/webui/test_util.m.js" ]
}
# Runtime dependencies
......
......@@ -4,6 +4,7 @@
import("//chrome/common/features.gni")
import("//chrome/test/base/js2gtest.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
js2gtest("interactive_ui_tests_js_webui") {
test_type = "webui"
......@@ -26,6 +27,7 @@ js2gtest("interactive_ui_tests_js_webui") {
]
deps = [
":modulize",
"//chrome/browser/ui",
]
......@@ -141,6 +143,7 @@ js2gtest("browser_tests_js_webui") {
sources += [ "print_preview/print_preview_ui_browsertest.js" ]
}
deps = [
":modulize",
"//chrome/browser/ui",
"//skia",
]
......@@ -219,3 +222,7 @@ js2gtest("unit_tests_js") {
]
}
}
js_modulizer("modulize") {
input_files = [ "test_util.js" ]
}
......@@ -12,7 +12,6 @@ def _CheckForModularizedTests(input_api, output_api):
'cr_elements/cr_view_manager_test.m.js',
'extensions/test_util.m.js',
'mock_timer.m.js',
'settings/test_util.m.js',
]
affected_files = [
input_api.os_path.relpath(f, input_api.PresubmitLocalPath())
......
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import {eventToPromise} from 'chrome://test/settings/test_util.m.js';
import {eventToPromise} from 'chrome://test/test_util.m.js';
suite('cr-button-v3', function() {
let button;
......
......@@ -5,7 +5,7 @@
import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js';
import {keyDownOn, keyUpOn, pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
import {eventToPromise} from 'chrome://test/settings/test_util.m.js';
import {eventToPromise} from 'chrome://test/test_util.m.js';
suite('cr-checkbox-v3', function() {
let checkbox;
......
......@@ -5,7 +5,7 @@
import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {eventToPromise, whenAttributeIs} from 'chrome://test/settings/test_util.m.js';
import {eventToPromise, whenAttributeIs} from 'chrome://test/test_util.m.js';
suite('cr-input', function() {
let crInput;
......
......@@ -5,7 +5,7 @@
import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
import {keyEventOn, tap} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
import {eventToPromise} from 'chrome://test/settings/test_util.m.js';
import {eventToPromise} from 'chrome://test/test_util.m.js';
suite('cr-toggle-v3', function() {
let toggle;
......
// Copyright 2016 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.
/**
* Observes an HTML attribute and fires a promise when it matches a given
* value.
* @param {!HTMLElement} target
* @param {string} attributeName
* @param {*} attributeValue
* @return {!Promise}
*/
export function whenAttributeIs(target, attributeName, attributeValue) {
function isDone() {
return target.getAttribute(attributeName) == attributeValue;
}
return isDone() ? Promise.resolve() : new Promise(function(resolve) {
new MutationObserver(function(mutations, observer) {
for (const mutation of mutations) {
assertEquals('attributes', mutation.type);
if (mutation.attributeName == attributeName && isDone()) {
observer.disconnect();
resolve();
return;
}
}
})
.observe(
target, {attributes: true, childList: false, characterData: false});
});
}
/**
* Converts an event occurrence to a promise.
* @param {string} eventType
* @param {!HTMLElement} target
* @return {!Promise} A promise firing once the event occurs.
*/
export function eventToPromise(eventType, target) {
return new Promise(function(resolve, reject) {
target.addEventListener(eventType, function f(e) {
target.removeEventListener(eventType, f);
resolve(e);
});
});
}
/**
* Data-binds two Polymer properties using the property-changed events and
* set/notifyPath API. Useful for testing components which would normally be
* used together.
* @param {!HTMLElement} el1
* @param {!HTMLElement} el2
* @param {string} property
*/
export function fakeDataBind(el1, el2, property) {
const forwardChange = function(el, event) {
if (event.detail.hasOwnProperty('path')) {
el.notifyPath(event.detail.path, event.detail.value);
} else {
el.set(property, event.detail.value);
}
};
// Add the listeners symmetrically. Polymer will prevent recursion.
el1.addEventListener(property + '-changed', forwardChange.bind(null, el2));
el2.addEventListener(property + '-changed', forwardChange.bind(null, el1));
}
/**
* Helper to create an object containing a ContentSettingsType key to array or
* object value. This is a convenience function that can eventually be
* replaced with ES6 computed properties.
* @param {settings.ContentSettingsTypes} contentType The ContentSettingsType
* to use as the key.
* @param {Object} value The value to map to |contentType|.
* @return {Object<setting: settings.ContentSettingsTypes, value: Object>}
*/
export function createContentSettingTypeToValuePair(contentType, value) {
return {setting: contentType, value: value};
}
/**
* Helper to create a mock DefaultContentSetting.
* @param {!Object=} override An object with a subset of the properties of
* DefaultContentSetting. Properties defined in |override| will
* overwrite the defaults in this function's return value.
* @return {DefaultContentSetting}
*/
export function createDefaultContentSetting(override) {
if (override === undefined) {
override = {};
}
return Object.assign(
{
setting: settings.ContentSetting.ASK,
source: settings.SiteSettingSource.PREFERENCE,
},
override);
}
/**
* Helper to create a mock RawSiteException.
* @param {!string} origin The origin to use for this RawSiteException.
* @param {!Object=} override An object with a subset of the properties of
* RawSiteException. Properties defined in |override| will overwrite the
* defaults in this function's return value.
* @return {RawSiteException}
*/
export function createRawSiteException(origin, override) {
if (override === undefined) {
override = {};
}
return Object.assign(
{
embeddingOrigin: origin,
incognito: false,
origin: origin,
displayName: '',
setting: settings.ContentSetting.ALLOW,
source: settings.SiteSettingSource.PREFERENCE,
},
override);
}
/**
* Helper to create a mock RawChooserException.
* @param {!settings.ChooserType} chooserType The chooser exception type.
* @param {Array<!RawSiteException>} sites A list of SiteExceptions
* corresponding to the chooser exception.
* @param {!Object=} override An object with a subset of the properties of
* RawChooserException. Properties defined in |override| will overwrite
* the defaults in this function's return value.
* @return {RawChooserException}
*/
export function createRawChooserException(chooserType, sites, override) {
return Object.assign(
{chooserType: chooserType, displayName: '', object: {}, sites: sites},
override || {});
}
/**
* Helper to create a mock SiteSettingsPref.
* @param {!Array<{setting: settings.ContentSettingsTypes,
* value: DefaultContentSetting}>} defaultsList A list of
* DefaultContentSettings and the content settings they apply to, which
* will overwrite the defaults in the SiteSettingsPref returned by this
* function.
* @param {!Array<{setting: settings.ContentSettingsTypes,
* value: !Array<RawSiteException>}>} exceptionsList A list of
* RawSiteExceptions and the content settings they apply to, which will
* overwrite the exceptions in the SiteSettingsPref returned by this
* function.
* @param {!Array<{setting: settings.ContentSettingsTypes,
* value: !Array<RawChooserException>}>} chooserExceptionsList
* A list of RawChooserExceptions and the chooser type that they apply to,
* which will overwrite the exceptions in the SiteSettingsPref returned by
* this function.
* @return {SiteSettingsPref}
*/
export function createSiteSettingsPrefs(
defaultsList, exceptionsList, chooserExceptionsList = []) {
// These test defaults reflect the actual defaults assigned to each
// ContentSettingType, but keeping these in sync shouldn't matter for tests.
const defaults = {};
for (let type in settings.ContentSettingsTypes) {
defaults[settings.ContentSettingsTypes[type]] =
createDefaultContentSetting({});
}
defaults[settings.ContentSettingsTypes.COOKIES].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.IMAGES].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.JAVASCRIPT].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.SOUND].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.POPUPS].setting =
settings.ContentSetting.BLOCK;
defaults[settings.ContentSettingsTypes.PROTOCOL_HANDLERS].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.BACKGROUND_SYNC].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.ADS].setting =
settings.ContentSetting.BLOCK;
defaults[settings.ContentSettingsTypes.SENSORS].setting =
settings.ContentSetting.ALLOW;
defaults[settings.ContentSettingsTypes.USB_DEVICES].setting =
settings.ContentSetting.ASK;
defaultsList.forEach((override) => {
defaults[override.setting] = override.value;
});
const chooserExceptions = {};
const exceptions = {};
for (let type in settings.ContentSettingsTypes) {
chooserExceptions[settings.ContentSettingsTypes[type]] = [];
exceptions[settings.ContentSettingsTypes[type]] = [];
}
exceptionsList.forEach(override => {
exceptions[override.setting] = override.value;
});
chooserExceptionsList.forEach(override => {
chooserExceptions[override.setting] = override.value;
});
return {
chooserExceptions: chooserExceptions,
defaults: defaults,
exceptions: exceptions,
};
}
/**
* Helper to create a mock SiteGroup.
* @param {!string} eTLDPlus1Name The eTLD+1 of all the origins provided in
* |originList|.
* @param {!Array<string>} originList A list of the origins with the same
* eTLD+1.
* @return {SiteGroup}
*/
export function createSiteGroup(eTLDPlus1Name, originList) {
const originInfoList = originList.map(origin => createOriginInfo(origin));
return {
etldPlus1: eTLDPlus1Name,
origins: originInfoList,
numCookies: 0,
};
}
export function createOriginInfo(origin, override) {
if (override === undefined) {
override = {};
}
return Object.assign(
{
origin: origin,
engagement: 0,
usage: 0,
numCookies: 0,
hasPermissionSettings: false,
},
override);
}
/**
* Helper to retrieve the category of a permission from the given
* |chooserType|.
* @param {settings.ChooserType} chooserType The chooser type of the
* permission.
* @return {?settings.ContentSettingsType}
*/
export function getContentSettingsTypeFromChooserType(chooserType) {
switch (chooserType) {
case settings.ChooserType.USB_DEVICES:
return settings.ContentSettingsTypes.USB_DEVICES;
default:
return null;
}
}
/**
* Converts beforeNextRender() API to promise-based.
* @param {!Element} element
* @return {!Promise}
*/
export function waitForRender(element) {
return new Promise(resolve => {
Polymer.RenderStatus.beforeNextRender(element, resolve);
});
}
......@@ -11,7 +11,8 @@ cr.define('test_util', function() {
* @param {*} attributeValue
* @return {!Promise}
*/
function whenAttributeIs(target, attributeName, attributeValue) {
/* #export */ function whenAttributeIs(
target, attributeName, attributeValue) {
function isDone() {
return target.getAttribute(attributeName) == attributeValue;
}
......@@ -40,7 +41,7 @@ cr.define('test_util', function() {
* @param {!HTMLElement} target
* @return {!Promise} A promise firing once the event occurs.
*/
function eventToPromise(eventType, target) {
/* #export */ function eventToPromise(eventType, target) {
return new Promise(function(resolve, reject) {
target.addEventListener(eventType, function f(e) {
target.removeEventListener(eventType, f);
......@@ -57,7 +58,7 @@ cr.define('test_util', function() {
* @param {!HTMLElement} el2
* @param {string} property
*/
function fakeDataBind(el1, el2, property) {
/* #export */ function fakeDataBind(el1, el2, property) {
const forwardChange = function(el, event) {
if (event.detail.hasOwnProperty('path')) {
el.notifyPath(event.detail.path, event.detail.value);
......@@ -75,12 +76,13 @@ cr.define('test_util', function() {
* @param {!Element} element
* @return {!Promise}
*/
function waitForRender(element) {
/* #export */ function waitForRender(element) {
return new Promise(resolve => {
Polymer.RenderStatus.beforeNextRender(element, resolve);
});
}
// #cr_define_end
return {
eventToPromise: eventToPromise,
fakeDataBind: fakeDataBind,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment