Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-02-17 21:14:00 -05:00
commit aab4a757c2
31 changed files with 406 additions and 417 deletions

View File

@ -414,6 +414,8 @@ DevTools.prototype = {
// No toolbox for target, create one
toolbox = new devtools.Toolbox(target, toolId, hostType, hostOptions);
this.emit("toolbox-created", toolbox);
this._toolboxes.set(target, toolbox);
toolbox.once("destroy", () => {

View File

@ -43,6 +43,7 @@ skip-if = e10s # Bug 1069044 - destroyInspector may hang during shutdown
[browser_toolbox_tabsswitch_shortcuts.js]
[browser_toolbox_tool_ready.js]
[browser_toolbox_tool_remote_reopen.js]
[browser_toolbox_transport_events.js]
[browser_toolbox_window_reload_target.js]
[browser_toolbox_window_shortcuts.js]
skip-if = os == "mac" && os_version == "10.8" || os == "win" && os_version == "5.1" # Bug 851129 - Re-enable browser_toolbox_window_shortcuts.js test after leaks are fixed

View File

@ -0,0 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const { on, off } = devtools.require("sdk/event/core");
const { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
function test() {
gDevTools.on("toolbox-created", onToolboxCreated);
on(DebuggerClient, "connect", onDebuggerClientConnect);
addTab("about:blank").then(function() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "webconsole").then(testResults);
});
}
function testResults(toolbox) {
testPackets(sent1, received1);
testPackets(sent2, received2);
cleanUp(toolbox);
}
function cleanUp(toolbox) {
gDevTools.off("toolbox-created", onToolboxCreated);
off(DebuggerClient, "connect", onDebuggerClientConnect);
toolbox.destroy().then(function() {
gBrowser.removeCurrentTab();
executeSoon(function() {
finish();
});
});
}
function testPackets(sent, received) {
ok(sent.length > 0, "There must be at least one sent packet");
ok(received.length > 0, "There must be at leaset one received packet");
if (!sent.length || received.length) {
return;
}
let sentPacket = sent[0];
let receivedPacket = received[0];
is(receivedPacket.from, "root",
"The first received packet is from the root");
is(receivedPacket.applicationType, "browser",
"The first received packet has browser type");
is(sentPacket.type, "listTabs",
"The first sent packet is for list of tabs");
}
// Listen to the transport object that is associated with the
// default Toolbox debugger client
let sent1 = [];
let received1 = [];
function send1(eventId, packet) {
sent1.push(packet);
}
function onPacket1(eventId, packet) {
received1.push(packet);
}
function onToolboxCreated(eventId, toolbox) {
toolbox.target.makeRemote();
let client = toolbox.target.client;
let transport = client._transport;
transport.on("send", send1);
transport.on("onPacket", onPacket1);
client.addOneTimeListener("closed", event => {
transport.off("send", send1);
transport.off("onPacket", onPacket1);
});
}
// Listen to all debugger client object protocols.
let sent2 = [];
let received2 = [];
function send2(eventId, packet) {
sent2.push(packet);
}
function onPacket2(eventId, packet) {
received2.push(packet);
}
function onDebuggerClientConnect(client) {
let transport = client._transport;
transport.on("send", send2);
transport.on("onPacket", onPacket2);
client.addOneTimeListener("closed", event => {
transport.off("send", send2);
transport.off("onPacket", onPacket2);
});
}

View File

@ -20,6 +20,11 @@ function consoleOpened(hud) {
return waitForMessages({
webconsole: hud,
messages: [{
text: "undefined",
category: CATEGORY_OUTPUT,
severity: SEVERITY_LOG,
},
{
text: "start",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,

View File

@ -20,7 +20,7 @@
}
function testXhrWarn(aCallback) {
makeXhr('get', 'http://example.com', null, aCallback);
makeXhr('get', 'http://example.com/browser/browser/devtools/netmonitor/test/sjs_cors-test-server.sjs', null, aCallback);
}
function testXhrPost(aCallback) {

View File

@ -9,6 +9,7 @@ const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).de
const {AppProjects} = require("devtools/app-manager/app-projects");
const {AppValidator} = require("devtools/app-manager/app-validator");
const {AppManager} = require("devtools/webide/app-manager");
const {ProjectBuilding} = require("devtools/webide/build");
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad);
@ -44,6 +45,8 @@ function resetUI() {
document.querySelector("#manifestURL").textContent = "";
document.querySelector("#location").textContent = "";
document.querySelector("#prePackageLog").hidden = true;
document.querySelector("#errorslist").innerHTML = "";
document.querySelector("#warningslist").innerHTML = "";
@ -102,6 +105,12 @@ function updateUI() {
}
}
if (project.type != "runtimeApp" && project.type != "mainProcess") {
ProjectBuilding.hasPrepackage(project).then(hasPrepackage => {
document.querySelector("#prePackageLog").hidden = !hasPrepackage;
});
}
let errorsNode = document.querySelector("#errorslist");
let warningsNode = document.querySelector("#warningslist");
@ -122,6 +131,10 @@ function updateUI() {
}
}
function showPrepackageLog() {
window.top.UI.selectDeckPanel("logs");
}
function removeProject() {
AppManager.removeSelectedProject();
}

View File

@ -43,6 +43,8 @@
<h3 id="manifestURLHeader">&details_manifestURL;</h3>
<p id="manifestURL"></p>
<button id="prePackageLog" onclick="showPrepackageLog()" hidden="true">&details_showPrepackageLog_button;</button>
</main>
<ul class="validation_messages" id="errorslist"></ul>

View File

@ -26,3 +26,5 @@ webide.jar:
content/devicesettings.xhtml (devicesettings.xhtml)
content/wifi-auth.js (wifi-auth.js)
content/wifi-auth.xhtml (wifi-auth.xhtml)
content/logs.xhtml (logs.xhtml)
content/logs.js (logs.js)

View File

@ -0,0 +1,71 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cu = Components.utils;
Cu.import("resource:///modules/devtools/gDevTools.jsm");
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const {AppManager} = require("devtools/webide/app-manager");
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad);
Logs.init();
});
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
Logs.uninit();
});
const Logs = {
init: function () {
this.list = document.getElementById("logs");
Logs.onAppManagerUpdate = Logs.onAppManagerUpdate.bind(this);
AppManager.on("app-manager-update", Logs.onAppManagerUpdate);
document.getElementById("close").onclick = Logs.close.bind(this);
},
uninit: function () {
AppManager.off("app-manager-update", Logs.onAppManagerUpdate);
},
onAppManagerUpdate: function(event, what, details) {
switch (what) {
case "pre-package":
this.prePackageLog(details);
break;
};
},
close: function () {
window.parent.UI.openProject();
},
prePackageLog: function (msg, details) {
if (msg == "start") {
this.clear();
} else if (msg == "succeed") {
setTimeout(function () {
Logs.close();
}, 1000);
} else if (msg == "failed") {
this.log(details);
} else {
this.log(msg);
}
},
clear: function () {
this.list.innerHTML = "";
},
log: function (msg) {
let line = document.createElement("li");
line.textContent = msg;
this.list.appendChild(line);
}
};

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % webideDTD SYSTEM "chrome://browser/locale/devtools/webide.dtd" >
%webideDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://webide/skin/logs.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://browser/content/devtools/theme-switching.js"></script>
<script type="application/javascript;version=1.8" src="logs.js"></script>
</head>
<body>
<div id="controls">
<a id="close">&deck_close;</a>
</div>
<h1>&logs_title;</h1>
<ul id="logs" class="devtools-monospace">
</ul>
</body>
</html>

