blob: 60b03af5a25284fe83abf82a0e3882d16bc8d480 [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.
/**
* @fileoverview Framework for running JavaScript tests of Polymer elements.
*/
/**
* Test fixture for Polymer element testing.
* @constructor
* @extends testing.Test
*/
function PolymerTest() {}
PolymerTest.prototype = {
__proto__: testing.Test.prototype,
/**
* Navigate to a WebUI to satisfy BrowserTest conditions. Override to load a
* more useful WebUI.
* @override
*/
browsePreload: 'chrome://chrome-urls/',
/**
* The mocha adapter assumes all tests are async.
* @override
* @final
*/
isAsync: true,
/**
* Old style a11y checks are obsolete. See ../a11y/accessibility_test.js for
* the new suggested way.
* @override
*/
runAccessibilityChecks: false,
/**
* Files that need not be compiled.
* @override
*/
extraLibraries: [
'//ui/webui/resources/js/cr.js',
'//ui/webui/resources/js/promise_resolver.js',
'//third_party/mocha/mocha.js',
'//chrome/test/data/webui/mocha_adapter.js',
'//third_party/polymer/v1_0/components-chromium/iron-test-helpers/' +
'mock-interactions.js',
],
/** @override */
setUp: function() {
testing.Test.prototype.setUp.call(this);
// List of imported URLs for debugging purposes.
PolymerTest.importUrls_ = [];
PolymerTest.scriptUrls_ = [];
// Importing a URL like "chrome://settings/foo" redirects to the base
// ("chrome://settings") page, which due to how browsePreload works can
// result in duplicate imports. Wrap document.registerElement so failures
// caused by re-registering Polymer elements are caught; otherwise Chrome
// simply throws "Script error" which is unhelpful.
var originalRegisterElement = document.registerElement;
document.registerElement = function() {
try {
return originalRegisterElement.apply(document, arguments);
} catch (e) {
var msg =
'If the call to document.registerElement failed because a type ' +
'is already registered, perhaps you have loaded a script twice. ' +
'Incorrect resource URLs can redirect to base WebUI pages; make ' +
'sure the following URLs are correct and unique:\n';
for (var i = 0; i < PolymerTest.importUrls_.length; i++) {
msg += ' ' + PolymerTest.importUrls_[i] + '\n';
}
for (var i = 0; i < PolymerTest.scriptUrls_.length; i++) {
msg += ' ' + PolymerTest.scriptUrls_[i] + '\n';
}
console.error(msg);
// Mocha will handle the error.
throw e;
}
};
},
/** @override */
tearDown: function() {
// Note: We do this in tearDown() so that we have a chance to stamp all the
// dom-if templates, add elements through interaction, etc.
PolymerTest.testIronIcons(document.body);
testing.Test.prototype.tearDown.call(this);
}
};
/**
* Tests that any iron-icon child of an HTML element has a corresponding
* non-empty svg element.
* @param {!HTMLElement} e The element to check the iron icons in.
*/
PolymerTest.testIronIcons = function(e) {
e.querySelectorAll('* /deep/ iron-icon').forEach(function(icon) {
// Early return if the src is set instead of the icon, since the tests
// below will not work correctly in this case.
if (icon.src && !icon.icon) {
return;
}
// If the icon isn't set (or is set to ''), then don't test this. Having no
// set icon is valid for cases when we don't want to display anything.
if (!icon.icon) {
var rect = icon.getBoundingClientRect();
expectFalse(
rect.width * rect.height > 0,
'iron-icon with undefined "icon" is visible in the DOM.');
return;
}
var svg = icon.$$('svg');
expectTrue(
!!svg && svg.innerHTML != '',
'icon "' + icon.icon + '" is not present');
});
};
/**
* Imports the HTML file.
* @param {string} src The URL to load.
* @return {!Promise} A promise that is resolved/rejected on success/failure.
*/
PolymerTest.importHtml = function(src) {
PolymerTest.importUrls_.push(src);
var link = document.createElement('link');
link.rel = 'import';
var promise = new Promise(function(resolve, reject) {
link.onload = resolve;
link.onerror = reject;
});
link.href = src;
document.head.appendChild(link);
return promise;
};
/**
* Loads the script file.
* @param {string} src The URL to load.
* @return {!Promise} A promise that is resolved/rejected on success/failure.
*/
PolymerTest.loadScript = function(src) {
PolymerTest.scriptUrls_.push(src);
var script = document.createElement('script');
var promise = new Promise(function(resolve, reject) {
script.onload = resolve;
script.onerror = reject;
});
script.src = src;
document.head.appendChild(script);
return promise;
};
/**
* Removes all content from the body. In a vulcanized build, this retains the
* inlined tags so stylesheets and dom-modules are not discarded.
*/
PolymerTest.clearBody = function() {
// Save the div where vulcanize inlines content before clearing the page.
var vulcanizeDiv =
document.querySelector('body > div[hidden][by-polymer-bundler]');
document.body.innerHTML = '';
if (vulcanizeDiv) {
document.body.appendChild(vulcanizeDiv);
}
};
/*
* Waits for queued up tasks to finish before proceeding. Inspired by:
* https://github.com/Polymer/web-component-tester/blob/master/browser/environment/helpers.js#L97
*/
PolymerTest.flushTasks = function() {
Polymer.dom.flush();
// Promises have microtask timing, so we use setTimeout to explicity force a
// new task.
return new Promise(function(resolve, reject) {
window.setTimeout(resolve, 0);
});
};
/**
* @param {!HTMLElement} element
* @return {!Promise} Promise that resolves when an afterNextRender()
* callback on |element| is run.
*/
PolymerTest.afterNextRender = function(element) {
return new Promise(resolve => {
Polymer.RenderStatus.afterNextRender(element, resolve);
});
};