mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 08:45:46 +00:00
Merge mozilla-central to mozilla-inbound. a=merge
This commit is contained in:
commit
a9686f654d
@ -55,9 +55,6 @@ module.exports = {
|
||||
}, {
|
||||
// TODO: Bug 1246594. Empty this list once the rule has landed for all dirs
|
||||
"files": [
|
||||
"gfx/layers/apz/test/mochitest/**",
|
||||
"mobile/android/components/**",
|
||||
"mobile/android/modules/**",
|
||||
"modules/libmar/tests/unit/head_libmar.js",
|
||||
"netwerk/protocol/http/WellKnownOpportunisticUtils.jsm",
|
||||
"netwerk/test/httpserver/httpd.js",
|
||||
|
@ -65,6 +65,12 @@ var SidebarUI = {
|
||||
_switcherArrow: null,
|
||||
_inited: false,
|
||||
|
||||
_initDeferred: PromiseUtils.defer(),
|
||||
|
||||
get promiseInitialized() {
|
||||
return this._initDeferred.promise;
|
||||
},
|
||||
|
||||
get initialized() {
|
||||
return this._inited;
|
||||
},
|
||||
@ -83,6 +89,8 @@ var SidebarUI = {
|
||||
});
|
||||
|
||||
this._inited = true;
|
||||
|
||||
this._initDeferred.resolve();
|
||||
},
|
||||
|
||||
uninit() {
|
||||
|
@ -983,7 +983,7 @@ const menuTracker = {
|
||||
gMenuBuilder.build(subject);
|
||||
},
|
||||
|
||||
onWindowOpen(window) {
|
||||
async onWindowOpen(window) {
|
||||
for (const id of menuTracker.menuIds) {
|
||||
const menu = window.document.getElementById(id);
|
||||
menu.addEventListener("popupshowing", menuTracker);
|
||||
@ -991,7 +991,10 @@ const menuTracker = {
|
||||
|
||||
const sidebarHeader = window.document.getElementById("sidebar-switcher-target");
|
||||
sidebarHeader.addEventListener("SidebarShown", menuTracker.onSidebarShown);
|
||||
if (window.SidebarUI.currentID === "viewBookmarksSidebar") {
|
||||
|
||||
await window.SidebarUI.promiseInitialized;
|
||||
|
||||
if (!window.closed && window.SidebarUI.currentID === "viewBookmarksSidebar") {
|
||||
menuTracker.onSidebarShown({currentTarget: sidebarHeader});
|
||||
}
|
||||
},
|
||||
|
@ -1185,7 +1185,6 @@ function getTransactionsForCopy(items, insertionIndex,
|
||||
!PlacesUtils.bookmarks.isVirtualRootItem(guid) &&
|
||||
!PlacesUtils.isVirtualLeftPaneItem(guid)) {
|
||||
transaction = PlacesTransactions.Copy({
|
||||
excludingAnnotation: "Places/SmartBookmark",
|
||||
guid,
|
||||
newIndex: index,
|
||||
newParentGuid: insertionParentGuid,
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
const TP_PB_ENABLED_PREF = "privacy.trackingprotection.pbmode.enabled";
|
||||
|
||||
const {UrlbarTestUtils} = ChromeUtils.import("resource://testing-common/UrlbarTestUtils.jsm");
|
||||
|
||||
/**
|
||||
* Opens a new private window and loads "about:privatebrowsing" there.
|
||||
*/
|
||||
@ -133,12 +135,15 @@ add_task(async function test_search_handoff_on_keydown() {
|
||||
});
|
||||
ok(urlBarHasNormalFocus(win), "url bar has normal focused");
|
||||
is(win.gURLBar.value, "@google f", "url bar has search text");
|
||||
await UrlbarTestUtils.promiseSearchComplete(win);
|
||||
// Close the popup.
|
||||
await UrlbarTestUtils.promisePopupClose(win);
|
||||
|
||||
// Hitting ESC should reshow the in-content search
|
||||
await new Promise(r => EventUtils.synthesizeKey("KEY_Escape", {}, win, r));
|
||||
await ContentTask.spawn(tab, null, async function() {
|
||||
ok(!content.document.getElementById("search-handoff-button").classList.contains("hidden"),
|
||||
"in-content search is not");
|
||||
"in-content search is not hidden");
|
||||
});
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
@ -176,6 +181,11 @@ add_task(async function test_search_handoff_on_paste() {
|
||||
.getService(SpecialPowers.Ci.nsIClipboardHelper);
|
||||
helper.copyString("words");
|
||||
await new Promise(r => EventUtils.synthesizeKey("v", {accelKey: true}, win, r));
|
||||
// TODO: Bug 1539199 We should be able to wait for search complete for AwesomeBar
|
||||
// as well.
|
||||
if (UrlbarPrefs.get("quantumbar")) {
|
||||
await UrlbarTestUtils.promiseSearchComplete(win);
|
||||
}
|
||||
ok(urlBarHasNormalFocus(win), "url bar has normal focused");
|
||||
is(win.gURLBar.value, "@google words", "url bar has search text");
|
||||
|
||||
|
@ -554,6 +554,7 @@ class UrlbarInput {
|
||||
muxer: "UnifiedComplete",
|
||||
providers: ["UnifiedComplete"],
|
||||
searchString,
|
||||
userContextId: this.window.gBrowser.selectedBrowser.getAttribute("usercontextid"),
|
||||
}));
|
||||
}
|
||||
|
||||
@ -989,12 +990,18 @@ class UrlbarInput {
|
||||
*/
|
||||
_loadURL(url, openUILinkWhere, params, result = {},
|
||||
browser = this.window.gBrowser.selectedBrowser) {
|
||||
this.value = url;
|
||||
browser.userTypedValue = url;
|
||||
// No point in setting these because we'll handleRevert() a few rows below.
|
||||
if (openUILinkWhere == "current") {
|
||||
this.value = url;
|
||||
browser.userTypedValue = url;
|
||||
}
|
||||
|
||||
if (this.window.gInitialPages.includes(url)) {
|
||||
// No point in setting this if we are loading in a new window.
|
||||
if (openUILinkWhere != "window" &&
|
||||
this.window.gInitialPages.includes(url)) {
|
||||
browser.initialPageLoadedFromUserAction = url;
|
||||
}
|
||||
|
||||
try {
|
||||
UrlbarUtils.addToUrlbarHistory(url, this.window);
|
||||
} catch (ex) {
|
||||
|
@ -395,6 +395,8 @@ class UrlbarQueryContext {
|
||||
* The maximum number of results that will be displayed for this query.
|
||||
* @param {boolean} options.allowAutofill
|
||||
* Whether or not to allow providers to include autofill results.
|
||||
* @param {number} options.userContextId
|
||||
* The container id where this context was generated, if any.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this._checkRequiredOptions(options, [
|
||||
@ -418,6 +420,8 @@ class UrlbarQueryContext {
|
||||
(!Array.isArray(options.sources) || !options.sources.length)) {
|
||||
throw new Error(`Invalid sources list`);
|
||||
}
|
||||
|
||||
this.userContextId = options.userContextId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,6 +226,17 @@ var UrlbarTestUtils = {
|
||||
let urlbar = getUrlbarAbstraction(win);
|
||||
return urlbar.isPopupOpen();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the userContextId (container id) for the last search.
|
||||
* @param {object} win The browser window
|
||||
* @returns {Promise} resolved when fetching is complete
|
||||
* @resolves {number} a userContextId
|
||||
*/
|
||||
promiseUserContextId(win) {
|
||||
let urlbar = getUrlbarAbstraction(win);
|
||||
return urlbar.promiseUserContextId();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -340,6 +351,15 @@ class UrlbarAbstraction {
|
||||
"waiting urlbar search to complete", 100, 50);
|
||||
}
|
||||
|
||||
async promiseUserContextId() {
|
||||
const defaultId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
|
||||
if (this.quantumbar) {
|
||||
let context = await this.urlbar.lastQueryContextPromise;
|
||||
return context.userContextId || defaultId;
|
||||
}
|
||||
return this.urlbar.userContextId || defaultId;
|
||||
}
|
||||
|
||||
async promiseResultAt(index) {
|
||||
if (!this.quantumbar) {
|
||||
// In the legacy address bar, old results are replaced when new results
|
||||
|
@ -70,7 +70,13 @@ async function withNewWindow(callback) {
|
||||
"", "chrome");
|
||||
await BrowserTestUtils.waitForEvent(win, "load");
|
||||
|
||||
win.gBrowser = {};
|
||||
win.gBrowser = {
|
||||
selectedBrowser: {
|
||||
getAttribute() {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Clone the elements into the new window, so we get exact copies without having
|
||||
// to replicate the xul.
|
||||
|
@ -11,8 +11,10 @@ const START_VALUE = "example.org";
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.altClickSave", true],
|
||||
["browser.urlbar.autoFill", false]],
|
||||
set: [
|
||||
["browser.altClickSave", true],
|
||||
["browser.urlbar.autoFill", false],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@ -29,7 +31,7 @@ add_task(async function alt_left_click_test() {
|
||||
};
|
||||
});
|
||||
|
||||
triggerCommand("click", {altKey: true});
|
||||
await triggerCommand("click", {altKey: true});
|
||||
|
||||
await saveURLPromise;
|
||||
ok(true, "SaveURL was called");
|
||||
@ -41,7 +43,7 @@ add_task(async function shift_left_click_test() {
|
||||
|
||||
let destinationURL = "http://" + TEST_VALUE + "/";
|
||||
let newWindowPromise = BrowserTestUtils.waitForNewWindow({url: destinationURL});
|
||||
triggerCommand("click", {shiftKey: true});
|
||||
await triggerCommand("click", {shiftKey: true});
|
||||
let win = await newWindowPromise;
|
||||
|
||||
info("URL should be loaded in a new window");
|
||||
@ -65,7 +67,7 @@ add_task(async function right_click_test() {
|
||||
// Add a new tab.
|
||||
await promiseOpenNewTab();
|
||||
|
||||
triggerCommand("click", {button: 2});
|
||||
await triggerCommand("click", {button: 2});
|
||||
|
||||
// Right click should do nothing (context menu will be shown).
|
||||
is(gURLBar.value, TEST_VALUE, "Urlbar still has the value we entered");
|
||||
@ -81,7 +83,7 @@ add_task(async function shift_accel_left_click_test() {
|
||||
let tab = await promiseOpenNewTab();
|
||||
|
||||
let loadStartedPromise = promiseLoadStarted();
|
||||
triggerCommand("click", {accelKey: true, shiftKey: true});
|
||||
await triggerCommand("click", {accelKey: true, shiftKey: true});
|
||||
await loadStartedPromise;
|
||||
|
||||
// Check the load occurred in a new background tab.
|
||||
@ -92,7 +94,7 @@ add_task(async function shift_accel_left_click_test() {
|
||||
|
||||
// Select the new background tab
|
||||
gBrowser.selectedTab = gBrowser.selectedTab.nextElementSibling;
|
||||
is(gURLBar.value, TEST_VALUE, "New URL is loaded in new tab");
|
||||
is(gURLBar.textValue, TEST_VALUE, "New URL is loaded in new tab");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeCurrentTab();
|
||||
@ -129,7 +131,7 @@ add_task(async function load_in_current_tab_test() {
|
||||
|
||||
// Trigger a load and check it occurs in the current tab.
|
||||
let loadStartedPromise = promiseLoadStarted();
|
||||
triggerCommand(type, details);
|
||||
await triggerCommand(type, details);
|
||||
await loadStartedPromise;
|
||||
|
||||
info("URL should be loaded in the current tab");
|
||||
@ -149,7 +151,7 @@ add_task(async function load_in_new_tab_test() {
|
||||
desc: "Ctrl/Cmd left click on go button",
|
||||
type: "click",
|
||||
details: {accelKey: true},
|
||||
url: null,
|
||||
url: "about:blank",
|
||||
},
|
||||
{
|
||||
desc: "Alt+Return keypress in a dirty tab",
|
||||
@ -163,16 +165,16 @@ add_task(async function load_in_new_tab_test() {
|
||||
info(`Running test: ${desc}`);
|
||||
|
||||
// Add a new tab.
|
||||
let tab = await promiseOpenNewTab(url || "about:blank");
|
||||
let tab = await promiseOpenNewTab(url);
|
||||
|
||||
// Trigger a load and check it occurs in the current tab.
|
||||
let tabSwitchedPromise = promiseNewTabSwitched();
|
||||
triggerCommand(type, details);
|
||||
await triggerCommand(type, details);
|
||||
await tabSwitchedPromise;
|
||||
|
||||
// Check the load occurred in a new tab.
|
||||
info("URL should be loaded in a new focused tab");
|
||||
is(gURLBar.inputField.value, TEST_VALUE, "Urlbar still has the value we entered");
|
||||
is(gURLBar.textValue, TEST_VALUE, "Urlbar still has the value we entered");
|
||||
await promiseCheckChildNoFocusedElement(gBrowser.selectedBrowser);
|
||||
is(document.activeElement, gBrowser.selectedBrowser, "Content window should be focused");
|
||||
isnot(gBrowser.selectedTab, tab, "New URL was loaded in a new tab");
|
||||
@ -183,11 +185,15 @@ add_task(async function load_in_new_tab_test() {
|
||||
}
|
||||
});
|
||||
|
||||
function triggerCommand(type, details = {}) {
|
||||
async function triggerCommand(type, details = {}) {
|
||||
gURLBar.focus();
|
||||
gURLBar.value = "";
|
||||
EventUtils.sendString(TEST_VALUE);
|
||||
|
||||
Assert.equal(await UrlbarTestUtils.promiseUserContextId(window),
|
||||
gBrowser.selectedTab.getAttribute("usercontextid"),
|
||||
"userContextId must be the same as the originating tab");
|
||||
|
||||
if (type == "click") {
|
||||
ok(gURLBar.hasAttribute("usertyping"),
|
||||
"usertyping attribute must be set for the go button to be visible");
|
||||
@ -212,8 +218,9 @@ function promiseLoadStarted() {
|
||||
});
|
||||
}
|
||||
|
||||
let gUserContextIdSerial = 1;
|
||||
async function promiseOpenNewTab(url = "about:blank") {
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, url);
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, url, {userContextId: gUserContextIdSerial++});
|
||||
let tabSwitchPromise = promiseNewTabSwitched(tab);
|
||||
gBrowser.selectedTab = tab;
|
||||
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
|
@ -45,10 +45,14 @@
|
||||
--white-100: #fff; /* for ui, no special semantic */
|
||||
|
||||
/* Typography from Photon */
|
||||
/* See https://firefox-dev.tools/photon/visuals/typography.html */
|
||||
--body-10-font-size: 13px;
|
||||
--body-10-font-weight: 400;
|
||||
--body-20-font-size: 15px;
|
||||
--body-20-font-weight: 700;
|
||||
--body-20-font-weight: 400;
|
||||
--body-20-font-weight-bold: 700;
|
||||
--caption-10-font-size: 11px;
|
||||
--caption-10-font-weight: 400;
|
||||
--caption-20-font-size: 13px;
|
||||
--caption-20-font-weight: 400;
|
||||
--caption-20-color: var(--grey-50);
|
||||
@ -245,7 +249,7 @@ p, h1 {
|
||||
|
||||
/* adds breathing space to the separator */
|
||||
.separator--breathe {
|
||||
margin: calc(var(--base-unit) * 4) 0;
|
||||
margin: calc(var(--base-unit) * 5) 0;
|
||||
}
|
||||
|
||||
/* a series of button-like elements, layed out horizontally */
|
||||
|
@ -43,7 +43,7 @@
|
||||
align-self: center;
|
||||
grid-area: name;
|
||||
font-size: var(--body-20-font-size);
|
||||
font-weight: var(--body-20-font-weight);
|
||||
font-weight: var(--body-20-font-weight-bold);
|
||||
line-height: 1.5;
|
||||
margin-inline-start: calc(var(--base-unit) * 3);
|
||||
}
|
||||
|
@ -2,6 +2,11 @@
|
||||
* 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/. */
|
||||
|
||||
.sidebar {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto;
|
||||
}
|
||||
|
||||
.sidebar__label {
|
||||
color: var(--grey-40);
|
||||
display: block;
|
||||
@ -13,3 +18,20 @@
|
||||
.sidebar__refresh-usb {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sidebar__footer {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.sidebar__footer__support-help {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
column-gap: calc(var(--base-unit) * 4);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidebar__footer__icon {
|
||||
width: calc(var(--base-unit) * 4);
|
||||
height: calc(var(--base-unit) * 4);
|
||||
}
|
||||
|
@ -63,9 +63,7 @@ class Sidebar extends PureComponent {
|
||||
|
||||
renderDevicesEmpty() {
|
||||
return SidebarItem(
|
||||
{
|
||||
isSelected: false,
|
||||
},
|
||||
{},
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-sidebar-no-devices",
|
||||
@ -89,12 +87,12 @@ class Sidebar extends PureComponent {
|
||||
}
|
||||
// render all devices otherwise
|
||||
return [
|
||||
...this.renderSidebarItems(GLOBE_ICON, networkRuntimes),
|
||||
...this.renderSidebarItems(USB_ICON, usbRuntimes),
|
||||
...this.renderRuntimeItems(GLOBE_ICON, networkRuntimes),
|
||||
...this.renderRuntimeItems(USB_ICON, usbRuntimes),
|
||||
];
|
||||
}
|
||||
|
||||
renderSidebarItems(icon, runtimes) {
|
||||
renderRuntimeItems(icon, runtimes) {
|
||||
const { dispatch, selectedPage, selectedRuntimeId } = this.props;
|
||||
|
||||
return runtimes.map(runtime => {
|
||||
@ -123,6 +121,51 @@ class Sidebar extends PureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
renderFooter() {
|
||||
const HELP_ICON_SRC = "chrome://global/skin/icons/help.svg";
|
||||
const SUPPORT_URL = "https://developer.mozilla.org/docs/Tools/about:debugging";
|
||||
|
||||
return dom.footer(
|
||||
{
|
||||
className: "sidebar__footer",
|
||||
},
|
||||
dom.ul(
|
||||
{},
|
||||
SidebarItem(
|
||||
{
|
||||
className: "sidebar-item--condensed",
|
||||
to: SUPPORT_URL,
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "sidebar__footer__support-help",
|
||||
},
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-sidebar-support-icon",
|
||||
attrs: {
|
||||
alt: true,
|
||||
},
|
||||
},
|
||||
dom.img(
|
||||
{
|
||||
className: "sidebar__footer__icon",
|
||||
src: HELP_ICON_SRC,
|
||||
}
|
||||
),
|
||||
),
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-sidebar-support",
|
||||
},
|
||||
dom.span({}, "about-debugging-sidebar-support"),
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dispatch, selectedPage, selectedRuntimeId, isScanningUsb } = this.props;
|
||||
|
||||
@ -156,17 +199,15 @@ class Sidebar extends PureComponent {
|
||||
),
|
||||
SidebarItem(
|
||||
{
|
||||
className: "sidebar-item--overflow",
|
||||
isSelected: false,
|
||||
className: "sidebar-item--overflow sidebar-item--full-width",
|
||||
},
|
||||
dom.hr({ className: "separator" }),
|
||||
dom.hr({ className: "separator separator--breathe" }),
|
||||
this.renderAdbAddonStatus(),
|
||||
),
|
||||
this.renderDevices(),
|
||||
SidebarItem(
|
||||
{
|
||||
className: "sidebar-item--breathe sidebar__refresh-usb",
|
||||
isSelected: false,
|
||||
key: "refresh-devices",
|
||||
},
|
||||
RefreshDevicesButton({
|
||||
@ -174,7 +215,8 @@ class Sidebar extends PureComponent {
|
||||
isScanning: isScanningUsb,
|
||||
})
|
||||
),
|
||||
)
|
||||
),
|
||||
this.renderFooter(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,9 @@
|
||||
border-radius: 2px;
|
||||
display: grid;
|
||||
grid-template-columns: 34px 1fr;
|
||||
font-size: 16px;
|
||||
height: 100%;
|
||||
font-size: var(--body-20-font-size);
|
||||
font-weight: var(--body-20-font-weight);
|
||||
}
|
||||
|
||||
.sidebar-fixed-item__icon {
|
||||
|
@ -33,6 +33,7 @@ class SidebarFixedItem extends PureComponent {
|
||||
|
||||
return SidebarItem(
|
||||
{
|
||||
className: "sidebar-item--tall",
|
||||
isSelected,
|
||||
to,
|
||||
},
|
||||
|
@ -11,17 +11,29 @@
|
||||
.sidebar-item {
|
||||
color: var(--sidebar-text-color);
|
||||
border-radius: 2px;
|
||||
height: var(--category-height);
|
||||
padding-inline-end: var(--category-padding);
|
||||
padding-inline-start: var(--category-padding);
|
||||
transition: background-color var(--category-transition-duration);
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.sidebar-item--overflow {
|
||||
.sidebar-item--tall {
|
||||
height: var(--category-height);
|
||||
}
|
||||
|
||||
.sidebar-item--condensed {
|
||||
height: calc(var(--base-unit) * 9);
|
||||
}
|
||||
|
||||
.sidebar-item--full-width {
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
|
||||
/* .sidebar-item--overflow {
|
||||
min-height: var(--category-height);
|
||||
height: auto;
|
||||
}
|
||||
} */
|
||||
|
||||
.sidebar-item__link {
|
||||
display: block;
|
||||
|
@ -22,24 +22,41 @@ class SidebarItem extends PureComponent {
|
||||
};
|
||||
}
|
||||
|
||||
static get defaultProps() {
|
||||
return {
|
||||
isSelected: false,
|
||||
};
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const { children, to } = this.props;
|
||||
|
||||
if (to) {
|
||||
return Link(
|
||||
{
|
||||
className: "sidebar-item__link js-sidebar-link",
|
||||
to,
|
||||
},
|
||||
children
|
||||
);
|
||||
const isExternalUrl = /^http/.test(to);
|
||||
|
||||
return isExternalUrl
|
||||
? dom.a(
|
||||
{
|
||||
className: "sidebar-item__link",
|
||||
href: to,
|
||||
target: "_blank",
|
||||
},
|
||||
children,
|
||||
)
|
||||
: Link(
|
||||
{
|
||||
className: "sidebar-item__link js-sidebar-link",
|
||||
to,
|
||||
},
|
||||
children,
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {className, isSelected, to } = this.props;
|
||||
const { className, isSelected, to } = this.props;
|
||||
|
||||
return dom.li(
|
||||
{
|
||||
|
@ -11,15 +11,25 @@
|
||||
*/
|
||||
|
||||
.sidebar-runtime-item__container {
|
||||
font-size: 0.8em;
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-column-gap: var(--base-unit);
|
||||
grid-template-columns: calc(var(--base-unit) * 6) 1fr auto;
|
||||
height: 100%;
|
||||
font-size: var(--body-20-font-size);
|
||||
font-weight: var(--body-20-font-weight);
|
||||
}
|
||||
|
||||
.sidebar-runtime-item__icon {
|
||||
fill: currentColor;
|
||||
-moz-context-properties: fill;
|
||||
}
|
||||
|
||||
.sidebar-runtime-item__runtime {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.sidebar-runtime-item__runtime__details {
|
||||
font-size: var(--caption-10-font-size);
|
||||
font-weight: var(--caption-10-font-weight);
|
||||
}
|
||||
|
@ -57,29 +57,47 @@ class SidebarRuntimeItem extends PureComponent {
|
||||
const displayName = isUnknown ?
|
||||
getString("about-debugging-sidebar-runtime-item-waiting-for-runtime") : name;
|
||||
|
||||
const titleLocalizationId = deviceName ?
|
||||
"about-debugging-sidebar-runtime-item-name" :
|
||||
"about-debugging-sidebar-runtime-item-name-no-device";
|
||||
const localizationId = deviceName
|
||||
? "about-debugging-sidebar-runtime-item-name"
|
||||
: "about-debugging-sidebar-runtime-item-name-no-device";
|
||||
|
||||
const className = "ellipsis-text sidebar-runtime-item__runtime";
|
||||
|
||||
function renderWithDevice() {
|
||||
return dom.span(
|
||||
{
|
||||
className,
|
||||
title: localizationId,
|
||||
},
|
||||
deviceName,
|
||||
dom.br({}),
|
||||
dom.span(
|
||||
{
|
||||
className: "sidebar-runtime-item__runtime__details",
|
||||
},
|
||||
displayName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function renderNoDevice() {
|
||||
return dom.span(
|
||||
{
|
||||
className,
|
||||
title: localizationId,
|
||||
},
|
||||
displayName,
|
||||
);
|
||||
}
|
||||
|
||||
return Localized(
|
||||
{
|
||||
id: titleLocalizationId,
|
||||
id: localizationId,
|
||||
attrs: { title: true },
|
||||
$deviceName: deviceName,
|
||||
$displayName: displayName,
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "ellipsis-text",
|
||||
title: titleLocalizationId,
|
||||
},
|
||||
displayName,
|
||||
// If a deviceName is available, display it on a separate line.
|
||||
...(deviceName ? [
|
||||
dom.br({}),
|
||||
deviceName,
|
||||
] : []),
|
||||
)
|
||||
deviceName ? renderWithDevice() : renderNoDevice(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -99,10 +117,11 @@ class SidebarRuntimeItem extends PureComponent {
|
||||
|
||||
return SidebarItem(
|
||||
{
|
||||
className: "sidebar-item--tall",
|
||||
isSelected,
|
||||
to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null,
|
||||
},
|
||||
dom.div(
|
||||
dom.section(
|
||||
{
|
||||
className: "sidebar-runtime-item__container",
|
||||
},
|
||||
|
@ -34,7 +34,7 @@ add_task(async function() {
|
||||
await waitUntil(() => !usbRuntimeSidebarItem.querySelector(".js-connect-button"));
|
||||
|
||||
info("Check whether the label of item is updated after connecting");
|
||||
ok(usbRuntimeSidebarItem.textContent.startsWith(RUNTIME_NAME), "Label of item updated");
|
||||
ok(usbRuntimeSidebarItem.textContent.includes(RUNTIME_NAME), "Label of item updated");
|
||||
|
||||
info("Remove all USB runtimes");
|
||||
mocks.removeUSBRuntime(RUNTIME_ID);
|
||||
|
10
devtools/client/aboutdebugging-new/test/jest/.eslintrc.js
Normal file
10
devtools/client/aboutdebugging-new/test/jest/.eslintrc.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"env": {
|
||||
"jest": true,
|
||||
},
|
||||
};
|
22
devtools/client/aboutdebugging-new/test/jest/README.md
Normal file
22
devtools/client/aboutdebugging-new/test/jest/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Jest Tests for devtools/client/aboutdebugging-new
|
||||
|
||||
## About
|
||||
|
||||
DevTools React components can be tested using [jest](https://jestjs.io/). Jest allows to test our UI components in isolation and complement our end to end mochitests.
|
||||
|
||||
## Run locally
|
||||
|
||||
We use yarn for dependency management. To run the tests locally:
|
||||
```
|
||||
cd devtools/client/shared/aboutdebugging-new/test/jest
|
||||
yarn && yarn test
|
||||
```
|
||||
|
||||
## Run on try
|
||||
|
||||
The tests run on try on linux64 platforms. The complete name of try job is `devtools-tests`. In treeherder, they will show up as `node(devtools)`.
|
||||
|
||||
Adding the tests to a try push depends on the try selector you are using.
|
||||
- try fuzzy: look for the job named `source-test-node-devtools-tests`
|
||||
|
||||
The configuration file for try can be found at `taskcluster/ci/source-test/node.yml`
|
@ -0,0 +1,19 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Message component renders the expected snapshot for INFO level 1`] = `
|
||||
<aside
|
||||
className="message message--level-info js-message some-classname"
|
||||
>
|
||||
<img
|
||||
className="message__icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-information.svg"
|
||||
/>
|
||||
<div
|
||||
className="message__body"
|
||||
>
|
||||
<div>
|
||||
Message content
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
`;
|
@ -0,0 +1,27 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Unit tests for the shared/Message component.
|
||||
*/
|
||||
|
||||
const renderer = require("react-test-renderer");
|
||||
const React = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const { MESSAGE_LEVEL } = require("devtools/client/aboutdebugging-new/src/constants");
|
||||
|
||||
const Message = React.createFactory(require("devtools/client/aboutdebugging-new/src/components/shared/Message"));
|
||||
|
||||
describe("Message component", () => {
|
||||
it("renders the expected snapshot for INFO level", () => {
|
||||
const message = renderer.create(Message({
|
||||
children: dom.div({}, "Message content"),
|
||||
className: "some-classname",
|
||||
level: MESSAGE_LEVEL.INFO,
|
||||
}));
|
||||
expect(message.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
14
devtools/client/aboutdebugging-new/test/jest/jest.config.js
Normal file
14
devtools/client/aboutdebugging-new/test/jest/jest.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* global __dirname */
|
||||
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
moduleNameMapper: {
|
||||
// Map all require("devtools/...") to the real devtools root.
|
||||
"^devtools\\/(.*)": `${__dirname}/../../../../$1`,
|
||||
},
|
||||
};
|
17
devtools/client/aboutdebugging-new/test/jest/package.json
Normal file
17
devtools/client/aboutdebugging-new/test/jest/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "devtools-client-framework-tests",
|
||||
"license": "MPL-2.0",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"node": ">=8.9.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"jest": "^23.0.0",
|
||||
"react-test-renderer": "16.4.1",
|
||||
"react": "16.4.1",
|
||||
"react-dom": "16.4.1"
|
||||
}
|
||||
}
|
3738
devtools/client/aboutdebugging-new/test/jest/yarn.lock
Normal file
3738
devtools/client/aboutdebugging-new/test/jest/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,14 @@ async function mapLocations(
|
||||
);
|
||||
}
|
||||
|
||||
// Filter out positions, that are not in the original source Id
|
||||
function filterBySource(positions, sourceId) {
|
||||
if (!isOriginalId(sourceId)) {
|
||||
return positions;
|
||||
}
|
||||
return positions.filter(position => position.location.sourceId == sourceId);
|
||||
}
|
||||
|
||||
function filterByUniqLocation(positions: MappedLocation[]) {
|
||||
return uniqBy(positions, ({ location }) => makeBreakpointId(location));
|
||||
}
|
||||
@ -96,6 +104,8 @@ async function _setBreakpointPositions(sourceId, thunkArgs) {
|
||||
|
||||
let positions = convertToList(results, generatedSource);
|
||||
positions = await mapLocations(positions, thunkArgs);
|
||||
|
||||
positions = filterBySource(positions, sourceId);
|
||||
positions = filterByUniqLocation(positions);
|
||||
|
||||
const source = getSource(getState(), sourceId);
|
||||
|
@ -44,7 +44,7 @@ export function generateBreakpoint(
|
||||
text: "",
|
||||
location: {
|
||||
sourceUrl: `http://localhost:8000/examples/${filename}`,
|
||||
sourceId: `${filename}/originalSource`,
|
||||
sourceId: `${filename}`,
|
||||
line,
|
||||
column
|
||||
},
|
||||
|
@ -30,19 +30,13 @@ jest.mock("../../utils/prefs", () => ({
|
||||
asyncStore: {
|
||||
pendingBreakpoints: {}
|
||||
},
|
||||
features: {
|
||||
replay: false
|
||||
},
|
||||
clear: jest.fn()
|
||||
}));
|
||||
|
||||
import "../sources/loadSourceText";
|
||||
|
||||
import {
|
||||
createStore,
|
||||
selectors,
|
||||
actions,
|
||||
makeOriginalSource,
|
||||
makeSource,
|
||||
waitForState
|
||||
} from "../../utils/test-head";
|
||||
@ -81,7 +75,7 @@ describe("when adding breakpoints", () => {
|
||||
mockSourceMaps()
|
||||
);
|
||||
|
||||
const source = makeOriginalSource("foo.js");
|
||||
const source = makeSource("foo.js");
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.newSource(makeSource("foo.js")));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
@ -116,8 +110,8 @@ describe("when adding breakpoints", () => {
|
||||
mockSourceMaps()
|
||||
);
|
||||
|
||||
const source1 = makeOriginalSource("foo");
|
||||
const source2 = makeOriginalSource("foo2");
|
||||
const source1 = makeSource("foo");
|
||||
const source2 = makeSource("foo2");
|
||||
|
||||
await dispatch(actions.newSource(makeSource("foo")));
|
||||
await dispatch(actions.newSource(makeSource("foo2")));
|
||||
@ -147,7 +141,7 @@ describe("when adding breakpoints", () => {
|
||||
mockSourceMaps()
|
||||
);
|
||||
|
||||
const source = makeOriginalSource("foo");
|
||||
const source = makeSource("foo");
|
||||
await dispatch(actions.newSource(makeSource("foo")));
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
@ -170,8 +164,8 @@ describe("when adding breakpoints", () => {
|
||||
await dispatch(actions.newSource(makeSource("foo")));
|
||||
await dispatch(actions.newSource(makeSource("foo2")));
|
||||
|
||||
const source1 = makeOriginalSource("foo");
|
||||
const source2 = makeOriginalSource("foo2");
|
||||
const source1 = makeSource("foo");
|
||||
const source2 = makeSource("foo2");
|
||||
|
||||
await dispatch(actions.newSource(source1));
|
||||
await dispatch(actions.newSource(source2));
|
||||
@ -200,7 +194,7 @@ describe("when changing an existing breakpoint", () => {
|
||||
const bp = generateBreakpoint("foo");
|
||||
const id = makePendingLocationId(bp.location);
|
||||
|
||||
const source = makeOriginalSource("foo");
|
||||
const source = makeSource("foo");
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.newSource(makeSource("foo")));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
@ -225,7 +219,7 @@ describe("when changing an existing breakpoint", () => {
|
||||
|
||||
await dispatch(actions.newSource(makeSource("foo")));
|
||||
|
||||
const source = makeOriginalSource("foo");
|
||||
const source = makeSource("foo");
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
|
||||
@ -244,7 +238,7 @@ describe("when changing an existing breakpoint", () => {
|
||||
);
|
||||
const bp = generateBreakpoint("foo.js");
|
||||
|
||||
const source = makeOriginalSource("foo.js");
|
||||
const source = makeSource("foo.js");
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.newSource(makeSource("foo.js")));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
@ -282,7 +276,7 @@ describe("initializing when pending breakpoints exist in prefs", () => {
|
||||
|
||||
await dispatch(actions.newSource(makeSource("bar.js")));
|
||||
|
||||
const source = makeOriginalSource("bar.js");
|
||||
const source = makeSource("bar.js");
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
await dispatch(actions.addBreakpoint(bar.location));
|
||||
@ -299,7 +293,7 @@ describe("initializing when pending breakpoints exist in prefs", () => {
|
||||
);
|
||||
const bp = generateBreakpoint("foo.js");
|
||||
|
||||
const source = makeOriginalSource("foo.js");
|
||||
const source = makeSource("foo.js");
|
||||
await dispatch(actions.newSource(source));
|
||||
await dispatch(actions.newSource(makeSource("foo.js")));
|
||||
await dispatch(actions.loadSourceText(source));
|
||||
@ -320,7 +314,7 @@ describe("initializing with disabled pending breakpoints in prefs", () => {
|
||||
);
|
||||
|
||||
const { getState, dispatch } = store;
|
||||
const source = makeOriginalSource("bar.js");
|
||||
const source = makeSource("bar.js");
|
||||
|
||||
await dispatch(actions.newSource(makeSource("bar.js")));
|
||||
await dispatch(actions.newSource(source));
|
||||
@ -356,7 +350,7 @@ describe("adding sources", () => {
|
||||
|
||||
expect(selectors.getBreakpointCount(getState())).toEqual(0);
|
||||
|
||||
const source = makeOriginalSource("bar.js");
|
||||
const source = makeSource("bar.js");
|
||||
|
||||
await dispatch(actions.newSource(makeSource("bar.js")));
|
||||
await dispatch(actions.newSource(source));
|
||||
@ -368,7 +362,7 @@ describe("adding sources", () => {
|
||||
});
|
||||
|
||||
it("corresponding breakpoints are added to the original source", async () => {
|
||||
const source = makeOriginalSource("bar.js", { sourceMapURL: "foo" });
|
||||
const source = makeSource("bar.js", { sourceMapURL: "foo" });
|
||||
const store = createStore(mockClient({ "5": [2] }), loadInitialState(), {
|
||||
getOriginalURLs: async () => [source.url],
|
||||
getOriginalSourceText: async () => ({ source: "" }),
|
||||
@ -406,8 +400,8 @@ describe("adding sources", () => {
|
||||
|
||||
expect(selectors.getBreakpointCount(getState())).toEqual(0);
|
||||
|
||||
const source1 = makeOriginalSource("bar.js");
|
||||
const source2 = makeOriginalSource("foo.js");
|
||||
const source1 = makeSource("bar.js");
|
||||
const source2 = makeSource("foo.js");
|
||||
await dispatch(actions.newSource(makeSource("bar.js")));
|
||||
await dispatch(actions.newSource(makeSource("foo.js")));
|
||||
await dispatch(actions.newSources([source1, source2]));
|
||||
|
@ -70,7 +70,7 @@ class DebugTargetInfo extends PureComponent {
|
||||
|
||||
return dom.span(
|
||||
{
|
||||
className: "iconized-label",
|
||||
className: "iconized-label js-connection-info",
|
||||
},
|
||||
dom.img({ src: image, alt: `${connectionType} icon`}),
|
||||
this.props.L10N.getStr(l10nId),
|
||||
@ -108,7 +108,7 @@ class DebugTargetInfo extends PureComponent {
|
||||
className: "iconized-label",
|
||||
},
|
||||
dom.img({ src: favicon, alt: "favicon"}),
|
||||
title ? dom.b({ className: "devtools-ellipsis-text"}, title) : null,
|
||||
title ? dom.b({ className: "devtools-ellipsis-text js-target-title"}, title) : null,
|
||||
dom.span({ className: "devtools-ellipsis-text" }, url),
|
||||
);
|
||||
}
|
||||
|
10
devtools/client/framework/test/jest/.eslintrc.js
Normal file
10
devtools/client/framework/test/jest/.eslintrc.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"env": {
|
||||
"jest": true,
|
||||
},
|
||||
};
|
22
devtools/client/framework/test/jest/README.md
Normal file
22
devtools/client/framework/test/jest/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Jest Tests for devtools/client/framework
|
||||
|
||||
## About
|
||||
|
||||
DevTools React components can be tested using [jest](https://jestjs.io/). Jest allows to test our UI components in isolation and complement our end to end mochitests.
|
||||
|
||||
## Run locally
|
||||
|
||||
We use yarn for dependency management. To run the tests locally:
|
||||
```
|
||||
cd devtools/client/shared/framework/test/jest
|
||||
yarn && yarn test
|
||||
```
|
||||
|
||||
## Run on try
|
||||
|
||||
The tests run on try on linux64 platforms. The complete name of the try job is `devtools-tests`. In treeherder, they will show up as `node(devtools)`.
|
||||
|
||||
Adding the tests to a try push depends on the try selector you are using.
|
||||
- try fuzzy: look for the job named `source-test-node-devtools-tests`
|
||||
|
||||
The configuration file for try can be found at `taskcluster/ci/source-test/node.yml`
|
@ -0,0 +1,130 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DebugTargetInfo component renders the expected snapshot for This Firefox target 1`] = `
|
||||
<header
|
||||
className="debug-target-info"
|
||||
>
|
||||
<span
|
||||
className="iconized-label"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
toolbox.debugTargetInfo.runtimeLabel.thisFirefox-1.0.0
|
||||
</b>
|
||||
<span
|
||||
className="devtools-ellipsis-text"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
>
|
||||
<img
|
||||
alt="favicon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-globe-icon.svg"
|
||||
/>
|
||||
<b
|
||||
className="devtools-ellipsis-text js-target-title"
|
||||
>
|
||||
Test Tab Name
|
||||
</b>
|
||||
<span
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
http://some.target/url
|
||||
</span>
|
||||
</span>
|
||||
</header>
|
||||
`;
|
||||
|
||||
exports[`DebugTargetInfo component renders the expected snapshot for USB Release target 1`] = `
|
||||
<header
|
||||
className="debug-target-info"
|
||||
>
|
||||
<span
|
||||
className="iconized-label js-connection-info"
|
||||
>
|
||||
<img
|
||||
alt="usb icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-usb-icon.svg"
|
||||
/>
|
||||
toolbox.debugTargetInfo.connection.usb
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
toolbox.debugTargetInfo.runtimeLabel-usbRuntimeBrandName-1.0.0
|
||||
</b>
|
||||
<span
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
usbDeviceName
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
>
|
||||
<img
|
||||
alt="favicon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-globe-icon.svg"
|
||||
/>
|
||||
<b
|
||||
className="devtools-ellipsis-text js-target-title"
|
||||
>
|
||||
Test Tab Name
|
||||
</b>
|
||||
<span
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
http://some.target/url
|
||||
</span>
|
||||
</span>
|
||||
</header>
|
||||
`;
|
||||
|
||||
exports[`DebugTargetInfo component renders the expected snapshot for a Toolbox with an unnamed target 1`] = `
|
||||
<header
|
||||
className="debug-target-info"
|
||||
>
|
||||
<span
|
||||
className="iconized-label"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
toolbox.debugTargetInfo.runtimeLabel.thisFirefox-1.0.0
|
||||
</b>
|
||||
<span
|
||||
className="devtools-ellipsis-text"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
>
|
||||
<img
|
||||
alt="favicon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-globe-icon.svg"
|
||||
/>
|
||||
<span
|
||||
className="devtools-ellipsis-text"
|
||||
>
|
||||
http://some.target/without/a/name
|
||||
</span>
|
||||
</span>
|
||||
</header>
|
||||
`;
|
@ -0,0 +1,110 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Unit tests for the DebugTargetInfo component.
|
||||
*/
|
||||
|
||||
const renderer = require("react-test-renderer");
|
||||
const React = require("devtools/client/shared/vendor/react");
|
||||
const DebugTargetInfo = React.createFactory(require("devtools/client/framework/components/DebugTargetInfo"));
|
||||
const { CONNECTION_TYPES } = require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
|
||||
/**
|
||||
* Stub for the L10N property expected by the DebugTargetInfo component.
|
||||
*/
|
||||
const stubL10N = {
|
||||
getStr: id => id,
|
||||
getFormatStr: (id, ...args) => [id, ...args].join("-"),
|
||||
};
|
||||
|
||||
const findByClassName = (testInstance, className) => {
|
||||
return testInstance.findAll(node => {
|
||||
return node.props.className && node.props.className.includes(className);
|
||||
});
|
||||
};
|
||||
|
||||
const TEST_TOOLBOX = {
|
||||
target: {
|
||||
name: "Test Tab Name",
|
||||
url: "http://some.target/url",
|
||||
},
|
||||
};
|
||||
|
||||
const TEST_TOOLBOX_NO_NAME = {
|
||||
target: {
|
||||
url: "http://some.target/without/a/name",
|
||||
},
|
||||
};
|
||||
|
||||
const USB_DEVICE_DESCRIPTION = {
|
||||
brandName: "usbRuntimeBrandName",
|
||||
connectionType: CONNECTION_TYPES.USB,
|
||||
channel: "release",
|
||||
deviceName: "usbDeviceName",
|
||||
version: "1.0.0",
|
||||
};
|
||||
|
||||
const THIS_FIREFOX_DEVICE_DESCRIPTION = {
|
||||
brandName: "thisFirefoxRuntimeBrandName",
|
||||
connectionType: CONNECTION_TYPES.THIS_FIREFOX,
|
||||
channel: "release",
|
||||
version: "1.0.0",
|
||||
};
|
||||
|
||||
const USB_TARGET_INFO = DebugTargetInfo({
|
||||
deviceDescription: USB_DEVICE_DESCRIPTION,
|
||||
toolbox: TEST_TOOLBOX,
|
||||
L10N: stubL10N,
|
||||
});
|
||||
|
||||
const THIS_FIREFOX_TARGET_INFO = DebugTargetInfo({
|
||||
deviceDescription: THIS_FIREFOX_DEVICE_DESCRIPTION,
|
||||
toolbox: TEST_TOOLBOX,
|
||||
L10N: stubL10N,
|
||||
});
|
||||
|
||||
const THIS_FIREFOX_NO_NAME_TARGET_INFO = DebugTargetInfo({
|
||||
deviceDescription: THIS_FIREFOX_DEVICE_DESCRIPTION,
|
||||
toolbox: TEST_TOOLBOX_NO_NAME,
|
||||
L10N: stubL10N,
|
||||
});
|
||||
|
||||
describe("DebugTargetInfo component", () => {
|
||||
it("displays connection info for USB Release target", () => {
|
||||
const targetInfo = renderer.create(USB_TARGET_INFO);
|
||||
expect(findByClassName(targetInfo.root, "js-connection-info").length).toEqual(1);
|
||||
});
|
||||
|
||||
it("renders the expected snapshot for USB Release target", () => {
|
||||
const targetInfo = renderer.create(USB_TARGET_INFO);
|
||||
expect(targetInfo.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("hides the connection info for This Firefox target", () => {
|
||||
const targetInfo = renderer.create(THIS_FIREFOX_TARGET_INFO);
|
||||
expect(findByClassName(targetInfo.root, "js-connection-info").length).toEqual(0);
|
||||
});
|
||||
|
||||
it("displays the target title if the target of the Toolbox has a name", () => {
|
||||
const targetInfo = renderer.create(THIS_FIREFOX_TARGET_INFO);
|
||||
expect(findByClassName(targetInfo.root, "js-target-title").length).toEqual(1);
|
||||
});
|
||||
|
||||
it("renders the expected snapshot for This Firefox target", () => {
|
||||
const targetInfo = renderer.create(THIS_FIREFOX_TARGET_INFO);
|
||||
expect(targetInfo.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("doesn't display the target title if the target of the Toolbox has no name", () => {
|
||||
const targetInfo = renderer.create(THIS_FIREFOX_NO_NAME_TARGET_INFO);
|
||||
expect(findByClassName(targetInfo.root, "js-target-title").length).toEqual(0);
|
||||
});
|
||||
|
||||
it("renders the expected snapshot for a Toolbox with an unnamed target", () => {
|
||||
const targetInfo = renderer.create(THIS_FIREFOX_NO_NAME_TARGET_INFO);
|
||||
expect(targetInfo.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
14
devtools/client/framework/test/jest/jest.config.js
Normal file
14
devtools/client/framework/test/jest/jest.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* global __dirname */
|
||||
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
moduleNameMapper: {
|
||||
// Map all require("devtools/...") to the real devtools root.
|
||||
"^devtools\\/(.*)": `${__dirname}/../../../../$1`,
|
||||
},
|
||||
};
|
17
devtools/client/framework/test/jest/package.json
Normal file
17
devtools/client/framework/test/jest/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "devtools-client-framework-tests",
|
||||
"license": "MPL-2.0",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"node": ">=8.9.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"jest": "^23.0.0",
|
||||
"react-test-renderer": "16.4.1",
|
||||
"react": "16.4.1",
|
||||
"react-dom": "16.4.1"
|
||||
}
|
||||
}
|
3224
devtools/client/framework/test/jest/yarn.lock
Normal file
3224
devtools/client/framework/test/jest/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,6 @@
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/layout.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/animation.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/Tabs.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/TabBar.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/SidebarToggle.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/inspector/components/InspectorTabPanel.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/splitter/SplitBox.css"/>
|
||||
|
@ -63,6 +63,15 @@ about-debugging-sidebar-runtime-item-name =
|
||||
about-debugging-sidebar-runtime-item-name-no-device =
|
||||
.title = { $displayName }
|
||||
|
||||
# Text to show in the footer of the sidebar that links to a help page
|
||||
# (currently: https://developer.mozilla.org/docs/Tools/about:debugging)
|
||||
about-debugging-sidebar-support = Debugging Support
|
||||
|
||||
# Text to show as the ALT attribute of a help icon that accompanies the help about
|
||||
# debugging link in the footer of the sidebar
|
||||
about-debugging-sidebar-support-icon =
|
||||
.alt = Help icon
|
||||
|
||||
# Text displayed in a sidebar button to refresh the list of USB devices. Clicking on it
|
||||
# will attempt to update the list of devices displayed in the sidebar.
|
||||
about-debugging-refresh-usb-devices-button = Refresh devices
|
||||
|
@ -6,7 +6,6 @@
|
||||
@import "resource://devtools/client/shared/components/splitter/SplitBox.css";
|
||||
@import "resource://devtools/client/shared/components/tree/TreeView.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/Tabs.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/TabBar.css";
|
||||
@import "chrome://devtools/skin/components-frame.css";
|
||||
@import "chrome://devtools/content/shared/sourceeditor/codemirror/lib/codemirror.css";
|
||||
@import "chrome://devtools/content/shared/sourceeditor/codemirror/addon/dialog/dialog.css";
|
||||
|
@ -6,7 +6,6 @@
|
||||
@import "resource://devtools/client/shared/components/splitter/SplitBox.css";
|
||||
@import "resource://devtools/client/shared/components/tree/TreeView.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/Tabs.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/TabBar.css";
|
||||
@import "chrome://devtools/skin/components-frame.css";
|
||||
@import "chrome://devtools/content/shared/sourceeditor/codemirror/lib/codemirror.css";
|
||||
@import "chrome://devtools/content/shared/sourceeditor/codemirror/addon/dialog/dialog.css";
|
||||
|
@ -1,46 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* 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/. */
|
||||
|
||||
/* Hides the tab strip in the TabBar */
|
||||
div[hidetabs=true] .tabs .tabs-navigation {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabs .tabs-navigation {
|
||||
display: flex;
|
||||
line-height: 15px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item:first-child {
|
||||
border-inline-start-width: 0;
|
||||
}
|
||||
|
||||
/* Remove the outline focusring from tabs-menu-item. */
|
||||
.tabs .tabs-navigation .tabs-menu-item > a:-moz-focusring {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item.is-active {
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
/* The tab takes entire horizontal space and individual tabs
|
||||
should stretch accordingly. Use flexbox for the behavior.
|
||||
Use also `overflow: hidden` so, 'overflow' and 'underflow'
|
||||
events are fired (it's utilized by the all-tabs-menu). */
|
||||
.tabs .tabs-navigation .tabs-menu {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tabs .tabs-navigation .tabs-menu-item {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.tabs .tabs-navigation .tabs-menu-item a {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -12,25 +12,72 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Hides the tab strip in the TabBar */
|
||||
div[hidetabs=true] .tabs .tabs-navigation {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabs .tabs-navigation {
|
||||
display: flex;
|
||||
line-height: 15px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
background: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
||||
.tabs .tabs-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* The tab takes entire horizontal space and individual tabs
|
||||
should stretch accordingly. Use flexbox for the behavior.
|
||||
Use also `overflow: hidden` so, 'overflow' and 'underflow'
|
||||
events are fired (it's utilized by the all-tabs-menu). */
|
||||
.tabs .tabs-navigation .tabs-menu {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--theme-toolbar-color);
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item.is-active {
|
||||
color: var(--theme-toolbar-selected-color);
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item:hover {
|
||||
background-color: var(--theme-toolbar-hover);
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item:hover:active:not(.is-active) {
|
||||
background-color: var(--theme-toolbar-hover-active);
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 4px 8px;
|
||||
padding: 3px 10px;
|
||||
border: 1px solid transparent;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
-moz-user-select: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Remove the outline focusring from tabs-menu-item. */
|
||||
.tabs .tabs-navigation .tabs-menu-item > a:-moz-focusring {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item .tab-badge {
|
||||
@ -54,11 +101,6 @@
|
||||
-moz-user-select: none !important;
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item a {
|
||||
cursor: default;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
/* Make sure panel content takes entire vertical space. */
|
||||
.tabs .panels {
|
||||
flex: 1;
|
||||
@ -69,43 +111,4 @@
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tabs .tabs-navigation,
|
||||
.tabs .tabs-navigation {
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
background: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item,
|
||||
.theme-light .tabs .tabs-menu-item {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--theme-toolbar-color);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item.is-active,
|
||||
.theme-light .tabs .tabs-menu-item.is-active {
|
||||
color: var(--theme-toolbar-selected-color);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item:last-child,
|
||||
.theme-light .tabs .tabs-menu-item:last-child {
|
||||
border-inline-end-width: 1px;
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item a,
|
||||
.theme-light .tabs .tabs-menu-item a {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item:hover,
|
||||
.theme-light .tabs .tabs-menu-item:hover {
|
||||
background-color: var(--theme-toolbar-hover);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item:hover:active:not(.is-active),
|
||||
.theme-light .tabs .tabs-menu-item:hover:active:not(.is-active) {
|
||||
background-color: var(--theme-toolbar-hover-active);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'TabBar.css',
|
||||
'TabBar.js',
|
||||
'Tabs.css',
|
||||
'Tabs.js',
|
||||
|
@ -14,7 +14,6 @@ Test all-tabs menu.
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/themes/variables.css">
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/themes/common.css">
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/shared/components/tabs/Tabs.css">
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/shared/components/tabs/TabBar.css">
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/inspector/components/side-panel.css">
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/inspector/components/InspectorTabPanel.css">
|
||||
</head>
|
||||
|
@ -17,7 +17,6 @@
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/SmartTrace.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/reps/reps.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/Tabs.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/TabBar.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/NotificationBox.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/netmonitor/src/assets/styles/httpi.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/webconsole/components/ReverseSearchInput.css"/>
|
||||
|
@ -389,13 +389,13 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
|
||||
|
||||
const { DOMNode: rawNode } = this.rawAccessible;
|
||||
const win = rawNode.ownerGlobal;
|
||||
this.walker.loadTransitionDisablingStyleSheet(win);
|
||||
this.walker.clearStyles(win);
|
||||
const contrastRatio = await getContrastRatioFor(rawNode.parentNode, {
|
||||
bounds: this.bounds,
|
||||
win,
|
||||
});
|
||||
|
||||
this.walker.removeTransitionDisablingStyleSheet(win);
|
||||
this.walker.restoreStyles(win);
|
||||
|
||||
return contrastRatio;
|
||||
},
|
||||
@ -407,16 +407,27 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
|
||||
* Audit results for the accessible object.
|
||||
*/
|
||||
async audit() {
|
||||
// More audit steps will be added here in the near future. In addition to colour
|
||||
// contrast ratio we will add autits for to the missing names, invalid states, etc.
|
||||
// (For example see bug 1518808).
|
||||
const [ contrastRatio ] = await Promise.all([
|
||||
this._getContrastRatio(),
|
||||
]);
|
||||
if (this._auditing) {
|
||||
return this._auditing;
|
||||
}
|
||||
|
||||
return this.isDefunct ? null : {
|
||||
// More audit steps will be added here in the near future. In addition to
|
||||
// colour contrast ratio we will add autits for to the missing names,
|
||||
// invalid states, etc. (For example see bug 1518808).
|
||||
this._auditing = Promise.all([
|
||||
this._getContrastRatio(),
|
||||
]).then(([
|
||||
contrastRatio,
|
||||
};
|
||||
]) => {
|
||||
const audit = this.isDefunct ? null : {
|
||||
contrastRatio,
|
||||
};
|
||||
|
||||
this._auditing = null;
|
||||
return audit;
|
||||
});
|
||||
|
||||
return this._auditing;
|
||||
},
|
||||
|
||||
snapshot() {
|
||||
|
@ -477,12 +477,14 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Load accessibility highlighter style sheet used for preventing transitions and
|
||||
* applying transparency when calculating colour contrast.
|
||||
* Ensure that nothing interferes with the audit for an accessible object
|
||||
* (CSS, overlays) by load accessibility highlighter style sheet used for
|
||||
* preventing transitions and applying transparency when calculating colour
|
||||
* contrast as well as temporarily hiding accessible highlighter overlay.
|
||||
* @param {Object} win
|
||||
* Window where highlighting happens.
|
||||
*/
|
||||
loadTransitionDisablingStyleSheet(win) {
|
||||
clearStyles(win) {
|
||||
if (this._sheetLoaded) {
|
||||
return;
|
||||
}
|
||||
@ -493,23 +495,45 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
|
||||
// taking a snapshot for contrast measurement).
|
||||
loadSheet(win, HIGHLIGHTER_STYLES_SHEET);
|
||||
this._sheetLoaded = true;
|
||||
this.hideHighlighter();
|
||||
},
|
||||
|
||||
/**
|
||||
* Unload accessibility highlighter style sheet used for preventing transitions and
|
||||
* applying transparency when calculating colour contrast.
|
||||
* Restore CSS and overlays that could've interfered with the audit for an
|
||||
* accessible object by unloading accessibility highlighter style sheet used
|
||||
* for preventing transitions and applying transparency when calculating
|
||||
* colour contrast and potentially restoring accessible highlighter overlay.
|
||||
* @param {Object} win
|
||||
* Window where highlighting was happenning.
|
||||
*/
|
||||
removeTransitionDisablingStyleSheet(win) {
|
||||
restoreStyles(win) {
|
||||
if (!this._sheetLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.showHighlighter();
|
||||
removeSheet(win, HIGHLIGHTER_STYLES_SHEET);
|
||||
this._sheetLoaded = false;
|
||||
},
|
||||
|
||||
hideHighlighter() {
|
||||
// TODO: Fix this workaround that temporarily removes higlighter bounds
|
||||
// overlay that can interfere with the contrast ratio calculation.
|
||||
if (this._highlighter) {
|
||||
const highlighter = this._highlighter.instance;
|
||||
highlighter.hideAccessibleBounds();
|
||||
}
|
||||
},
|
||||
|
||||
showHighlighter() {
|
||||
// TODO: Fix this workaround that temporarily removes higlighter bounds
|
||||
// overlay that can interfere with the contrast ratio calculation.
|
||||
if (this._highlighter) {
|
||||
const highlighter = this._highlighter.instance;
|
||||
highlighter.showAccessibleBounds();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Public method used to show an accessible object highlighter on the client
|
||||
* side.
|
||||
|
@ -509,6 +509,13 @@ exports.CustomHighlighterActor = protocol.ActorClassWithSpec(customHighlighterSp
|
||||
|
||||
release: function() {},
|
||||
|
||||
/**
|
||||
* Get current instance of the highlighter object.
|
||||
*/
|
||||
get instance() {
|
||||
return this._highlighter;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the highlighter.
|
||||
* This calls through to the highlighter instance's |show(node, options)|
|
||||
|
@ -232,18 +232,53 @@ class AccessibleHighlighter extends AutoRefreshHighlighter {
|
||||
this.highlighterEnv.window.document.documentElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API method to temporarily hide accessible bounds for things like
|
||||
* color contrast calculation.
|
||||
*/
|
||||
hideAccessibleBounds() {
|
||||
if (this.getElement("elements").hasAttribute("hidden")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._hideAccessibleBounds();
|
||||
this._shouldRestoreBoundsVisibility = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API method to show accessible bounds in case they were temporarily
|
||||
* hidden.
|
||||
*/
|
||||
showAccessibleBounds() {
|
||||
if (this._shouldRestoreBoundsVisibility) {
|
||||
this._showAccessibleBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the accessible bounds container.
|
||||
*/
|
||||
_hideAccessibleBounds() {
|
||||
this._shouldRestoreBoundsVisibility = null;
|
||||
setIgnoreLayoutChanges(true);
|
||||
this.getElement("elements").setAttribute("hidden", "true");
|
||||
setIgnoreLayoutChanges(false,
|
||||
this.highlighterEnv.window.document.documentElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the accessible bounds container.
|
||||
*/
|
||||
_showAccessibleBounds() {
|
||||
this._shouldRestoreBoundsVisibility = null;
|
||||
if (!this.currentNode || !this.highlighterEnv.window) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIgnoreLayoutChanges(true);
|
||||
this.getElement("elements").removeAttribute("hidden");
|
||||
setIgnoreLayoutChanges(false,
|
||||
this.highlighterEnv.window.document.documentElement);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,11 +337,39 @@ class XULWindowAccessibleHighlighter {
|
||||
return isNodeValid(node) || isNodeValid(node, TEXT_NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API method to temporarily hide accessible bounds for things like
|
||||
* color contrast calculation.
|
||||
*/
|
||||
hideAccessibleBounds() {
|
||||
if (this.container.hasAttribute("hidden")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._hideAccessibleBounds();
|
||||
this._shouldRestoreBoundsVisibility = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API method to show accessible bounds in case they were temporarily
|
||||
* hidden.
|
||||
*/
|
||||
showAccessibleBounds() {
|
||||
if (this._shouldRestoreBoundsVisibility) {
|
||||
this._showAccessibleBounds();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show accessible bounds highlighter.
|
||||
*/
|
||||
_showAccessibleBounds() {
|
||||
this._shouldRestoreBoundsVisibility = null;
|
||||
if (this.container) {
|
||||
if (!this.currentNode || !this.highlighterEnv.window) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.container.removeAttribute("hidden");
|
||||
}
|
||||
}
|
||||
@ -350,6 +378,7 @@ class XULWindowAccessibleHighlighter {
|
||||
* Hide accessible bounds highlighter.
|
||||
*/
|
||||
_hideAccessibleBounds() {
|
||||
this._shouldRestoreBoundsVisibility = null;
|
||||
if (this.container) {
|
||||
this.container.setAttribute("hidden", "true");
|
||||
}
|
||||
|
@ -22,7 +22,8 @@
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h" // For PropertyValuesPair etc.
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "jsapi.h" // For ForOfIterator etc.
|
||||
#include "jsapi.h" // For most JSAPI
|
||||
#include "js/ForOfIterator.h" // For JS::ForOfIterator
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsContentUtils.h" // For GetContextForContent
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/ForOfIterator.h" // JS::ForOfIterator
|
||||
#include "xpcprivate.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
||||
|
@ -12,7 +12,8 @@
|
||||
|
||||
#include "AccessCheck.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/JSON.h"
|
||||
#include "js/ForOfIterator.h" // JS::ForOfIterator
|
||||
#include "js/JSON.h" // JS_ParseJSON
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
|
@ -1134,11 +1134,18 @@ class CGHeaders(CGWrapper):
|
||||
headerSet = declareIncludes
|
||||
else:
|
||||
headerSet = bindingHeaders
|
||||
if t.nullable():
|
||||
# Need to make sure that Nullable as a dictionary
|
||||
# member works.
|
||||
headerSet.add("mozilla/dom/Nullable.h")
|
||||
unrolled = t.unroll()
|
||||
# Strip off outer layers and add headers they might (conservatively:
|
||||
# only nullable non-pointer types need Nullable.h, and only
|
||||
# sequences outside unions require ForOfIterator.h) require.
|
||||
unrolled = t
|
||||
while True:
|
||||
if unrolled.nullable():
|
||||
headerSet.add("mozilla/dom/Nullable.h")
|
||||
elif unrolled.isSequence():
|
||||
bindingHeaders.add("js/ForOfIterator.h")
|
||||
else:
|
||||
break
|
||||
unrolled = unrolled.inner
|
||||
if unrolled.isUnion():
|
||||
headerSet.add(self.getUnionDeclarationFilename(config, unrolled))
|
||||
bindingHeaders.add("mozilla/dom/UnionConversions.h")
|
||||
@ -1371,6 +1378,10 @@ def UnionTypes(unionTypes, config):
|
||||
if f.nullable():
|
||||
headers.add("mozilla/dom/Nullable.h")
|
||||
isSequence = f.isSequence()
|
||||
if isSequence:
|
||||
# Dealing with sequences requires for-of-compatible
|
||||
# iteration.
|
||||
implheaders.add("js/ForOfIterator.h")
|
||||
f = f.unroll()
|
||||
if f.isPromise():
|
||||
headers.add("mozilla/dom/Promise.h")
|
||||
@ -1471,6 +1482,10 @@ def UnionConversions(unionTypes, config):
|
||||
unionConversions[name] = CGUnionConversionStruct(t, config)
|
||||
|
||||
def addHeadersForType(f):
|
||||
if f.isSequence():
|
||||
# Sequences require JSAPI C++ for-of iteration code to fill
|
||||
# them.
|
||||
headers.add("js/ForOfIterator.h")
|
||||
f = f.unroll()
|
||||
if f.isPromise():
|
||||
headers.add("mozilla/dom/Promise.h")
|
||||
|
7
dom/cache/PrincipalVerifier.cpp
vendored
7
dom/cache/PrincipalVerifier.cpp
vendored
@ -13,7 +13,6 @@
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -118,12 +117,6 @@ void PrincipalVerifier::VerifyOnMainThread() {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> ssm = nsContentUtils::GetSecurityManager();
|
||||
if (NS_WARN_IF(!ssm)) {
|
||||
DispatchToInitiatingThread(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify if a child process uses system principal, which is not allowed
|
||||
// to prevent system principal is spoofed.
|
||||
if (NS_WARN_IF(actor && principal->IsSystemPrincipal())) {
|
||||
|
@ -606,6 +606,15 @@ dictionary WindowActorOptions {
|
||||
*/
|
||||
boolean includeChrome = false;
|
||||
|
||||
/**
|
||||
* An array of URL match patterns (as accepted by the MatchPattern
|
||||
* class in MatchPattern.webidl) which restrict which pages the actor
|
||||
* may be instantiated for. If this is defined, only documents URL which match
|
||||
* are allowed to have the given actor created for them. Other
|
||||
* documents will fail to have their actor constructed, returning nullptr.
|
||||
**/
|
||||
sequence<DOMString> matches;
|
||||
|
||||
/** This fields are used for configuring individual sides of the actor. */
|
||||
required WindowActorSidedOptions parent;
|
||||
required WindowActorChildOptions child;
|
||||
|
@ -651,7 +651,7 @@ void TextComposition::EndHandlingComposition(EditorBase* aEditorBase) {
|
||||
|
||||
#ifdef DEBUG
|
||||
RefPtr<EditorBase> editorBase = GetEditorBase();
|
||||
MOZ_ASSERT(editorBase == aEditorBase,
|
||||
MOZ_ASSERT(!editorBase || editorBase == aEditorBase,
|
||||
"Another editor handled the composition?");
|
||||
#endif // #ifdef DEBUG
|
||||
mEditorBaseWeak = nullptr;
|
||||
|
@ -1168,7 +1168,9 @@ void ContentChild::LaunchRDDProcess() {
|
||||
nsresult rv;
|
||||
Endpoint<PRemoteDecoderManagerChild> endpoint;
|
||||
Unused << SendLaunchRDDProcess(&rv, &endpoint);
|
||||
if (rv == NS_OK) {
|
||||
// Only call InitForContent if we got a valid enpoint back which
|
||||
// indicates we needed to launch an RDD process.
|
||||
if (rv == NS_OK && endpoint.IsValid()) {
|
||||
RemoteDecoderManagerChild::InitForContent(std::move(endpoint));
|
||||
}
|
||||
}));
|
||||
|
@ -1064,6 +1064,14 @@ mozilla::ipc::IPCResult ContentParent::RecvLaunchRDDProcess(
|
||||
Preferences::GetBool("media.rdd-process.enabled", false)) {
|
||||
RDDProcessManager* rdd = RDDProcessManager::Get();
|
||||
if (rdd) {
|
||||
// If there is already an RDDChild, then we've already launched the
|
||||
// RDD process. We don't need to do anything else. Specifically,
|
||||
// we want to avoid calling CreateContentBridge again because that
|
||||
// causes the RemoteDecoderManagerParent to rebuild needlessly.
|
||||
if (rdd->GetRDDChild()) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
rdd->LaunchRDDProcess();
|
||||
|
||||
bool rddOpened = rdd->CreateContentBridge(OtherPid(), aEndpoint);
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozJSComponentLoader.h"
|
||||
#include "mozilla/extensions/WebExtensionContentScript.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -119,9 +121,6 @@ class JSWindowActorProtocol final : public nsIObserver,
|
||||
nsTArray<nsCString> mObservers;
|
||||
};
|
||||
|
||||
const nsAString& Name() const { return mName; }
|
||||
bool AllFrames() const { return mAllFrames; }
|
||||
bool IncludeChrome() const { return mIncludeChrome; }
|
||||
const ParentSide& Parent() const { return mParent; }
|
||||
const ChildSide& Child() const { return mChild; }
|
||||
|
||||
@ -129,17 +128,22 @@ class JSWindowActorProtocol final : public nsIObserver,
|
||||
void UnregisterListenersFor(EventTarget* aRoot);
|
||||
void AddObservers();
|
||||
void RemoveObservers();
|
||||
bool Matches(BrowsingContext* aBrowsingContext, nsIURI* aURI);
|
||||
|
||||
private:
|
||||
explicit JSWindowActorProtocol(const nsAString& aName) : mName(aName) {}
|
||||
|
||||
extensions::MatchPatternSet* GetURIMatcher();
|
||||
~JSWindowActorProtocol() = default;
|
||||
|
||||
nsString mName;
|
||||
bool mAllFrames = false;
|
||||
bool mIncludeChrome = false;
|
||||
nsTArray<nsString> mMatches;
|
||||
|
||||
ParentSide mParent;
|
||||
ChildSide mChild;
|
||||
|
||||
RefPtr<extensions::MatchPatternSet> mURIMatcher;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(JSWindowActorProtocol, nsIObserver, nsIDOMEventListener);
|
||||
@ -153,6 +157,7 @@ JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
|
||||
// irrelevant and not propagated.
|
||||
proto->mIncludeChrome = false;
|
||||
proto->mAllFrames = aInfo.allFrames();
|
||||
proto->mMatches = aInfo.matches();
|
||||
proto->mChild.mModuleURI.Assign(aInfo.url());
|
||||
|
||||
proto->mChild.mEvents.SetCapacity(aInfo.events().Length());
|
||||
@ -177,6 +182,7 @@ JSWindowActorInfo JSWindowActorProtocol::ToIPC() {
|
||||
JSWindowActorInfo info;
|
||||
info.name() = mName;
|
||||
info.allFrames() = mAllFrames;
|
||||
info.matches() = mMatches;
|
||||
info.url() = mChild.mModuleURI;
|
||||
|
||||
info.events().SetCapacity(mChild.mEvents.Length());
|
||||
@ -205,6 +211,11 @@ JSWindowActorProtocol::FromWebIDLOptions(const nsAString& aName,
|
||||
proto->mAllFrames = aOptions.mAllFrames;
|
||||
proto->mIncludeChrome = aOptions.mIncludeChrome;
|
||||
|
||||
if (aOptions.mMatches.WasPassed()) {
|
||||
MOZ_ASSERT(aOptions.mMatches.Value().Length());
|
||||
proto->mMatches = aOptions.mMatches.Value();
|
||||
}
|
||||
|
||||
proto->mParent.mModuleURI = aOptions.mParent.mModuleURI;
|
||||
proto->mChild.mModuleURI = aOptions.mChild.mModuleURI;
|
||||
|
||||
@ -302,7 +313,13 @@ NS_IMETHODIMP JSWindowActorProtocol::Observe(nsISupports* aSubject,
|
||||
ErrorResult error;
|
||||
RefPtr<JSWindowActorChild> actor = wgc->GetActor(mName, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
nsresult rv = error.StealNSResult();
|
||||
|
||||
// Don't raise an error if creation of our actor was vetoed.
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
return NS_OK;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Get the wrapper for our actor. If we don't have a wrapper, the target
|
||||
@ -382,6 +399,52 @@ void JSWindowActorProtocol::RemoveObservers() {
|
||||
}
|
||||
}
|
||||
|
||||
extensions::MatchPatternSet* JSWindowActorProtocol::GetURIMatcher() {
|
||||
// If we've already created the pattern set, return it.
|
||||
if (mURIMatcher || mMatches.IsEmpty()) {
|
||||
return mURIMatcher;
|
||||
}
|
||||
|
||||
// Constructing the MatchPatternSet requires a JS environment to be run in.
|
||||
// We can construct it here in the JSM scope, as we will be keeping it around.
|
||||
AutoJSAPI jsapi;
|
||||
MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
|
||||
GlobalObject global(jsapi.cx(), xpc::PrivilegedJunkScope());
|
||||
|
||||
nsTArray<OwningStringOrMatchPattern> patterns;
|
||||
patterns.SetCapacity(mMatches.Length());
|
||||
for (nsString& s : mMatches) {
|
||||
auto* entry = patterns.AppendElement();
|
||||
entry->SetAsString() = s;
|
||||
}
|
||||
|
||||
MatchPatternOptions matchPatternOptions;
|
||||
// Make MatchPattern's mSchemes create properly.
|
||||
matchPatternOptions.mRestrictSchemes = false;
|
||||
mURIMatcher = extensions::MatchPatternSet::Constructor(
|
||||
global, patterns, matchPatternOptions, IgnoreErrors());
|
||||
return mURIMatcher;
|
||||
}
|
||||
|
||||
bool JSWindowActorProtocol::Matches(BrowsingContext* aBrowsingContext,
|
||||
nsIURI* aURI) {
|
||||
if (!mAllFrames && aBrowsingContext->GetParent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mIncludeChrome && !aBrowsingContext->IsContent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extensions::MatchPatternSet* uriMatcher = GetURIMatcher()) {
|
||||
if (!uriMatcher->Matches(aURI)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSWindowActorService::JSWindowActorService() { MOZ_ASSERT(NS_IsMainThread()); }
|
||||
|
||||
JSWindowActorService::~JSWindowActorService() { MOZ_ASSERT(NS_IsMainThread()); }
|
||||
@ -489,13 +552,12 @@ void JSWindowActorService::GetJSWindowActorInfos(
|
||||
}
|
||||
}
|
||||
|
||||
void JSWindowActorService::ConstructActor(const nsAString& aName,
|
||||
bool aParentSide,
|
||||
BrowsingContext* aBrowsingContext,
|
||||
JS::MutableHandleObject aActor,
|
||||
ErrorResult& aRv) {
|
||||
void JSWindowActorService::ConstructActor(
|
||||
const nsAString& aName, bool aParentSide, BrowsingContext* aBrowsingContext,
|
||||
nsIURI* aURI, JS::MutableHandleObject aActor, ErrorResult& aRv) {
|
||||
MOZ_ASSERT_IF(aParentSide, XRE_IsParentProcess());
|
||||
|
||||
MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");
|
||||
MOZ_ASSERT(aURI, "Must have URI!");
|
||||
// Constructing an actor requires a running script, so push an AutoEntryScript
|
||||
// onto the stack.
|
||||
AutoEntryScript aes(xpc::PrivilegedJunkScope(), "JSWindowActor construction");
|
||||
@ -515,14 +577,9 @@ void JSWindowActorService::ConstructActor(const nsAString& aName,
|
||||
side = &proto->Child();
|
||||
}
|
||||
|
||||
// Check if our current BrowsingContext matches the requirements for this
|
||||
// actor to load.
|
||||
if (!proto->AllFrames() && aBrowsingContext->GetParent()) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!proto->IncludeChrome() && !aBrowsingContext->IsContent()) {
|
||||
// Check if our current BrowsingContext and URI matches the requirements for
|
||||
// this actor to load.
|
||||
if (!proto->Matches(aBrowsingContext, aURI)) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ class JSWindowActorService final {
|
||||
// This method will not initialize the actor or set its manager,
|
||||
// which is handled by callers.
|
||||
void ConstructActor(const nsAString& aName, bool aParentSide,
|
||||
BrowsingContext* aBrowsingContext,
|
||||
BrowsingContext* aBrowsingContext, nsIURI* aURI,
|
||||
JS::MutableHandleObject aActor, ErrorResult& aRv);
|
||||
|
||||
void ReceiveMessage(nsISupports* aActor, JS::RootedObject& aObj,
|
||||
|
@ -242,6 +242,7 @@ struct JSWindowActorInfo
|
||||
|
||||
JSWindowActorEventDecl[] events;
|
||||
nsCString[] observers;
|
||||
nsString[] matches;
|
||||
};
|
||||
|
||||
struct GMPAPITags
|
||||
|
@ -70,6 +70,8 @@ already_AddRefed<WindowGlobalChild> WindowGlobalChild::Create(
|
||||
MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowGlobalChild entry for ID!");
|
||||
entry.OrInsert([&] { return wgc; });
|
||||
|
||||
// Send down our initial document URI.
|
||||
wgc->SendUpdateDocumentURI(aWindow->GetDocumentURI());
|
||||
return wgc.forget();
|
||||
}
|
||||
|
||||
@ -167,7 +169,7 @@ already_AddRefed<JSWindowActorChild> WindowGlobalChild::GetActor(
|
||||
|
||||
JS::RootedObject obj(RootingCx());
|
||||
actorSvc->ConstructActor(aName, /* aChildSide */ false, mBrowsingContext,
|
||||
&obj, aRv);
|
||||
mWindowGlobal->GetDocumentURI(), &obj, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ already_AddRefed<JSWindowActorParent> WindowGlobalParent::GetActor(
|
||||
|
||||
JS::RootedObject obj(RootingCx());
|
||||
actorSvc->ConstructActor(aName, /* aParentSide */ true, mBrowsingContext,
|
||||
&obj, aRv);
|
||||
mDocumentURI, &obj, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
"use strict";
|
||||
|
||||
const URL = "about:blank";
|
||||
const TEST_URL = "http://test2.example.org/";
|
||||
let windowActorOptions = {
|
||||
parent: {
|
||||
moduleURI: "resource://testing-common/TestParent.jsm",
|
||||
@ -20,6 +21,12 @@ let windowActorOptions = {
|
||||
},
|
||||
};
|
||||
|
||||
function teardown() {
|
||||
windowActorOptions.allFrames = false;
|
||||
delete windowActorOptions.matches;
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
}
|
||||
|
||||
add_task(function test_registerWindowActor() {
|
||||
ok(ChromeUtils, "Should be able to get the ChromeUtils interface");
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
@ -52,63 +59,6 @@ add_task(async function test_getActor() {
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_without_allFrames() {
|
||||
windowActorOptions.allFrames = false;
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
await ContentTask.spawn(
|
||||
browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if allFrames is false.");
|
||||
});
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_allFrames() {
|
||||
windowActorOptions.allFrames = true;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
await ContentTask.spawn(
|
||||
browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
});
|
||||
});
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_without_includeChrome() {
|
||||
windowActorOptions.includeChrome = false;
|
||||
let parent = window.docShell.browsingContext.currentWindowGlobal;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
SimpleTest.doesThrow(() =>
|
||||
parent.getActor("Test"),
|
||||
"Should throw if includeChrome is false.");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_includeChrome() {
|
||||
windowActorOptions.includeChrome = true;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
let parent = window.docShell.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function test_asyncMessage() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
@ -257,3 +207,150 @@ add_task(async function test_observers_dont_notify_with_wrong_window() {
|
||||
});
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_mismatch() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
windowActorOptions.matches = ["*://*/*"];
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent, "WindowGlobalParent should have value.");
|
||||
Assert.throws(() => parent.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
});
|
||||
teardown();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_matches() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: TEST_URL},
|
||||
async function(browser) {
|
||||
windowActorOptions.matches = ["*://*/*"];
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent.getActor("Test"), "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
|
||||
teardown();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_iframe_matches() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
windowActorOptions.allFrames = true;
|
||||
windowActorOptions.matches = ["*://*/*"];
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, TEST_URL, async function(url) {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
teardown();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_iframe_mismatch() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
windowActorOptions.allFrames = true;
|
||||
windowActorOptions.matches = ["about:home"];
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, TEST_URL, async function(url) {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
});
|
||||
teardown();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_without_allFrames() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
windowActorOptions.allFrames = false;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if allFrames is false.");
|
||||
});
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_allFrames() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
|
||||
async function(browser) {
|
||||
windowActorOptions.allFrames = true;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
});
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_without_includeChrome() {
|
||||
windowActorOptions.includeChrome = false;
|
||||
let parent = window.docShell.browsingContext.currentWindowGlobal;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
SimpleTest.doesThrow(() =>
|
||||
parent.getActor("Test"),
|
||||
"Should throw if includeChrome is false.");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function test_getActor_with_includeChrome() {
|
||||
windowActorOptions.includeChrome = true;
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
let parent = window.docShell.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
@ -32,7 +32,7 @@ function nativeVerticalWheelEventMsg() {
|
||||
case "mac": return 0; // value is unused, can be anything
|
||||
case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
|
||||
}
|
||||
throw "Native wheel events not supported on platform " + getPlatform();
|
||||
throw new Error("Native wheel events not supported on platform " + getPlatform());
|
||||
}
|
||||
|
||||
function nativeHorizontalWheelEventMsg() {
|
||||
@ -41,7 +41,7 @@ function nativeHorizontalWheelEventMsg() {
|
||||
case "mac": return 0; // value is unused, can be anything
|
||||
case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
|
||||
}
|
||||
throw "Native wheel events not supported on platform " + getPlatform();
|
||||
throw new Error("Native wheel events not supported on platform " + getPlatform());
|
||||
}
|
||||
|
||||
// Given an event target which may be a window or an element, get the associated window.
|
||||
@ -81,7 +81,7 @@ function nativeMouseDownEventMsg() {
|
||||
case "linux": return 4; // GDK_BUTTON_PRESS
|
||||
case "android": return 5; // ACTION_POINTER_DOWN
|
||||
}
|
||||
throw "Native mouse-down events not supported on platform " + getPlatform();
|
||||
throw new Error("Native mouse-down events not supported on platform " + getPlatform());
|
||||
}
|
||||
|
||||
function nativeMouseMoveEventMsg() {
|
||||
@ -91,7 +91,7 @@ function nativeMouseMoveEventMsg() {
|
||||
case "linux": return 3; // GDK_MOTION_NOTIFY
|
||||
case "android": return 7; // ACTION_HOVER_MOVE
|
||||
}
|
||||
throw "Native mouse-move events not supported on platform " + getPlatform();
|
||||
throw new Error("Native mouse-move events not supported on platform " + getPlatform());
|
||||
}
|
||||
|
||||
function nativeMouseUpEventMsg() {
|
||||
@ -101,7 +101,7 @@ function nativeMouseUpEventMsg() {
|
||||
case "linux": return 7; // GDK_BUTTON_RELEASE
|
||||
case "android": return 6; // ACTION_POINTER_UP
|
||||
}
|
||||
throw "Native mouse-up events not supported on platform " + getPlatform();
|
||||
throw new Error("Native mouse-up events not supported on platform " + getPlatform());
|
||||
}
|
||||
|
||||
function getBoundingClientRectRelativeToVisualViewport(aElement) {
|
||||
@ -164,7 +164,7 @@ function rectRelativeToScreen(aElement) {
|
||||
function synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver) {
|
||||
var pt = coordinatesRelativeToScreen(aX, aY, aTarget);
|
||||
if (aDeltaX && aDeltaY) {
|
||||
throw "Simultaneous wheeling of horizontal and vertical is not supported on all platforms.";
|
||||
throw new Error("Simultaneous wheeling of horizontal and vertical is not supported on all platforms.");
|
||||
}
|
||||
aDeltaX = nativeScrollUnits(aTarget, aDeltaX);
|
||||
aDeltaY = nativeScrollUnits(aTarget, aDeltaY);
|
||||
@ -277,7 +277,10 @@ function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null,
|
||||
continue;
|
||||
}
|
||||
if (aPositions[i].length != aTouchIds.length) {
|
||||
throw "aPositions[" + i + "] did not have the expected number of positions; expected " + aTouchIds.length + " touch points but found " + aPositions[i].length;
|
||||
throw new Error(
|
||||
`aPositions[${i}] did not have the expected number of positions; ` +
|
||||
`expected ${aTouchIds.length} touch points but found ${aPositions[i].length}`
|
||||
);
|
||||
}
|
||||
for (let j = 0; j < aTouchIds.length; j++) {
|
||||
if (aPositions[i][j] != null) {
|
||||
@ -286,7 +289,7 @@ function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null,
|
||||
}
|
||||
}
|
||||
if (lastNonNullValue < 0) {
|
||||
throw "All values in positions array were null!";
|
||||
throw new Error("All values in positions array were null!");
|
||||
}
|
||||
|
||||
// Insert a row of nulls at the end of aPositions, to ensure that all
|
||||
|
@ -162,7 +162,7 @@ function promiseApzRepaintsFlushed(aWindow = window) {
|
||||
|
||||
function flushApzRepaints(aCallback, aWindow = window) {
|
||||
if (!aCallback) {
|
||||
throw "A callback must be provided!";
|
||||
throw new Error("A callback must be provided!");
|
||||
}
|
||||
promiseApzRepaintsFlushed(aWindow).then(aCallback);
|
||||
}
|
||||
|
@ -24,3 +24,4 @@ use Mozilla's I18n APIs.
|
||||
locale
|
||||
dataintl
|
||||
localization
|
||||
l10n/l10n/index
|
||||
|
118
js/public/ForOfIterator.h
Normal file
118
js/public/ForOfIterator.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* 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/. */
|
||||
|
||||
/*
|
||||
* A convenience class that makes it easy to perform the operations of a for-of
|
||||
* loop.
|
||||
*/
|
||||
|
||||
#ifndef js_ForOfIterator_h
|
||||
#define js_ForOfIterator_h
|
||||
|
||||
#include "mozilla/Attributes.h" // MOZ_MUST_USE, MOZ_STACK_CLASS
|
||||
|
||||
#include <stdint.h> // UINT32_MAX, uint32_t
|
||||
|
||||
#include "jstypes.h" // JS_PUBLIC_API
|
||||
|
||||
#include "js/RootingAPI.h" // JS::{Handle,Rooted}
|
||||
#include "js/Value.h" // JS::Value, JS::{,Mutable}Handle<JS::Value>
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
namespace JS {
|
||||
|
||||
/**
|
||||
* A convenience class for imitating a JS for-of loop. Typical usage:
|
||||
*
|
||||
* JS::ForOfIterator it(cx);
|
||||
* if (!it.init(iterable)) {
|
||||
* return false;
|
||||
* }
|
||||
* JS::Rooted<JS::Value> val(cx);
|
||||
* while (true) {
|
||||
* bool done;
|
||||
* if (!it.next(&val, &done)) {
|
||||
* return false;
|
||||
* }
|
||||
* if (done) {
|
||||
* break;
|
||||
* }
|
||||
* if (!DoStuff(cx, val)) {
|
||||
* return false;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator {
|
||||
protected:
|
||||
JSContext* cx_;
|
||||
|
||||
// Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try to
|
||||
// optimize iteration across arrays.
|
||||
//
|
||||
// Case 1: Regular Iteration
|
||||
// iterator - pointer to the iterator object.
|
||||
// nextMethod - value of |iterator|.next.
|
||||
// index - fixed to NOT_ARRAY (== UINT32_MAX)
|
||||
//
|
||||
// Case 2: Optimized Array Iteration
|
||||
// iterator - pointer to the array object.
|
||||
// nextMethod - the undefined value.
|
||||
// index - current position in array.
|
||||
//
|
||||
// The cases are distinguished by whether |index == NOT_ARRAY|.
|
||||
Rooted<JSObject*> iterator;
|
||||
Rooted<Value> nextMethod;
|
||||
|
||||
static constexpr uint32_t NOT_ARRAY = UINT32_MAX;
|
||||
|
||||
uint32_t index = NOT_ARRAY;
|
||||
|
||||
ForOfIterator(const ForOfIterator&) = delete;
|
||||
ForOfIterator& operator=(const ForOfIterator&) = delete;
|
||||
|
||||
public:
|
||||
explicit ForOfIterator(JSContext* cx)
|
||||
: cx_(cx), iterator(cx), nextMethod(cx) {}
|
||||
|
||||
enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable };
|
||||
|
||||
/**
|
||||
* Initialize the iterator. If AllowNonIterable is passed then if getting
|
||||
* the @@iterator property from iterable returns undefined init() will just
|
||||
* return true instead of throwing. Callers must then check
|
||||
* valueIsIterable() before continuing with the iteration.
|
||||
*/
|
||||
MOZ_MUST_USE bool init(
|
||||
Handle<Value> iterable,
|
||||
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
|
||||
|
||||
/**
|
||||
* Get the next value from the iterator. If false *done is true
|
||||
* after this call, do not examine val.
|
||||
*/
|
||||
MOZ_MUST_USE bool next(MutableHandle<Value> val, bool* done);
|
||||
|
||||
/**
|
||||
* Close the iterator.
|
||||
* For the case that completion type is throw.
|
||||
*/
|
||||
void closeThrow();
|
||||
|
||||
/**
|
||||
* If initialized with throwOnNonCallable = false, check whether
|
||||
* the value is iterable.
|
||||
*/
|
||||
bool valueIsIterable() const { return iterator; }
|
||||
|
||||
private:
|
||||
inline bool nextFromOptimizedArray(MutableHandle<Value> val, bool* done);
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif // js_ForOfIterator_h
|
@ -19,6 +19,7 @@ typedef uint32_t HashNumber;
|
||||
#include "js/ContextOptions.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/Date.h"
|
||||
#include "js/ForOfIterator.h"
|
||||
#include "js/Initialization.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/PropertySpec.h"
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "gc/Heap.h"
|
||||
#include "js/Debug.h"
|
||||
#include "js/ForOfIterator.h" // JS::ForOfIterator
|
||||
#include "js/PropertySpec.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
|
@ -693,21 +693,6 @@ struct GlobalAccess {
|
||||
|
||||
typedef Vector<GlobalAccess, 0, SystemAllocPolicy> GlobalAccessVector;
|
||||
|
||||
// A CallFarJump records the offset of a jump that needs to be patched to a
|
||||
// call at the end of the module when all calls have been emitted.
|
||||
|
||||
struct CallFarJump {
|
||||
uint32_t funcIndex;
|
||||
jit::CodeOffset jump;
|
||||
|
||||
CallFarJump(uint32_t funcIndex, jit::CodeOffset jump)
|
||||
: funcIndex(funcIndex), jump(jump) {}
|
||||
|
||||
void offsetBy(size_t delta) { jump.offsetBy(delta); }
|
||||
};
|
||||
|
||||
typedef Vector<CallFarJump, 0, SystemAllocPolicy> CallFarJumpVector;
|
||||
|
||||
} // namespace wasm
|
||||
|
||||
namespace jit {
|
||||
@ -717,7 +702,6 @@ class AssemblerShared {
|
||||
wasm::CallSiteVector callSites_;
|
||||
wasm::CallSiteTargetVector callSiteTargets_;
|
||||
wasm::TrapSiteVectorArray trapSites_;
|
||||
wasm::CallFarJumpVector callFarJumps_;
|
||||
wasm::SymbolicAccessVector symbolicAccesses_;
|
||||
|
||||
protected:
|
||||
@ -756,9 +740,6 @@ class AssemblerShared {
|
||||
void append(wasm::Trap trap, wasm::TrapSite site) {
|
||||
enoughMemory_ &= trapSites_[trap].append(site);
|
||||
}
|
||||
void append(wasm::CallFarJump jmp) {
|
||||
enoughMemory_ &= callFarJumps_.append(jmp);
|
||||
}
|
||||
void append(const wasm::MemoryAccessDesc& access, uint32_t pcOffset) {
|
||||
appendOutOfBoundsTrap(access.trapOffset(), pcOffset);
|
||||
}
|
||||
@ -773,7 +754,6 @@ class AssemblerShared {
|
||||
wasm::CallSiteVector& callSites() { return callSites_; }
|
||||
wasm::CallSiteTargetVector& callSiteTargets() { return callSiteTargets_; }
|
||||
wasm::TrapSiteVectorArray& trapSites() { return trapSites_; }
|
||||
wasm::CallFarJumpVector& callFarJumps() { return callFarJumps_; }
|
||||
wasm::SymbolicAccessVector& symbolicAccesses() { return symbolicAccesses_; }
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "js/ForOfIterator.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
BEGIN_TEST(testForOfIterator_basicNonIterable) {
|
||||
|
@ -3165,93 +3165,6 @@ extern JS_PUBLIC_API RefPtr<WasmModule> GetWasmModule(HandleObject obj);
|
||||
extern JS_PUBLIC_API RefPtr<WasmModule> DeserializeWasmModule(
|
||||
PRFileDesc* bytecode, JS::UniqueChars filename, unsigned line);
|
||||
|
||||
/**
|
||||
* Convenience class for imitating a JS level for-of loop. Typical usage:
|
||||
*
|
||||
* ForOfIterator it(cx);
|
||||
* if (!it.init(iterable)) {
|
||||
* return false;
|
||||
* }
|
||||
* RootedValue val(cx);
|
||||
* while (true) {
|
||||
* bool done;
|
||||
* if (!it.next(&val, &done)) {
|
||||
* return false;
|
||||
* }
|
||||
* if (done) {
|
||||
* break;
|
||||
* }
|
||||
* if (!DoStuff(cx, val)) {
|
||||
* return false;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator {
|
||||
protected:
|
||||
JSContext* cx_;
|
||||
/*
|
||||
* Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try
|
||||
* to optimize iteration across arrays.
|
||||
*
|
||||
* Case 1: Regular Iteration
|
||||
* iterator - pointer to the iterator object.
|
||||
* nextMethod - value of |iterator|.next.
|
||||
* index - fixed to NOT_ARRAY (== UINT32_MAX)
|
||||
*
|
||||
* Case 2: Optimized Array Iteration
|
||||
* iterator - pointer to the array object.
|
||||
* nextMethod - the undefined value.
|
||||
* index - current position in array.
|
||||
*
|
||||
* The cases are distinguished by whether or not |index| is equal to
|
||||
* NOT_ARRAY.
|
||||
*/
|
||||
JS::RootedObject iterator;
|
||||
JS::RootedValue nextMethod;
|
||||
uint32_t index;
|
||||
|
||||
static const uint32_t NOT_ARRAY = UINT32_MAX;
|
||||
|
||||
ForOfIterator(const ForOfIterator&) = delete;
|
||||
ForOfIterator& operator=(const ForOfIterator&) = delete;
|
||||
|
||||
public:
|
||||
explicit ForOfIterator(JSContext* cx)
|
||||
: cx_(cx), iterator(cx_), nextMethod(cx), index(NOT_ARRAY) {}
|
||||
|
||||
enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable };
|
||||
|
||||
/**
|
||||
* Initialize the iterator. If AllowNonIterable is passed then if getting
|
||||
* the @@iterator property from iterable returns undefined init() will just
|
||||
* return true instead of throwing. Callers must then check
|
||||
* valueIsIterable() before continuing with the iteration.
|
||||
*/
|
||||
bool init(JS::HandleValue iterable,
|
||||
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
|
||||
|
||||
/**
|
||||
* Get the next value from the iterator. If false *done is true
|
||||
* after this call, do not examine val.
|
||||
*/
|
||||
bool next(JS::MutableHandleValue val, bool* done);
|
||||
|
||||
/**
|
||||
* Close the iterator.
|
||||
* For the case that completion type is throw.
|
||||
*/
|
||||
void closeThrow();
|
||||
|
||||
/**
|
||||
* If initialized with throwOnNonCallable = false, check whether
|
||||
* the value is iterable.
|
||||
*/
|
||||
bool valueIsIterable() const { return iterator; }
|
||||
|
||||
private:
|
||||
inline bool nextFromOptimizedArray(MutableHandleValue val, bool* done);
|
||||
};
|
||||
|
||||
/**
|
||||
* If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS
|
||||
* engine may call the large-allocation-failure callback, if set, to allow the
|
||||
|
@ -131,6 +131,7 @@ EXPORTS.js += [
|
||||
'../public/Debug.h',
|
||||
'../public/Equality.h',
|
||||
'../public/ErrorReport.h',
|
||||
'../public/ForOfIterator.h',
|
||||
'../public/GCAnnotations.h',
|
||||
'../public/GCAPI.h',
|
||||
'../public/GCHashTable.h',
|
||||
|
@ -4,8 +4,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "js/ForOfIterator.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSObject.h"
|
||||
|
@ -1149,9 +1149,7 @@ bool wasm::EnsureBuiltinThunksInitialized() {
|
||||
|
||||
MOZ_ASSERT(masm.callSites().empty());
|
||||
MOZ_ASSERT(masm.callSiteTargets().empty());
|
||||
MOZ_ASSERT(masm.callFarJumps().empty());
|
||||
MOZ_ASSERT(masm.trapSites().empty());
|
||||
MOZ_ASSERT(masm.callFarJumps().empty());
|
||||
|
||||
ExecutableAllocator::cacheFlush(thunks->codeBase, thunks->codeSize);
|
||||
if (!ExecutableAllocator::makeExecutable(thunks->codeBase,
|
||||
|
@ -685,9 +685,7 @@ bool LazyStubTier::createMany(const Uint32Vector& funcExportIndices,
|
||||
|
||||
MOZ_ASSERT(masm.callSites().empty());
|
||||
MOZ_ASSERT(masm.callSiteTargets().empty());
|
||||
MOZ_ASSERT(masm.callFarJumps().empty());
|
||||
MOZ_ASSERT(masm.trapSites().empty());
|
||||
MOZ_ASSERT(masm.callFarJumps().empty());
|
||||
|
||||
if (masm.oom()) {
|
||||
return false;
|
||||
|
@ -52,7 +52,6 @@ bool CompiledCode::swap(MacroAssembler& masm) {
|
||||
callSites.swap(masm.callSites());
|
||||
callSiteTargets.swap(masm.callSiteTargets());
|
||||
trapSites.swap(masm.trapSites());
|
||||
callFarJumps.swap(masm.callFarJumps());
|
||||
symbolicAccesses.swap(masm.symbolicAccesses());
|
||||
codeLabels.swap(masm.codeLabels());
|
||||
return true;
|
||||
@ -668,13 +667,6 @@ bool ModuleGenerator::linkCompiledCode(CompiledCode& code) {
|
||||
}
|
||||
}
|
||||
|
||||
auto callFarJumpOp = [=](uint32_t, CallFarJump* cfj) {
|
||||
cfj->offsetBy(offsetInModule);
|
||||
};
|
||||
if (!AppendForEach(&callFarJumps_, code.callFarJumps, callFarJumpOp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const SymbolicAccess& access : code.symbolicAccesses) {
|
||||
uint32_t patchAt = offsetInModule + access.patchAt.offset();
|
||||
if (!linkData_->symbolicLinks[access.target].append(patchAt)) {
|
||||
@ -923,7 +915,6 @@ bool ModuleGenerator::finishCodegen() {
|
||||
MOZ_ASSERT(masm_.callSites().empty());
|
||||
MOZ_ASSERT(masm_.callSiteTargets().empty());
|
||||
MOZ_ASSERT(masm_.trapSites().empty());
|
||||
MOZ_ASSERT(masm_.callFarJumps().empty());
|
||||
MOZ_ASSERT(masm_.symbolicAccesses().empty());
|
||||
MOZ_ASSERT(masm_.codeLabels().empty());
|
||||
|
||||
@ -1262,7 +1253,6 @@ size_t CompiledCode::sizeOfExcludingThis(
|
||||
codeRanges.sizeOfExcludingThis(mallocSizeOf) +
|
||||
callSites.sizeOfExcludingThis(mallocSizeOf) +
|
||||
callSiteTargets.sizeOfExcludingThis(mallocSizeOf) + trapSitesSize +
|
||||
callFarJumps.sizeOfExcludingThis(mallocSizeOf) +
|
||||
symbolicAccesses.sizeOfExcludingThis(mallocSizeOf) +
|
||||
codeLabels.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
@ -62,7 +62,6 @@ struct CompiledCode {
|
||||
CallSiteVector callSites;
|
||||
CallSiteTargetVector callSiteTargets;
|
||||
TrapSiteVectorArray trapSites;
|
||||
CallFarJumpVector callFarJumps;
|
||||
SymbolicAccessVector symbolicAccesses;
|
||||
jit::CodeLabelVector codeLabels;
|
||||
StackMaps stackMaps;
|
||||
@ -75,7 +74,6 @@ struct CompiledCode {
|
||||
callSites.clear();
|
||||
callSiteTargets.clear();
|
||||
trapSites.clear();
|
||||
callFarJumps.clear();
|
||||
symbolicAccesses.clear();
|
||||
codeLabels.clear();
|
||||
stackMaps.clear();
|
||||
@ -85,8 +83,7 @@ struct CompiledCode {
|
||||
bool empty() {
|
||||
return bytes.empty() && codeRanges.empty() && callSites.empty() &&
|
||||
callSiteTargets.empty() && trapSites.empty() &&
|
||||
callFarJumps.empty() && symbolicAccesses.empty() &&
|
||||
codeLabels.empty() && stackMaps.empty();
|
||||
symbolicAccesses.empty() && codeLabels.empty() && stackMaps.empty();
|
||||
}
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
@ -137,6 +134,12 @@ struct CompileTask {
|
||||
class MOZ_STACK_CLASS ModuleGenerator {
|
||||
typedef Vector<CompileTask, 0, SystemAllocPolicy> CompileTaskVector;
|
||||
typedef Vector<jit::CodeOffset, 0, SystemAllocPolicy> CodeOffsetVector;
|
||||
struct CallFarJump {
|
||||
uint32_t funcIndex;
|
||||
jit::CodeOffset jump;
|
||||
CallFarJump(uint32_t fi, jit::CodeOffset j) : funcIndex(fi), jump(j) {}
|
||||
};
|
||||
typedef Vector<CallFarJump, 0, SystemAllocPolicy> CallFarJumpVector;
|
||||
|
||||
// Constant parameters
|
||||
SharedCompileArgs const compileArgs_;
|
||||
|
@ -5528,6 +5528,26 @@ TEST_F(JsepSessionTest, AudioCallAnswererUsesActpass) {
|
||||
ASSERT_EQ(kJsepStateHaveLocalOffer, mSessionOff->GetState());
|
||||
}
|
||||
|
||||
// Verify that 'actpass' in reoffer from previous answerer doesn't result
|
||||
// in a role switch.
|
||||
TEST_F(JsepSessionTest, AudioCallPreviousAnswererUsesActpassInReoffer) {
|
||||
types.push_back(SdpMediaSection::kAudio);
|
||||
AddTracks(*mSessionOff, "audio");
|
||||
AddTracks(*mSessionAns, "audio");
|
||||
|
||||
OfferAnswer();
|
||||
|
||||
ValidateSetupAttribute(*mSessionOff, SdpSetupAttribute::kActpass);
|
||||
ValidateSetupAttribute(*mSessionAns, SdpSetupAttribute::kActive);
|
||||
|
||||
SwapOfferAnswerRoles();
|
||||
|
||||
OfferAnswer();
|
||||
|
||||
ValidateSetupAttribute(*mSessionOff, SdpSetupAttribute::kActpass);
|
||||
ValidateSetupAttribute(*mSessionAns, SdpSetupAttribute::kPassive);
|
||||
}
|
||||
|
||||
// Disabled: See Bug 1329028
|
||||
TEST_F(JsepSessionTest, DISABLED_AudioCallOffererAttemptsSetupRoleSwitch) {
|
||||
types.push_back(SdpMediaSection::kAudio);
|
||||
|
@ -546,8 +546,15 @@ nsresult JsepSessionImpl::CreateAnswerMsection(
|
||||
MOZ_ASSERT(transceiver.GetMid() == msection.GetAttributeList().GetMid());
|
||||
|
||||
SdpSetupAttribute::Role role;
|
||||
rv = DetermineAnswererSetupRole(remoteMsection, &role);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (transceiver.mTransport.mDtls && !IsIceRestarting()) {
|
||||
role = (transceiver.mTransport.mDtls->mRole ==
|
||||
JsepDtlsTransport::kJsepDtlsClient)
|
||||
? SdpSetupAttribute::kActive
|
||||
: SdpSetupAttribute::kPassive;
|
||||
} else {
|
||||
rv = DetermineAnswererSetupRole(remoteMsection, &role);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = AddTransportAttributes(&msection, role);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -1072,6 +1079,7 @@ nsresult JsepSessionImpl::FinalizeTransport(const SdpAttributeList& remote,
|
||||
if (!transport->mIce || transport->mIce->mUfrag != remote.GetIceUfrag() ||
|
||||
transport->mIce->mPwd != remote.GetIcePwd()) {
|
||||
UniquePtr<JsepIceTransport> ice = MakeUnique<JsepIceTransport>();
|
||||
transport->mDtls = nullptr;
|
||||
|
||||
// We do sanity-checking for these in ParseSdp
|
||||
ice->mUfrag = remote.GetIceUfrag();
|
||||
|
@ -48,7 +48,7 @@ LoginManagerPrompter.prototype = {
|
||||
};
|
||||
|
||||
if (!this.__strBundle)
|
||||
throw "String bundle for Login Manager not present!";
|
||||
throw new Error("String bundle for Login Manager not present!");
|
||||
}
|
||||
|
||||
return this.__strBundle;
|
||||
|
@ -109,7 +109,7 @@ NSSDialogs.prototype = {
|
||||
setPKCS12FilePassword: function(aCtx, aPassword) {
|
||||
// this dialog is never shown in Fennec; in Desktop it is shown while backing up a personal
|
||||
// certificate to a file via Preferences->Advanced->Encryption->View Certificates->Your Certificates
|
||||
throw "Unimplemented";
|
||||
throw new Error("Unimplemented");
|
||||
},
|
||||
|
||||
getPKCS12FilePassword: function(aCtx, aPassword) {
|
||||
|
@ -719,11 +719,11 @@ var PromptUtils = {
|
||||
// channel's actual destination.
|
||||
if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
|
||||
if (!(aChannel instanceof Ci.nsIProxiedChannel))
|
||||
throw "proxy auth needs nsIProxiedChannel";
|
||||
throw new Error("proxy auth needs nsIProxiedChannel");
|
||||
|
||||
let info = aChannel.proxyInfo;
|
||||
if (!info)
|
||||
throw "proxy auth needs nsIProxyInfo";
|
||||
throw new Error("proxy auth needs nsIProxyInfo");
|
||||
|
||||
// Proxies don't have a scheme, but we'll use "moz-proxy://"
|
||||
// so that it's more obvious what the login is for.
|
||||
|
@ -1422,12 +1422,12 @@ SessionStore.prototype = {
|
||||
try {
|
||||
state = JSON.parse(aData);
|
||||
} catch (e) {
|
||||
throw "Invalid session JSON: " + aData;
|
||||
throw new Error("Invalid session JSON: " + aData);
|
||||
}
|
||||
|
||||
// To do a restore, we must have at least one window with one tab
|
||||
if (!state || state.windows.length == 0 || !state.windows[0].tabs || state.windows[0].tabs.length == 0) {
|
||||
throw "Invalid session JSON: " + aData;
|
||||
throw new Error("Invalid session JSON: " + aData);
|
||||
}
|
||||
|
||||
let window = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
@ -1491,7 +1491,7 @@ SessionStore.prototype = {
|
||||
|
||||
getClosedTabs(aWindow) {
|
||||
if (!aWindow.__SSID) {
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
throw new Error(Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
return this._windows[aWindow.__SSID].closedTabs;
|
||||
@ -1499,7 +1499,7 @@ SessionStore.prototype = {
|
||||
|
||||
undoCloseTab(aWindow, aCloseTabData) {
|
||||
if (!aWindow.__SSID) {
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
throw new Error(Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
// If the tab data is in the closedTabs array, remove it.
|
||||
@ -1562,7 +1562,7 @@ SessionStore.prototype = {
|
||||
}
|
||||
|
||||
if (!aWindow.__SSID) {
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
throw new Error(Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
let closedTabs = this._windows[aWindow.__SSID].closedTabs;
|
||||
|
@ -118,9 +118,9 @@ GeckoViewPermission.prototype = {
|
||||
});
|
||||
|
||||
if (constraints.video && !sources.some(source => source.type === "videoinput")) {
|
||||
throw "no video source";
|
||||
throw new Error("no video source");
|
||||
} else if (constraints.audio && !sources.some(source => source.type === "audioinput")) {
|
||||
throw "no audio source";
|
||||
throw new Error("no audio source");
|
||||
}
|
||||
|
||||
let dispatcher = GeckoViewUtils.getDispatcherForWindow(win);
|
||||
|
@ -760,11 +760,11 @@ PromptDelegate.prototype = {
|
||||
// channel's actual destination.
|
||||
if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
|
||||
if (!(aChannel instanceof Ci.nsIProxiedChannel)) {
|
||||
throw "proxy auth needs nsIProxiedChannel";
|
||||
throw new Error("proxy auth needs nsIProxiedChannel");
|
||||
}
|
||||
let info = aChannel.proxyInfo;
|
||||
if (!info) {
|
||||
throw "proxy auth needs nsIProxyInfo";
|
||||
throw new Error("proxy auth needs nsIProxyInfo");
|
||||
}
|
||||
// Proxies don't have a scheme, but we'll use "moz-proxy://"
|
||||
// so that it's more obvious what the login is for.
|
||||
|
@ -132,7 +132,7 @@ var DownloadNotifications = {
|
||||
}
|
||||
}
|
||||
|
||||
throw "Couldn't find download for " + cookie;
|
||||
throw new Error("Couldn't find download for " + cookie);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -20,7 +20,7 @@ const DEFAULT_WEIGHT = 100;
|
||||
// See bug 915424
|
||||
function resolveGeckoURI(aURI) {
|
||||
if (!aURI)
|
||||
throw "Can't resolve an empty uri";
|
||||
throw new Error("Can't resolve an empty uri");
|
||||
|
||||
if (aURI.startsWith("chrome://")) {
|
||||
let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
|
||||
@ -168,7 +168,7 @@ var HomeBanner = (function() {
|
||||
*/
|
||||
remove: function(id) {
|
||||
if (!(id in _messages)) {
|
||||
throw "Home.banner: Can't remove message that doesn't exist: id = " + id;
|
||||
throw new Error("Home.banner: Can't remove message that doesn't exist: id = " + id);
|
||||
}
|
||||
|
||||
delete _messages[id];
|
||||
@ -220,10 +220,10 @@ var HomePanels = (function() {
|
||||
let id = data.id;
|
||||
let options = _registeredPanels[id]();
|
||||
if (!options.auth) {
|
||||
throw "Home.panels: Invalid auth for panel.id = " + id;
|
||||
throw new Error("Home.panels: Invalid auth for panel.id = " + id);
|
||||
}
|
||||
if (!options.auth.authenticate || typeof options.auth.authenticate !== "function") {
|
||||
throw "Home.panels: Invalid auth authenticate function: panel.id = " + this.id;
|
||||
throw new Error("Home.panels: Invalid auth authenticate function: panel.id = " + this.id);
|
||||
}
|
||||
options.auth.authenticate();
|
||||
},
|
||||
@ -233,13 +233,13 @@ var HomePanels = (function() {
|
||||
let view = options.views[data.viewIndex];
|
||||
|
||||
if (!view) {
|
||||
throw "Home.panels: Invalid view for panel.id = " + data.panelId
|
||||
+ ", view.index = " + data.viewIndex;
|
||||
throw new Error("Home.panels: Invalid view for panel.id = " +
|
||||
`${data.panelId}, view.index = ${data.viewIndex}`);
|
||||
}
|
||||
|
||||
if (!view.onrefresh || typeof view.onrefresh !== "function") {
|
||||
throw "Home.panels: Invalid onrefresh for panel.id = " + data.panelId
|
||||
+ ", view.index = " + data.viewIndex;
|
||||
throw new Error("Home.panels: Invalid onrefresh for panel.id = " +
|
||||
`${data.panelId}, view.index = ${data.viewIndex}`);
|
||||
}
|
||||
|
||||
view.onrefresh();
|
||||
@ -254,7 +254,7 @@ var HomePanels = (function() {
|
||||
return;
|
||||
}
|
||||
if (typeof options.oninstall !== "function") {
|
||||
throw "Home.panels: Invalid oninstall function: panel.id = " + this.id;
|
||||
throw new Error("Home.panels: Invalid oninstall function: panel.id = " + this.id);
|
||||
}
|
||||
options.oninstall();
|
||||
},
|
||||
@ -268,7 +268,7 @@ var HomePanels = (function() {
|
||||
return;
|
||||
}
|
||||
if (typeof options.onuninstall !== "function") {
|
||||
throw "Home.panels: Invalid onuninstall function: panel.id = " + this.id;
|
||||
throw new Error("Home.panels: Invalid onuninstall function: panel.id = " + this.id);
|
||||
}
|
||||
options.onuninstall();
|
||||
},
|
||||
@ -314,19 +314,21 @@ var HomePanels = (function() {
|
||||
this.default = !!options.default;
|
||||
|
||||
if (!this.id || !this.title) {
|
||||
throw "Home.panels: Can't create a home panel without an id and title!";
|
||||
throw new Error("Home.panels: Can't create a home panel without an id and title!");
|
||||
}
|
||||
|
||||
if (!this.layout) {
|
||||
// Use FRAME layout by default
|
||||
this.layout = Layout.FRAME;
|
||||
} else if (!_valueExists(Layout, this.layout)) {
|
||||
throw "Home.panels: Invalid layout for panel: panel.id = " + this.id + ", panel.layout =" + this.layout;
|
||||
throw new Error("Home.panels: Invalid layout for panel: panel.id = " +
|
||||
`${this.id}, panel.layout =${this.layout}`);
|
||||
}
|
||||
|
||||
for (let view of this.views) {
|
||||
if (!_valueExists(View, view.type)) {
|
||||
throw "Home.panels: Invalid view type: panel.id = " + this.id + ", view.type = " + view.type;
|
||||
throw new Error("Home.panels: Invalid view type: panel.id = " +
|
||||
`${this.id}, view.type = ${view.type}`);
|
||||
}
|
||||
|
||||
if (!view.itemType) {
|
||||
@ -338,18 +340,21 @@ var HomePanels = (function() {
|
||||
view.itemType = Item.IMAGE;
|
||||
}
|
||||
} else if (!_valueExists(Item, view.itemType)) {
|
||||
throw "Home.panels: Invalid item type: panel.id = " + this.id + ", view.itemType = " + view.itemType;
|
||||
throw new Error("Home.panels: Invalid item type: panel.id = " +
|
||||
`${this.id}, view.itemType = ${view.itemType}`);
|
||||
}
|
||||
|
||||
if (!view.itemHandler) {
|
||||
// Use BROWSER item handler by default
|
||||
view.itemHandler = ItemHandler.BROWSER;
|
||||
} else if (!_valueExists(ItemHandler, view.itemHandler)) {
|
||||
throw "Home.panels: Invalid item handler: panel.id = " + this.id + ", view.itemHandler = " + view.itemHandler;
|
||||
throw new Error("Home.panels: Invalid item handler: panel.id = " +
|
||||
`${this.id}, view.itemHandler = ${view.itemHandler}`);
|
||||
}
|
||||
|
||||
if (!view.dataset) {
|
||||
throw "Home.panels: No dataset provided for view: panel.id = " + this.id + ", view.type = " + view.type;
|
||||
throw new Error("Home.panels: No dataset provided for view: panel.id = " +
|
||||
`${this.id}, view.type = ${view.type}`);
|
||||
}
|
||||
|
||||
if (view.onrefresh) {
|
||||
@ -359,10 +364,10 @@ var HomePanels = (function() {
|
||||
|
||||
if (options.auth) {
|
||||
if (!options.auth.messageText) {
|
||||
throw "Home.panels: Invalid auth messageText: panel.id = " + this.id;
|
||||
throw new Error("Home.panels: Invalid auth messageText: panel.id = " + this.id);
|
||||
}
|
||||
if (!options.auth.buttonText) {
|
||||
throw "Home.panels: Invalid auth buttonText: panel.id = " + this.id;
|
||||
throw new Error("Home.panels: Invalid auth buttonText: panel.id = " + this.id);
|
||||
}
|
||||
|
||||
this.authConfig = {
|
||||
@ -398,7 +403,7 @@ var HomePanels = (function() {
|
||||
|
||||
let _assertPanelExists = function(id) {
|
||||
if (!(id in _registeredPanels)) {
|
||||
throw "Home.panels: Panel doesn't exist: id = " + id;
|
||||
throw new Error("Home.panels: Panel doesn't exist: id = " + id);
|
||||
}
|
||||
};
|
||||
|
||||
@ -411,11 +416,11 @@ var HomePanels = (function() {
|
||||
register: function(id, optionsCallback) {
|
||||
// Bail if the panel already exists
|
||||
if (id in _registeredPanels) {
|
||||
throw "Home.panels: Panel already exists: id = " + id;
|
||||
throw new Error("Home.panels: Panel already exists: id = " + id);
|
||||
}
|
||||
|
||||
if (!optionsCallback || typeof optionsCallback !== "function") {
|
||||
throw "Home.panels: Panel callback must be a function: id = " + id;
|
||||
throw new Error("Home.panels: Panel callback must be a function: id = " + id);
|
||||
}
|
||||
|
||||
_registeredPanels[id] = optionsCallback;
|
||||
|
@ -333,8 +333,8 @@ HomeStorage.prototype = {
|
||||
*/
|
||||
async save(data, options) {
|
||||
if (data && data.length > MAX_SAVE_COUNT) {
|
||||
throw "save failed for dataset = " + this.datasetId +
|
||||
": you cannot save more than " + MAX_SAVE_COUNT + " items at once";
|
||||
throw new Error(`save failed for dataset = ${this.datasetId}: ` +
|
||||
`you cannot save more than ${MAX_SAVE_COUNT} items at once`);
|
||||
}
|
||||
|
||||
let db = await getDatabaseConnection();
|
||||
|
@ -22,12 +22,12 @@ Notification.prototype = {
|
||||
if ("icon" in aOptions && aOptions.icon != null)
|
||||
this._icon = aOptions.icon;
|
||||
else
|
||||
throw "Notification icon is mandatory";
|
||||
throw new Error("Notification icon is mandatory");
|
||||
|
||||
if ("title" in aOptions && aOptions.title != null)
|
||||
this._title = aOptions.title;
|
||||
else
|
||||
throw "Notification title is mandatory";
|
||||
throw new Error("Notification title is mandatory");
|
||||
|
||||
if ("message" in aOptions && aOptions.message != null)
|
||||
this._message = aOptions.message;
|
||||
@ -39,7 +39,7 @@ Notification.prototype = {
|
||||
|
||||
if ("buttons" in aOptions && aOptions.buttons != null) {
|
||||
if (aOptions.buttons.length > 3)
|
||||
throw "Too many buttons provided. The max number is 3";
|
||||
throw new Error("Too many buttons provided. The max number is 3");
|
||||
|
||||
this._buttons = {};
|
||||
for (let i = 0; i < aOptions.buttons.length; i++) {
|
||||
@ -184,7 +184,7 @@ var Notifications = {
|
||||
update: function notif_update(aId, aOptions) {
|
||||
let notification = _notificationsMap[aId];
|
||||
if (!notification)
|
||||
throw "Unknown notification id";
|
||||
throw new Error("Unknown notification id");
|
||||
notification.fillWithOptions(aOptions);
|
||||
notification.show();
|
||||
},
|
||||
|
@ -18,7 +18,7 @@ var EXPORTED_SYMBOLS = ["PageActions"];
|
||||
// TODO: We should move this method to a common importable location
|
||||
function resolveGeckoURI(aURI) {
|
||||
if (!aURI)
|
||||
throw "Can't resolve an empty uri";
|
||||
throw new Error("Can't resolve an empty uri");
|
||||
|
||||
if (aURI.startsWith("chrome://")) {
|
||||
let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
|
||||
|
@ -61,7 +61,7 @@ function SharedPreferencesImpl(options = {}) {
|
||||
}
|
||||
|
||||
if (options.scope == null || options.scope == undefined) {
|
||||
throw "Shared Preferences must specifiy a scope.";
|
||||
throw new Error("Shared Preferences must specifiy a scope.");
|
||||
}
|
||||
|
||||
this._scope = options.scope;
|
||||
|
@ -116,7 +116,7 @@ var WebrtcUI = {
|
||||
notificationOptions.icon = "drawable:alert_mic";
|
||||
} else {
|
||||
// somethings wrong. lets throw
|
||||
throw "Couldn't find any cameras or microphones being used";
|
||||
throw new Error("Couldn't find any cameras or microphones being used");
|
||||
}
|
||||
|
||||
if (this._notificationId)
|
||||
|
@ -24,6 +24,34 @@ debugger-tests:
|
||||
files-changed:
|
||||
- 'devtools/client/debugger/new/**'
|
||||
|
||||
devtools-tests:
|
||||
description: devtools node-based tests (for instance jest)
|
||||
platform: linux64/opt
|
||||
treeherder:
|
||||
symbol: node(devtools)
|
||||
kind: test
|
||||
tier: 1
|
||||
worker-type: aws-provisioner-v1/gecko-t-linux-xlarge
|
||||
worker:
|
||||
docker-image: {in-tree: "lint"}
|
||||
max-run-time: 1800
|
||||
run:
|
||||
using: run-task
|
||||
cache-dotcache: true
|
||||
command: >
|
||||
cd /builds/worker/checkouts/gecko/ &&
|
||||
npm install &&
|
||||
cd /builds/worker/checkouts/gecko/devtools/client/aboutdebugging-new/test/jest &&
|
||||
yarn &&
|
||||
yarn test &&
|
||||
cd /builds/worker/checkouts/gecko/devtools/client/framework/test/jest &&
|
||||
yarn &&
|
||||
yarn test
|
||||
when:
|
||||
files-changed:
|
||||
- 'devtools/client/aboutdebugging-new/src/components/**'
|
||||
- 'devtools/client/framework/components/**'
|
||||
|
||||
eslint-plugin-mozilla:
|
||||
description: eslint-plugin-mozilla integration tests
|
||||
platform: linux64/opt
|
||||
|
1
testing/web-platform/meta/2dcontext/__dir__.ini
Normal file
1
testing/web-platform/meta/2dcontext/__dir__.ini
Normal file
@ -0,0 +1 @@
|
||||
leak-threshold: [default: 30000]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user