Bug 1460971 - Update Debugger Frontend v52. r=jdescottes

MozReview-Commit-ID: J3gIzebCWre
This commit is contained in:
Jason Laster 2018-05-11 15:33:10 -04:00
Родитель 922e46b318
Коммит 0da2193389
34 изменённых файлов: 156 добавлений и 1881 удалений

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

@ -1,9 +1,9 @@
This is the debugger.html project output.
See https://github.com/devtools-html/debugger.html
Version 50
Version 52
Comparison: https://github.com/devtools-html/debugger.html/compare/release-49...release-50
Comparison: https://github.com/devtools-html/debugger.html/compare/release-51...release-52
Packages:
- babel-plugin-transform-es2015-modules-commonjs @6.26.2

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

@ -973,16 +973,17 @@ img.close::before {
.search-field {
position: relative;
height: 27px;
width: calc(100% - 1px);
background-color: var(--theme-toolbar-background);
border-bottom: 1px solid var(--theme-splitter-color);
padding: 5px 10px;
padding-right: 10px;
display: flex;
flex-shrink: 0;
}
.search-field.big {
padding: 5px 10px;
height: 40px;
}
@ -993,23 +994,27 @@ img.close::before {
}
.search-field i svg {
width: 16px;
}
.search-field.big i svg {
width: 22px;
}
.search-field.big input {
line-height: 40px;
}
.search-field input {
position: relative;
margin-left: 30px;
border: none;
line-height: 30px;
background-color: var(--theme-toolbar-background);
color: var(--theme-body-color-active);
width: calc(100% - 38px);
flex: 1;
}
.search-field.big input {
position: relative;
margin-left: 30px;
font-size: 14px;
line-height: 40px;
}
.search-field input:focus {
@ -1022,22 +1027,14 @@ img.close::before {
.search-field i.magnifying-glass,
.search-field i.sad-face {
position: absolute;
top: 50%;
padding: 2px 0;
padding: 6px;
width: 24px;
margin-top: -12px;
}
.search-field i.sad-face {
padding-top: 1px;
}
.search-field.big i.magnifying-glass,
.search-field.big i.sad-face {
padding: 14px;
position: absolute;
width: 40px;
margin-top: -20px;
}
.search-field .magnifying-glass path,
@ -1053,16 +1050,16 @@ img.close::before {
color: var(--theme-highlight-orange);
}
.search-field.big .summary {
line-height: 40px;
}
.search-field .summary {
line-height: 27px;
padding-right: 10px;
color: var(--theme-body-color-inactive);
}
.search-field.big .summary {
line-height: 40px;
}
.search-field .search-nav-buttons {
display: flex;
user-select: none;
@ -1869,7 +1866,7 @@ html .toggle-button.end.vertical svg {
}
.search-field .close-btn {
margin-top: 12px;
align-self: center;
}
.search-bottom-bar * {
@ -2918,6 +2915,7 @@ debug-expression-error {
color: var(--theme-content-color1);
position: relative;
transition: all 0.25s ease;
cursor: pointer;
}
.breakpoints-list .breakpoint-heading,
@ -3087,7 +3085,7 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line {
}
.CodeMirror.cm-s-mozilla-breakpoint {
cursor: default;
cursor: pointer;
}
.CodeMirror.cm-s-mozilla-breakpoint .CodeMirror-lines {

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

@ -24745,6 +24745,10 @@ const inExpression = (parent, grandParent) => inStepExpression(parent) || t.isJS
const isExport = node => t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node);
function getStartLine(node) {
return node.loc.start.line;
}
function getPausePoints(sourceId) {
const state = {};
(0, _ast.traverseAst)(sourceId, { enter: onEnter }, state);
@ -24781,10 +24785,12 @@ function onEnter(node, ancestors, state) {
}
if (isReturn(node)) {
// We do not want to pause at the return and the call e.g. return foo()
if (isCall(node.argument)) {
// We do not want to pause at the return if the
// argument is a call on the same line e.g. return foo()
if (isCall(node.argument) && getStartLine(node) == getStartLine(node.argument)) {
return addEmptyPoint(state, startLocation);
}
return addStopPoint(state, startLocation);
}

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

@ -112,15 +112,16 @@ function setPausePoints(sourceId) {
return;
}
const pausePoints = await (0, _parser.getPausePoints)(source.id);
const pausePoints = await (0, _parser.getPausePoints)(sourceId);
if ((0, _devtoolsSourceMap.isGeneratedId)(source.id)) {
await client.setPausePoints(source.id, pausePoints);
if ((0, _devtoolsSourceMap.isGeneratedId)(sourceId)) {
await client.setPausePoints(sourceId, pausePoints);
}
dispatch({
type: "SET_PAUSE_POINTS",
source: source.toJS(),
sourceText: source.text,
sourceId,
pausePoints
});
};

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

@ -18,14 +18,13 @@ exports.breakOnNext = breakOnNext;
* @static
*/
function breakOnNext() {
return ({
return async ({
dispatch,
client
}) => {
client.breakOnNext();
await client.breakOnNext();
return dispatch({
type: "BREAK_ON_NEXT",
value: true
type: "BREAK_ON_NEXT"
});
};
}

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

@ -142,6 +142,15 @@ Object.defineProperty(exports, "pauseOnExceptions", {
}
});
var _selectComponent = require("./selectComponent");
Object.defineProperty(exports, "selectComponent", {
enumerable: true,
get: function () {
return _selectComponent.selectComponent;
}
});
var _selectFrame = require("./selectFrame");
Object.defineProperty(exports, "selectFrame", {

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

@ -19,6 +19,7 @@ DevToolsModules(
'paused.js',
'pauseOnExceptions.js',
'resumed.js',
'selectComponent.js',
'selectFrame.js',
'setPopupObjectProperties.js',
'skipPausing.js',

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

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.selectComponent = selectComponent;
/* 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/>. */
function selectComponent(componentIndex) {
return async ({
dispatch
}) => {
dispatch({
type: "SELECT_COMPONENT",
componentIndex
});
};
}

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

@ -118,7 +118,7 @@ function selectLocation(location) {
}
const source = sourceRecord.toJS();
dispatch((0, _tabs.addTab)(source, 0));
dispatch((0, _tabs.addTab)(source.url, 0));
dispatch({
type: "SELECT_SOURCE",
source,

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

@ -22,10 +22,10 @@ var _selectors = require("../../selectors/index");
* Redux actions for the sources state
* @module actions/sources
*/
function addTab(source, tabIndex) {
function addTab(url, tabIndex) {
return {
type: "ADD_TAB",
source,
url,
tabIndex
};
}

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

@ -436,7 +436,7 @@ class QuickOpenModal extends _react.Component {
return _react2.default.createElement(_Modal2.default, {
"in": enabled,
handleClose: this.closeModal
}, _react2.default.createElement(_SearchInput2.default, {
}, _react2.default.createElement(_SearchInput2.default, _extends({
query: query,
hasPrefix: true,
count: this.getResultCount(),
@ -447,8 +447,11 @@ class QuickOpenModal extends _react.Component {
onKeyDown: this.onKeyDown,
handleClose: this.closeModal,
expanded: expanded,
showClose: false,
selectedItemId: expanded && items[selectedIndex] ? items[selectedIndex].id : ""
}), this.renderLoading(), newResults && _react2.default.createElement(_ResultList2.default, _extends({
}, this.isSourceSearch() ? {
size: "big"
} : {})), this.renderLoading(), newResults && _react2.default.createElement(_ResultList2.default, _extends({
key: "results",
items: items,
selected: selectedIndex,

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

@ -14,6 +14,10 @@ var _actions = require("../../actions/index");
var _actions2 = _interopRequireDefault(_actions);
var _classnames = require("devtools/client/debugger/new/dist/vendors").vendored["classnames"];
var _classnames2 = _interopRequireDefault(_classnames);
var _selectors = require("../../selectors/index");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@ -22,6 +26,14 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
* 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/>. */
class ReactComponentStack extends _react.PureComponent {
onMouseDown(e, componentIndex) {
if (e.nativeEvent.which == 3) {
return;
}
this.props.selectComponent(componentIndex);
}
render() {
const {
componentStack
@ -29,14 +41,19 @@ class ReactComponentStack extends _react.PureComponent {
return _react2.default.createElement("div", {
className: "pane frames"
}, _react2.default.createElement("ul", null, componentStack.slice().reverse().map((component, index) => _react2.default.createElement("li", {
key: index
className: (0, _classnames2.default)("frame", {
selected: this.props.selectedComponentIndex === index
}),
key: index,
onMouseDown: e => this.onMouseDown(e, index)
}, component))));
}
}
const mapStateToProps = state => ({
extra: (0, _selectors.getExtra)(state)
extra: (0, _selectors.getExtra)(state),
selectedComponentIndex: (0, _selectors.getSelectedComponentIndex)(state)
});
exports.default = (0, _reactRedux.connect)(mapStateToProps, _actions2.default)(ReactComponentStack);

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

@ -8,7 +8,6 @@ DIRS += [
'PrimaryPanes',
'SecondaryPanes',
'shared',
'test',
]
DevToolsModules(

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

@ -141,7 +141,8 @@ class SearchInput extends _react.Component {
selectedItemId,
showErrorEmoji,
size,
summaryMsg
summaryMsg,
showClose
} = this.props;
const inputProps = {
className: (0, _classnames2.default)({
@ -172,7 +173,7 @@ class SearchInput extends _react.Component {
"aria-expanded": expanded
}, this.renderSvg(), _react2.default.createElement("input", inputProps), summaryMsg && _react2.default.createElement("div", {
className: "summary"
}, summaryMsg), this.renderNav(), _react2.default.createElement(_Close2.default, {
}, summaryMsg), this.renderNav(), showClose && _react2.default.createElement(_Close2.default, {
handleClick: handleClose,
buttonClass: size
})));
@ -184,6 +185,7 @@ SearchInput.defaultProps = {
expanded: false,
hasPrefix: false,
selectedItemId: "",
size: ""
size: "",
showClose: true
};
exports.default = SearchInput;

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

@ -1,316 +0,0 @@
"use strict";
var _react = require("devtools/client/shared/vendor/react");
var _react2 = _interopRequireDefault(_react);
var _enzyme = require("enzyme/index");
var _Outline = require("../../components/PrimaryPanes/Outline");
var _Outline2 = _interopRequireDefault(_Outline);
var _testHead = require("../../utils/test-head");
var _devtoolsContextmenu = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-contextmenu"];
var _clipboard = require("../../utils/clipboard");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
jest.mock("devtools-contextmenu", () => ({
showMenu: jest.fn()
}));
jest.mock("../../utils/clipboard", () => ({
copyToTheClipboard: jest.fn()
}));
const sourceId = "id";
const mockFunctionText = "mock function text";
function generateDefaults(overrides) {
return _objectSpread({
selectLocation: jest.genMockFunction(),
selectedSource: {
get: () => sourceId
},
getFunctionText: jest.fn().mockReturnValue(mockFunctionText),
flashLineRange: jest.fn(),
isHidden: false,
symbols: {},
selectedLocation: {
sourceId: sourceId
},
onAlphabetizeClick: jest.fn()
}, overrides);
}
function render(overrides = {}) {
const props = generateDefaults(overrides);
const component = (0, _enzyme.shallow)(_react2.default.createElement(_Outline2.default.WrappedComponent, props));
const instance = component.instance();
return {
component,
props,
instance
};
}
describe("Outline", () => {
afterEach(() => {
_clipboard.copyToTheClipboard.mockClear();
_devtoolsContextmenu.showMenu.mockClear();
});
it("renders a list of functions when properties change", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("my_example_function1", 21), (0, _testHead.makeSymbolDeclaration)("my_example_function2", 22)]
};
const {
component
} = render({
symbols
});
expect(component).toMatchSnapshot();
});
it("selects a line of code in the current file on click", async () => {
const startLine = 12;
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("my_example_function", startLine)]
};
const {
component,
props
} = render({
symbols
});
const {
selectLocation
} = props;
const listItem = component.find("li").first();
listItem.simulate("click");
expect(selectLocation).toHaveBeenCalledWith({
line: startLine,
sourceId
});
});
describe("renders outline", () => {
describe("renders loading", () => {
it("if symbols is not defined", () => {
const {
component
} = render({
symbols: null
});
expect(component).toMatchSnapshot();
});
it("if symbols are loading", () => {
const {
component
} = render({
symbols: {
loading: true
}
});
expect(component).toMatchSnapshot();
});
});
it("renders ignore anonymous functions", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("my_example_function1", 21), (0, _testHead.makeSymbolDeclaration)("anonymous", 25)]
};
const {
component
} = render({
symbols
});
expect(component).toMatchSnapshot();
});
describe("renders placeholder", () => {
it("`No File Selected` if selectedSource is not defined", async () => {
const {
component
} = render({
selectedSource: null
});
expect(component).toMatchSnapshot();
});
it("`No functions` if all func are anonymous", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("anonymous", 25), (0, _testHead.makeSymbolDeclaration)("anonymous", 30)]
};
const {
component
} = render({
symbols
});
expect(component).toMatchSnapshot();
});
it("`No functions` if symbols has no func", async () => {
const symbols = {
functions: []
};
const {
component
} = render({
symbols
});
expect(component).toMatchSnapshot();
});
});
it("sorts functions alphabetically by function name", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("c_function", 25), (0, _testHead.makeSymbolDeclaration)("x_function", 30), (0, _testHead.makeSymbolDeclaration)("a_function", 70)]
};
const {
component
} = render({
symbols: symbols,
alphabetizeOutline: true
});
expect(component).toMatchSnapshot();
});
it("calls onAlphabetizeClick when sort button is clicked", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("example_function", 25)]
};
const {
component,
props
} = render({
symbols
});
await component.find(".outline-footer").find("button").simulate("click", {});
expect(props.onAlphabetizeClick).toHaveBeenCalled();
});
it("renders functions by function class", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("x_function", 25, 26, "x_klass"), (0, _testHead.makeSymbolDeclaration)("a2_function", 30, 31, "a_klass"), (0, _testHead.makeSymbolDeclaration)("a1_function", 70, 71, "a_klass")],
classes: [(0, _testHead.makeSymbolDeclaration)("x_klass", 24, 27), (0, _testHead.makeSymbolDeclaration)("a_klass", 29, 72)]
};
const {
component
} = render({
symbols: symbols
});
expect(component).toMatchSnapshot();
});
it("renders functions by function class, alphabetically", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("x_function", 25, 26, "x_klass"), (0, _testHead.makeSymbolDeclaration)("a2_function", 30, 31, "a_klass"), (0, _testHead.makeSymbolDeclaration)("a1_function", 70, 71, "a_klass")],
classes: [(0, _testHead.makeSymbolDeclaration)("x_klass", 24, 27), (0, _testHead.makeSymbolDeclaration)("a_klass", 29, 72)]
};
const {
component
} = render({
symbols: symbols,
alphabetizeOutline: true
});
expect(component).toMatchSnapshot();
});
it("selects class on click on class headline", async () => {
const symbols = {
functions: [(0, _testHead.makeSymbolDeclaration)("x_function", 25, 26, "x_klass")],
classes: [(0, _testHead.makeSymbolDeclaration)("x_klass", 24, 27)]
};
const {
component,
props
} = render({
symbols: symbols
});
await component.find("h2").simulate("click", {});
expect(props.selectLocation).toHaveBeenCalledWith({
line: 24,
sourceId: sourceId
});
});
it("does not select an item if selectedSource is not defined", async () => {
const {
instance,
props
} = render({
selectedSource: null
});
await instance.selectItem({});
expect(props.selectLocation).not.toHaveBeenCalled();
});
});
describe("onContextMenu of Outline", () => {
it("is called onContextMenu for each item", async () => {
const event = {
event: "oncontextmenu"
};
const fn = (0, _testHead.makeSymbolDeclaration)("exmple_function", 2);
const symbols = {
functions: [fn]
};
const {
component,
instance
} = render({
symbols
});
instance.onContextMenu = jest.fn(() => {});
await component.find(".outline-list__element").simulate("contextmenu", event);
expect(instance.onContextMenu).toHaveBeenCalledWith(event, fn);
});
it("does not show menu with no selected source", async () => {
const mockEvent = {
preventDefault: jest.fn(),
stopPropagation: jest.fn()
};
const {
instance
} = render({
selectedSource: null
});
await instance.onContextMenu(mockEvent, {});
expect(mockEvent.preventDefault).toHaveBeenCalled();
expect(mockEvent.stopPropagation).toHaveBeenCalled();
expect(_devtoolsContextmenu.showMenu).not.toHaveBeenCalled();
});
it("shows menu to copy func, copies to clipboard on click", async () => {
const startLine = 12;
const endLine = 21;
const func = (0, _testHead.makeSymbolDeclaration)("my_example_function", startLine, endLine);
const symbols = {
functions: [func]
};
const mockEvent = {
preventDefault: jest.fn(),
stopPropagation: jest.fn()
};
const {
instance,
props
} = render({
symbols
});
await instance.onContextMenu(mockEvent, func);
expect(mockEvent.preventDefault).toHaveBeenCalled();
expect(mockEvent.stopPropagation).toHaveBeenCalled();
const expectedMenuOptions = [{
accesskey: "F",
click: expect.any(Function),
disabled: false,
id: "node-menu-copy-function",
label: "Copy function"
}];
expect(props.getFunctionText).toHaveBeenCalledWith(12);
expect(_devtoolsContextmenu.showMenu).toHaveBeenCalledWith(mockEvent, expectedMenuOptions);
_devtoolsContextmenu.showMenu.mock.calls[0][1][0].click();
expect(_clipboard.copyToTheClipboard).toHaveBeenCalledWith(mockFunctionText);
expect(props.flashLineRange).toHaveBeenCalledWith({
end: endLine,
sourceId: sourceId,
start: startLine
});
});
});
});

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

@ -1,248 +0,0 @@
"use strict";
var _react = require("devtools/client/shared/vendor/react");
var _react2 = _interopRequireDefault(_react);
var _enzyme = require("enzyme/index");
var _immutable = require("devtools/client/shared/vendor/immutable");
var _ProjectSearch = require("../ProjectSearch");
var _projectTextSearch = require("../../reducers/project-text-search");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
const hooks = {
on: [],
off: []
};
const shortcuts = {
dispatch(eventName) {
hooks.on.forEach(hook => {
if (hook.event === eventName) {
hook.cb();
}
});
hooks.off.forEach(hook => {
if (hook.event === eventName) {
hook.cb();
}
});
},
on: jest.fn((event, cb) => hooks.on.push({
event,
cb
})),
off: jest.fn((event, cb) => hooks.off.push({
event,
cb
}))
};
const context = {
shortcuts
};
const testResults = (0, _immutable.List)([{
filepath: "testFilePath1",
matches: [{
match: "match1",
value: "some thing match1",
column: 30
}, {
match: "match2",
value: "some thing match2",
column: 60
}, {
match: "match3",
value: "some thing match3",
column: 90
}]
}, {
filepath: "testFilePath2",
matches: [{
match: "match4",
value: "some thing match4",
column: 80
}, {
match: "match5",
value: "some thing match5",
column: 40
}]
}]);
const testMatch = {
match: "match1",
value: "some thing match1",
column: 30
};
function render(overrides = {}, mounted = false) {
const props = _objectSpread({
status: "DONE",
sources: {},
results: (0, _immutable.List)([]),
query: "foo",
activeSearch: "project",
closeProjectSearch: jest.fn(),
searchSources: jest.fn(),
clearSearch: jest.fn(),
updateSearchStatus: jest.fn(),
selectLocation: jest.fn(),
doSearchForHighlight: jest.fn()
}, overrides);
return mounted ? (0, _enzyme.mount)(_react2.default.createElement(_ProjectSearch.ProjectSearch, props), {
context
}) : (0, _enzyme.shallow)(_react2.default.createElement(_ProjectSearch.ProjectSearch, props), {
context
});
}
describe("ProjectSearch", () => {
beforeEach(() => {
context.shortcuts.on.mockClear();
context.shortcuts.off.mockClear();
});
it("renders nothing when disabled", () => {
const component = render({
activeSearch: null
});
expect(component).toMatchSnapshot();
});
it("where <Enter> has not been pressed", () => {
const component = render({
query: ""
});
expect(component).toMatchSnapshot();
});
it("found no search results", () => {
const component = render();
expect(component).toMatchSnapshot();
});
it("should display loading message while search is in progress", () => {
const component = render({
query: "match",
status: _projectTextSearch.statusType.fetching
});
expect(component).toMatchSnapshot();
});
it("found search results", () => {
const component = render({
query: "match",
results: testResults
}, true);
expect(component).toMatchSnapshot();
});
it("turns off shortcuts on unmount", () => {
const component = render({
query: ""
});
expect(component).toMatchSnapshot();
component.unmount();
expect(context.shortcuts.off).toHaveBeenCalled();
});
it("calls inputOnChange", () => {
const component = render({
results: testResults
}, true);
component.find("SearchInput input").simulate("change", {
target: {
value: "bar"
}
});
expect(component.state().inputValue).toEqual("bar");
});
it("onKeyDown Escape/Other", () => {
const searchSources = jest.fn();
const component = render({
results: testResults,
searchSources
}, true);
component.find("SearchInput input").simulate("keydown", {
key: "Escape"
});
expect(searchSources).not.toHaveBeenCalled();
searchSources.mockClear();
component.find("SearchInput input").simulate("keydown", {
key: "Other",
stopPropagation: jest.fn()
});
expect(searchSources).not.toHaveBeenCalled();
});
it("onKeyDown Enter", () => {
const searchSources = jest.fn();
const component = render({
results: testResults,
searchSources
}, true);
component.find("SearchInput input").simulate("keydown", {
key: "Enter",
stopPropagation: jest.fn()
});
expect(searchSources).toHaveBeenCalledWith("foo");
});
it("onEnterPress shortcut no match or setExpanded", () => {
const selectLocation = jest.fn();
const component = render({
results: testResults,
selectLocation
}, true);
component.instance().focusedItem = {};
shortcuts.dispatch("Enter");
expect(selectLocation).not.toHaveBeenCalled();
});
it("onEnterPress shortcut match", () => {
const selectLocation = jest.fn();
const component = render({
results: testResults,
selectLocation
}, true);
component.instance().focusedItem = {
match: testMatch
};
shortcuts.dispatch("Enter");
expect(selectLocation).toHaveBeenCalledWith(testMatch);
});
it("onEnterPress shortcut setExpanded", () => {
const selectLocation = jest.fn();
const component = render({
results: testResults,
selectLocation
}, true);
const setExpanded = jest.fn();
const testFile = {
filepath: "testFilePath1",
matches: [testMatch]
};
component.instance().focusedItem = {
setExpanded,
file: testFile,
expanded: true
};
shortcuts.dispatch("Enter");
expect(setExpanded).toHaveBeenCalledWith(testFile, false);
});
describe("showErrorEmoji", () => {
it("false if not done & results", () => {
const component = render({
status: _projectTextSearch.statusType.fetching,
results: testResults
});
expect(component).toMatchSnapshot();
});
it("false if not done & no results", () => {
const component = render({
status: _projectTextSearch.statusType.fetching
});
expect(component).toMatchSnapshot();
}); // "false if done & has results"
// is the same test as "found search results"
// "true if done & has no results"
// is the same test as "found no search results"
});
});

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

@ -1,277 +0,0 @@
"use strict";
var _react = require("devtools/client/shared/vendor/react");
var _react2 = _interopRequireDefault(_react);
var _enzyme = require("enzyme/index");
var _QuickOpenModal = require("../QuickOpenModal");
var _fuzzaldrinPlus = require("devtools/client/debugger/new/dist/vendors").vendored["fuzzaldrin-plus"];
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
jest.mock("fuzzaldrin-plus");
function generateModal(propOverrides, renderType = "shallow") {
const props = _objectSpread({
enabled: false,
query: "",
searchType: "sources",
sources: [],
tabs: [],
selectLocation: jest.fn(),
setQuickOpenQuery: jest.fn(),
highlightLineRange: jest.fn(),
clearHighlightLineRange: jest.fn(),
closeQuickOpen: jest.fn()
}, propOverrides);
return {
wrapper: renderType === "shallow" ? (0, _enzyme.shallow)(_react2.default.createElement(_QuickOpenModal.QuickOpenModal, props)) : (0, _enzyme.mount)(_react2.default.createElement(_QuickOpenModal.QuickOpenModal, props)),
props
};
}
describe("QuickOpenModal", () => {
beforeEach(() => {
_fuzzaldrinPlus.filter.mockClear();
});
test("Doesn't render when disabled", () => {
const {
wrapper
} = generateModal();
expect(wrapper).toMatchSnapshot();
});
test("Renders when enabled", () => {
const {
wrapper
} = generateModal({
enabled: true
});
expect(wrapper).toMatchSnapshot();
});
test("Basic render with mount", () => {
const {
wrapper
} = generateModal({
enabled: true
}, "mount");
expect(wrapper).toMatchSnapshot();
});
test("Basic render with mount & searchType = functions", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "@",
searchType: "functions",
symbols: {
functions: [],
variables: []
}
}, "mount");
expect(wrapper).toMatchSnapshot();
});
test("Ensure anonymous functions do not render in QuickOpenModal", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "@",
searchType: "functions",
symbols: {
functions: [{
title: "anonymous"
}, {
title: "c"
}, {
title: "anonymous"
}],
variables: []
}
}, "mount");
expect(wrapper.find("ResultList")).toHaveLength(1);
expect(wrapper.find("li")).toHaveLength(1);
});
test("Basic render with mount & searchType = variables", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "#",
searchType: "variables",
symbols: {
functions: [],
variables: []
}
}, "mount");
expect(wrapper).toMatchSnapshot();
});
test("Basic render with mount & searchType = shortcuts", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "?",
searchType: "shortcuts",
symbols: {
functions: [],
variables: []
}
}, "mount");
expect(wrapper.find("ResultList")).toHaveLength(1);
expect(wrapper.find("li")).toHaveLength(3);
});
test("updateResults on enable", () => {
const {
wrapper
} = generateModal({}, "mount");
expect(wrapper).toMatchSnapshot();
wrapper.setProps({
enabled: true
});
expect(wrapper).toMatchSnapshot();
});
test("basic source search", () => {
const {
wrapper
} = generateModal({
enabled: true,
symbols: {
functions: [],
variables: []
}
}, "mount");
wrapper.find("input").simulate("change", {
target: {
value: "somefil"
}
});
expect(_fuzzaldrinPlus.filter).toHaveBeenCalledWith([], "somefil", {
key: "value",
maxResults: 1000
});
});
test("basic gotoSource search", () => {
const {
wrapper
} = generateModal({
enabled: true,
searchType: "gotoSource",
symbols: {
functions: [],
variables: []
}
}, "mount");
wrapper.find("input").simulate("change", {
target: {
value: "somefil:33"
}
});
expect(_fuzzaldrinPlus.filter).toHaveBeenCalledWith([], "somefil", {
key: "value",
maxResults: 1000
});
});
test("basic symbol seach", () => {
const {
wrapper
} = generateModal({
enabled: true,
searchType: "functions",
symbols: {
functions: [],
variables: []
},
// symbol searching relies on a source being selected.
// So we dummy out the source and the API.
selectedSource: {
get: jest.fn(() => true)
}
}, "mount");
wrapper.find("input").simulate("change", {
target: {
value: "@someFunc"
}
});
expect(_fuzzaldrinPlus.filter).toHaveBeenCalledWith([], "someFunc", {
key: "value",
maxResults: 1000
});
});
test("Simple goto search query = :abc & searchType = goto", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: ":abc",
searchType: "goto",
symbols: {
functions: [],
variables: []
}
}, "mount");
expect(wrapper).toMatchSnapshot();
expect(wrapper.state().results).toEqual(null);
});
describe("showErrorEmoji", () => {
it("true when no count + query", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "test",
searchType: ""
}, "mount");
expect(wrapper).toMatchSnapshot();
});
it("false when count + query", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "dasdasdas"
}, "mount");
wrapper.setState(() => ({
results: [1, 2]
}));
expect(wrapper).toMatchSnapshot();
});
it("false when no query", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: "",
searchType: ""
}, "mount");
expect(wrapper).toMatchSnapshot();
});
it("false when goto numeric ':2222'", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: ":2222",
searchType: "goto"
}, "mount");
expect(wrapper).toMatchSnapshot();
});
it("true when goto not numeric ':22k22'", () => {
const {
wrapper
} = generateModal({
enabled: true,
query: ":22k22",
searchType: "goto"
}, "mount");
expect(wrapper).toMatchSnapshot();
});
});
});

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

