This commit is contained in:
Wes Kocher 2016-08-12 16:29:24 -07:00
Родитель 64542d8c51 b44cee8b2a
Коммит b1e2d2ad52
413 изменённых файлов: 29759 добавлений и 3696 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -74,6 +74,9 @@ python/psutil/build/
devtools/client/chrome.manifest
devtools/shared/chrome.manifest
# Ignore node_modules directories in devtools
devtools/client/**/node_modules
# Tag files generated by GNU Global
GTAGS
GRTAGS

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

@ -78,6 +78,9 @@ _OPT\.OBJ/
^devtools/client/chrome.manifest$
^devtools/shared/chrome.manifest$
# Ignore node_modules directories in devtools
^devtools/client/.*/node_modules/
# git checkout of libstagefright
^media/libstagefright/android$

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

@ -7198,6 +7198,8 @@ var gIdentityHandler = {
if (event.target == this._identityPopup) {
window.addEventListener("focus", this, true);
}
this._identityPopupMultiView._mainView.style.height =
this._identityPopup.getBoundingClientRect().height + "px";
},
onPopupHidden(event) {

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

@ -384,6 +384,12 @@ function* closeStream(aAlreadyClosed, aFrameId) {
if (promises)
yield Promise.all(promises);
// If a GC occurs before MediaStream.stop() is dispatched, we'll receive
// recording-device-events for each track instead of one for the stream.
if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
todo(false, "Stream was GC'd before MediaStream.stop() was dispatched (bug 1284038)");
}
yield* assertWebRTCIndicatorStatus(null);
}

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

