diff options
Diffstat (limited to 'devtools/client/debugger/src/actions/pause/tests/pause.spec.js')
-rw-r--r-- | devtools/client/debugger/src/actions/pause/tests/pause.spec.js | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/actions/pause/tests/pause.spec.js b/devtools/client/debugger/src/actions/pause/tests/pause.spec.js new file mode 100644 index 0000000000..f8bd87375a --- /dev/null +++ b/devtools/client/debugger/src/actions/pause/tests/pause.spec.js @@ -0,0 +1,290 @@ +/* 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 { + actions, + selectors, + createStore, + createSourceObject, + makeSource, + makeOriginalSource, + makeFrame, +} from "../../../utils/test-head"; + +import { makeWhyNormal } from "../../../utils/test-mockup"; +import { createLocation } from "../../../utils/location"; + +const mockCommandClient = { + stepIn: () => new Promise(), + stepOver: () => new Promise(_resolve => _resolve), + evaluate: async () => {}, + evaluateExpressions: async () => [], + resume: async () => {}, + getFrameScopes: async frame => frame.scope, + getFrames: async () => [], + setBreakpoint: () => new Promise(_resolve => {}), + sourceContents: ({ source }) => { + return new Promise((resolve, reject) => { + switch (source) { + case "foo1": + return resolve({ + source: "function foo1() {\n return 5;\n}", + contentType: "text/javascript", + }); + case "await": + return resolve({ + source: "async function aWait() {\n await foo(); return 5;\n}", + contentType: "text/javascript", + }); + + case "foo": + return resolve({ + source: "function foo() {\n return -5;\n}", + contentType: "text/javascript", + }); + case "foo-original": + return resolve({ + source: "\n\nfunction fooOriginal() {\n return -5;\n}", + contentType: "text/javascript", + }); + case "foo-wasm": + return resolve({ + source: { binary: new ArrayBuffer(0) }, + contentType: "application/wasm", + }); + case "foo-wasm/originalSource": + return resolve({ + source: "fn fooBar() {}\nfn barZoo() { fooBar() }", + contentType: "text/rust", + }); + } + + return resolve(); + }); + }, + getSourceActorBreakpointPositions: async () => ({}), + getSourceActorBreakableLines: async () => [], + actorID: "threadActorID", +}; + +const mockFrameId = "1"; + +function createPauseInfo( + frameLocation = createLocation({ + source: createSourceObject("foo1"), + line: 2, + }), + frameOpts = {} +) { + const frames = [ + makeFrame( + { id: mockFrameId, sourceId: frameLocation.source.id }, + { + location: frameLocation, + generatedLocation: frameLocation, + ...frameOpts, + } + ), + ]; + return { + thread: "FakeThread", + frame: frames[0], + frames, + loadedObjects: [], + why: makeWhyNormal(), + }; +} + +function debuggerToSourceMapLocation(l) { + return { + sourceId: l.source.id, + line: l.line, + column: l.column, + }; +} + +describe("pause", () => { + describe("stepping", () => { + it("should only step when paused", async () => { + const client = { stepIn: jest.fn() }; + const { dispatch } = createStore(client); + + dispatch(actions.stepIn()); + expect(client.stepIn.mock.calls).toHaveLength(0); + }); + + it("getting frame scopes with bindings", async () => { + const client = { ...mockCommandClient }; + const store = createStore(client, {}); + const { dispatch, getState } = store; + + const source = await dispatch( + actions.newGeneratedSource(makeSource("foo")) + ); + const generatedLocation = createLocation({ + source, + line: 1, + column: 0, + sourceActor: selectors.getFirstSourceActorForGeneratedSource( + getState(), + source.id + ), + }); + const mockPauseInfo = createPauseInfo(generatedLocation, { + scope: { + bindings: { + variables: { b: { value: {} } }, + arguments: [{ a: { value: {} } }], + }, + }, + }); + + const { frames } = mockPauseInfo; + client.getFrames = async () => frames; + await dispatch(actions.newOriginalSources([makeOriginalSource(source)])); + + await dispatch(actions.paused(mockPauseInfo)); + expect(selectors.getFrames(getState(), "FakeThread")).toEqual([ + { + id: mockFrameId, + generatedLocation, + location: generatedLocation, + library: null, + scope: { + bindings: { + arguments: [{ a: { value: {} } }], + variables: { b: { value: {} } }, + }, + }, + thread: "FakeThread", + }, + ]); + + expect(selectors.getFrameScopes(getState(), "FakeThread")).toEqual({ + generated: { + 1: { + pending: false, + scope: { + bindings: { + arguments: [{ a: { value: {} } }], + variables: { b: { value: {} } }, + }, + }, + }, + }, + mappings: { 1: undefined }, + original: { 1: { pending: false, scope: undefined } }, + }); + + expect( + selectors.getSelectedFrameBindings(getState(), "FakeThread") + ).toEqual(["b", "a"]); + }); + + it("maps frame to original frames", async () => { + const sourceMapLoaderMock = { + getOriginalStackFrames: loc => Promise.resolve(originStackFrames), + getOriginalLocation: () => + Promise.resolve(debuggerToSourceMapLocation(originalLocation)), + getOriginalLocations: async items => + items.map(debuggerToSourceMapLocation), + getOriginalSourceText: async () => ({ + text: "fn fooBar() {}\nfn barZoo() { fooBar() }", + contentType: "text/rust", + }), + getGeneratedRangesForOriginal: async () => [], + }; + + const client = { ...mockCommandClient }; + const store = createStore(client, {}, sourceMapLoaderMock); + const { dispatch, getState } = store; + + const generatedSource = await dispatch( + actions.newGeneratedSource( + makeSource("foo-wasm", { introductionType: "wasm" }) + ) + ); + + const generatedLocation = createLocation({ + source: generatedSource, + line: 1, + column: 0, + sourceActor: selectors.getFirstSourceActorForGeneratedSource( + getState(), + generatedSource.id + ), + }); + const mockPauseInfo = createPauseInfo(generatedLocation); + const { frames } = mockPauseInfo; + client.getFrames = async () => frames; + + const [originalSource] = await dispatch( + actions.newOriginalSources([makeOriginalSource(generatedSource)]) + ); + + const originalLocation = createLocation({ + source: originalSource, + line: 1, + column: 1, + }); + const originalLocation2 = createLocation({ + source: originalSource, + line: 2, + column: 14, + sourceActor: selectors.getFirstSourceActorForGeneratedSource( + getState(), + originalSource.id + ), + }); + + const originStackFrames = [ + { + displayName: "fooBar", + thread: "FakeThread", + }, + { + displayName: "barZoo", + location: originalLocation2, + thread: "FakeThread", + }, + ]; + + await dispatch(actions.paused(mockPauseInfo)); + expect(selectors.getFrames(getState(), "FakeThread")).toEqual([ + { + asyncCause: undefined, + displayName: "fooBar", + generatedLocation, + id: "1", + index: undefined, + isOriginal: true, + library: null, + location: originalLocation, + originalDisplayName: "fooBar", + originalVariables: undefined, + state: undefined, + this: undefined, + thread: "FakeThread", + type: undefined, + }, + { + asyncCause: undefined, + displayName: "barZoo", + generatedLocation, + id: "1-originalFrame1", + index: undefined, + isOriginal: true, + library: null, + location: originalLocation2, + originalDisplayName: "barZoo", + originalVariables: undefined, + state: undefined, + this: undefined, + thread: "FakeThread", + type: undefined, + }, + ]); + }); + }); +}); |