summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/actions/tests/preview.spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/actions/tests/preview.spec.js')
-rw-r--r--devtools/client/debugger/src/actions/tests/preview.spec.js217
1 files changed, 217 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/actions/tests/preview.spec.js b/devtools/client/debugger/src/actions/tests/preview.spec.js
new file mode 100644
index 0000000000..3b6c9c23ac
--- /dev/null
+++ b/devtools/client/debugger/src/actions/tests/preview.spec.js
@@ -0,0 +1,217 @@
+/* eslint max-nested-callbacks: ["error", 6] */
+/* 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/>. */
+
+import {
+ createStore,
+ selectors,
+ actions,
+ makeSource,
+ makeFrame,
+ waitForState,
+ waitATick,
+} from "../../utils/test-head";
+import { createLocation } from "../../utils/location";
+
+function waitForPreview(store, expression) {
+ return waitForState(store, state => {
+ const preview = selectors.getPreview(state);
+ return preview && preview.expression == expression;
+ });
+}
+
+function mockThreadFront(overrides) {
+ return {
+ evaluate: async () => ({ result: {} }),
+ getFrameScopes: async () => {},
+ getFrames: async () => [],
+ sourceContents: async () => ({
+ source: "",
+ contentType: "text/javascript",
+ }),
+ getSourceActorBreakpointPositions: async () => ({}),
+ getSourceActorBreakableLines: async () => [],
+ evaluateExpressions: async () => [],
+ loadObjectProperties: async () => ({}),
+ ...overrides,
+ };
+}
+
+function dispatchSetPreview(dispatch, context, expression, target) {
+ return dispatch(
+ actions.setPreview(
+ context,
+ expression,
+ {
+ start: { url: "foo.js", line: 1, column: 2 },
+ end: { url: "foo.js", line: 1, column: 5 },
+ },
+ { line: 2, column: 3 },
+ target.getBoundingClientRect(),
+ target
+ )
+ );
+}
+
+async function pause(store, client) {
+ const { dispatch, cx, getState } = store;
+ const source = makeSource("base.js");
+ const base = await dispatch(actions.newGeneratedSource(source));
+ const sourceActor = selectors.getFirstSourceActorForGeneratedSource(
+ getState(),
+ base.id
+ );
+
+ await dispatch(actions.selectSource(cx, base, sourceActor));
+ const location = createLocation({ source: base, sourceActor });
+ await waitForState(store, state => selectors.getSymbols(state, location));
+
+ const { thread } = cx;
+ const frames = [makeFrame({ id: "frame1", sourceId: base.id, thread })];
+ client.getFrames = async () => frames;
+
+ await dispatch(
+ actions.paused({
+ thread,
+ frame: frames[0],
+ loadedObjects: [],
+ why: { type: "debuggerStatement" },
+ })
+ );
+}
+
+describe("preview", () => {
+ it("should generate previews", async () => {
+ const store = createStore(mockThreadFront());
+ const { dispatch, getState, cx } = store;
+ const source = makeSource("base.js");
+ const base = await dispatch(actions.newGeneratedSource(source));
+
+ await dispatch(actions.selectSource(cx, base));
+ const sourceActor = selectors.getFirstSourceActorForGeneratedSource(
+ getState(),
+ base.id
+ );
+ const location = createLocation({ source: base, sourceActor });
+
+ await waitForState(store, state => selectors.getSymbols(state, location));
+ const frames = [makeFrame({ id: "f1", sourceId: base.id })];
+
+ await dispatch(
+ actions.paused({
+ thread: store.cx.thread,
+ frame: frames[0],
+ frames,
+ loadedObjects: [],
+ why: { type: "debuggerStatement" },
+ })
+ );
+
+ const newCx = selectors.getContext(getState());
+ const firstTarget = document.createElement("div");
+
+ dispatchSetPreview(dispatch, newCx, "foo", firstTarget);
+
+ expect(selectors.getPreview(getState())).toMatchSnapshot();
+ });
+
+ // When a 2nd setPreview is called before a 1st setPreview dispatches
+ // and the 2nd setPreview has not dispatched yet,
+ // the first setPreview should not finish dispatching
+ it("queued previews (w/ the 1st finishing first)", async () => {
+ let resolveFirst, resolveSecond;
+ const promises = [
+ new Promise(resolve => {
+ resolveFirst = resolve;
+ }),
+ new Promise(resolve => {
+ resolveSecond = resolve;
+ }),
+ ];
+
+ const client = mockThreadFront({
+ loadObjectProperties: () => promises.shift(),
+ });
+ const store = createStore(client);
+
+ const { dispatch, getState } = store;
+ await pause(store, client);
+
+ const newCx = selectors.getContext(getState());
+ const firstTarget = document.createElement("div");
+ const secondTarget = document.createElement("div");
+
+ // Start the dispatch of the first setPreview. At this point, it will not
+ // finish execution until we resolve the firstSetPreview
+ dispatchSetPreview(dispatch, newCx, "firstSetPreview", firstTarget);
+
+ // Start the dispatch of the second setPreview. At this point, it will not
+ // finish execution until we resolve the secondSetPreview
+ dispatchSetPreview(dispatch, newCx, "secondSetPreview", secondTarget);
+
+ let fail = false;
+
+ resolveFirst();
+ waitForPreview(store, "firstSetPreview").then(() => {
+ fail = true;
+ });
+
+ resolveSecond();
+ await waitForPreview(store, "secondSetPreview");
+ expect(fail).toEqual(false);
+
+ const preview = selectors.getPreview(getState());
+ expect(preview && preview.expression).toEqual("secondSetPreview");
+ });
+
+ // When a 2nd setPreview is called before a 1st setPreview dispatches
+ // and the 2nd setPreview has dispatched,
+ // the first setPreview should not finish dispatching
+ it("queued previews (w/ the 2nd finishing first)", async () => {
+ let resolveFirst, resolveSecond;
+ const promises = [
+ new Promise(resolve => {
+ resolveFirst = resolve;
+ }),
+ new Promise(resolve => {
+ resolveSecond = resolve;
+ }),
+ ];
+
+ const client = mockThreadFront({
+ loadObjectProperties: () => promises.shift(),
+ });
+ const store = createStore(client);
+
+ const { dispatch, getState } = store;
+ await pause(store, client);
+
+ const cx = selectors.getThreadContext(getState());
+ const firstTarget = document.createElement("div");
+ const secondTarget = document.createElement("div");
+
+ // Start the dispatch of the first setPreview. At this point, it will not
+ // finish execution until we resolve the firstSetPreview
+ dispatchSetPreview(dispatch, cx, "firstSetPreview", firstTarget);
+
+ // Start the dispatch of the second setPreview. At this point, it will not
+ // finish execution until we resolve the secondSetPreview
+ dispatchSetPreview(dispatch, cx, "secondSetPreview", secondTarget);
+
+ let fail = false;
+
+ resolveSecond();
+ await waitForPreview(store, "secondSetPreview");
+
+ resolveFirst();
+ waitForPreview(store, "firstSetPreview").then(() => {
+ fail = true;
+ });
+
+ await waitATick(() => expect(fail).toEqual(false));
+
+ const preview = selectors.getPreview(getState());
+ expect(preview && preview.expression).toEqual("secondSetPreview");
+ });
+});