@ -152,7 +152,7 @@ const PanelUI = {
anchor = aEvent.target;
}
this.panel.addEventListener("popupshown", function onPopupShown() {
this.panel.addEventListener("popupshown", function onPopupShown(event) {
this.removeEventListener("popupshown", onPopupShown);
resolve();
});

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

@ -58,8 +58,7 @@
<field name="_anchorElement">null</field>
<field name="_mainViewHeight">0</field>
<field name="_subViewObserver">null</field>
<field name="__transitioning">false</field>
<field name="_ignoreMutations">false</field>
<field name="__transitioning">true</field>
<property name="showingSubView" readonly="true"
onget="return this._viewStack.getAttribute('viewtype') == 'subview'"/>
@ -69,22 +68,6 @@
<property name="showingSubViewAsMainView" readonly="true"
onget="return this.getAttribute('mainViewIsSubView') == 'true'"/>
<property name="ignoreMutations">
<getter>
return this._ignoreMutations;
</getter>
<setter><![CDATA[
this._ignoreMutations = val;
if (!val && this._panel.state == "open") {
if (this.showingSubView) {
this._syncContainerWithSubView();
} else {
this._syncContainerWithMainView();
}
}
]]></setter>
</property>
<property name="_transitioning">
<getter>
return this.__transitioning;
@ -223,7 +206,10 @@
let container = this._viewContainer;
this._transitioning = true;
let onTransitionEnd = () => {
let onTransitionEnd = (event) => {
if (event.propertyName != "transform") {
return;
}
container.removeEventListener("transitionend", onTransitionEnd);
this._transitioning = false;
};
@ -296,7 +282,6 @@
}
break;
case "popupshowing":
this.setAttribute("panelopen", "true");
// Bug 941196 - The panel can get taller when opening a subview. Disabling
// autoPositioning means that the panel won't jump around if an opened
// subview causes the panel to exceed the dimensions of the screen in the
@ -312,9 +297,18 @@
subtree: true
});
break;
case "popupshown":
this._setMaxHeight();
let onTransitionEnd = (event) => {
if (event.propertyName != "transform") {
return;
}
let panel = event.target;
panel.removeEventListener("tranitionend", onTransitionEnd);
// Needed in case the panel is closed before the transition ends.
if (panel.state == "open") {
this.setAttribute("panelopen", "true");
}
};
this._panel.addEventListener("transitionend", onTransitionEnd);
break;
case "popuphidden":
this.removeAttribute("panelopen");
@ -338,22 +332,9 @@
]]></body>
</method>
<method name="_setMaxHeight">
<body><![CDATA[
if (!this._shouldSetHeight())
return;
// Ignore the mutation that'll fire when we set the height of
// the main view.
this.ignoreMutations = true;
this._mainView.style.height =
this.getBoundingClientRect().height + "px";
this.ignoreMutations = false;
]]></body>
</method>
<method name="_adjustContainerHeight">
<body><![CDATA[
if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
if (!this.showingSubView && !this._transitioning) {
let height;
if (this.showingSubViewAsMainView) {
height = this._heightOfSubview(this._mainView);
@ -371,7 +352,7 @@
return;
}
if (!this.ignoreMutations && this.showingSubView) {
if (this.showingSubView) {
let newHeight = this._heightOfSubview(this._currentSubView, this._subViews);
this._viewContainer.style.height = newHeight + "px";
}

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

@ -149,7 +149,8 @@ skip-if = os == "mac"
[browser_1096763_seen_widgets_post_reset.js]
[browser_1161838_inserted_new_default_buttons.js]
[browser_bootstrapped_custom_toolbar.js]
[browser_check_tooltips_in_navbar.js]
[browser_customizemode_contextmenu_menubuttonstate.js]
[browser_no_mutationrecords_during_panel_opening.js]
[browser_panel_toggle.js]
[browser_switch_to_customize_mode.js]
[browser_check_tooltips_in_navbar.js]

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

@ -0,0 +1,88 @@
/* 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";
/**
* Test that we don't get unexpected mutations during the opening of the
* browser menu.
*/
add_task(function* test_setup() {
yield resetCustomization();
yield PanelUI.show();
let hiddenPromise = promisePanelHidden(window);
PanelUI.hide();
yield hiddenPromise;
});
add_task(function* no_mutation_events_during_opening() {
let panel = PanelUI.panel;
yield PanelUI.ensureReady();
let failures = 0;
let observer = new MutationObserver(function(mutations) {
for (let mutation of mutations) {
if (mutation.target.localName == "panel" &&
mutation.type == "attributes" &&
mutation.attributeName == "animate") {
// This mutation is allowed because it triggers the CSS transition.
continue;
}
if (mutation.type == "attributes" &&
mutation.attributeName == "panelopen") {
// This mutation is allowed because it is set after the panel has
// finished the transition.
continue;
}
let newValue = null;
if (mutation.type == "attributes") {
newValue = mutation.target.getAttribute(mutation.attributeName);
} else if (mutation.type == "characterData") {
newValue = mutation.target.textContent;
}
if (AppConstants.isPlatformAndVersionAtMost("win", "6.1") &&
mutation.target.className == "panel-arrowbox" &&
mutation.attributeName == "style" &&
newValue.startsWith("transform:")) {
// Windows 7 and earlier has an alignment offset on the arrowbox.
// This is allowed here as it is no longer used on newer platforms.
continue;
}
if (newValue == mutation.oldValue) {
// Mutations records are observed even when the new and old value are
// identical. This is unlikely to invalidate the panel, so ignore these.
continue;
}
let nodeIdentifier = `${mutation.target.localName}#${mutation.target.id}.${mutation.target.className};`;
ok(false, `Observed: ${mutation.type}; ${nodeIdentifier} ${mutation.attributeName}; oldValue: ${mutation.oldValue}; newValue: ${newValue}`);
failures++;
}
});
observer.observe(panel, {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeOldValue: true,
characterDataOldValue: true,
});
let shownPromise = promisePanelShown(window);
PanelUI.show();
yield shownPromise;
observer.disconnect();
is(failures, 0, "There should be no unexpected mutation events during opening of the panel");
});
add_task(function* cleanup() {
let hiddenPromise = promisePanelHidden(window);
PanelUI.hide();
yield hiddenPromise;
});

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

@ -175,17 +175,23 @@ function* testPopupSize(standardsMode, browserWin = window, arrowSide = "top") {
let checkPanelPosition = () => {
is(panel.getAttribute("side"), arrowSide, "Panel arrow is positioned as expected");
function isGreaterThanOrWithinPixelRoundingError(a, b, message) {
let result = a + 1 >= b;
ok(result, `${a} should be greater than or within one pixel of ${b}: ${message}`);
}
let panelRect = panel.getBoundingClientRect();
if (arrowSide == "top") {
ok(panelRect.top, origPanelRect.top, "Panel has not moved downwards");
ok(panelRect.bottom >= origPanelRect.bottom, `Panel has not shrunk from original size (${panelRect.bottom} >= ${origPanelRect.bottom})`);
isGreaterThanOrWithinPixelRoundingError(panelRect.top, origPanelRect.top, "Panel has not moved downwards");
isGreaterThanOrWithinPixelRoundingError(panelRect.bottom, origPanelRect.bottom, "Panel has not shrunk from original size");
let screenBottom = browserWin.screen.availTop + win.screen.availHeight;
let panelBottom = browserWin.mozInnerScreenY + panelRect.bottom;
ok(panelBottom <= screenBottom, `Bottom of popup should be on-screen. (${panelBottom} <= ${screenBottom})`);
} else {
ok(panelRect.bottom, origPanelRect.bottom, "Panel has not moved upwards");
ok(panelRect.top <= origPanelRect.top, `Panel has not shrunk from original size (${panelRect.top} <= ${origPanelRect.top})`);
isGreaterThanOrWithinPixelRoundingError(panelRect.bottom, origPanelRect.bottom, "Panel has not moved upwards");
// The arguments here are reversed compared to the above calls due to the coordinate system.
isGreaterThanOrWithinPixelRoundingError(origPanelRect.top, panelRect.top, "Panel has not shrunk from original size");
let panelTop = browserWin.mozInnerScreenY + panelRect.top;
ok(panelTop >= browserWin.screen.availTop, `Top of popup should be on-screen. (${panelTop} >= ${browserWin.screen.availTop})`);

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

@ -12,41 +12,21 @@ const TELEMETRY_RESULT_ENUM = {
RESTORED_DEFAULT: 0,
KEPT_CURRENT: 1,
CHANGED_ENGINE: 2,
CLOSED_PAGE: 3
CLOSED_PAGE: 3,
OPENED_SETTINGS: 4
};
window.onload = function() {
let list = document.getElementById("defaultEngine");
let originalDefault = Services.search.originalDefaultEngine.name;
Services.search.getDefaultEngines().forEach(e => {
let opt = document.createElement("option");
opt.setAttribute("value", e.name);
opt.engine = e;
opt.textContent = e.name;
if (e.iconURI)
opt.style.backgroundImage = 'url("' + e.iconURI.spec + '")';
if (e.name == originalDefault)
opt.setAttribute("selected", "true");
list.appendChild(opt);
});
let updateIcon = () => {
list.style.setProperty("--engine-icon-url",
list.selectedOptions[0].style.backgroundImage);
};
list.addEventListener("change", updateIcon);
// When selecting using the keyboard, the 'change' event is only fired after
// the user presses <enter> or moves the focus elsewhere.
// keypress/keyup fire too late and cause flicker when updating the icon.
// keydown fires too early and the selected option isn't changed yet.
list.addEventListener("keydown", () => {
Services.tm.mainThread.dispatch(updateIcon, Ci.nsIThread.DISPATCH_NORMAL);
});
updateIcon();
let defaultEngine = document.getElementById("defaultEngine");
let originalDefault = Services.search.originalDefaultEngine;
defaultEngine.textContent = originalDefault.name;
defaultEngine.style.backgroundImage =
'url("' + originalDefault.iconURI.spec + '")';
document.getElementById("searchResetChangeEngine").focus();
window.addEventListener("unload", recordPageClosed);
document.getElementById("linkSettingsPage")
.addEventListener("click", openingSettings);
};
function doSearch() {
@ -77,6 +57,11 @@ function doSearch() {
win.openUILinkIn(submission.uri.spec, "current", false, submission.postData);
}
function openingSettings() {
record(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
window.removeEventListener("unload", recordPageClosed);
}
function record(result) {
Services.telemetry.getHistogramById("SEARCH_RESET_RESULT").add(result);
}
@ -90,18 +75,12 @@ function keepCurrentEngine() {
}
function changeSearchEngine() {
let list = document.getElementById("defaultEngine");
let engine = list.selectedOptions[0].engine;
let engine = Services.search.originalDefaultEngine;
if (engine.hidden)
engine.hidden = false;
Services.search.currentEngine = engine;
// Record if we restored the original default or changed to another engine.
let originalDefault = Services.search.originalDefaultEngine.name;
let code = TELEMETRY_RESULT_ENUM.CHANGED_ENGINE;
if (Services.search.originalDefaultEngine.name == engine.name)
code = TELEMETRY_RESULT_ENUM.RESTORED_DEFAULT;
record(code);
record(TELEMETRY_RESULT_ENUM.RESTORED_DEFAULT);
doSearch();
}

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

@ -39,9 +39,7 @@
<div class="description">
<p>&searchreset.pageInfo1;</p>
<p>&searchreset.selector.label;
<select id="defaultEngine"></select>
</p>
<p>&searchreset.selector.label;<span id="defaultEngine"/></p>
<p>&searchreset.beforelink.pageInfo2;<a id="linkSettingsPage" href="about:preferences#search">&searchreset.link.pageInfo2;</a>&searchreset.afterlink.pageInfo2;</p>
</div>

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

@ -6,7 +6,8 @@ const TELEMETRY_RESULT_ENUM = {
RESTORED_DEFAULT: 0,
KEPT_CURRENT: 1,
CHANGED_ENGINE: 2,
CLOSED_PAGE: 3
CLOSED_PAGE: 3,
OPENED_SETTINGS: 4
};
const kSearchStr = "a search";
@ -77,12 +78,15 @@ var gTests = [
run: function* () {
let currentEngine = Services.search.currentEngine;
let originalEngine = Services.search.originalDefaultEngine;
let doc = gBrowser.contentDocument;
let defaultEngineSpan = doc.getElementById("defaultEngine");
is(defaultEngineSpan.textContent, originalEngine.name,
"the name of the original default engine is displayed");
let expectedURL = originalEngine.
getSubmission(kSearchStr, null, kSearchPurpose).
uri.spec;
let loadPromise = promiseStoppedLoad(expectedURL);
let doc = gBrowser.contentDocument;
let button = doc.getElementById("searchResetChangeEngine");
is(doc.activeElement, button,
"the 'Change Search Engine' button is focused");
@ -98,41 +102,15 @@ var gTests = [
},
{
desc: "Test the engine selector drop down.",
desc: "Click the settings link.",
run: function* () {
let originalEngineName = Services.search.originalDefaultEngine.name;
let doc = gBrowser.contentDocument;
let list = doc.getElementById("defaultEngine");
is(list.value, originalEngineName,
"the default selection of the dropdown is the original default engine");
let defaultEngines = Services.search.getDefaultEngines();
is(list.childNodes.length, defaultEngines.length,
"the dropdown has the correct count of engines");
// Select an engine that isn't the original default one.
let engine;
for (let i = 0; i < defaultEngines.length; ++i) {
if (defaultEngines[i].name != originalEngineName) {
engine = defaultEngines[i];
engine.hidden = true;
break;
}
}
list.value = engine.name;
let expectedURL = engine.getSubmission(kSearchStr, null, kSearchPurpose)
.uri.spec;
let loadPromise = promiseStoppedLoad(expectedURL);
doc.getElementById("searchResetChangeEngine").click();
let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
false,
"about:preferences#search")
gBrowser.contentDocument.getElementById("linkSettingsPage").click();
yield loadPromise;
ok(!engine.hidden, "the selected engine has been unhidden");
is(engine, Services.search.currentEngine,
"the current engine is what was selected in the drop down");
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.CHANGED_ENGINE);
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
}
},

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

@ -10,35 +10,13 @@ body {
background-image: url("chrome://browser/skin/icon-search-64.svg");
}
select {
font: inherit;
padding-inline-end: 24px;
#defaultEngine {
padding-inline-start: 26px;
background-image: var(--engine-icon-url),
url("chrome://global/skin/in-content/dropdown.svg#dropdown");
background-repeat: no-repeat;
background-position: 8px center, calc(100% - 4px) center;
background-position: 5px center;
background-size: 16px, 16px;
}
select:-moz-dir(rtl) {
background-position: calc(100% - 8px) center, 4px center;
}
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 var(--in-content-text-color);
}
option {
padding: 4px;
padding-inline-start: 30px;
background-repeat: no-repeat;
background-position: 8px center;
background-size: 16px;
background-color: var(--in-content-page-background);
}
option:-moz-dir(rtl) {
background-position: calc(100% - 8px) center;
#defaultEngine:-moz-dir(rtl) {
background-position: calc(100% - 5px) center;
}

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

@ -3,6 +3,10 @@ subsuite = screenshots
support-files =
head.js
mozscreenshots/extension/lib/permissionPrompts.html
mozscreenshots/extension/lib/controlCenter/password.html
mozscreenshots/extension/lib/controlCenter/mixed.html
mozscreenshots/extension/lib/controlCenter/mixed_active.html
mozscreenshots/extension/lib/controlCenter/mixed_passive.html
mozscreenshots/extension/lib/borderify.xpi
[browser_screenshots.js]

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

@ -0,0 +1,6 @@
[DEFAULT]
subsuite = screenshots
support-files =
../head.js
[browser_controlCenter.js]

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

@ -0,0 +1,14 @@
/* 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";
add_task(function* capture() {
if (!shouldCapture()) {
return;
}
let sets = ["LightweightThemes", "ControlCenter"];
yield TestRunner.start(sets, "controlCenter");
});

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

@ -8,6 +8,7 @@ BROWSER_CHROME_MANIFESTS += [
# Each test is in it's own directory so it gets run in a clean profile with
# run-by-dir.
'browser.ini',
'controlCenter/browser.ini',
'devtools/browser.ini',
'permissionPrompts/browser.ini',
'preferences/browser.ini',

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

@ -0,0 +1,238 @@
/* 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";
this.EXPORTED_SYMBOLS = ["ControlCenter"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://testing-common/BrowserTestUtils.jsm");
Cu.import("resource:///modules/SitePermissions.jsm");
let {UrlClassifierTestUtils} = Cu.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
const RESOURCE_PATH = "extensions/mozscreenshots/browser/chrome/mozscreenshots/lib/controlCenter";
const HTTP_PAGE = "http://example.com/";
const HTTPS_PAGE = "https://example.com/";
const PERMISSIONS_PAGE = "https://test1.example.com/";
const HTTP_PASSWORD_PAGE = `http://test2.example.org/${RESOURCE_PATH}/password.html`;
const MIXED_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed.html`;
const MIXED_ACTIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_active.html`;
const MIXED_PASSIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_passive.html`;
const TRACKING_PAGE = `http://tracking.example.org/${RESOURCE_PATH}/tracking.html`;
this.ControlCenter = {
init(libDir) { },
configurations: {
about: {
applyConfig: Task.async(function* () {
yield loadPage("about:home");
yield openIdentityPopup();
}),
},
localFile: {
applyConfig: Task.async(function* () {
let filePath = "file:///";
if (Services.appinfo.OS === "WINNT") {
filePath += "C:/";
}
yield loadPage(filePath);
yield openIdentityPopup();
}),
},
http: {
applyConfig: Task.async(function* () {
yield loadPage(HTTP_PAGE);
yield openIdentityPopup();
}),
},
httpSubView: {
applyConfig: Task.async(function* () {
yield loadPage(HTTP_PAGE);
yield openIdentityPopup(true);
}),
},
https: {
applyConfig: Task.async(function* () {
yield loadPage(HTTPS_PAGE);
yield openIdentityPopup();
}),
},
httpsSubView: {
applyConfig: Task.async(function* () {
yield loadPage(HTTPS_PAGE);
yield openIdentityPopup(true);
}),
},
singlePermission: {
applyConfig: Task.async(function* () {
let uri = Services.io.newURI(PERMISSIONS_PAGE, null, null)
SitePermissions.set(uri, "camera", SitePermissions.ALLOW);
yield loadPage(PERMISSIONS_PAGE);
yield openIdentityPopup();
}),
},
allPermissions: {
applyConfig: Task.async(function* () {
// there are 3 possible non-default permission states, so we alternate between them
let states = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.SESSION];
let uri = Services.io.newURI(PERMISSIONS_PAGE, null, null)
SitePermissions.listPermissions().forEach(function (permission, index) {
SitePermissions.set(uri, permission, states[index % 3]);
});
yield loadPage(PERMISSIONS_PAGE);
yield openIdentityPopup();
}),
},
mixed: {
applyConfig: Task.async(function* () {
yield loadPage(MIXED_CONTENT_URL);
yield openIdentityPopup();
}),
},
mixedSubView: {
applyConfig: Task.async(function* () {
yield loadPage(MIXED_CONTENT_URL);
yield openIdentityPopup(true);
}),
},
mixedPassive: {
applyConfig: Task.async(function* () {
yield loadPage(MIXED_PASSIVE_CONTENT_URL);
yield openIdentityPopup();
}),
},
mixedPassiveSubView: {
applyConfig: Task.async(function* () {
yield loadPage(MIXED_PASSIVE_CONTENT_URL);
yield openIdentityPopup(true);
}),
},
mixedActive: {
applyConfig: Task.async(function* () {
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
yield openIdentityPopup();
}),
},
mixedActiveSubView: {
applyConfig: Task.async(function* () {
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
yield openIdentityPopup(true);
}),
},
mixedActiveUnblocked: {
applyConfig: Task.async(function* () {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
gBrowser.ownerGlobal.gIdentityHandler.disableMixedContentProtection();
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, MIXED_ACTIVE_CONTENT_URL);
yield openIdentityPopup();
}),
},
mixedActiveUnblockedSubView: {
applyConfig: Task.async(function* () {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
gBrowser.ownerGlobal.gIdentityHandler.disableMixedContentProtection();
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, MIXED_ACTIVE_CONTENT_URL);
yield openIdentityPopup(true);
}),
},
httpPassword: {
applyConfig: Task.async(function* () {
yield loadPage(HTTP_PASSWORD_PAGE);
yield openIdentityPopup();
}),
},
httpPasswordSubView: {
applyConfig: Task.async(function* () {
yield loadPage(HTTP_PASSWORD_PAGE);
yield openIdentityPopup(true);
}),
},
trackingProtectionNoElements: {
applyConfig: Task.async(function* () {
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
yield loadPage(HTTP_PAGE);
yield openIdentityPopup();
}),
},
trackingProtectionEnabled: {
applyConfig: Task.async(function* () {
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
yield UrlClassifierTestUtils.addTestTrackers();
yield loadPage(TRACKING_PAGE);
yield openIdentityPopup();
}),
},
trackingProtectionDisabled: {
applyConfig: Task.async(function* () {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
yield UrlClassifierTestUtils.addTestTrackers();
yield loadPage(TRACKING_PAGE);
yield openIdentityPopup();
// unblock the page
gBrowser.ownerGlobal.document.querySelector("#tracking-action-unblock").click();
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, TRACKING_PAGE);
yield openIdentityPopup();
}),
},
},
};
function* loadPage(url) {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, url);
}
function* openIdentityPopup(expand) {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
let { gIdentityHandler } = gBrowser.ownerGlobal;
gIdentityHandler._identityPopup.hidePopup();
gIdentityHandler._identityBox.querySelector("#identity-icon").click();
if (expand) {
// give some time for opening to avoid weird style issues
yield new Promise((c) => setTimeout(c, 500));
gIdentityHandler._identityPopup.querySelector("#identity-popup-security-expander").click();
}
}

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

@ -20,6 +20,7 @@ let lastTab = null;
this.PermissionPrompts = {
init(libDir) {
Services.prefs.setBoolPref("media.navigator.permission.fake", true);
Services.prefs.setBoolPref("media.getusermedia.screensharing.allow_on_old_platforms", true);
Services.prefs.setCharPref("media.getusermedia.screensharing.allowed_domains",
"test1.example.com");
Services.prefs.setBoolPref("extensions.install.requireBuiltInCerts", false);

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

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>Mixed Content test</title>
</head>
<body>
<iframe style="visibility:hidden" src="http://example.com"></iframe>
<img style="visibility:hidden" src="http://example.com/tests/image/test/mochitest/blue.png"></img>
</body>
</html>

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

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>Mixed Active Content test</title>
</head>
<body>
<iframe style="visibility:hidden" src="http://example.com"></iframe>
</body>
</html>

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

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>Mixed Passive Content test</title>
</head>
<body>
<img style="visibility:hidden" src="http://example.com/tests/image/test/mochitest/blue.png"></img>
</body>
</html>

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

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>HTTP Password test</title>
</head>
<body>
<form>
<input type="password" />
<button type="submit">Submit</button>
</form>
</body>
</html>

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

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>Tracking test</title>
</head>
<body>
<iframe style="visibility:hidden" src="http://tracking.example.com/"></iframe>
</body>
</html>

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

@ -51,6 +51,8 @@ SEARCH_PATHS = [
'python/pyyaml/lib',
'python/requests',
'python/slugid',
'python/py',
'python/pytest',
'python/voluptuous',
'build',
'build/pymake',

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

@ -14,9 +14,7 @@ js_option('--with-android-toolchain', nargs=1,
js_option('--with-android-gnu-compiler-version', nargs=1,
help='GNU compiler version to use')
@depends('--help')
def min_android_version(_):
return '9'
min_android_version = dependable('9')
js_option('--with-android-version',
nargs=1,

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

@ -93,7 +93,6 @@ def checking(what, callback=None):
# use that value instead.
@template
@imports(_from='mozbuild.shellutil', _import='quote')
@imports(_from='mozbuild.configure', _import='DependsFunction')
def check_prog(var, progs, what=None, input=None, allow_missing=False,
paths=None):
if input:
@ -115,10 +114,8 @@ def check_prog(var, progs, what=None, input=None, allow_missing=False,
what = what or var.lower()
# Trick to make a @depends function out of an immediate value.
if not isinstance(progs, DependsFunction):
progs = depends('--help')(lambda h: progs)
if not isinstance(paths, DependsFunction):
paths = depends('--help')(lambda h: paths)
progs = dependable(progs)
paths = dependable(paths)
@depends_if(input, progs, paths)
@checking('for %s' % what, lambda x: quote(x) if x else 'not found')

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

@ -44,7 +44,7 @@ def try_compile(includes=None, body='', language='C++', flags=None, check_msg=No
# conditional on the value of that function.
@template
def check_header(header, language='C++', flags=None, includes=None, when=None):
when = when or depends('--help')(lambda _: True)
when = when or always
if includes:
includes = includes[:]
@ -55,8 +55,7 @@ def check_header(header, language='C++', flags=None, includes=None, when=None):
@depends_when(try_compile(includes=includes, language=language, flags=flags,
check_msg='for %s' % header), when=when)
def have_header(value):
if value is not None:
return True
return value
header_var = 'HAVE_%s' % (header.upper()
.replace('-', '_')
.replace('/', '_')
@ -104,8 +103,7 @@ def check_and_add_gcc_warning(warning, compiler=None, when=None, check=True):
else:
compilers = (c_compiler, cxx_compiler)
if not when:
when = depends('--help')(lambda _: True)
when = when or always
for c in compilers:
assert c in (c_compiler, cxx_compiler)
@ -140,7 +138,7 @@ def check_and_add_gcc_warning(warning, compiler=None, when=None, check=True):
@depends(result, warnings_flags)
def maybe_add_flag(result, warnings_flags):
if result is not None:
if result:
warnings_flags.append(warning)
# Add the given warning to the list of warning flags for the build.

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

@ -38,8 +38,7 @@ def compiler_class(compiler):
if check_msg:
def checking_fn(fn):
return checking(check_msg,
callback=lambda r: r is not None)(fn)
return checking(check_msg)(fn)
else:
def checking_fn(fn):
return fn
@ -55,9 +54,11 @@ def compiler_class(compiler):
flags += extra_flags
flags.append('-c')
return try_invoke_compiler(
if try_invoke_compiler(
compiler.wrapper + [compiler.compiler] + compiler.flags,
compiler.language, source, flags, onerror=onerror)
compiler.language, source, flags,
onerror=onerror) is not None:
return True
return func

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

@ -125,21 +125,18 @@ set_config('MOZCONFIG', depends(mozconfig)(lambda m: m['path']))
# Hacks related to old-configure
# ==============================
@depends('--help')
def old_configure_assignments(help):
@dependable
def old_configure_assignments():
return []
@depends('--help')
def extra_old_configure_args(help):
@dependable
def extra_old_configure_args():
return []
@template
@imports(_from='mozbuild.configure', _import='DependsFunction')
def add_old_configure_assignment(var, value):
if not isinstance(var, DependsFunction):
var = depends('--help')(lambda x: var)
if not isinstance(value, DependsFunction):
value = depends('--help')(lambda x: value)
var = dependable(var)
value = dependable(value)
@depends(old_configure_assignments, var, value)
@imports(_from='mozbuild.shellutil', _import='quote')
@ -248,9 +245,9 @@ add_old_configure_assignment('PYTHON', virtualenv_python)
# below, so collect them.
@template
def early_options():
@depends('--help')
@dependable
@imports('__sandbox__')
def early_options(help):
def early_options():
return set(
option.env
for option in __sandbox__._options.itervalues()
@ -324,6 +321,7 @@ option('--target', nargs=1,
'used')
@imports(_from='mozbuild.configure.constants', _import='CPU')
@imports(_from='mozbuild.configure.constants', _import='CPU_bitness')
@imports(_from='mozbuild.configure.constants', _import='Endianness')
@imports(_from='mozbuild.configure.constants', _import='Kernel')
@imports(_from='mozbuild.configure.constants', _import='OS')
@ -422,6 +420,7 @@ def split_triplet(triplet):
return namespace(
alias=triplet,
cpu=CPU(canonical_cpu),
bitness=CPU_bitness[canonical_cpu],
kernel=Kernel(canonical_kernel),
os=OS(canonical_os),
endianness=Endianness(endianness),
@ -472,6 +471,16 @@ set_define('CROSS_COMPILE', cross_compiling)
add_old_configure_assignment('CROSS_COMPILE', cross_compiling)
@depends(target)
def have_64_bit(target):
if target.bitness == 64:
return True
set_config('HAVE_64BIT_BUILD', have_64_bit)
set_define('HAVE_64BIT_BUILD', have_64_bit)
add_old_configure_assignment('HAVE_64BIT_BUILD', have_64_bit)
# Autoconf needs these set
@depends(host)
def host_for_old_configure(host):
@ -804,8 +813,8 @@ add_old_configure_assignment('PKG_CONFIG', pkg_config)
# actual implementation is located in b2g/moz.configure.
# Remove this function as soon as 'android_ndk_include'
# depends on 'target.'
@depends('--help')
def gonkdir(_):
@dependable
def gonkdir():
return None
include(include_project_configure)

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

@ -145,8 +145,8 @@ def old_configure_options(*options):
for opt in options:
option(opt, nargs='*', help='Help missing for old configure options')
@depends('--help')
def all_options(help):
@dependable
def all_options():
return list(options)
return depends(prepare_configure, extra_old_configure_args, all_options,
@ -435,10 +435,10 @@ def post_old_configure(raw_config):
# them. We only do so for options that haven't been declared so far,
# which should be a proxy for the options that old-configure handles
# and that we don't know anything about.
@depends('--help')
@dependable
@imports('__sandbox__')
@imports(_from='mozbuild.configure.options', _import='Option')
def remaining_mozconfig_options(_):
def remaining_mozconfig_options():
helper = __sandbox__._helper
for arg in helper:
if helper._origins[arg] != 'mozconfig':

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

@ -25,14 +25,11 @@ def pkg_config_version(pkg_config):
# will be returned to the caller.
# Returns `True` when the package description is fulfilled.
@template
@imports(_from='mozbuild.configure', _import='DependsFunction')
def pkg_check_modules(var, package_desc,
condition=depends('--help')(lambda _: True),
def pkg_check_modules(var, package_desc, condition=always,
allow_missing=False):
if isinstance(package_desc, (tuple, list)):
package_desc = ' '.join(package_desc)
if not isinstance(package_desc, DependsFunction):
package_desc = depends('--help')(lambda _: package_desc)
package_desc = dependable(package_desc)
@depends_when(pkg_config, pkg_config_version, when=condition)
def check_pkg_config(pkg_config, version):

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

@ -62,8 +62,8 @@ set_config('HAVE_YASM', have_yasm)
# Until the YASM variable is not necessary in old-configure.
add_old_configure_assignment('YASM', have_yasm)
@depends('--help')
def extra_toolchain_flags(_):
@dependable
def extra_toolchain_flags():
# This value will be overriden for android builds, where
# extra flags are required to do basic checks.
return []
@ -766,6 +766,15 @@ host_cxx_compiler = compiler('C++', host, c_compiler=host_c_compiler,
include('compile-checks.configure')
@depends(have_64_bit,
try_compile(body='static_assert(sizeof(void *) == 8, "")',
check_msg='for 64-bit OS'))
def check_have_64_bit(have_64_bit, compiler_have_64_bit):
if have_64_bit != compiler_have_64_bit:
configure_error('The target compiler does not agree with configure '
'about the target bitness.')
@depends(c_compiler)
def default_debug_flags(compiler_info):
# Debug info is ON by default.

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

@ -302,6 +302,24 @@ def namespace(**kwargs):
return ReadOnlyNamespace(**kwargs)
# Turn an object into an object that can be used as an argument to @depends.
# The given object can be a literal value, a function that takes no argument,
# or, for convenience, a @depends function.
@template
@imports(_from='inspect', _import='isfunction')
@imports(_from='mozbuild.configure', _import='DependsFunction')
def dependable(obj):
if isinstance(obj, DependsFunction):
return obj
if isfunction(obj):
return depends('--help')(lambda _: obj())
return depends('--help')(lambda _: obj)
always = dependable(True)
never = dependable(False)
# Some @depends function return namespaces, and one could want to use one
# specific attribute from such a namespace as a "value" given to functions
# such as `set_config`. But those functions do not take immediate values.

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

@ -57,7 +57,7 @@ if __name__ == '__main__':
env["XPCOM_DEBUG_BREAK"] = "warn"
# For VC12+, make sure we can find the right bitness of pgort1x0.dll
if not substs['HAVE_64BIT_BUILD']:
if not substs.get('HAVE_64BIT_BUILD'):
for e in ('VS140COMNTOOLS', 'VS120COMNTOOLS'):
if e not in env:
continue

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

@ -16,6 +16,8 @@ which.pth:python/which
ply.pth:other-licenses/ply/
macholib.pth:python/macholib
mock.pth:python/mock-1.0.0
py.pth:python/py
pytest.pth:python/pytest
mozilla.pth:build
mozilla.pth:config
mozilla.pth:xpcom/typelib/xpt/tools

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

@ -586,6 +586,22 @@ BasePrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
bool
BasePrincipal::AddonHasPermission(const nsAString& aPerm)
{
if (mOriginAttributes.mAddonId.IsEmpty()) {
return false;
}
nsCOMPtr<nsIAddonPolicyService> aps =
do_GetService("@mozilla.org/addons/policy-service;1");
NS_ENSURE_TRUE(aps, false);
bool retval = false;
nsresult rv = aps->AddonHasPermission(mOriginAttributes.mAddonId, aPerm, &retval);
NS_ENSURE_SUCCESS(rv, false);
return retval;
}
already_AddRefed<BasePrincipal>
BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttributes& aAttrs)
{

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

@ -266,6 +266,8 @@ public:
NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
NS_IMETHOD GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) final;
virtual bool AddonHasPermission(const nsAString& aPerm);
virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
virtual bool IsCodebasePrincipal() const { return false; };

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

@ -40,6 +40,11 @@ interface nsIAddonPolicyService : nsISupports
*/
ACString getGeneratedBackgroundPageUrl(in ACString aAddonId);
/**
* Returns true if the addon was granted the |aPerm| API permission.
*/
boolean addonHasPermission(in AString aAddonId, in AString aPerm);
/**
* Returns true if unprivileged code associated with the given addon may load
* data from |aURI|.

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

@ -786,6 +786,17 @@ nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain)
return NS_ERROR_NOT_AVAILABLE;
}
bool
nsExpandedPrincipal::AddonHasPermission(const nsAString& aPerm)
{
for (size_t i = 0; i < mPrincipals.Length(); ++i) {
if (BasePrincipal::Cast(mPrincipals[i])->AddonHasPermission(aPerm)) {
return true;
}
}
return false;
}
bool
nsExpandedPrincipal::IsOnCSSUnprefixingWhitelist()
{

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

@ -79,6 +79,7 @@ public:
NS_IMETHOD GetDomain(nsIURI** aDomain) override;
NS_IMETHOD SetDomain(nsIURI* aDomain) override;
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
virtual bool AddonHasPermission(const nsAString& aPerm) override;
virtual bool IsOnCSSUnprefixingWhitelist() override;
virtual void GetScriptLocation(nsACString &aStr) override;
nsresult GetOriginInternal(nsACString& aOrigin) override;

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

@ -19,7 +19,6 @@ const { LocationStore, serialize, deserialize } = require("./location-store");
function SourceMapService(target) {
this._target = target;
this._locationStore = new LocationStore();
this._isInitialResolve = true;
EventEmitter.decorate(this);
@ -41,7 +40,6 @@ function SourceMapService(target) {
* Clears the store containing the cached resolved locations and promises
*/
SourceMapService.prototype.reset = function () {
this._isInitialResolve = true;
this._locationStore.clear();
};
@ -51,7 +49,6 @@ SourceMapService.prototype.destroy = function () {
this._target.off("navigate", this.reset);
this._target.off("will-navigate", this.reset);
this._target.off("close", this.destroy);
this._isInitialResolve = null;
this._target = this._locationStore = null;
};
@ -63,10 +60,7 @@ SourceMapService.prototype.destroy = function () {
SourceMapService.prototype.subscribe = function (location, callback) {
this.on(serialize(location), callback);
this._locationStore.set(location);
if (this._isInitialResolve) {
this._resolveAndUpdate(location);
this._isInitialResolve = false;
}
this._resolveAndUpdate(location);
};
/**
@ -76,7 +70,12 @@ SourceMapService.prototype.subscribe = function (location, callback) {
*/
SourceMapService.prototype.unsubscribe = function (location, callback) {
this.off(serialize(location), callback);
this._locationStore.clearByURL(location.url);
// Check to see if the store exists before attempting to clear a location
// Sometimes un-subscribe happens during the destruction cascades and this
// condition is to protect against that. Could be looked into in the future.
if (this._locationStore) {
this._locationStore.clearByURL(location.url);
}
};
/**
@ -87,16 +86,10 @@ SourceMapService.prototype.unsubscribe = function (location, callback) {
*/
SourceMapService.prototype._resolveAndUpdate = function (location) {
this._resolveLocation(location).then(resolvedLocation => {
// We try to source map the first console log to initiate the source-updated event from
// target. The isSameLocation check is to make sure we don't update the frame, if the
// location is not source-mapped.
if (resolvedLocation) {
if (this._isInitialResolve) {
if (!isSameLocation(location, resolvedLocation)) {
this.emit(serialize(location), location, resolvedLocation);
return;
}
}
// We try to source map the first console log to initiate the source-updated
// event from target. The isSameLocation check is to make sure we don't update
// the frame, if the location is not source-mapped.
if (resolvedLocation && !isSameLocation(location, resolvedLocation)) {
this.emit(serialize(location), location, resolvedLocation);
}
});
@ -182,7 +175,6 @@ function resolveLocation(target, location) {
if (newLocation.error) {
return null;
}
return newLocation;
});
}
@ -197,4 +189,4 @@ function isSameLocation(location, resolvedLocation) {
return location.url === resolvedLocation.url &&
location.line === resolvedLocation.line &&
location.column === resolvedLocation.column;
};
}

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

@ -19,25 +19,22 @@ const PAGE_URL = `${DEBUGGER_ROOT}doc_empty-tab-01.html`;
const JS_URL = `${URL_ROOT}code_binary_search.js`;
const COFFEE_URL = `${URL_ROOT}code_binary_search.coffee`;
const { SourceMapService } = require("devtools/client/framework/source-map-service");
const { serialize } = require("devtools/client/framework/location-store");
add_task(function* () {
const toolbox = yield openNewTabAndToolbox(PAGE_URL, "jsdebugger");
const service = new SourceMapService(toolbox.target);
const aggregator = [];
let aggregator = new Map();
function onUpdate(e, oldLoc, newLoc) {
if (oldLoc.line === 6) {
checkLoc1(oldLoc, newLoc);
} else if (oldLoc.line === 8) {
checkLoc2(oldLoc, newLoc);
} else if (oldLoc.line === 2) {
checkLoc3(oldLoc, newLoc);
} else {
throw new Error(`Unexpected location update: ${JSON.stringify(oldLoc)}`);
}
aggregator.push(newLoc);
aggregator.set(serialize(oldLoc), newLoc);
}
let loc1 = { url: JS_URL, line: 6 };
@ -51,7 +48,9 @@ add_task(function* () {
yield createScript(JS_URL);
yield sourceShown;
yield waitUntil(() => aggregator.length === 2);
yield waitUntil(() => aggregator.size === 2);
aggregator = Array.from(aggregator.values());
ok(aggregator.find(i => i.url === COFFEE_URL && i.line === 4), "found first updated location");
ok(aggregator.find(i => i.url === COFFEE_URL && i.line === 6), "found second updated location");

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

@ -591,7 +591,12 @@ Toolbox.prototype = {
["forceReload2", true]
].forEach(([id, force]) => {
let key = toolboxStrings("toolbox." + id + ".key");
shortcuts.on(key, this.reloadTarget.bind(this, force));
shortcuts.on(key, (name, event) => {
this.reloadTarget(force);
// Prevent Firefox shortcuts from reloading the page
event.preventDefault();
});
});
},

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

@ -17,7 +17,9 @@ const {LocalizationHelper} = require("devtools/client/shared/l10n");
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
const STRINGS_URI = "chrome://devtools/locale/shared.properties";
const STRINGS_INSPECTOR = "chrome://devtools-shared/locale/styleinspector.properties";
const SHARED_L10N = new LocalizationHelper(STRINGS_URI);
const INSPECTOR_L10N = new LocalizationHelper(STRINGS_INSPECTOR);
const NUMERIC = /^-?[\d\.]+$/;
const LONG_TEXT_ROTATE_LIMIT = 3;
@ -734,8 +736,14 @@ LayoutView.prototype = {
title += "\n" + sourceRule.selectors.join(", ");
}
if (sourceRule && sourceRule.parentStyleSheet) {
title += "\n" + sourceRule.parentStyleSheet.href + ":" + sourceRule.line;
if (sourceRule.parentStyleSheet.href) {
title += "\n" + sourceRule.parentStyleSheet.href + ":" + sourceRule.line;
} else {
title += "\n" + INSPECTOR_L10N.getStr("rule.sourceInline") +
":" + sourceRule.line;
}
}
el.setAttribute("title", title);
},

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

@ -28,45 +28,45 @@ const VALUES_TEST_DATA = [{
values: [{
name: "margin-top",
ruleSelector: "#div1",
styleSheetLocation: "null:1"
styleSheetLocation: "inline:1"
}, {
name: "margin-right",
ruleSelector: "#div1",
styleSheetLocation: "null:1"
styleSheetLocation: "inline:1"
}, {
name: "margin-bottom",
ruleSelector: "#div1",
styleSheetLocation: "null:1"
styleSheetLocation: "inline:1"
}, {
name: "margin-left",
ruleSelector: "#div1",
styleSheetLocation: "null:1"
styleSheetLocation: "inline:1"
}]
}, {
selector: "#div2",
values: [{
name: "border-bottom-width",
ruleSelector: "#div2",
styleSheetLocation: "null:2"
styleSheetLocation: "inline:2"
}]
}, {
selector: "#div3",
values: [{
name: "padding-top",
ruleSelector: "html, body, #div3",
styleSheetLocation: "null:3"
styleSheetLocation: "inline:3"
}, {
name: "padding-right",
ruleSelector: "html, body, #div3",
styleSheetLocation: "null:3"
styleSheetLocation: "inline:3"
}, {
name: "padding-bottom",
ruleSelector: "html, body, #div3",
styleSheetLocation: "null:3"
styleSheetLocation: "inline:3"
}, {
name: "padding-left",
ruleSelector: "html, body, #div3",
styleSheetLocation: "null:3"
styleSheetLocation: "inline:3"
}]
}];

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

@ -14,7 +14,7 @@ add_task(function* () {
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let {show, synthesizeKey, finalize} = helper;
let {show, finalize} = helper;
info("Show the eyedropper with the copyOnSelect option");
yield show("html", {copyOnSelect: true});
@ -24,8 +24,7 @@ add_task(function* () {
yield waitForClipboard(() => {
info("Activate the eyedropper so the background color is copied");
let generateKey = synthesizeKey({key: "VK_RETURN", options: {}});
generateKey.next();
EventUtils.synthesizeKey("VK_RETURN", {});
}, "#FF0000");
ok(true, "The clipboard contains the right value");

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

@ -35,7 +35,7 @@ add_task(function* () {
function* respondsToMoveEvents(helper) {
info("Checking that the eyedropper responds to events from the mouse and keyboard");
let {mouse, synthesizeKey} = helper;
let {mouse} = helper;
for (let {type, x, y, key, shift, expected} of MOVE_EVENTS_DATA) {
info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
@ -43,7 +43,7 @@ function* respondsToMoveEvents(helper) {
yield mouse.move(x, y);
} else if (type === "keyboard") {
let options = shift ? {shiftKey: true} : {};
yield synthesizeKey({key, options});
yield EventUtils.synthesizeKey(key, options);
}
yield checkPosition(expected, helper);
}
@ -55,17 +55,17 @@ function* checkPosition({x, y}, {getElementAttribute}) {
`The eyedropper is at the expected ${x} ${y} position`);
}
function* respondsToReturnAndEscape({synthesizeKey, isElementHidden, show}) {
function* respondsToReturnAndEscape({isElementHidden, show}) {
info("Simulating return to select the color and hide the eyedropper");
yield synthesizeKey({key: "VK_RETURN", options: {}});
yield EventUtils.synthesizeKey("VK_RETURN", {});
let hidden = yield isElementHidden("root");
ok(hidden, "The eyedropper has been hidden");
info("Showing the eyedropper again and simulating escape to hide it");
yield show("html");
yield synthesizeKey({key: "VK_ESCAPE", options: {}});
yield EventUtils.synthesizeKey("VK_ESCAPE", {});
hidden = yield isElementHidden("root");
ok(hidden, "The eyedropper has been hidden again");
}

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

@ -465,10 +465,6 @@ const getHighlighterHelperFor = (type) => Task.async(
yield testActor.synthesizeMouse(options);
},
synthesizeKey: function* (options) {
yield testActor.synthesizeKey(options);
},
// This object will synthesize any "mouse" prefixed event to the
// `testActor`, using the name of method called as suffix for the
// event's name.

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

@ -56,6 +56,10 @@ function makeMemoryTest(url, generator) {
return Task.async(function* () {
waitForExplicitFinish();
// It can take a long time to save a snapshot to disk, read the snapshots
// back from disk, and finally perform analyses on them.
requestLongerTimeout(2);
const tab = yield addTab(url);
const results = yield openMemoryPanel(tab);

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

@ -112,7 +112,6 @@ skip-if = (os == 'linux' && e10s && debug) # Bug 1242204
[browser_net_reload-markers.js]
[browser_net_req-resp-bodies.js]
[browser_net_resend.js]
skip-if = e10s # Bug 1091612
[browser_net_security-details.js]
[browser_net_security-error.js]
[browser_net_security-icon-click.js]

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

@ -180,6 +180,16 @@ function tunnelToInnerBrowser(outer, inner) {
outer.setDocShellIsActiveAndForeground = value => {
inner.frameLoader.tabParent.setDocShellIsActiveAndForeground(value);
};
// Make the PopupNotifications object available on the iframe's owner
// This is used for permission doorhangers
Object.defineProperty(inner.ownerGlobal, "PopupNotifications", {
get() {
return outer.ownerGlobal.PopupNotifications;
},
configurable: true,
enumerable: true,
});
}),
stop() {
@ -210,6 +220,9 @@ function tunnelToInnerBrowser(outer, inner) {
delete outer.docShellIsActive;
delete outer.setDocShellIsActiveAndForeground;
// Delete the PopupNotifications getter added for permission doorhangers
delete inner.ownerGlobal.PopupNotifications;
mmTunnel.destroy();
mmTunnel = null;

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

@ -6,6 +6,7 @@ skip-if = !e10s
support-files =
devices.json
doc_page_state.html
geolocation.html
head.js
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
@ -25,6 +26,7 @@ support-files =
[browser_mouse_resize.js]
[browser_navigation.js]
[browser_page_state.js]
[browser_permission_doorhanger.js]
[browser_resize_cmd.js]
skip-if = true # GCLI target confused after swap, will fix in bug 1240912
[browser_screenshot_button.js]

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

@ -0,0 +1,52 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that permission popups asking for user approval still appear in RDM
const DUMMY_URL = "http://example.com/";
const TEST_URL = `${URL_ROOT}geolocation.html`;
function waitForGeolocationPrompt(win, browser) {
return new Promise(resolve => {
win.PopupNotifications.panel.addEventListener("popupshown", function popupShown() {
let notification = win.PopupNotifications.getNotification("geolocation", browser);
if (notification) {
win.PopupNotifications.panel.removeEventListener("popupshown", popupShown);
resolve();
}
});
});
}
add_task(function* () {
let tab = yield addTab(DUMMY_URL);
let browser = tab.linkedBrowser;
let win = browser.ownerGlobal;
let waitPromptPromise = waitForGeolocationPrompt(win, browser);
// Checks if a geolocation permission doorhanger appears when openning a page
// requesting geolocation
yield load(browser, TEST_URL);
yield waitPromptPromise;
ok(true, "Permission doorhanger appeared without RDM enabled");
// Lets switch back to the dummy website and enable RDM
yield load(browser, DUMMY_URL);
let { ui } = yield openRDM(tab);
let newBrowser = ui.getViewportBrowser();
waitPromptPromise = waitForGeolocationPrompt(win, newBrowser);
// Checks if the doorhanger appeared again when reloading the geolocation
// page inside RDM
yield load(browser, TEST_URL);
yield waitPromptPromise;
ok(true, "Permission doorhanger appeared inside RDM");
yield closeRDM(tab);
yield removeTab(tab);
});

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

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Geolocation permission test</title>
</head>
<body>
<script type="text/javascript">
"use strict";
navigator.geolocation.getCurrentPosition(function (pos) {});
</script>
</body>
</html>

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

@ -122,13 +122,19 @@ define(function (require, exports, module) {
let mode = this.props.mode || "short";
let object = this.props.object;
let items;
let brackets;
let needSpace = function (space) {
return space ? { left: "[ ", right: " ]"} : { left: "[", right: "]"};
};
if (mode == "tiny") {
let isEmpty = object.length === 0;
items = DOM.span({className: "length"}, isEmpty ? "" : object.length);
brackets = needSpace(false);
} else {
let max = (mode == "short") ? 3 : 300;
items = this.arrayIterator(object, max);
brackets = needSpace(items.length > 0);
}
let objectLink = this.props.objectLink || DOM.span;
@ -140,13 +146,13 @@ define(function (require, exports, module) {
className: "arrayLeftBracket",
role: "presentation",
object: object
}, "["),
}, brackets.left),
items,
objectLink({
className: "arrayRightBracket",
role: "presentation",
object: object
}, "]"),
}, brackets.right),
DOM.span({
className: "arrayProperties",
role: "group"}

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

@ -105,14 +105,20 @@ define(function (require, exports, module) {
let object = this.props.object;
let items;
let brackets;
let needSpace = function (space) {
return space ? { left: "[ ", right: " ]"} : { left: "[", right: "]"};
};
if (mode == "tiny") {
let objectLength = this.getLength(object);
let isEmpty = objectLength === 0;
items = span({className: "length"}, isEmpty ? "" : objectLength);
brackets = needSpace(false);
} else {
let max = (mode == "short") ? 3 : 300;
items = this.arrayIterator(object, max);
brackets = needSpace(items.length > 0);
}
let objectLink = this.props.objectLink || span;
@ -126,13 +132,13 @@ define(function (require, exports, module) {
className: "arrayLeftBracket",
role: "presentation",
object: object
}, "["),
}, brackets.left),
items,
objectLink({
className: "arrayRightBracket",
role: "presentation",
object: object
}, "]"),
}, brackets.right),
span({
className: "arrayProperties",
role: "group"}

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

@ -189,13 +189,13 @@ define(function (require, exports, module) {
className: "objectLeftBrace",
role: "presentation",
object: object
}, " {"),
}, " { "),
props,
objectLink({
className: "objectRightBrace",
role: "presentation",
object: object
}, "}")
}, " }")
)
);
},

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

@ -150,13 +150,13 @@ define(function (require, exports, module) {
className: "objectLeftBrace",
role: "presentation",
object: object
}, "{"),
}, " { "),
props,
objectLink({
className: "objectRightBrace",
role: "presentation",
object: object
}, "}")
}, " }")
)
);
},

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

@ -131,16 +131,6 @@
font-weight: bold;
}
.objectLeftBrace,
.arrayLeftBracket {
margin-right: 4px;
}
.objectRightBrace,
.arrayRightBracket {
margin-left: 4px;
}
/******************************************************************************/
/* Cycle reference*/

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

@ -81,7 +81,7 @@ window.onload = Task.async(function* () {
function testMaxProps() {
const stub = [1, "foo", {}];
const defaultOutput = `[1, "foo", Object]`;
const defaultOutput = `[ 1, "foo", Object ]`;
const modeTests = [
{
@ -107,7 +107,7 @@ window.onload = Task.async(function* () {
function testMoreThanShortMaxProps() {
const stub = Array(maxLength.short + 1).fill("foo");
const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, 1 more…]`;
const defaultShortOutput = `[ ${Array(maxLength.short).fill("\"foo\"").join(", ")}, 1 more… ]`;
const modeTests = [
{
@ -124,7 +124,7 @@ window.onload = Task.async(function* () {
},
{
mode: "long",
expectedOutput: `[${Array(maxLength.short + 1).fill("\"foo\"").join(", ")}]`,
expectedOutput: `[ ${Array(maxLength.short + 1).fill("\"foo\"").join(", ")} ]`,
}
];
@ -133,8 +133,8 @@ window.onload = Task.async(function* () {
function testMoreThanLongMaxProps() {
const stub = Array(maxLength.long + 1).fill("foo");
const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more…]`;
const defaultLongOutput = `[${Array(maxLength.long).fill("\"foo\"").join(", ")}, 1 more…]`;
const defaultShortOutput = `[ ${Array(maxLength.short).fill("\"foo\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more… ]`;
const defaultLongOutput = `[ ${Array(maxLength.long).fill("\"foo\"").join(", ")}, 1 more… ]`;
const modeTests = [
{
@ -161,7 +161,7 @@ window.onload = Task.async(function* () {
function testRecursiveArray() {
let stub = [1];
stub.push(stub);
const defaultOutput = `[1, […]]`;
const defaultOutput = `[ 1, […] ]`;
const modeTests = [
{
@ -194,7 +194,7 @@ window.onload = Task.async(function* () {
p4: "s4"
}
];
const defaultOutput = `[Object{p1: "s1", p3: "s3", p4: "s4", 1 more…}]`;
const defaultOutput = `[ Object { p1: "s1", p3: "s3", p4: "s4", 1 more… } ]`;
const modeTests = [
{
@ -224,10 +224,10 @@ window.onload = Task.async(function* () {
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
];
const defaultOutput = `["a", "b", "c", "d", "e", "f", "g", "h", "i", "j",` +
const defaultOutput = `[ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",` +
` "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",` +
` "u", "v", "w", "x", "y", "z"]`;
const shortOutput = `["a", "b", "c", 23 more…]`;
` "u", "v", "w", "x", "y", "z" ]`;
const shortOutput = `[ "a", "b", "c", 23 more… ]`;
const modeTests = [
{

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

@ -78,7 +78,7 @@ window.onload = Task.async(function* () {
// Test array: `[1, "foo", {}]`;
const testName = "testMaxProps";
const defaultOutput = `Array[1, "foo", Object]`;
const defaultOutput = `Array[ 1, "foo", Object ]`;
const modeTests = [
{
@ -106,7 +106,7 @@ window.onload = Task.async(function* () {
// Test array = `["test string"…] //4 items`
const testName = "testMoreThanShortMaxProps";
const defaultOutput = `Array[${Array(maxLength.short).fill("\"test string\"").join(", ")}, 1 more…]`;
const defaultOutput = `Array[ ${Array(maxLength.short).fill("\"test string\"").join(", ")}, 1 more… ]`;
const modeTests = [
{
@ -123,7 +123,7 @@ window.onload = Task.async(function* () {
},
{
mode: "long",
expectedOutput: `Array[${Array(maxLength.short + 1).fill("\"test string\"").join(", ")}]`,
expectedOutput: `Array[ ${Array(maxLength.short + 1).fill("\"test string\"").join(", ")} ]`,
}
];
@ -134,8 +134,8 @@ window.onload = Task.async(function* () {
// Test array = `["test string"…] //301 items`
const testName = "testMoreThanLongMaxProps";
const defaultShortOutput = `Array[${Array(maxLength.short).fill("\"test string\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more…]`;
const defaultLongOutput = `Array[${Array(maxLength.long).fill("\"test string\"").join(", ")}, 1 more…]`;
const defaultShortOutput = `Array[ ${Array(maxLength.short).fill("\"test string\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more… ]`;
const defaultLongOutput = `Array[ ${Array(maxLength.long).fill("\"test string\"").join(", ")}, 1 more… ]`;
const modeTests = [
{
@ -166,7 +166,7 @@ window.onload = Task.async(function* () {
// Test array = `let a = []; a = [a]`
const testName = "testRecursiveArray";
const defaultOutput = `Array[[1]]`;
const defaultOutput = `Array[ [1] ]`;
const modeTests = [
{
@ -193,7 +193,7 @@ window.onload = Task.async(function* () {
function testNamedNodeMap() {
const testName = "testNamedNodeMap";
const defaultOutput = `NamedNodeMap[class="myclass", cellpadding="7", border="3"]`;
const defaultOutput = `NamedNodeMap[ class="myclass", cellpadding="7", border="3" ]`;
const modeTests = [
{

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

@ -75,7 +75,7 @@ window.onload = Task.async(function* () {
// Test object: `{a: "a", b: "b", c: "c"}`;
const testName = "testMaxProps";
const defaultOutput = `Object {a: "a", b: "b", c: "c"}`;
const defaultOutput = `Object { a: "a", b: "b", c: "c" }`;
const modeTests = [
{
@ -103,7 +103,7 @@ window.onload = Task.async(function* () {
// Test object = `{p0: "0", p1: "1", p2: "2", …, p100: "100"}`
const testName = "testMoreThanMaxProps";
const defaultOutput = `Object {p0: "0", p1: "1", p2: "2", 98 more…}`;
const defaultOutput = `Object { p0: "0", p1: "1", p2: "2", 98 more… }`;
// Generate string with 100 properties, which is the max limit
// for 'long' mode.
@ -112,7 +112,7 @@ window.onload = Task.async(function* () {
props += "p" + i + ": \"" + i + "\", ";
}
const longOutput = `Object {${props}1 more…}`;
const longOutput = `Object { ${props}1 more… }`;
const modeTests = [
{
@ -140,14 +140,14 @@ window.onload = Task.async(function* () {
// Test object: `{a: undefined, b: undefined, c: "c", d: 1}`
// @TODO This is not how we actually want the preview to be output.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1276376
const expectedOutput = `Object {a: undefined, b: undefined, c: "c", 1 more…}`;
const expectedOutput = `Object { a: undefined, b: undefined, c: "c", 1 more… }`;
}
function testNestedObject() {
// Test object: `{objProp: {id: 1}, strProp: "test string"}`
const testName = "testNestedObject";
const defaultOutput = `Object {objProp: Object, strProp: "test string"}`;
const defaultOutput = `Object { objProp: Object, strProp: "test string" }`;
const modeTests = [
{
@ -175,7 +175,7 @@ window.onload = Task.async(function* () {
// Test object: `{arrProp: ["foo", "bar", "baz"]}`
const testName = "testNestedArray";
const defaultOutput = `Object {arrProp: [3]}`;
const defaultOutput = `Object { arrProp: [3] }`;
const modeTests = [
{

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

@ -72,7 +72,7 @@ window.onload = Task.async(function* () {
const testName = "testMaxProps";
const stub = {a: "a", b: "b", c: "c"};
const defaultOutput = `Object{a: "a", b: "b", c: "c"}`;
const defaultOutput = `Object { a: "a", b: "b", c: "c" }`;
const modeTests = [
{
@ -101,7 +101,7 @@ window.onload = Task.async(function* () {
for (let i = 0; i<100; i++) {
stub[`p${i}`] = i
}
const defaultOutput = `Object{p0: 0, p1: 1, p2: 2, 97 more…}`;
const defaultOutput = `Object { p0: 0, p1: 1, p2: 2, 97 more… }`;
const modeTests = [
{
@ -127,7 +127,7 @@ window.onload = Task.async(function* () {
function testUninterestingProps() {
const stub = {a:undefined, b:undefined, c:"c", d:0};
const defaultOutput = `Object{c: "c", d: 0, a: undefined, 1 more…}`;
const defaultOutput = `Object { c: "c", d: 0, a: undefined, 1 more… }`;
const modeTests = [
{
@ -160,7 +160,7 @@ window.onload = Task.async(function* () {
strProp: "test string",
arrProp: [1]
};
const defaultOutput = `Object{strProp: "test string", objProp: Object{id: 1, arr: [2]}, arrProp: [1]}`;
const defaultOutput = `Object { strProp: "test string", objProp: Object { id: 1, arr: [ 2 ] }, arrProp: [ 1 ] }`;
const modeTests = [
{

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

@ -15,6 +15,9 @@ const PREF_INT = 64;
const PREF_BOOL = 128;
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
// We prefix all our local storage items with this.
const PREFIX = "Services.prefs:";
/**
* Create a new preference object.
*
@ -101,7 +104,7 @@ Preference.prototype = {
userValue: this.userValue,
};
localStorage.setItem(this.fullName, JSON.stringify(store));
localStorage.setItem(PREFIX + this.fullName, JSON.stringify(store));
this.branch._notify(this.name);
},
@ -249,9 +252,6 @@ PrefBranch.prototype = {
/** @see nsIPrefBranch.addObserver */
addObserver: function (domain, observer, holdWeak) {
if (domain !== "" && !domain.endsWith(".")) {
throw new Error("invalid domain to addObserver: " + domain);
}
if (holdWeak) {
throw new Error("shim prefs only supports strong observers");
}
@ -325,7 +325,8 @@ PrefBranch.prototype = {
*/
_notify: function (relativeName) {
for (let domain in this._observers) {
if (relativeName.startsWith(domain)) {
if (relativeName === domain || domain === "" ||
(domain.endsWith(".") && relativeName.startsWith(domain))) {
// Allow mutation while walking.
let localList = this._observers[domain].slice();
for (let observer of localList) {
@ -448,9 +449,12 @@ PrefBranch.prototype = {
// representations.
for (let i = 0; i < localStorage.length; ++i) {
let keyName = localStorage.key(i);
let {userValue, hasUserValue, defaultValue} =
JSON.parse(localStorage.getItem(keyName));
this._findOrCreatePref(keyName, userValue, hasUserValue, defaultValue);
if (keyName.startsWith(PREFIX)) {
let {userValue, hasUserValue, defaultValue} =
JSON.parse(localStorage.getItem(keyName));
this._findOrCreatePref(keyName.slice(PREFIX.length), userValue,
hasUserValue, defaultValue);
}
}
this._onStorageChange = this._onStorageChange.bind(this);

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

@ -16,7 +16,7 @@ var exports = {}
var module = {exports};
// Add some starter prefs.
localStorage.setItem("devtools.branch1.somebool", JSON.stringify({
localStorage.setItem("Services.prefs:devtools.branch1.somebool", JSON.stringify({
// bool
type: 128,
defaultValue: false,
@ -24,7 +24,7 @@ localStorage.setItem("devtools.branch1.somebool", JSON.stringify({
userValue: false
}));
localStorage.setItem("devtools.branch1.somestring", JSON.stringify({
localStorage.setItem("Services.prefs:devtools.branch1.somestring", JSON.stringify({
// string
type: 32,
defaultValue: "dinosaurs",
@ -32,7 +32,7 @@ localStorage.setItem("devtools.branch1.somestring", JSON.stringify({
userValue: "elephants"
}));
localStorage.setItem("devtools.branch2.someint", JSON.stringify({
localStorage.setItem("Services.prefs:devtools.branch2.someint", JSON.stringify({
// string
type: 64,
defaultValue: -16,
@ -144,11 +144,11 @@ function do_tests() {
WrappedPrefs.setIntPref("devtools.branch2.someint", -93);
is(WrappedPrefs.getIntPref("devtools.branch2.someint"), -93, "set int pref");
WrappedPrefs.setCharPref("devtools.branch1.somestring", "hello");
ok(WrappedPrefs.getCharPref("devtools.branch1.somestring"), "hello",
is(WrappedPrefs.getCharPref("devtools.branch1.somestring"), "hello",
"set string pref");
Services.prefs.clearUserPref("devtools.branch1.somestring");
ok(Services.prefs.getCharPref("devtools.branch1.somestring"), "dinosaurs",
is(Services.prefs.getCharPref("devtools.branch1.somestring"), "dinosaurs",
"clear string pref");
ok(Services.prefs.prefHasUserValue("devtools.branch1.somebool"),
@ -168,9 +168,9 @@ function do_tests() {
Services.prefs.setCharPref("devtools.branch1.somestring", "octopus");
is(Services.prefs.getCharPref("devtools.branch1.somestring"), "octopus",
"set correctly via branch");
ok(branch0.getCharPref("devtools.branch1.somestring"), "octopus",
is(branch0.getCharPref("devtools.branch1.somestring"), "octopus",
"get via base branch");
ok(branch1.getCharPref("somestring"), "octopus", "get via branch");
is(branch1.getCharPref("somestring"), "octopus", "get via branch");
let notifications = {};
@ -181,14 +181,7 @@ function do_tests() {
}
};
try {
threw = false;
branch0.addObserver("devtools.branch1", null, null);
} catch (e) {
threw = true;
}
ok(threw, "invalid branch name to addObserver");
branch0.addObserver("devtools.branch1", null, null);
branch0.addObserver("devtools.branch1.", observer, false);
branch1.addObserver("", observer, false);
@ -209,6 +202,15 @@ function do_tests() {
"somestring": true
}, "removeObserver worked");
clearNotificationList();
branch0.addObserver("devtools.branch1.somestring", observer, false);
Services.prefs.setCharPref("devtools.branch1.somestring", "northern shoveler");
isDeeply(notifications, {
"devtools.branch1.somestring": true,
"somestring": true
}, "notifications sent to two listeners");
branch0.removeObserver("devtools.branch1.somestring", observer);
// Make sure we update if the pref change comes from somewhere else.
clearNotificationList();
pref("devtools.branch1.someotherstring", "lazuli bunting");

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

@ -136,10 +136,6 @@
margin-inline-start: -12px !important;
}
.expander:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.expandable {
visibility: visible;
}

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

@ -282,6 +282,12 @@ div.CodeMirror span.eval-text {
visibility: hidden;
}
/* Mirror the twisty for rtl direction */
.theme-twisty:dir(rtl),
.theme-twisty:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.theme-checkbox {
display: inline-block;
border: 0;

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

@ -1,6 +1,6 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="#0b0b0b">
<path d="M6.7 8l3.6-3.6c.2-.2.2-.5 0-.7-.2-.2-.5-.2-.7 0L6 7.3 2.4 3.7c-.2-.2-.5-.2-.7 0-.2.2-.2.5 0 .7L5.3 8l-3.6 3.6c-.2.2-.2.5 0 .7.2.2.5.2.7 0L6 8.7l3.6 3.6c.2.2.5.2.7 0 .2-.2.2-.5 0-.7L6.7 8z"/>
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b">
<path d="M8.707 8l4.23 4.23a.5.5 0 1 1-.707.707L8 8.707l-4.23 4.23a.5.5 0 1 1-.707-.707L7.293 8l-4.23-4.23a.5.5 0 1 1 .707-.707L8 7.293l4.23-4.23a.5.5 0 0 1 .707.707L8.707 8z" fill-rule="evenodd"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 520 B

После

Ширина:  |  Высота:  |  Размер: 518 B

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

@ -294,6 +294,12 @@ div.CodeMirror span.eval-text {
background-position: -42px -14px;
}
/* Mirror the twisty for rtl direction */
.theme-twisty:dir(rtl),
.theme-twisty:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.theme-checkbox {
display: inline-block;
border: 0;

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

@ -536,6 +536,12 @@ a {
flex-shrink: 0;
}
/*Do not mirror the twisty because container force to ltr */
.message .theme-twisty:dir(rtl),
.message .theme-twisty:-moz-locale-dir(rtl) {
transform: none;
}
.cm-s-mozilla a[class] {
font-style: italic;
text-decoration: none;

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

@ -0,0 +1,3 @@
{
"presets": ["es2015"]
}

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

@ -9,6 +9,7 @@
const {
prepareMessage
} = require("devtools/client/webconsole/new-console-output/utils/messages");
const { IdGenerator } = require("devtools/client/webconsole/new-console-output/utils/id-generator");
const {
MESSAGE_ADD,
@ -18,8 +19,14 @@ const {
FILTERS_CLEAR,
} = require("../constants");
function messageAdd(packet) {
let message = prepareMessage(packet);
const defaultIdGenerator = new IdGenerator();
function messageAdd(packet, idGenerator = null) {
if (idGenerator == null) {
idGenerator = defaultIdGenerator;
}
let message = prepareMessage(packet, idGenerator);
return {
type: MESSAGE_ADD,
message

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

@ -14,7 +14,6 @@ const { getAllFilters } = require("devtools/client/webconsole/new-console-output
const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
const messagesActions = require("devtools/client/webconsole/new-console-output/actions/messages");
const uiActions = require("devtools/client/webconsole/new-console-output/actions/ui");
const { store } = require("devtools/client/webconsole/new-console-output/store");
const {
SEVERITY_FILTER
} = require("../constants");
@ -30,23 +29,23 @@ const FilterBar = createClass({
},
onClearOutputButtonClick: function () {
store.dispatch(messagesActions.messagesClear());
this.props.dispatch(messagesActions.messagesClear());
},
onToggleFilterConfigBarButtonClick: function () {
store.dispatch(uiActions.filterBarToggle());
this.props.dispatch(uiActions.filterBarToggle());
},
onClearFiltersButtonClick: function () {
store.dispatch(messagesActions.filtersClear());
this.props.dispatch(messagesActions.filtersClear());
},
onSearchInput: function (e) {
store.dispatch(messagesActions.messagesSearch(e.target.value));
this.props.dispatch(messagesActions.messagesSearch(e.target.value));
},
render() {
const {filter, ui} = this.props;
const {dispatch, filter, ui} = this.props;
let configFilterBarVisible = ui.configFilterBarVisible;
let children = [];
@ -78,22 +77,30 @@ const FilterBar = createClass({
active: filter.error,
label: "Errors",
filterType: SEVERITY_FILTER,
filterKey: "error"}),
filterKey: "error",
dispatch
}),
FilterToggleButton({
active: filter.warn,
label: "Warnings",
filterType: SEVERITY_FILTER,
filterKey: "warn"}),
filterKey: "warn",
dispatch
}),
FilterToggleButton({
active: filter.log,
label: "Logs",
filterType: SEVERITY_FILTER,
filterKey: "log"}),
filterKey: "log",
dispatch
}),
FilterToggleButton({
active: filter.info,
label: "Info",
filterType: SEVERITY_FILTER,
filterKey: "info"})
filterKey: "info",
dispatch
})
)
);
}

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

@ -8,7 +8,6 @@ const {
DOM: dom,
PropTypes
} = require("devtools/client/shared/vendor/react");
const { store } = require("devtools/client/webconsole/new-console-output/store");
const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
const {
SEVERITY_FILTER
@ -23,11 +22,12 @@ const FilterToggleButton = createClass({
filterType: PropTypes.string.isRequired,
filterKey: PropTypes.string.isRequired,
active: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired,
},
onClick: function () {
if (this.props.filterType === SEVERITY_FILTER) {
store.dispatch(actions.severityFilter(
this.props.dispatch(actions.severityFilter(
this.props.filterKey, !this.props.active));
}
},

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

@ -6,6 +6,12 @@
"use strict";
// If this is being run from Mocha, then the browser loader hasn't set up
// define. We need to do that before loading Rep.
if (typeof define === "undefined") {
require("amd-loader");
}
// React
const {
createFactory,

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

@ -19,13 +19,3 @@ DevToolsModules(
'store.js',
'types.js',
)
MOCHITEST_CHROME_MANIFESTS += [
'test/components/chrome.ini',
'test/utils/chrome.ini'
]
XPCSHELL_TESTS_MANIFESTS += [
'test/actions/xpcshell.ini',
'test/store/xpcshell.ini'
]

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

@ -9,17 +9,19 @@ const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
const { store } = require("devtools/client/webconsole/new-console-output/store");
const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
const ConsoleOutput = React.createFactory(require("devtools/client/webconsole/new-console-output/components/console-output"));
const FilterBar = React.createFactory(require("devtools/client/webconsole/new-console-output/components/filter-bar"));
const store = configureStore();
function NewConsoleOutputWrapper(parentNode, jsterm) {
let childComponent = ConsoleOutput({ jsterm });
let filterBar = FilterBar({});
let provider = React.createElement(
Provider,
{ store: store },
{ store },
React.DOM.div(
{className: "webconsole-output-wrapper"},
filterBar,

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

@ -3,13 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Services = require("Services");
const {FilterState} = require("devtools/client/webconsole/new-console-output/reducers/filters");
const {PrefState} = require("devtools/client/webconsole/new-console-output/reducers/prefs");
const { combineReducers, createStore } = require("devtools/client/shared/vendor/redux");
const { reducers } = require("./reducers/index");
function storeFactory() {
function configureStore(Services) {
if (!Services) {
Services = require("Services");
}
const initialState = {
prefs: new PrefState({
logLimit: Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1),
@ -26,9 +29,7 @@ function storeFactory() {
return createStore(combineReducers(reducers), initialState);
}
// Provide the single store instance for app code.
module.exports.store = storeFactory();
// Provide the store factory for test code so that each test is working with
// its own instance.
module.exports.storeFactory = storeFactory;
module.exports.configureStore = configureStore;

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

@ -1,39 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var { utils: Cu } = Components;
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var flags = require("devtools/shared/flags");
flags.testing = true;
flags.wantLogging = true;
flags.wantVerbose = false;
// @TODO consolidate once we have a shared head. See #16
const testPackets = new Map();
testPackets.set("console.log", {
"from": "server1.conn4.child1/consoleActor2",
"type": "consoleAPICall",
"message": {
"arguments": [
"foobar",
"test"
],
"columnNumber": 1,
"counter": null,
"filename": "file:///test.html",
"functionName": "",
"groupName": "",
"level": "log",
"lineNumber": 1,
"private": false,
"styles": [],
"timeStamp": 1455064271115,
"timer": null,
"workerType": "none",
"category": "webdev"
}
});

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

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { getRepeatId } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
const { setupActions } = require("devtools/client/webconsole/new-console-output/test/helpers");
const constants = require("devtools/client/webconsole/new-console-output/constants");
const expect = require("expect");
let actions;
describe("Message actions:", () => {
before(()=>{
actions = setupActions();
});
describe("messageAdd", () => {
it("creates expected action given a packet", () => {
const packet = {
"from": "server1.conn4.child1/consoleActor2",
"type": "consoleAPICall",
"message": {
"arguments": [
"foobar",
"test"
],
"columnNumber": 1,
"counter": null,
"filename": "file:///test.html",
"functionName": "",
"groupName": "",
"level": "log",
"lineNumber": 1,
"private": false,
"styles": [],
"timeStamp": 1455064271115,
"timer": null,
"workerType": "none",
"category": "webdev"
}
};
const action = actions.messageAdd(packet);
const expected = {
type: constants.MESSAGE_ADD,
message: stubConsoleMessages.get("console.log('foobar', 'test')")
};
// Some values on the message are generated by prepareMessage. Manually set
// these on the expected message to match.
expected.message = expected.message.set("repeatId", getRepeatId(expected.message));
expected.message = expected.message.set("id", "1");
expect(action).toEqual(expected);
});
});
describe("messagesClear", () => {
it("creates expected action", () => {
const action = actions.messagesClear();
const expected = {
type: constants.MESSAGES_CLEAR,
};
expect(action).toEqual(expected);
});
});
});

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

@ -1,40 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {
messageAdd,
messagesClear
} = require("devtools/client/webconsole/new-console-output/actions/messages");
const {
prepareMessage
} = require("devtools/client/webconsole/new-console-output/utils/messages");
const constants = require("devtools/client/webconsole/new-console-output/constants");
function run_test() {
run_next_test();
}
add_task(function* () {
const packet = testPackets.get("console.log");
const action = messageAdd(packet);
const expected = {
type: constants.MESSAGE_ADD,
// Prepare message is tested independently.
message: prepareMessage(packet)
};
// Remove ID for deepEqual comparison.
action.message = action.message.remove('id');
expected.message = expected.message.remove('id');
deepEqual(action, expected,
"messageAdd action creator returns expected action object");
});
add_task(function* () {
const action = messagesClear();
const expected = {
type: constants.MESSAGES_CLEAR,
};
deepEqual(action, expected,
"messagesClear action creator returns expected action object");
});

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

@ -1,7 +0,0 @@
[DEFAULT]
tags = devtools devtools-webconsole
head = head.js
tail =
firefox-appdir = browser
[test_messages.js]

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

@ -1,8 +1,7 @@
[DEFAULT]
support-files =
../components/head.js
head.js
[test_getRepeatId.html]
[test_render_perf.html]
skip-if = debug

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

@ -0,0 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var { utils: Cu } = Components;
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var { Assert } = require("resource://testing-common/Assert.jsm");
var { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
var { Task } = require("devtools/shared/task");
var { require: browserRequire } = BrowserLoader({
baseURI: "resource://devtools/client/webconsole/",
window: this
});

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

@ -57,11 +57,13 @@ function timeit(cb) {
}
window.onload = Task.async(function* () {
const { store } = browserRequire("devtools/client/webconsole/new-console-output/store");
const { configureStore } = browserRequire("devtools/client/webconsole/new-console-output/store");
const { messagesSearch, filtersClear } = browserRequire("devtools/client/webconsole/new-console-output/actions/messages");
const NewConsoleOutputWrapper = browserRequire("devtools/client/webconsole/new-console-output/new-console-output-wrapper");
const wrapper = new NewConsoleOutputWrapper(document.querySelector("#output"), {});
const store = configureStore();
let time = yield timeit(() => {
testPackets.forEach((message) => {
wrapper.dispatchMessageAdd(message);

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

@ -1,12 +0,0 @@
[DEFAULT]
support-files =
head.js
[test_console-api-call.html]
[test_console-api-call_repeat.html]
[test_evaluation-result.html]
[test_message-icon.html]
[test_message-container.html]
[test_message-repeat.html]
[test_page-error.html]

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

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
const { ConsoleApiCall } = require("devtools/client/webconsole/new-console-output/components/message-types/console-api-call");
const jsdom = require("mocha-jsdom");
const expect = require("expect");
const {
renderComponent
} = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("ConsoleAPICall component:", () => {
jsdom();
describe("console.log", () => {
it("renders string grips", () => {
const message = stubConsoleMessages.get("console.log('foobar', 'test')");
const rendered = renderComponent(ConsoleApiCall, {message});
const messageBody = getMessageBody(rendered);
// @TODO should output: foobar test
expect(messageBody.textContent).toBe("\"foobar\"\"test\"");
const consoleStringNodes = messageBody.querySelectorAll(".objectBox-string");
expect(consoleStringNodes.length).toBe(2);
});
it("renders repeat node", () => {
const message =
stubConsoleMessages.get("console.log('foobar', 'test')")
.set("repeat", 107);
const rendered = renderComponent(ConsoleApiCall, {message});
const repeatNode = getRepeatNode(rendered);
expect(repeatNode[0].textContent).toBe("107");
});
});
describe("console.count", () => {
it("renders", () => {
const message = stubConsoleMessages.get("console.count('bar')");
const rendered = renderComponent(ConsoleApiCall, {message});
const messageBody = getMessageBody(rendered);
expect(messageBody.textContent).toBe(message.messageText);
});
});
});
function getMessageBody(rendered) {
const queryPath = "div.message.cm-s-mozilla span span.message-flex-body span.message-body.devtools-monospace";
return rendered.querySelector(queryPath);
}
function getRepeatNode(rendered) {
const repeatPath = "span > span.message-flex-body > span.message-body.devtools-monospace + span.message-repeats";
return rendered.querySelectorAll(repeatPath);
}

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

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
const { EvaluationResult } = require("devtools/client/webconsole/new-console-output/components/message-types/evaluation-result");
const jsdom = require("mocha-jsdom");
const expect = require("expect");
const {
renderComponent
} = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("EvaluationResult component:", () => {
jsdom();
it("renders a grip result", () => {
const message = stubConsoleMessages.get("new Date(0)");
const props = {
message
};
const rendered = renderComponent(EvaluationResult, props);
const messageBody = getMessageBody(rendered);
expect(messageBody.textContent).toBe("Date1970-01-01T00:00:00.000Z");
});
});
function getMessageBody(rendered) {
const queryPath = "div.message.cm-s-mozilla span.message-body-wrapper.message-body.devtools-monospace";
return rendered.querySelector(queryPath);
}

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

@ -1,268 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* exported getPacket, renderComponent, shallowRenderComponent,
cleanActualHTML, cleanExpectedHTML */
"use strict";
var { utils: Cu } = Components;
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var { Assert } = require("resource://testing-common/Assert.jsm");
var { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var flags = require("devtools/shared/flags");
var { Task } = require("devtools/shared/task");
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/main");
const Services = require("Services");
flags.testing = true;
var { require: browserRequire } = BrowserLoader({
baseURI: "resource://devtools/client/webconsole/",
window: this
});
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
let React = browserRequire("devtools/client/shared/vendor/react");
var TestUtils = React.addons.TestUtils;
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/stubs");
// @TODO Remove this.
let testCommands = new Map();
testCommands.set("console.log()", {
command: "console.log('foobar', 'test')",
commandType: "consoleAPICall",
// @TODO should output: foobar test
expectedText: "\"foobar\"\"test\""
});
testCommands.set("new Date()", {
command: "new Date(448156800000)",
commandType: "evaluationResult",
// @TODO should output: Date 1984-03-15T00:00:00.000Z
expectedText: "Date1984-03-15T00:00:00.000Z"
});
testCommands.set("pageError", {
command: null,
commandType: "pageError",
expectedText: "ReferenceError: asdf is not defined"
});
function* getPacket(command, type = "evaluationResult") {
try {
// Attach the console to the tab.
let state = yield new Promise(function (resolve) {
attachConsoleToTab(["ConsoleAPI"], resolve);
});
// Run the command and get the packet.
let packet;
switch (type) {
case "consoleAPICall":
packet = yield new Promise((resolve) => {
function onConsoleApiCall(apiCallType, apiCallPacket) {
state.dbgClient.removeListener("consoleAPICall", onConsoleApiCall);
resolve(apiCallPacket);
}
state.dbgClient.addListener("consoleAPICall", onConsoleApiCall);
state.client.evaluateJS(`top.${command}`);
});
break;
case "evaluationResult":
packet = yield new Promise(resolve => {
state.client.evaluateJS(command, resolve);
});
break;
case "pageError":
// @TODO: get packet with RDP
packet = {
"from": "server1.conn1.child1/consoleActor2",
"type": "pageError",
"pageError": {
"errorMessage": "ReferenceError: asdf is not defined",
"sourceName": "data:text/html,<script>asdf</script>",
"lineText": "",
"lineNumber": 1,
"columnNumber": 1,
"category": "content javascript",
"timeStamp": 1455735574091,
"warning": false,
"error": false,
"exception": true,
"strict": false,
"info": false,
"private": false,
"stacktrace": [{
"columnNumber": 68,
"filename": "test.html",
"functionName": "baz",
"language": 2,
"lineNumber": 1
}, {
"columnNumber": 43,
"filename": "test.html",
"functionName": "bar",
"language": 2,
"lineNumber": 2
}, {
"columnNumber": 18,
"filename": "test.html",
"functionName": "foo",
"language": 2,
"lineNumber": 3
}, {
"columnNumber": 150,
"filename": "test.html",
"functionName": "",
"language": 2,
"lineNumber": 4
}]
}
};
break;
}
closeDebugger(state);
return packet;
} catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
}
}
function renderComponent(component, props) {
const el = React.createElement(component, props, {});
// By default, renderIntoDocument() won't work for stateless components, but
// it will work if the stateless component is wrapped in a stateful one.
// See https://github.com/facebook/react/issues/4839
const wrappedEl = React.DOM.span({}, [el]);
const renderedComponent = TestUtils.renderIntoDocument(wrappedEl);
return ReactDOM.findDOMNode(renderedComponent).children[0];
}
function shallowRenderComponent(component, props) {
const el = React.createElement(component, props);
const renderer = TestUtils.createRenderer();
renderer.render(el, {});
return renderer.getRenderOutput();
}
function cleanActualHTML(htmlString) {
return htmlString.replace(/ data-reactid=\".*?\"/g, "");
}
function cleanExpectedHTML(htmlString) {
return htmlString.replace(/(?:\r\n|\r|\n)\s*/g, "");
}
// Helpers copied in from shared/webconsole/test/common.js
function initCommon()
{
// Services.prefs.setBoolPref("devtools.debugger.log", true);
}
function initDebuggerServer()
{
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.allowChromeProcess = true;
}
function connectToDebugger(aCallback)
{
initCommon();
initDebuggerServer();
let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport);
let dbgState = { dbgClient: client };
client.connect().then(response => aCallback(dbgState, response));
}
function closeDebugger(aState, aCallback)
{
aState.dbgClient.close(aCallback);
aState.dbgClient = null;
aState.client = null;
}
function attachConsole(aListeners, aCallback) {
_attachConsole(aListeners, aCallback);
}
function attachConsoleToTab(aListeners, aCallback) {
_attachConsole(aListeners, aCallback, true);
}
function attachConsoleToWorker(aListeners, aCallback) {
_attachConsole(aListeners, aCallback, true, true);
}
function _attachConsole(aListeners, aCallback, aAttachToTab, aAttachToWorker)
{
function _onAttachConsole(aState, aResponse, aWebConsoleClient)
{
if (aResponse.error) {
console.error("attachConsole failed: " + aResponse.error + " " +
aResponse.message);
}
aState.client = aWebConsoleClient;
aCallback(aState, aResponse);
}
connectToDebugger(function _onConnect(aState, aResponse) {
if (aResponse.error) {
console.error("client.connect() failed: " + aResponse.error + " " +
aResponse.message);
aCallback(aState, aResponse);
return;
}
if (aAttachToTab) {
aState.dbgClient.listTabs(function _onListTabs(aResponse) {
if (aResponse.error) {
console.error("listTabs failed: " + aResponse.error + " " +
aResponse.message);
aCallback(aState, aResponse);
return;
}
let tab = aResponse.tabs[aResponse.selected];
aState.dbgClient.attachTab(tab.actor, function (response, tabClient) {
if (aAttachToWorker) {
var worker = new Worker("console-test-worker.js");
worker.addEventListener("message", function listener() {
worker.removeEventListener("message", listener);
tabClient.listWorkers(function (response) {
tabClient.attachWorker(response.workers[0].actor, function (response, workerClient) {
workerClient.attachThread({}, function (aResponse) {
aState.actor = workerClient.consoleActor;
aState.dbgClient.attachConsole(workerClient.consoleActor, aListeners,
_onAttachConsole.bind(null, aState));
});
});
});
});
} else {
aState.actor = tab.consoleActor;
aState.dbgClient.attachConsole(tab.consoleActor, aListeners,
_onAttachConsole.bind(null, aState));
}
});
});
} else {
aState.dbgClient.getProcess().then(response => {
aState.dbgClient.attachTab(response.form.actor, function () {
let consoleActor = response.form.consoleActor;
aState.actor = consoleActor;
aState.dbgClient.attachConsole(consoleActor, aListeners,
_onAttachConsole.bind(null, aState));
});
});
}
});
}

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

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
const { MessageContainer } = require("devtools/client/webconsole/new-console-output/components/message-container");
const { ConsoleApiCall } = require("devtools/client/webconsole/new-console-output/components/message-types/console-api-call");
const { EvaluationResult } = require("devtools/client/webconsole/new-console-output/components/message-types/evaluation-result");
const { PageError } = require("devtools/client/webconsole/new-console-output/components/message-types/page-error");
const jsdom = require("mocha-jsdom");
const expect = require("expect");
const {
renderComponent,
shallowRenderComponent
} = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("MessageContainer component:", () => {
jsdom();
it("pipes data to children as expected", () => {
const message = stubConsoleMessages.get("console.log('foobar', 'test')");
const rendered = renderComponent(MessageContainer, {message});
expect(rendered.textContent.includes("foobar")).toBe(true);
});
it("picks correct child component", () => {
const messageTypes = [
{
component: ConsoleApiCall,
message: stubConsoleMessages.get("console.log('foobar', 'test')")
},
{
component: EvaluationResult,
message: stubConsoleMessages.get("new Date(0)")
},
{
component: PageError,
message: stubConsoleMessages.get("ReferenceError")
}
];
messageTypes.forEach(info => {
const rendered = shallowRenderComponent(MessageContainer, {message: info.message});
expect(rendered.type).toBe(info.component);
});
});
});

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

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {
SEVERITY_ERROR,
} = require("devtools/client/webconsole/new-console-output/constants");
const { MessageIcon } = require("devtools/client/webconsole/new-console-output/components/message-icon");
const jsdom = require("mocha-jsdom");
const expect = require("expect");
const {
renderComponent
} = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("MessageIcon component:", () => {
jsdom();
it("renders icon based on severity", () => {
const rendered = renderComponent(MessageIcon, { severity: SEVERITY_ERROR });
expect(rendered.classList.contains("icon")).toBe(true);
expect(rendered.getAttribute("title")).toBe("Error");
});
});

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

@ -0,0 +1,30 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs");
const { PageError } = require("devtools/client/webconsole/new-console-output/components/message-types/page-error");
const jsdom = require("mocha-jsdom");
const expect = require("expect");
const {
renderComponent
} = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("PageError component:", () => {
jsdom();
it("renders a page error", () => {
const message = stubConsoleMessages.get("ReferenceError");
const rendered = renderComponent(PageError, {message});
const messageBody = getMessageBody(rendered);
expect(messageBody.textContent).toBe("ReferenceError: asdf is not defined");
});
});
function getMessageBody(rendered) {
const queryPath = "div.message span.message-body-wrapper.message-body.devtools-monospace";
return rendered.querySelector(queryPath);
}

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

@ -0,0 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { MessageRepeat } = require("devtools/client/webconsole/new-console-output/components/message-repeat");
const jsdom = require("mocha-jsdom");
const expect = require("expect");
const {
renderComponent
} = require("devtools/client/webconsole/new-console-output/test/helpers");
describe("MessageRepeat component:", () => {
jsdom();
it("renders repeated value correctly", () => {
const rendered = renderComponent(MessageRepeat, { repeat: 99 });
expect(rendered.classList.contains("message-repeats")).toBe(true);
expect(rendered.style.visibility).toBe("visible");
expect(rendered.textContent).toBe("99");
});
it("renders an un-repeated value correctly", () => {
const rendered = renderComponent(MessageRepeat, { repeat: 1 });
expect(rendered.style.visibility).toBe("hidden");
});
});

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

@ -1,66 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for ConsoleApiCall component</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for ConsoleApiCall component</p>
<script type="text/javascript;version=1.8">
const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { ConsoleApiCall } = require("devtools/client/webconsole/new-console-output/components/message-types/console-api-call");
window.onload = Task.async(function* () {
yield testConsoleLog();
yield testConsoleCount();
SimpleTest.finish()
});
function testConsoleLog() {
const packet = yield getPacket("console.log('foobar', 'test')", "consoleAPICall");
const message = prepareMessage(packet);
const rendered = renderComponent(ConsoleApiCall, {message});
const messageBody = getMessageBody(rendered);
// @TODO should output: foobar test
is(messageBody.textContent, "\"foobar\"\"test\"", "ConsoleApiCall outputs expected text");
const consoleStringNodes = messageBody.querySelectorAll(".objectBox");
is(consoleStringNodes.length, 2, "ConsoleApiCall outputs expected HTML structure");
}
function testConsoleCount() {
for (let i = 0; i < 3; i++) {
const packet = yield getPacket("console.count('bar')", "consoleAPICall");
const message = prepareMessage(packet);
const rendered = renderComponent(ConsoleApiCall, {message: message});
const messageBody = getMessageBody(rendered);
const expected = `bar: ${i + 1}`;
is(messageBody.textContent, expected,
`console.count has the expected text content: "${expected}"`);
}
const packet = yield getPacket("console.count()", "consoleAPICall")
const message = prepareMessage(packet);
const rendered = renderComponent(ConsoleApiCall, {message: message});
const messageBody = getMessageBody(rendered);
const expected = "<no label>: 1";
is(messageBody.textContent, expected,
`console.count without label has the expected text content: "${expected}"`);
}
function getMessageBody(renderedComponent) {
const queryPath = "div.message.cm-s-mozilla span span.message-flex-body span.message-body.devtools-monospace";
return renderedComponent.querySelector(queryPath);
}
</script>
</body>
</html>

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

@ -1,36 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for ConsoleApiCall component with repeats</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for ConsoleApiCall component with repeats</p>
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { ConsoleApiCall } = require("devtools/client/webconsole/new-console-output/components/message-types/console-api-call");
const packet = yield getPacket("console.log('foobar', 'test')", "consoleAPICall");
const message = prepareMessage(packet).set("repeat", 107);
const rendered = renderComponent(ConsoleApiCall, {message});
const messageBodyPath = "span > span.message-flex-body > span.message-body.devtools-monospace";
const messageBody = rendered.querySelectorAll(messageBodyPath);
// @TODO Expected output should be: foobar test
is(messageBody[0].textContent, "\"foobar\"\"test\"", "ConsoleApiCall outputs expected text for repeated message");
const repeatPath = "span > span.message-flex-body > span.message-body.devtools-monospace + span.message-repeats";
const repeat = rendered.querySelectorAll(repeatPath);
is(repeat[0].textContent, `${message.repeat}`, "ConsoleApiCall outputs correct repeat count");
SimpleTest.finish()
});
</script>
</body>
</html>

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

@ -1,46 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for EvaluationResult component</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for EvaluationResult component</p>
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
const {
EvaluationResult
} = require("devtools/client/webconsole/new-console-output/components/message-types/evaluation-result");
yield testDate();
SimpleTest.finish()
/**
* Test that evaluation result correctly outputs date results.
*/
function testDate() {
const testCommand = testCommands.get("new Date()");
const packet = yield getPacket(testCommand.command, testCommand.commandType);
const message = prepareMessage(packet);
const props = {
message
};
const rendered = renderComponent(EvaluationResult, props);
const queryPathBase = "div.message.cm-s-mozilla span.message-body-wrapper.message-body.devtools-monospace span .objectBox";
const preview = rendered.querySelectorAll(queryPathBase);
is(preview[0].textContent, testCommand.expectedText, "EvaluationResult outputs expected text");
}
});
</script>
</body>
</html>

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

@ -1,78 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for MessageContainer component</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for MessageContainer component</p>
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { MessageContainer } = require("devtools/client/webconsole/new-console-output/components/message-container");
const { ConsoleApiCall } = require("devtools/client/webconsole/new-console-output/components/message-types/console-api-call");
const { EvaluationResult } = require("devtools/client/webconsole/new-console-output/components/message-types/evaluation-result");
const { PageError } = require("devtools/client/webconsole/new-console-output/components/message-types/page-error");
yield testFullRender();
yield testGetMessageComponent();
SimpleTest.finish();
/**
* Test that passing in a message correctly wires up all the children.
*
* The different combinations of children are tested in separate per-component
* tests. This test just ensures that this component pipes data to its children.
*/
function testFullRender() {
const testValue = testCommands.get("console.log()");
const packet = yield getPacket(testValue.command, testValue.commandType);
const message = prepareMessage(packet);
const props = {
message
};
const rendered = renderComponent(MessageContainer, props);
ok(rendered.textContent.includes(testValue.expectedText),
"MessageContainer pipes data to its children as expected");
}
/**
* Test that getMessageComponent() returns correct component for each message type.
*/
function testGetMessageComponent() {
const testValues = [
{
commandObj: testCommands.get("console.log()"),
expectedComponent: ConsoleApiCall
},
{
commandObj: testCommands.get("new Date()"),
expectedComponent: EvaluationResult
},
{
commandObj: testCommands.get("pageError"),
expectedComponent: PageError
}
];
for (let testValue of testValues) {
const { commandObj, expectedComponent } = testValue;
const packet = yield getPacket(commandObj.command, commandObj.commandType);
const message = prepareMessage(packet);
const rendered = shallowRenderComponent(MessageContainer, {message});
is(rendered.type, expectedComponent,
`MessageContainer nests ${expectedComponent} based on command: ${commandObj.command}`);
}
}
});
</script>
</body>
</html>

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

@ -1,31 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for MessageRepeat component</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for MessageIcon component</p>
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const {
SEVERITY_ERROR,
} = require("devtools/client/webconsole/new-console-output/constants");
const { MessageIcon } = require("devtools/client/webconsole/new-console-output/components/message-icon");
let severity = SEVERITY_ERROR;
const iconRendered = renderComponent(MessageIcon, { severity });
ok(iconRendered.classList.contains("icon"), "MessageIcon has expected class");
is(iconRendered.getAttribute("title"), "Error",
"MessageIcon shows correct title attribute");
SimpleTest.finish();
});
</script>
</body>
</html>

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

@ -1,31 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for MessageRepeat component</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for MessageRepeat component</p>
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const { MessageRepeat } = require("devtools/client/webconsole/new-console-output/components/message-repeat");
const repeatRendered = renderComponent(MessageRepeat, { repeat: 99 });
ok(repeatRendered.classList.contains("message-repeats"), "MessageRepeat has expected class");
is(repeatRendered.style.visibility, "visible", "MessageRepeat with 2+ repeats is visible");
is(repeatRendered.textContent, "99", "MessageRepeat shows correct number of repeats");
const noRepeatRendered = renderComponent(MessageRepeat, { repeat: 1 });
is(noRepeatRendered.style.visibility, "hidden", "MessageRepeat with 1 repeat is hidden");
is(noRepeatRendered.textContent, "1", "MessageRepeat with 1 repeat shows correct number of repeats")
SimpleTest.finish();
});
</script>
</body>
</html>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше