diff --git a/.babel/transform-mc.js b/.babel/transform-mc.js
index eb682ae148..7274d26567 100644
--- a/.babel/transform-mc.js
+++ b/.babel/transform-mc.js
@@ -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"`
@@ -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) {
diff --git a/configs/mozilla-central-mappings.js b/configs/mozilla-central-mappings.js
index 21d50790a7..92e9f9701b 100644
--- a/configs/mozilla-central-mappings.js
+++ b/configs/mozilla-central-mappings.js
@@ -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"
diff --git a/docs/dbg.md b/docs/dbg.md
index 1171ab8d69..eb31efb61c 100644
--- a/docs/dbg.md
+++ b/docs/dbg.md
@@ -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.
diff --git a/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap b/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
index 68bd889dc8..c382fe03d2 100644
--- a/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
+++ b/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
@@ -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",
},
}
`;
diff --git a/src/actions/tests/pending-breakpoints.spec.js b/src/actions/tests/pending-breakpoints.spec.js
index d20c4e9457..3f6b24401c 100644
--- a/src/actions/tests/pending-breakpoints.spec.js
+++ b/src/actions/tests/pending-breakpoints.spec.js
@@ -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: {
@@ -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")));
@@ -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")));
@@ -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")));
@@ -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")));
@@ -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")));
@@ -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);
@@ -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));
@@ -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")));
@@ -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")));
@@ -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());
@@ -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());
@@ -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");
diff --git a/src/client/index.js b/src/client/index.js
index b4f50f1360..9c45cf5da8 100644
--- a/src/client/index.js
+++ b/src/client/index.js
@@ -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 {
@@ -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
@@ -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);
diff --git a/src/reducers/pending-breakpoints.js b/src/reducers/pending-breakpoints.js
index 78c65b3c42..215b41ab6e 100644
--- a/src/reducers/pending-breakpoints.js
+++ b/src/reducers/pending-breakpoints.js
@@ -14,21 +14,12 @@ import {
makePendingLocationId
} from "../utils/breakpoint";
-import { prefs } from "../utils/prefs";
-
import type { PendingBreakpoint } from "../types";
import type { Action, DonePromiseAction } from "../actions/types";
export type PendingBreakpointsState = { [string]: PendingBreakpoint };
-export function initialPendingBreakpointsState(): PendingBreakpointsState {
- return restorePendingBreakpoints();
-}
-
-function update(
- state: PendingBreakpointsState = initialPendingBreakpointsState(),
- action: Action
-) {
+function update(state: PendingBreakpointsState = {}, action: Action) {
switch (action.type) {
case "ADD_BREAKPOINT": {
return addBreakpoint(state, action);
@@ -161,8 +152,4 @@ export function getPendingBreakpointsForSource(
);
}
-function restorePendingBreakpoints() {
- return { ...prefs.pendingBreakpoints };
-}
-
export default update;
diff --git a/src/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js b/src/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
index d54bdebf34..396c9d95d4 100644
--- a/src/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
+++ b/src/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
@@ -47,7 +47,6 @@ add_task(async function() {
await pushPref("devtools.debugger.features.map-scopes", true);
const dbg = await initDebugger("doc-sourcemapped.html");
-
await evalInConsoleAtPoint(dbg, "webpack3-babel6", "eval-maps", { line: 14, column: 4 }, [
"one === 1",
"two === 4",
diff --git a/src/test/mochitest/helpers.js b/src/test/mochitest/helpers.js
index af93ecc7f3..e508d7335a 100644
--- a/src/test/mochitest/helpers.js
+++ b/src/test/mochitest/helpers.js
@@ -8,6 +8,7 @@
var { Toolbox } = require("devtools/client/framework/toolbox");
var { Task } = require("devtools/shared/task");
+var asyncStorage = require("devtools/shared/async-storage");
const sourceUtils = {
isLoaded: source => source.loadedState === "loaded"
@@ -481,6 +482,7 @@ function createDebuggerContext(toolbox) {
* Clear all the debugger related preferences.
*/
function clearDebuggerPreferences() {
+ asyncStorage.clear()
Services.prefs.clearUserPref("devtools.debugger.pause-on-exceptions");
Services.prefs.clearUserPref("devtools.debugger.pause-on-caught-exceptions");
Services.prefs.clearUserPref("devtools.debugger.ignore-caught-exceptions");
diff --git a/src/utils/asyncStoreHelper.js b/src/utils/asyncStoreHelper.js
new file mode 100644
index 0000000000..9e793a7bd5
--- /dev/null
+++ b/src/utils/asyncStoreHelper.js
@@ -0,0 +1,55 @@
+/* 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 . */
+
+// @flow
+
+import { asyncStorage } from "devtools-modules";
+
+/*
+ * asyncStoreHelper wraps asyncStorage so that it is easy to define project
+ * specific properties. It is similar to PrefsHelper.
+ *
+ * e.g.
+ * const asyncStore = asyncStoreHelper("r", {a: "_a"})
+ * asyncStore.a // => asyncStorage.getItem("r._a")
+ * asyncStore.a = 2 // => asyncStorage.setItem("r._a", 2)
+ */
+export function asyncStoreHelper(root: string, mappings: Object) {
+ let store: any = {};
+
+ function getMappingKey(key) {
+ return Array.isArray(mappings[key]) ? mappings[key][0] : mappings[key];
+ }
+
+ function getMappingDefaultValue(key) {
+ return Array.isArray(mappings[key]) ? mappings[key][1] : null;
+ }
+
+ Object.keys(mappings).map(key =>
+ Object.defineProperty(store, key, {
+ async get() {
+ const value = await asyncStorage.getItem(
+ `${root}.${getMappingKey(key)}`
+ );
+ return value || getMappingDefaultValue(key);
+ },
+ set(value) {
+ return asyncStorage.setItem(`${root}.${getMappingKey(key)}`, value);
+ }
+ })
+ );
+
+ store = new Proxy(store, {
+ set: function(target, property, value, receiver) {
+ if (!mappings.hasOwnProperty(property)) {
+ throw new Error(`AsyncStore: ${property} is not defined in mappings`);
+ }
+
+ Reflect.set(...arguments);
+ return true;
+ }
+ });
+
+ return (store: { [$Keys]: any });
+}
diff --git a/src/utils/bootstrap.js b/src/utils/bootstrap.js
index 4f53fc5197..3861e821a5 100644
--- a/src/utils/bootstrap.js
+++ b/src/utils/bootstrap.js
@@ -19,7 +19,7 @@ import configureStore from "../actions/utils/create-store";
import reducers from "../reducers";
import * as selectors from "../selectors";
import App from "../components/App";
-import { prefs } from "./prefs";
+import { asyncStore } from "./prefs";
function renderPanel(component, store) {
const root = document.createElement("div");
@@ -37,7 +37,11 @@ function renderPanel(component, store) {
);
}
-export function bootstrapStore(client: any, { services, toolboxActions }: any) {
+export function bootstrapStore(
+ client: any,
+ { services, toolboxActions }: any,
+ initialState: Object
+) {
const createStore = configureStore({
log: isTesting(),
timing: isDevelopment(),
@@ -46,7 +50,7 @@ export function bootstrapStore(client: any, { services, toolboxActions }: any) {
}
});
- const store = createStore(combineReducers(reducers));
+ const store = createStore(combineReducers(reducers), initialState);
store.subscribe(() => updatePrefs(store.getState()));
const actions = bindActionCreators(
@@ -101,6 +105,6 @@ function updatePrefs(state: any) {
previousPendingBreakpoints &&
currentPendingBreakpoints !== previousPendingBreakpoints
) {
- prefs.pendingBreakpoints = currentPendingBreakpoints;
+ asyncStore.pendingBreakpoints = currentPendingBreakpoints;
}
}
diff --git a/src/utils/dbg.js b/src/utils/dbg.js
index 9743907c2f..882f65bbd7 100644
--- a/src/utils/dbg.js
+++ b/src/utils/dbg.js
@@ -5,7 +5,7 @@
// @flow
import * as timings from "./timings";
-import { prefs, features } from "./prefs";
+import { prefs, asyncStore, features } from "./prefs";
import { isDevelopment, isTesting } from "devtools-environment";
import { formatPausePoints } from "./pause/pausePoints";
@@ -61,6 +61,7 @@ export function setupHelper(obj: Object) {
...obj,
selectors,
prefs,
+ asyncStore,
features,
timings,
getCM,
diff --git a/src/utils/prefs.js b/src/utils/prefs.js
index 7dead8941c..f6efc6198c 100644
--- a/src/utils/prefs.js
+++ b/src/utils/prefs.js
@@ -4,9 +4,10 @@
// @flow
-const { isDevelopment } = require("devtools-environment");
-const { PrefsHelper } = require("devtools-modules");
-const Services = require("devtools-services");
+import { PrefsHelper } from "devtools-modules";
+import { isDevelopment } from "devtools-environment";
+import Services from "devtools-services";
+import { asyncStoreHelper } from "./asyncStoreHelper";
const prefsSchemaVersion = "1.0.3";
@@ -110,6 +111,10 @@ export const features = new PrefsHelper("devtools.debugger.features", {
componentPane: ["Bool", "component-pane"]
});
+export const asyncStore = asyncStoreHelper("debugger", {
+ pendingBreakpoints: ["pending-breakpoints", {}]
+});
+
if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
// clear pending Breakpoints
prefs.pendingBreakpoints = {};
diff --git a/src/utils/tests/asyncStoreHelper.spec.js b/src/utils/tests/asyncStoreHelper.spec.js
new file mode 100644
index 0000000000..9a158f104c
--- /dev/null
+++ b/src/utils/tests/asyncStoreHelper.spec.js
@@ -0,0 +1,44 @@
+/* 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 . */
+
+import { asyncStoreHelper } from "../asyncStoreHelper";
+import { asyncStorage } from "devtools-modules";
+
+function mockAsyncStorage() {
+ const store = {};
+ jest.spyOn(asyncStorage, "getItem");
+ jest.spyOn(asyncStorage, "setItem");
+
+ asyncStorage.getItem.mockImplementation(key => store[key]);
+ asyncStorage.setItem.mockImplementation((key, value) => (store[key] = value));
+}
+
+describe("asycStoreHelper", () => {
+ it("can get and set values", async () => {
+ mockAsyncStorage();
+ const asyncStore = asyncStoreHelper("root", { a: "_a" });
+ asyncStore.a = 3;
+ expect(await asyncStore.a).toEqual(3);
+ });
+
+ it("supports default values", async () => {
+ mockAsyncStorage();
+ const asyncStore = asyncStoreHelper("root", { a: ["_a", {}] });
+ expect(await asyncStore.a).toEqual({});
+ });
+
+ it("undefined default value", async () => {
+ mockAsyncStorage();
+ const asyncStore = asyncStoreHelper("root", { a: "_a" });
+ expect(await asyncStore.a).toEqual(null);
+ });
+
+ it("setting an undefined mapping", async () => {
+ mockAsyncStorage();
+ const asyncStore = asyncStoreHelper("root", { a: "_a" });
+ expect(() => {
+ asyncStore.b = 3;
+ }).toThrow("AsyncStore: b is not defined");
+ });
+});