Bug 1314057 - Remove old debugger assets. r=jdescottes

This commit is contained in:
David Walsh 2018-10-22 17:19:00 -05:00
Родитель e996e1e744
Коммит 7aef56cc4e
220 изменённых файлов: 25 добавлений и 17858 удалений

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

@ -1,191 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const promise = require("promise");
const { asPaused } = require("../utils");
const { PROMISE } = require("devtools/client/shared/redux/middleware/promise");
const {
getSource, getBreakpoint, getBreakpoints, makeLocationId
} = require("../queries");
const { Task } = require("devtools/shared/task");
// Because breakpoints are just simple data structures, we still need
// a way to lookup the actual client instance to talk to the server.
// We keep an internal database of clients based off of actor ID.
const BREAKPOINT_CLIENT_STORE = new Map();
function setBreakpointClient(actor, client) {
BREAKPOINT_CLIENT_STORE.set(actor, client);
}
function getBreakpointClient(actor) {
return BREAKPOINT_CLIENT_STORE.get(actor);
}
function enableBreakpoint(location) {
// Enabling is exactly the same as adding. It will use the existing
// breakpoint that still stored.
return addBreakpoint(location);
}
function _breakpointExists(state, location) {
const currentBp = getBreakpoint(state, location);
return currentBp && !currentBp.disabled;
}
function _getOrCreateBreakpoint(state, location, condition) {
return getBreakpoint(state, location) || { location, condition };
}
function addBreakpoint(location, condition) {
return (dispatch, getState) => {
if (_breakpointExists(getState(), location)) {
return;
}
const bp = _getOrCreateBreakpoint(getState(), location, condition);
return dispatch({
type: constants.ADD_BREAKPOINT,
breakpoint: bp,
condition: condition,
[PROMISE]: Task.spawn(function* () {
const sourceClient = gThreadClient.source(
getSource(getState(), bp.location.actor)
);
const [response, bpClient] = yield sourceClient.setBreakpoint({
line: bp.location.line,
column: bp.location.column,
condition: bp.condition
});
const { isPending, actualLocation } = response;
// Save the client instance
setBreakpointClient(bpClient.actor, bpClient);
let lineOrOffset = DebuggerView.editor.isWasm ? bp.location.line :
(actualLocation ? actualLocation.line : bp.location.line) - 1;
return {
text: DebuggerView.editor.getText(lineOrOffset).trim(),
isWasm: DebuggerView.editor.isWasm,
// If the breakpoint response has an "actualLocation" attached, then
// the original requested placement for the breakpoint wasn't
// accepted.
actualLocation: isPending ? null : actualLocation,
actor: bpClient.actor
};
})
});
};
}
function disableBreakpoint(location) {
return _removeOrDisableBreakpoint(location, true);
}
function removeBreakpoint(location) {
return _removeOrDisableBreakpoint(location);
}
function _removeOrDisableBreakpoint(location, isDisabled) {
return (dispatch, getState) => {
let bp = getBreakpoint(getState(), location);
if (!bp) {
throw new Error("attempt to remove breakpoint that does not exist");
}
if (bp.loading) {
// TODO(jwl): make this wait until the breakpoint is saved if it
// is still loading
throw new Error("attempt to remove unsaved breakpoint");
}
const bpClient = getBreakpointClient(bp.actor);
const action = {
type: constants.REMOVE_BREAKPOINT,
breakpoint: bp,
disabled: isDisabled
};
// If the breakpoint is already disabled, we don't need to remove
// it from the server. We just need to dispatch an action
// simulating a successful server request to remove it, and it
// will be removed completely from the state.
if (!bp.disabled) {
return dispatch(Object.assign({}, action, {
[PROMISE]: bpClient.remove()
}));
} else {
return dispatch(Object.assign({}, action, { status: "done" }));
}
};
}
function removeAllBreakpoints() {
return (dispatch, getState) => {
const breakpoints = getBreakpoints(getState());
const activeBreakpoints = breakpoints.filter(bp => !bp.disabled);
activeBreakpoints.forEach(bp => removeBreakpoint(bp.location));
};
}
/**
* Update the condition of a breakpoint.
*
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
* @param string aClients
* The condition to set on the breakpoint
* @return object
* A promise that will be resolved with the breakpoint client
*/
function setBreakpointCondition(location, condition) {
return (dispatch, getState) => {
const bp = getBreakpoint(getState(), location);
if (!bp) {
throw new Error("Breakpoint does not exist at the specified location");
}
if (bp.loading) {
// TODO(jwl): when this function is called, make sure the action
// creator waits for the breakpoint to exist
throw new Error("breakpoint must be saved");
}
const bpClient = getBreakpointClient(bp.actor);
const action = {
type: constants.SET_BREAKPOINT_CONDITION,
breakpoint: bp,
condition: condition
};
// If it's not disabled, we need to update the condition on the
// server. Otherwise, just dispatch a non-remote action that
// updates the condition locally.
if (!bp.disabled) {
return dispatch(Object.assign({}, action, {
[PROMISE]: Task.spawn(function* () {
const newClient = yield bpClient.setCondition(gThreadClient, condition);
// Remove the old instance and save the new one
setBreakpointClient(bpClient.actor, null);
setBreakpointClient(newClient.actor, newClient);
return { actor: newClient.actor };
})
}));
} else {
return dispatch(action);
}
};
}
module.exports = {
enableBreakpoint,
addBreakpoint,
disableBreakpoint,
removeBreakpoint,
removeAllBreakpoints,
setBreakpointCondition
};

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

