зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1314057 - Remove old debugger assets. r=jdescottes
This commit is contained in:
Родитель
e996e1e744
Коммит
7aef56cc4e
|
@ -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
|
||||
// <, 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="©Cmd.label;"
|
||||
accesskey="©Cmd.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");
|
Двоичный файл не отображается.
Двоичные данные
devtools/client/debugger/test/mochitest/addon5.xpi
Двоичные данные
devtools/client/debugger/test/mochitest/addon5.xpi
Двоичный файл не отображается.
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче