merge fx-team to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-11-11 12:04:33 +01:00
commit 10eb71a64a
170 changed files with 9979 additions and 8475 deletions

View File

@ -286,7 +286,7 @@ exports.testSetNoSetRead = function (assert, done) {
function setGetRoot(assert, done, val, compare) {
compare = compare || (a, b) => a === b;
compare = compare || ((a, b) => a === b);
// Load the module once, set a value.
let loader = Loader(module);

View File

@ -995,8 +995,6 @@ pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
#endif
pref("browser.geolocation.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/geolocation/");
pref("browser.push.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/push/");
pref("browser.push.warning.migrationURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/push#w_upgraded-notifications");
pref("browser.EULA.version", 3);
pref("browser.rights.version", 3);

View File

@ -24,7 +24,9 @@ add_task(function* test_permissionMigration() {
let alertWindow = yield alertWindowPromise;
info("Clicking on notification");
let url = Services.urlFormatter.formatURLPref("browser.push.warning.migrationURL");
let url =
Services.urlFormatter.formatURLPref("app.support.baseURL") +
"push#w_upgraded-notifications";
let closePromise = promiseWindowClosed(alertWindow);
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow);

View File

@ -309,10 +309,12 @@ CustomizeMode.prototype = {
this.exit();
}
}.bind(this)).then(null, function(e) {
ERROR(e);
ERROR("Error entering customize mode", e);
// We should ensure this has been called, and calling it again doesn't hurt:
window.PanelUI.endBatchUpdate();
this._handler.isEnteringCustomizeMode = false;
// Exit customize mode to ensure proper clean-up when entering failed.
this.exit();
}.bind(this));
},
@ -482,7 +484,7 @@ CustomizeMode.prototype = {
this.enter();
}
}.bind(this)).then(null, function(e) {
ERROR(e);
ERROR("Error exiting customize mode", e);
// We should ensure this has been called, and calling it again doesn't hurt:
window.PanelUI.endBatchUpdate();
this._handler.isExitingCustomizeMode = false;

View File

@ -166,6 +166,8 @@ const PanelUI = {
document.getAnonymousElementByAttribute(anchor, "class",
"toolbarbutton-icon");
this.panel.openPopup(iconAnchor || anchor);
}, (reason) => {
console.error("Error showing the PanelUI menu", reason);
});
return deferred.promise;

View File

@ -127,7 +127,7 @@ extensions.registerAPI((extension, context) => {
}
};
WindowListManager.addOpenListener(windowListener, false);
WindowListManager.addOpenListener(windowListener);
AllWindowEvents.addListener("TabOpen", listener);
return () => {
WindowListManager.removeOpenListener(windowListener);
@ -195,7 +195,9 @@ extensions.registerAPI((extension, context) => {
let tab = gBrowser.getTabForBrowser(browser);
let tabId = TabManager.getId(tab);
let [needed, changeInfo] = sanitize(extension, {status});
fire(tabId, changeInfo, TabManager.convert(extension, tab));
if (needed) {
fire(tabId, changeInfo, TabManager.convert(extension, tab));
}
},
onLocationChange(browser, webProgress, request, locationURI, flags) {

View File

@ -424,7 +424,7 @@ global.WindowListManager = {
}
},
addOpenListener(listener, fireOnExisting = true) {
addOpenListener(listener) {
if (this._openListeners.length == 0 && this._closeListeners.length == 0) {
Services.ww.registerNotification(this);
}
@ -433,8 +433,6 @@ global.WindowListManager = {
for (let window of this.browserWindows(true)) {
if (window.document.readyState != "complete") {
window.addEventListener("load", this);
} else if (fireOnExisting) {
listener(window);
}
}
},
@ -462,7 +460,7 @@ global.WindowListManager = {
handleEvent(event) {
let window = event.target.defaultView;
window.removeEventListener("load", this.loadListener);
window.removeEventListener("load", this);
if (window.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
return;
}
@ -504,7 +502,9 @@ global.AllWindowEvents = {
return WindowListManager.addCloseListener(listener);
}
let needOpenListener = this._listeners.size == 0;
if (this._listeners.size == 0) {
WindowListManager.addOpenListener(this.openListener);
}
if (!this._listeners.has(type)) {
this._listeners.set(type, new Set());
@ -512,10 +512,7 @@ global.AllWindowEvents = {
let list = this._listeners.get(type);
list.add(listener);
if (needOpenListener) {
WindowListManager.addOpenListener(this.openListener, false);
}
// Register listener on all existing windows.
for (let window of WindowListManager.browserWindows()) {
this.addWindowListener(window, type, listener);
}
@ -537,6 +534,7 @@ global.AllWindowEvents = {
}
}
// Unregister listener from all existing windows.
for (let window of WindowListManager.browserWindows()) {
if (type == "progress") {
window.gBrowser.removeTabsProgressListener(listener);

View File

@ -76,3 +76,93 @@ add_task(function* () {
yield BrowserTestUtils.closeWindow(win1);
});
function* do_test_update(background) {
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
yield focusWindow(win1);
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
},
background: background,
});
yield Promise.all([
yield extension.startup(),
yield extension.awaitFinish("finish")
]);
yield extension.unload();
yield BrowserTestUtils.closeWindow(win1);
}
add_task(function* test_pinned() {
yield do_test_update(function background() {
// Create a new tab for testing update.
browser.tabs.create(null, function(tab) {
browser.tabs.onUpdated.addListener(function onUpdated(tabId, changeInfo) {
// Check callback
browser.test.assertEq(tabId, tab.id, "Check tab id");
browser.test.log("onUpdate: " + JSON.stringify(changeInfo));
if ("pinned" in changeInfo) {
browser.test.assertTrue(changeInfo.pinned, "Check changeInfo.pinned");
browser.tabs.onUpdated.removeListener(onUpdated);
// Remove created tab.
browser.tabs.remove(tabId);
browser.test.notifyPass("finish");
return;
}
});
browser.tabs.update(tab.id, {pinned: true});
});
});
});
add_task(function* test_unpinned() {
yield do_test_update(function background() {
// Create a new tab for testing update.
browser.tabs.create({pinned: true}, function(tab) {
browser.tabs.onUpdated.addListener(function onUpdated(tabId, changeInfo) {
// Check callback
browser.test.assertEq(tabId, tab.id, "Check tab id");
browser.test.log("onUpdate: " + JSON.stringify(changeInfo));
if ("pinned" in changeInfo) {
browser.test.assertFalse(changeInfo.pinned, "Check changeInfo.pinned");
browser.tabs.onUpdated.removeListener(onUpdated);
// Remove created tab.
browser.tabs.remove(tabId);
browser.test.notifyPass("finish");
return;
}
});
browser.tabs.update(tab.id, {pinned: false});
});
});
});
add_task(function* test_url() {
yield do_test_update(function background() {
// Create a new tab for testing update.
browser.tabs.create(null, function(tab) {
browser.tabs.onUpdated.addListener(function onUpdated(tabId, changeInfo) {
// Check callback
browser.test.assertEq(tabId, tab.id, "Check tab id");
browser.test.log("onUpdate: " + JSON.stringify(changeInfo));
if ("url" in changeInfo) {
browser.test.assertEq("about:preferences", changeInfo.url,
"Check changeInfo.url");
browser.tabs.onUpdated.removeListener(onUpdated);
// Remove created tab.
browser.tabs.remove(tabId);
browser.test.notifyPass("finish");
return;
}
});
browser.tabs.update(tab.id, {url: "about:preferences"});
});
});
});

View File

@ -507,7 +507,9 @@ loop.OTSdkDriver = (function() {
case "Session.forceDisconnected":
break;
default:
if (eventName.indexOf("sdk.exception") === -1) {
// We don't want unexpected events being sent to the server, so
// filter out the unexpected, and let the known ones through.
if (!/^sdk\.(exception|datachannel)/.test(eventName)) {
console.error("Unexpected event name", eventName);
return;
}
@ -620,7 +622,7 @@ loop.OTSdkDriver = (function() {
this.dispatcher.dispatch(new sharedActions.MediaConnected());
}
this._setupDataChannelIfNeeded(sdkSubscriberObject.stream.connection);
this._setupDataChannelIfNeeded(sdkSubscriberObject);
},
/**
@ -655,64 +657,28 @@ loop.OTSdkDriver = (function() {
* channel set-up routines. A data channel cannot be requested before this
* time as the peer connection is not set up.
*
* @param {OT.Connection} connection The OT connection class object.paul
* sched
* @param {OT.Subscriber} sdkSubscriberObject The subscriber object for the stream.
*
*/
_setupDataChannelIfNeeded: function(connection) {
if (this._useDataChannels) {
this.session.signal({
type: "readyForDataChannel",
to: connection
}, function(signalError) {
if (signalError) {
console.error(signalError);
}
});
}
},
/**
* Handles receiving the signal that the other end of the connection
* has subscribed to the stream and we're ready to setup the data channel.
*
* We get data channels for both the publisher and subscriber on reception
* of the signal, as it means that a) the remote client is setup for data
* channels, and b) that subscribing of streams has definitely completed
* for both clients.
*
* @param {OT.SignalEvent} event Details of the signal received.
*/
_onReadyForDataChannel: function(event) {
// If we don't want data channels, just ignore the message. We haven't
// send the other side a message, so it won't display anything.
_setupDataChannelIfNeeded: function(sdkSubscriberObject) {
if (!this._useDataChannels) {
return;
}
// This won't work until a subscriber exists for this publisher
this.publisher._.getDataChannel("text", {}, function(err, channel) {
if (err) {
console.error(err);
return;
this.session.signal({
type: "readyForDataChannel",
to: sdkSubscriberObject.stream.connection
}, function(signalError) {
if (signalError) {
console.error(signalError);
}
});
this._publisherChannel = channel;
channel.on({
close: function(e) {
// XXX We probably want to dispatch and handle this somehow.
console.log("Published data channel closed!");
}
});
this._checkDataChannelsAvailable();
}.bind(this));
this.subscriber._.getDataChannel("text", {}, function(err, channel) {
sdkSubscriberObject._.getDataChannel("text", {}, function(err, channel) {
// Sends will queue until the channel is fully open.
if (err) {
console.error(err);
this._notifyMetricsEvent("sdk.datachannel.sub." + err.message);
return;
}
@ -741,6 +707,45 @@ loop.OTSdkDriver = (function() {
}.bind(this));
},
/**
* Handles receiving the signal that the other end of the connection
* has subscribed to the stream and we're ready to setup the data channel.
*
* We create the publisher data channel when we get the signal as it means
* that the remote client is setup for data
* channels. Getting the data channel for the subscriber is handled
* separately when the subscription completes.
*
* @param {OT.SignalEvent} event Details of the signal received.
*/
_onReadyForDataChannel: function(event) {
// If we don't want data channels, just ignore the message. We haven't
// send the other side a message, so it won't display anything.
if (!this._useDataChannels) {
return;
}
// This won't work until a subscriber exists for this publisher
this.publisher._.getDataChannel("text", {}, function(err, channel) {
if (err) {
console.error(err);
this._notifyMetricsEvent("sdk.datachannel.pub." + err.message);
return;
}
this._publisherChannel = channel;
channel.on({
close: function(e) {
// XXX We probably want to dispatch and handle this somehow.
console.log("Published data channel closed!");
}
});
this._checkDataChannelsAvailable();
}.bind(this));
},
/**
* Checks to see if all channels have been obtained, and if so it dispatches
* a notification to the stores to inform them.

File diff suppressed because it is too large Load Diff

View File

@ -142,6 +142,50 @@ class Test1BrowserCall(MarionetteTestCase):
self.switch_to_chatbox()
self.check_video(".remote-video")
def send_chat_message(self, text):
"""
Sends a chat message using the current context.
:param text: The text to send.
"""
chatbox = self.wait_for_element_displayed(By.CSS_SELECTOR,
".text-chat-box > form > input")
chatbox.send_keys(text + "\n")
def check_received_message(self, expectedText):
"""
Checks a chat message has been received in the current context. The
test assumes only one chat message will be received during the tests.
:param expectedText: The expected text of the chat message.
"""
text_entry = self.wait_for_element_displayed(By.CSS_SELECTOR,
".text-chat-entry.received > p > span")
self.assertEqual(text_entry.text, expectedText,
"should have received the correct message")
def check_text_messaging(self):
"""
Checks text messaging between the generator and clicker in a bi-directional
fashion.
"""
# Send a message using the link generator.
self.switch_to_chatbox()
self.send_chat_message("test1")
# Now check the result on the link clicker.
self.switch_to_standalone()
self.check_received_message("test1")
# Then send a message using the standalone.
self.send_chat_message("test2")
# Finally check the link generator got it.
self.switch_to_chatbox()
self.check_received_message("test2")
def local_enable_screenshare(self):
self.switch_to_chatbox()
button = self.marionette.find_element(By.CLASS_NAME, "btn-screen-share")
@ -242,6 +286,9 @@ class Test1BrowserCall(MarionetteTestCase):
self.standalone_check_remote_video()
self.local_check_remote_video()
# Check text messaging
self.check_text_messaging()
# since bi-directional media is connected, make sure we've set
# the start time
self.local_check_media_start_time_initialized()

View File

@ -752,6 +752,9 @@ describe("loop.OTSdkDriver", function() {
};
fakeSubscriberObject = _.extend({
"_": {
getDataChannel: sinon.stub()
},
session: { connection: fakeConnection },
stream: fakeStream
}, Backbone.Events);
@ -996,131 +999,225 @@ describe("loop.OTSdkDriver", function() {
}));
});
it("should subscribe to a camera stream", function() {
session.trigger("streamCreated", { stream: fakeStream });
describe("Audio/Video streams", function() {
beforeEach(function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
videoElement).returns(this.fakeSubscriberObject);
});
sinon.assert.calledOnce(session.subscribe);
sinon.assert.calledWithExactly(session.subscribe,
fakeStream, sinon.match.instanceOf(HTMLDivElement), publisherConfig,
sinon.match.func);
});
it("should subscribe to a camera stream", function() {
session.trigger("streamCreated", { stream: fakeStream });
it("should dispatch MediaStreamCreated after subscribe is complete", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
videoElement).returns(this.fakeSubscriberObject);
driver.session = session;
fakeStream.connection = fakeConnection;
fakeStream.hasVideo = true;
sinon.assert.calledOnce(session.subscribe);
sinon.assert.calledWithExactly(session.subscribe,
fakeStream, sinon.match.instanceOf(HTMLDivElement), publisherConfig,
sinon.match.func);
});
session.trigger("streamCreated", { stream: fakeStream });
it("should dispatch MediaStreamCreated after streamCreated is triggered on the session", function() {
driver.session = session;
fakeStream.connection = fakeConnection;
fakeStream.hasVideo = true;
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.MediaStreamCreated({
hasVideo: true,
isLocal: false,
srcMediaElement: videoElement
}));
});
session.trigger("streamCreated", { stream: fakeStream });
it("should dispatch MediaStreamCreated after subscribe with audio-only indication if hasVideo=false", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
videoElement);
fakeStream.connection = fakeConnection;
fakeStream.hasVideo = false;
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.MediaStreamCreated({
hasVideo: true,
isLocal: false,
srcMediaElement: videoElement
}));
});
session.trigger("streamCreated", { stream: fakeStream });
it("should dispatch MediaStreamCreated after streamCreated with audio-only indication if hasVideo=false", function() {
fakeStream.connection = fakeConnection;
fakeStream.hasVideo = false;
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.MediaStreamCreated({
hasVideo: false,
isLocal: false,
srcMediaElement: videoElement
}));
});
session.trigger("streamCreated", { stream: fakeStream });
it("should trigger a readyForDataChannel signal after subscribe is complete", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
document.createElement("video"));
driver._useDataChannels = true;
fakeStream.connection = fakeConnection;
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.MediaStreamCreated({
hasVideo: false,
isLocal: false,
srcMediaElement: videoElement
}));
});
session.trigger("streamCreated", { stream: fakeStream });
it("should dispatch a mediaConnected action if both streams are up", function() {
driver._publishedLocalStream = true;
sinon.assert.calledOnce(session.signal);
sinon.assert.calledWith(session.signal, {
type: "readyForDataChannel",
to: fakeConnection
session.trigger("streamCreated", { stream: fakeStream });
// Called twice due to the VideoDimensionsChanged above.
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
new sharedActions.MediaConnected({}));
});
it("should store the start time when both streams are up and" +
" driver._sendTwoWayMediaTelemetry is true", function() {
driver._sendTwoWayMediaTelemetry = true;
driver._publishedLocalStream = true;
var startTime = 1;
sandbox.stub(performance, "now").returns(startTime);
session.trigger("streamCreated", { stream: fakeStream });
expect(driver._getTwoWayMediaStartTime()).to.eql(startTime);
});
it("should not store the start time when both streams are up and" +
" driver._isDesktop is false", function() {
driver._isDesktop = false;
driver._publishedLocalStream = true;
var startTime = 73;
sandbox.stub(performance, "now").returns(startTime);
session.trigger("streamCreated", { stream: fakeStream });
expect(driver._getTwoWayMediaStartTime()).to.not.eql(startTime);
});
describe("Data channel setup", function() {
var fakeChannel;
beforeEach(function() {
fakeChannel = _.extend({}, Backbone.Events);
fakeStream.connection = fakeConnection;
driver._useDataChannels = true;
sandbox.stub(console, "error");
});
it("should trigger a readyForDataChannel signal after subscribe is complete", function() {
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.calledOnce(session.signal);
sinon.assert.calledWith(session.signal, {
type: "readyForDataChannel",
to: fakeConnection
});
});
it("should not trigger readyForDataChannel signal if data channels are not wanted", function() {
driver._useDataChannels = false;
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.notCalled(session.signal);
});
it("should get the data channel after subscribe is complete", function() {
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.calledOnce(fakeSubscriberObject._.getDataChannel);
sinon.assert.calledWith(fakeSubscriberObject._.getDataChannel, "text", {});
});
it("should not get the data channel if data channels are not wanted", function() {
driver._useDataChannels = false;
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.notCalled(fakeSubscriberObject._.getDataChannel);
});
it("should log an error if the data channel couldn't be obtained", function() {
var err = new Error("fakeError");
fakeSubscriberObject._.getDataChannel.callsArgWith(2, err);
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.calledOnce(console.error);
sinon.assert.calledWithMatch(console.error, err);
});
it("should dispatch ConnectionStatus if the data channel couldn't be obtained", function() {
fakeSubscriberObject._.getDataChannel.callsArgWith(2, new Error("fakeError"));
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
connections: 0,
event: "sdk.datachannel.sub.fakeError",
sendStreams: 0,
state: "receiving",
recvStreams: 1
}));
});
it("should dispatch `DataChannelsAvailable` if the publisher channel is setup", function() {
// Fake a publisher channel.
driver._publisherChannel = {};
fakeSubscriberObject._.getDataChannel.callsArgWith(2, null, fakeChannel);
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.DataChannelsAvailable({
available: true
}));
});
it("should not dispatch `DataChannelsAvailable` if the publisher channel isn't setup", function() {
fakeSubscriberObject._.getDataChannel.callsArgWith(2, null, fakeChannel);
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.neverCalledWith(dispatcher.dispatch,
new sharedActions.DataChannelsAvailable({
available: true
}));
});
it("should dispatch `ReceivedTextChatMessage` when a text message is received", function() {
var data = '{"contentType":"' + CHAT_CONTENT_TYPES.TEXT +
'","message":"Are you there?","receivedTimestamp": "2015-06-25T00:29:14.197Z"}';
var clock = sinon.useFakeTimers();
fakeSubscriberObject._.getDataChannel.callsArgWith(2, null, fakeChannel);
session.trigger("streamCreated", { stream: fakeStream });
// Now send the message.
fakeChannel.trigger("message", {
data: data
});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ReceivedTextChatMessage({
contentType: CHAT_CONTENT_TYPES.TEXT,
message: "Are you there?",
receivedTimestamp: "1970-01-01T00:00:00.000Z"
}));
/* Restore the time. */
clock.restore();
});
});
});
it("should not trigger readyForDataChannel signal if data channels are not wanted", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
document.createElement("video"));
driver._useDataChannels = false;
fakeStream.connection = fakeConnection;
describe("screen sharing streams", function() {
it("should subscribe to a screen sharing stream", function() {
fakeStream.videoType = "screen";
session.trigger("streamCreated", { stream: fakeStream });
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.notCalled(session.signal);
});
sinon.assert.calledOnce(session.subscribe);
sinon.assert.calledWithExactly(session.subscribe,
fakeStream, sinon.match.instanceOf(HTMLDivElement), publisherConfig,
sinon.match.func);
});
it("should subscribe to a screen sharing stream", function() {
fakeStream.videoType = "screen";
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.calledOnce(session.subscribe);
sinon.assert.calledWithExactly(session.subscribe,
fakeStream, sinon.match.instanceOf(HTMLDivElement), publisherConfig,
sinon.match.func);
});
it("should dispatch a mediaConnected action if both streams are up", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
videoElement);
driver._publishedLocalStream = true;
session.trigger("streamCreated", { stream: fakeStream });
// Called twice due to the VideoDimensionsChanged above.
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
new sharedActions.MediaConnected({}));
});
it("should store the start time when both streams are up and" +
" driver._sendTwoWayMediaTelemetry is true", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
videoElement);
driver._sendTwoWayMediaTelemetry = true;
driver._publishedLocalStream = true;
var startTime = 1;
sandbox.stub(performance, "now").returns(startTime);
session.trigger("streamCreated", { stream: fakeStream });
expect(driver._getTwoWayMediaStartTime()).to.eql(startTime);
});
it("should not store the start time when both streams are up and" +
" driver._isDesktop is false", function() {
session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
videoElement);
driver._isDesktop = false;
driver._publishedLocalStream = true;
var startTime = 73;
sandbox.stub(performance, "now").returns(startTime);
session.trigger("streamCreated", { stream: fakeStream });
expect(driver._getTwoWayMediaStartTime()).to.not.eql(startTime);
});
it("should not dispatch a mediaConnected action for screen sharing streams",
function() {
it("should not dispatch a mediaConnected action for screen sharing streams", function() {
driver._publishedLocalStream = true;
fakeStream.videoType = "screen";
@ -1130,16 +1227,14 @@ describe("loop.OTSdkDriver", function() {
sinon.match.hasOwn("name", "mediaConnected"));
});
it("should not dispatch a ReceivingScreenShare action for camera streams",
function() {
it("should not dispatch a ReceivingScreenShare action for camera streams", function() {
session.trigger("streamCreated", { stream: fakeStream });
sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
new sharedActions.ReceivingScreenShare({ receiving: true }));
});
it("should dispatch a ReceivingScreenShare action for screen" +
" sharing streams", function() {
it("should dispatch a ReceivingScreenShare action for screen sharing streams", function() {
fakeStream.videoType = "screen";
session.trigger("streamCreated", { stream: fakeStream });
@ -1149,6 +1244,7 @@ describe("loop.OTSdkDriver", function() {
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ReceivingScreenShare({ receiving: true }));
});
});
});
describe("streamDestroyed: publisher/local", function() {
@ -1482,6 +1578,7 @@ describe("loop.OTSdkDriver", function() {
beforeEach(function() {
driver.subscriber = subscriber;
driver._useDataChannels = true;
sandbox.stub(console, "error");
});
it("should not do anything if data channels are not wanted", function() {
@ -1499,16 +1596,38 @@ describe("loop.OTSdkDriver", function() {
sinon.assert.calledOnce(publisher._.getDataChannel);
});
it("should get the data channel for the subscriber", function() {
it("should log an error if the data channel couldn't be obtained", function() {
var err = new Error("fakeError");
publisher._.getDataChannel.callsArgWith(2, err);
session.trigger("signal:readyForDataChannel");
sinon.assert.calledOnce(subscriber._.getDataChannel);
sinon.assert.calledOnce(console.error);
sinon.assert.calledWithMatch(console.error, err);
});
it("should dispatch `DataChannelsAvailable` once both data channels have been obtained", function() {
it("should dispatch ConnectionStatus if the data channel couldn't be obtained", function() {
publisher._.getDataChannel.callsArgWith(2, new Error("fakeError"));
session.trigger("signal:readyForDataChannel");
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
connections: 0,
event: "sdk.datachannel.pub.fakeError",
sendStreams: 0,
state: "starting",
recvStreams: 0
}));
});
it("should dispatch `DataChannelsAvailable` if the subscriber channel is setup", function() {
var fakeChannel = _.extend({}, Backbone.Events);
subscriber._.getDataChannel.callsArgWith(2, null, fakeChannel);
driver._subscriberChannel = fakeChannel;
publisher._.getDataChannel.callsArgWith(2, null, fakeChannel);
session.trigger("signal:readyForDataChannel");
@ -1520,31 +1639,17 @@ describe("loop.OTSdkDriver", function() {
}));
});
it("should dispatch `ReceivedTextChatMessage` when a text message is received", function() {
it("should not dispatch `DataChannelsAvailable` if the subscriber channel isn't setup", function() {
var fakeChannel = _.extend({}, Backbone.Events);
var data = '{"contentType":"' + CHAT_CONTENT_TYPES.TEXT +
'","message":"Are you there?","receivedTimestamp": "2015-06-25T00:29:14.197Z"}';
var clock = sinon.useFakeTimers();
subscriber._.getDataChannel.callsArgWith(2, null, fakeChannel);
publisher._.getDataChannel.callsArgWith(2, null, fakeChannel);
session.trigger("signal:readyForDataChannel");
// Now send the message.
fakeChannel.trigger("message", {
data: data
});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ReceivedTextChatMessage({
contentType: CHAT_CONTENT_TYPES.TEXT,
message: "Are you there?",
receivedTimestamp: "1970-01-01T00:00:00.000Z"
sinon.assert.neverCalledWith(dispatcher.dispatch,
new sharedActions.DataChannelsAvailable({
available: true
}));
/* Restore the time. */
clock.restore();
});
});

View File

@ -2287,7 +2287,8 @@ BrowserGlue.prototype = {
"chrome://branding/content/about-logo.png";
let title = gBrowserBundle.GetStringFromName("webNotifications.upgradeTitle");
let text = gBrowserBundle.GetStringFromName("webNotifications.upgradeBody");
let url = Services.urlFormatter.formatURLPref("browser.push.warning.migrationURL");
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") +
"push#w_upgraded-notifications";
AlertsService.showAlertNotification(imageURL, title, text,
true, url, clickCallback);
@ -2765,7 +2766,8 @@ ContentPermissionPrompt.prototype = {
}
var options = {
learnMoreURL: Services.urlFormatter.formatURLPref("browser.push.warning.infoURL"),
learnMoreURL:
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push",
};
this._showPrompt(aRequest, message, "desktop-notification", actions,

View File

@ -74,7 +74,8 @@ var gContentPane = {
setEventListener("notificationsDoNotDisturb", "command",
gContentPane.toggleDoNotDisturbNotifications);
let notificationInfoURL = Services.urlFormatter.formatURLPref("browser.push.warning.infoURL");
let notificationInfoURL =
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
document.getElementById("notificationsPolicyLearnMore").setAttribute("href",
notificationInfoURL);

View File

@ -53,13 +53,6 @@ body {
flex: 1;
}
/* Pressing the retry button will cause the cursor to flicker from a pointer to
* not-allowed. Override the disabled cursor behaviour since we will never show
* the button disabled as the initial state. Remove this in Bug 1219861. */
button:disabled {
cursor: pointer;
}
#returnButton {
background-color: var(--in-content-primary-button-background);
border: none;

View File

@ -164,13 +164,10 @@
.browserContainer > findbar,
#browser-bottombox {
background-color: var(--chrome-secondary-background-color) !important;
background-image: none !important;
color: var(--chrome-color);
}
.browserContainer > findbar {
background-image: none;
}
.browserContainer > .findbar-textbox {
background-color: var(--url-and-searchbar-background-color) !important;
color: var(--url-and-searchbar-color);
@ -245,7 +242,6 @@ window:not([chromehidden~="toolbar"]) #urlbar-wrapper {
border-bottom: none !important;
border-radius: 0 !important;
box-shadow: 0 -1px var(--chrome-nav-bar-separator-color) !important;
background-image: none !important;
}
/* No extra vertical padding for nav bar */

View File

@ -24,6 +24,18 @@ memory.panelLabel=Memory Panel
# displayed inside the developer tools window.
memory.tooltip=Memory
# LOCALIZATION NOTE (snapshot.io.save): The label for the link that saves a snapshot
# to disk.
snapshot.io.save=Save
# LOCALIZATION NOTE (snapshot.io.save.window): The title for the window displayed when
# saving a snapshot to disk.
snapshot.io.save.window=Save Heap Snapshot
# LOCALIZATION NOTE (snapshot.io.filter): The title for the filter used to
# filter file types (*.fxsnapshot)
snapshot.io.filter=Firefox Heap Snapshots
# LOCALIZATION NOTE (aggregate.mb): The label annotating the number of bytes (in megabytes)
# in a snapshot. %S represents the value, rounded to 2 decimal points.
aggregate.mb=%S MB

View File

@ -23,7 +23,6 @@ support-files =
doc_markup_toggle.html
doc_markup_tooltip.png
doc_markup_xul.xul
frame-script-utils.js
head.js
helper_attributes_test_runner.js
helper_events_test_runner.js

View File

@ -20,10 +20,7 @@ add_task(function*() {
info("Press arrowUp to focus <body> " +
"(which works if the node was focused properly)");
let onNodeHighlighted = toolbox.once("node-highlight");
EventUtils.synthesizeKey("VK_UP", {});
yield waitForChildrenUpdated(inspector);
yield onNodeHighlighted;
yield selectPreviousNodeWithArrowUp(inspector);
assertNodeSelected(inspector, "body");
info("Select the test node with the element picker");
@ -32,10 +29,7 @@ add_task(function*() {
info("Press arrowUp to focus <body> " +
"(which works if the node was focused properly)");
onNodeHighlighted = toolbox.once("node-highlight");
EventUtils.synthesizeKey("VK_UP", {});
yield waitForChildrenUpdated(inspector);
yield onNodeHighlighted;
yield selectPreviousNodeWithArrowUp(inspector);
assertNodeSelected(inspector, "body");
});
@ -44,29 +38,18 @@ function assertNodeSelected(inspector, tagName) {
`The <${tagName}> node is selected`);
}
function* selectWithBrowserMenu(inspector) {
// This test can't use BrowserTestUtils.synthesizeMouseAtCenter()
// method (see below) since it causes intermittent test failures.
// So, we are introducing a new "Test:MarkupView:SynthesizeMouse" event
// that is handled in the content scope. The main difference between
// this new event and BrowserTestUtils library is EventUtils library.
// While BrowserTestUtils is using:
// chrome://mochikit/content/tests/SimpleTest/EventUtils.js
// (see: AsyncUtilsContent.js)
// ... this test requires:
// chrome://marionette/content/EventUtils.js
// (see markupview/test/frame-script-utils.js)
// See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1199180
yield executeInContent("Test:MarkupView:SynthesizeMouse", {
center: true,
selector: "div",
options: {type: "contextmenu", button: 2}
});
function selectPreviousNodeWithArrowUp(inspector) {
let onNodeHighlighted = inspector.toolbox.once("node-highlight");
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_UP", {});
return Promise.all([onUpdated, onNodeHighlighted]);
}
//yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
// type: "contextmenu",
// button: 2
//}, gBrowser.selectedBrowser);
function* selectWithBrowserMenu(inspector) {
yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
type: "contextmenu",
button: 2
}, gBrowser.selectedBrowser);
// nsContextMenu also requires the popupNode to be set, but we can't set it to
// node under e10s as it's a CPOW, not a DOM node. But under e10s,
@ -89,16 +72,9 @@ function* selectWithBrowserMenu(inspector) {
function* selectWithElementPicker(inspector) {
yield inspector.toolbox.highlighterUtils.startPicker();
yield executeInContent("Test:MarkupView:SynthesizeMouse", {
center: true,
selector: "div",
options: {type: "mousemove"}
});
// Read comment in selectWithBrowserMenu() method.
//yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
// type: "mousemove",
//}, gBrowser.selectedBrowser);
yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
type: "mousemove",
}, gBrowser.selectedBrowser);
executeInContent("Test:SynthesizeKey", {
key: "VK_RETURN",

View File

@ -1,46 +0,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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var {classes: Cc, interfaces: Ci} = Components;
const subScriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
var EventUtils = {};
subScriptLoader.loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
/**
* Synthesize a mouse event on an element. This handler doesn't send a message
* back. Consumers should listen to specific events on the inspector/highlighter
* to know when the event got synthesized.
* @param {Object} msg The msg.data part expects the following properties:
* - {Number} x
* - {Number} y
* - {Boolean} center If set to true, x/y will be ignored and
* synthesizeMouseAtCenter will be used instead
* - {Object} options Other event options
* - {String} selector An optional selector that will be used to find the node to
* synthesize the event on, if msg.objects doesn't contain the CPOW.
* The msg.objects part should be the element.
* @param {Object} data Event detail properties:
*/
addMessageListener("Test:MarkupView:SynthesizeMouse", function(msg) {
let {x, y, center, options, selector} = msg.data;
let {node} = msg.objects;
if (!node && selector) {
node = content.document.querySelector(selector);
}
if (center) {
EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView);
} else {
EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView);
}
// Most consumers won't need to listen to this message, unless they want to
// wait for the mouse event to be synthesized and don't have another event
// to listen to instead.
sendAsyncMessage("Test:MarkupView:SynthesizeMouse");
});

View File

@ -51,7 +51,6 @@ registerCleanupFunction(function*() {
const TEST_URL_ROOT = "http://mochi.test:8888/browser/devtools/client/markupview/test/";
const CHROME_BASE = "chrome://mochitests/content/browser/devtools/client/markupview/test/";
const COMMON_FRAME_SCRIPT_URL = "chrome://devtools/content/shared/frame-script-utils.js";
const MARKUPVIEW_FRAME_SCRIPT_URL = CHROME_BASE + "frame-script-utils.js";
/**
* Add a new test tab in the browser and load the given url.
@ -72,7 +71,6 @@ function addTab(url) {
info("Loading the helper frame script " + COMMON_FRAME_SCRIPT_URL);
linkedBrowser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
linkedBrowser.messageManager.loadFrameScript(MARKUPVIEW_FRAME_SCRIPT_URL, false);
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);

View File

@ -0,0 +1,45 @@
/* 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/. */
"use strict";
const { assert } = require("devtools/shared/DevToolsUtils");
const { snapshotState: states, actions } = require("../constants");
const { L10N, openFilePicker } = require("../utils");
const { OS } = require("resource://gre/modules/osfile.jsm");
const VALID_EXPORT_STATES = [states.SAVED, states.READ, states.SAVING_CENSUS, states.SAVED_CENSUS];
exports.pickFileAndExportSnapshot = function (snapshot) {
return function* (dispatch, getState) {
let outputFile = yield openFilePicker({
title: L10N.getFormatStr("snapshot.io.save.window"),
defaultName: OS.Path.basename(snapshot.path),
filters: [[L10N.getFormatStr("snapshot.io.filter"), "*.fxsnapshot"]]
});
if (!outputFile) {
return;
}
yield dispatch(exportSnapshot(snapshot, outputFile.path));
};
};
const exportSnapshot = exports.exportSnapshot = function (snapshot, dest) {
return function* (dispatch, getState) {
dispatch({ type: actions.EXPORT_SNAPSHOT_START, snapshot });
assert(VALID_EXPORT_STATES.includes(snapshot.state),
`Snapshot is in invalid state for exporting: ${snapshot.state}`);
try {
yield OS.File.copy(snapshot.path, dest);
} catch (error) {
reportException("exportSnapshot", error);
dispatch({ type: actions.EXPORT_SNAPSHOT_ERROR, snapshot, error });
}
dispatch({ type: actions.EXPORT_SNAPSHOT_END, snapshot });
};
};

View File

@ -8,5 +8,6 @@ DevToolsModules(
'breakdown.js',
'filter.js',
'inverted.js',
'io.js',
'snapshot.js',
)

View File

@ -9,6 +9,7 @@ const { toggleRecordingAllocationStacks } = require("./actions/allocations");
const { setBreakdownAndRefresh } = require("./actions/breakdown");
const { toggleInvertedAndRefresh } = require("./actions/inverted");
const { setFilterStringAndRefresh } = require("./actions/filter");
const { pickFileAndExportSnapshot } = require("./actions/io");
const { selectSnapshotAndRefresh, takeSnapshotAndCensus } = require("./actions/snapshot");
const { breakdownNameToSpec, getBreakdownDisplayData } = require("./utils");
const Toolbar = createFactory(require("./components/toolbar"));
@ -78,7 +79,8 @@ const App = createClass({
List({
itemComponent: SnapshotListItem,
items: snapshots,
onClick: snapshot => dispatch(selectSnapshotAndRefresh(heapWorker, snapshot))
onClick: snapshot => dispatch(selectSnapshotAndRefresh(heapWorker, snapshot)),
onSave: snapshot => dispatch(pickFileAndExportSnapshot(snapshot))
}),
HeapView({

View File

@ -23,9 +23,9 @@ const List = module.exports = createClass({
return (
dom.ul({ className: "list" }, ...items.map((item, index) => {
return Item({
return Item(Object.assign({}, this.props, {
key: index, item, index, onClick: () => onClick(item),
});
}));
}))
);
}

View File

@ -11,13 +11,14 @@ const SnapshotListItem = module.exports = createClass({
displayName: "snapshot-list-item",
propTypes: {
onClick: PropTypes.func,
onClick: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired,
item: snapshotModel.isRequired,
index: PropTypes.number.isRequired,
},
render() {
let { index, item: snapshot, onClick } = this.props;
let { index, item: snapshot, onClick, onSave } = this.props;
let className = `snapshot-list-item ${snapshot.selected ? " selected" : ""}`;
let statusText = getSnapshotStatusText(snapshot);
let title = getSnapshotTitle(snapshot);
@ -34,12 +35,20 @@ const SnapshotListItem = module.exports = createClass({
details = dom.span({ className: "snapshot-state" }, statusText);
}
let saveLink = !snapshot.path ? void 0 : dom.a({
onClick: () => onSave(snapshot),
className: "save",
}, L10N.getFormatStr("snapshot.io.save"));
return (
dom.li({ className, onClick },
dom.span({
className: `snapshot-title ${statusText ? " devtools-throbber" : ""}`
}, title),
details
dom.div({ className: "snapshot-info" },
details,
saveLink
)
)
);
}

View File

@ -23,6 +23,12 @@ actions.TAKE_CENSUS_END = "take-census-end";
actions.TOGGLE_RECORD_ALLOCATION_STACKS_START = "toggle-record-allocation-stacks-start";
actions.TOGGLE_RECORD_ALLOCATION_STACKS_END = "toggle-record-allocation-stacks-end";
// When a heap snapshot is being saved to a user-specified
// location on disk.
actions.EXPORT_SNAPSHOT_START = "export-snapshot-start";
actions.EXPORT_SNAPSHOT_END = "export-snapshot-end";
actions.EXPORT_SNAPSHOT_ERROR = "export-snapshot-error";
// Fired by UI to select a snapshot to view.
actions.SELECT_SNAPSHOT = "select-snapshot";

View File

@ -8,6 +8,20 @@ const reducers = require("./reducers");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
module.exports = function () {
let shouldLog = DevToolsUtils.testing;
return createStore({ log: shouldLog })(combineReducers(reducers), {});
let shouldLog = false;
let history;
// If testing, store the action history in an array
// we'll later attach to the store
if (DevToolsUtils.testing) {
history = [];
}
let store = createStore({ log: shouldLog, history })(combineReducers(reducers), {});
if (history) {
store.history = history;
}
return store;
};

View File

@ -8,6 +8,8 @@ var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
var { gDevTools } = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
var { console } = Cu.import("resource://gre/modules/Console.jsm", {});
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var { OS } = require("resource://gre/modules/osfile.jsm");
var { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
var { TargetFactory } = require("devtools/client/framework/target");
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var promise = require("promise");
@ -70,6 +72,25 @@ function waitUntilState (store, predicate) {
return deferred.promise;
}
function waitUntilAction (store, actionType) {
let deferred = promise.defer();
let unsubscribe = store.subscribe(check);
let history = store.history;
let index = history.length;
do_print(`Waiting for action "${actionType}"`);
function check () {
let action = history[index++];
if (action && action.type === actionType) {
do_print(`Found action "${actionType}"`);
unsubscribe();
deferred.resolve(store.getState());
}
}
return deferred.promise;
}
function waitUntilSnapshotState (store, expected) {
let predicate = () => {
let snapshots = store.getState().snapshots;

View File

@ -0,0 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test exporting a snapshot to a user specified location on disk.
let { exportSnapshot } = require("devtools/client/memory/actions/io");
let { takeSnapshotAndCensus } = require("devtools/client/memory/actions/snapshot");
let { snapshotState: states, actions } = require("devtools/client/memory/constants");
function run_test() {
run_next_test();
}
add_task(function *() {
let front = new StubbedMemoryFront();
let heapWorker = new HeapAnalysesClient();
yield front.attach();
let store = Store();
const { getState, dispatch } = store;
let file = FileUtils.getFile("TmpD", ["tmp.fxsnapshot"]);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
let destPath = file.path;
let stat = yield OS.File.stat(destPath);
ok(stat.size === 0, "new file is 0 bytes at start");
dispatch(takeSnapshotAndCensus(front, heapWorker));
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);
let exportEvents = Promise.all([
waitUntilAction(store, actions.EXPORT_SNAPSHOT_START),
waitUntilAction(store, actions.EXPORT_SNAPSHOT_END)
]);
dispatch(exportSnapshot(getState().snapshots[0], destPath));
yield exportEvents;
stat = yield OS.File.stat(destPath);
do_print(stat.size);
ok(stat.size > 0, "destination file is more than 0 bytes");
heapWorker.destroy();
yield front.detach();
});

View File

@ -35,7 +35,7 @@ add_task(function *() {
let s1 = utils.createSnapshot();
let s2 = utils.createSnapshot();
ok(s1.state, states.SAVING, "utils.createSnapshot() creates snapshot in saving state");
equal(s1.state, states.SAVING, "utils.createSnapshot() creates snapshot in saving state");
ok(s1.id !== s2.id, "utils.createSnapshot() creates snapshot with unique ids");
ok(utils.breakdownEquals(utils.breakdownNameToSpec("coarseType"), breakdowns.coarseType.breakdown),

View File

@ -5,6 +5,7 @@ tail =
firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_action-export-snapshot.js]
[test_action-filter-01.js]
[test_action-filter-02.js]
[test_action-filter-03.js]

View File

@ -2,7 +2,7 @@
* 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 } = require("chrome");
const { Cu, Cc, Ci } = require("chrome");
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
const STRINGS_URI = "chrome://devtools/locale/memory.properties"
@ -314,3 +314,40 @@ exports.parseSource = function (source) {
return { short, long, host };
};
/**
* Takes some configurations and opens up a file picker and returns
* a promise to the chosen file if successful.
*
* @param {String} .title
* The title displayed in the file picker window.
* @param {Array<Array<String>>} .filters
* An array of filters to display in the file picker. Each filter in the array
* is a duple of two strings, one a name for the filter, and one the filter itself
* (like "*.json").
* @param {String} .defaultName
* The default name chosen by the file picker window.
* @return {Promise<?nsILocalFile>}
* The file selected by the user, or null, if cancelled.
*/
exports.openFilePicker = function({ title, filters, defaultName }) {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, title, Ci.nsIFilePicker.modeSave);
for (let filter of (filters || [])) {
fp.appendFilter(filter[0], filter[1]);
}
fp.defaultString = defaultName;
return new Promise(resolve => {
fp.open({
done: result => {
if (result === Ci.nsIFilePicker.returnCancel) {
resolve(null);
return;
}
resolve(fp.file);
}
});
});
};

View File

@ -567,7 +567,11 @@ RuleRewriter.prototype = {
* declarations.
*
* @param {String} text The input text. This should include the trailing ";".
* @return {String} Text that has been rewritten to be "lexically safe".
* @return {Array} An array of the form [anySanitized, text], where
* |anySanitized| is a boolean that indicates
* whether anything substantive has changed; and
* where |text| is the text that has been rewritten
* to be "lexically safe".
*/
sanitizePropertyValue: function(text) {
let lexer = DOMUtils.getCSSLexer(text);
@ -575,6 +579,7 @@ RuleRewriter.prototype = {
let result = "";
let previousOffset = 0;
let braceDepth = 0;
let anySanitized = false;
while (true) {
let token = lexer.nextToken();
if (!token) {
@ -605,6 +610,7 @@ RuleRewriter.prototype = {
// Quote the offending symbol.
result += "\\" + token.text;
previousOffset = token.endOffset;
anySanitized = true;
}
break;
}
@ -612,9 +618,13 @@ RuleRewriter.prototype = {
}
// Copy out any remaining text, then any needed terminators.
result += text.substring(previousOffset, text.length) +
lexer.performEOFFixup("", true);
return result;
result += text.substring(previousOffset, text.length);
let eofFixup = lexer.performEOFFixup("", true);
if (eofFixup) {
anySanitized = true;
result += eofFixup;
}
return [anySanitized, result];
},
/**
@ -662,10 +672,16 @@ RuleRewriter.prototype = {
// before any trailing whitespace.
this.result = this.result.substring(0, endIndex) + termDecl.terminator +
trailingText;
// The terminator includes the ";", but we don't want it in
// the changed value.
this.changedDeclarations[index] =
termDecl.value + termDecl.terminator.slice(0, -1);
// In a couple of cases, we may have had to add something to
// terminate the declaration, but the termination did not
// actually affect the property's value -- and at this spot, we
// only care about reporting value changes. In particular, we
// might have added a plain ";", or we might have terminated a
// comment with "*/;". Neither of these affect the value.
if (termDecl.terminator !== ";" && termDecl.terminator !== "*/;") {
this.changedDeclarations[index] =
termDecl.value + termDecl.terminator.slice(0, -1);
}
}
// If the rule generally has newlines, but this particular
// declaration doesn't have a trailing newline, insert one now.
@ -685,8 +701,8 @@ RuleRewriter.prototype = {
* @return {String} The sanitized text.
*/
sanitizeText: function(text, index) {
let sanitizedText = this.sanitizePropertyValue(text);
if (sanitizedText !== text) {
let [anySanitized, sanitizedText] = this.sanitizePropertyValue(text);
if (anySanitized) {
this.changedDeclarations[index] = sanitizedText;
}
return sanitizedText;

View File

@ -9,14 +9,17 @@ const { waitUntilService } = require("./middleware/wait-service");
const { task } = require("./middleware/task");
const { log } = require("./middleware/log");
const { promise } = require("./middleware/promise");
const { history } = require("./middleware/history");
/**
* This creates a dispatcher with all the standard middleware in place
* that all code requires. It can also be optionally configured in
* various ways, such as logging and recording.
*
* @param {object} opts - boolean configuration flags
* @param {object} opts:
* - log: log all dispatched actions to console
* - history: an array to store every action in. Should only be
* used in tests.
* - middleware: array of middleware to be included in the redux store
*/
module.exports = (opts={}) => {
@ -27,13 +30,17 @@ module.exports = (opts={}) => {
promise,
];
if (opts.log) {
middleware.push(log);
if (opts.history) {
middleware.push(history(opts.history));
}
if (opts.middleware) {
opts.middleware.forEach(fn => middleware.push(fn));
}
if (opts.log) {
middleware.push(log);
}
return applyMiddleware(...middleware)(createStore);
}

View File

@ -0,0 +1,23 @@
/* 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/. */
"use strict";
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
/**
* A middleware that stores every action coming through the store in the passed
* in logging object. Should only be used for tests, as it collects all
* action information, which will cause memory bloat.
*/
exports.history = (log=[]) => ({ dispatch, getState }) => {
if (!DevToolsUtils.testing) {
console.warn(`Using history middleware stores all actions in state for testing\
and devtools is not currently running in test mode. Be sure this is\
intentional.`);
}
return next => action => {
log.push(action);
next(action);
};
};

View File

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'history.js',
'log.js',
'promise.js',
'task.js',

View File

@ -6,7 +6,7 @@ var {colorUtils} = require("devtools/shared/css-color");
var origColorUnit;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
info("Creating a test canvas element to test colors");

View File

@ -11,7 +11,7 @@ const {CubicBezierWidget} =
require("devtools/client/shared/widgets/CubicBezierWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
info("Checking that the graph markup is created in the parent");

View File

@ -12,7 +12,7 @@ const {CubicBezierWidget} =
const {PREDEFINED} = require("devtools/client/shared/widgets/CubicBezierPresets");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
// Required or widget will be clipped inside of 'bottom'

View File

@ -12,7 +12,7 @@ const {CubicBezierWidget} =
const {PREDEFINED} = require("devtools/client/shared/widgets/CubicBezierPresets");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
let container = doc.querySelector("#container");

View File

@ -12,7 +12,7 @@ const {CubicBezierPresetWidget} =
const {PRESETS} = require("devtools/client/shared/widgets/CubicBezierPresets");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
let container = doc.querySelector("#container");

View File

@ -13,7 +13,7 @@ const {PREDEFINED, PRESETS, DEFAULT_PRESET_CATEGORY} =
require("devtools/client/shared/widgets/CubicBezierPresets");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
let container = doc.querySelector("#container");

View File

@ -13,7 +13,7 @@ const {CubicBezierWidget} =
const {PRESETS} = require("devtools/client/shared/widgets/CubicBezierPresets");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
let container = doc.querySelector("#container");

View File

@ -9,7 +9,7 @@ const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
add_task(function *() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -13,7 +13,7 @@ const STRINGS_URI = "chrome://devtools/locale/filterwidget.properties";
const L10N = new ViewHelpers.L10N(STRINGS_URI);
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const TEST_DATA = [

View File

@ -12,7 +12,7 @@ const GRAYSCALE_MAX = 100;
const INVERT_MIN = 0;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -10,7 +10,7 @@ const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWi
const LIST_ITEM_HEIGHT = 32;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -16,7 +16,7 @@ const GRAYSCALE_MAX = 100,
GRAYSCALE_MIN = 0;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -7,7 +7,6 @@
const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
const { Cu } = require("chrome");
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
const { ViewHelpers } = Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm", {});
@ -15,7 +14,7 @@ const STRINGS_URI = "chrome://devtools/locale/filterwidget.properties";
const L10N = new ViewHelpers.L10N(STRINGS_URI);
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -7,7 +7,6 @@
const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
const { Cu } = require("chrome");
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
const { ViewHelpers } = Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm", {});
@ -15,7 +14,7 @@ const STRINGS_URI = "chrome://devtools/locale/filterwidget.properties";
const L10N = new ViewHelpers.L10N(STRINGS_URI);
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -14,7 +14,7 @@ const SLOW_VALUE_MULTIPLIER = 0.1;
const DEFAULT_VALUE_MULTIPLIER = 1;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -14,7 +14,7 @@ const SLOW_VALUE_MULTIPLIER = 0.1;
const DEFAULT_VALUE_MULTIPLIER = 1;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -14,7 +14,7 @@ const SLOW_VALUE_MULTIPLIER = 0.1;
const DEFAULT_VALUE_MULTIPLIER = 1;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
const container = doc.querySelector("#container");

View File

@ -9,7 +9,7 @@ const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
add_task(function* () {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);

View File

@ -9,7 +9,7 @@ const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
add_task(function* () {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);

View File

@ -9,7 +9,7 @@ const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
add_task(function* () {
yield promiseTab("about:blank");
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);

View File

@ -6,7 +6,7 @@
var {FlameGraph} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -6,7 +6,7 @@
var {FlameGraph} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -11,7 +11,7 @@ var TEST_HEIGHT = 100;
var {FlameGraph} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -12,7 +12,7 @@ var TEST_DPI_DENSITIY = 2;
var {FlameGraph} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -12,7 +12,7 @@ var TEST_DPI_DENSITIY = 2;
var {FlameGraph} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -12,7 +12,7 @@ var {FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY} = require("devtools/client/shared/widge
var L10N = new ViewHelpers.L10N();
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ var {FlameGraphUtils} = require("devtools/client/shared/widgets/FlameGraph");
var {PALLETTE_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ var {FlameGraphUtils} = require("devtools/client/shared/widgets/FlameGraph");
var {PALLETTE_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ var {PALLETTE_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
var {FrameNode} = require("devtools/client/performance/modules/logic/tree-model");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ var {PALLETTE_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
var {FrameNode} = require("devtools/client/performance/modules/logic/tree-model");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -6,7 +6,7 @@
var {FlameGraphUtils} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ var {FlameGraphUtils} = require("devtools/client/shared/widgets/FlameGraph");
var {PALLETTE_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -6,7 +6,7 @@
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
finish();

View File

@ -8,7 +8,7 @@ const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -6,7 +6,7 @@
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -9,7 +9,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
var CURRENT_ZOOM = 1;
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ const TEST_DATA = [{ delta: 100, value: 60 }, { delta: 200, value: 59.9 }];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -10,7 +10,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ const TEST_DATA = [{ delta: 100, value: 60 }, { delta: 200, value: 1 }];
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -5,7 +5,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -12,7 +12,7 @@ const CATEGORIES = [
];
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -12,7 +12,7 @@ const CATEGORIES = [
];
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -8,7 +8,7 @@ var BarGraphWidget = require("devtools/client/shared/widgets/BarGraphWidget");
var {CanvasGraphUtils} = require("devtools/client/shared/widgets/Graphs");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -6,7 +6,7 @@
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -7,7 +7,7 @@ const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -23,7 +23,7 @@ for (let frameRate of FRAMES) {
var LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -20,7 +20,7 @@ const SECTIONS = [
];
add_task(function*() {
yield promiseTab("about:blank");
yield addTab("about:blank");
yield performTest();
gBrowser.removeCurrentTab();
});

View File

@ -4,13 +4,12 @@
"use strict";
var promise = require("promise");
var {editableField, getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
// Test the inplace-editor behavior.
add_task(function*() {
yield promiseTab("data:text/html;charset=utf-8,inline editor tests");
yield addTab("data:text/html;charset=utf-8,inline editor tests");
let [host, win, doc] = yield createHost();
yield testMultipleInitialization(doc);

View File

@ -5,12 +5,11 @@
"use strict";
var {editableField, getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
var promise = require("promise");
// Test that the trimOutput option for the inplace editor works correctly.
add_task(function*() {
yield promiseTab("data:text/html;charset=utf-8,inline editor tests");
yield addTab("data:text/html;charset=utf-8,inline editor tests");
let [host, win, doc] = yield createHost();
yield testNonTrimmed(doc);

View File

@ -9,28 +9,27 @@ var {getAdjustedQuads} = require("devtools/shared/layout/utils");
const TEST_URI = TEST_URI_ROOT + "browser_layoutHelpers-getBoxQuads.html";
function test() {
addTab(TEST_URI, function(browser, tab) {
let doc = browser.contentDocument;
add_task(function* () {
ok(typeof getAdjustedQuads === "function", "getAdjustedQuads is defined");
let tab = yield addTab(TEST_URI);
let doc = tab.linkedBrowser.contentDocument;
info("Running tests");
ok(typeof getAdjustedQuads === "function", "getAdjustedQuads is defined");
returnsTheRightDataStructure(doc);
isEmptyForMissingNode(doc);
isEmptyForHiddenNodes(doc);
defaultsToBorderBoxIfNoneProvided(doc);
returnsLikeGetBoxQuadsInSimpleCase(doc);
takesIframesOffsetsIntoAccount(doc);
takesScrollingIntoAccount(doc);
takesZoomIntoAccount(doc);
returnsMultipleItemsForWrappingInlineElements(doc);
info("Running tests");
gBrowser.removeCurrentTab();
finish();
});
}
returnsTheRightDataStructure(doc);
isEmptyForMissingNode(doc);
isEmptyForHiddenNodes(doc);
defaultsToBorderBoxIfNoneProvided(doc);
returnsLikeGetBoxQuadsInSimpleCase(doc);
takesIframesOffsetsIntoAccount(doc);
takesScrollingIntoAccount(doc);
takesZoomIntoAccount(doc);
returnsMultipleItemsForWrappingInlineElements(doc);
gBrowser.removeCurrentTab();
});
function returnsTheRightDataStructure(doc) {
info("Checks that the returned data contains bounds and 4 points");

Some files were not shown because too many files have changed in this diff Show More