@ -1,118 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const { asPaused } = require("../utils");
const { reportException } = require("devtools/shared/DevToolsUtils");
const { setNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
const { Task } = require("devtools/shared/task");
const FETCH_EVENT_LISTENERS_DELAY = 200; // ms
function fetchEventListeners() {
return (dispatch, getState) => {
// Make sure we"re not sending a batch of closely repeated requests.
// This can easily happen whenever new sources are fetched.
setNamedTimeout("event-listeners-fetch", FETCH_EVENT_LISTENERS_DELAY, () => {
// In case there is still a request of listeners going on (it
// takes several RDP round trips right now), make sure we wait
// on a currently running request
if (getState().eventListeners.fetchingListeners) {
dispatch({
type: services.WAIT_UNTIL,
predicate: action => (
action.type === constants.FETCH_EVENT_LISTENERS &&
action.status === "done"
),
run: dispatch => dispatch(fetchEventListeners())
});
return;
}
dispatch({
type: constants.FETCH_EVENT_LISTENERS,
status: "begin"
});
asPaused(gThreadClient, _getListeners).then(listeners => {
// Notify that event listeners were fetched and shown in the view,
// and callback to resume the active thread if necessary.
window.emit(EVENTS.EVENT_LISTENERS_FETCHED);
dispatch({
type: constants.FETCH_EVENT_LISTENERS,
status: "done",
listeners: listeners
});
});
});
};
}
const _getListeners = Task.async(function* () {
const response = yield gThreadClient.eventListeners();
// Make sure all the listeners are sorted by the event type, since
// they"re not guaranteed to be clustered together.
response.listeners.sort((a, b) => a.type > b.type ? 1 : -1);
// Add all the listeners in the debugger view event linsteners container.
let fetchedDefinitions = new Map();
let listeners = [];
for (let listener of response.listeners) {
let definitionSite;
if (fetchedDefinitions.has(listener.function.actor)) {
definitionSite = fetchedDefinitions.get(listener.function.actor);
} else if (listener.function.class == "Function") {
definitionSite = yield _getDefinitionSite(listener.function);
if (!definitionSite) {
// We don"t know where this listener comes from so don"t show it in
// the UI as breaking on it doesn"t work (bug 942899).
continue;
}
fetchedDefinitions.set(listener.function.actor, definitionSite);
}
listener.function.url = definitionSite;
listeners.push(listener);
}
fetchedDefinitions.clear();
return listeners;
});
const _getDefinitionSite = Task.async(function* (aFunction) {
const grip = gThreadClient.pauseGrip(aFunction);
let response;
try {
response = yield grip.getDefinitionSite();
}
catch (e) {
// Don't make this error fatal, because it would break the entire events pane.
reportException("_getDefinitionSite", e);
return null;
}
return response.source.url;
});
function updateEventBreakpoints(eventNames) {
return dispatch => {
setNamedTimeout("event-breakpoints-update", 0, () => {
gThreadClient.pauseOnDOMEvents(eventNames, function () {
// Notify that event breakpoints were added/removed on the server.
window.emit(EVENTS.EVENT_BREAKPOINTS_UPDATED);
dispatch({
type: constants.UPDATE_EVENT_BREAKPOINTS,
eventNames: eventNames
});
});
});
};
}
module.exports = { updateEventBreakpoints, fetchEventListeners };

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

@ -1,10 +0,0 @@
# vim: set filetype=python:
# 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/.
DevToolsModules(
'breakpoints.js',
'event-listeners.js',
'sources.js'
)

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

@ -1,283 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const promise = require("promise");
const Services = require("Services");
const { dumpn } = require("devtools/shared/DevToolsUtils");
const { PROMISE, HISTOGRAM_ID } = require("devtools/client/shared/redux/middleware/promise");
const { getSource, getSourceText } = require("../queries");
const { Task } = require("devtools/shared/task");
const Telemetry = require("devtools/client/shared/telemetry");
const NEW_SOURCE_IGNORED_URLS = ["debugger eval code", "XStringBundle"];
const FETCH_SOURCE_RESPONSE_DELAY = 200; // ms
const telemetry = new Telemetry();
function getSourceClient(source) {
return gThreadClient.source(source);
}
/**
* Handler for the debugger client's unsolicited newSource notification.
*/
function newSource(source) {
return dispatch => {
// Ignore bogus scripts, e.g. generated from 'clientEvaluate' packets.
if (NEW_SOURCE_IGNORED_URLS.includes(source.url)) {
return;
}
// Signal that a new source has been added.
window.emit(EVENTS.NEW_SOURCE);
return dispatch({
type: constants.ADD_SOURCE,
source: source
});
};
}
function selectSource(source, opts) {
return (dispatch, getState) => {
if (!gThreadClient) {
// No connection, do nothing. This happens when the debugger is
// shut down too fast and it tries to display a default source.
return;
}
source = getSource(getState(), source.actor);
// Make sure to start a request to load the source text.
dispatch(loadSourceText(source));
dispatch({
type: constants.SELECT_SOURCE,
source: source,
opts: opts
});
};
}
function loadSources() {
return {
type: constants.LOAD_SOURCES,
[PROMISE]: Task.spawn(function* () {
const response = yield gThreadClient.getSources();
// Top-level breakpoints may pause the entire loading process
// because scripts are executed as they are loaded, so the
// engine may pause in the middle of loading all the sources.
// This is relatively harmless, as individual `newSource`
// notifications are fired for each script and they will be
// added to the UI through that.
if (!response.sources) {
dumpn(
"Error getting sources, probably because a top-level " +
"breakpoint was hit while executing them"
);
return;
}
// Ignore bogus scripts, e.g. generated from 'clientEvaluate' packets.
return response.sources.filter(source => {
return !NEW_SOURCE_IGNORED_URLS.includes(source.url);
});
})
};
}
/**
* Set the black boxed status of the given source.
*
* @param Object aSource
* The source form.
* @param bool aBlackBoxFlag
* True to black box the source, false to un-black box it.
* @returns Promise
* A promize that resolves to [aSource, isBlackBoxed] or rejects to
* [aSource, error].
*/
function blackbox(source, shouldBlackBox) {
const client = getSourceClient(source);
return {
type: constants.BLACKBOX,
source: source,
[PROMISE]: Task.spawn(function* () {
yield shouldBlackBox ? client.blackBox() : client.unblackBox();
return {
isBlackBoxed: shouldBlackBox
};
})
};
}
/**
* Toggle the pretty printing of a source's text. All subsequent calls to
* |getText| will return the pretty-toggled text. Nothing will happen for
* non-javascript files.
*
* @param Object aSource
* The source form from the RDP.
* @returns Promise
* A promise that resolves to [aSource, prettyText] or rejects to
* [aSource, error].
*/
function togglePrettyPrint(source) {
return (dispatch, getState) => {
const sourceClient = getSourceClient(source);
const wantPretty = !source.isPrettyPrinted;
return dispatch({
type: constants.TOGGLE_PRETTY_PRINT,
source: source,
[PROMISE]: Task.spawn(function* () {
let response;
// Only attempt to pretty print JavaScript sources.
const sourceText = getSourceText(getState(), source.actor);
const contentType = sourceText ? sourceText.contentType : null;
if (!SourceUtils.isJavaScript(source.url, contentType)) {
throw new Error("Can't prettify non-javascript files.");
}
if (wantPretty) {
response = yield sourceClient.prettyPrint(Prefs.editorTabSize);
}
else {
response = yield sourceClient.disablePrettyPrint();
}
// Remove the cached source AST from the Parser, to avoid getting
// wrong locations when searching for functions.
DebuggerController.Parser.clearSource(source.url);
return {
isPrettyPrinted: wantPretty,
text: response.source,
contentType: response.contentType
};
})
});
};
}
function loadSourceText(source) {
return (dispatch, getState) => {
// Fetch the source text only once.
let textInfo = getSourceText(getState(), source.actor);
if (textInfo) {
// It's already loaded or is loading
return promise.resolve(textInfo);
}
const sourceClient = getSourceClient(source);
return dispatch({
type: constants.LOAD_SOURCE_TEXT,
source: source,
[PROMISE]: Task.spawn(function* () {
let transportType = gClient.localTransport ? "_LOCAL" : "_REMOTE";
let histogramId = "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE" + transportType + "_MS";
telemetry.start(histogramId, this);
const response = yield sourceClient.source();
telemetry.finish(histogramId, this);
// Automatically pretty print if enabled and the test is
// detected to be "minified"
if (Prefs.autoPrettyPrint &&
!source.isPrettyPrinted &&
SourceUtils.isMinified(source.actor, response.source)) {
dispatch(togglePrettyPrint(source));
}
return { text: response.source,
contentType: response.contentType };
})
});
};
}
/**
* Starts fetching all the sources, silently.
*
* @param array aUrls
* The urls for the sources to fetch. If fetching a source's text
* takes too long, it will be discarded.
* @return object
* A promise that is resolved after source texts have been fetched.
*/
function getTextForSources(actors) {
return (dispatch, getState) => {
let deferred = promise.defer();
let pending = new Set(actors);
let fetched = [];
// Can't use promise.all, because if one fetch operation is rejected, then
// everything is considered rejected, thus no other subsequent source will
// be getting fetched. We don't want that. Something like Q's allSettled
// would work like a charm here.
// Try to fetch as many sources as possible.
for (let actor of actors) {
let source = getSource(getState(), actor);
dispatch(loadSourceText(source)).then(({ text, contentType }) => {
onFetch([source, text, contentType]);
}, err => {
onError(source, err);
});
}
setTimeout(onTimeout, FETCH_SOURCE_RESPONSE_DELAY);
/* Called if fetching a source takes too long. */
function onTimeout() {
pending = new Set();
maybeFinish();
}
/* Called if fetching a source finishes successfully. */
function onFetch([aSource, aText, aContentType]) {
// If fetching the source has previously timed out, discard it this time.
if (!pending.has(aSource.actor)) {
return;
}
pending.delete(aSource.actor);
fetched.push([aSource.actor, aText, aContentType]);
maybeFinish();
}
/* Called if fetching a source failed because of an error. */
function onError([aSource, aError]) {
pending.delete(aSource.actor);
maybeFinish();
}
/* Called every time something interesting happens while fetching sources. */
function maybeFinish() {
if (pending.size == 0) {
// Sort the fetched sources alphabetically by their url.
deferred.resolve(fetched.sort(([aFirst], [aSecond]) => aFirst > aSecond));
}
}
return deferred.promise;
};
}
module.exports = {
newSource,
selectSource,
loadSources,
blackbox,
togglePrettyPrint,
loadSourceText,
getTextForSources
};

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

@ -1,25 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
exports.UPDATE_EVENT_BREAKPOINTS = "UPDATE_EVENT_BREAKPOINTS";
exports.FETCH_EVENT_LISTENERS = "FETCH_EVENT_LISTENERS";
exports.TOGGLE_PRETTY_PRINT = "TOGGLE_PRETTY_PRINT";
exports.BLACKBOX = "BLACKBOX";
exports.ADD_BREAKPOINT = "ADD_BREAKPOINT";
exports.REMOVE_BREAKPOINT = "REMOVE_BREAKPOINT";
exports.ENABLE_BREAKPOINT = "ENABLE_BREAKPOINT";
exports.DISABLE_BREAKPOINT = "DISABLE_BREAKPOINT";
exports.SET_BREAKPOINT_CONDITION = "SET_BREAKPOINT_CONDITION";
exports.ADD_SOURCE = "ADD_SOURCE";
exports.LOAD_SOURCES = "LOAD_SOURCES";
exports.LOAD_SOURCE_TEXT = "LOAD_SOURCE_TEXT";
exports.SELECT_SOURCE = "SELECT_SOURCE";
exports.UNLOAD = "UNLOAD";
exports.RELOAD = "RELOAD";

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

@ -1,18 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
const constants = require("./constants");
// Fired when the page is being unloaded, for example when it's being
// navigated away from.
function unload() {
return {
type: constants.UNLOAD
};
}
module.exports = { unload };

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

@ -1,18 +0,0 @@
# vim: set filetype=python:
# 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/.
DIRS += [
'actions',
'reducers',
'tooltip',
'views',
]
DevToolsModules(
'constants.js',
'globalActions.js',
'queries.js',
'utils.js'
)

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

@ -1,70 +0,0 @@
function getSource(state, actor) {
return state.sources.sources[actor];
}
function getSources(state) {
return state.sources.sources;
}
function getSourceCount(state) {
return Object.keys(state.sources.sources).length;
}
function getSourceByURL(state, url) {
for (let k in state.sources.sources) {
const source = state.sources.sources[k];
if (source.url === url) {
return source;
}
}
}
function getSourceByActor(state, actor) {
for (let k in state.sources.sources) {
const source = state.sources.sources[k];
if (source.actor === actor) {
return source;
}
}
}
function getSelectedSource(state) {
return state.sources.sources[state.sources.selectedSource];
}
function getSelectedSourceOpts(state) {
return state.sources.selectedSourceOpts;
}
function getSourceText(state, actor) {
return state.sources.sourcesText[actor];
}
function getBreakpoints(state) {
return Object.keys(state.breakpoints.breakpoints).map(k => {
return state.breakpoints.breakpoints[k];
});
}
function getBreakpoint(state, location) {
return state.breakpoints.breakpoints[makeLocationId(location)];
}
function makeLocationId(location) {
return location.actor + ":" + location.line.toString();
}
module.exports = {
getSource,
getSources,
getSourceCount,
getSourceByURL,
getSourceByActor,
getSelectedSource,
getSelectedSourceOpts,
getSourceText,
getBreakpoint,
getBreakpoints,
makeLocationId
};

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

@ -1,31 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const initialState = [];
function update(state = initialState, action, emitChange) {
const { seqId } = action;
if (action.type === constants.UNLOAD) {
return initialState;
}
else if (seqId) {
let newState;
if (action.status === "start") {
newState = [...state, seqId];
}
else if (action.status === "error" || action.status === "done") {
newState = state.filter(id => id !== seqId);
}
emitChange("open-requests", newState);
return newState;
}
return state;
}
module.exports = update;

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

@ -1,154 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const Immutable = require("devtools/client/shared/vendor/seamless-immutable");
const { mergeIn, setIn, deleteIn } = require("../utils");
const { makeLocationId } = require("../queries");
const initialState = Immutable({
breakpoints: {}
});
// Return the first argument that is a string, or null if nothing is a
// string.
function firstString(...args) {
for (var arg of args) {
if (typeof arg === "string") {
return arg;
}
}
return null;
}
function update(state = initialState, action, emitChange) {
switch (action.type) {
case constants.ADD_BREAKPOINT: {
const id = makeLocationId(action.breakpoint.location);
if (action.status === "start") {
const existingBp = state.breakpoints[id];
const bp = existingBp || Immutable(action.breakpoint);
state = setIn(state, ["breakpoints", id], bp.merge({
disabled: false,
loading: true,
// We want to do an OR here, but we can't because we need
// empty strings to be truthy, i.e. an empty string is a valid
// condition.
condition: firstString(action.condition, bp.condition)
}));
emitChange(existingBp ? "breakpoint-enabled" : "breakpoint-added",
state.breakpoints[id]);
return state;
}
else if (action.status === "done") {
const { actor, text, isWasm } = action.value;
let { actualLocation } = action.value;
// If the breakpoint moved, update the map
if (actualLocation) {
// XXX Bug 1227417: The `setBreakpoint` RDP request rdp
// request returns an `actualLocation` field that doesn't
// conform to the regular { actor, line } location shape, but
// it has a `source` field. We should fix that.
actualLocation = { actor: actualLocation.source.actor,
line: actualLocation.line };
state = deleteIn(state, ["breakpoints", id]);
const movedId = makeLocationId(actualLocation);
const currentBp = state.breakpoints[movedId] || Immutable(action.breakpoint);
const prevLocation = action.breakpoint.location;
const newBp = currentBp.merge({ location: actualLocation });
state = setIn(state, ["breakpoints", movedId], newBp);
emitChange("breakpoint-moved", {
breakpoint: newBp,
prevLocation: prevLocation
});
}
const finalLocation = (
actualLocation ? actualLocation : action.breakpoint.location
);
const finalLocationId = makeLocationId(finalLocation);
state = mergeIn(state, ["breakpoints", finalLocationId], {
disabled: false,
loading: false,
actor: actor,
isWasm: isWasm,
text: text
});
emitChange("breakpoint-updated", state.breakpoints[finalLocationId]);
return state;
}
else if (action.status === "error") {
// Remove the optimistic update
emitChange("breakpoint-removed", state.breakpoints[id]);
return deleteIn(state, ["breakpoints", id]);
}
break;
}
case constants.REMOVE_BREAKPOINT: {
if (action.status === "done") {
const id = makeLocationId(action.breakpoint.location);
const bp = state.breakpoints[id];
if (action.disabled) {
state = mergeIn(state, ["breakpoints", id],
{ loading: false, disabled: true });
emitChange("breakpoint-disabled", state.breakpoints[id]);
return state;
}
state = deleteIn(state, ["breakpoints", id]);
emitChange("breakpoint-removed", bp);
return state;
}
break;
}
case constants.SET_BREAKPOINT_CONDITION: {
const id = makeLocationId(action.breakpoint.location);
const bp = state.breakpoints[id];
emitChange("breakpoint-condition-updated", bp);
if (!action.status) {
// No status means that it wasn't a remote request. Just update
// the condition locally.
return mergeIn(state, ["breakpoints", id], {
condition: action.condition
});
}
else if (action.status === "start") {
return mergeIn(state, ["breakpoints", id], {
loading: true,
condition: action.condition
});
}
else if (action.status === "done") {
return mergeIn(state, ["breakpoints", id], {
loading: false,
condition: action.condition,
// Setting a condition creates a new breakpoint client as of
// now, so we need to update the actor
actor: action.value.actor
});
}
else if (action.status === "error") {
emitChange("breakpoint-removed", bp);
return deleteIn(state, ["breakpoints", id]);
}
break;
}}
return state;
}
module.exports = update;

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

@ -1,37 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const FETCH_EVENT_LISTENERS_DELAY = 200; // ms
const initialState = {
activeEventNames: [],
listeners: [],
fetchingListeners: false,
};
function update(state = initialState, action, emit) {
switch (action.type) {
case constants.UPDATE_EVENT_BREAKPOINTS:
state.activeEventNames = action.eventNames;
emit("activeEventNames", state.activeEventNames);
break;
case constants.FETCH_EVENT_LISTENERS:
if (action.status === "begin") {
state.fetchingListeners = true;
}
else if (action.status === "done") {
state.fetchingListeners = false;
state.listeners = action.listeners;
emit("event-listeners", state.listeners);
}
break;
}
return state;
}
module.exports = update;

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

@ -1,16 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const eventListeners = require("./event-listeners");
const sources = require("./sources");
const breakpoints = require("./breakpoints");
const asyncRequests = require("./async-requests");
module.exports = {
eventListeners,
sources,
breakpoints,
asyncRequests
};

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

@ -1,12 +0,0 @@
# vim: set filetype=python:
# 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/.
DevToolsModules(
'async-requests.js',
'breakpoints.js',
'event-listeners.js',
'index.js',
'sources.js'
)

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

@ -1,128 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const constants = require("../constants");
const Immutable = require("devtools/client/shared/vendor/seamless-immutable");
const { mergeIn, setIn } = require("../utils");
const initialState = Immutable({
sources: {},
selectedSource: null,
selectedSourceOpts: null,
sourcesText: {}
});
function update(state = initialState, action, emitChange) {
switch (action.type) {
case constants.ADD_SOURCE:
emitChange("source", action.source);
return mergeIn(state, ["sources", action.source.actor], action.source);
case constants.LOAD_SOURCES:
if (action.status === "done") {
const sources = action.value;
if (!sources) {
return state;
}
const sourcesByActor = {};
sources.forEach(source => {
if (!state.sources[source.actor]) {
emitChange("source", source);
}
sourcesByActor[source.actor] = source;
});
return mergeIn(state, ["sources"], state.sources.merge(sourcesByActor));
}
break;
case constants.SELECT_SOURCE:
emitChange("source-selected", action.source);
return state.merge({
selectedSource: action.source.actor,
selectedSourceOpts: action.opts
});
case constants.LOAD_SOURCE_TEXT: {
const s = _updateText(state, action);
emitChange("source-text-loaded", s.sources[action.source.actor]);
return s;
}
case constants.BLACKBOX:
if (action.status === "done") {
const s = mergeIn(state,
["sources", action.source.actor, "isBlackBoxed"],
action.value.isBlackBoxed);
emitChange("blackboxed", s.sources[action.source.actor]);
return s;
}
break;
case constants.TOGGLE_PRETTY_PRINT:
let s = state;
if (action.status === "error") {
s = mergeIn(state, ["sourcesText", action.source.actor], {
loading: false
});
// If it errored, just display the source as it was before, but
// only if there is existing text already. If auto-prettifying
// is on, the original text may still be coming in and we don't
// have it yet. If we try to set empty text we confuse the
// editor because it thinks it's already displaying the source's
// text and won't load the text when it actually comes in.
if (s.sourcesText[action.source.actor].text != null) {
emitChange("prettyprinted", s.sources[action.source.actor]);
}
}
else {
s = _updateText(state, action);
// Don't do this yet, the progress bar is still imperatively shown
// from the source view. We will fix in the next iteration.
// emitChange('source-text-loaded', s.sources[action.source.actor]);
if (action.status === "done") {
s = mergeIn(s,
["sources", action.source.actor, "isPrettyPrinted"],
action.value.isPrettyPrinted);
emitChange("prettyprinted", s.sources[action.source.actor]);
}
}
return s;
case constants.UNLOAD:
// Reset the entire state to just the initial state, a blank state
// if you will.
return initialState;
}
return state;
}
function _updateText(state, action) {
const { source } = action;
if (action.status === "start") {
// Merge this in, don't set it. That way the previous value is
// still stored here, and we can retrieve it if whatever we're
// doing fails.
return mergeIn(state, ["sourcesText", source.actor], {
loading: true
});
}
else if (action.status === "error") {
return setIn(state, ["sourcesText", source.actor], {
error: action.error
});
}
else {
return setIn(state, ["sourcesText", source.actor], {
text: action.value.text,
contentType: action.value.contentType
});
}
}
module.exports = update;

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

@ -1,411 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const defer = require("devtools/shared/defer");
const EventEmitter = require("devtools/shared/event-emitter");
const {KeyCodes} = require("devtools/client/shared/keycodes");
const {TooltipToggle} = require("devtools/client/shared/widgets/tooltip/TooltipToggle");
const XHTML_NS = "http://www.w3.org/1999/xhtml";
const ESCAPE_KEYCODE = KeyCodes.DOM_VK_ESCAPE;
const POPUP_EVENTS = ["shown", "hidden", "showing", "hiding"];
/**
* Tooltip widget.
*
* This widget is intended at any tool that may need to show rich content in the
* form of floating panels.
* A common use case is image previewing in the CSS rule view, but more complex
* use cases may include color pickers, object inspection, etc...
*
* Tooltips are based on XUL (namely XUL arrow-type <panel>s), and therefore
* need a XUL Document to live in.
* This is pretty much the only requirement they have on their environment.
*
* The way to use a tooltip is simply by instantiating a tooltip yourself and
* attaching some content in it, or using one of the ready-made content types.
*
* A convenient `startTogglingOnHover` method may avoid having to register event
* handlers yourself if the tooltip has to be shown when hovering over a
* specific element or group of elements (which is usually the most common case)
*/
/**
* Tooltip class.
*
* Basic usage:
* let t = new Tooltip(xulDoc);
* t.content = someXulContent;
* t.show();
* t.hide();
* t.destroy();
*
* Better usage:
* let t = new Tooltip(xulDoc);
* t.startTogglingOnHover(container, target => {
* if (<condition based on target>) {
* t.content = el;
* return true;
* }
* });
* t.destroy();
*
* @param {XULDocument} doc
* The XUL document hosting this tooltip
* @param {Object} options
* Optional options that give options to consumers:
* - consumeOutsideClick {Boolean} Wether the first click outside of the
* tooltip should close the tooltip and be consumed or not.
* Defaults to false.
* - closeOnKeys {Array} An array of key codes that should close the
* tooltip. Defaults to [27] (escape key).
* - closeOnEvents [{emitter: {Object}, event: {String},
* useCapture: {Boolean}}]
* Provide an optional list of emitter objects and event names here to
* trigger the closing of the tooltip when these events are fired by the
* emitters. The emitter objects should either implement
* on/off(event, cb) or addEventListener/removeEventListener(event, cb).
* Defaults to [].
* For instance, the following would close the tooltip whenever the
* toolbox selects a new tool and when a DOM node gets scrolled:
* new Tooltip(doc, {
* closeOnEvents: [
* {emitter: toolbox, event: "select"},
* {emitter: myContainer, event: "scroll", useCapture: true}
* ]
* });
* - noAutoFocus {Boolean} Should the focus automatically go to the panel
* when it opens. Defaults to true.
*
* Fires these events:
* - showing : just before the tooltip shows
* - shown : when the tooltip is shown
* - hiding : just before the tooltip closes
* - hidden : when the tooltip gets hidden
* - keydown : when any key gets pressed, with keyCode
*/
class Tooltip {
constructor(doc, {
consumeOutsideClick = false,
closeOnKeys = [ESCAPE_KEYCODE],
noAutoFocus = true,
closeOnEvents = [],
} = {}) {
EventEmitter.decorate(this);
this.defaultPosition = "before_start";
// px
this.defaultOffsetX = 0;
// px
this.defaultOffsetY = 0;
// px
this.doc = doc;
this.consumeOutsideClick = consumeOutsideClick;
this.closeOnKeys = closeOnKeys;
this.noAutoFocus = noAutoFocus;
this.closeOnEvents = closeOnEvents;
this.panel = this._createPanel();
// Create tooltip toggle helper and decorate the Tooltip instance with
// shortcut methods.
this._toggle = new TooltipToggle(this);
this.startTogglingOnHover = this._toggle.start.bind(this._toggle);
this.stopTogglingOnHover = this._toggle.stop.bind(this._toggle);
// Emit show/hide events when the panel does.
for (const eventName of POPUP_EVENTS) {
this["_onPopup" + eventName] = (name => {
return e => {
if (e.target === this.panel) {
this.emit(name);
}
};
})(eventName);
this.panel.addEventListener("popup" + eventName,
this["_onPopup" + eventName]);
}
// Listen to keydown events to close the tooltip if configured to do so
const win = this.doc.querySelector("window");
this._onKeyDown = event => {
if (this.panel.hidden) {
return;
}
this.emit("keydown", event.keyCode);
if (this.closeOnKeys.includes(event.keyCode) &&
this.isShown()) {
event.stopPropagation();
this.hide();
}
};
win.addEventListener("keydown", this._onKeyDown);
// Listen to custom emitters' events to close the tooltip
this.hide = this.hide.bind(this);
for (const {emitter, event, useCapture} of this.closeOnEvents) {
for (const add of ["addEventListener", "on"]) {
if (add in emitter) {
emitter[add](event, this.hide, useCapture);
break;
}
}
}
}
/**
* Show the tooltip. It might be wise to append some content first if you
* don't want the tooltip to be empty. You may access the content of the
* tooltip by setting a XUL node to t.content.
* @param {node} anchor
* Which node should the tooltip be shown on
* @param {string} position [optional]
* Optional tooltip position. Defaults to before_start
* https://developer.mozilla.org/en-US/docs/XUL/PopupGuide/Positioning
* @param {number} x, y [optional]
* The left and top offset coordinates, in pixels.
*/
show(anchor,
position = this.defaultPosition,
x = this.defaultOffsetX,
y = this.defaultOffsetY) {
this.panel.hidden = false;
this.panel.openPopup(anchor, position, x, y);
}
/**
* Hide the tooltip
*/
hide() {
this.panel.hidden = true;
this.panel.hidePopup();
}
isShown() {
return this.panel &&
this.panel.state !== "closed" &&
this.panel.state !== "hiding";
}
setSize(width, height) {
this.panel.sizeTo(width, height);
}
/**
* Empty the tooltip's content
*/
empty() {
while (this.panel.hasChildNodes()) {
this.panel.firstChild.remove();
}
}
/**
* Gets this panel's visibility state.
* @return boolean
*/
isHidden() {
return this.panel.state == "closed" || this.panel.state == "hiding";
}
/**
* Gets if this panel has any child nodes.
* @return boolean
*/
isEmpty() {
return !this.panel.hasChildNodes();
}
/**
* Get rid of references and event listeners
*/
destroy() {
this.hide();
for (const eventName of POPUP_EVENTS) {
this.panel.removeEventListener("popup" + eventName,
this["_onPopup" + eventName]);
}
const win = this.doc.querySelector("window");
win.removeEventListener("keydown", this._onKeyDown);
for (const {emitter, event, useCapture} of this.closeOnEvents) {
for (const remove of ["removeEventListener", "off"]) {
if (remove in emitter) {
emitter[remove](event, this.hide, useCapture);
break;
}
}
}
this.content = null;
this._toggle.destroy();
this.doc = null;
this.panel.remove();
this.panel = null;
}
/**
* Returns the outer container node (that includes the arrow etc.). Happens
* to be identical to this.panel here, can be different element in other
* Tooltip implementations.
*/
get container() {
return this.panel;
}
/**
* Set the content of this tooltip. Will first empty the tooltip and then
* append the new content element.
* Consider using one of the set<type>Content() functions instead.
* @param {node} content
* A node that can be appended in the tooltip XUL element
*/
set content(content) {
if (this.content == content) {
return;
}
this.empty();
this.panel.removeAttribute("clamped-dimensions");
this.panel.removeAttribute("clamped-dimensions-no-min-height");
this.panel.removeAttribute("clamped-dimensions-no-max-or-min-height");
this.panel.removeAttribute("wide");
if (content) {
this.panel.appendChild(content);
}
}
get content() {
return this.panel.firstChild;
}
/**
* Sets some text as the content of this tooltip.
*
* @param {array} messages
* A list of text messages.
* @param {string} messagesClass [optional]
* A style class for the text messages.
* @param {string} containerClass [optional]
* A style class for the text messages container.
*/
setTextContent(
{
messages,
messagesClass,
containerClass
},
extraButtons = []) {
messagesClass = messagesClass || "default-tooltip-simple-text-colors";
containerClass = containerClass || "default-tooltip-simple-text-colors";
const vbox = this.doc.createXULElement("vbox");
vbox.className = "devtools-tooltip-simple-text-container " + containerClass;
vbox.setAttribute("flex", "1");
for (const text of messages) {
const description = this.doc.createXULElement("description");
description.setAttribute("flex", "1");
description.className = "devtools-tooltip-simple-text " + messagesClass;
description.textContent = text;
vbox.appendChild(description);
}
for (const { label, className, command } of extraButtons) {
const button = this.doc.createXULElement("button");
button.className = className;
button.setAttribute("label", label);
button.addEventListener("command", command);
vbox.appendChild(button);
}
this.content = vbox;
}
/**
* Load a document into an iframe, and set the iframe
* to be the tooltip's content.
*
* Used by tooltips that want to load their interface
* into an iframe from a URL.
*
* @param {string} width
* Width of the iframe.
* @param {string} height
* Height of the iframe.
* @param {string} url
* URL of the document to load into the iframe.
*
* @return {promise} A promise which is resolved with
* the iframe.
*
* This function creates an iframe, loads the specified document
* into it, sets the tooltip's content to the iframe, and returns
* a promise.
*
* When the document is loaded, the function gets the content window
* and resolves the promise with the content window.
*/
setIFrameContent({width, height}, url) {
const def = defer();
// Create an iframe
const iframe = this.doc.createElementNS(XHTML_NS, "iframe");
iframe.setAttribute("transparent", true);
iframe.setAttribute("width", width);
iframe.setAttribute("height", height);
iframe.setAttribute("flex", "1");
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.setAttribute("class", "devtools-tooltip-iframe");
// Wait for the load to initialize the widget
function onLoad() {
iframe.removeEventListener("load", onLoad, true);
def.resolve(iframe);
}
iframe.addEventListener("load", onLoad, true);
// load the document from url into the iframe
iframe.setAttribute("src", url);
// Put the iframe in the tooltip
this.content = iframe;
return def.promise;
}
/**
* Create the tooltip panel
*/
_createPanel() {
const panel = this.doc.createXULElement("panel");
panel.setAttribute("hidden", true);
panel.setAttribute("ignorekeys", true);
panel.setAttribute("animate", false);
panel.setAttribute("consumeoutsideclicks",
this.consumeOutsideClick);
panel.setAttribute("noautofocus", this.noAutoFocus);
panel.setAttribute("type", "arrow");
panel.setAttribute("level", "top");
panel.setAttribute("class", "devtools-tooltip theme-tooltip-panel");
this.doc.querySelector("window").appendChild(panel);
return panel;
}
}
module.exports = Tooltip;

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

@ -1,89 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
const ChromeUtils = require("ChromeUtils");
ChromeUtils.defineModuleGetter(this, "VariablesView",
"resource://devtools/client/shared/widgets/VariablesView.jsm");
ChromeUtils.defineModuleGetter(this, "VariablesViewController",
"resource://devtools/client/shared/widgets/VariablesViewController.jsm");
/**
* Fill the tooltip with a variables view, inspecting an object via its
* corresponding object actor, as specified in the remote debugging protocol.
*
* @param {Tooltip} tooltip
* The tooltip to use
* @param {object} objectActor
* The value grip for the object actor.
* @param {object} viewOptions [optional]
* Options for the variables view visualization.
* @param {object} controllerOptions [optional]
* Options for the variables view controller.
* @param {object} relayEvents [optional]
* A collection of events to listen on the variables view widget.
* For example, { fetched: () => ... }
* @param {array} extraButtons [optional]
* An array of extra buttons to add. Each element of the array
* should be of the form {label, className, command}.
* @param {Toolbox} toolbox [optional]
* Pass the instance of the current toolbox if you want the variables
* view widget to allow highlighting and selection of DOM nodes
*/
function setTooltipVariableContent(tooltip, objectActor,
viewOptions = {}, controllerOptions = {},
relayEvents = {}, extraButtons = [],
toolbox = null) {
const doc = tooltip.doc;
const vbox = doc.createXULElement("vbox");
vbox.className = "devtools-tooltip-variables-view-box";
vbox.setAttribute("flex", "1");
const innerbox = doc.createXULElement("vbox");
innerbox.className = "devtools-tooltip-variables-view-innerbox";
innerbox.setAttribute("flex", "1");
vbox.appendChild(innerbox);
for (const { label, className, command } of extraButtons) {
const button = doc.createXULElement("button");
button.className = className;
button.setAttribute("label", label);
button.addEventListener("command", command);
vbox.appendChild(button);
}
const widget = new VariablesView(innerbox, viewOptions);
// If a toolbox was provided, link it to the vview
if (toolbox) {
widget.toolbox = toolbox;
}
// Analyzing state history isn't useful with transient object inspectors.
widget.commitHierarchy = () => {};
for (const e in relayEvents) {
widget.on(e, relayEvents[e]);
}
VariablesViewController.attach(widget, controllerOptions);
// Some of the view options are allowed to change between uses.
widget.searchPlaceholder = viewOptions.searchPlaceholder;
widget.searchEnabled = viewOptions.searchEnabled;
// Use the object actor's grip to display it as a variable in the widget.
// The controller options are allowed to change between uses.
widget.controller.setSingleVariable(
{ objectActor: objectActor }, controllerOptions);
tooltip.content = vbox;
tooltip.panel.setAttribute("clamped-dimensions", "");
}
exports.setTooltipVariableContent = setTooltipVariableContent;

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

@ -1,9 +0,0 @@
# vim: set filetype=python:
# 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/.
DevToolsModules(
'Tooltip.js',
'VariableContentHelper.js',
)

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

@ -1,173 +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/. */
:root.theme-light {
--old-tooltip-simpletext-color: black;
--old-tooltip-simpletext-border: #d9e1e8;
--old-tooltip-arrow-vertical: url("chrome://devtools/skin/tooltip/arrow-vertical-light.png");
--old-tooltip-arrow-horizontal: url("chrome://devtools/skin/tooltip/arrow-horizontal-light.png");
--old-tooltip-arrow-vertical-2x: url("chrome://devtools/skin/tooltip/arrow-vertical-light@2x.png");
--old-tooltip-arrow-horizontal-2x: url("chrome://devtools/skin/tooltip/arrow-horizontal-light@2x.png");
--old-tooltip-arrowcontent-background: rgba(255, 255, 255, .9);
--old-tooltip-arrowcontent-border: #d9e1e8;
}
:root.theme-dark {
--old-tooltip-simpletext-color: white;
--old-tooltip-simpletext-border: #434850;
--old-tooltip-arrow-vertical: url("chrome://devtools/skin/tooltip/arrow-vertical-dark.png");
--old-tooltip-arrow-horizontal: url("chrome://devtools/skin/tooltip/arrow-horizontal-dark.png");
--old-tooltip-arrow-vertical-2x: url("chrome://devtools/skin/tooltip/arrow-vertical-dark@2x.png");
--old-tooltip-arrow-horizontal-2x: url("chrome://devtools/skin/tooltip/arrow-horizontal-dark@2x.png");
--old-tooltip-arrowcontent-background: rgba(19, 28, 38, .9);
--old-tooltip-arrowcontent-border: #434850;
}
.devtools-tooltip .panel-arrowcontent {
padding: 4px;
}
.devtools-tooltip .panel-arrowcontainer {
/* Reseting the transition used when panels are shown */
transition: none;
/* Panels slide up/down/left/right when they appear using a transform.
Since we want to remove the transition, we don't need to transform anymore
plus it can interfeer by causing mouseleave events on the underlying nodes */
transform: none;
}
.devtools-tooltip[clamped-dimensions] {
min-height: 100px;
max-height: 400px;
min-width: 100px;
max-width: 400px;
}
.devtools-tooltip[clamped-dimensions-no-min-height] {
min-height: 0;
max-height: 400px;
min-width: 100px;
max-width: 400px;
}
.devtools-tooltip[clamped-dimensions-no-max-or-min-height] {
min-width: 400px;
max-width: 400px;
}
.devtools-tooltip[clamped-dimensions] .panel-arrowcontent,
.devtools-tooltip[clamped-dimensions-no-min-height] .panel-arrowcontent,
.devtools-tooltip[clamped-dimensions-no-max-or-min-height] .panel-arrowcontent {
overflow: hidden;
}
.devtools-tooltip[wide] {
max-width: 600px;
}
/* Tooltip: Simple Text */
.devtools-tooltip-simple-text {
max-width: 400px;
margin: 0 -4px; /* Compensate for the .panel-arrowcontent padding. */
padding: 8px 12px;
white-space: pre-wrap;
}
.devtools-tooltip-simple-text:first-child {
margin-top: -4px;
}
.devtools-tooltip-simple-text:last-child {
margin-bottom: -4px;
}
/* Tooltip: Variables View */
.devtools-tooltip-variables-view-box {
margin: -4px; /* Compensate for the .panel-arrowcontent padding. */
}
.devtools-tooltip-variables-view-box .variable-or-property > .title {
padding-inline-end: 6px;
}
.devtools-tooltip-iframe {
border: none;
background: transparent;
}
/* Overring panel arrow images to fit with our light and dark themes */
.theme-tooltip-panel .devtools-tooltip-simple-text:last-child {
border-bottom: 0;
}
.theme-tooltip-panel .panel-arrowcontent {
padding: 4px;
background: var(--old-tooltip-arrowcontent-background);
border-radius: 5px;
box-shadow: none;
border: 3px solid var(--old-tooltip-arrowcontent-border);
}
/* Overring panel arrow images to fit with our light and dark themes */
.theme-tooltip-panel .panel-arrow {
--arrow-margin: -4px;
}
:root[platform="win"] .theme-tooltip-panel .panel-arrow {
--arrow-margin: -7px;
}
.theme-tooltip-panel .panel-arrow[side="top"],
.theme-tooltip-panel .panel-arrow[side="bottom"] {
list-style-image: var(--old-tooltip-arrow-vertical);
/* !important is needed to override the popup.css rules in toolkit/themes */
width: 39px !important;
height: 16px !important;
}
.theme-tooltip-panel .panel-arrow[side="left"],
.theme-tooltip-panel .panel-arrow[side="right"] {
list-style-image: var(--old-tooltip-arrow-horizontal);
/* !important is needed to override the popup.css rules in toolkit/themes */
width: 16px !important;
height: 39px !important;
}
.theme-tooltip-panel .panel-arrow[side="top"] {
margin-bottom: var(--arrow-margin);
}
.theme-tooltip-panel .panel-arrow[side="bottom"] {
margin-top: var(--arrow-margin);
}
.theme-tooltip-panel .panel-arrow[side="left"] {
margin-right: var(--arrow-margin);
}
.theme-tooltip-panel .panel-arrow[side="right"] {
margin-left: var(--arrow-margin);
}
@media (min-resolution: 1.1dppx) {
.theme-tooltip-panel .panel-arrow[side="top"],
.theme-tooltip-panel .panel-arrow[side="bottom"] {
list-style-image: var(--old-tooltip-arrow-vertical-2x);
}
.theme-tooltip-panel .panel-arrow[side="left"],
.theme-tooltip-panel .panel-arrow[side="right"] {
list-style-image: var(--old-tooltip-arrow-horizontal-2x);
}
}
.theme-tooltip-panel .devtools-tooltip-simple-text {
color: var(--old-tooltip-simpletext-color);
border-bottom: 1px solid var(--old-tooltip-simpletext-border);
}

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

@ -1,88 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
const { reportException } = require("devtools/shared/DevToolsUtils");
const { Task } = require("devtools/shared/task");
function asPaused(client, func) {
if (client.state != "paused") {
return Task.spawn(function* () {
yield client.interrupt();
let result;
try {
result = yield func();
}
catch (e) {
// Try to put the debugger back in a working state by resuming
// it
yield client.resume();
throw e;
}
yield client.resume();
return result;
});
} else {
return func();
}
}
function handleError(err) {
reportException("promise", err.toString());
}
function onReducerEvents(controller, listeners, thisContext) {
Object.keys(listeners).forEach(name => {
const listener = listeners[name];
controller.onChange(name, payload => {
listener.call(thisContext, payload);
});
});
}
function _getIn(destObj, path) {
return path.reduce(function (acc, name) {
return acc[name];
}, destObj);
}
function mergeIn(destObj, path, value) {
path = [...path];
path.reverse();
var obj = path.reduce(function (acc, name) {
return { [name]: acc };
}, value);
return destObj.merge(obj, { deep: true });
}
function setIn(destObj, path, value) {
destObj = mergeIn(destObj, path, null);
return mergeIn(destObj, path, value);
}
function updateIn(destObj, path, fn) {
return setIn(destObj, path, fn(_getIn(destObj, path)));
}
function deleteIn(destObj, path) {
const objPath = path.slice(0, -1);
const propName = path[path.length - 1];
const obj = _getIn(destObj, objPath);
return setIn(destObj, objPath, obj.without(propName));
}
module.exports = {
asPaused,
handleError,
onReducerEvents,
mergeIn,
setIn,
updateIn,
deleteIn
};

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

@ -1,296 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* import-globals-from ../../debugger-controller.js */
const actions = require("../actions/event-listeners");
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
const { extend } = require("devtools/shared/extend");
const { WidgetMethods } = require("devtools/client/shared/widgets/view-helpers");
const { SideMenuWidget } = require("resource://devtools/client/shared/widgets/SideMenuWidget.jsm");
/**
* Functions handling the event listeners UI.
*/
function EventListenersView(controller) {
dumpn("EventListenersView was instantiated");
this.actions = bindActionCreators(actions, controller.dispatch);
this.getState = () => controller.getState().eventListeners;
this._onCheck = this._onCheck.bind(this);
this._onClick = this._onClick.bind(this);
controller.onChange("event-listeners", this.renderListeners.bind(this));
}
EventListenersView.prototype = extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function () {
dumpn("Initializing the EventListenersView");
this.widget = new SideMenuWidget(document.getElementById("event-listeners"), {
showItemCheckboxes: true,
showGroupCheckboxes: true
});
this.emptyText = L10N.getStr("noEventListenersText");
this._eventCheckboxTooltip = L10N.getStr("eventCheckboxTooltip");
this._onSelectorString = " " + L10N.getStr("eventOnSelector") + " ";
this._inSourceString = " " + L10N.getStr("eventInSource") + " ";
this._inNativeCodeString = L10N.getStr("eventNative");
this.widget.addEventListener("check", this._onCheck);
this.widget.addEventListener("click", this._onClick);
},
/**
* Destruction function, called when the debugger is closed.
*/
destroy: function () {
dumpn("Destroying the EventListenersView");
this.widget.removeEventListener("check", this._onCheck);
this.widget.removeEventListener("click", this._onClick);
},
renderListeners: function (listeners) {
listeners.forEach(listener => {
this.addListener(listener, { staged: true });
});
// Flushes all the prepared events into the event listeners container.
this.commit();
},
/**
* Adds an event to this event listeners container.
*
* @param object aListener
* The listener object coming from the active thread.
* @param object aOptions [optional]
* Additional options for adding the source. Supported options:
* - staged: true to stage the item to be appended later
*/
addListener: function (aListener, aOptions = {}) {
let { node: { selector }, function: { url }, type } = aListener;
if (!type) return;
// Some listener objects may be added from plugins, thus getting
// translated to native code.
if (!url) {
url = this._inNativeCodeString;
}
// If an event item for this listener's url and type was already added,
// avoid polluting the view and simply increase the "targets" count.
let eventItem = this.getItemForPredicate(aItem =>
aItem.attachment.url == url &&
aItem.attachment.type == type);
if (eventItem) {
let { selectors, view: { targets } } = eventItem.attachment;
if (!selectors.includes(selector)) {
selectors.push(selector);
targets.setAttribute("value", L10N.getFormatStr("eventNodes", selectors.length));
}
return;
}
// There's no easy way of grouping event types into higher-level groups,
// so we need to do this by hand.
let is = (...args) => args.includes(type);
let has = str => type.includes(str);
let starts = str => type.startsWith(str);
let group;
if (starts("animation")) {
group = L10N.getStr("animationEvents");
} else if (starts("audio")) {
group = L10N.getStr("audioEvents");
} else if (is("levelchange")) {
group = L10N.getStr("batteryEvents");
} else if (is("cut", "copy", "paste")) {
group = L10N.getStr("clipboardEvents");
} else if (starts("composition")) {
group = L10N.getStr("compositionEvents");
} else if (starts("device")) {
group = L10N.getStr("deviceEvents");
} else if (is("fullscreenchange", "fullscreenerror", "orientationchange",
"overflow", "resize", "scroll", "underflow", "zoom")) {
group = L10N.getStr("displayEvents");
} else if (starts("drag") || starts("drop")) {
group = L10N.getStr("dragAndDropEvents");
} else if (starts("gamepad")) {
group = L10N.getStr("gamepadEvents");
} else if (is("canplay", "canplaythrough", "durationchange", "emptied",
"ended", "loadeddata", "loadedmetadata", "pause", "play", "playing",
"ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate",
"volumechange", "waiting")) {
group = L10N.getStr("mediaEvents");
} else if (is("blocked", "complete", "success", "upgradeneeded", "versionchange")) {
group = L10N.getStr("indexedDBEvents");
} else if (is("blur", "change", "focus", "focusin", "focusout", "invalid",
"reset", "select", "submit")) {
group = L10N.getStr("interactionEvents");
} else if (starts("key") || is("input")) {
group = L10N.getStr("keyboardEvents");
} else if (starts("mouse") || has("click") || is("contextmenu", "show", "wheel")) {
group = L10N.getStr("mouseEvents");
} else if (starts("DOM")) {
group = L10N.getStr("mutationEvents");
} else if (is("abort", "error", "hashchange", "load", "loadend", "loadstart",
"pagehide", "pageshow", "progress", "timeout", "unload", "uploadprogress",
"visibilitychange")) {
group = L10N.getStr("navigationEvents");
} else if (is("pointerlockchange", "pointerlockerror")) {
group = L10N.getStr("pointerLockEvents");
} else if (is("compassneedscalibration", "userproximity")) {
group = L10N.getStr("sensorEvents");
} else if (starts("storage")) {
group = L10N.getStr("storageEvents");
} else if (is("beginEvent", "endEvent", "repeatEvent")) {
group = L10N.getStr("timeEvents");
} else if (starts("touch")) {
group = L10N.getStr("touchEvents");
} else {
group = L10N.getStr("otherEvents");
}
// Create the element node for the event listener item.
const itemView = this._createItemView(type, selector, url);
// Event breakpoints survive target navigations. Make sure the newly
// inserted event item is correctly checked.
const activeEventNames = this.getState().activeEventNames;
const checkboxState = activeEventNames.includes(type);
// Append an event listener item to this container.
this.push([itemView.container], {
staged: aOptions.staged, /* stage the item to be appended later? */
attachment: {
url: url,
type: type,
view: itemView,
selectors: [selector],
group: group,
checkboxState: checkboxState,
checkboxTooltip: this._eventCheckboxTooltip
}
});
},
/**
* Gets all the event types known to this container.
*
* @return array
* List of event types, for example ["load", "click"...]
*/
getAllEvents: function () {
return this.attachments.map(e => e.type);
},
/**
* Gets the checked event types in this container.
*
* @return array
* List of event types, for example ["load", "click"...]
*/
getCheckedEvents: function () {
return this.attachments.filter(e => e.checkboxState).map(e => e.type);
},
/**
* Customization function for creating an item's UI.
*
* @param string aType
* The event type, for example "click".
* @param string aSelector
* The target element's selector.
* @param string url
* The source url in which the event listener is located.
* @return object
* An object containing the event listener view nodes.
*/
_createItemView: function (aType, aSelector, aUrl) {
let container = document.createElement("hbox");
container.className = "dbg-event-listener";
let eventType = document.createElement("label");
eventType.className = "plain dbg-event-listener-type";
eventType.setAttribute("value", aType);
container.appendChild(eventType);
let typeSeparator = document.createElement("label");
typeSeparator.className = "plain dbg-event-listener-separator";
typeSeparator.setAttribute("value", this._onSelectorString);
container.appendChild(typeSeparator);
let eventTargets = document.createElement("label");
eventTargets.className = "plain dbg-event-listener-targets";
eventTargets.setAttribute("value", aSelector);
container.appendChild(eventTargets);
let selectorSeparator = document.createElement("label");
selectorSeparator.className = "plain dbg-event-listener-separator";
selectorSeparator.setAttribute("value", this._inSourceString);
container.appendChild(selectorSeparator);
let eventLocation = document.createElement("label");
eventLocation.className = "plain dbg-event-listener-location";
eventLocation.setAttribute("value", SourceUtils.getSourceLabel(aUrl));
eventLocation.setAttribute("flex", "1");
eventLocation.setAttribute("crop", "center");
container.appendChild(eventLocation);
return {
container: container,
type: eventType,
targets: eventTargets,
location: eventLocation
};
},
/**
* The check listener for the event listeners container.
*/
_onCheck: function ({ detail: { description, checked }, target }) {
if (description == "item") {
this.getItemForElement(target).attachment.checkboxState = checked;
this.actions.updateEventBreakpoints(this.getCheckedEvents());
return;
}
// Check all the event items in this group.
this.items
.filter(e => e.attachment.group == description)
.forEach(e => this.callMethod("checkItem", e.target, checked));
},
/**
* The select listener for the event listeners container.
*/
_onClick: function ({ target }) {
// Changing the checkbox state is handled by the _onCheck event. Avoid
// handling that again in this click event, so pass in "noSiblings"
// when retrieving the target's item, to ignore the checkbox.
let eventItem = this.getItemForElement(target, { noSiblings: true });
if (eventItem) {
let newState = eventItem.attachment.checkboxState ^= 1;
this.callMethod("checkItem", eventItem.target, newState);
}
},
_eventCheckboxTooltip: "",
_onSelectorString: "",
_inSourceString: "",
_inNativeCodeString: ""
});
module.exports = EventListenersView;

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

