Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Commit

Permalink
[breakpoints] save breakpoints via indexeddb and async-storage (#6741)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonLaster authored and darkwing committed Aug 6, 2018
1 parent ea7f43f commit 8506987
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 119 deletions.
11 changes: 8 additions & 3 deletions .babel/transform-mc.js
Expand Up @@ -36,6 +36,11 @@ const VENDORS = [
"Svg"
];

const moduleMapping = {
Telemetry: "devtools/client/shared/telemetry",
asyncStorage: "devtools/shared/async-storage"
};

/*
* Updates devtools-modules imports such as
* `import { Telemetry } from "devtools-modules"`
Expand All @@ -49,11 +54,11 @@ function updateDevtoolsModulesImport(path, t) {

for (let i = 0; i < specifiers.length; i++) {
let specifier = specifiers[i];

if (specifier.local.name === "Telemetry") {
const localName = specifier.local.name;
if (localName in moduleMapping) {
const newImport = t.importDeclaration(
[t.importDefaultSpecifier(specifier.local)],
t.stringLiteral("devtools/client/shared/telemetry")
t.stringLiteral(moduleMapping[localName])
);

if (specifiers.length > 1) {
Expand Down
1 change: 0 additions & 1 deletion configs/mozilla-central-mappings.js
Expand Up @@ -25,7 +25,6 @@ module.exports = Object.assign(
"react-redux": "devtools/client/shared/vendor/react-redux",
redux: "devtools/client/shared/vendor/redux",
"prop-types": "devtools/client/shared/vendor/react-prop-types",
"devtools-modules/src/utils/telemetry": "devtools/client/shared/telemetry",
"devtools-services": "Services",
"wasmparser/dist/WasmParser": "devtools/client/shared/vendor/WasmParser",
"wasmparser/dist/WasmDis": "devtools/client/shared/vendor/WasmDis"
Expand Down
10 changes: 10 additions & 0 deletions docs/dbg.md
Expand Up @@ -61,6 +61,16 @@ dbg.prefs.pauseOnExceptions = true;
dbg.prefs.pauseOnExceptions; // true
```

### prefs

`dbg.asyncStore` references the async store helper. You can use `dbg.asyncStore` to see or change the state of any item.

```js
dbg.asyncStore.pendingBreakpoints; // Promise(false)
dbg.asyncStore.pendingBreakpoints = true;
dbg.asyncStore.pendingBreakpoints; // Promise(true)
```

### features

`dbg.features` references the debugger's feature flags. You can use `dbg.features` to see or change the state of any flag.
Expand Down
34 changes: 18 additions & 16 deletions src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
Expand Up @@ -2,24 +2,26 @@

exports[`initializing when pending breakpoints exist in prefs syncs pending breakpoints 1`] = `
Object {
"astLocation": Object {
"name": undefined,
"offset": Object {
"http://localhost:8000/examples/bar.js:5:": Object {
"astLocation": Object {
"name": undefined,
"offset": Object {
"line": 5,
},
},
"condition": null,
"disabled": false,
"generatedLocation": Object {
"column": undefined,
"line": 5,
"sourceUrl": "http://localhost:8000/examples/bar.js",
},
"hidden": false,
"location": Object {
"column": undefined,
"line": 5,
"sourceUrl": "http://localhost:8000/examples/bar.js",
},
},
"condition": null,
"disabled": false,
"generatedLocation": Object {
"column": undefined,
"line": 5,
"sourceUrl": "http://localhost:8000/examples/bar.js",
},
"hidden": false,
"location": Object {
"column": undefined,
"line": 5,
"sourceUrl": "http://localhost:8000/examples/bar.js",
},
}
`;
Expand Down
138 changes: 67 additions & 71 deletions src/actions/tests/pending-breakpoints.spec.js
Expand Up @@ -13,11 +13,21 @@ import {
simpleMockThreadClient
} from "./helpers/threadClient.js";

import { prefs } from "../../utils/prefs";
import { asyncStore } from "../../utils/prefs";

function loadInitialState(opts = {}) {
const mockedPendingBreakpoint = mockPendingBreakpoint(opts);
const id = makePendingLocationId(mockedPendingBreakpoint.location);
asyncStore.pendingBreakpoints = { [id]: mockedPendingBreakpoint };

return { pendingBreakpoints: asyncStore.pendingBreakpoints };
}

jest.mock("../../utils/prefs", () => ({
prefs: {
expressions: [],
expressions: []
},
asyncStore: {
pendingBreakpoints: {}
},
features: {
Expand All @@ -39,15 +49,11 @@ import {
import { makePendingLocationId } from "../../utils/breakpoint";

describe("when adding breakpoints", () => {
const mockedPendingBreakpoint = mockPendingBreakpoint();

beforeEach(() => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
prefs.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
});

it("a corresponding pending breakpoint should be added", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);

await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText(makeSource("foo.js")));
Expand Down Expand Up @@ -76,7 +82,10 @@ describe("when adding breakpoints", () => {
});

it("add a corresponding pendingBreakpoint for each addition", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);

await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.newSource(makeSource("foo2")));
Expand All @@ -93,7 +102,10 @@ describe("when adding breakpoints", () => {
});

it("hidden breakponts do not create pending bps", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);

await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.loadSourceText(makeSource("foo")));
Expand All @@ -107,7 +119,10 @@ describe("when adding breakpoints", () => {
});

it("remove a corresponding pending breakpoint when deleting", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.newSource(makeSource("foo2")));
await dispatch(actions.loadSourceText(makeSource("foo")));
Expand All @@ -125,15 +140,11 @@ describe("when adding breakpoints", () => {
});

describe("when changing an existing breakpoint", () => {
const mockedPendingBreakpoint = mockPendingBreakpoint();

beforeEach(() => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
prefs.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
});

it("updates corresponding pendingBreakpoint", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
const bp = generateBreakpoint("foo");
const id = makePendingLocationId(bp.location);
await dispatch(actions.newSource(makeSource("foo")));
Expand All @@ -149,7 +160,10 @@ describe("when changing an existing breakpoint", () => {
});

it("if disabled, updates corresponding pendingBreakpoint", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
const bp = generateBreakpoint("foo");
const id = makePendingLocationId(bp.location);

Expand All @@ -164,7 +178,10 @@ describe("when changing an existing breakpoint", () => {
});

it("does not delete the pre-existing pendingBreakpoint", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
const bp = generateBreakpoint("foo.js");
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
Expand All @@ -183,23 +200,20 @@ describe("when changing an existing breakpoint", () => {
});

describe("initializing when pending breakpoints exist in prefs", () => {
const mockedPendingBreakpoint = mockPendingBreakpoint();

beforeEach(() => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
prefs.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
});

it("syncs pending breakpoints", async () => {
const { getState } = createStore(simpleMockThreadClient);
const id = makePendingLocationId(mockedPendingBreakpoint.location);
const { getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
const bps = selectors.getPendingBreakpoints(getState());
const bp = bps[id];
expect(bp).toMatchSnapshot();
expect(bps).toMatchSnapshot();
});

it("re-adding breakpoints update existing pending breakpoints", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
const bar = generateBreakpoint("bar.js");
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.loadSourceText(makeSource("bar.js")));
Expand All @@ -211,7 +225,10 @@ describe("initializing when pending breakpoints exist in prefs", () => {
});

it("adding bps doesn't remove existing pending breakpoints", async () => {
const { dispatch, getState } = createStore(simpleMockThreadClient);
const { dispatch, getState } = createStore(
simpleMockThreadClient,
loadInitialState()
);
const bp = generateBreakpoint("foo.js");

await dispatch(actions.newSource(makeSource("foo.js")));
Expand All @@ -225,46 +242,32 @@ describe("initializing when pending breakpoints exist in prefs", () => {
});

describe("initializing with disabled pending breakpoints in prefs", () => {
const mockedPendingBreakpoint = mockPendingBreakpoint({ disabled: true });

beforeEach(() => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
prefs.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
});

it("syncs breakpoints with pending breakpoints", async () => {
const expectedLocation = {
...mockedPendingBreakpoint.location,
sourceId: "bar.js"
};
const store = createStore(
simpleMockThreadClient,
loadInitialState({ disabled: true })
);

const store = createStore(simpleMockThreadClient);
const { getState, dispatch } = store;
const source = makeSource("bar.js");
await dispatch(actions.newSource(source));

await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(makeSource("bar.js")));

await waitForState(store, state =>
selectors.getBreakpoint(state, expectedLocation)
);
await waitForState(store, state => {
const bps = selectors.getBreakpointsForSource(state, "bar.js");
return bps && bps.size > 0;
});

const bp = selectors.getBreakpoint(getState(), expectedLocation);
expect(bp.location).toEqual(expectedLocation);
expect(bp.disabled).toEqual(mockedPendingBreakpoint.disabled);
const bp = selectors.getBreakpointForLine(getState(), "bar.js", 5);
expect(bp.location.sourceId).toEqual("bar.js");
expect(bp.disabled).toEqual(true);
});
});

describe("adding sources", () => {
const mockedPendingBreakpoint = mockPendingBreakpoint();

beforeEach(() => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
prefs.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
});

it("corresponding breakpoints are added for a single source", async () => {
const store = createStore(simpleMockThreadClient);
const store = createStore(simpleMockThreadClient, loadInitialState());
const { getState, dispatch } = store;

let bps = selectors.getBreakpoints(getState());
Expand All @@ -284,7 +287,7 @@ describe("adding sources", () => {
});

it("add corresponding breakpoints for multiple sources", async () => {
const store = createStore(simpleMockThreadClient);
const store = createStore(simpleMockThreadClient, loadInitialState());
const { getState, dispatch } = store;

let bps = selectors.getBreakpoints(getState());
Expand All @@ -307,13 +310,6 @@ describe("adding sources", () => {
});

describe("invalid breakpoint location", () => {
const mockedPendingBreakpoint = mockPendingBreakpoint();

beforeEach(() => {
const id = makePendingLocationId(mockedPendingBreakpoint.location);
prefs.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
});

it("a corrected corresponding pending breakpoint is added", async () => {
// setup
const bp = generateBreakpoint("foo.js");
Expand Down
20 changes: 15 additions & 5 deletions src/client/index.js
Expand Up @@ -6,7 +6,7 @@

import * as firefox from "./firefox";

import { prefs } from "../utils/prefs";
import { prefs, asyncStore } from "../utils/prefs";
import { setupHelper } from "../utils/dbg";

import {
Expand All @@ -25,6 +25,11 @@ function loadFromPrefs(actions: Object) {
}
}

async function loadInitialState() {
const pendingBreakpoints = await asyncStore.pendingBreakpoints;
return { pendingBreakpoints };
}

export async function onConnect(
connection: Object,
{ services, toolboxActions }: Object
Expand All @@ -35,10 +40,15 @@ export async function onConnect(
}

const commands = firefox.clientCommands;
const { store, actions, selectors } = bootstrapStore(commands, {
services,
toolboxActions
});
const initialState = await loadInitialState();
const { store, actions, selectors } = bootstrapStore(
commands,
{
services,
toolboxActions
},
initialState
);

const workers = bootstrapWorkers();
await firefox.onConnect(connection, actions);
Expand Down

0 comments on commit 8506987

Please sign in to comment.