diff options
Diffstat (limited to 'devtools/client/debugger/src/actions/tests/preview.spec.js')
-rw-r--r-- | devtools/client/debugger/src/actions/tests/preview.spec.js | 217 |
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"); + }); +}); |