@ -1,9 +0,0 @@
# vim: set filetype=python:
# 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/.
DevToolsModules(
'event-listeners-view.js',
'sources-view.js'
)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,998 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const SOURCE_URL_DEFAULT_MAX_LENGTH = 64; // chars
const STACK_FRAMES_SOURCE_URL_MAX_LENGTH = 15; // chars
const STACK_FRAMES_SOURCE_URL_TRIM_SECTION = "center";
const STACK_FRAMES_SCROLL_DELAY = 100; // ms
const BREAKPOINT_SMALL_WINDOW_WIDTH = 850; // px
const RESULTS_PANEL_POPUP_POSITION = "before_end";
const RESULTS_PANEL_MAX_RESULTS = 10;
const FILE_SEARCH_ACTION_MAX_DELAY = 300; // ms
const GLOBAL_SEARCH_EXPAND_MAX_RESULTS = 50;
const GLOBAL_SEARCH_LINE_MAX_LENGTH = 300; // chars
const GLOBAL_SEARCH_ACTION_MAX_DELAY = 1500; // ms
const FUNCTION_SEARCH_ACTION_MAX_DELAY = 400; // ms
const SEARCH_GLOBAL_FLAG = "!";
const SEARCH_FUNCTION_FLAG = "@";
const SEARCH_TOKEN_FLAG = "#";
const SEARCH_LINE_FLAG = ":";
const SEARCH_VARIABLE_FLAG = "*";
const SEARCH_AUTOFILL = [SEARCH_GLOBAL_FLAG, SEARCH_FUNCTION_FLAG, SEARCH_TOKEN_FLAG];
const TOOLBAR_ORDER_POPUP_POSITION = "topcenter bottomleft";
const RESIZE_REFRESH_RATE = 50; // ms
const EventListenersView = require("./content/views/event-listeners-view");
const SourcesView = require("./content/views/sources-view");
var actions = Object.assign(
{},
require("./content/globalActions"),
require("./content/actions/breakpoints"),
require("./content/actions/sources"),
require("./content/actions/event-listeners")
);
var queries = require("./content/queries");
var constants = require("./content/constants");
/**
* Object defining the debugger view components.
*/
var DebuggerView = {
/**
* This is attached so tests can change it without needing to load an
* actual large file in automation
*/
LARGE_FILE_SIZE: 1048576, // 1 MB in bytes
/**
* Initializes the debugger view.
*
* @return object
* A promise that is resolved when the view finishes initializing.
*/
initialize: function (isWorker) {
if (this._startup) {
return this._startup;
}
const deferred = promise.defer();
this._startup = deferred.promise;
this._initializePanes();
this._initializeEditor(deferred.resolve);
this.Toolbar.initialize();
this.Options.initialize();
this.Filtering.initialize();
this.StackFrames.initialize();
this.StackFramesClassicList.initialize();
this.Workers.initialize();
this.Sources.initialize(isWorker);
this.VariableBubble.initialize();
this.WatchExpressions.initialize();
this.EventListeners.initialize();
this.GlobalSearch.initialize();
this._initializeVariablesView();
this._editorSource = {};
this._editorDocuments = {};
this.editor.on("cursorActivity", this.Sources._onEditorCursorActivity);
this.controller = DebuggerController;
const getState = this.controller.getState;
onReducerEvents(this.controller, {
"source-text-loaded": this.renderSourceText,
"source-selected": this.renderSourceText,
"blackboxed": this.renderBlackBoxed,
"prettyprinted": this.renderPrettyPrinted,
"breakpoint-added": this.addEditorBreakpoint,
"breakpoint-enabled": this.addEditorBreakpoint,
"breakpoint-disabled": this.removeEditorBreakpoint,
"breakpoint-removed": this.removeEditorBreakpoint,
"breakpoint-condition-updated": this.renderEditorBreakpointCondition,
"breakpoint-moved": ({ breakpoint, prevLocation }) => {
const selectedSource = queries.getSelectedSource(getState());
const { location } = breakpoint;
if (selectedSource &&
selectedSource.actor === location.actor) {
this.editor.moveBreakpoint(this.toEditorLine(prevLocation.line),
this.toEditorLine(location.line));
}
}
}, this);
return deferred.promise;
},
/**
* Destroys the debugger view.
*
* @return object
* A promise that is resolved when the view finishes destroying.
*/
destroy: function () {
if (this._hasShutdown) {
return;
}
this._hasShutdown = true;
window.removeEventListener("resize", this._onResize);
this.editor.off("cursorActivity", this.Sources._onEditorCursorActivity);
this.Toolbar.destroy();
this.Options.destroy();
this.Filtering.destroy();
this.StackFrames.destroy();
this.StackFramesClassicList.destroy();
this.Sources.destroy();
this.VariableBubble.destroy();
this.WatchExpressions.destroy();
this.EventListeners.destroy();
this.GlobalSearch.destroy();
this._destroyPanes();
this.editor.destroy();
this.editor = null;
this.controller.dispatch(actions.removeAllBreakpoints());
},
/**
* Initializes the UI for all the displayed panes.
*/
_initializePanes: function () {
dumpn("Initializing the DebuggerView panes");
this._body = document.getElementById("body");
this._editorDeck = document.getElementById("editor-deck");
this._workersAndSourcesPane = document.getElementById("workers-and-sources-pane");
this._instrumentsPane = document.getElementById("instruments-pane");
this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle");
this.showEditor = this.showEditor.bind(this);
this.showBlackBoxMessage = this.showBlackBoxMessage.bind(this);
this.showProgressBar = this.showProgressBar.bind(this);
this._onTabSelect = this._onInstrumentsPaneTabSelect.bind(this);
this._instrumentsPane.tabpanels.addEventListener("select", this._onTabSelect);
this._collapsePaneString = L10N.getStr("collapsePanes");
this._expandPaneString = L10N.getStr("expandPanes");
this._workersAndSourcesPane.setAttribute("width", Prefs.workersAndSourcesWidth);
this._instrumentsPane.setAttribute("width", Prefs.instrumentsWidth);
this.toggleInstrumentsPane({ visible: Prefs.panesVisibleOnStartup });
this.updateLayoutMode();
this._onResize = this._onResize.bind(this);
window.addEventListener("resize", this._onResize);
},
/**
* Destroys the UI for all the displayed panes.
*/
_destroyPanes: function () {
dumpn("Destroying the DebuggerView panes");
if (gHostType != "right" && gHostType != "left") {
Prefs.workersAndSourcesWidth = this._workersAndSourcesPane.getAttribute("width");
Prefs.instrumentsWidth = this._instrumentsPane.getAttribute("width");
}
this._workersAndSourcesPane = null;
this._instrumentsPane = null;
this._instrumentsPaneToggleButton = null;
},
/**
* Initializes the VariablesView instance and attaches a controller.
*/
_initializeVariablesView: function () {
this.Variables = new VariablesView(document.getElementById("variables"), {
searchPlaceholder: L10N.getStr("emptyVariablesFilterText"),
emptyText: L10N.getStr("emptyVariablesText"),
onlyEnumVisible: Prefs.variablesOnlyEnumVisible,
searchEnabled: Prefs.variablesSearchboxVisible,
eval: (variable, value) => {
let string = variable.evaluationMacro(variable, value);
DebuggerController.StackFrames.evaluate(string);
},
lazyEmpty: true
});
// Attach the current toolbox to the VView so it can link DOMNodes to
// the inspector/highlighter
this.Variables.toolbox = DebuggerController._toolbox;
// Attach a controller that handles interfacing with the debugger protocol.
VariablesViewController.attach(this.Variables, {
getEnvironmentClient: aObject => gThreadClient.environment(aObject),
getObjectClient: aObject => {
return gThreadClient.pauseGrip(aObject);
}
});
// Relay events from the VariablesView.
this.Variables.on("fetched", aType => {
switch (aType) {
case "scopes":
window.emit(EVENTS.FETCHED_SCOPES);
break;
case "variables":
window.emit(EVENTS.FETCHED_VARIABLES);
break;
case "properties":
window.emit(EVENTS.FETCHED_PROPERTIES);
break;
}
});
},
/**
* Initializes the Editor instance.
*
* @param function aCallback
* Called after the editor finishes initializing.
*/
_initializeEditor: function (callback) {
dumpn("Initializing the DebuggerView editor");
let extraKeys = {};
bindKey("_doTokenSearch", "tokenSearchKey");
bindKey("_doGlobalSearch", "globalSearchKey", { alt: true });
bindKey("_doFunctionSearch", "functionSearchKey");
extraKeys[Editor.keyFor("jumpToLine")] = false;
extraKeys["Esc"] = false;
function bindKey(func, key, modifiers = {}) {
key = document.getElementById(key).getAttribute("key");
let shortcut = Editor.accel(key, modifiers);
extraKeys[shortcut] = () => DebuggerView.Filtering[func]();
}
let gutters = ["breakpoints"];
this.editor = new Editor({
mode: Editor.modes.text,
readOnly: true,
lineNumbers: true,
showAnnotationRuler: true,
gutters: gutters,
extraKeys: extraKeys,
contextMenu: "sourceEditorContextMenu",
enableCodeFolding: false
});
this.editor.appendTo(document.getElementById("editor")).then(() => {
this.editor.extend(DebuggerEditor);
this._loadingText = L10N.getStr("loadingText");
callback();
});
this.editor.on("gutterClick", (line, button) => {
// A right-click shouldn't do anything but keep track of where
// it was clicked.
if (button == 2) {
this.clickedLine = line;
}
else {
const source = queries.getSelectedSource(this.controller.getState());
if (source) {
const location = { actor: source.actor, line: this.toSourceLine(line) };
if (this.editor.hasBreakpoint(line)) {
this.controller.dispatch(actions.removeBreakpoint(location));
} else {
this.controller.dispatch(actions.addBreakpoint(location));
}
}
}
});
this.editor.on("cursorActivity", () => {
this.clickedLine = null;
});
},
toEditorLine: function (line) {
return this.editor.isWasm ? line : line - 1;
},
toSourceLine: function (line) {
return this.editor.isWasm ? line : line + 1;
},
updateEditorBreakpoints: function (source) {
const breakpoints = queries.getBreakpoints(this.controller.getState());
const sources = queries.getSources(this.controller.getState());
for (let bp of breakpoints) {
if (sources[bp.location.actor] && !bp.disabled) {
this.addEditorBreakpoint(bp);
}
else {
this.removeEditorBreakpoint(bp);
}
}
},
addEditorBreakpoint: function (breakpoint) {
const { location, condition } = breakpoint;
const source = queries.getSelectedSource(this.controller.getState());
if (source &&
source.actor === location.actor &&
!breakpoint.disabled) {
this.editor.addBreakpoint(this.toEditorLine(location.line), condition);
}
},
removeEditorBreakpoint: function (breakpoint) {
const { location } = breakpoint;
const source = queries.getSelectedSource(this.controller.getState());
if (source && source.actor === location.actor) {
let line = this.toEditorLine(location.line);
this.editor.removeBreakpoint(line);
this.editor.removeBreakpointCondition(line);
}
},
renderEditorBreakpointCondition: function (breakpoint) {
const { location, condition, disabled } = breakpoint;
const source = queries.getSelectedSource(this.controller.getState());
if (source && source.actor === location.actor && !disabled) {
let line = this.toEditorLine(location.line);
if (condition) {
this.editor.setBreakpointCondition(line);
} else {
this.editor.removeBreakpointCondition(line);
}
}
},
/**
* Display the source editor.
*/
showEditor: function () {
this._editorDeck.selectedIndex = 0;
},
/**
* Display the black box message.
*/
showBlackBoxMessage: function () {
this._editorDeck.selectedIndex = 1;
},
/**
* Display the progress bar.
*/
showProgressBar: function () {
this._editorDeck.selectedIndex = 2;
},
/**
* Sets the currently displayed text contents in the source editor.
* This resets the mode and undo stack.
*
* @param string documentKey
* Key to get the correct editor document
*
* @param string aTextContent
* The source text content.
*
* @param boolean shouldUpdateText
Forces a text and mode reset
*/
_setEditorText: function (documentKey, aTextContent = "", shouldUpdateText = false) {
const isNew = this._setEditorDocument(documentKey);
this.editor.clearDebugLocation();
this.editor.clearHistory();
this.editor.removeBreakpoints();
// Only set editor's text and mode if it is a new document
if (isNew || shouldUpdateText) {
this.editor.setMode(Editor.modes.text);
this.editor.setText(aTextContent);
}
},
/**
* Sets the proper editor mode (JS or HTML) according to the specified
* content type, or by determining the type from the url or text content.
*
* @param string aUrl
* The source url.
* @param string aContentType [optional]
* The source content type.
* @param string aTextContent [optional]
* The source text content.
*/
_setEditorMode: function (aUrl, aContentType = "", aTextContent = "") {
// Use JS mode for files with .js and .jsm extensions.
if (SourceUtils.isJavaScript(aUrl, aContentType)) {
return void this.editor.setMode(Editor.modes.js);
}
if (aContentType === "text/wasm") {
return void this.editor.setMode(Editor.modes.text);
}
// Use HTML mode for files in which the first non whitespace character is
// &lt;, regardless of extension.
if (typeof aTextContent === 'string' && aTextContent.match(/^\s*</)) {
return void this.editor.setMode(Editor.modes.html);
}
// Unknown language, use text.
this.editor.setMode(Editor.modes.text);
},
/**
* Sets the editor's displayed document.
* If there isn't a document for the source, create one
*
* @param string key - key used to access the editor document cache
*
* @return boolean isNew - was the document just created
*/
_setEditorDocument: function (key) {
let isNew;
if (!this._editorDocuments[key]) {
isNew = true;
this._editorDocuments[key] = this.editor.createDocument();
} else {
isNew = false;
}
const doc = this._editorDocuments[key];
this.editor.replaceDocument(doc);
return isNew;
},
renderBlackBoxed: function (source) {
this._renderSourceText(
source,
queries.getSourceText(this.controller.getState(), source.actor)
);
},
renderPrettyPrinted: function (source) {
this._renderSourceText(
source,
queries.getSourceText(this.controller.getState(), source.actor)
);
},
renderSourceText: function (source) {
this._renderSourceText(
source,
queries.getSourceText(this.controller.getState(), source.actor),
queries.getSelectedSourceOpts(this.controller.getState())
);
},
_renderSourceText: function (source, textInfo, opts = {}) {
const selectedSource = queries.getSelectedSource(this.controller.getState());
// Exit early if we're attempting to render an unselected source
if (!selectedSource || selectedSource.actor !== source.actor) {
return;
}
if (source.isBlackBoxed) {
this.showBlackBoxMessage();
setTimeout(() => {
window.emit(EVENTS.SOURCE_SHOWN, source);
}, 0);
return;
}
else {
this.showEditor();
}
if (textInfo.loading) {
// TODO: bug 1228866, we need to update `_editorSource` here but
// still make the editor be updated when the full text comes
// through somehow.
this._setEditorText("loading", L10N.getStr("loadingText"));
return;
}
else if (textInfo.error) {
let msg = L10N.getFormatStr("errorLoadingText3", textInfo.error);
this._setEditorText("error", msg);
console.error(new Error(msg));
dumpn(msg);
this.showEditor();
window.emit(EVENTS.SOURCE_ERROR_SHOWN, source);
return;
}
// If the line is not specified, default to the current frame's position,
// if available and the frame's url corresponds to the requested url.
if (!("line" in opts)) {
let cachedFrames = DebuggerController.activeThread.cachedFrames;
let currentDepth = DebuggerController.StackFrames.currentFrameDepth;
let frame = cachedFrames[currentDepth];
if (frame && frame.source.actor == source.actor) {
opts.line = frame.where.line;
}
}
if (this._editorSource.actor === source.actor &&
this._editorSource.prettyPrinted === source.isPrettyPrinted &&
this._editorSource.blackboxed === source.isBlackBoxed) {
this.updateEditorPosition(opts);
return;
}
let { text, contentType } = textInfo;
let shouldUpdateText = this._editorSource.prettyPrinted != source.isPrettyPrinted;
this._setEditorText(source.actor, text, shouldUpdateText);
this._editorSource.actor = source.actor;
this._editorSource.prettyPrinted = source.isPrettyPrinted;
this._editorSource.blackboxed = source.isBlackBoxed;
this._editorSource.prettyPrinted = source.isPrettyPrinted;
this._setEditorMode(source.url, contentType, text);
this.updateEditorBreakpoints(source);
setTimeout(() => {
window.emit(EVENTS.SOURCE_SHOWN, source);
}, 0);
this.updateEditorPosition(opts);
},
updateEditorPosition: function (opts) {
let line = opts.line || 0;
if (this.editor.isWasm && line > 0) {
line = this.toSourceLine(this.editor.wasmOffsetToLine(line));
}
// Line numbers in the source editor should start from 1. If
// invalid or not specified, then don't do anything.
if (line < 1) {
window.emit(EVENTS.EDITOR_LOCATION_SET);
return;
}
if (opts.charOffset) {
line += this.editor.getPosition(opts.charOffset).line;
}
if (opts.lineOffset) {
line += opts.lineOffset;
}
line = this.toEditorLine(line);
if (opts.moveCursor) {
let location = { line: line, ch: opts.columnOffset || 0 };
this.editor.setCursor(location);
}
if (!opts.noDebug) {
this.editor.setDebugLocation(line);
}
window.emit(EVENTS.EDITOR_LOCATION_SET);
},
/**
* Update the source editor's current caret and debug location based on
* a requested url and line.
*
* @param string aActor
* The target actor id.
* @param number aLine [optional]
* The target line in the source.
* @param object aFlags [optional]
* Additional options for showing the source. Supported options:
* - charOffset: character offset for the caret or debug location
* - lineOffset: line offset for the caret or debug location
* - columnOffset: column offset for the caret or debug location
* - noCaret: don't set the caret location at the specified line
* - noDebug: don't set the debug location at the specified line
* - align: string specifying whether to align the specified line
* at the "top", "center" or "bottom" of the editor
* - force: boolean forcing all text to be reshown in the editor
* @return object
* A promise that is resolved after the source text has been set.
*/
setEditorLocation: function (aActor, aLine, aFlags = {}) {
// Avoid trying to set a source for a url that isn't known yet.
if (!this.Sources.containsValue(aActor)) {
throw new Error("Unknown source for the specified URL.");
}
let sourceItem = this.Sources.getItemByValue(aActor);
let source = sourceItem.attachment.source;
// Make sure the requested source client is shown in the editor,
// then update the source editor's caret position and debug
// location.
this.controller.dispatch(actions.selectSource(source, {
line: aLine,
charOffset: aFlags.charOffset,
lineOffset: aFlags.lineOffset,
columnOffset: aFlags.columnOffset,
moveCursor: !aFlags.noCaret,
noDebug: aFlags.noDebug,
forceUpdate: aFlags.force
}));
},
/**
* Gets the visibility state of the instruments pane.
* @return boolean
*/
get instrumentsPaneHidden() {
return this._instrumentsPane.classList.contains("pane-collapsed");
},
/**
* Gets the currently selected tab in the instruments pane.
* @return string
*/
get instrumentsPaneTab() {
return this._instrumentsPane.selectedTab.id;
},
/**
* Sets the instruments pane hidden or visible.
*
* @param object aFlags
* An object containing some of the following properties:
* - visible: true if the pane should be shown, false to hide
* - animated: true to display an animation on toggle
* - delayed: true to wait a few cycles before toggle
* - callback: a function to invoke when the toggle finishes
* @param number aTabIndex [optional]
* The index of the intended selected tab in the details pane.
*/
toggleInstrumentsPane: function (aFlags, aTabIndex) {
let pane = this._instrumentsPane;
let button = this._instrumentsPaneToggleButton;
ViewHelpers.togglePane(aFlags, pane);
if (aFlags.visible) {
button.classList.remove("pane-collapsed");
button.setAttribute("tooltiptext", this._collapsePaneString);
} else {
button.classList.add("pane-collapsed");
button.setAttribute("tooltiptext", this._expandPaneString);
}
if (aTabIndex !== undefined) {
pane.selectedIndex = aTabIndex;
}
},
/**
* Sets the instruments pane visible after a short period of time.
*
* @param function aCallback
* A function to invoke when the toggle finishes.
*/
showInstrumentsPane: function (aCallback) {
DebuggerView.toggleInstrumentsPane({
visible: true,
animated: true,
delayed: true,
callback: aCallback
}, 0);
},
/**
* Handles a tab selection event on the instruments pane.
*/
_onInstrumentsPaneTabSelect: function () {
if (this._instrumentsPane.selectedTab.id == "events-tab") {
this.controller.dispatch(actions.fetchEventListeners());
}
},
/**
* Handles a host change event issued by the parent toolbox.
*
* @param string aType
* The host type, either "bottom", "left", "right" or "window".
*/
handleHostChanged: function (hostType) {
this._hostType = hostType;
this.updateLayoutMode();
},
/**
* Resize handler for this container's window.
*/
_onResize: function (evt) {
// Allow requests to settle down first.
setNamedTimeout(
"resize-events", RESIZE_REFRESH_RATE, () => this.updateLayoutMode());
},
/**
* Set the layout to "vertical" or "horizontal" depending on the host type.
*/
updateLayoutMode: function () {
if (this._isSmallWindowHost() ||
this._hostType == "left" ||
this._hostType == "right") {
this._setLayoutMode("vertical");
} else {
this._setLayoutMode("horizontal");
}
},
/**
* Check if the current host is in window mode and is
* too small for horizontal layout
*/
_isSmallWindowHost: function () {
if (this._hostType != "window") {
return false;
}
return window.outerWidth <= BREAKPOINT_SMALL_WINDOW_WIDTH;
},
/**
* Enter the provided layoutMode. Do nothing if the layout is the same as the current one.
* @param {String} layoutMode new layout ("vertical" or "horizontal")
*/
_setLayoutMode: function (layoutMode) {
if (this._body.getAttribute("layout") == layoutMode) {
return;
}
if (layoutMode == "vertical") {
this._enterVerticalLayout();
} else {
this._enterHorizontalLayout();
}
this._body.setAttribute("layout", layoutMode);
window.emit(EVENTS.LAYOUT_CHANGED, layoutMode);
},
/**
* Switches the debugger widgets to a vertical layout.
*/
_enterVerticalLayout: function () {
let vertContainer = document.getElementById("vertical-layout-panes-container");
// Move the soruces and instruments panes in a different container.
let splitter = document.getElementById("sources-and-instruments-splitter");
vertContainer.insertBefore(this._workersAndSourcesPane, splitter);
vertContainer.appendChild(this._instrumentsPane);
// Make sure the vertical layout container's height doesn't repeatedly
// grow or shrink based on the displayed sources, variables etc.
vertContainer.setAttribute("height",
vertContainer.getBoundingClientRect().height);
},
/**
* Switches the debugger widgets to a horizontal layout.
*/
_enterHorizontalLayout: function () {
let normContainer = document.getElementById("debugger-widgets");
let editorPane = document.getElementById("editor-and-instruments-pane");
// The sources and instruments pane need to be inserted at their
// previous locations in their normal container.
let splitter = document.getElementById("sources-and-editor-splitter");
normContainer.insertBefore(this._workersAndSourcesPane, splitter);
editorPane.appendChild(this._instrumentsPane);
// Revert to the preferred sources and instruments widths, because
// they flexed in the vertical layout.
this._workersAndSourcesPane.setAttribute("width", Prefs.workersAndSourcesWidth);
this._instrumentsPane.setAttribute("width", Prefs.instrumentsWidth);
},
/**
* Handles any initialization on a tab navigation event issued by the client.
*/
handleTabNavigation: function () {
dumpn("Handling tab navigation in the DebuggerView");
this.Filtering.clearSearch();
this.GlobalSearch.clearView();
this.StackFrames.empty();
this.Sources.empty();
this.Variables.empty();
this.EventListeners.empty();
if (this.editor) {
this.editor.setMode(Editor.modes.text);
this.editor.setText("");
this.editor.clearHistory();
this._editorSource = {};
this._editorDocuments = {};
}
},
Toolbar: null,
Options: null,
Filtering: null,
GlobalSearch: null,
StackFrames: null,
Sources: null,
Variables: null,
VariableBubble: null,
WatchExpressions: null,
EventListeners: null,
editor: null,
_loadingText: "",
_body: null,
_editorDeck: null,
_workersAndSourcesPane: null,
_instrumentsPane: null,
_instrumentsPaneToggleButton: null,
_collapsePaneString: "",
_expandPaneString: ""
};
/**
* A custom items container, used for displaying views like the
* FilteredSources, FilteredFunctions etc., inheriting the generic WidgetMethods.
*/
function ResultsPanelContainer() {
}
ResultsPanelContainer.prototype = extend(WidgetMethods, {
/**
* Sets the anchor node for this container panel.
* @param Node aNode
*/
set anchor(aNode) {
this._anchor = aNode;
// If the anchor node is not null, create a panel to attach to the anchor
// when showing the popup.
if (aNode) {
if (!this._panel) {
this._panel = document.createElement("panel");
this._panel.id = "results-panel";
this._panel.setAttribute("level", "top");
this._panel.setAttribute("noautofocus", "true");
this._panel.setAttribute("consumeoutsideclicks", "false");
document.documentElement.appendChild(this._panel);
}
if (!this.widget) {
this.widget = new SimpleListWidget(this._panel);
this.autoFocusOnFirstItem = false;
this.autoFocusOnSelection = false;
this.maintainSelectionVisible = false;
}
}
// Cleanup the anchor and remove the previously created panel.
else {
this._panel.remove();
this._panel = null;
this.widget = null;
}
},
/**
* Gets the anchor node for this container panel.
* @return Node
*/
get anchor() {
return this._anchor;
},
/**
* Sets the container panel hidden or visible. It's hidden by default.
* @param boolean aFlag
*/
set hidden(aFlag) {
if (aFlag) {
this._panel.hidden = true;
this._panel.hidePopup();
} else {
this._panel.hidden = false;
this._panel.openPopup(this._anchor, this.position, this.left, this.top);
}
},
/**
* Gets this container's visibility state.
* @return boolean
*/
get hidden() {
return this._panel.state == "closed" ||
this._panel.state == "hiding";
},
/**
* Removes all items from this container and hides it.
*/
clearView: function () {
this.hidden = true;
this.empty();
},
/**
* Selects the next found item in this container.
* Does not change the currently focused node.
*/
selectNext: function () {
let nextIndex = this.selectedIndex + 1;
if (nextIndex >= this.itemCount) {
nextIndex = 0;
}
this.selectedItem = this.getItemAtIndex(nextIndex);
},
/**
* Selects the previously found item in this container.
* Does not change the currently focused node.
*/
selectPrev: function () {
let prevIndex = this.selectedIndex - 1;
if (prevIndex < 0) {
prevIndex = this.itemCount - 1;
}
this.selectedItem = this.getItemAtIndex(prevIndex);
},
/**
* Customization function for creating an item's UI.
*
* @param string aLabel
* The item's label string.
* @param string aBeforeLabel
* An optional string shown before the label.
* @param string aBelowLabel
* An optional string shown underneath the label.
*/
_createItemView: function (aLabel, aBelowLabel, aBeforeLabel) {
let container = document.createElement("vbox");
container.className = "results-panel-item";
let firstRowLabels = document.createElement("hbox");
let secondRowLabels = document.createElement("hbox");
if (aBeforeLabel) {
let beforeLabelNode = document.createElement("label");
beforeLabelNode.className = "plain results-panel-item-label-before";
beforeLabelNode.setAttribute("value", aBeforeLabel);
firstRowLabels.appendChild(beforeLabelNode);
}
let labelNode = document.createElement("label");
labelNode.className = "plain results-panel-item-label";
labelNode.setAttribute("value", aLabel);
firstRowLabels.appendChild(labelNode);
if (aBelowLabel) {
let belowLabelNode = document.createElement("label");
belowLabelNode.className = "plain results-panel-item-label-below";
belowLabelNode.setAttribute("value", aBelowLabel);
secondRowLabels.appendChild(belowLabelNode);
}
container.appendChild(firstRowLabels);
container.appendChild(secondRowLabels);
return container;
},
_anchor: null,
_panel: null,
position: RESULTS_PANEL_POPUP_POSITION,
left: 0,
top: 0
});
DebuggerView.EventListeners = new EventListenersView(DebuggerController);
DebuggerView.Sources = new SourcesView(DebuggerController, DebuggerView);

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

@ -1,69 +0,0 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=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/. */
/* Side pane views */
#workers-pane > tabpanels > tabpanel,
#sources-pane > tabpanels > tabpanel,
#instruments-pane > tabpanels > tabpanel {
-moz-box-orient: vertical;
}
/* Toolbar controls */
.devtools-toolbarbutton:not([label]) > .toolbarbutton-text {
display: none;
}
/* Horizontal vs. vertical layout */
#body[layout=vertical] #debugger-widgets {
-moz-box-orient: vertical;
}
#body[layout=vertical] #workers-and-sources-pane {
-moz-box-flex: 1;
}
#body[layout=vertical] #instruments-pane {
-moz-box-flex: 2;
}
#body[layout=vertical] #instruments-pane-toggle {
display: none;
}
#body[layout=vertical] #sources-and-editor-splitter,
#body[layout=vertical] #editor-and-instruments-splitter {
display: none;
}
#body[layout=horizontal] #vertical-layout-splitter,
#body[layout=horizontal] #vertical-layout-panes-container {
display: none;
}
#body[layout=vertical] #stackframes {
visibility: hidden;
}
#source-progress-container {
display: flex;
flex-flow: column;
justify-content: center;
}
#source-progress {
flex: none;
}
#redux-devtools * {
display: block;
}
#redux-devtools span {
display: inline
}

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

@ -1,479 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/content/debugger/debugger.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/content/debugger/content/tooltip/tooltips-old.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/debugger.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % debuggerDTD SYSTEM "chrome://devtools/locale/debugger.dtd">
%debuggerDTD;
<!ENTITY % editMenuDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
%editMenuDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
macanimationtype="document"
fullscreenbutton="true"
screenX="4" screenY="4"
width="960" height="480"
persist="screenX screenY width height sizemode">
<script type="application/javascript"
src="chrome://devtools/content/shared/theme-switching.js"/>
<script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="text/javascript" src="debugger-controller.js"/>
<script type="text/javascript" src="debugger-view.js"/>
<script type="text/javascript" src="utils.js"/>
<script type="text/javascript" src="views/workers-view.js"/>
<script type="text/javascript" src="views/variable-bubble-view.js"/>
<script type="text/javascript" src="views/watch-expressions-view.js"/>
<script type="text/javascript" src="views/global-search-view.js"/>
<script type="text/javascript" src="views/toolbar-view.js"/>
<script type="text/javascript" src="views/options-view.js"/>
<script type="text/javascript" src="views/stack-frames-view.js"/>
<script type="text/javascript" src="views/stack-frames-classic-view.js"/>
<script type="text/javascript" src="views/filter-view.js"/>
#include ../../../toolkit/content/editMenuCommands.inc.xul
<commandset id="debuggerCommands"></commandset>
<popupset id="debuggerPopupset">
<menupopup id="sourceEditorContextMenu"
onpopupshowing="goUpdateGlobalEditMenuItems()">
<menuitem id="se-dbg-cMenu-addBreakpoint"
label="&debuggerUI.seMenuBreak;"
key="addBreakpointKey"
command="addBreakpointCommand"/>
<menuitem id="se-dbg-cMenu-addConditionalBreakpoint"
label="&debuggerUI.seMenuCondBreak;"
key="addConditionalBreakpointKey"
command="addConditionalBreakpointCommand"/>
<menuitem id="se-dbg-cMenu-editConditionalBreakpoint"
label="&debuggerUI.seEditMenuCondBreak;"
key="addConditionalBreakpointKey"
command="addConditionalBreakpointCommand"/>
<menuitem id="se-dbg-cMenu-addAsWatch"
label="&debuggerUI.seMenuAddWatch;"
key="addWatchExpressionKey"
command="addWatchExpressionCommand"/>
<menuseparator/>
<menuitem id="cMenu_copy" label="&copyCmd.label;"
accesskey="&copyCmd.accesskey;" command="cmd_copy"/>
<menuseparator/>
<menuitem id="cMenu_selectAll" label="&selectAllCmd.label;"
accesskey="&selectAllCmd.accesskey;" command="cmd_selectAll"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findFile"
label="&debuggerUI.searchFile;"
accesskey="&debuggerUI.searchFile.accesskey;"
key="fileSearchKey"
command="fileSearchCommand"/>
<menuitem id="se-dbg-cMenu-findGlobal"
label="&debuggerUI.searchGlobal;"
accesskey="&debuggerUI.searchGlobal.accesskey;"
key="globalSearchKey"
command="globalSearchCommand"/>
<menuitem id="se-dbg-cMenu-findFunction"
label="&debuggerUI.searchFunction;"
accesskey="&debuggerUI.searchFunction.accesskey;"
key="functionSearchKey"
command="functionSearchCommand"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findToken"
label="&debuggerUI.searchToken;"
accesskey="&debuggerUI.searchToken.accesskey;"
key="tokenSearchKey"
command="tokenSearchCommand"/>
<menuitem id="se-dbg-cMenu-findLine"
label="&debuggerUI.searchGoToLine;"
accesskey="&debuggerUI.searchGoToLine.accesskey;"
key="lineSearchKey"
command="lineSearchCommand"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findVariable"
label="&debuggerUI.searchVariable;"
accesskey="&debuggerUI.searchVariable.accesskey;"
key="variableSearchKey"
command="variableSearchCommand"/>
<menuitem id="se-dbg-cMenu-focusVariables"
label="&debuggerUI.focusVariables;"
accesskey="&debuggerUI.focusVariables.accesskey;"
key="variablesFocusKey"
command="variablesFocusCommand"/>
<menuitem id="se-dbg-cMenu-prettyPrint"
label="&debuggerUI.sources.prettyPrint;"
command="prettyPrintCommand"/>
</menupopup>
<menupopup id="debuggerWatchExpressionsContextMenu">
<menuitem id="add-watch-expression"
label="&debuggerUI.addWatch;"
accesskey="&debuggerUI.addWatch.accesskey;"
key="addWatchExpressionKey"
command="addWatchExpressionCommand"/>
<menuitem id="removeAll-watch-expression"
label="&debuggerUI.removeAllWatch;"
accesskey="&debuggerUI.removeAllWatch.accesskey;"
key="removeAllWatchExpressionsKey"
command="removeAllWatchExpressionsCommand"/>
</menupopup>
<menupopup id="debuggerPrefsContextMenu"
position="before_end"
onpopupshowing="DebuggerView.Options._onPopupShowing()"
onpopuphiding="DebuggerView.Options._onPopupHiding()"
onpopuphidden="DebuggerView.Options._onPopupHidden()">
<menuitem id="auto-pretty-print"
type="checkbox"
label="&debuggerUI.autoPrettyPrint;"
accesskey="&debuggerUI.autoPrettyPrint.accesskey;"
command="toggleAutoPrettyPrint"/>
<menuitem id="pause-on-exceptions"
type="checkbox"
label="&debuggerUI.pauseExceptions;"
accesskey="&debuggerUI.pauseExceptions.accesskey;"
command="togglePauseOnExceptions"/>
<menuitem id="ignore-caught-exceptions"
type="checkbox"
label="&debuggerUI.ignoreCaughtExceptions;"
accesskey="&debuggerUI.ignoreCaughtExceptions.accesskey;"
command="toggleIgnoreCaughtExceptions"/>
<menuitem id="show-panes-on-startup"
type="checkbox"
label="&debuggerUI.showPanesOnInit;"
accesskey="&debuggerUI.showPanesOnInit.accesskey;"
command="toggleShowPanesOnStartup"/>
<menuitem id="show-vars-only-enum"
type="checkbox"
label="&debuggerUI.showOnlyEnum;"
accesskey="&debuggerUI.showOnlyEnum.accesskey;"
command="toggleShowOnlyEnum"/>
<menuitem id="show-vars-filter-box"
type="checkbox"
label="&debuggerUI.showVarsFilter;"
accesskey="&debuggerUI.showVarsFilter.accesskey;"
command="toggleShowVariablesFilterBox"/>
<menuitem id="show-original-source"
type="checkbox"
label="&debuggerUI.showOriginalSource;"
accesskey="&debuggerUI.showOriginalSource.accesskey;"
command="toggleShowOriginalSource"/>
<menuitem id="auto-black-box"
type="checkbox"
label="&debuggerUI.autoBlackBox;"
accesskey="&debuggerUI.autoBlackBox.accesskey;"
command="toggleAutoBlackBox"/>
</menupopup>
</popupset>
<popupset id="debuggerSourcesPopupset">
<menupopup id="debuggerSourcesContextMenu">
<menuitem id="debugger-sources-context-newtab"
label="&debuggerUI.context.newTab;"
accesskey="&debuggerUI.context.newTab.accesskey;"/>
<menuitem id="debugger-sources-context-copyurl"
label="&debuggerUI.context.copyUrl;"
accesskey="&debuggerUI.context.copyUrl.accesskey;"/>
</menupopup>
</popupset>
<keyset id="debuggerKeys">
<key id="nextSourceKey"
keycode="VK_DOWN"
modifiers="accel alt"
command="nextSourceCommand"/>
<key id="prevSourceKey"
keycode="VK_UP"
modifiers="accel alt"
command="prevSourceCommand"/>
<key id="resumeKey"
keycode="&debuggerUI.stepping.resume1;"
command="resumeCommand"/>
<key id="stepOverKey"
keycode="&debuggerUI.stepping.stepOver1;"
command="stepOverCommand"/>
<key id="stepInKey"
keycode="&debuggerUI.stepping.stepIn1;"
command="stepInCommand"/>
<key id="stepOutKey"
keycode="&debuggerUI.stepping.stepOut1;"
modifiers="shift"
command="stepOutCommand"/>
<key id="fileSearchKey"
key="&debuggerUI.searchFile.key;"
modifiers="accel"
command="fileSearchCommand"/>
<key id="fileSearchKey"
key="&debuggerUI.searchFile.altkey;"
modifiers="accel"
command="fileSearchCommand"/>
<key id="globalSearchKey"
key="&debuggerUI.searchGlobal.key;"
modifiers="accel alt"
command="globalSearchCommand"/>
<key id="functionSearchKey"
key="&debuggerUI.searchFunction.key;"
modifiers="accel"
command="functionSearchCommand"/>
<key id="tokenSearchKey"
key="&debuggerUI.searchToken.key;"
modifiers="accel"
command="tokenSearchCommand"/>
<key id="lineSearchKey"
key="&debuggerUI.searchGoToLine.key;"
modifiers="accel"
command="lineSearchCommand"/>
<key id="variableSearchKey"
key="&debuggerUI.searchVariable.key;"
modifiers="accel alt"
command="variableSearchCommand"/>
<key id="variablesFocusKey"
key="&debuggerUI.focusVariables.key;"
modifiers="accel shift"
command="variablesFocusCommand"/>
<key id="addBreakpointKey"
key="&debuggerUI.seMenuBreak.key;"
modifiers="accel"
command="addBreakpointCommand"/>
<key id="addConditionalBreakpointKey"
key="&debuggerUI.seMenuCondBreak.key;"
modifiers="accel shift"
command="addConditionalBreakpointCommand"/>
<key id="addWatchExpressionKey"
key="&debuggerUI.seMenuAddWatch.key;"
modifiers="accel shift"
command="addWatchExpressionCommand"/>
<key id="removeAllWatchExpressionsKey"
key="&debuggerUI.removeAllWatch.key;"
modifiers="accel alt"
command="removeAllWatchExpressionsCommand"/>
<key id="debuggerSourcesCopyUrl"
key="&debuggerUI.context.copyUrl.key;"
modifiers="accel"
oncommand="DebuggerView.Sources._onCopyUrlCommand()"/>
</keyset>
<vbox id="body"
class="theme-body"
layout="horizontal"
flex="1">
<toolbar id="debugger-toolbar"
class="devtools-toolbar">
<hbox id="debugger-controls"
class="devtools-toolbarbutton-group">
<toolbarbutton id="resume"
class="devtools-toolbarbutton"
tabindex="0"/>
<toolbarbutton id="step-over"
class="devtools-toolbarbutton"
tabindex="0"/>
<toolbarbutton id="step-in"
class="devtools-toolbarbutton"
tabindex="0"/>
<toolbarbutton id="step-out"
class="devtools-toolbarbutton"
tabindex="0"/>
</hbox>
<vbox id="stackframes" flex="1"/>
<textbox id="searchbox"
class="devtools-searchinput" type="search"/>
<toolbarbutton id="instruments-pane-toggle"
class="devtools-toolbarbutton"
tooltiptext="&debuggerUI.panesButton.tooltip;"
tabindex="0"/>
<toolbarbutton id="debugger-options"
class="devtools-toolbarbutton devtools-option-toolbarbutton"
tooltiptext="&debuggerUI.optsButton.tooltip;"
popup="debuggerPrefsContextMenu"
tabindex="0"/>
</toolbar>
<vbox id="globalsearch" orient="vertical" hidden="true"/>
<splitter class="devtools-horizontal-splitter" hidden="true"/>
<hbox id="debugger-widgets" flex="1">
<vbox id="workers-and-sources-pane">
<tabbox id="workers-pane"
class="devtools-sidebar-tabs"
flex="0"
hidden="true">
<tabs>
<tab id="workers-tab"
crop="end"
label="&debuggerUI.tabs.workers;"/>
</tabs>
<tabpanels flex="1">
<tabpanel>
<vbox id="workers" flex="1"/>
</tabpanel>
</tabpanels>
</tabbox>
<splitter id="workers-splitter"
class="devtools-horizontal-splitter"
hidden="true" />
<tabbox id="sources-pane"
class="devtools-sidebar-tabs"
flex="1">
<tabs>
<tab id="sources-tab"
crop="end"
label="&debuggerUI.tabs.sources;"/>
<tab id="callstack-tab"
crop="end"
label="&debuggerUI.tabs.callstack;"/>
</tabs>
<tabpanels flex="1">
<tabpanel id="sources-tabpanel">
<vbox id="sources" flex="1"/>
<toolbar id="sources-toolbar" class="devtools-toolbar">
<hbox id="sources-controls"
class="devtools-toolbarbutton-group">
<toolbarbutton id="black-box"
class="devtools-toolbarbutton"
tooltiptext="&debuggerUI.sources.blackBoxTooltip;"
command="blackBoxCommand"/>
<toolbarbutton id="pretty-print"
class="devtools-toolbarbutton"
tooltiptext="&debuggerUI.sources.prettyPrint;"
command="prettyPrintCommand"
hidden="true"/>
</hbox>
<vbox class="devtools-separator"/>
<toolbarbutton id="toggle-breakpoints"
class="devtools-toolbarbutton"
tooltiptext="&debuggerUI.sources.toggleBreakpoints;"
command="toggleBreakpointsCommand"/>
</toolbar>
</tabpanel>
<tabpanel id="callstack-tabpanel">
<vbox id="callstack-list" flex="1"/>
</tabpanel>
</tabpanels>
</tabbox>
</vbox>
<splitter id="sources-and-editor-splitter"
class="devtools-side-splitter"/>
<vbox id="debugger-content" flex="1">
<hbox id="editor-and-instruments-pane" flex="1">
<deck id="editor-deck" flex="1" class="devtools-main-content">
<vbox id="editor"/>
<vbox id="black-boxed-message"
align="center"
pack="center">
<description id="black-boxed-message-label">
&debuggerUI.blackBoxMessage.label;
</description>
<button id="black-boxed-message-button"
class="devtools-toolbarbutton"
label="&debuggerUI.blackBoxMessage.unBlackBoxButton;"
command="unBlackBoxCommand"/>
</vbox>
<html:div id="source-progress-container"
align="center">
<html:div id="hbox">
<html:progress id="source-progress"></html:progress>
</html:div>
</html:div>
</deck>
<splitter id="editor-and-instruments-splitter"
class="devtools-side-splitter"/>
<tabbox id="instruments-pane"
class="devtools-sidebar-tabs"
hidden="true">
<tabs>
<tab id="variables-tab"
crop="end"
label="&debuggerUI.tabs.variables;"/>
<tab id="events-tab"
crop="end"
label="&debuggerUI.tabs.events;"/>
</tabs>
<tabpanels flex="1">
<tabpanel id="variables-tabpanel">
<vbox id="expressions"/>
<splitter class="devtools-horizontal-splitter"/>
<vbox id="variables" flex="1"/>
</tabpanel>
<tabpanel id="events-tabpanel">
<vbox id="event-listeners" flex="1"/>
</tabpanel>
</tabpanels>
</tabbox>
</hbox>
</vbox>
<splitter id="vertical-layout-splitter"
class="devtools-horizontal-splitter"/>
<hbox id="vertical-layout-panes-container">
<splitter id="sources-and-instruments-splitter"
class="devtools-side-splitter"/>
<!-- The sources-pane and instruments-pane will be moved in this
container if the toolbox's host requires it. -->
</hbox>
</hbox>
</vbox>
<panel id="searchbox-help-panel"
level="top"
type="arrow"
position="before_start"
noautofocus="true"
consumeoutsideclicks="false">
<vbox>
<hbox>
<label id="filter-label"/>
</hbox>
<label id="searchbox-panel-operators"
value="&debuggerUI.searchPanelOperators;"/>
<hbox align="center">
<button id="global-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="globalSearchCommand"/>
<label id="global-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="function-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="functionSearchCommand"/>
<label id="function-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="token-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="tokenSearchCommand"/>
<label id="token-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="line-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="lineSearchCommand"/>
<label id="line-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="variable-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="variableSearchCommand"/>
<label id="variable-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
</vbox>
</panel>
<panel id="conditional-breakpoint-panel"
level="top"
type="arrow"
noautofocus="true"
consumeoutsideclicks="false">
<vbox>
<label id="conditional-breakpoint-panel-description"
value="&debuggerUI.condBreakPanelTitle;"/>
<textbox id="conditional-breakpoint-panel-textbox"/>
</vbox>
</panel>
</window>

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

@ -4,18 +4,12 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'content',
'new'
]
DevToolsModules(
'panel.js'
)
BROWSER_CHROME_MANIFESTS += [
'new/test/mochitest/browser.ini',
'test/mochitest/browser.ini',
'test/mochitest/browser2.ini'
'test/mochitest/browser.ini'
]
with Files('**'):

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