View File

@ -195,6 +195,9 @@ let UI = {
case "runtime-apps-found":
this.autoSelectProject();
break;
case "pre-package":
this.prePackageLog(details);
break;
};
this._updatePromise = promise.resolve();
},
@ -768,9 +771,13 @@ let UI = {
},
selectDeckPanel: function(id) {
let deck = document.querySelector("#deck");
if (deck.selectedPanel && deck.selectedPanel.id === "deck-panel-" + id) {
// This panel is already displayed.
return;
}
this.hidePanels();
this.resetFocus();
let deck = document.querySelector("#deck");
let panel = deck.querySelector("#deck-panel-" + id);
let lazysrc = panel.getAttribute("lazysrc");
if (lazysrc) {
@ -1004,6 +1011,12 @@ let UI = {
document.querySelector("#action-button-debug").removeAttribute("active");
this.updateToolboxFullscreenState();
},
prePackageLog: function (msg) {
if (msg == "start") {
UI.selectDeckPanel("logs");
}
}
};
let Cmds = {

View File

@ -201,6 +201,7 @@
<iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/>
<iframe id="deck-panel-devicepreferences" flex="1" lazysrc="devicepreferences.xhtml"/>
<iframe id="deck-panel-devicesettings" flex="1" lazysrc="devicesettings.xhtml"/>
<iframe id="deck-panel-logs" flex="1" src="logs.xhtml"/>
</deck>
<splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/>
<!-- toolbox iframe will be inserted here -->

View File

@ -481,7 +481,10 @@ let AppManager = exports.AppManager = {
return Task.spawn(function* () {
let self = AppManager;
let packageDir = yield ProjectBuilding.build(project);
let packageDir = yield ProjectBuilding.build({
project: project,
logger: self.update.bind(self, "pre-package")
});
yield self.validateProject(project);

View File

@ -30,13 +30,32 @@ const ProjectBuilding = exports.ProjectBuilding = {
return manifest;
}),
// If the app depends on some build step, run it before pushing the app
build: Task.async(function* (project) {
hasPrepackage: Task.async(function* (project) {
let manifest = yield ProjectBuilding.fetchPackageManifest(project);
if (!manifest || !manifest.webide || !manifest.webide.prepackage) {
return manifest && manifest.webide && "prepackage" in manifest.webide;
}),
// If the app depends on some build step, run it before pushing the app
build: Task.async(function* ({ project, logger }) {
if (!this.hasPrepackage(project)) {
return;
}
let manifest = yield ProjectBuilding.fetchPackageManifest(project);
logger("start");
let packageDir;
try {
packageDir = yield this._build(project, manifest, logger);
logger("succeed");
} catch(e) {
logger("failed", e);
}
return packageDir;
}),
_build: Task.async(function* (project, manifest, logger) {
// Look for `webide` property
manifest = manifest.webide;
@ -80,10 +99,10 @@ const ProjectBuilding = exports.ProjectBuilding = {
cwd = project.location;
}
console.log("Running pre-package hook '" + command + "' " +
args.join(" ") +
" with ENV=[" + env.join(", ") + "]" +
" at " + cwd);
logger("Running pre-package hook '" + command + "' " +
args.join(" ") +
" with ENV=[" + env.join(", ") + "]" +
" at " + cwd);
// Run the command through a shell command in order to support non absolute
// paths.
@ -115,12 +134,12 @@ const ProjectBuilding = exports.ProjectBuilding = {
workdir: cwd,
stdout: data =>
console.log("pre-package: " + data),
logger(data),
stderr: data =>
console.error("pre-package: " + data),
logger(data),
done: result => {
console.log("pre-package: Terminated with error code: " + result.exitCode);
logger("Terminated with error code: " + result.exitCode);
if (result.exitCode == 0) {
defer.resolve();
} else {

View File

@ -50,8 +50,20 @@
ok(!project.manifest, "manifest includes name");
is(project.name, "--", "Display name uses manifest name");
let packageDir = yield ProjectBuilding.build(project);
let loggedMessages = [];
let logger = function (msg) {
loggedMessages.push(msg);
}
let packageDir = yield ProjectBuilding.build({
project,
logger
});
ok(!packageDir, "no custom packagedir");
is(loggedMessages[0], "start", "log messages are correct");
ok(loggedMessages[1].indexOf("Running pre-package hook") != -1, "log messages are correct");
is(loggedMessages[2], "Terminated with error code: 0", "log messages are correct");
is(loggedMessages[3], "succeed", "log messages are correct");
// Trigger validation
yield AppManager.validateProject(AppManager.selectedProject);
@ -70,9 +82,17 @@
project = win.AppManager.selectedProject;
packageDir = yield ProjectBuilding.build(project);
loggedMessages = [];
packageDir = yield ProjectBuilding.build({
project,
logger
});
is(OS.Path.normalize(packageDir),
OS.Path.join(packagedAppLocation, "stage"), "custom packagedir");
is(loggedMessages[0], "start", "log messages are correct");
ok(loggedMessages[1].indexOf("Running pre-package hook") != -1, "log messages are correct");
is(loggedMessages[2], "Terminated with error code: 0", "log messages are correct");
is(loggedMessages[3], "succeed", "log messages are correct");
// Switch to the package dir in order to verify the generated webapp.manifest
yield win.Cmds.importPackagedApp(packageDir);

View File

@ -17,3 +17,4 @@ webide.jar:
skin/monitor.css (monitor.css)
skin/config-view.css (config-view.css)
skin/wifi-auth.css (wifi-auth.css)
skin/logs.css (logs.css)

View File

@ -0,0 +1,18 @@
html, body {
background: var(--theme-body-background);
color: var(--theme-body-color);
}
h1 {
font-size: 1.2em;
}
ul {
padding: 0;
font-size: 1em;
}
li {
list-style: none;
margin: 0;
}

View File

@ -94,6 +94,7 @@
<!ENTITY details_location "Location">
<!ENTITY details_manifestURL "App ID">
<!ENTITY details_removeProject_button "Remove Project">
<!ENTITY details_showPrepackageLog_button "Show Pre-package Log">
<!-- New App -->
<!ENTITY newAppWindowTitle "New App">
@ -191,3 +192,6 @@
<!-- LOCALIZATION NOTE (wifi_auth_token_request): Instructions requesting the
user to transfer authentication info by transferring a token. -->
<!ENTITY wifi_auth_token_request "If your other device asks for a token instead of scanning a QR code, please copy the value below to the other device:">
<!-- Logs panel -->
<!ENTITY logs_title "Pre-packaging Command Logs">

View File

@ -29,6 +29,12 @@
<include layout="@layout/shared_ui_components"/>
<ViewStub android:id="@+id/zoomed_view_stub"
android:inflatedId="@+id/zoomed_view"
android:layout="@layout/zoomed_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<FrameLayout android:id="@+id/home_pager_container"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -26,12 +26,6 @@
<include layout="@layout/text_selection_handles"/>
<ViewStub android:id="@+id/zoomed_view_stub"
android:inflatedId="@+id/zoomed_view"
android:layout="@layout/zoomed_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<FrameLayout android:id="@+id/camera_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"

View File

@ -7,6 +7,7 @@ this.EXPORTED_SYMBOLS = ["RemoteAddonsParent"];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import('resource://gre/modules/Services.jsm');
@ -512,22 +513,33 @@ let EventTargetParent = {
for (let [handler, target] of handlers) {
let EventProxy = {
get: function(actualEvent, name) {
if (name == "currentTarget") {
return target;
} else {
return actualEvent[name];
}
get: function(knownProps, name) {
if (knownProps.hasOwnProperty(name))
return knownProps[name];
return event[name];
}
};
let proxyEvent = new Proxy(event, EventProxy);
}
let proxyEvent = new Proxy({
currentTarget: target,
target: eventTarget,
type: type,
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIDOMEventTarget))
return proxyEvent;
// If event deson't support the interface this will throw. If it
// does we want to return the proxy
event.QueryInterface(iid);
return proxyEvent;
}
}, EventProxy);
try {
Prefetcher.withPrefetching(prefetched, cpows, () => {
if ("handleEvent" in handler) {
handler.handleEvent(proxyEvent);
} else {
handler.call(event.target, proxyEvent);
handler.call(eventTarget, proxyEvent);
}
});
} catch (e) {

View File

@ -250,7 +250,7 @@ var LoginManagerContent = {
let doc = form.ownerDocument;
let autofillForm = gAutofillForms && !PrivateBrowsingUtils.isContentWindowPrivate(doc.defaultView);
this._fillForm(form, autofillForm, false, false, false, loginsFound);
this._fillForm(form, autofillForm, false, false, loginsFound);
},
/*
@ -293,7 +293,7 @@ var LoginManagerContent = {
if (usernameField == acInputField && passwordField) {
this._asyncFindLogins(acForm, { showMasterPassword: false })
.then(({ form, loginsFound }) => {
this._fillForm(form, true, true, true, true, loginsFound);
this._fillForm(form, true, true, true, loginsFound);
})
.then(null, Cu.reportError);
} else {
@ -564,14 +564,13 @@ var LoginManagerContent = {
* [success, foundLogins].
*
* - autofillForm denotes if we should fill the form in automatically
* - ignoreAutocomplete denotes if we should ignore autocomplete=off
* attributes
* - userTriggered is an indication of whether this filling was triggered by
* the user
* - foundLogins is an array of nsILoginInfo for optimization
*/
_fillForm : function (form, autofillForm, ignoreAutocomplete,
clobberPassword, userTriggered, foundLogins) {
_fillForm : function (form, autofillForm, clobberPassword,
userTriggered, foundLogins) {
let ignoreAutocomplete = true;
// Heuristically determine what the user/pass fields are
// We do this before checking to see if logins are stored,
// so that the user isn't prompted for a master password

View File

@ -587,8 +587,7 @@ LoginManager.prototype = {
log("fillForm processing form[ id:", form.id, "]");
return LoginManagerContent._asyncFindLogins(form, { showMasterPassword: true })
.then(function({ form, loginsFound }) {
return LoginManagerContent._fillForm(form, true, true,
false, false, loginsFound)[0];
return LoginManagerContent._fillForm(form, true, false, false, loginsFound)[0];
});
},

View File

@ -40,7 +40,6 @@ skip-if = toolkit == 'android'
[test_case_differences.html]
skip-if = toolkit == 'android'
[test_basic_form_html5.html]
[test_basic_form_observer_autocomplete.html]
[test_basic_form_observer_autofillForms.html]
[test_basic_form_observer_foundLogins.html]
[test_basic_form_pwevent.html]
@ -49,7 +48,6 @@ skip-if = toolkit == 'android'
# This test doesn't pass because we can't ensure a cross-platform event that
# occurs between DOMContentLoaded and Pageload
skip-if = true
[test_bug_227640.html]
[test_bug_242956.html]
[test_bug_360493_1.html]
[test_bug_360493_2.html]

View File

@ -558,13 +558,13 @@ function* runTest() {
yield runNextTest();
/* Tests for single-user forms with autocomplete=off */
/* Tests for single-user forms for ignoring autocomplete=off */
/* test 100 */
// Turn our attention to form2
uname = $_(2, "uname");
pword = $_(2, "pword");
checkACForm("", "");
checkACForm("singleuser5", "singlepass5");
// Trigger autocomplete popup
restoreForm();
@ -585,8 +585,8 @@ function* runTest() {
// Turn our attention to form3
uname = $_(3, "uname");
pword = $_(3, "pword");
checkACForm("", "");
checkACForm("singleuser5", "singlepass5");
// Trigger autocomplete popup
restoreForm();
doKey("down");
@ -605,7 +605,7 @@ function* runTest() {
// Turn our attention to form4
uname = $_(4, "uname");
pword = $_(4, "pword");
checkACForm("", "");
checkACForm("singleuser5", "singlepass5");
// Trigger autocomplete popup
restoreForm();
@ -625,7 +625,7 @@ function* runTest() {
// Turn our attention to form5
uname = $_(5, "uname");
pword = $_(5, "pword");
checkACForm("", "");
checkACForm("singleuser5", "singlepass5");
// Trigger autocomplete popup
restoreForm();

View File

@ -1,103 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Login Manager</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="pwmgr_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Login Manager test: simple form with autocomplete off and notifying observers & normal form
<script>
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
commonInit();
SimpleTest.waitForExplicitFinish();
</script>
<p id="display"></p>
<div id="content" style="display: block">
<form id="form1" action="formtest.js" autocomplete="off">
<p>This is form 1.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form2" action="formtest.js">
<p>This is form 2.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: simple form with autocomplete off and notifying observers & normal form **/
var TestObserver = {
receivedNotification1 : false,
receivedNotification2 : false,
data1 : "",
data2 : "",
observe : function (subject, topic, data) {
var pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
if (topic == "passwordmgr-found-form") {
if (subject.id == "form1") {
this.receivedNotification1 = true;
this.data1 = data;
} else if (subject.id == "form2") {
this.receivedNotification2 = true;
this.data2 = data;
}
// Now fill the form
pwmgr.fillForm(subject)
.then(startTest);
}
}
};
// Add the observer
SpecialPowers.addObserver(TestObserver, "passwordmgr-found-form", false);
function startTest(){
// Test that observer is notified & got correct data
is(TestObserver.receivedNotification1, true, "Checking observer was notified");
is(TestObserver.data1, "autocompleteOff", "Checking observer got correct data");
// Check that form1 was filled
is($_(1, "uname").value, "testuser", "Checking for filled username 1");
is($_(1, "pword").value, "testpass", "Checking for filled password 1");
// Test that observer wasn't notified & didn't get data
is(TestObserver.receivedNotification2, false, "Checking observer was not notified");
is(TestObserver.data2, "", "Checking observer didn't get data");
// Check that form2 was filled
is($_(2, "uname").value, "testuser", "Checking for filled username 2");
is($_(2, "pword").value, "testpass", "Checking for filled password 2");
// Remove the observer
try {
SpecialPowers.removeObserver(TestObserver, "passwordmgr-found-form");
} catch (e) {
ok(false, SpecialPowers.wrap(e));
}
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -44,7 +44,7 @@ var TestObserver = {
};
// Initialize the object that stores the results of notifications.
for (var formID of ["form1", "form2", "form3", "form4", "form5"])
for (var formID of ["form1", "form2", "form3", "form5"])
TestObserver.results[formID] = { receivedNotification: false, data: null };
// Add the observer
@ -82,15 +82,6 @@ SpecialPowers.addObserver(TestObserver, "passwordmgr-found-logins", false);
<button type="reset"> Reset </button>
</form>
<form id="form4" action="formtest.js" autocomplete="off">
<p>This is form 4.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form5" action="http://www.example.com">
<p>This is form 5.</p>
<input type="text" name="uname">
@ -139,17 +130,6 @@ function startTest(){
is(TestObserver.results["form3"].data.get("foundLogins").length, 1, "Checking foundLogins contains one login");
is(TestObserver.results["form3"].data.get("selectedLogin"), null, "Checking selectedLogin is null");
// Test notification of a form that wasn't filled because autocomplete is off.
is(TestObserver.results["form4"].receivedNotification, true, "Checking observer was notified");
is(TestObserver.results["form4"].data.get("didntFillReason"), "autocompleteOff", "Checking didntFillReason is autocompleteOff");
is(SpecialPowers.unwrap(TestObserver.results["form4"].data.get("usernameField")), $_(4, "uname"), "Checking username field is correct");
is(SpecialPowers.unwrap(TestObserver.results["form4"].data.get("passwordField")), $_(4, "pword"), "Checking password field is correct");
is(TestObserver.results["form4"].data.get("foundLogins").constructor.name, "Array", "Checking foundLogins is array");
is(TestObserver.results["form4"].data.get("foundLogins").length, 1, "Checking foundLogins contains one login");
ok(TestObserver.results["form4"].data.get("selectedLogin").QueryInterface(Ci.nsILoginInfo), "Checking selectedLogin is nsILoginInfo");
ok(TestObserver.results["form4"].data.get("selectedLogin").equals(TestObserver.results["form4"].data.get("foundLogins")[0]),
"Checking selectedLogin is found login");
// Test notification of a form that wasn't filled because multiple logins
// are available for the form.
is(TestObserver.results["form5"].receivedNotification, true, "Checking observer was notified");

View File

@ -1,243 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Login Manager</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="pwmgr_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Login Manager test: 227640
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
</script>
<p id="display"></p>
<div id="content" style="display: none">
<!-- no autocomplete for password field -->
<form id="form1" onsubmit="return checkSubmit(1)" method="get">
<input type="text" name="uname" value="">
<input type="password" name="pword" value="" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for username field -->
<form id="form2" onsubmit="return checkSubmit(2);" method="get">
<input type="text" name="uname" value="" autocomplete=off>
<input type="password" name="pword" value="">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for username or password fields -->
<form id="form3" onsubmit="return checkSubmit(3);" method="get">
<input type="text" name="uname" value="" autocomplete=off>
<input type="password" name="pword" value="" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form -->
<form id="form4" onsubmit="return checkSubmit(4);" method="get" autocomplete=off>
<input type="text" name="uname" value="">
<input type="password" name="pword" value="">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form and password field -->
<form id="form5" onsubmit="return checkSubmit(5);" method="get">
<input type="text" name="uname" value="">
<input type="password" name="pword" value="" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form and username field -->
<form id="form6" onsubmit="return checkSubmit(6);" method="get">
<input type="text" name="uname" value="" autocomplete=off>
<input type="password" name="pword" value="">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form, userfield, and password field -->
<form id="form7" onsubmit="return checkSubmit(7);" method="get" autocomplete=off>
<input type="text" name="uname" value="" autocomplete=off>
<input type="password" name="pword" value="" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- ===== repeat, but with logins not previously stored ===== -->
<!-- no autocomplete for password field -->
<form id="form8" onsubmit="return checkSubmit(8);" method="get">
<input type="text" name="xxxuname" value="newuser">
<input type="password" name="xxxpword" value="newpass" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for username field -->
<form id="form9" onsubmit="return checkSubmit(9);" method="get">
<input type="text" name="xxxuname" value="newuser" autocomplete=off>
<input type="password" name="xxxpword" value="newpass">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for username or password fields -->
<form id="form10" onsubmit="return checkSubmit(10);" method="get">
<input type="text" name="xxxuname" value="newuser" autocomplete=off>
<input type="password" name="xxxpword" value="newpass" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form -->
<form id="form11" onsubmit="return checkSubmit(11);" method="get" autocomplete=off>
<input type="text" name="xxxuname" value="newuser">
<input type="password" name="xxxpword" value="newpass">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form and password field -->
<form id="form12" onsubmit="return checkSubmit(12);" method="get">
<input type="text" name="xxxuname" value="newuser">
<input type="password" name="xxxpword" value="newpass" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form and username field -->
<form id="form13" onsubmit="return checkSubmit(13);" method="get">
<input type="text" name="xxxuname" value="newuser" autocomplete=off>
<input type="password" name="xxxpword" value="newpass">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<!-- no autocomplete for entire form, userfield, and password field -->
<form id="form14" onsubmit="return checkSubmit(14);" method="get" autocomplete=off>
<input type="text" name="xxxuname" value="newuser" autocomplete=off>
<input type="password" name="xxxpword" value="newpass" autocomplete=off>
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: 227640 (password is saved even when the
password field has autocomplete="off") **/
// This test ensures that pwmgr does not save a username or password when
// autocomplete=off is present.
var numStartingLogins = 0;
var numSubmittedForms = 0;
function startTest() {
// Get current number of logins, so we can know if some accidently get
// added during the test.
numStartingLogins = countLogins();
ok(numStartingLogins > 0, "counting logins at start");
// Check first set of forms, which should not be filled by pwmgr.
for (var i = 1; i <= 7; i++) {
is($_(i, "uname").value, "", "Checking for unfilled username " + i);
is($_(i, "pword").value, "", "Checking for unfilled password " + i);
// Set the field values to that of an existing login
$_(i, "uname").value = "testuser";
$_(i, "pword").value = "testpass";
}
// Check second set of forms, which should have preset values (and are unknown to pwmgr).
for (var i = 8; i <= 14; i++) {
is($_(i, "xxxuname").value, "newuser", "Checking unmodified username " + i);
is($_(i, "xxxpword").value, "newpass", "Checking unmodified password " + i);
}
var button = getFormSubmitButton(1);
// submit the first form.
button.click();
}
// Called by each form's onsubmit handler.
function checkSubmit(formNum) {
numSubmittedForms++;
// End the test at the last form.
if (formNum == 14) {
is(numSubmittedForms, 14, "Ensuring all forms were submitted.");;
var numEndingLogins = countLogins();
ok(numEndingLogins > 0, "counting logins at end");
is(numStartingLogins, numEndingLogins, "counting logins at end");
SimpleTest.finish();
return false; // return false to cancel current form submission
}
var button = getFormSubmitButton(formNum + 1);
// submit the next form.
button.click();
return false; // return false to cancel current form submission
}
function getFormSubmitButton(formNum) {
var form = $("form" + formNum); // by id, not name
ok(form != null, "getting form " + formNum);
// we can't just call form.submit(), because that doesn't seem to
// invoke the form onsubmit handler.
var button = form.firstChild;
while (button && button.type != "submit") { button = button.nextSibling; }
ok(button != null, "getting form submit button");
return button;
}
// Counts the number of logins currently stored by password manager.
function countLogins() {
var logins = pwmgr.getAllLogins();
return logins.length;
}
window.addEventListener("runTests", startTest);
</script>
</pre>
</body>
</html>

View File

@ -41,6 +41,7 @@ const PREF_ENABLED = PREF_BRANCH + "enabled";
const PREF_PREVIOUS_BUILDID = PREF_BRANCH + "previousBuildID";
const PREF_CACHED_CLIENTID = PREF_BRANCH + "cachedClientID"
const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
const PREF_ASYNC_PLUGIN_INIT = "dom.ipc.plugins.asyncInit";
const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload";
@ -547,7 +548,8 @@ let Impl = {
appUpdateChannel: UpdateChannel.get(),
platformBuildID: ai.platformBuildID,
revision: HISTOGRAMS_FILE_VERSION,
locale: getLocale()
locale: getLocale(),
asyncPluginInit: Preferences.get(PREF_ASYNC_PLUGIN_INIT, false)
};
// In order to share profile data, the appName used for Metro Firefox is "Firefox",

View File

@ -396,6 +396,12 @@ DebuggerClient.prototype = {
* received from the debugging server.
*/
connect: function (aOnConnected) {
this.emit("connect");
// Also emit the event on the |DebuggerServer| object (not on
// the instance), so it's possible to track all instances.
events.emit(DebuggerClient, "connect", this);
this.addOneTimeListener("connected", (aName, aApplicationType, aTraits) => {
this.traits = aTraits;
if (aOnConnected) {

View File

@ -30,6 +30,7 @@ const StreamUtils = require("devtools/toolkit/transport/stream-utils");
const { Packet, JSONPacket, BulkPacket } =
require("devtools/toolkit/transport/packets");
const promise = require("promise");
const EventEmitter = require("devtools/toolkit/event-emitter");
DevToolsUtils.defineLazyGetter(this, "Pipe", () => {
return CC("@mozilla.org/pipe;1", "nsIPipe", "init");
@ -100,6 +101,8 @@ const PACKET_HEADER_MAX = 200;
* details on the format of these packets.
*/
function DebuggerTransport(input, output) {
EventEmitter.decorate(this);
this._input = input;
this._scriptableInput = new ScriptableInputStream(input);
this._output = output;
@ -131,6 +134,8 @@ DebuggerTransport.prototype = {
* they are passed to this method.
*/
send: function(object) {
this.emit("send", object);
let packet = new JSONPacket(this);
packet.object = object;
this._outgoing.push(packet);
@ -179,6 +184,8 @@ DebuggerTransport.prototype = {
* that is copied. See stream-utils.js.
*/
startBulkSend: function(header) {
this.emit("startBulkSend", header);
let packet = new BulkPacket(this);
packet.header = header;
this._outgoing.push(packet);
@ -193,6 +200,8 @@ DebuggerTransport.prototype = {
* closing the transport (likely because a stream closed or failed).
*/
close: function(reason) {
this.emit("onClosed", reason);
this.active = false;
this._input.close();
this._scriptableInput.close();
@ -458,6 +467,7 @@ DebuggerTransport.prototype = {
DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
// Ensure the transport is still alive by the time this runs.
if (this.active) {
this.emit("onPacket", object);
this.hooks.onPacket(object);
}
}, "DebuggerTransport instance's this.hooks.onPacket"));
@ -473,6 +483,7 @@ DebuggerTransport.prototype = {
DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
// Ensure the transport is still alive by the time this runs.
if (this.active) {
this.emit("onBulkPacket", ...args);
this.hooks.onBulkPacket(...args);
}
}, "DebuggerTransport instance's this.hooks.onBulkPacket"));
@ -506,6 +517,8 @@ exports.DebuggerTransport = DebuggerTransport;
* @see DebuggerTransport
*/
function LocalDebuggerTransport(other) {
EventEmitter.decorate(this);
this.other = other;
this.hooks = null;
@ -524,6 +537,8 @@ LocalDebuggerTransport.prototype = {
* endpoint.
*/
send: function(packet) {
this.emit("send", packet);
let serial = this._serial.count++;
if (dumpn.wantLogging) {
/* Check 'from' first, as 'echo' packets have both. */
@ -542,6 +557,7 @@ LocalDebuggerTransport.prototype = {
dumpn("Received packet " + serial + ": " + JSON.stringify(packet, null, 2));
}
if (other.hooks) {
other.emit("onPacket", packet);
other.hooks.onPacket(packet);
}
}, "LocalDebuggerTransport instance's this.other.hooks.onPacket"));
@ -558,6 +574,8 @@ LocalDebuggerTransport.prototype = {
* done with it.
*/
startBulkSend: function({actor, type, length}) {
this.emit("startBulkSend", {actor, type, length});
let serial = this._serial.count++;
dumpn("Sent bulk packet " + serial + " for actor " + actor);
@ -575,8 +593,7 @@ LocalDebuggerTransport.prototype = {
// Receiver
let deferred = promise.defer();
this.other.hooks.onBulkPacket({
let packet = {
actor: actor,
type: type,
length: length,
@ -588,7 +605,10 @@ LocalDebuggerTransport.prototype = {
},
stream: pipe.inputStream,
done: deferred
});
};
this.other.emit("onBulkPacket", packet);
this.other.hooks.onBulkPacket(packet);
// Await the result of reading from the stream
deferred.promise.then(() => pipe.inputStream.close(), this.close);
@ -624,6 +644,8 @@ LocalDebuggerTransport.prototype = {
* Close the transport.
*/
close: function() {
this.emit("close");
if (this.other) {
// Remove the reference to the other endpoint before calling close(), to
// avoid infinite recursion.
@ -681,6 +703,8 @@ exports.LocalDebuggerTransport = LocalDebuggerTransport;
* <prefix> is |prefix|, whose data is the protocol packet.
*/
function ChildDebuggerTransport(sender, prefix) {
EventEmitter.decorate(this);
this._sender = sender.QueryInterface(Ci.nsIMessageSender);
this._messageName = "debug:" + prefix + ":packet";
}
@ -701,14 +725,17 @@ ChildDebuggerTransport.prototype = {
close: function () {
this._sender.removeMessageListener(this._messageName, this);
this.emit("onClosed");
this.hooks.onClosed();
},
receiveMessage: function ({data}) {
this.emit("onPacket", data);
this.hooks.onPacket(data);
},
send: function (packet) {
this.emit("send", packet);
this._sender.sendAsyncMessage(this._messageName, packet);
},