Bug 1742774 - [devtools] Add remove all breakpoints button in breakpoints header r=nchevobbe

In this patch
 - Added remove all breakpoints button in the Breakpoints list header bar
 - Start clearing `asyncStore.pendingBreakpoints` when we remove all the breakpoints
 - Add jest tests

Differential Revision: https://phabricator.services.mozilla.com/D150350
This commit is contained in:
Hubert Boma Manilla 2022-07-06 21:57:30 +00:00
Родитель 881532a243
Коммит 4644b088bf
6 изменённых файлов: 80 добавлений и 18 удалений

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

@ -8,6 +8,7 @@
*/
import { PROMISE } from "../utils/middleware/promise";
import { asyncStore } from "../../utils/prefs";
import {
getBreakpointsList,
getXHRBreakpoints,
@ -131,6 +132,7 @@ export function removeAllBreakpoints(cx) {
breakpointList.map(bp => dispatch(removeBreakpoint(cx, bp)))
);
dispatch({ type: "CLEAR_BREAKPOINTS" });
asyncStore.pendingBreakpoints = {};
};
}

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

@ -13,10 +13,27 @@ import {
import { mockCommandClient } from "../../tests/helpers/mockCommandClient";
import { mockPendingBreakpoint } from "../../tests/helpers/breakpoints.js";
import { makePendingLocationId } from "../../../utils/breakpoint";
import { asyncStore } from "../../../utils/prefs";
const {
registerStoreObserver,
} = require("devtools/client/shared/redux/subscriber");
jest.mock("../../../utils/prefs", () => ({
prefs: {
expressions: [],
},
asyncStore: {
pendingBreakpoints: {},
},
features: {
inlinePreview: true,
},
}));
function mockClient(positionsResponse = {}) {
return {
...mockCommandClient,
setSkipPausing: jest.fn(),
getSourceActorBreakpointPositions: async () => positionsResponse,
getSourceActorBreakableLines: async () => [],
};
@ -307,10 +324,29 @@ describe("breakpoints", () => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
const pendingBreakpoints = { [id]: mockedPendingBreakpoint };
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1], "6": [2] }),
{ pendingBreakpoints }
);
asyncStore.pendingBreakpoints = pendingBreakpoints;
const store = createStore(mockClient({ "5": [1], "6": [2] }), {
pendingBreakpoints,
});
const { dispatch, getState, cx } = store;
// This mocks the updatePrefs observer which listens & updates the asyncStore
// when the reducer state changes. See https://searchfox.org/mozilla-central/
// rev/287583a4a605eee8cd2d41381ffaea7a93d7b987/devtools/client/debugger/
// src/utils/bootstrap.js#114-142
function mockUpdatePrefs(state, oldState) {
if (
selectors.getPendingBreakpoints(oldState) &&
selectors.getPendingBreakpoints(oldState) !==
selectors.getPendingBreakpoints(state)
) {
asyncStore.pendingBreakpoints = selectors.getPendingBreakpoints(state);
}
}
registerStoreObserver(store, mockUpdatePrefs);
const loc1 = {
sourceId: "a",
@ -332,16 +368,24 @@ describe("breakpoints", () => {
const bSource = await dispatch(actions.newGeneratedSource(makeSource("b")));
await dispatch(actions.loadSourceText({ cx, source: bSource }));
expect(selectors.getBreakpointsList(getState())).toHaveLength(0);
expect(selectors.getPendingBreakpointList(getState())).toHaveLength(1);
expect(Object.keys(asyncStore.pendingBreakpoints)).toHaveLength(1);
await dispatch(actions.addBreakpoint(cx, loc1));
await dispatch(actions.addBreakpoint(cx, loc2));
// The breakpoint list contains all the live breakpoints while the pending-breakpoint
// list stores contains all the breakpoints persisted across toolbox reopenings.
expect(selectors.getBreakpointsList(getState())).toHaveLength(2);
expect(selectors.getPendingBreakpointList(getState())).toHaveLength(3);
expect(Object.keys(asyncStore.pendingBreakpoints)).toHaveLength(3);
await dispatch(actions.removeAllBreakpoints(cx));
const bps = selectors.getBreakpointsList(getState());
const pendingBps = selectors.getPendingBreakpointList(getState());
expect(bps).toHaveLength(0);
expect(pendingBps).toHaveLength(0);
expect(selectors.getBreakpointsList(getState())).toHaveLength(0);
expect(selectors.getPendingBreakpointList(getState())).toHaveLength(0);
expect(Object.keys(asyncStore.pendingBreakpoints)).toHaveLength(0);
});
it("should toggle a breakpoint at a location", async () => {

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

@ -92,6 +92,7 @@ class SecondaryPanes extends Component {
toggleEventLogging: PropTypes.func.isRequired,
toggleMapScopes: PropTypes.func.isRequired,
workers: PropTypes.array.isRequired,
removeAllBreakpoints: PropTypes.func.isRequired,
};
}
@ -159,6 +160,20 @@ class SecondaryPanes extends Component {
return buttons;
}
breakpointsHeaderButtons() {
return [
debugBtn(
evt => {
evt.stopPropagation();
this.props.removeAllBreakpoints(this.props.cx);
},
"removeAll",
"removeAll",
L10N.getStr("breakpointMenuItem.deleteAll")
),
];
}
getScopeItem() {
return {
header: L10N.getStr("scopes.header"),
@ -304,6 +319,7 @@ class SecondaryPanes extends Component {
return {
header: L10N.getStr("breakpoints.header"),
className: "breakpoints-pane",
buttons: this.breakpointsHeaderButtons(),
component: (
<Breakpoints
shouldPauseOnExceptions={shouldPauseOnExceptions}
@ -501,4 +517,5 @@ export default connect(mapStateToProps, {
toggleMapScopes: actions.toggleMapScopes,
breakOnNext: actions.breakOnNext,
toggleEventLogging: actions.toggleEventLogging,
removeAllBreakpoints: actions.removeAllBreakpoints,
})(SecondaryPanes);

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

@ -146,6 +146,10 @@ html[dir="rtl"] .img.more-tabs {
mask-image: url(chrome://devtools/content/debugger/images/prettyPrint.svg);
}
.img.removeAll {
mask-image: url(chrome://devtools/skin/images/clear.svg)
}
.img.refresh {
mask-image: url(chrome://devtools/content/debugger/images/reload.svg);
}

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

@ -9,6 +9,9 @@ const { Provider } = require("react-redux");
import ToolboxProvider from "devtools/client/framework/store-provider";
import flags from "devtools/shared/flags";
const {
registerStoreObserver,
} = require("devtools/client/shared/redux/subscriber");
const { AppConstants } = require("resource://gre/modules/AppConstants.jsm");
@ -102,15 +105,6 @@ export function unmountRoot() {
ReactDOM.unmountComponentAtNode(getMountElement());
}
function registerStoreObserver(store, subscriber) {
let oldState = store.getState();
store.subscribe(() => {
const state = store.getState();
subscriber(state, oldState);
oldState = state;
});
}
function updatePrefs(state, oldState) {
const hasChanged = selector =>
selector(oldState) && selector(oldState) !== selector(state);

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

@ -40,6 +40,7 @@ add_task(async function() {
"resource://devtools/client/shared/vendor/react-dom-factories.js",
"resource://devtools/client/shared/vendor/react-redux.js",
"resource://devtools/client/shared/vendor/redux.js",
"resource://devtools/client/shared/redux/subscriber.js",
"resource://devtools/client/shared/worker-utils.js",
"resource://devtools/client/debugger/src/workers/parser/index.js",
"resource://devtools/client/shared/source-map/index.js",