@ -46,12 +46,6 @@ Services.scriptloader.loadSubScript(
const EXAMPLE_URL =
"http://example.com/browser/devtools/client/debugger/new/test/mochitest/examples/";
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
// NOTE: still experimental, the screenshots might not be exactly correct
async function takeScreenshot(dbg) {
let canvas = dbg.win.document.createElementNS(

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

@ -1,185 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
const { Cc, Ci, Cu, Cr } = require("chrome");
const promise = require("promise");
const EventEmitter = require("devtools/shared/event-emitter");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
function DebuggerPanel(iframeWindow, toolbox) {
this.panelWin = iframeWindow;
this._toolbox = toolbox;
this._destroyer = null;
this._view = this.panelWin.DebuggerView;
this._controller = this.panelWin.DebuggerController;
this._view._hostType = this._toolbox.hostType;
this._controller._target = this.target;
this._controller._toolbox = this._toolbox;
this.handleHostChanged = this.handleHostChanged.bind(this);
EventEmitter.decorate(this);
}
exports.DebuggerPanel = DebuggerPanel;
DebuggerPanel.prototype = {
/**
* Open is effectively an asynchronous constructor.
*
* @return object
* A promise that is resolved when the Debugger completes opening.
*/
open: function () {
// Listen for tab switching events to manage focus when the content window
// is paused and events suppressed.
if (this.target.isLocalTab) {
this.target.tab.addEventListener("TabSelect", this);
}
return Promise.resolve(this._controller.startupDebugger())
.then(() => this._controller.connect())
.then(() => {
this._toolbox.on("host-changed", this.handleHostChanged);
// Add keys from this document's keyset to the toolbox, so they
// can work when the split console is focused.
let keysToClone = ["resumeKey", "stepOverKey", "stepInKey", "stepOutKey"];
for (let key of keysToClone) {
let elm = this.panelWin.document.getElementById(key);
let keycode = elm.getAttribute("keycode");
let modifiers = elm.getAttribute("modifiers");
let command = elm.getAttribute("command");
let handler = this._view.Toolbar.getCommandHandler(command);
let keyShortcut = this.translateToKeyShortcut(keycode, modifiers);
this._toolbox.useKeyWithSplitConsole(keyShortcut, handler, "jsdebugger");
}
this.isReady = true;
this.emit("ready");
return this;
})
.catch(function onError(aReason) {
DevToolsUtils.reportException("DebuggerPanel.prototype.open", aReason);
});
},
/**
* Translate a VK_ keycode, with modifiers, to a key shortcut that can be used with
* shared/key-shortcut.
*
* @param {String} keycode
* The VK_* keycode to translate
* @param {String} modifiers
* The list (blank-space separated) of modifiers applying to this keycode.
* @return {String} a key shortcut ready to be used with shared/key-shortcut.js
*/
translateToKeyShortcut: function (keycode, modifiers) {
// Remove the VK_ prefix.
keycode = keycode.replace("VK_", "");
// Translate modifiers
if (modifiers.includes("shift")) {
keycode = "Shift+" + keycode;
}
if (modifiers.includes("alt")) {
keycode = "Alt+" + keycode;
}
if (modifiers.includes("control")) {
keycode = "Ctrl+" + keycode;
}
if (modifiers.includes("meta")) {
keycode = "Cmd+" + keycode;
}
if (modifiers.includes("accel")) {
keycode = "CmdOrCtrl+" + keycode;
}
return keycode;
},
// DevToolPanel API
get target() {
return this._toolbox.target;
},
destroy: function () {
// Make sure this panel is not already destroyed.
if (this._destroyer) {
return this._destroyer;
}
if (!this.target.isRemote) {
this.target.tab.removeEventListener("TabSelect", this);
}
return this._destroyer = this._controller.shutdownDebugger().then(() => {
this.emit("destroyed");
});
},
// DebuggerPanel API
getMappedExpression(expression) {
// No-op implementation since this feature doesn't exist in the older
// debugger implementation.
return null;
},
isPaused() {
let framesController = this.panelWin.DebuggerController.StackFrames;
let thread = framesController.activeThread;
return thread && thread.paused;
},
getFrames() {
let framesController = this.panelWin.DebuggerController.StackFrames;
let thread = framesController.activeThread;
if (this.isPaused()) {
return {
frames: thread.cachedFrames,
selected: framesController.currentFrameDepth,
};
}
return null;
},
addBreakpoint: function (location) {
const { actions } = this.panelWin;
const { dispatch } = this._controller;
return dispatch(actions.addBreakpoint(location));
},
removeBreakpoint: function (location) {
const { actions } = this.panelWin;
const { dispatch } = this._controller;
return dispatch(actions.removeBreakpoint(location));
},
blackbox: function (source, flag) {
const { actions } = this.panelWin;
const { dispatch } = this._controller;
return dispatch(actions.blackbox(source, flag));
},
handleHostChanged: function () {
this._view.handleHostChanged(this._toolbox.hostType);
},
// nsIDOMEventListener API
handleEvent: function (aEvent) {
if (aEvent.target == this.target.tab &&
this._controller.activeThread.state == "paused") {
// Wait a tick for the content focus event to be delivered.
DevToolsUtils.executeSoon(() => this._toolbox.focusTool("jsdebugger"));
}
}
};

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

@ -1,20 +0,0 @@
var { Cc, Ci } = require("chrome");
var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
var observer = {
observe: function () {
debugger;
}
};
observerService.addObserver(observer, "debuggerAttached");
var devtoolsLoaderDestroyObserver = {
observe: function () {
// Remove all observers on devtools:loader:destroy
observerService.removeObserver(observer, "debuggerAttached");
observerService.removeObserver(devtoolsLoaderDestroyObserver, "devtools:loader:destroy");
}
};
observerService.addObserver(devtoolsLoaderDestroyObserver, "devtools:loader:destroy");

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

@ -1,9 +0,0 @@
{
"name": "browser_dbg_addon3",
"title": "browser_dbg_addon3",
"id": "jid1-ami3akps3baaeg",
"description": "a basic add-on",
"author": "",
"license": "MPL 2.0",
"version": "0.1"
}

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

@ -1,34 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function notify() {
// Log objects so makeDebuggeeValue can get the global to use
console.log({ msg: "Hello again" });
}
function startup(aParams, aReason) {
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon4", aParams.resourceURI);
// Load a JS module
ChromeUtils.import("resource://browser_dbg_addon4/test.jsm"); // eslint-disable-line mozilla/no-single-arg-cu-import
// Log objects so makeDebuggeeValue can get the global to use
console.log({ msg: "Hello from the test add-on" });
Services.obs.addObserver(notify, "addon-test-ping");
}
function shutdown(aParams, aReason) {
Services.obs.removeObserver(notify, "addon-test-ping");
// Unload the JS module
Cu.unload("resource://browser_dbg_addon4/test.jsm");
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon4", null);
}

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

@ -1 +0,0 @@
content browser_dbg_addon4 .

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

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>browser_dbg_addon4@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:name>Test add-on with JS Modules</em:name>
<em:bootstrap>true</em:bootstrap>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

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

@ -1,6 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Foo"];
const Foo = {};

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

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul.js"/>
<label value="test.xul"/>
</window>

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

@ -1,6 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Bar"];
const Bar = {};

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

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul2.js"/>
<label value="test2.xul"/>
</window>

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

@ -1,4 +0,0 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

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

@ -1,4 +0,0 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

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

@ -1,21 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function startup(aParams, aReason) {
ChromeUtils.import("resource://gre/modules/Services.jsm");
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon5", aParams.resourceURI);
// Load a JS module
ChromeUtils.import("resource://browser_dbg_addon5/test.jsm");
}
function shutdown(aParams, aReason) {
// Unload the JS module
Cu.unload("resource://browser_dbg_addon5/test.jsm");
let res = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
res.setSubstitution("browser_dbg_addon5", null);
}

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

@ -1 +0,0 @@
content browser_dbg_addon5 .

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

@ -1,20 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>browser_dbg_addon5@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:name>Test unpacked add-on with JS Modules</em:name>
<em:bootstrap>true</em:bootstrap>
<em:unpack>true</em:unpack>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

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

@ -1,6 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Foo"];
const Foo = {};

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

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul.js"/>
<label value="test.xul"/>
</window>

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

@ -1,6 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const EXPORTED_SYMBOLS = ["Bar"];
const Bar = {};

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

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="testxul2.js"/>
<label value="test2.xul"/>
</window>

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

@ -1,4 +0,0 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

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

@ -1,4 +0,0 @@
// Define something in here or the script may get collected
window.addEventListener("unload", function () {
window.foo = "bar";
});

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

@ -1,18 +0,0 @@
{
"manifest_version": 2,
"name": "test content script sources",
"description": "test content script sources",
"version": "0.1.0",
"applications": {
"gecko": {
"id": "test-contentscript-sources@mozilla.com"
}
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["webext-content-script.js"],
"run_at": "document_start"
}
]
}

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

@ -1 +0,0 @@
console.log("CONTENT SCRIPT LOADED");

Двоичный файл не отображается.

Двоичный файл не отображается.

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

@ -7,175 +7,25 @@ subsuite = devtools
skip-if = (os == 'linux' && debug && bits == 32)
support-files =
addon4.xpi
addon5.xpi
addon-webext-contentscript.xpi
addon-source/browser_dbg_addon5/*
code_binary_search.coffee
code_binary_search.js
code_binary_search.map
code_breakpoints-break-on-last-line-of-script-on-reload.js
code_breakpoints-other-tabs.js
code_bug-896139.js
code_frame-script.js
code_function-jump-01.js
code_function-search-01.js
code_function-search-02.js
code_function-search-03.js
code_location-changes.js
code_listworkers-worker1.js
code_listworkers-worker2.js
code_math.js
code_math.map
code_math.min.js
code_math_bogus_map.js
code_same-line-functions.js
code_script-eval.js
code_script-switching-01.js
code_script-switching-02.js
code_test-editor-mode
code_ugly.js
code_ugly-2.js
code_ugly-3.js
code_ugly-4.js
code_ugly-5.js
code_ugly-6.js
code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
code_worker-source-map.coffee
code_worker-source-map.js
code_worker-source-map.js.map
code_WorkerTargetActor.attach-worker1.js
code_WorkerTargetActor.attach-worker2.js
code_WorkerTargetActor.attachThread-worker.js
doc_binary_search.html
doc_breakpoints-break-on-last-line-of-script-on-reload.html
doc_breakpoints-other-tabs.html
doc_breakpoints-reload.html
doc_bug-896139.html
doc_closures.html
doc_closure-optimized-out.html
doc_breakpoint-move.html
doc_conditional-breakpoints.html
doc_domnode-variables.html
doc_editor-mode.html
doc_empty-tab-01.html
doc_empty-tab-02.html
doc_event-listeners-01.html
doc_event-listeners-02.html
doc_event-listeners-03.html
doc_frame-parameters.html
doc_function-display-name.html
doc_function-jump.html
doc_function-search.html
doc_iframes.html
doc_included-script.html
doc_inline-debugger-statement.html
doc_inline-script.html
doc_large-array-buffer.html
doc_listworkers-tab.html
doc_map-set.html
doc_minified.html
doc_minified_bogus_map.html
doc_native-event-handler.html
doc_no-page-sources.html
doc_pause-exceptions.html
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
doc_promise.html
doc_proxy.html
doc_random-javascript.html
doc_recursion-stack.html
doc_scope-variable.html
doc_scope-variable-2.html
doc_scope-variable-3.html
doc_scope-variable-4.html
doc_script-eval.html
doc_script-bookmarklet.html
doc_script-switching-01.html
doc_script-switching-02.html
doc_script_webext_contentscript.html
doc_split-console-paused-reload.html
doc_step-many-statements.html
doc_step-out.html
doc_terminate-on-tab-close.html
doc_watch-expressions.html
doc_watch-expression-button.html
doc_whitespace-property-names.html
doc_with-frame.html
doc_worker-source-map.html
doc_WorkerTargetActor.attach-tab1.html
doc_WorkerTargetActor.attach-tab2.html
doc_WorkerTargetActor.attachThread-tab.html
head.js
sjs_post-page.sjs
sjs_random-javascript.sjs
testactors.js
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
[browser_dbg_aaa_run_first_leaktest.js]
skip-if = e10s && debug
[browser_dbg_addon-modules.js]
skip-if = e10s # TODO
tags = addons
[browser_dbg_addon-modules-unpacked.js]
skip-if = e10s # TODO
tags = addons
[browser_dbg_addon-console.js]
skip-if = e10s && debug || os == 'win' || verify # bug 1005274
skip-if = (e10s && debug || os == 'win' || verify) || true # bug 1005274
tags = addons
[browser_dbg_bfcache.js]
skip-if = e10s || true # bug 1113935
[browser_dbg_break-in-anon.js]
[browser_dbg_break-on-next.js]
skip-if = true # Bug 1437712
[browser_dbg_break-on-next-console.js]
uses-unsafe-cpows = true
[browser_dbg_break-unselected.js]
[browser_dbg_breakpoints-editor.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-eval.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-new-script.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-other-tabs.js]
skip-if = e10s && debug
[browser_dbg_bug-896139.js]
skip-if = e10s && debug
[browser_dbg_clean-exit.js]
skip-if = true # Bug 1044985 (racy test)
[browser_dbg_closure-inspection.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-01.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-02.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-03.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-04.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-05.js]
skip-if = e10s && debug
[browser_dbg_console-eval.js]
skip-if = e10s && debug
[browser_dbg_console-named-eval.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-01.js]
skip-if = e10s && debug || (os == "linux") # Bug 1468669
[browser_dbg_server-conditional-bp-02.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-03.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-04.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-05.js]
skip-if = e10s && debug
[browser_dbg_controller-evaluate-01.js]
skip-if = e10s && debug
[browser_dbg_controller-evaluate-02.js]
skip-if = e10s && debug
[browser_dbg_debugger-statement.js]
skip-if = e10s && debug
[browser_dbg_event-listeners-01.js]
@ -184,14 +34,21 @@ skip-if = e10s && debug
skip-if = e10s && debug
[browser_dbg_event-listeners-03.js]
skip-if = e10s && debug
[browser_dbg_file-reload.js]
skip-if = e10s && debug
[browser_dbg_host-layout.js]
skip-if = e10s && debug
[browser_dbg_jump-to-function-definition.js]
skip-if = e10s && debug
[browser_dbg_iframes.js]
skip-if = e10s # TODO
[browser_dbg_interrupts.js]
skip-if = e10s && debug
[browser_dbg_listworkers.js]
[browser_dbg_promises-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_promises-chrome-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = true # Bug 1177730
[browser_dbg_promises-fulfillment-stack.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_promises-rejection-stack.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_terminate-on-tab-close.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_worker-window.js]
skip-if = (e10s && debug) || true # Bug 1486974

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

@ -1,169 +0,0 @@
# Tests in this directory are split into two manifests (this and browser.ini)
# to facilitate better chunking; see bug 1294489.
[DEFAULT]
tags = devtools
subsuite = devtools
skip-if = (os == 'linux' && debug && bits == 32)
support-files =
addon4.xpi
addon5.xpi
addon-webext-contentscript.xpi
addon-source/browser_dbg_addon5/*
code_binary_search.coffee
code_binary_search.js
code_binary_search.map
code_breakpoints-break-on-last-line-of-script-on-reload.js
code_breakpoints-other-tabs.js
code_bug-896139.js
code_frame-script.js
code_function-jump-01.js
code_function-search-01.js
code_function-search-02.js
code_function-search-03.js
code_location-changes.js
code_listworkers-worker1.js
code_listworkers-worker2.js
code_math.js
code_math.map
code_math.min.js
code_math_bogus_map.js
code_same-line-functions.js
code_script-eval.js
code_script-switching-01.js
code_script-switching-02.js
code_test-editor-mode
code_ugly.js
code_ugly-2.js
code_ugly-3.js
code_ugly-4.js
code_ugly-5.js
code_ugly-6.js
code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
code_worker-source-map.coffee
code_worker-source-map.js
code_worker-source-map.js.map
code_WorkerTargetActor.attach-worker1.js
code_WorkerTargetActor.attach-worker2.js
code_WorkerTargetActor.attachThread-worker.js
doc_binary_search.html
doc_breakpoints-break-on-last-line-of-script-on-reload.html
doc_breakpoints-other-tabs.html
doc_breakpoints-reload.html
doc_bug-896139.html
doc_closures.html
doc_closure-optimized-out.html
doc_breakpoint-move.html
doc_conditional-breakpoints.html
doc_domnode-variables.html
doc_editor-mode.html
doc_empty-tab-01.html
doc_empty-tab-02.html
doc_event-listeners-01.html
doc_event-listeners-02.html
doc_event-listeners-03.html
doc_frame-parameters.html
doc_function-display-name.html
doc_function-jump.html
doc_function-search.html
doc_iframes.html
doc_included-script.html
doc_inline-debugger-statement.html
doc_inline-script.html
doc_large-array-buffer.html
doc_listworkers-tab.html
doc_map-set.html
doc_minified.html
doc_minified_bogus_map.html
doc_native-event-handler.html
doc_no-page-sources.html
doc_pause-exceptions.html
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
doc_promise.html
doc_proxy.html
doc_random-javascript.html
doc_recursion-stack.html
doc_scope-variable.html
doc_scope-variable-2.html
doc_scope-variable-3.html
doc_scope-variable-4.html
doc_script-eval.html
doc_script-bookmarklet.html
doc_script-switching-01.html
doc_script-switching-02.html
doc_script_webext_contentscript.html
doc_split-console-paused-reload.html
doc_step-many-statements.html
doc_step-out.html
doc_terminate-on-tab-close.html
doc_watch-expressions.html
doc_watch-expression-button.html
doc_whitespace-property-names.html
doc_with-frame.html
doc_worker-source-map.html
doc_WorkerTargetActor.attach-tab1.html
doc_WorkerTargetActor.attach-tab2.html
doc_WorkerTargetActor.attachThread-tab.html
head.js
sjs_post-page.sjs
sjs_random-javascript.sjs
testactors.js
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
[browser_dbg_on-pause-raise.js]
uses-unsafe-cpows = true
skip-if = e10s && debug || os == "linux" # Bug 888811 & bug 891176
[browser_dbg_optimized-out-vars.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_pause-resume.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_pause-warning.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_paused-keybindings.js]
skip-if = e10s
[browser_dbg_post-page.js]
uses-unsafe-cpows = true
[browser_dbg_progress-listener-bug.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_promises-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_promises-chrome-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = true # Bug 1177730
[browser_dbg_promises-fulfillment-stack.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_promises-rejection-stack.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_sources-cache.js]
uses-unsafe-cpows = true
[browser_dbg_sources-iframe-reload.js]
uses-unsafe-cpows = true
skip-if = (os == "linux" && debug && bits == 64) #Bug 1455225, disable on Linux x64 debug for frequent failures
[browser_dbg_sources-bookmarklet.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_split-console-paused-reload.js]
skip-if = true # Bug 1288348 - previously e10s && debug
[browser_dbg_terminate-on-tab-close.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_worker-source-map.js]
uses-unsafe-cpows = true
skip-if = e10s && debug
[browser_dbg_worker-window.js]
skip-if = (e10s && debug) || true # Bug 1486974
[browser_dbg_split-console-keypress.js]
uses-unsafe-cpows = true
skip-if = (debug || os == "linux") # Bug 1214439

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

@ -1,33 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This tests if the debugger leaks on initialization and sudden destruction.
* You can also use this initialization format as a template for other tests.
* If leaks happen here, there's something very, very fishy going on.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
// Wait longer for this very simple test that comes first, to make sure that
// GC from previous tests does not interfere with the debugger suite.
requestLongerTimeout(2);
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
ok(aTab, "Should have a tab available.");
ok(aPanel, "Should have a debugger pane available.");
waitForSourceAndCaretAndScopes(aPanel, "-02.js", 1).then(() => {
resumeDebuggerThenCloseAndFinish(aPanel);
});
callInTab(aTab, "firstCall");
});
}

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

@ -1,67 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Make sure the add-on actor can see loaded JS Modules from an add-on
const ADDON_ID = "browser_dbg_addon5@tests.mozilla.org";
const ADDON_PATH = "addon-source/browser_dbg_addon5/";
const ADDON_URL = getTemporaryAddonURLFromPath(ADDON_PATH);
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let tab1 = yield addTab("chrome://browser_dbg_addon5/content/test.xul");
let addonDebugger = yield initAddonDebugger(ADDON_ID);
is(addonDebugger.title,
`Developer Tools - Test unpacked add-on with JS Modules - ${ADDON_URL}`,
"Saw the right toolbox title.");
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
is(sources.length, 3, "Should be three sources");
ok(sources[0].url.endsWith("/browser_dbg_addon5/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
// Load a new module and tab and check they appear in the list of sources
ChromeUtils.import("resource://browser_dbg_addon5/test2.jsm", {});
let tab2 = yield addTab("chrome://browser_dbg_addon5/content/test2.xul");
groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
sources = groups[0].sources;
is(sources.length, 5, "Should be five sources");
ok(sources[0].url.endsWith("/browser_dbg_addon5/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
is(sources[3].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code");
is(sources[3].label, "test2.jsm", "correct label for addon code");
is(sources[4].url, "chrome://browser_dbg_addon5/content/testxul2.js", "correct url for addon tab code");
is(sources[4].label, "testxul2.js", "correct label for addon tab code");
Cu.unload("resource://browser_dbg_addon5/test2.jsm");
yield addonDebugger.destroy();
yield removeTab(tab1);
yield removeTab(tab2);
yield removeAddon(addon);
finish();
});
}

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

@ -1,66 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Make sure the add-on actor can see loaded JS Modules from an add-on
const ADDON_ID = "browser_dbg_addon4@tests.mozilla.org";
const ADDON_PATH = "addon4.xpi";
const ADDON_URL = getTemporaryAddonURLFromPath(ADDON_PATH);
function test() {
Task.spawn(function* () {
let addon = yield addTemporaryAddon(ADDON_PATH);
let tab1 = yield addTab("chrome://browser_dbg_addon4/content/test.xul");
let addonDebugger = yield initAddonDebugger(ADDON_ID);
is(addonDebugger.title, `Developer Tools - Test add-on with JS Modules - ${ADDON_URL}`,
"Saw the right toolbox title.");
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
is(sources.length, 3, "Should be three sources");
ok(sources[0].url.endsWith("/addon4.xpi!/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
// Load a new module and tab and check they appear in the list of sources
ChromeUtils.import("resource://browser_dbg_addon4/test2.jsm", {});
let tab2 = yield addTab("chrome://browser_dbg_addon4/content/test2.xul");
groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
is(groups[1].name, "chrome://global", "XUL code should be the second group");
is(groups.length, 2, "Should be only two groups.");
sources = groups[0].sources;
is(sources.length, 5, "Should be five sources");
ok(sources[0].url.endsWith("/addon4.xpi!/bootstrap.js"), "correct url for bootstrap code");
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code");
is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code");
is(sources[1].label, "test.jsm", "correct label for addon code");
is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code");
is(sources[2].label, "testxul.js", "correct label for addon tab code");
is(sources[3].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code");
is(sources[3].label, "test2.jsm", "correct label for addon code");
is(sources[4].url, "chrome://browser_dbg_addon4/content/testxul2.js", "correct url for addon tab code");
is(sources[4].label, "testxul2.js", "correct label for addon tab code");
Cu.unload("resource://browser_dbg_addon4/test2.jsm");
yield addonDebugger.destroy();
yield removeTab(tab1);
yield removeTab(tab2);
yield removeAddon(addon);
finish();
});
}

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

@ -1,98 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the debugger is updated with the correct sources when moving
* back and forward in the tab.
*/
const TAB_URL_1 = EXAMPLE_URL + "doc_script-switching-01.html";
const TAB_URL_2 = EXAMPLE_URL + "doc_recursion-stack.html";
var gTab, gPanel, gDebugger;
var gSources;
const test = Task.async(function* () {
info("Starting browser_dbg_bfcache.js's `test`.");
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
([gTab, gPanel]) = yield initDebugger(TAB_URL_1, options);
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
yield testFirstPage();
yield testLocationChange();
yield testBack();
yield testForward();
return closeDebuggerAndFinish(gPanel);
});
function testFirstPage() {
info("Testing first page.");
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
ContentTask.spawn(gTab.linkedBrowser, null, async () => {
content.wrappedJSObject.firstCall();
});
});
return waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
.then(validateFirstPage);
}
function testLocationChange() {
info("Navigating to a different page.");
return navigateActiveTabTo(gPanel,
TAB_URL_2,
gDebugger.EVENTS.SOURCES_ADDED)
.then(validateSecondPage);
}
function testBack() {
info("Going back.");
return navigateActiveTabInHistory(gPanel,
"back",
gDebugger.EVENTS.SOURCES_ADDED)
.then(validateFirstPage);
}
function testForward() {
info("Going forward.");
return navigateActiveTabInHistory(gPanel,
"forward",
gDebugger.EVENTS.SOURCES_ADDED)
.then(validateSecondPage);
}
function validateFirstPage() {
is(gSources.itemCount, 2,
"Found the expected number of sources.");
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-01.js"),
"Found the first source label.");
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-02.js"),
"Found the second source label.");
}
function validateSecondPage() {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
ok(gSources.getItemForAttachment(e => e.label == "doc_recursion-stack.html"),
"Found the single source label.");
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gSources = null;
});

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

@ -1,40 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure anonymous eval scripts can still break with a `debugger`
* statement
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
const options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
return Task.spawn(function* () {
is(gSources.values.length, 1, "Should have 1 source");
callInTab(gTab, "evalSourceWithDebugger");
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
is(gSources.values.length, 2, "Should have 2 sources");
let item = gSources.getItemForAttachment(e => e.label.indexOf("SCRIPT") === 0);
ok(item, "Source label is incorrect.");
is(item.attachment.group, gDebugger.L10N.getStr("anonymousSourcesLabel"),
"Source group is incorrect");
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,61 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if 'break on next' functionality works from executions
* in content triggered by the console in the toolbox.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
let options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gTarget = gDebugger.gTarget;
gThreadClient = gDebugger.gThreadClient;
gResumeButton = gDebugger.document.getElementById("resume");
gResumeKey = gDebugger.document.getElementById("resumeKey");
testConsole()
.then(() => closeDebuggerAndFinish(gPanel));
});
let testConsole = Task.async(function* () {
info("Starting testConsole");
let oncePaused = gTarget.once("thread-paused");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
let jsterm = yield getSplitConsole(gDevTools.getToolbox(gPanel.target));
let executed = jsterm.execute("1+1");
yield oncePaused;
let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
let variables = gDebugger.DebuggerView.Variables;
is(variables._store.length, 3, "Correct number of scopes available");
is(variables.getScopeAtIndex(0).name, "With scope [Object]",
"Paused with correct scope (0)");
is(variables.getScopeAtIndex(1).name, "Block scope",
"Paused with correct scope (1)");
is(variables.getScopeAtIndex(2).name, "Global scope [Window]",
"Paused with correct scope (2)");
let onceResumed = gTarget.once("thread-resumed");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield onceResumed;
yield executed;
});
}

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

@ -1,103 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if 'break on next' functionality works from executions
* in content that are triggered by the page.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
const options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gTarget = gDebugger.gTarget;
gThreadClient = gDebugger.gThreadClient;
gResumeButton = gDebugger.document.getElementById("resume");
gResumeKey = gDebugger.document.getElementById("resumeKey");
testInterval()
.then(testEvent)
.then(() => closeDebuggerAndFinish(gPanel));
});
// Testing an interval instead of a timeout / rAF because
// it's less likely to fail due to timing issues. If the
// first callback happens to fire before the break request
// happens then we'll just get it next time.
let testInterval = Task.async(function* () {
info("Starting testInterval");
yield evalInTab(gTab, `
var interval = setInterval(function() {
return 1+1;
}, 100);
`);
let oncePaused = gTarget.once("thread-paused");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield oncePaused;
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
let variables = gDebugger.DebuggerView.Variables;
is(variables._store.length, 3, "Correct number of scopes available");
is(variables.getScopeAtIndex(0).name, "Function scope [interval<]",
"Paused with correct scope (0)");
is(variables.getScopeAtIndex(1).name, "Block scope",
"Paused with correct scope (1)");
is(variables.getScopeAtIndex(2).name, "Global scope [Window]",
"Paused with correct scope (2)");
yield evalInTab(gTab, "clearInterval(interval)");
let onceResumed = gTarget.once("thread-resumed");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield onceResumed;
});
let testEvent = Task.async(function* () {
info("Starting testEvent");
let oncePaused = gTarget.once("thread-paused");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
once(gDebugger.gClient, "willInterrupt").then(() => {
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
});
yield oncePaused;
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
let variables = gDebugger.DebuggerView.Variables;
is(variables._store.length, 6, "Correct number of scopes available");
is(variables.getScopeAtIndex(0).name, "Function scope [onclick]",
"Paused with correct scope (0)");
// Non-syntactic lexical scope introduced by non-syntactic scope chain.
is(variables.getScopeAtIndex(1).name, "Block scope",
"Paused with correct scope (1)");
is(variables.getScopeAtIndex(2).name, "With scope [HTMLButtonElement]",
"Paused with correct scope (2)");
is(variables.getScopeAtIndex(3).name, "With scope [HTMLDocument]",
"Paused with correct scope (3)");
// Global lexical scope.
is(variables.getScopeAtIndex(4).name, "Block scope",
"Paused with correct scope (4)");
is(variables.getScopeAtIndex(5).name, "Global scope [Window]",
"Paused with correct scope (5)");
let onceResumed = gTarget.once("thread-resumed");
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
yield onceResumed;
});
}

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

@ -1,48 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test breaking in code and jumping to the debugger before
* the debugger UI has been initialized.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
Task.spawn(function* () {
const tab = yield getTab(TAB_URL);
const target = yield TargetFactory.forTab(tab);
const toolbox = yield gDevTools.showToolbox(target, "webconsole");
is(toolbox.currentToolId, "webconsole", "Console is the current panel");
toolbox.target.on("thread-paused", Task.async(function* () {
// Wait for the toolbox to handle the event and switch tools
yield waitForTick();
is(toolbox.currentToolId, "jsdebugger", "Debugger is the current panel");
// Wait until it's actually fully loaded
yield toolbox.loadTool("jsdebugger");
const panel = toolbox.getCurrentPanel();
const queries = panel.panelWin.require("./content/queries");
const getState = panel.panelWin.DebuggerController.getState;
is(panel.panelWin.gThreadClient.state, "paused",
"Thread is still paused");
yield waitForSourceAndCaret(panel, "debugger-statement.html", 16);
is(queries.getSelectedSource(getState()).url, TAB_URL,
"Selected source is the current tab url");
is(queries.getSelectedSourceOpts(getState()).line, 16,
"Line 16 is highlighted in the editor");
resumeDebuggerThenCloseAndFinish(panel);
}));
callInTab(tab, "runDebuggerStatement");
});
}

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

