Bug 847863 - Part 7 of 8 - Convert Downloads Panel tests. r=enn

This commit is contained in:
Paolo Amadini 2013-08-21 09:36:07 +02:00
Родитель ebe4488a9b
Коммит fb3d5df5a2
3 изменённых файлов: 107 добавлений и 280 удалений

Просмотреть файл

@ -7,39 +7,33 @@
* Make sure the downloads panel can display items in the right order and
* contains the expected data.
*/
function gen_test()
function test_task()
{
// Display one of each download state.
const DownloadData = [
{ endTime: 1180493839859239, state: nsIDM.DOWNLOAD_NOTSTARTED },
{ endTime: 1180493839859238, state: nsIDM.DOWNLOAD_DOWNLOADING },
{ endTime: 1180493839859237, state: nsIDM.DOWNLOAD_PAUSED },
{ endTime: 1180493839859236, state: nsIDM.DOWNLOAD_SCANNING },
{ endTime: 1180493839859235, state: nsIDM.DOWNLOAD_QUEUED },
{ endTime: 1180493839859234, state: nsIDM.DOWNLOAD_FINISHED },
{ endTime: 1180493839859233, state: nsIDM.DOWNLOAD_FAILED },
{ endTime: 1180493839859232, state: nsIDM.DOWNLOAD_CANCELED },
{ endTime: 1180493839859231, state: nsIDM.DOWNLOAD_BLOCKED_PARENTAL },
{ endTime: 1180493839859230, state: nsIDM.DOWNLOAD_DIRTY },
{ endTime: 1180493839859229, state: nsIDM.DOWNLOAD_BLOCKED_POLICY },
{ state: nsIDM.DOWNLOAD_NOTSTARTED },
{ state: nsIDM.DOWNLOAD_PAUSED },
{ state: nsIDM.DOWNLOAD_FINISHED },
{ state: nsIDM.DOWNLOAD_FAILED },
{ state: nsIDM.DOWNLOAD_CANCELED },
];
// For testing purposes, show all the download items at once.
var originalCountLimit = DownloadsView.kItemCountLimit;
DownloadsView.kItemCountLimit = DownloadData.length;
registerCleanupFunction(function () {
DownloadsView.kItemCountLimit = originalCountLimit;
});
try {
// Ensure that state is reset in case previous tests didn't finish.
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
yield task_resetState();
// For testing purposes, show all the download items at once.
var originalCountLimit = DownloadsView.kItemCountLimit;
DownloadsView.kItemCountLimit = DownloadData.length;
registerCleanupFunction(function () {
DownloadsView.kItemCountLimit = originalCountLimit;
});
// Populate the downloads database with the data required by this test.
for (let yy in gen_addDownloadRows(DownloadData)) yield undefined;
yield task_addDownloads(DownloadData);
// Open the user interface and wait for data to be fully loaded.
for (let yy in gen_openPanel(DownloadsCommon.getData(window))) yield undefined;
yield task_openPanel();
// Test item data and count. This also tests the ordering of the display.
let richlistbox = document.getElementById("downloadsListBox");
@ -47,16 +41,14 @@ function gen_test()
is(richlistbox.children.length, DownloadData.length,
"There is the correct number of richlistitems");
*/
for (let i = 0; i < richlistbox.children.length; i++) {
let element = richlistbox.children[i];
let itemCount = richlistbox.children.length;
for (let i = 0; i < itemCount; i++) {
let element = richlistbox.children[itemCount - i - 1];
let dataItem = new DownloadsViewItemController(element).dataItem;
is(dataItem.target, DownloadData[i].name, "Download names match up");
is(dataItem.state, DownloadData[i].state, "Download states match up");
is(dataItem.file, DownloadData[i].target, "Download targets match up");
is(dataItem.uri, DownloadData[i].source, "Download sources match up");
}
} finally {
// Clean up when the test finishes.
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
yield task_resetState();
}
}

Просмотреть файл

@ -8,19 +8,19 @@
* download it notices. All subsequent downloads, even across sessions, should
* not open the panel automatically.
*/
function gen_test()
function test_task()
{
try {
// Ensure that state is reset in case previous tests didn't finish.
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
yield task_resetState();
// With this set to false, we should automatically open the panel
// the first time a download is started.
// With this set to false, we should automatically open the panel the first
// time a download is started.
DownloadsCommon.getData(window).panelHasShownBefore = false;
prepareForPanelOpen();
let promise = promisePanelOpened();
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
yield undefined;
yield promise;
// If we got here, that means the panel opened.
DownloadsPanel.hidePanel();
@ -28,29 +28,26 @@ function gen_test()
ok(DownloadsCommon.getData(window).panelHasShownBefore,
"Should have recorded that the panel was opened on a download.")
// Next, make sure that if we start another download, we don't open
// the panel automatically.
panelShouldNotOpen();
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
yield waitFor(2);
} catch(e) {
ok(false, e);
// Next, make sure that if we start another download, we don't open the
// panel automatically.
let originalOnPopupShown = DownloadsPanel.onPopupShown;
DownloadsPanel.onPopupShown = function () {
originalOnPopupShown.apply(this, arguments);
ok(false, "Should not have opened the downloads panel.");
};
try {
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
// Wait 2 seconds to ensure that the panel does not open.
let deferTimeout = Promise.defer();
setTimeout(deferTimeout.resolve, 2000);
yield deferTimeout.promise;
} finally {
DownloadsPanel.onPopupShown = originalOnPopupShown;
}
} finally {
// Clean up when the test finishes.
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
yield task_resetState();
}
}
/**
* Call this to record a test failure for the next time the downloads panel
* opens.
*/
function panelShouldNotOpen()
{
// Hook to wait until the test data has been loaded.
let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
DownloadsPanel.onViewLoadCompleted = function () {
DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
ok(false, "Should not have opened the downloads panel.");
};
}

Просмотреть файл

@ -10,10 +10,16 @@
////////////////////////////////////////////////////////////////////////////////
//// Globals
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
const nsIDM = Ci.nsIDownloadManager;
let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]);
@ -22,253 +28,85 @@ registerCleanupFunction(function () {
gTestTargetFile.remove(false);
});
/**
* This objects contains a property for each column in the downloads table.
*/
let gDownloadRowTemplate = {
name: "test-download.txt",
source: "http://www.example.com/test-download.txt",
target: NetUtil.newURI(gTestTargetFile).spec,
startTime: 1180493839859230,
endTime: 1180493839859234,
state: nsIDM.DOWNLOAD_FINISHED,
currBytes: 0,
maxBytes: -1,
preferredAction: 0,
autoResume: 0
};
////////////////////////////////////////////////////////////////////////////////
//// Infrastructure
// All test are run through the test runner.
function test()
{
testRunner.runTest(this.gen_test);
waitForExplicitFinish();
Task.spawn(test_task).then(null, ex => ok(false, ex)).then(finish);
}
/**
* Runs a browser-chrome test defined through a generator function.
*
* This object is a singleton, initialized automatically when this script is
* included. Every browser-chrome test file includes a new copy of this object.
*/
var testRunner = {
_testIterator: null,
_lastEventResult: undefined,
_testRunning: false,
_eventRaised: false,
// --- Main test runner ---
/**
* Runs the test described by the provided generator function asynchronously.
*
* Calling yield in the generator will cause it to wait until continueTest is
* called. The parameter provided to continueTest will be the return value of
* the yield operator.
*
* @param aGenerator
* Test generator function. The function will be called with no
* arguments to retrieve its iterator.
*/
runTest: function TR_runTest(aGenerator) {
waitForExplicitFinish();
testRunner._testIterator = aGenerator();
testRunner.continueTest();
},
/**
* Continues the currently running test.
*
* @param aEventResult
* This will be the return value of the yield operator in the test.
*/
continueTest: function TR_continueTest(aEventResult) {
// Store the last event result, or set it to undefined.
testRunner._lastEventResult = aEventResult;
// Never reenter the main loop, but notify that the event has been raised.
if (testRunner._testRunning) {
testRunner._eventRaised = true;
return;
}
// Enter the main iteration loop.
testRunner._testRunning = true;
try {
do {
// Call the iterator, but don't leave the loop if the expected event is
// raised during the execution of the generator.
testRunner._eventRaised = false;
testRunner._testIterator.send(testRunner._lastEventResult);
} while (testRunner._eventRaised);
}
catch (e) {
// This block catches exceptions raised by the generator, including the
// normal StopIteration exception. Unexpected exceptions are reported as
// test failures.
if (!(e instanceof StopIteration))
ok(false, e);
// In any case, stop the tests in this file.
finish();
}
// Wait for the next event or finish.
testRunner._testRunning = false;
}
};
////////////////////////////////////////////////////////////////////////////////
//// Asynchronous generator-based support subroutines
//// Asynchronous support subroutines
//
// The following functions are all generators that can be used inside the main
// test generator to perform specific tasks asynchronously. To invoke these
// subroutines correctly, an iteration syntax should be used:
//
// for (let yy in gen_example("Parameter")) yield undefined;
//
function gen_resetState(aData)
function promiseFocus()
{
let statement = Services.downloads.DBConnection.createAsyncStatement(
"DELETE FROM moz_downloads");
try {
statement.executeAsync({
handleResult: function(aResultSet) { },
handleError: function(aError)
{
Cu.reportError(aError);
},
handleCompletion: function(aReason)
{
testRunner.continueTest();
}
});
yield undefined;
} finally {
statement.finalize();
let deferred = Promise.defer();
waitForFocus(deferred.resolve);
return deferred.promise;
}
function promisePanelOpened()
{
let deferred = Promise.defer();
// Hook to wait until the panel is shown.
let originalOnPopupShown = DownloadsPanel.onPopupShown;
DownloadsPanel.onPopupShown = function () {
DownloadsPanel.onPopupShown = originalOnPopupShown;
originalOnPopupShown.apply(this, arguments);
// Defer to the next tick of the event loop so that we don't continue
// processing during the DOM event handler itself.
setTimeout(deferred.resolve, 0);
};
return deferred.promise;
}
function task_resetState()
{
// Remove all downloads.
let publicList = yield Downloads.getPublicDownloadList();
let downloads = yield publicList.getAll();
for (let download of downloads) {
publicList.remove(download);
yield download.finalize(true);
}
// Reset any prefs that might have been changed.
Services.prefs.clearUserPref("browser.download.panel.shown");
// Ensure that the panel is closed and data is unloaded.
aData.clear();
aData._loadState = aData.kLoadNone;
DownloadsPanel.hidePanel();
// Wait for focus on the main window.
waitForFocus(testRunner.continueTest);
yield undefined;
yield promiseFocus();
}
function gen_addDownloadRows(aDataRows)
function task_addDownloads(aItems)
{
let columnNames = Object.keys(gDownloadRowTemplate).join(", ");
let parameterNames = Object.keys(gDownloadRowTemplate)
.map(function(n) ":" + n)
.join(", ");
let statement = Services.downloads.DBConnection.createAsyncStatement(
"INSERT INTO moz_downloads (" + columnNames +
", guid) VALUES(" + parameterNames + ", GENERATE_GUID())");
try {
// Execute the statement for each of the provided downloads in reverse.
for (let i = aDataRows.length - 1; i >= 0; i--) {
let dataRow = aDataRows[i];
let startTimeMs = Date.now();
// Populate insert parameters from the provided data.
for (let columnName in gDownloadRowTemplate) {
if (!(columnName in dataRow)) {
// Update the provided row object with data from the global template,
// for columns whose value is not provided explicitly.
dataRow[columnName] = gDownloadRowTemplate[columnName];
}
statement.params[columnName] = dataRow[columnName];
}
// Run the statement asynchronously and wait.
statement.executeAsync({
handleResult: function(aResultSet) { },
handleError: function(aError)
{
Cu.reportError(aError.message + " (Result = " + aError.result + ")");
},
handleCompletion: function(aReason)
{
testRunner.continueTest();
}
});
yield undefined;
// At each iteration, ensure that the start and end time in the global
// template is distinct, as these column are used to sort each download
// in its category.
gDownloadRowTemplate.startTime++;
gDownloadRowTemplate.endTime++;
}
} finally {
statement.finalize();
let publicList = yield Downloads.getPublicDownloadList();
for (let item of aItems) {
publicList.add(yield Downloads.createDownload({
source: "http://www.example.com/test-download.txt",
target: gTestTargetFile,
succeeded: item.state == nsIDM.DOWNLOAD_FINISHED,
canceled: item.state == nsIDM.DOWNLOAD_CANCELED ||
item.state == nsIDM.DOWNLOAD_PAUSED,
error: item.state == nsIDM.DOWNLOAD_FAILED ? new Error("Failed.") : null,
hasPartialData: item.state == nsIDM.DOWNLOAD_PAUSED,
startTime: new Date(startTimeMs++),
}));
}
}
function gen_openPanel(aData)
function task_openPanel()
{
// Hook to wait until the test data has been loaded.
let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
DownloadsPanel.onViewLoadCompleted = function () {
DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
originalOnViewLoadCompleted.apply(this);
testRunner.continueTest();
};
yield promiseFocus();
// Start loading all the downloads from the database asynchronously.
aData.ensurePersistentDataLoaded(false);
// Wait for focus on the main window.
waitForFocus(testRunner.continueTest);
yield undefined;
// Open the downloads panel, waiting until loading is completed.
let promise = promisePanelOpened();
DownloadsPanel.showPanel();
yield undefined;
}
/**
* Spin the event loop for aSeconds seconds, and then signal the test to
* continue.
*
* @param aSeconds the number of seconds to wait.
* @note This helper should _only_ be used when there's no valid event to
* listen to and one can't be made.
*/
function waitFor(aSeconds)
{
setTimeout(function() {
testRunner.continueTest();
}, aSeconds * 1000);
}
/**
* Make it so that the next time the downloads panel opens, we signal to
* continue the test. This function needs to be called each time you want
* to wait for the panel to open.
*
* Example usage:
*
* prepareForPanelOpen();
* // Do something to open the panel
* yield undefined;
* // We can assume the panel is open now.
*/
function prepareForPanelOpen()
{
// Hook to wait until the test data has been loaded.
let originalOnPopupShown = DownloadsPanel.onPopupShown;
DownloadsPanel.onPopupShown = function (aEvent) {
DownloadsPanel.onPopupShown = originalOnPopupShown;
DownloadsPanel.onPopupShown.apply(this, [aEvent]);
testRunner.continueTest();
};
yield promise;
}