@ -1,28 +0,0 @@
"use strict";
var _react = require("devtools/client/shared/vendor/react");
var _react2 = _interopRequireDefault(_react);
var _enzyme = require("enzyme/index");
var _ShortcutsModal = require("../ShortcutsModal");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* 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/>. */
describe("ShortcutsModal", () => {
it("renders when enabled", () => {
const enabled = true;
const wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_ShortcutsModal.ShortcutsModal, {
enabled: enabled
}));
expect(wrapper).toMatchSnapshot();
});
it("renders nothing when not enabled", () => {
const wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_ShortcutsModal.ShortcutsModal, null));
expect(wrapper.text()).toBe("");
});
});

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

@ -1,639 +0,0 @@
"use strict";
var _react = require("devtools/client/shared/vendor/react");
var _react2 = _interopRequireDefault(_react);
var _enzyme = require("enzyme/index");
var _SourcesTree = require("../../components/PrimaryPanes/SourcesTree");
var _SourcesTree2 = _interopRequireDefault(_SourcesTree);
var _immutable = require("devtools/client/shared/vendor/immutable");
var I = _interopRequireWildcard(_immutable);
var _devtoolsContextmenu = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-contextmenu"];
var _clipboard = require("../../utils/clipboard");
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
jest.mock("devtools-contextmenu", () => ({
showMenu: jest.fn()
}));
jest.mock("../../utils/clipboard", () => ({
copyToTheClipboard: jest.fn()
}));
describe("SourcesTree", () => {
afterEach(() => {
_clipboard.copyToTheClipboard.mockClear();
_devtoolsContextmenu.showMenu.mockClear();
});
it("Should show the tree with nothing expanded", async () => {
const {
component
} = render();
expect(component).toMatchSnapshot();
});
describe("When loading initial source", () => {
it("Shows the tree with one.js, two.js and three.js expanded", async () => {
const {
component,
props
} = render();
await component.setProps(_objectSpread({}, props, {
expanded: ["one.js", "two.js", "three.js"]
}));
expect(component).toMatchSnapshot();
});
});
describe("After changing expanded nodes", () => {
it("Shows the tree with four.js, five.js and six.js expanded", async () => {
const {
component,
props
} = render();
await component.setProps(_objectSpread({}, props, {
expanded: ["four.js", "five.js", "six.js"]
}));
expect(component).toMatchSnapshot();
});
});
describe("on receiving new props", () => {
describe("recreates tree", () => {
it("does not recreate tree if no new source is added", async () => {
const {
component,
props,
defaultState
} = render();
const mockSource = I.Map({
"server1.conn13.child1/41": createMockSource("server1.conn13.child1/41", "http://mdn.com/three.js")
});
await component.setProps(_objectSpread({}, props, {
sources: mockSource
}));
expect(component.state("uncollapsedTree")).toEqual(defaultState.uncollapsedTree);
});
it("updates tree with a new item", async () => {
const {
component,
props
} = render();
const sources = props.sources.merge({
"server1.conn13.child1/42": createMockSource("server1.conn13.child1/42", "http://mdn.com/four.js")
});
await component.setProps(_objectSpread({}, props, {
sources: sources
}));
expect(component.state("uncollapsedTree").contents[0].contents).toHaveLength(4);
});
it("updates sources if sources are emptied", async () => {
const {
component,
props,
defaultState
} = render();
expect(defaultState.uncollapsedTree.contents).toHaveLength(1);
await component.setProps(_objectSpread({}, props, {
sources: I.Map({})
}));
expect(component.state("uncollapsedTree").contents).toHaveLength(0);
});
it("recreates tree if projectRoot is changed", async () => {
const {
component,
props,
defaultState
} = render();
const sources = I.Map({
"server1.conn13.child1/41": createMockSource("server1.conn13.child1/41", "http://mozilla.com/three.js")
});
expect(defaultState.uncollapsedTree.contents[0].contents).toHaveLength(3);
await component.setProps(_objectSpread({}, props, {
sources: sources,
projectRoot: "mozilla"
}));
expect(component.state("uncollapsedTree").contents[0].contents).toHaveLength(1);
});
it("recreates tree if debugeeUrl is changed", async () => {
const {
component,
props,
defaultState
} = render();
const mockSource = I.Map({
"server1.conn13.child1/41": createMockSource("server1.conn13.child1/41", "http://mdn.com/three.js")
});
expect(defaultState.uncollapsedTree.contents[0].contents).toHaveLength(3);
await component.setProps(_objectSpread({}, props, {
debuggeeUrl: "mozilla",
sources: mockSource
}));
expect(component.state("uncollapsedTree").contents[0].contents).toHaveLength(1);
});
});
describe("updates list items", () => {
it("updates list items if shownSource changes", async () => {
const {
component,
props
} = render();
await component.setProps(_objectSpread({}, props, {
shownSource: "http://mdn.com/three.js"
}));
expect(component).toMatchSnapshot();
expect(props.selectLocation).toHaveBeenCalledWith({
sourceId: "server1.conn13.child1/41"
});
});
});
describe("updates highlighted items", () => {
it("updates highlightItems if selectedSource changes", async () => {
const {
component,
props
} = render();
const mockSource = I.Map({
"server1.conn13.child1/41": createMockSource("server1.conn13.child1/41", "http://mdn.com/three.js")
});
await component.setProps(_objectSpread({}, props, {
selectedSource: mockSource
}));
expect(component).toMatchSnapshot();
});
});
});
describe("focusItem", () => {
it("update the focused item", async () => {
const {
component,
instance,
props
} = render();
const item = createMockItem();
await instance.focusItem(item);
await component.update();
await component.find(".sources-list").simulate("keydown", {
keyCode: 13
});
expect(props.selectLocation).toHaveBeenCalledWith({
sourceId: item.contents.get("id")
});
});
});
describe("with custom root", () => {
it("renders custom root source list", async () => {
const {
component
} = render({
projectRoot: "mdn.com"
});
expect(component).toMatchSnapshot();
});
it("calls clearProjectDirectoryRoot on click", async () => {
const {
component,
props
} = render({
projectRoot: "mdn"
});
component.find(".sources-clear-root").simulate("click");
expect(props.clearProjectDirectoryRoot).toHaveBeenCalled();
});
it("renders empty custom root source list", async () => {
const {
component
} = render({
projectRoot: "custom",
sources: I.Map()
});
expect(component).toMatchSnapshot();
});
});
describe("onContextMenu of the tree", () => {
it("shows context menu on directory to set as root", async () => {
const menuOptions = [{
accesskey: "r",
click: expect.any(Function),
disabled: false,
id: "node-set-directory-root",
label: "Set directory root"
}];
const mockEvent = {
preventDefault: jest.fn(),
stopPropagation: jest.fn()
};
const {
props,
instance
} = render({
projectRoot: "root/"
});
await instance.onContextMenu(mockEvent, createMockDirectory());
expect(_devtoolsContextmenu.showMenu).toHaveBeenCalledWith(mockEvent, menuOptions);
expect(mockEvent.preventDefault).toHaveBeenCalled();
expect(mockEvent.stopPropagation).toHaveBeenCalled();
_devtoolsContextmenu.showMenu.mock.calls[0][1][0].click();
expect(props.setProjectDirectoryRoot).toHaveBeenCalled();
expect(props.clearProjectDirectoryRoot).not.toHaveBeenCalled();
expect(_clipboard.copyToTheClipboard).not.toHaveBeenCalled();
});
it("shows context menu on file to copy source uri", async () => {
const menuOptions = [{
accesskey: "u",
click: expect.any(Function),
disabled: false,
id: "node-menu-copy-source",
label: "Copy source URI"
}];
const mockEvent = {
preventDefault: jest.fn(),
stopPropagation: jest.fn()
};
const {
props,
instance
} = render({
projectRoot: "root/"
});
await instance.onContextMenu(mockEvent, createMockItem());
expect(_devtoolsContextmenu.showMenu).toHaveBeenCalledWith(mockEvent, menuOptions);
expect(mockEvent.preventDefault).toHaveBeenCalled();
expect(mockEvent.stopPropagation).toHaveBeenCalled();
_devtoolsContextmenu.showMenu.mock.calls[0][1][0].click();
expect(props.setProjectDirectoryRoot).not.toHaveBeenCalled();
expect(props.clearProjectDirectoryRoot).not.toHaveBeenCalled();
expect(_clipboard.copyToTheClipboard).toHaveBeenCalled();
});
it("shows context menu on root to remove directory root", async () => {
const menuOptions = [{
click: expect.any(Function),
disabled: false,
id: "node-remove-directory-root",
label: "Remove directory root"
}];
const {
props,
instance
} = render({
projectRoot: "root/"
});
const mockEvent = {
preventDefault: jest.fn(),
stopPropagation: jest.fn()
};
await instance.onContextMenu(mockEvent, createMockDirectory("root/", "root"));
expect(_devtoolsContextmenu.showMenu).toHaveBeenCalledWith(mockEvent, menuOptions);
expect(mockEvent.preventDefault).toHaveBeenCalled();
expect(mockEvent.stopPropagation).toHaveBeenCalled();
_devtoolsContextmenu.showMenu.mock.calls[0][1][0].click();
expect(props.setProjectDirectoryRoot).not.toHaveBeenCalled();
expect(props.clearProjectDirectoryRoot).toHaveBeenCalled();
expect(_clipboard.copyToTheClipboard).not.toHaveBeenCalled();
});
});
describe("renderItem", () => {
it("should show icon for webpack item", async () => {
const {
instance
} = render();
const item = createMockDirectory("webpack://", "webpack://");
const node = renderItem(instance, item);
expect(node).toMatchSnapshot();
});
it("should show icon for angular item", async () => {
const {
instance
} = render();
const item = createMockDirectory("ng://", "ng://");
const node = renderItem(instance, item);
expect(node).toMatchSnapshot();
});
it("should show icon for moz-extension item", async () => {
const {
instance
} = render();
const item = createMockDirectory("moz-extension://", "moz-extension://");
const node = renderItem(instance, item);
expect(node).toMatchSnapshot();
});
it("should show icon for folder with arrow", async () => {
const {
instance
} = render();
const node = renderItem(instance, createMockDirectory());
expect(node).toMatchSnapshot();
});
it("should show icon for folder with expanded arrow", async () => {
const {
instance
} = render();
const node = renderItem(instance, createMockDirectory(), 1, false, true);
expect(node).toMatchSnapshot();
});
it("should show focused item for folder with expanded arrow", async () => {
const {
instance
} = render();
const node = renderItem(instance, createMockDirectory(), 1, true, true);
expect(node).toMatchSnapshot();
});
it("should show source item with source icon", async () => {
const {
instance
} = render();
const node = renderItem(instance, createMockItem());
expect(node).toMatchSnapshot();
});
it("should show source item with source icon with focus", async () => {
const {
instance
} = render();
const node = renderItem(instance, createMockItem(), 1, true, false);
expect(node).toMatchSnapshot();
});
it("should show domain item", async () => {
const {
instance
} = render();
const item = createMockItem("root", "root");
const node = renderItem(instance, item, 0);
expect(node).toMatchSnapshot();
});
it("should show domain item as debuggee", async () => {
const {
instance
} = render();
const item = createMockItem("root", "http://mdn.com");
const node = renderItem(instance, item, 0);
expect(node).toMatchSnapshot();
});
it("should show domain item as debuggee with focus and arrow", async () => {
const {
instance
} = render();
const item = createMockDirectory("root", "http://mdn.com");
const node = renderItem(instance, item, 0, true);
expect(node).toMatchSnapshot();
});
it("should not show domain item when the projectRoot exists", async () => {
const {
instance
} = render({
projectRoot: "root/"
});
const node = renderItem(instance, createMockItem(), 0);
expect(node).toMatchSnapshot();
});
it("should show menu on contextmenu of an item", async () => {
const {
instance
} = render();
const item = createMockItem();
instance.onContextMenu = jest.fn(() => {});
const event = {
event: "contextmenu"
};
const node = (0, _enzyme.shallow)(renderItem(instance, item, 1, true));
node.simulate("contextmenu", event);
expect(instance.onContextMenu).toHaveBeenCalledWith(event, item);
});
it("should focus on and select item on click", async () => {
const {
component,
instance,
props
} = render();
const item = createMockItem();
const event = {
event: "click"
};
const setExpanded = jest.fn();
const node = (0, _enzyme.shallow)(renderItem(instance, item, 1, true, false, setExpanded));
node.simulate("click", event);
await component.find(".sources-list").simulate("keydown", {
keyCode: 13
});
expect(props.selectLocation).toHaveBeenCalledWith({
sourceId: item.contents.get("id")
});
expect(setExpanded).not.toHaveBeenCalled();
});
it("should focus on and expand directory on click", async () => {
const {
component,
instance,
props
} = render();
const event = {
event: "click"
};
const setExpanded = jest.fn();
const mockDirectory = createMockDirectory();
const node = (0, _enzyme.shallow)(renderItem(instance, mockDirectory, 1, true, false, setExpanded));
node.simulate("click", event);
expect(component.state("focusedItem")).toEqual(mockDirectory);
expect(setExpanded).toHaveBeenCalled();
expect(props.selectLocation).not.toHaveBeenCalledWith();
});
});
describe("selectItem", () => {
it("should select item with no children", async () => {
const {
instance,
props
} = render();
instance.selectItem(createMockItem());
expect(props.selectLocation).toHaveBeenCalledWith({
sourceId: "server1.conn13.child1/39"
});
});
it("should not select item with children", async () => {
const {
props,
instance
} = render();
instance.selectItem(createMockDirectory());
expect(props.selectLocation).not.toHaveBeenCalled();
});
it("should select item on enter onKeyDown event", async () => {
const {
component,
props,
instance
} = render();
await instance.focusItem(createMockItem());
await component.update();
await component.find(".sources-list").simulate("keydown", {
keyCode: 13
});
expect(props.selectLocation).toHaveBeenCalledWith({
sourceId: "server1.conn13.child1/39"
});
});
it("does not select if no item is focused on", async () => {
const {
component,
props
} = render();
await component.find(".sources-list").simulate("keydown", {
keyCode: 13
});
expect(props.selectLocation).not.toHaveBeenCalled();
});
});
describe("handles items", () => {
it("getChildren from directory", async () => {
const {
component
} = render();
const item = createMockDirectory("http://mdn.com/views", "views", ["a", "b"]);
const children = component.find("ManagedTree").props().getChildren(item);
expect(children).toEqual(["a", "b"]);
});
it("getChildren from non directory", async () => {
const {
component
} = render();
const children = component.find("ManagedTree").props().getChildren(createMockItem());
expect(children).toEqual([]);
});
it("onExpand", async () => {
const {
component,
props
} = render();
const expandedState = ["x", "y"];
await component.find("ManagedTree").props().onExpand({}, expandedState);
expect(props.setExpandedState).toHaveBeenCalledWith(expandedState);
});
it("onCollapse", async () => {
const {
component,
props
} = render();
const expandedState = ["y", "z"];
await component.find("ManagedTree").props().onCollapse({}, expandedState);
expect(props.setExpandedState).toHaveBeenCalledWith(expandedState);
});
it("getParent", async () => {
const {
component
} = render();
const item = component.state("sourceTree").contents[0].contents[0];
const parent = component.find("ManagedTree").props().getParent(item);
expect(parent.path).toEqual("mdn.com");
expect(parent.contents).toHaveLength(3);
});
});
describe("getPath", () => {
it("should return path for item", async () => {
const {
instance
} = render();
const path = instance.getPath(createMockItem());
expect(path).toEqual("http://mdn.com/one.js/one.js/");
});
it("should return path for blackboxedboxed item", async () => {
const item = createMockItem("http://mdn.com/blackboxed.js", "blackboxed.js", I.Map({
id: "server1.conn13.child1/59"
}));
const source = I.Map({
"server1.conn13.child1/59": createMockSource("server1.conn13.child1/59", "http://mdn.com/blackboxed.js", true)
});
const {
instance
} = render({
sources: source
});
const path = instance.getPath(item);
expect(path).toEqual("http://mdn.com/blackboxed.js/blackboxed.js/update");
});
});
});
function generateDefaults(overrides) {
const defaultSources = I.Map({
"server1.conn13.child1/39": createMockSource("server1.conn13.child1/39", "http://mdn.com/one.js"),
"server1.conn13.child1/40": createMockSource("server1.conn13.child1/40", "http://mdn.com/two.js"),
"server1.conn13.child1/41": createMockSource("server1.conn13.child1/41", "http://mdn.com/three.js")
});
return _objectSpread({
autoExpandAll: true,
selectLocation: jest.fn(),
setExpandedState: jest.fn(),
sources: defaultSources,
debuggeeUrl: "http://mdn.com",
clearProjectDirectoryRoot: jest.fn(),
setProjectDirectoryRoot: jest.fn(),
projectRoot: ""
}, overrides);
}
function renderItem(instance, item = createMockItem(), depth = 1, focused = false, expanded = false, setExpanded = jest.fn()) {
return instance.renderItem(item, depth, focused, null, expanded, {
setExpanded: setExpanded
});
}
function render(overrides = {}) {
const props = generateDefaults(overrides);
const component = (0, _enzyme.shallow)(_react2.default.createElement(_SourcesTree2.default.WrappedComponent, props));
const defaultState = component.state();
const instance = component.instance();
instance.shouldComponentUpdate = () => true;
return {
component,
props,
defaultState,
instance
};
}
function createMockSource(id, url, isBlackBoxed = false) {
return I.Map({
id: id,
url: url,
isPrettyPrinted: false,
isWasm: false,
sourceMapURL: null,
isBlackBoxed: isBlackBoxed,
loadedState: "unloaded"
});
}
function createMockDirectory(path = "folder/", name = "folder", contents = []) {
return {
name,
path,
contents
};
}
function createMockItem(path = "http://mdn.com/one.js", name = "one.js", contents = I.Map({
id: "server1.conn13.child1/39"
})) {
return {
name,
path,
contents
};
}

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