@ -1,235 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 723069: Test the debugger breakpoint API and connection to the
* source editor.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
Task.spawn(function* () {
yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 2,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("debugger"), 166,
"The correct source was loaded initially.");
is(queries.getSelectedSource(getState()).actor, gSources.values[1],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
info("Add the first breakpoint.");
gEditor.once("breakpointAdded", onEditorBreakpointAddFirst);
let location = { actor: gSources.selectedValue, line: 6 };
yield actions.addBreakpoint(location);
checkFirstBreakpoint(location);
info("Remove the first breakpoint.");
gEditor.once("breakpointRemoved", onEditorBreakpointRemoveFirst);
yield actions.removeBreakpoint(location);
checkFirstBreakpointRemoved(location);
checkBackgroundBreakpoint(yield testBreakpointAddBackground());
info("Switch to the first source, which is not yet selected");
gEditor.once("breakpointAdded", onEditorBreakpointAddSwitch);
gEditor.once("change", onEditorTextChanged);
actions.selectSource(gSources.items[0].attachment.source);
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
onReadyForClick();
});
callInTab(gTab, "firstCall");
let breakpointsAdded = 0;
let breakpointsRemoved = 0;
let editorBreakpointChanges = 0;
function onEditorBreakpointAddFirst(aLine) {
editorBreakpointChanges++;
info("breakpoint1 added to the editor.");
is(aLine, 5,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct.");
}
function onEditorBreakpointRemoveFirst(aLine) {
editorBreakpointChanges++;
info("breakpoint1 removed from the editor.");
is(aLine, 5,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 0,
"editor.getBreakpoints().length is correct.");
}
function checkFirstBreakpoint(location) {
breakpointsAdded++;
const bp = queries.getBreakpoint(getState(), location);
ok(bp,
"breakpoint1 exists");
is(bp.location.actor, queries.getSelectedSource(getState()).actor,
"breakpoint1 actor is correct.");
is(bp.location.line, 6,
"breakpoint1 line is correct.");
is(queries.getBreakpoints(getState()).length, 1,
"The list of added breakpoints holds only one breakpoint.");
is(queries.getSelectedSource(getState()).actor, gSources.values[1],
"The second source should be currently selected.");
}
function checkFirstBreakpointRemoved(location) {
breakpointsRemoved++;
const bp = queries.getBreakpoint(getState(), location);
ok(!bp, "breakpoint1 removed");
}
function testBreakpointAddBackground() {
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
is(gSources.values[1], gSources.selectedValue,
"The second source should be currently selected.");
info("Add a breakpoint to the first source, which is not selected.");
let location = { actor: gSources.values[0], line: 5 };
gEditor.on("breakpointAdded", onEditorBreakpointAddBackgroundTrap);
return actions.addBreakpoint(location).then(() => location);
}
function onEditorBreakpointAddBackgroundTrap() {
// Trap listener: no breakpoint must be added to the editor when a
// breakpoint is added to a source that is not currently selected.
editorBreakpointChanges++;
ok(false, "breakpoint2 must not be added to the editor.");
}
function checkBackgroundBreakpoint(location) {
breakpointsAdded++;
const bp = queries.getBreakpoint(getState(), location);
ok(bp,
"breakpoint2 added, client received");
is(bp.location.actor, gSources.values[0],
"breakpoint2 client url is correct.");
is(bp.location.line, 5,
"breakpoint2 client line is correct.");
ok(queries.getBreakpoint(getState(), bp.location),
"breakpoint2 found in the list of added breakpoints.");
is(queries.getBreakpoints(getState()).length, 1,
"The list of added breakpoints holds only one breakpoint.");
is(queries.getSelectedSource(getState()).actor, gSources.values[1],
"The second source should be currently selected.");
// Remove the trap listener.
gEditor.off("breakpointAdded", onEditorBreakpointAddBackgroundTrap);
}
function onEditorBreakpointAddSwitch(aLine) {
editorBreakpointChanges++;
info("breakpoint2 added to the editor.");
is(aLine, 4,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct");
}
function onEditorTextChanged() {
// Wait for the actual text to be shown.
if (gEditor.getText() == gDebugger.L10N.getStr("loadingText"))
return void gEditor.once("change", onEditorTextChanged);
is(gEditor.getText().indexOf("debugger"), -1,
"The second source is no longer displayed.");
is(gEditor.getText().indexOf("firstCall"), 118,
"The first source is displayed.");
is(gSources.values[0], gSources.selectedValue,
"The first source should be currently selected.");
}
function onReadyForClick() {
info("Remove the second breakpoint using the mouse.");
gEditor.once("breakpointRemoved", onEditorBreakpointRemoveSecond);
let iframe = gEditor.container;
let testWin = iframe.ownerDocument.defaultView;
// Flush the layout for the iframe.
info("rect " + iframe.contentDocument.documentElement.getBoundingClientRect());
let utils = testWin.windowUtils;
let coords = gEditor.getCoordsFromPosition({ line: 4, ch: 0 });
let rect = iframe.getBoundingClientRect();
let left = rect.left + 10;
let top = rect.top + coords.top + 4;
utils.sendMouseEventToWindow("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEventToWindow("mouseup", left, top, 0, 1, 0, false, 0, 0);
}
function onEditorBreakpointRemoveSecond(aLine) {
editorBreakpointChanges++;
info("breakpoint2 removed from the editor.");
is(aLine, 4,
"Editor breakpoint line is correct.");
is(gEditor.getBreakpoints().length, 0,
"editor.getBreakpoints().length is correct.");
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
finalCheck();
closeDebuggerAndFinish(gPanel);
});
gDebugger.gThreadClient.resume();
}
function finalCheck() {
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
is(breakpointsAdded, 2,
"Correct number of breakpoints have been added.");
is(breakpointsRemoved, 1,
"Correct number of breakpoints have been removed.");
is(editorBreakpointChanges, 4,
"Correct number of editor breakpoint changes.");
}
});
}

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

@ -1,47 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test setting breakpoints on an eval script
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let options = {
source: EXAMPLE_URL + "code_script-eval.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const actions = bindActionCreators(gPanel);
Task.spawn(function* () {
let newSource = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.NEW_SOURCE);
callInTab(gTab, "evalSourceWithSourceURL");
yield newSource;
// Wait for it to be added to the UI
yield waitForTick();
const newSourceActor = getSourceActor(gSources, EXAMPLE_URL + "bar.js");
yield actions.addBreakpoint({
actor: newSourceActor,
line: 2
});
yield ensureThreadClientState(gPanel, "resumed");
const paused = waitForThreadEvents(gPanel, "paused");
callInTab(gTab, "bar");
let frame = (yield paused).frame;
is(frame.where.source.actor, newSourceActor, "Should have broken on the eval'ed source");
is(frame.where.line, 2, "Should break on line 2");
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,92 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 771452: Make sure that setting a breakpoint in an inline source doesn't
* add it twice.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require('./content/queries');
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function testResume() {
const deferred = promise.defer();
is(gDebugger.gThreadClient.state, "paused",
"The breakpoint wasn't hit yet.");
gDebugger.gThreadClient.resume(() => {
gDebugger.gThreadClient.addOneTimeListener("paused", (aEvent, aPacket) => {
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
is(aPacket.why.type, "breakpoint",
"Execution has advanced to the next breakpoint.");
isnot(aPacket.why.type, "debuggerStatement",
"The breakpoint was hit before the debugger statement.");
ok(isCaretPos(gPanel, 20),
"The source editor caret position is incorrect (2).");
deferred.resolve();
});
});
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
});
return deferred.promise;
}
function testBreakpointHit() {
const deferred = promise.defer();
is(gDebugger.gThreadClient.state, "paused",
"The breakpoint was hit.");
gDebugger.gThreadClient.addOneTimeListener("paused", (aEvent, aPacket) => {
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
is(aPacket.why.type, "debuggerStatement",
"Execution has advanced to the next line.");
isnot(aPacket.why.type, "breakpoint",
"No ghost breakpoint was hit.");
ok(isCaretPos(gPanel, 20),
"The source editor caret position is incorrect (3).");
deferred.resolve();
});
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return deferred.promise;
}
(async function(){
let onCaretUpdated = waitForCaretAndScopes(gPanel, 16);
callInTab(gTab, "runDebuggerStatement");
await onCaretUpdated;
is(gDebugger.gThreadClient.state, "paused",
"The debugger statement was reached.");
ok(isCaretPos(gPanel, 16),
"The source editor caret position is incorrect (1).");
await actions.addBreakpoint({ actor: getSourceActor(gSources, TAB_URL), line: 20 });
await testResume();
await testBreakpointHit();
resumeDebuggerThenCloseAndFinish(gPanel);
})();
});
}

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

@ -1,41 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint in one tab, doesn't cause another tab at
* the same source to pause at that location.
*/
const TAB_URL = EXAMPLE_URL + "doc_breakpoints-other-tabs.html";
var test = Task.async(function* () {
const options = {
source: EXAMPLE_URL + "code_breakpoints-other-tabs.js",
line: 1
};
const [tab1, panel1] = yield initDebugger(TAB_URL, options);
const [tab2, panel2] = yield initDebugger(TAB_URL, options);
const queries = panel1.panelWin.require("./content/queries");
const actions = bindActionCreators(panel1);
const getState = panel1.panelWin.DebuggerController.getState;
const sources = panel1.panelWin.DebuggerView.Sources;
yield actions.addBreakpoint({
actor: queries.getSelectedSource(getState()).actor,
line: 2
});
const paused = waitForThreadEvents(panel2, "paused");
callInTab(tab2, "testCase");
const packet = yield paused;
is(packet.why.type, "debuggerStatement",
"Should have stopped at the debugger statement, not the other tab's breakpoint");
is(packet.frame.where.line, 3,
"Should have stopped at line 3 (debugger statement), not line 2 (other tab's breakpoint)");
yield resumeDebuggerThenCloseAndFinish(panel2);
});

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

@ -1,48 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 896139 - Breakpoints not triggering when reloading script.
*/
const TAB_URL = EXAMPLE_URL + "doc_bug-896139.html";
const SCRIPT_URL = EXAMPLE_URL + "code_bug-896139.js";
function test() {
Task.spawn(function* () {
function testBreakpoint() {
let promise = waitForDebuggerEvents(panel, win.EVENTS.FETCHED_SCOPES);
callInTab(tab, "f");
return promise.then(() => doResume(panel));
}
let options = {
source: SCRIPT_URL,
line: 1
};
let [tab, panel] = yield initDebugger(TAB_URL, options);
let win = panel.panelWin;
let Sources = win.DebuggerView.Sources;
yield panel.addBreakpoint({
actor: getSourceActor(win.DebuggerView.Sources, SCRIPT_URL),
line: 6
});
// Race condition: the setBreakpoint request sometimes leaves the
// debugger in paused state for a bit because we are called before
// that request finishes (see bug 1156531 for plans to fix)
if (panel.panelWin.gThreadClient.state !== "attached") {
yield waitForThreadEvents(panel, "resumed");
}
yield testBreakpoint();
yield reloadActiveTab(panel, win.EVENTS.SOURCE_SHOWN);
yield testBreakpoint();
yield closeDebuggerAndFinish(panel);
});
}

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

@ -1,44 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that closing a tab with the debugger in a paused state exits cleanly.
*/
var gTab, gPanel, gDebugger;
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
const options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
testCleanExit();
});
}
function testCleanExit() {
promise.all([
waitForSourceAndCaretAndScopes(gPanel, ".html", 16),
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED)
]).then(() => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after the debugger statement.");
}).then(() => closeDebuggerAndFinish(gPanel, { whilePaused: true }));
callInTab(gTab, "runDebuggerStatement");
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
});

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

@ -1,153 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const TAB_URL = EXAMPLE_URL + "doc_closures.html";
// Test that inspecting a closure works as expected.
function test() {
let gPanel, gTab, gDebugger;
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
testClosure()
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
function testClosure() {
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
let gVars = gDebugger.DebuggerView.Variables;
let localScope = gVars.getScopeAtIndex(0);
let localNodes = localScope.target.querySelector(".variables-view-element-details").childNodes;
is(localNodes[4].querySelector(".name").getAttribute("value"), "person",
"Should have the right property name for |person|.");
is(localNodes[4].querySelector(".value").getAttribute("value"), "Object",
"Should have the right property value for |person|.");
// Expand the 'person' tree node. This causes its properties to be
// retrieved and displayed.
let personNode = gVars.getItemForNode(localNodes[4]);
let personFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES);
personNode.expand();
return personFetched.then(() => {
is(personNode.expanded, true,
"|person| should be expanded at this point.");
is(personNode.get("getName").target.querySelector(".name")
.getAttribute("value"), "getName",
"Should have the right property name for 'getName' in person.");
is(personNode.get("getName").target.querySelector(".value")
.getAttribute("value"), "getName()",
"'getName' in person should have the right value.");
is(personNode.get("getFoo").target.querySelector(".name")
.getAttribute("value"), "getFoo",
"Should have the right property name for 'getFoo' in person.");
is(personNode.get("getFoo").target.querySelector(".value")
.getAttribute("value"), "getFoo()",
"'getFoo' in person should have the right value.");
// Expand the function nodes. This causes their properties to be
// retrieved and displayed.
let getFooNode = personNode.get("getFoo");
let getNameNode = personNode.get("getName");
let funcsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
let funcClosuresFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES, 2);
getFooNode.expand();
getNameNode.expand();
return funcsFetched.then(() => {
is(getFooNode.expanded, true,
"|person.getFoo| should be expanded at this point.");
is(getNameNode.expanded, true,
"|person.getName| should be expanded at this point.");
is(getFooNode.get("<Closure>").target.querySelector(".name")
.getAttribute("value"), "<Closure>",
"Found the closure node for getFoo.");
is(getFooNode.get("<Closure>").target.querySelector(".value")
.getAttribute("value"), "",
"The closure node has no value for getFoo.");
is(getNameNode.get("<Closure>").target.querySelector(".name")
.getAttribute("value"), "<Closure>",
"Found the closure node for getName.");
is(getNameNode.get("<Closure>").target.querySelector(".value")
.getAttribute("value"), "",
"The closure node has no value for getName.");
// Expand the closure nodes. This causes their environments to be
// retrieved and displayed.
let getFooClosure = getFooNode.get("<Closure>");
let getNameClosure = getNameNode.get("<Closure>");
getFooClosure.expand();
getNameClosure.expand();
return funcClosuresFetched.then(() => {
is(getFooClosure.expanded, true,
"|person.getFoo| closure should be expanded at this point.");
is(getNameClosure.expanded, true,
"|person.getName| closure should be expanded at this point.");
is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".name")
.getAttribute("value"), "Function scope [_pfactory]",
"Found the function scope node for the getFoo closure.");
is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".value")
.getAttribute("value"), "",
"The function scope node has no value for the getFoo closure.");
is(getNameClosure.get("Function scope [_pfactory]").target.querySelector(".name")
.getAttribute("value"), "Function scope [_pfactory]",
"Found the function scope node for the getName closure.");
is(getNameClosure.get("Function scope [_pfactory]").target.querySelector(".value")
.getAttribute("value"), "",
"The function scope node has no value for the getName closure.");
// Expand the scope nodes.
let getFooInnerScope = getFooClosure.get("Function scope [_pfactory]");
let getNameInnerScope = getNameClosure.get("Function scope [_pfactory]");
let innerFuncsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
getFooInnerScope.expand();
getNameInnerScope.expand();
return funcsFetched.then(() => {
is(getFooInnerScope.expanded, true,
"|person.getFoo| inner scope should be expanded at this point.");
is(getNameInnerScope.expanded, true,
"|person.getName| inner scope should be expanded at this point.");
// Only test that each function closes over the necessary variable.
// We wouldn't want future SpiderMonkey closure space
// optimizations to break this test.
is(getFooInnerScope.get("foo").target.querySelector(".name")
.getAttribute("value"), "foo",
"Found the foo node for the getFoo inner scope.");
is(getFooInnerScope.get("foo").target.querySelector(".value")
.getAttribute("value"), "10",
"The foo node has the expected value.");
is(getNameInnerScope.get("name").target.querySelector(".name")
.getAttribute("value"), "name",
"Found the name node for the getName inner scope.");
is(getNameInnerScope.get("name").target.querySelector(".value")
.getAttribute("value"), '"Bob"',
"The name node has the expected value.");
});
});
});
});
});
}
}

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

@ -1,218 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 740825: Test the debugger conditional breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
// Linux debug test slaves are a bit slow at this test sometimes.
requestLongerTimeout(2);
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
const addBreakpoints = Task.async(function* () {
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 },
"undefined");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 19 },
"null");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 20 },
"42");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 21 },
"true");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 22 },
"'nasu'");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 23 },
"/regexp/");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 24 },
"({})");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 25 },
"(function() {})");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 26 },
"(function() { return false; })()");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 27 },
"a");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 28 },
"a !== undefined");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 29 },
"b");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 30 },
"a !== null");
});
function resumeAndTestBreakpoint(line) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return finished;
}
function resumeAndTestNoBreakpoint() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(!gSources._selectedBreakpoint,
"There should be no selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.document.querySelectorAll(".dbg-breakpoint").length, 13,
"There should be thirteen visible breakpoints.");
});
gDebugger.gThreadClient.resume();
return finished;
}
function testBreakpoint(line, highlightBreakpoint) {
// Highlight the breakpoint only if required.
if (highlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: line });
return finished;
}
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
let source = gSources.selectedItem.attachment.source;
let bp = queries.getBreakpoint(getState(), selectedBreakpoint.location);
ok(bp, "The selected breakpoint exists");
is(bp.location.actor, source.actor,
"The breakpoint on line " + line + " wasn't added on the correct source.");
is(bp.location.line, line,
"The breakpoint on line " + line + " wasn't found.");
is(!!bp.disabled, false,
"The breakpoint on line " + line + " should be enabled.");
is(!!selectedBreakpointItem.attachment.openPopup, false,
"The breakpoint on line " + line + " should not have opened a popup.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not have been shown.");
isnot(bp.condition, undefined,
"The breakpoint on line " + line + " should have a conditional expression.");
ok(isCaretPos(gPanel, line),
"The editor caret position is not properly set.");
}
const testAfterReload = Task.async(function* () {
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
ok(selectedActor,
"There should be a selected item in the sources pane after reload.");
ok(!selectedBreakpoint,
"There should be no selected breakpoint in the sources pane after reload.");
yield testBreakpoint(18, true);
yield testBreakpoint(19, true);
yield testBreakpoint(20, true);
yield testBreakpoint(21, true);
yield testBreakpoint(22, true);
yield testBreakpoint(23, true);
yield testBreakpoint(24, true);
yield testBreakpoint(25, true);
yield testBreakpoint(26, true);
yield testBreakpoint(27, true);
yield testBreakpoint(28, true);
yield testBreakpoint(29, true);
yield testBreakpoint(30, true);
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded again.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(gSources._selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
});
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield addBreakpoints();
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 13,
"13 breakpoints currently added.");
yield resumeAndTestBreakpoint(20);
yield resumeAndTestBreakpoint(21);
yield resumeAndTestBreakpoint(22);
yield resumeAndTestBreakpoint(23);
yield resumeAndTestBreakpoint(24);
yield resumeAndTestBreakpoint(25);
yield resumeAndTestBreakpoint(27);
yield resumeAndTestBreakpoint(28);
yield resumeAndTestBreakpoint(29);
yield resumeAndTestBreakpoint(30);
yield resumeAndTestNoBreakpoint();
let sourceShown = waitForSourceShown(gPanel, ".html");
reload(gPanel),
yield sourceShown;
testAfterReload();
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
closeDebuggerAndFinish(gPanel);
});
});
}

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

@ -1,219 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 740825: Test the debugger conditional breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const CONDITIONAL_POPUP_SHOWN = gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
function addBreakpoint1() {
return actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 });
}
function addBreakpoint2() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
setCaretPosition(19);
gSources._onCmdAddBreakpoint();
return finished;
}
function modBreakpoint2() {
setCaretPosition(19);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
gSources._onCmdAddConditionalBreakpoint();
return popupShown;
}
function* addBreakpoint3() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
setCaretPosition(20);
gSources._onCmdAddConditionalBreakpoint();
yield finished;
yield popupShown;
}
function* modBreakpoint3() {
setCaretPosition(20);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
gSources._onCmdAddConditionalBreakpoint();
yield popupShown;
typeText(gSources._cbTextbox, "bamboocha");
let finished = waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
EventUtils.sendKey("RETURN", gDebugger);
yield finished;
}
function addBreakpoint4() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
setCaretPosition(21);
gSources._onCmdAddBreakpoint();
return finished;
}
function delBreakpoint4() {
let finished = waitForDispatch(gPanel, constants.REMOVE_BREAKPOINT);
setCaretPosition(21);
gSources._onCmdAddBreakpoint();
return finished;
}
function testBreakpoint(aLine, aPopupVisible, aConditionalExpression) {
const source = queries.getSelectedSource(getState());
ok(source,
"There should be a selected item in the sources pane.");
const bp = queries.getBreakpoint(getState(), {
actor: source.actor,
line: aLine
});
const bpItem = gSources._getBreakpoint(bp);
ok(bp, "There should be a breakpoint.");
ok(bpItem, "There should be a breakpoint in the sources pane.");
is(bp.location.actor, source.actor,
"The breakpoint on line " + aLine + " wasn't added on the correct source.");
is(bp.location.line, aLine,
"The breakpoint on line " + aLine + " wasn't found.");
is(!!bp.disabled, false,
"The breakpoint on line " + aLine + " should be enabled.");
is(gSources._conditionalPopupVisible, aPopupVisible,
"The breakpoint on line " + aLine + " should have a correct popup state (2).");
is(bp.condition, aConditionalExpression,
"The breakpoint on line " + aLine + " should have a correct conditional expression.");
}
function testNoBreakpoint(aLine) {
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
ok(selectedActor,
"There should be a selected item in the sources pane for line " + aLine + ".");
ok(!selectedBreakpoint,
"There should be no selected brekapoint in the sources pane for line " + aLine + ".");
ok(isCaretPos(gPanel, aLine),
"The editor caret position is not properly set.");
}
function setCaretPosition(aLine) {
gEditor.setCursor({ line: aLine - 1, ch: 0 });
}
function clickOnBreakpoint(aIndex) {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[aIndex],
gDebugger);
}
function waitForConditionUpdate() {
// This will close the popup and send another request to update
// the condition
gSources._hideConditionalPopup();
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
yield addBreakpoint1();
testBreakpoint(18, false, undefined);
yield addBreakpoint2();
testBreakpoint(19, false, undefined);
yield modBreakpoint2();
testBreakpoint(19, true, undefined);
yield waitForConditionUpdate();
yield addBreakpoint3();
testBreakpoint(20, true, "");
yield waitForConditionUpdate();
yield modBreakpoint3();
testBreakpoint(20, false, "bamboocha");
yield addBreakpoint4();
testBreakpoint(21, false, undefined);
yield delBreakpoint4();
setCaretPosition(18);
is(gSources._selectedBreakpoint.location.line, 18,
"The selected breakpoint is line 18");
yield testBreakpoint(18, false, undefined);
setCaretPosition(19);
is(gSources._selectedBreakpoint.location.line, 19,
"The selected breakpoint is line 19");
yield testBreakpoint(19, false, "");
setCaretPosition(20);
is(gSources._selectedBreakpoint.location.line, 20,
"The selected breakpoint is line 20");
yield testBreakpoint(20, false, "bamboocha");
setCaretPosition(17);
yield testNoBreakpoint(17);
setCaretPosition(21);
yield testNoBreakpoint(21);
clickOnBreakpoint(0);
is(gSources._selectedBreakpoint.location.line, 18,
"The selected breakpoint is line 18");
yield testBreakpoint(18, false, undefined);
clickOnBreakpoint(1);
is(gSources._selectedBreakpoint.location.line, 19,
"The selected breakpoint is line 19");
yield testBreakpoint(19, false, "");
clickOnBreakpoint(2);
is(gSources._selectedBreakpoint.location.line, 20,
"The selected breakpoint is line 20");
testBreakpoint(20, true, "bamboocha");
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,78 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that conditional breakpoint expressions survive disabled breakpoints.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
initDebugger().then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
function waitForConditionUpdate() {
// This will close the popup and send another request to update
// the condition
gSources._hideConditionalPopup();
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretUpdated(gPanel, 17);
yield navigateActiveTabTo(gPanel,
TAB_URL,
gDebugger.EVENTS.SOURCE_SHOWN);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
const location = { actor: gSources.selectedValue, line: 18 };
yield actions.addBreakpoint(location, "hello");
yield actions.disableBreakpoint(location);
yield actions.addBreakpoint(location);
const bp = queries.getBreakpoint(getState(), location);
is(bp.condition, "hello", "The conditional expression is correct.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
yield finished;
const textbox = gDebugger.document.getElementById("conditional-breakpoint-panel-textbox");
is(textbox.value, "hello", "The expression is correct (2).");
yield waitForConditionUpdate();
yield actions.disableBreakpoint(location);
yield actions.setBreakpointCondition(location, "foo");
yield actions.addBreakpoint(location);
finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
yield finished;
is(textbox.value, "foo", "The expression is correct (3).");
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,52 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that conditional breakpoints with blank expressions
* maintain their conditions after enabling them.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
const location = { actor: gSources.selectedValue, line: 18 };
yield actions.addBreakpoint(location, "");
yield actions.disableBreakpoint(location);
yield actions.addBreakpoint(location);
const bp = queries.getBreakpoint(getState(), location);
is(bp.condition, "", "The conditional expression is correct.");
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,141 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that conditional breakpoints with an exception-throwing expression
* could pause on hit
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
// This test forces conditional breakpoints to be evaluated on the
// client-side
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
function resumeAndTestBreakpoint(line) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return finished;
}
function resumeAndTestNoBreakpoint() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(!gSources._selectedBreakpoint,
"There should be no selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.document.querySelectorAll(".dbg-breakpoint").length, 6,
"There should be thirteen visible breakpoints.");
});
gDebugger.gThreadClient.resume();
return finished;
}
function testBreakpoint(line, highlightBreakpoint) {
// Highlight the breakpoint only if required.
if (highlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: line });
return finished;
}
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
let source = queries.getSource(getState(), selectedActor);
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint.");
ok(selectedBreakpointItem,
"There should be a selected breakpoint item in the sources pane.");
is(selectedBreakpoint.location.actor, source.actor,
"The breakpoint on line " + line + " wasn't added on the correct source.");
is(selectedBreakpoint.location.line, line,
"The breakpoint on line " + line + " wasn't found.");
is(!!selectedBreakpoint.location.disabled, false,
"The breakpoint on line " + line + " should be enabled.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not have been shown.");
isnot(selectedBreakpoint.condition, undefined,
"The breakpoint on line " + line + " should have a conditional expression.");
ok(isCaretPos(gPanel, line),
"The editor caret position is not properly set.");
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 18 }, " 1a"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 19 }, "new Error()"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 20 }, "true"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 21 }, "false"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 22 }, "0"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 23 }, "randomVar"
);
yield resumeAndTestBreakpoint(18);
yield resumeAndTestBreakpoint(19);
yield resumeAndTestBreakpoint(20);
yield resumeAndTestBreakpoint(23);
yield resumeAndTestNoBreakpoint();
// Reset traits back to default value
client.mainRoot.traits.conditionalBreakpoints = true;
closeDebuggerAndFinish(gPanel);
});
});
}

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

@ -1,41 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Breaking in the middle of a script evaluated by the console should
* work
*/
function test() {
Task.spawn(function* () {
let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
let [, panel] = yield initDebugger(TAB_URL, { source: null });
let dbgWin = panel.panelWin;
let sources = dbgWin.DebuggerView.Sources;
let frames = dbgWin.DebuggerView.StackFrames;
let editor = dbgWin.DebuggerView.editor;
let toolbox = gDevTools.getToolbox(panel.target);
let paused = promise.all([
waitForEditorEvents(panel, "cursorActivity"),
waitForDebuggerEvents(panel, dbgWin.EVENTS.SOURCE_SHOWN)
]);
toolbox.once("webconsole-ready", () => {
ok(toolbox.splitConsole, "Split console is shown.");
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
jsterm.execute("debugger");
});
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
yield paused;
is(sources.selectedItem.attachment.label, "SCRIPT0",
"Anonymous source is selected in sources");
ok(editor.getText() === "debugger", "Editor has correct text");
yield toolbox.closeSplitConsole();
yield resumeDebuggerThenCloseAndFinish(panel);
});
}

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

@ -1,42 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Breaking in the middle of a named eval script created by the
* console should work
*/
function test() {
Task.spawn(runTests);
}
function* runTests() {
let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
let [, panel] = yield initDebugger(TAB_URL, { source: null });
let dbgWin = panel.panelWin;
let sources = dbgWin.DebuggerView.Sources;
let frames = dbgWin.DebuggerView.StackFrames;
let editor = dbgWin.DebuggerView.editor;
let toolbox = gDevTools.getToolbox(panel.target);
let paused = waitForSourceAndCaretAndScopes(panel, "foo.js", 1);
toolbox.once("webconsole-ready", () => {
ok(toolbox.splitConsole, "Split console is shown.");
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
jsterm.execute("eval('debugger; //# sourceURL=foo.js')");
});
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
yield paused;
is(sources.selectedItem.attachment.label, "foo.js",
"New source is selected in sources");
is(sources.selectedItem.attachment.group, "http://example.com",
"New source is in the right group");
ok(editor.getText() === "debugger; //# sourceURL=foo.js", "Editor has correct text");
yield toolbox.closeSplitConsole();
yield resumeDebuggerThenCloseAndFinish(panel);
}

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

