Revision control
Copy as Markdown
Other Tools
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
<window title="Chrome Window ID Checking Tests"
onload="RunTest();">
<description>Chrome Window ID Checking Tests</description>
<script>
<![CDATA[
let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Ci.mozIJSSubScriptLoader);
let rootDir = getRootDirectory(window.location.href);
scriptLoader.loadSubScript(rootDir + "mailTestUtils.js", this);
var gLoadedWindows = {};
// Have all loaded windows been closed again?
function AllWindowsClosed()
{
return Object.keys(window.gLoadedWindows).length == 0;
}
function DumpElementTree(aElement)
{
// walk upwards from element to DOM root
while (aElement)
{
// print nodeName, id and index in parent
let s = " " + aElement.nodeName + " " + aElement.id + " ";
let ix = 0;
while (aElement.previousSibling)
{
aElement = aElement.previousSibling;
++ix;
}
dump(s + "[" + ix + "]\n");
aElement = aElement.parentNode;
}
}
function CheckIDs(aDocument, aIgnorableIDs)
{
var filename = aDocument.location.href.match(/[^/]+$/);
// all panes are loaded, now check the ids
// first, get the list of all used ids
var idList = aDocument.getElementsByAttribute("id", "*");
// then store them in another object, checking if it's already there
var checkedList = {};
var ignoredList = {};
for (let i = 0; i < idList.length; ++i)
{
let id = idList[i].id;
let duplicate = (id in checkedList);
if (!duplicate)
{
checkedList[id] = idList[i];
}
else
{
// always dump DOM trees of the conflicting elements
dump("Double id='" + id + "' detected in " + aDocument.location.href + ":\n");
dump(" Tree 0:\n");
DumpElementTree(checkedList[id]);
dump(" Tree 1:\n");
DumpElementTree(idList[i]);
}
if (!aIgnorableIDs.includes(id))
{
// if the id is not in our ignore list, show its status
ok(!duplicate, "check id: " + filename + "#" + id);
}
else if (!(id in ignoredList))
{
// mark ignored id tests as todo,
// even though we may never (be able to) fix them
ignoredList[id] = idList[i];
todo(false, "disabled id checks: " + filename + "#" + id);
}
}
// finally, close the loaded window
aDocument.defaultView.close();
}
function DisambiguateCharsetMenulist(aDocument, aListID, aPrefix)
{
let menulist = aDocument.getElementById(aListID)
.getElementsByTagName("menuitem");
for (let menuitem of menulist)
{
menuitem.id = aPrefix + menuitem.id;
menuitem = menuitem.nextSibling;
}
}
function LoadPaneLoop(aDocument, aPanes, aPaneIndex, aForceLoad)
{
if (aPaneIndex < aPanes.length)
{
const WAIT_CYCLE = 10;
// may need to load this pane
let pane = aPanes[aPaneIndex];
if (pane.loaded)
{
// okay, check/load next one
setTimeout(LoadPaneLoop, WAIT_CYCLE, aDocument, aPanes, aPaneIndex + 1, true);
}
else
{
// force load once and wait until done
if (aForceLoad)
{
try
{
aDocument.documentElement.showPane.call(aDocument.documentElement, pane);
}
catch (ignored) {}
}
setTimeout(LoadPaneLoop, WAIT_CYCLE, aDocument, aPanes, aPaneIndex, false);
}
}
else
{
// All preference panes are loaded now!
// The character_encoding_pane contains two template driven menulists
// (viewDefaultCharsetList and sendDefaultCharsetList),
// both of which autogenerate the *same* ids for their menuitems.
// The same ids are generated by the charset list (defaultCharsetList)
// on the languages_pane, too.
// We alter two of these sets here to avoid unnecessary test failure.
// (We probably should remove those RDF templates?)
DisambiguateCharsetMenulist(aDocument, "viewDefaultCharsetList", "test_idcheck.1.");
DisambiguateCharsetMenulist(aDocument, "sendDefaultCharsetList", "test_idcheck.2.");
// now check the ids
CheckIDs(aDocument, window.gLoadedWindows[aDocument.location.href]);
}
}
function CheckPreferences()
{
this.removeEventListener("load", window.CheckPreferences, false);
// Prefpanes are loaded lazily, thus we need to trigger each panel manually
// before we can check for doubled ids...
var panes = this.document.getElementsByTagName("prefpane");
setTimeout(LoadPaneLoop, 0, this.document, panes, 0, true);
}
function CheckGenerics()
{
this.removeEventListener("load", window.CheckGenerics, false);
CheckIDs(this.document, window.gLoadedWindows[this.location.href]);
}
function UncountWindow()
{
if (this.location.href in window.gLoadedWindows)
{
this.removeEventListener("unload", window.UncountWindow, false);
delete window.gLoadedWindows[this.location.href];
}
}
function InitTest()
{
// fake a mail account to avoid the account creation wizard
loadLocalMailAccount();
}
function ExitTest()
{
// remove the mailnews data from the test profile
Services.prefs.resetPrefs();
}
function FinishTest()
{
if (AllWindowsClosed())
{
// commented out to fix test failures after this due to missing prefs
//ExitTest();
SimpleTest.finish();
}
else
{
setTimeout(FinishTest, 1000);
}
}
function RunTest()
{
SimpleTest.waitForExplicitFinish();
InitTest();
// Basically, this test framework is generic enough to check arbitrary
// chrome windows for doubled ids. But certain stuff like preferences
// needs some extra processing.
// The uriList members have the following format:
// [
// check function,
// array of IDs to be ignored during in the test
// ],
var uriList =
{
// Preferences
[
window.CheckPreferences,
[]
],
// Browser
[
window.CheckGenerics,
["contentAreaContextSet"]
],
// MailNews (needs at least one mail account)
[
window.CheckGenerics,
[]
],
[
window.CheckGenerics,
[]
],
[
window.CheckGenerics,
[]
],
// Addressbook (needs at least one mail account)
[
window.CheckGenerics,
[]
],
// Composer
[
window.CheckGenerics,
[]
],
// Error Console
[
window.CheckGenerics,
[]
],
// Chatzilla
[
window.CheckGenerics,
[]
],
};
// run test
for (var uri in uriList)
{
// load the window, but postpone the id check until it's fully loaded
window.gLoadedWindows[uri] = uriList[uri][1]; // ignore these ids
var win = openDialog(uri, "", "chrome,titlebar,dialog=no,resizable");
win.addEventListener("load", uriList[uri][0], false);
win.addEventListener("unload", window.UncountWindow, false);
}
// wait for all tests to finish
SimpleTest.executeSoon(FinishTest);
}
]]>
</script>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</window>