@ -1,50 +0,0 @@
"use strict";
var _react = require("devtools/client/shared/vendor/react");
var _react2 = _interopRequireDefault(_react);
var _enzyme = require("enzyme/index");
var _WelcomeBox = require("../WelcomeBox");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* 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/>. */
describe("WelomeBox", () => {
const setActiveSearch = () => null;
it("renders with default values", () => {
const wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_WelcomeBox.WelcomeBox, {
setActiveSearch: setActiveSearch
}));
expect(wrapper).toMatchSnapshot();
});
it("doesn't render toggle button in horizontal mode", () => {
const horizontal = true;
const wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_WelcomeBox.WelcomeBox, {
horizontal: horizontal,
setActiveSearch: setActiveSearch
}));
expect(wrapper.find("PaneToggleButton")).toHaveLength(0);
});
it("calls correct function on searchSources click", () => {
const openQuickOpen = jest.fn();
const wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_WelcomeBox.WelcomeBox, {
setActiveSearch: setActiveSearch,
openQuickOpen: openQuickOpen
}));
wrapper.find(".welcomebox__searchSources").simulate("click");
expect(openQuickOpen).toBeCalled();
});
it("calls correct function on searchProject click", () => {
const setActiveSearchSpy = jest.fn();
const wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_WelcomeBox.WelcomeBox, {
setActiveSearch: setActiveSearchSpy
}));
wrapper.find(".welcomebox__searchProject").simulate("click");
expect(setActiveSearchSpy).toBeCalled();
});
});

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

@ -1,45 +0,0 @@
"use strict";
var _enzyme = require("enzyme/index");
var _WhyPaused = require("../SecondaryPanes/Frames/WhyPaused.js/index");
var _WhyPaused2 = _interopRequireDefault(_WhyPaused);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* 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/>. */
describe("WhyPaused", () => {
it("should pause reason with message", () => {
const why = {
type: "breakpoint",
message: "bla is hit"
};
const component = (0, _enzyme.shallow)((0, _WhyPaused2.default)(why));
expect(component).toMatchSnapshot();
});
it("should show pause reason with exception details", () => {
const why = {
type: "exception",
exception: {
class: "Error",
preview: {
name: "ReferenceError",
message: "o is not defined"
}
}
};
const component = (0, _enzyme.shallow)((0, _WhyPaused2.default)(why));
expect(component).toMatchSnapshot();
});
it("should show pause reason with exception string", () => {
const why = {
type: "exception",
exception: "Not Available"
};
const component = (0, _enzyme.shallow)((0, _WhyPaused2.default)(why));
expect(component).toMatchSnapshot();
});
});

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

@ -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 += [
]
DevToolsModules(
'Outline.spec.js',
'ProjectSearch.spec.js',
'QuickOpenModal.spec.js',
'ShortcutsModal.spec.js',
'SourcesTree.spec.js',
'WelcomeBox.spec.js',
'WhyPaused.spec.js',
)

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