@ -1,106 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the public evaluation API from the debugger controller.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
Task.spawn(function* () {
const options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
const [tab, panel] = yield initDebugger(TAB_URL, options);
const win = panel.panelWin;
const frames = win.DebuggerController.StackFrames;
const framesView = win.DebuggerView.StackFrames;
const sourcesView = win.DebuggerView.Sources;
const editorView = win.DebuggerView.editor;
const events = win.EVENTS;
const queries = win.require("./content/queries");
const constants = win.require("./content/constants");
const actions = bindActionCreators(panel);
const getState = win.DebuggerController.getState;
function checkView(frameDepth, selectedSource, caretLine, editorText) {
is(win.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(framesView.itemCount, 2,
"Should have four frames.");
is(framesView.selectedDepth, frameDepth,
"The correct frame is selected in the widget.");
is(sourcesView.selectedIndex, selectedSource,
"The correct source is selected in the widget.");
ok(isCaretPos(panel, caretLine),
"Editor caret location is correct.");
is(editorView.getText().search(editorText[0]), editorText[1],
"The correct source is not displayed.");
}
// Cache the sources text to avoid having to wait for their
// retrieval.
const sources = queries.getSources(getState());
yield promise.all(Object.keys(sources).map(k => {
return actions.loadSourceText(sources[k]);
}));
is(Object.keys(getState().sources.sourcesText).length, 2,
"There should be two cached sources in the cache.");
// Eval while not paused.
try {
yield frames.evaluate("foo");
} catch (error) {
is(error.message, "No stack frame available.",
"Evaluating shouldn't work while the debuggee isn't paused.");
}
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 6);
checkView(0, 1, 6, [/secondCall/, 118]);
// Eval in the topmost frame, while paused.
let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
let result = yield frames.evaluate("foo");
ok(!result.throw, "The evaluation hasn't thrown.");
is(result.return.type, "object", "The evaluation return type is correct.");
is(result.return.class, "Function", "The evaluation return class is correct.");
yield updatedView;
checkView(0, 1, 6, [/secondCall/, 118]);
ok(true, "Evaluating in the topmost frame works properly.");
// Eval in a different frame, while paused.
updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
try {
yield frames.evaluate("foo", { depth: 1 }); // oldest frame
} catch (result) {
is(result.return.type, "object", "The evaluation thrown type is correct.");
is(result.return.class, "Error", "The evaluation thrown class is correct.");
ok(!result.return, "The evaluation hasn't returned.");
}
yield updatedView;
checkView(0, 1, 6, [/secondCall/, 118]);
ok(true, "Evaluating in a custom frame works properly.");
// Eval in a non-existent frame, while paused.
waitForDebuggerEvents(panel, events.FETCHED_SCOPES).then(() => {
ok(false, "Shouldn't have updated the view when trying to evaluate " +
"an expression in a non-existent stack frame.");
});
try {
yield frames.evaluate("foo", { depth: 4 }); // non-existent frame
} catch (error) {
is(error.message, "No stack frame available.",
"Evaluating shouldn't work if the specified frame doesn't exist.");
}
yield resumeDebuggerThenCloseAndFinish(panel);
});
}

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

@ -1,78 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the public evaluation API from the debugger controller.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
Task.spawn(function* () {
const options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
const [tab, panel] = yield initDebugger(TAB_URL, options);
const win = panel.panelWin;
const frames = win.DebuggerController.StackFrames;
const framesView = win.DebuggerView.StackFrames;
const sourcesView = win.DebuggerView.Sources;
const editorView = win.DebuggerView.editor;
const events = win.EVENTS;
const queries = win.require("./content/queries");
const constants = win.require("./content/constants");
const actions = bindActionCreators(panel);
const getState = win.DebuggerController.getState;
function checkView(selectedFrame, selectedSource, caretLine, editorText) {
is(win.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(framesView.itemCount, 2,
"Should have four frames.");
is(framesView.selectedDepth, selectedFrame,
"The correct frame is selected in the widget.");
is(sourcesView.selectedIndex, selectedSource,
"The correct source is selected in the widget.");
ok(isCaretPos(panel, caretLine),
"Editor caret location is correct.");
is(editorView.getText().search(editorText[0]), editorText[1],
"The correct source is not displayed.");
}
// Cache the sources text to avoid having to wait for their
// retrieval.
const sources = queries.getSources(getState());
yield promise.all(Object.keys(sources).map(k => {
return actions.loadSourceText(sources[k]);
}));
// Allow this generator function to yield first.
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 6);
checkView(0, 1, 6, [/secondCall/, 118]);
// Change the selected frame and eval inside it.
let updatedFrame = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
framesView.selectedDepth = 1; // oldest frame
yield updatedFrame;
checkView(1, 0, 5, [/firstCall/, 118]);
let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
try {
yield frames.evaluate("foo");
} catch (result) {
is(result.return.type, "object", "The evaluation thrown type is correct.");
is(result.return.class, "Error", "The evaluation thrown class is correct.");
ok(!result.return, "The evaluation hasn't returned.");
}
yield updatedView;
checkView(1, 0, 5, [/firstCall/, 118]);
ok(true, "Evaluating while in a user-selected frame works properly.");
yield resumeDebuggerThenCloseAndFinish(panel);
});
}

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

@ -1,72 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that source contents are invalidated when the target navigates.
*/
const TAB_URL = EXAMPLE_URL + "doc_random-javascript.html";
const JS_URL = EXAMPLE_URL + "sjs_random-javascript.sjs";
function test() {
let options = {
source: JS_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gPanel = aPanel;
const gDebugger = aPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
Task.spawn(function* () {
let source = queries.getSelectedSource(getState());
is(queries.getSourceCount(getState()), 1,
"There should be one source displayed in the view.");
is(source.url, JS_URL,
"The correct source is currently selected in the view.");
ok(gEditor.getText().includes("bacon"),
"The currently shown source contains bacon. Mmm, delicious!");
const { text: firstText } = yield queries.getSourceText(getState(), source.actor);
const firstNumber = parseFloat(firstText.match(/\d\.\d+/)[0]);
is(firstText, gEditor.getText(),
"gControllerSources.getText() returned the expected contents.");
ok(firstNumber <= 1 && firstNumber >= 0,
"The generated number seems to be created correctly.");
yield reloadActiveTab(aPanel, gDebugger.EVENTS.SOURCE_SHOWN);
is(queries.getSourceCount(getState()), 1,
"There should be one source displayed in the view.");
is(source.url, JS_URL,
"The correct source is currently selected in the view.");
ok(gEditor.getText().includes("bacon"),
"The newly shown source contains bacon. Mmm, delicious!");
source = queries.getSelectedSource(getState());
const { text: secondText } = yield queries.getSourceText(getState(), source.actor);
const secondNumber = parseFloat(secondText.match(/\d\.\d+/)[0]);
is(secondText, gEditor.getText(),
"gControllerSources.getText() returned the expected contents.");
ok(secondNumber <= 1 && secondNumber >= 0,
"The generated number seems to be created correctly.");
isnot(firstText, secondText,
"The displayed sources were different across reloads.");
isnot(firstNumber, secondNumber,
"The displayed sources differences were correct across reloads.");
yield closeDebuggerAndFinish(aPanel);
});
});
}

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

@ -1,160 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This if the debugger's layout is correctly modified when the toolbox's
* host changes.
*/
"use strict";
var gDefaultHostType = Services.prefs.getCharPref("devtools.toolbox.host");
function test() {
// test is too slow on some platforms due to the number of test cases
requestLongerTimeout(3);
(async function() {
await testHosts(["bottom", "right", "window:big"], ["horizontal", "vertical", "horizontal"]);
await testHosts(["right", "bottom", "right"], ["vertical", "horizontal", "vertical"]);
await testHosts(["bottom", "right", "bottom"], ["horizontal", "vertical", "horizontal"]);
await testHosts(["right", "window:big", "right"], ["vertical", "horizontal", "vertical"]);
await testHosts(["window:big", "right", "window:big"], ["horizontal", "vertical", "horizontal"]);
await testHosts(["window:small", "bottom", "right"], ["vertical", "horizontal", "vertical"]);
await testHosts(["window:small", "window:big", "window:small"], ["vertical", "horizontal", "vertical"]);
finish();
})();
}
async function testHosts(aHostTypes, aLayoutTypes) {
let [firstHost, secondHost, thirdHost] = aHostTypes;
let [firstLayout, secondLayout, thirdLayout] = aLayoutTypes;
Services.prefs.setCharPref("devtools.toolbox.host", getHost(firstHost));
let [tab, panel] = await initDebugger();
if (getHost(firstHost) === "window") {
await resizeToolboxWindow(panel, firstHost);
}
await testHost(panel, getHost(firstHost), firstLayout);
await switchAndTestHost(tab, panel, secondHost, secondLayout);
await switchAndTestHost(tab, panel, thirdHost, thirdLayout);
await teardown(panel);
}
async function switchAndTestHost(aTab, aPanel, aHostType, aLayoutType) {
let gToolbox = aPanel._toolbox;
let gDebugger = aPanel.panelWin;
let layoutChanged = waitEventOnce(gDebugger, gDebugger.EVENTS.LAYOUT_CHANGED);
let hostChanged = gToolbox.switchHost(getHost(aHostType));
await hostChanged;
info("The toolbox's host has changed.");
if (getHost(aHostType) === "window") {
await resizeToolboxWindow(aPanel, aHostType);
}
await layoutChanged;
info("The debugger's layout has changed.");
await testHost(aPanel, getHost(aHostType), aLayoutType);
}
function waitEventOnce(aTarget, aEvent) {
return new Promise(resolve => aTarget.once(aEvent, resolve));
}
function getHost(host) {
if (host.indexOf("window") == 0) {
return "window";
}
return host;
}
async function resizeToolboxWindow(panel, host) {
let sizeOption = host.split(":")[1];
let win = panel._toolbox.win.parent;
// should be the same value as BREAKPOINT_SMALL_WINDOW_WIDTH in debugger-view.js
let breakpoint = 850;
if (sizeOption == "big" && win.outerWidth <= breakpoint) {
await resizeAndWaitForLayoutChange(panel, breakpoint + 300);
} else if (sizeOption == "small" && win.outerWidth >= breakpoint) {
await resizeAndWaitForLayoutChange(panel, breakpoint - 300);
} else {
info("Window resize unnecessary for host " + host);
}
}
async function resizeAndWaitForLayoutChange(panel, width) {
info("Updating toolbox window width to " + width);
let win = panel._toolbox.win.parent;
let gDebugger = panel.panelWin;
win.resizeTo(width, window.screen.availHeight);
await waitEventOnce(gDebugger, gDebugger.EVENTS.LAYOUT_CHANGED);
}
function testHost(aPanel, aHostType, aLayoutType) {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
is(gView._hostType, aHostType,
"The default host type should've been set on the panel window (1).");
is(gDebugger.gHostType, aHostType,
"The default host type should've been set on the panel window (2).");
is(gView._body.getAttribute("layout"), aLayoutType,
"The default host type is present as an attribute on the panel's body.");
if (aLayoutType == "horizontal") {
is(gView._workersAndSourcesPane.parentNode.id, "debugger-widgets",
"The workers and sources pane's parent is correct for the horizontal layout.");
is(gView._instrumentsPane.parentNode.id, "editor-and-instruments-pane",
"The instruments pane's parent is correct for the horizontal layout.");
} else {
is(gView._workersAndSourcesPane.parentNode.id, "vertical-layout-panes-container",
"The workers and sources pane's parent is correct for the vertical layout.");
is(gView._instrumentsPane.parentNode.id, "vertical-layout-panes-container",
"The instruments pane's parent is correct for the vertical layout.");
}
let widgets = gDebugger.document.getElementById("debugger-widgets").childNodes;
let content = gDebugger.document.getElementById("debugger-content").childNodes;
let editorPane =
gDebugger.document.getElementById("editor-and-instruments-pane").childNodes;
let verticalPane =
gDebugger.document.getElementById("vertical-layout-panes-container").childNodes;
if (aLayoutType == "horizontal") {
is(widgets.length, 5, // 1 pane, 1 content box, 2 splitters and a phantom box.
"Found the correct number of debugger widgets.");
is(content.length, 1, // 1 pane
"Found the correct number of debugger content.");
is(editorPane.length, 3, // 2 panes, 1 splitter
"Found the correct number of debugger panes.");
is(verticalPane.length, 1, // 1 lonely splitter in the phantom box.
"Found the correct number of debugger panes.");
} else {
is(widgets.length, 4, // 1 content box, 2 splitters and a phantom box.
"Found the correct number of debugger widgets.");
is(content.length, 1, // 1 pane
"Found the correct number of debugger content.");
is(editorPane.length, 2, // 1 pane, 1 splitter
"Found the correct number of debugger panes.");
is(verticalPane.length, 3, // 2 panes and 1 splitter in the phantom box.
"Found the correct number of debugger panes.");
}
}
registerCleanupFunction(function() {
Services.prefs.setCharPref("devtools.toolbox.host", gDefaultHostType);
gDefaultHostType = null;
});

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

@ -1,74 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that iframes can be added as debuggees.
*/
const TAB_URL = EXAMPLE_URL + "doc_iframes.html";
function test() {
let gTab, gPanel, gDebugger;
let gEditor, gSources, gFrames;
let options = {
source: EXAMPLE_URL + "doc_inline-debugger-statement.html",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gFrames = gDebugger.DebuggerView.StackFrames;
checkIframeSource();
checkIframePause()
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
function checkIframeSource() {
is(gDebugger.gThreadClient.paused, false,
"Should be running after starting the test.");
ok(isCaretPos(gPanel, 1),
"The source editor caret position was incorrect.");
is(gFrames.itemCount, 0,
"Should have only no frames.");
is(gSources.itemCount, 1,
"Found the expected number of entries in the sources widget.");
is(gEditor.getText().indexOf("debugger"), 348,
"The correct source was loaded initially.");
is(getSelectedSourceURL(gSources), EXAMPLE_URL + "doc_inline-debugger-statement.html",
"The currently selected source value is incorrect (0).");
is(gSources.selectedValue, gSources.values[0],
"The currently selected source value is incorrect (1).");
}
function checkIframePause() {
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
ContentTask.spawn(gTab.linkedBrowser, null, async () => {
content.frames[0].wrappedJSObject.runDebuggerStatement()
});
});
return waitForCaretAndScopes(gPanel, 16).then(() => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after an interrupt request.");
ok(isCaretPos(gPanel, 16),
"The source editor caret position was incorrect.");
is(gFrames.itemCount, 1,
"Should have only one frame.");
});
}
}

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

@ -1,123 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test resuming from button and keyboard shortcuts.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
let options = {
source: EXAMPLE_URL + "code_script-switching-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
gTarget = gDebugger.gTarget;
gThreadClient = gDebugger.gThreadClient;
gResumeButton = gDebugger.document.getElementById("resume");
gResumeKey = gDebugger.document.getElementById("resumeKey");
gTarget.on("thread-paused", failOnPause);
addBreakpoints()
.then(() => { gTarget.off("thread-paused", failOnPause); })
.then(testResumeButton)
.then(testResumeKeyboard)
.then(() => closeDebuggerAndFinish(gPanel))
.catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
function failOnPause() {
ok(false, "A pause was sent, but it shouldn't have been");
}
function addBreakpoints() {
return promise.resolve(null)
.then(() => gPanel.addBreakpoint({ actor: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 7 }))
.then(() => ensureThreadClientState(gPanel, "resumed"));
}
function resume() {
let onceResumed = gTarget.once("thread-resumed");
gThreadClient.resume();
return onceResumed;
}
function testResumeButton() {
info("Pressing the resume button, expecting a thread-paused");
ok(!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 1");
ok(!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
ok(!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
let oncePaused = gTarget.once("thread-paused");
// Click the pause button to break on next execution
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
ok(gResumeButton.hasAttribute("disabled"), "Resume button is disabled");
ok(gResumeButton.hasAttribute("break-on-next"), "Resume button is waiting for next execution");
ok(!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
// Evaluate a script to fully pause the debugger
once(gDebugger.gClient, "willInterrupt").then(() => {
evalInTab(gTab, "1+1;");
});
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN)
.then(() => {
ok(!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
is(gResumeButton.getAttribute("checked"), "true", "Resume button is checked");
ok(!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 2");
})
.then(() => {
let p = ensureThreadClientState(gPanel, "resumed");
gThreadClient.resume();
return p;
});
}
function testResumeKeyboard() {
let key = gResumeKey.getAttribute("keycode");
info("Triggering a pause with keyboard (" + key + "), expecting a thread-paused");
ok(!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 3");
ok(!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
ok(!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
// Press the key to break on next execution
EventUtils.synthesizeKey(key, { }, gDebugger);
ok(gResumeButton.hasAttribute("disabled"), "Resume button is disabled");
ok(gResumeButton.hasAttribute("break-on-next"), "Resume button is waiting for next execution");
ok(!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
// Evaluate a script to fully pause the debugger
once(gDebugger.gClient, "willInterrupt").then(() => {
evalInTab(gTab, "1+1;");
});
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN)
.then(() => {
ok(!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
is(gResumeButton.getAttribute("checked"), "true", "Resume button is checked");
ok(!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 4");
})
.then(() => {
let p = ensureThreadClientState(gPanel, "resumed");
gThreadClient.resume();
return p;
});
}
}

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

@ -1,50 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the jump to function definition works properly.
*/
const TAB_URL = EXAMPLE_URL + "doc_function-jump.html";
const SCRIPT_URI = EXAMPLE_URL + "code_function-jump-01.js";
function test() {
let gTab, gPanel, gDebugger, gSources;
let options = {
source: EXAMPLE_URL + "code_function-jump-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
jumpToFunctionDefinition()
.then(() => closeDebuggerAndFinish(gPanel))
.catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
function jumpToFunctionDefinition() {
let callLocation = {line: 5, ch: 0};
let editor = gDebugger.DebuggerView.editor;
let coords = editor.getCoordsFromPosition(callLocation);
gDebugger.DebuggerView.Sources._onMouseDown({ clientX: coords.left,
clientY: coords.top,
metaKey: true });
let deferred = promise.defer();
executeSoon(() => {
is(editor.getDebugLocation(), 1, "foo definition should be highlighted");
deferred.resolve();
});
return deferred.promise;
}
}

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

@ -1,113 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the toolbox is raised when the debugger gets paused.
*/
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
add_task(async function() {
let options = {
source: TAB_URL,
line: 1
};
let [tab, panel] = await initDebugger(TAB_URL, options);
let panelWin = panel.panelWin;
let toolbox = panel._toolbox;
let toolboxTab = toolbox.doc.getElementById("toolbox-tab-jsdebugger");
let newTab = await addTab(TAB_URL);
isnot(newTab, tab,
"The newly added tab is different from the debugger's tab.");
is(gBrowser.selectedTab, newTab,
"Debugger's tab is not the selected tab.");
info("Run tests against bottom host.");
await testPause();
await testResume();
// testResume selected the console, select back the debugger.
await toolbox.selectTool("jsdebugger");
info("Switching to a toolbox window host.");
await toolbox.switchHost(Toolbox.HostType.WINDOW);
info("Run tests against window host.");
await testPause();
await testResume();
info("Cleanup after the test.");
await toolbox.switchHost(Toolbox.HostType.BOTTOM);
await closeDebuggerAndFinish(panel);
async function testPause() {
is(panelWin.gThreadClient.paused, false,
"Should be running after starting the test.");
let onFocus, onTabSelect;
if (toolbox.hostType == Toolbox.HostType.WINDOW) {
onFocus = new Promise(done => {
toolbox.win.parent.addEventListener("focus", function () {
done();
}, {capture: true, once: true});
});
} else {
onTabSelect = new Promise(done => {
tab.parentNode.addEventListener("TabSelect", function listener({type}) {
tab.parentNode.removeEventListener(type, listener);
done();
});
});
}
let onPaused = waitForPause(panelWin.gThreadClient);
// Evaluate a script to fully pause the debugger
evalInTab(tab, "debugger;");
await onPaused;
await onFocus;
await onTabSelect;
if (toolbox.hostType != Toolbox.HostType.WINDOW) {
is(gBrowser.selectedTab, tab,
"Debugger's tab got selected.");
}
await toolbox.selectTool("webconsole");
ok(toolboxTab.classList.contains("highlighted"),
"The highlighted class is present");
ok(!toolboxTab.classList.contains("selected"),
"The tab is not selected");
await toolbox.selectTool("jsdebugger");
ok(toolboxTab.classList.contains("highlighted"),
"The highlighted class is present");
ok(toolboxTab.classList.contains("selected"),
"...and the tab is selected, so the glow will not be present.");
}
async function testResume() {
let onPaused = waitForEvent(panelWin.gThreadClient, "resumed");
EventUtils.sendMouseEvent({ type: "mousedown" },
panelWin.document.getElementById("resume"),
panelWin);
await onPaused;
await toolbox.selectTool("webconsole");
ok(!toolboxTab.classList.contains("highlighted"),
"The highlighted class is not present now after the resume");
ok(!toolboxTab.classList.contains("selected"),
"The tab is not selected");
}
});
registerCleanupFunction(function () {
// Revert to the default toolbox host, so that the following tests proceed
// normally and not inside a non-default host.
Services.prefs.setCharPref("devtools.toolbox.host", Toolbox.HostType.BOTTOM);
});

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

@ -1,50 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that optimized out variables aren't present in the variables view.
function test() {
Task.spawn(function* () {
const TAB_URL = EXAMPLE_URL + "doc_closure-optimized-out.html";
let gDebugger, sources;
let options = {
source: TAB_URL,
line: 1
};
let [tab, panel] = yield initDebugger(TAB_URL, options);
gDebugger = panel.panelWin;
sources = gDebugger.DebuggerView.Sources;
yield panel.addBreakpoint({ actor: sources.values[0],
line: 18 });
yield ensureThreadClientState(panel, "resumed");
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
generateMouseClickInTab(tab, "content.document.querySelector('button')");
yield waitForDebuggerEvents(panel, gDebugger.EVENTS.FETCHED_SCOPES);
let gVars = gDebugger.DebuggerView.Variables;
let outerScope = gVars.getScopeAtIndex(1);
outerScope.expand();
let upvarVar = outerScope.get("upvar");
ok(upvarVar, "The variable `upvar` is shown.");
is(upvarVar.target.querySelector(".value").getAttribute("value"),
gDebugger.L10N.getStr("variablesViewOptimizedOut"),
"Should show the optimized out message for upvar.");
let argVar = outerScope.get("arg");
is(argVar.target.querySelector(".name").getAttribute("value"), "arg",
"Should have the right property name for |arg|.");
is(argVar.target.querySelector(".value").getAttribute("value"), 44,
"Should have the right property value for |arg|.");
yield resumeDebuggerThenCloseAndFinish(panel);
}).catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
}

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

@ -1,91 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if pausing and resuming in the main loop works properly.
*/
const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
var gTab, gPanel, gDebugger;
var gResumeButton, gResumeKey, gFrames;
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gResumeButton = gDebugger.document.getElementById("resume");
gResumeKey = gDebugger.document.getElementById("resumeKey");
gFrames = gDebugger.DebuggerView.StackFrames;
testPause();
});
}
function testPause() {
is(gDebugger.gThreadClient.paused, false,
"Should be running after starting the test.");
is(gResumeButton.getAttribute("tooltiptext"),
gDebugger.L10N.getFormatStr("pauseButtonTooltip",
gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
"Button tooltip should be 'pause' when running.");
gDebugger.gThreadClient.addOneTimeListener("paused", () => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after an interrupt request.");
is(gResumeButton.getAttribute("tooltiptext"),
gDebugger.L10N.getFormatStr("resumeButtonTooltip",
gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
"Button tooltip should be 'resume' when paused.");
is(gFrames.itemCount, 0,
"Should have no frames when paused in the main loop.");
testResume();
});
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
is(gResumeButton.getAttribute("tooltiptext"),
gDebugger.L10N.getFormatStr("pausePendingButtonTooltip"),
"Button tooltip should be 'waiting for execution' when breaking on nex.");
// Evaluate a script to fully pause the debugger
once(gDebugger.gClient, "willInterrupt").then(() => {
evalInTab(gTab, "1+1;");
});
}
function testResume() {
gDebugger.gThreadClient.addOneTimeListener("resumed", () => {
is(gDebugger.gThreadClient.paused, false,
"Should be paused after an interrupt request.");
is(gResumeButton.getAttribute("tooltiptext"),
gDebugger.L10N.getFormatStr("pauseButtonTooltip",
gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
"Button tooltip should be pause when running.");
closeDebuggerAndFinish(gPanel);
});
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gResumeButton = null;
gResumeKey = null;
gFrames = null;
});

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

@ -1,107 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if a warning is shown in the inspector when debugger is paused.
*/
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
var gTab, gPanel, gDebugger;
var gTarget, gToolbox;
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gTarget = gPanel.target;
gToolbox = gPanel._toolbox;
testPause();
});
}
function testPause() {
gDebugger.gThreadClient.addOneTimeListener("paused", () => {
ok(gDebugger.gThreadClient.paused,
"threadClient.paused has been updated to true.");
gToolbox.once("inspector-selected").then(testNotificationIsUp1);
gToolbox.selectTool("inspector");
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
// Evaluate a script to fully pause the debugger
once(gDebugger.gClient, "willInterrupt").then(() => {
evalInTab(gTab, "1+1;");
});
}
function testNotificationIsUp1() {
let notificationBox = gToolbox.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
ok(notification,
"Inspector notification is present (1).");
gToolbox.once("jsdebugger-selected", testNotificationIsHidden);
gToolbox.selectTool("jsdebugger");
}
function testNotificationIsHidden() {
let notificationBox = gToolbox.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
ok(!notification,
"Inspector notification is hidden (2).");
gToolbox.once("inspector-selected", testNotificationIsUp2);
gToolbox.selectTool("inspector");
}
function testNotificationIsUp2() {
let notificationBox = gToolbox.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
ok(notification,
"Inspector notification is present again (3).");
testResume();
}
function testResume() {
gDebugger.gThreadClient.addOneTimeListener("resumed", () => {
ok(!gDebugger.gThreadClient.paused,
"threadClient.paused has been updated to false.");
let notificationBox = gToolbox.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
ok(!notification,
"Inspector notification was removed once debugger resumed.");
closeDebuggerAndFinish(gPanel);
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
}
registerCleanupFunction(function () {
gTab = null;
gPanel = null;
gDebugger = null;
gTarget = null;
gToolbox = null;
});

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

@ -1,49 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that keybindings still work when the content window is paused and
// the tab is selected again.
function test() {
Task.spawn(function* () {
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
let gDebugger, searchBox;
let options = {
source: TAB_URL,
line: 1
};
let [tab, panel] = yield initDebugger(TAB_URL, options);
gDebugger = panel.panelWin;
searchBox = gDebugger.DebuggerView.Filtering._searchbox;
let onCaretUpdated = ensureCaretAt(panel, 20, 1, true);
let onThreadPaused = ensureThreadClientState(panel, "paused");
ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.document.querySelector("button").click();
});
yield onCaretUpdated;
yield onThreadPaused
// Now open a tab and close it.
let tab2 = yield addTab(TAB_URL);
yield waitForTick();
yield removeTab(tab2);
yield ensureCaretAt(panel, 20);
// Try to use the Cmd-L keybinding to see if it still works.
let caretMove = ensureCaretAt(panel, 15, 1, true);
// Wait a tick for the editor focus event to occur first.
executeSoon(function () {
EventUtils.synthesizeKey("l", {accelKey: true});
EventUtils.sendString("15");
});
yield caretMove;
yield resumeDebuggerThenCloseAndFinish(panel);
}).catch(aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
}

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

@ -1,56 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that source contents are invalidated when the target navigates.
*/
const TAB_URL = EXAMPLE_URL + "sjs_post-page.sjs";
const FORM = "<form method=\"POST\"><input type=\"submit\"></form>";
const GET_CONTENT = "<script>\"GET\";</script>" + FORM;
const POST_CONTENT = "<script>\"POST\";</script>" + FORM;
add_task(async function() {
// Disable rcwn to make cache behavior deterministic.
await pushPref("network.http.rcwn.enabled", false);
let options = {
source: TAB_URL,
line: 1
};
let [tab, panel] = await initDebugger(TAB_URL, options);
let win = panel.panelWin;
let editor = win.DebuggerView.editor;
let queries = win.require("./content/queries");
let getState = win.DebuggerController.getState;
let source = queries.getSelectedSource(getState());
is(queries.getSourceCount(getState()), 1,
"There should be one source displayed in the view.");
is(source.url, TAB_URL,
"The correct source is currently selected in the view.");
is(editor.getText(), GET_CONTENT,
"The currently shown source contains bacon. Mmm, delicious!");
// Submit the form and wait for debugger update
let onSourceUpdated = waitForSourceShown(panel, TAB_URL);
await ContentTask.spawn(tab.linkedBrowser, null, function () {
content.document.querySelector("input[type=\"submit\"]").click();
});
await onSourceUpdated;
// Verify that the source updates to the POST page content
source = queries.getSelectedSource(getState());
is(queries.getSourceCount(getState()), 1,
"There should be one source displayed in the view.");
is(source.url, TAB_URL,
"The correct source is currently selected in the view.");
is(editor.getText(), POST_CONTENT,
"The currently shown source contains bacon. Mmm, delicious!");
await closeDebuggerAndFinish(panel);
});

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

@ -1,89 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the debugger does show up even if a progress listener reads the
* WebProgress argument's DOMWindow property in onStateChange() (bug 771655).
*/
var gTab, gPanel, gDebugger;
var gOldListener;
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
function test() {
installListener();
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
is(!!gDebugger.DebuggerController._startup, true,
"Controller should be initialized after starting the test.");
testPause();
});
}
function testPause() {
let onCaretUpdated = waitForCaretUpdated(gPanel, 16);
callInTab(gTab, "runDebuggerStatement");
onCaretUpdated.then(() => {
is(gDebugger.gThreadClient.state, "paused",
"The debugger statement was reached.");
resumeDebuggerThenCloseAndFinish(gPanel);
});
}
// This is taken almost verbatim from bug 771655.
function installListener() {
if ("_testPL" in window) {
gOldListener = _testPL;
Cc["@mozilla.org/docloaderservice;1"]
.getService(Ci.nsIWebProgress)
.removeProgressListener(_testPL);
}
window._testPL = {
START_DOC: Ci.nsIWebProgressListener.STATE_START |
Ci.nsIWebProgressListener.STATE_IS_DOCUMENT,
onStateChange: function (wp, req, stateFlags, status) {
if ((stateFlags & this.START_DOC) === this.START_DOC) {
// This DOMWindow access triggers the unload event.
wp.DOMWindow;
}
},
QueryInterface: function (iid) {
if (iid.equals(Ci.nsISupportsWeakReference) ||
iid.equals(Ci.nsIWebProgressListener))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
Cc["@mozilla.org/docloaderservice;1"]
.getService(Ci.nsIWebProgress)
.addProgressListener(_testPL, Ci.nsIWebProgress.NOTIFY_STATE_REQUEST);
}
registerCleanupFunction(function () {
if (gOldListener) {
window._testPL = gOldListener;
} else {
delete window._testPL;
}
gTab = null;
gPanel = null;
gDebugger = null;
gOldListener = null;
});

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

@ -1,218 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test adding conditional breakpoints (with server-side support)
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
// Linux debug test slaves are a bit slow at this test sometimes.
requestLongerTimeout(2);
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const addBreakpoints = Task.async(function* () {
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 },
"undefined");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 19 },
"null");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 20 },
"42");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 21 },
"true");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 22 },
"'nasu'");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 23 },
"/regexp/");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 24 },
"({})");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 25 },
"(function() {})");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 26 },
"(function() { return false; })()");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 27 },
"a");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 28 },
"a !== undefined");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 29 },
"b");
yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 30 },
"a !== null");
});
function resumeAndTestBreakpoint(line) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return finished;
}
function resumeAndTestNoBreakpoint() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(!gSources._selectedBreakpoint,
"There should be no selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.document.querySelectorAll(".dbg-breakpoint").length, 13,
"There should be thirteen visible breakpoints.");
});
gDebugger.gThreadClient.resume();
return finished;
}
function testBreakpoint(line, highlightBreakpoint) {
// Highlight the breakpoint only if required.
if (highlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: line });
return finished;
}
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
let source = gSources.selectedItem.attachment.source;
let bp = queries.getBreakpoint(getState(), selectedBreakpoint.location);
ok(bp, "The selected breakpoint exists");
is(bp.location.actor, source.actor,
"The breakpoint on line " + line + " wasn't added on the correct source.");
is(bp.location.line, line,
"The breakpoint on line " + line + " wasn't found.");
is(!!bp.disabled, false,
"The breakpoint on line " + line + " should be enabled.");
is(!!selectedBreakpointItem.attachment.openPopup, false,
"The breakpoint on line " + line + " should not have opened a popup.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not have been shown.");
isnot(bp.condition, undefined,
"The breakpoint on line " + line + " should have a conditional expression.");
ok(isCaretPos(gPanel, line),
"The editor caret position is not properly set.");
}
const testAfterReload = Task.async(function* () {
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
ok(selectedActor,
"There should be a selected item in the sources pane after reload.");
ok(!selectedBreakpoint,
"There should be no selected breakpoint in the sources pane after reload.");
yield testBreakpoint(18, true);
yield testBreakpoint(19, true);
yield testBreakpoint(20, true);
yield testBreakpoint(21, true);
yield testBreakpoint(22, true);
yield testBreakpoint(23, true);
yield testBreakpoint(24, true);
yield testBreakpoint(25, true);
yield testBreakpoint(26, true);
yield testBreakpoint(27, true);
yield testBreakpoint(28, true);
yield testBreakpoint(29, true);
yield testBreakpoint(30, true);
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded again.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(gSources._selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
});
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield addBreakpoints();
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 13,
"13 breakpoints currently added.");
yield resumeAndTestBreakpoint(20);
yield resumeAndTestBreakpoint(21);
yield resumeAndTestBreakpoint(22);
yield resumeAndTestBreakpoint(23);
yield resumeAndTestBreakpoint(24);
yield resumeAndTestBreakpoint(25);
yield resumeAndTestBreakpoint(27);
yield resumeAndTestBreakpoint(28);
yield resumeAndTestBreakpoint(29);
yield resumeAndTestBreakpoint(30);
yield resumeAndTestNoBreakpoint();
let sourceShown = waitForSourceShown(gPanel, ".html");
reload(gPanel),
yield sourceShown;
testAfterReload();
// When a breakpoint is highlighted, the conditional expression
// popup opens, and then closes, and when it closes it sends the
// expression to the server which pauses the server. Make sure
// we wait if there is a pending request.
if (gDebugger.gThreadClient.state === "paused") {
yield waitForThreadEvents(gPanel, "resumed");
}
closeDebuggerAndFinish(gPanel);
});
});
}

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