@ -70,11 +70,12 @@ function update(state = initialASTState(), action) {
case "SET_PAUSE_POINTS":
{
const {
source,
sourceText,
sourceId,
pausePoints
} = action;
const emptyLines = (0, _ast.findEmptyLines)(source, pausePoints);
return state.setIn(["pausePoints", source.id], pausePoints).setIn(["emptyLines", source.id], emptyLines);
const emptyLines = (0, _ast.findEmptyLines)(sourceText, pausePoints);
return state.setIn(["pausePoints", sourceId], pausePoints).setIn(["emptyLines", sourceId], emptyLines);
}
case "OUT_OF_SCOPE_LOCATIONS":

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

@ -24,6 +24,7 @@ exports.getFrameScope = getFrameScope;
exports.getSelectedScope = getSelectedScope;
exports.getSelectedScopeMappings = getSelectedScopeMappings;
exports.getSelectedFrameId = getSelectedFrameId;
exports.getSelectedComponentIndex = getSelectedComponentIndex;
exports.getTopFrame = getTopFrame;
exports.getDebuggeeUrl = getDebuggeeUrl;
exports.getSkipPausing = getSkipPausing;
@ -47,6 +48,7 @@ const createPauseState = exports.createPauseState = () => ({
isWaitingOnBreak: false,
frames: undefined,
selectedFrameId: undefined,
selectedComponentIndex: undefined,
frameScopes: {
generated: {},
original: {},
@ -177,6 +179,11 @@ function update(state = createPauseState(), action) {
selectedFrameId: action.frame.id
});
case "SELECT_COMPONENT":
return _objectSpread({}, state, {
selectedComponentIndex: action.componentIndex
});
case "SET_POPUP_OBJECT_PROPERTIES":
if (!action.properties) {
return _objectSpread({}, state);
@ -386,6 +393,10 @@ function getSelectedFrameId(state) {
return state.pause.selectedFrameId;
}
function getSelectedComponentIndex(state) {
return state.pause.selectedComponentIndex;
}
function getTopFrame(state) {
const frames = getFrames(state);
return frames && frames[0];

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

@ -115,7 +115,7 @@ function update(state = initialSourcesState(), action) {
return state.merge({
tabs: updateTabList({
sources: state
}, action.source.url)
}, action.url)
});
case "MOVE_TAB":

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

@ -4,7 +4,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'test',
]
DevToolsModules(

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

@ -1,189 +0,0 @@
"use strict";
var _getCallStackFrames = require("../getCallStackFrames");
var _immutable = require("devtools/client/shared/vendor/immutable");
var _lodash = require("devtools/client/shared/vendor/lodash");
/* 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/>. */
describe("getCallStackFrames selector", () => {
describe("library annotation", () => {
it("annotates React frames", () => {
const state = {
frames: [{
location: {
sourceId: "source1"
}
}, {
location: {
sourceId: "source2"
}
}, {
location: {
sourceId: "source2"
}
}],
sources: (0, _immutable.fromJS)({
source1: {
id: "source1",
url: "webpack:///src/App.js"
},
source2: {
id: "source2",
url: "webpack:///~/react-dom/lib/ReactCompositeComponent.js"
}
}),
selectedSource: (0, _immutable.fromJS)({
id: "sourceId-originalSource"
})
};
const frames = _getCallStackFrames.getCallStackFrames.resultFunc(state.frames, state.sources, state.selectedSource, true);
expect(frames[0]).not.toHaveProperty("library");
expect(frames[1]).toHaveProperty("library", "React");
expect(frames[2]).toHaveProperty("library", "React");
}); // Multiple Babel async frame groups occur when you have an async function
// calling another async function (a common case).
//
// There are two possible frame groups that can occur depending on whether
// one sets a breakpoint before or after an await
it("annotates frames related to Babel async transforms", () => {
const preAwaitGroup = [{
displayName: "asyncAppFunction",
location: {
sourceId: "bundle"
}
}, {
displayName: "tryCatch",
location: {
sourceId: "regenerator"
}
}, {
displayName: "invoke",
location: {
sourceId: "regenerator"
}
}, {
displayName: "defineIteratorMethods/</prototype[method]",
location: {
sourceId: "regenerator"
}
}, {
displayName: "step",
location: {
sourceId: "bundle"
}
}, {
displayName: "_asyncToGenerator/</<",
location: {
sourceId: "bundle"
}
}, {
displayName: "Promise",
location: {
sourceId: "promise"
}
}, {
displayName: "_asyncToGenerator/<",
location: {
sourceId: "bundle"
}
}, {
displayName: "asyncAppFunction",
location: {
sourceId: "app"
}
}];
const postAwaitGroup = [{
displayName: "asyncAppFunction",
location: {
sourceId: "bundle"
}
}, {
displayName: "tryCatch",
location: {
sourceId: "regenerator"
}
}, {
displayName: "invoke",
location: {
sourceId: "regenerator"
}
}, {
displayName: "defineIteratorMethods/</prototype[method]",
location: {
sourceId: "regenerator"
}
}, {
displayName: "step",
location: {
sourceId: "bundle"
}
}, {
displayName: "step/<",
location: {
sourceId: "bundle"
}
}, {
displayName: "run",
location: {
sourceId: "bundle"
}
}, {
displayName: "notify/<",
location: {
sourceId: "bundle"
}
}, {
displayName: "flush",
location: {
sourceId: "microtask"
}
}];
const state = {
frames: [...preAwaitGroup, ...postAwaitGroup],
sources: (0, _immutable.fromJS)({
app: {
id: "app",
url: "webpack///app.js"
},
bundle: {
id: "bundle",
url: "https://foo.com/bundle.js"
},
regenerator: {
id: "regenerator",
url: "webpack:///foo/node_modules/regenerator-runtime/runtime.js"
},
microtask: {
id: "microtask",
url: "webpack:///foo/node_modules/core-js/modules/_microtask.js"
},
promise: {
id: "promise",
url: "webpack///foo/node_modules/core-js/modules/es6.promise.js"
}
}),
selectedSource: (0, _immutable.fromJS)({
id: "sourceId-originalSource"
})
};
const frames = _getCallStackFrames.getCallStackFrames.resultFunc(state.frames, state.sources, state.selectedSource);
const babelFrames = (0, _lodash.pullAt)(frames, [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17]);
const otherFrames = frames;
expect(babelFrames).toEqual(Array(babelFrames.length).fill(expect.objectContaining({
library: "Babel"
})));
expect(otherFrames).not.toEqual(Array(babelFrames.length).fill(expect.objectContaining({
library: "Babel"
})));
});
});
});

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

@ -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/.
DIRS += [
]
DevToolsModules(
'getCallStackFrames.spec.js',
)

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

@ -44,8 +44,8 @@ function findBestMatchExpression(symbols, tokenPos) {
}, null);
}
function findEmptyLines(selectedSource, pausePoints) {
if (!pausePoints || !selectedSource) {
function findEmptyLines(sourceText, pausePoints) {
if (!pausePoints || !sourceText) {
return [];
}
@ -53,11 +53,11 @@ function findEmptyLines(selectedSource, pausePoints) {
const breakpoints = pausePointsList.filter(point => point.types.break);
const breakpointLines = breakpoints.map(point => point.location.line);
if (!selectedSource.text || breakpointLines.length == 0) {
if (!sourceText || breakpointLines.length == 0) {
return [];
}
const lineCount = selectedSource.text.split("\n").length;
const lineCount = sourceText.split("\n").length;
const sourceLines = (0, _lodash.range)(1, lineCount + 1);
return (0, _lodash.xor)(sourceLines, breakpointLines);
}

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

@ -37,7 +37,6 @@ DevToolsModules(
'source.js',
'tabs.js',
'task.js',
'test-head.js',
'text.js',
'timings.js',
'ui.js',

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

@ -40,6 +40,10 @@ const inExpression = (parent, grandParent) => inStepExpression(parent) || t.isJS
const isExport = node => t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node);
function getStartLine(node) {
return node.loc.start.line;
}
function getPausePoints(sourceId) {
const state = {};
(0, _ast.traverseAst)(sourceId, {
@ -81,8 +85,9 @@ function onEnter(node, ancestors, state) {
}
if (isReturn(node)) {
// We do not want to pause at the return and the call e.g. return foo()
if (isCall(node.argument)) {
// We do not want to pause at the return if the
// argument is a call on the same line e.g. return foo()
if (isCall(node.argument) && getStartLine(node) == getStartLine(node.argument)) {
return addEmptyPoint(state, startLocation);
}

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

@ -186,6 +186,7 @@ skip-if = os == "linux" # bug 1351952
[browser_dbg-outline.js]
[browser_dbg-pause-exceptions.js]
skip-if = !debug && (os == "win" && os_version == "6.1") # Bug 1456441
[browser_dbg-pause-on-next.js]
[browser_dbg-pause-ux.js]
skip-if = os == "win"
[browser_dbg-navigation.js]

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

@ -0,0 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that when pause on next is selected, we pause on the next execution
add_task(async function() {
const dbg = await initDebugger("doc-scripts.html");
clickElement(dbg, "pause");
await waitForState(dbg, state => dbg.selectors.getIsWaitingOnBreak(state))
invokeInTab("simple");
await waitForPaused(dbg, "simple3");
assertPaused(dbg);
});

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

@ -249,6 +249,15 @@ function assertNotPaused(dbg) {
ok(!isPaused(dbg), "client is not paused");
}
/**
* Assert that the debugger is currently paused.
* @memberof mochitest/asserts
* @static
*/
function assertPaused(dbg) {
ok(isPaused(dbg), "client is paused");
}
function getVisibleSelectedFrameLine(dbg) {
const { selectors: { getVisibleSelectedFrame }, getState } = dbg;
const frame = getVisibleSelectedFrame(getState());
@ -1014,6 +1023,7 @@ const selectors = {
debugErrorLine: ".new-debug-line-error",
codeMirror: ".CodeMirror",
resume: ".resume.active",
pause: ".pause.active",
sourceTabs: ".source-tabs",
stepOver: ".stepOver.active",
stepOut: ".stepOut.active",