@ -1,214 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test adding and modifying conditional breakpoints (with server-side support)
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
const CONDITIONAL_POPUP_SHOWN = gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN;
function addBreakpoint1() {
return actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 });
}
function addBreakpoint2() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
setCaretPosition(19);
gSources._onCmdAddBreakpoint();
return finished;
}
function modBreakpoint2() {
setCaretPosition(19);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
gSources._onCmdAddConditionalBreakpoint();
return popupShown;
}
function* addBreakpoint3() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
setCaretPosition(20);
gSources._onCmdAddConditionalBreakpoint();
yield finished;
yield popupShown;
}
function* modBreakpoint3() {
setCaretPosition(20);
let popupShown = waitForDebuggerEvents(gPanel, CONDITIONAL_POPUP_SHOWN);
gSources._onCmdAddConditionalBreakpoint();
yield popupShown;
typeText(gSources._cbTextbox, "bamboocha");
let finished = waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
EventUtils.sendKey("RETURN", gDebugger);
yield finished;
}
function addBreakpoint4() {
let finished = waitForDispatch(gPanel, constants.ADD_BREAKPOINT);
setCaretPosition(21);
gSources._onCmdAddBreakpoint();
return finished;
}
function delBreakpoint4() {
let finished = waitForDispatch(gPanel, constants.REMOVE_BREAKPOINT);
setCaretPosition(21);
gSources._onCmdAddBreakpoint();
return finished;
}
function testBreakpoint(aLine, aPopupVisible, aConditionalExpression) {
const source = queries.getSelectedSource(getState());
ok(source,
"There should be a selected item in the sources pane.");
const bp = queries.getBreakpoint(getState(), {
actor: source.actor,
line: aLine
});
const bpItem = gSources._getBreakpoint(bp);
ok(bp, "There should be a breakpoint.");
ok(bpItem, "There should be a breakpoint in the sources pane.");
is(bp.location.actor, source.actor,
"The breakpoint on line " + aLine + " wasn't added on the correct source.");
is(bp.location.line, aLine,
"The breakpoint on line " + aLine + " wasn't found.");
is(!!bp.disabled, false,
"The breakpoint on line " + aLine + " should be enabled.");
is(gSources._conditionalPopupVisible, aPopupVisible,
"The breakpoint on line " + aLine + " should have a correct popup state (2).");
is(bp.condition, aConditionalExpression,
"The breakpoint on line " + aLine + " should have a correct conditional expression.");
}
function testNoBreakpoint(aLine) {
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
ok(selectedActor,
"There should be a selected item in the sources pane for line " + aLine + ".");
ok(!selectedBreakpoint,
"There should be no selected brekapoint in the sources pane for line " + aLine + ".");
ok(isCaretPos(gPanel, aLine),
"The editor caret position is not properly set.");
}
function setCaretPosition(aLine) {
gEditor.setCursor({ line: aLine - 1, ch: 0 });
}
function clickOnBreakpoint(aIndex) {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[aIndex],
gDebugger);
}
function waitForConditionUpdate() {
// This will close the popup and send another request to update
// the condition
gSources._hideConditionalPopup();
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
is(gDebugger.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(queries.getSourceCount(getState()), 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
is(queries.getBreakpoints(getState()).length, 0,
"No breakpoints currently added.");
yield addBreakpoint1();
testBreakpoint(18, false, undefined);
yield addBreakpoint2();
testBreakpoint(19, false, undefined);
yield modBreakpoint2();
testBreakpoint(19, true, undefined);
yield waitForConditionUpdate();
yield addBreakpoint3();
testBreakpoint(20, true, "");
yield waitForConditionUpdate();
yield modBreakpoint3();
testBreakpoint(20, false, "bamboocha");
yield addBreakpoint4();
testBreakpoint(21, false, undefined);
yield delBreakpoint4();
setCaretPosition(18);
is(gSources._selectedBreakpoint.location.line, 18,
"The selected breakpoint is line 18");
yield testBreakpoint(18, false, undefined);
setCaretPosition(19);
is(gSources._selectedBreakpoint.location.line, 19,
"The selected breakpoint is line 19");
yield testBreakpoint(19, false, "");
setCaretPosition(20);
is(gSources._selectedBreakpoint.location.line, 20,
"The selected breakpoint is line 20");
yield testBreakpoint(20, false, "bamboocha");
setCaretPosition(17);
yield testNoBreakpoint(17);
setCaretPosition(21);
yield testNoBreakpoint(21);
clickOnBreakpoint(0);
is(gSources._selectedBreakpoint.location.line, 18,
"The selected breakpoint is line 18");
yield testBreakpoint(18, false, undefined);
clickOnBreakpoint(1);
is(gSources._selectedBreakpoint.location.line, 19,
"The selected breakpoint is line 19");
yield testBreakpoint(19, false, "");
clickOnBreakpoint(2);
is(gSources._selectedBreakpoint.location.line, 20,
"The selected breakpoint is line 20");
testBreakpoint(20, true, "bamboocha");
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,73 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that conditional breakpoints survive disabled breakpoints
* (with server-side support)
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function waitForConditionUpdate() {
// This will close the popup and send another request to update
// the condition
gSources._hideConditionalPopup();
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
const location = { actor: gSources.selectedValue, line: 18 };
yield actions.addBreakpoint(location, "hello");
yield actions.disableBreakpoint(location);
yield actions.addBreakpoint(location);
const bp = queries.getBreakpoint(getState(), location);
is(bp.condition, "hello", "The conditional expression is correct.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
yield finished;
const textbox = gDebugger.document.getElementById("conditional-breakpoint-panel-textbox");
is(textbox.value, "hello", "The expression is correct (2).");
yield waitForConditionUpdate();
yield actions.disableBreakpoint(location);
yield actions.setBreakpointCondition(location, "foo");
yield actions.addBreakpoint(location);
finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWN);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
yield finished;
is(textbox.value, "foo", "The expression is correct (3).");
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,46 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that conditional breakpoints with undefined expressions
* maintain their conditions when re-enabling them (with
* server-side support)
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
const location = { actor: gSources.selectedValue, line: 18 };
yield actions.addBreakpoint(location, "");
yield actions.disableBreakpoint(location);
yield actions.addBreakpoint(location);
const bp = queries.getBreakpoint(getState(), location);
is(bp.condition, "", "The conditional expression is correct.");
resumeDebuggerThenCloseAndFinish(gPanel);
});
});
}

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

@ -1,134 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test conditional breakpoints throwing exceptions
* with server support
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
const options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const queries = gDebugger.require("./content/queries");
const constants = gDebugger.require("./content/constants");
const actions = bindActionCreators(gPanel);
const getState = gDebugger.DebuggerController.getState;
function resumeAndTestBreakpoint(line) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
return finished;
}
function resumeAndTestNoBreakpoint() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("ermahgerd"), 253,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[0],
"The correct source is selected.");
ok(gSources.selectedItem,
"There should be a selected source in the sources pane.");
ok(!gSources._selectedBreakpoint,
"There should be no selected breakpoint in the sources pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.document.querySelectorAll(".dbg-breakpoint").length, 6,
"There should be thirteen visible breakpoints.");
});
gDebugger.gThreadClient.resume();
return finished;
}
function testBreakpoint(line, highlightBreakpoint) {
// Highlight the breakpoint only if required.
if (highlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, line).then(() => testBreakpoint(line));
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: line });
return finished;
}
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpoint;
let selectedBreakpointItem = gSources._getBreakpoint(selectedBreakpoint);
let source = queries.getSource(getState(), selectedActor);
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint.");
ok(selectedBreakpointItem,
"There should be a selected breakpoint item in the sources pane.");
is(selectedBreakpoint.location.actor, source.actor,
"The breakpoint on line " + line + " wasn't added on the correct source.");
is(selectedBreakpoint.location.line, line,
"The breakpoint on line " + line + " wasn't found.");
is(!!selectedBreakpoint.location.disabled, false,
"The breakpoint on line " + line + " should be enabled.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not have been shown.");
isnot(selectedBreakpoint.condition, undefined,
"The breakpoint on line " + line + " should have a conditional expression.");
ok(isCaretPos(gPanel, line),
"The editor caret position is not properly set.");
}
Task.spawn(function* () {
let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
callInTab(gTab, "ermahgerd");
yield onCaretUpdated;
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 18 }, " 1a"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 19 }, "new Error()"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 20 }, "true"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 21 }, "false"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 22 }, "0"
);
yield actions.addBreakpoint(
{ actor: gSources.selectedValue, line: 23 }, "randomVar"
);
yield resumeAndTestBreakpoint(18);
yield resumeAndTestBreakpoint(19);
yield resumeAndTestBreakpoint(20);
yield resumeAndTestBreakpoint(23);
yield resumeAndTestNoBreakpoint();
closeDebuggerAndFinish(gPanel);
});
});
}

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

@ -1,53 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure javascript bookmarklet scripts appear and load correctly in the source list
*/
const TAB_URL = EXAMPLE_URL + "doc_script-bookmarklet.html";
const BOOKMARKLET_SCRIPT_CODE = "console.log('bookmarklet executed');";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gSources = gDebugger.DebuggerView.Sources;
const gBreakpoints = gDebugger.DebuggerController.Breakpoints;
const getState = gDebugger.DebuggerController.getState;
const constants = gDebugger.require("./content/constants");
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
return Task.spawn(function* () {
const added = waitForNextDispatch(gDebugger.DebuggerController, constants.ADD_SOURCE);
// NOTE: devtools debugger panel needs to be already open,
// or the bookmarklet script will not be shown in the sources panel
callInTab(gTab, "injectBookmarklet", BOOKMARKLET_SCRIPT_CODE);
yield added;
is(queries.getSourceCount(getState()), 2, "Should have 2 sources");
const sources = queries.getSources(getState());
const sourceActor = Object.keys(sources).filter(k => {
return sources[k].url.indexOf("javascript:") === 0;
})[0];
const source = sources[sourceActor];
ok(source, "Source exists.");
let res = yield actions.loadSourceText(source);
is(res.text, BOOKMARKLET_SCRIPT_CODE, "source is correct");
is(res.contentType, "text/javascript", "contentType is correct");
yield closeDebuggerAndFinish(gPanel);
});
});
}

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

@ -1,146 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the sources cache knows how to cache sources when prompted.
*/
const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
const TOTAL_SOURCES = 4;
function test() {
let options = {
source: EXAMPLE_URL + "code_function-search-01.js",
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
const gEditor = gDebugger.DebuggerView.editor;
const gSources = gDebugger.DebuggerView.Sources;
const gPrevLabelsCache = gDebugger.SourceUtils._labelsCache;
const gPrevGroupsCache = gDebugger.SourceUtils._groupsCache;
const getState = gDebugger.DebuggerController.getState;
const queries = gDebugger.require("./content/queries");
const actions = bindActionCreators(gPanel);
function initialChecks() {
ok(gEditor.getText().includes("First source!"),
"Editor text contents appears to be correct.");
is(gSources.selectedItem.attachment.label, "code_function-search-01.js",
"The currently selected label in the sources container is correct.");
ok(getSelectedSourceURL(gSources).includes("code_function-search-01.js"),
"The currently selected value in the sources container appears to be correct.");
is(gSources.itemCount, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " sources present in the sources list.");
is(gSources.visibleItems.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " sources visible in the sources list.");
is(gSources.attachments.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " attachments stored in the sources container model.");
is(gSources.values.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " values stored in the sources container model.");
info("Source labels: " + gSources.attachments.toSource());
info("Source values: " + gSources.values.toSource());
is(gSources.attachments[0].label, "code_function-search-01.js",
"The first source label is correct.");
ok(gSources.attachments[0].source.url.includes("code_function-search-01.js"),
"The first source value appears to be correct.");
is(gSources.attachments[1].label, "code_function-search-02.js",
"The second source label is correct.");
ok(gSources.attachments[1].source.url.includes("code_function-search-02.js"),
"The second source value appears to be correct.");
is(gSources.attachments[2].label, "code_function-search-03.js",
"The third source label is correct.");
ok(gSources.attachments[2].source.url.includes("code_function-search-03.js"),
"The third source value appears to be correct.");
is(gSources.attachments[3].label, "doc_function-search.html",
"The third source label is correct.");
ok(gSources.attachments[3].source.url.includes("doc_function-search.html"),
"The third source value appears to be correct.");
is(gDebugger.SourceUtils._labelsCache.size, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " labels cached.");
is(gDebugger.SourceUtils._groupsCache.size, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " groups cached.");
}
function performReloadAndTestState() {
gDebugger.gTarget.once("will-navigate", testStateBeforeReload);
gDebugger.gTarget.once("navigate", testStateAfterReload);
return reloadActiveTab(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
}
function testCacheIntegrity(cachedSources) {
const contents = {
[EXAMPLE_URL + "code_function-search-01.js"]: "First source!",
[EXAMPLE_URL + "code_function-search-02.js"]: "Second source!",
[EXAMPLE_URL + "code_function-search-03.js"]: "Third source!",
[EXAMPLE_URL + "doc_function-search.html"]: "Peanut butter jelly time!"
};
const sourcesText = getState().sources.sourcesText;
is(Object.keys(sourcesText).length, cachedSources.length,
"The right number of sources is cached");
cachedSources.forEach(sourceUrl => {
const source = queries.getSourceByURL(getState(), EXAMPLE_URL + sourceUrl);
const content = queries.getSourceText(getState(), source.actor);
ok(content, "Source text is cached");
ok(content.text.includes(contents[source.url]), "Source text is correct");
});
}
function fetchAllSources() {
const sources = queries.getSources(getState());
return Promise.all(Object.keys(sources).map(k => {
const source = sources[k];
return actions.loadSourceText(source);
}));
}
function testStateBeforeReload() {
is(gSources.itemCount, 0,
"There should be no sources present in the sources list during reload.");
is(gDebugger.SourceUtils._labelsCache, gPrevLabelsCache,
"The labels cache has been refreshed during reload and no new objects were created.");
is(gDebugger.SourceUtils._groupsCache, gPrevGroupsCache,
"The groups cache has been refreshed during reload and no new objects were created.");
is(gDebugger.SourceUtils._labelsCache.size, 0,
"There should be no labels cached during reload");
is(gDebugger.SourceUtils._groupsCache.size, 0,
"There should be no groups cached during reload");
}
function testStateAfterReload() {
is(gSources.itemCount, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " sources present in the sources list.");
is(gDebugger.SourceUtils._labelsCache.size, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " labels cached after reload.");
is(gDebugger.SourceUtils._groupsCache.size, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " groups cached after reload.");
}
Task.spawn(function* () {
yield initialChecks();
yield testCacheIntegrity(["code_function-search-01.js"]);
yield fetchAllSources();
yield testCacheIntegrity([
"code_function-search-01.js",
"code_function-search-02.js",
"code_function-search-03.js",
"doc_function-search.html"
]);
yield performReloadAndTestState();
closeDebuggerAndFinish(gPanel);
});
});
}

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

@ -1,35 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure iframe scripts don't disappear after few reloads (bug 1259743)
*/
"use strict";
const IFRAME_URL = "data:text/html;charset=utf-8," +
"<script>function fn() { console.log('hello'); }</script>" +
"<div onclick='fn()'>hello</div>";
const TAB_URL = `data:text/html;charset=utf-8,<iframe src="${IFRAME_URL}"/>`;
add_task(async function() {
let [, panel] = await initDebugger();
let dbg = panel.panelWin;
let newSource;
newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
reload(panel, TAB_URL);
await newSource;
ok(true, "Source event fired on initial load");
for (let i = 0; i < 5; i++) {
newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
reload(panel);
await newSource;
ok(true, `Source event fired after ${i + 1} reloads`);
}
await closeDebuggerAndFinish(panel);
});

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

@ -1,110 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* When the split console is focused and the debugger is open,
* debugger shortcut keys like F11 should work
*/
const TAB_URL = EXAMPLE_URL + "doc_step-many-statements.html";
function test() {
// This does the same assertions over a series of sub-tests, and it
// can timeout in linux e10s. No sense in breaking it up into multiple
// tests, so request extra time.
requestLongerTimeout(2);
let gDebugger, gToolbox, gThreadClient, gTab, gPanel;
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
gPanel = aPanel;
gDebugger = aPanel.panelWin;
gToolbox = gDevTools.getToolbox(aPanel.target);
gTab = aTab;
gThreadClient = gDebugger.DebuggerController.activeThread;
testConsole();
});
let testConsole = Task.async(function* () {
// We need to open the split console (with an ESC keypress),
// then get the script into a paused state by pressing a button in the page,
// ensure focus is in the split console,
// synthesize a few keys - important ones we share listener for are
// "resumeKey", "stepOverKey", "stepInKey", "stepOutKey"
// then check that
// * The input cursor remains in the console's input box
// * The paused state is as expected
// * the debugger cursor is where we want it
let jsterm = yield getSplitConsole(gToolbox, gDebugger);
// The console is now open (if not make the test fail already)
ok(gToolbox.splitConsole, "Split console is shown.");
// Information for sub-tests. When 'key' is synthesized 'keyRepeat' times,
// cursor should be at 'caretLine' of this test..
let stepTests = [
{key: "KEY_F11", keyRepeat: 1, caretLine: 16},
{key: "KEY_F11", keyRepeat: 2, caretLine: 18},
{key: "KEY_F11", keyRepeat: 2, caretLine: 27},
{key: "KEY_F10", keyRepeat: 1, caretLine: 27},
{key: "KEY_F11", keyRepeat: 1, caretLine: 19},
{key: "KEY_F11", keyRepeat: 5, caretLine: 29},
{key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 32},
{key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 34},
{key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 34}
];
// Trigger script that stops at debugger statement
executeSoon(() => generateMouseClickInTab(gTab,
"content.document.getElementById('start')"));
yield waitForPause(gThreadClient);
// Focus the console and add event listener to track whether it loses focus
// (Must happen after generateMouseClickInTab() call)
let consoleLostFocus = false;
jsterm.focus();
const node = jsterm.inputNode || jsterm.node;
node.addEventListener("blur", () => {consoleLostFocus = true;});
is(gThreadClient.paused, true,
"Should be paused at debugger statement.");
// As long as we have test work to do..
for (let i = 0, thisTest; thisTest = stepTests[i]; i++) {
// First we send another key event if required by the test
while (thisTest.keyRepeat > 0) {
thisTest.keyRepeat --;
let keyMods = thisTest.modifier === "Shift" ? {shiftKey:true} : {};
executeSoon(() => {EventUtils.synthesizeKey(thisTest.key, keyMods);});
yield waitForPause(gThreadClient);
}
// We've sent the required number of keys
// Here are the conditions we're interested in: paused state,
// cursor still in console (tested later), caret correct in editor
is(gThreadClient.paused, true,
"Should still be paused");
// ok(isCaretPos(gPanel, thisTest.caretLine),
// "Test " + i + ": CaretPos at line " + thisTest.caretLine);
ok(isDebugPos(gPanel, thisTest.caretLine),
"Test " + i + ": DebugPos at line " + thisTest.caretLine);
}
// Did focus go missing while we were stepping?
is(consoleLostFocus, false, "Console input should not lose focus");
// We're done with the tests in the stepTests array
// Last key we test is "resume"
executeSoon(() => EventUtils.synthesizeKey("KEY_F8"));
// We reset the variable tracking loss of focus to test the resume case
consoleLostFocus = false;
gPanel.target.on("thread-resumed", () => {
is(gThreadClient.paused, false,
"Should not be paused after resume");
// Final test: did we preserve console inputNode focus during resume?
is(consoleLostFocus, false, "Resume - console should keep focus");
closeDebuggerAndFinish(gPanel);
});
});
}

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