summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/utils/test-head.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/utils/test-head.js')
-rw-r--r--devtools/client/debugger/src/utils/test-head.js289
1 files changed, 289 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/utils/test-head.js b/devtools/client/debugger/src/utils/test-head.js
new file mode 100644
index 0000000000..590726d08e
--- /dev/null
+++ b/devtools/client/debugger/src/utils/test-head.js
@@ -0,0 +1,289 @@
+/* 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/>. */
+
+/**
+ * Utils for Jest
+ * @module utils/test-head
+ */
+
+import { combineReducers } from "redux";
+import reducers from "../reducers";
+import actions from "../actions";
+import * as selectors from "../selectors";
+import {
+ searchWorker,
+ prettyPrintWorker,
+ parserWorker,
+} from "../test/tests-setup";
+import configureStore from "../actions/utils/create-store";
+import sourceQueue from "../utils/source-queue";
+import { setupCreate } from "../client/firefox/create";
+import { createLocation } from "./location";
+
+// Import the internal module used by the source-map worker
+// as node doesn't have Web Worker support and require path mapping
+// doesn't work from nodejs worker thread and break mappings to devtools/ folder.
+import sourceMapLoader from "devtools/client/shared/source-map-loader/source-map";
+
+/**
+ * This file contains older interfaces used by tests that have not been
+ * converted to use test-mockup.js
+ */
+
+/**
+ * @memberof utils/test-head
+ * @static
+ */
+function createStore(client, initialState = {}, sourceMapLoaderMock) {
+ const store = configureStore({
+ log: false,
+ makeThunkArgs: args => {
+ return {
+ ...args,
+ client,
+ sourceMapLoader:
+ sourceMapLoaderMock !== undefined
+ ? sourceMapLoaderMock
+ : sourceMapLoader,
+ parserWorker,
+ prettyPrintWorker,
+ searchWorker,
+ };
+ },
+ })(combineReducers(reducers), initialState);
+ sourceQueue.clear();
+ sourceQueue.initialize({
+ newOriginalSources: sources =>
+ store.dispatch(actions.newOriginalSources(sources)),
+ });
+
+ store.thunkArgs = () => ({
+ dispatch: store.dispatch,
+ getState: store.getState,
+ client,
+ sourceMapLoader,
+ panel: {},
+ });
+
+ // Put the initial context in the store, for convenience to unit tests.
+ store.cx = selectors.getThreadContext(store.getState());
+
+ setupCreate({ store });
+
+ return store;
+}
+
+/**
+ * @memberof utils/test-head
+ * @static
+ */
+function commonLog(msg, data = {}) {
+ console.log(`[INFO] ${msg} ${JSON.stringify(data)}`);
+}
+
+function makeFrame({ id, sourceId, thread }, opts = {}) {
+ const source = createSourceObject(sourceId);
+ const sourceActor = {
+ id: `${sourceId}-actor`,
+ actor: `${sourceId}-actor`,
+ source: sourceId,
+ sourceObject: source,
+ };
+ return {
+ id,
+ scope: { bindings: { variables: {}, arguments: [] } },
+ location: createLocation({ source, sourceActor, line: 4 }),
+ thread: thread || "FakeThread",
+ ...opts,
+ };
+}
+
+function createSourceObject(filename, props = {}) {
+ return {
+ id: filename,
+ url: makeSourceURL(filename),
+ isPrettyPrinted: false,
+ isExtension: false,
+ isOriginal: filename.includes("originalSource"),
+ };
+}
+
+function createOriginalSourceObject(generated) {
+ const rv = {
+ ...generated,
+ id: `${generated.id}/originalSource`,
+ };
+
+ return rv;
+}
+
+function makeSourceURL(filename) {
+ return `http://localhost:8000/examples/${filename}`;
+}
+
+function createMakeSource() {
+ const indicies = {};
+
+ return function (name, props = {}) {
+ const index = (indicies[name] | 0) + 1;
+ indicies[name] = index;
+
+ // Mock a SOURCE Resource, which happens to be the SourceActor's form
+ // with resourceType and targetFront additional attributes
+ return {
+ resourceType: "source",
+ // Mock the targetFront to support makeSourceId function
+ targetFront: {
+ isDestroyed() {
+ return false;
+ },
+ getCachedFront(typeName) {
+ return typeName == "thread" ? { actorID: "FakeThread" } : null;
+ },
+ },
+ // Allow to use custom ID's for reducer source objects
+ mockedJestID: name,
+ actor: `${name}-${index}-actor`,
+ url: `http://localhost:8000/examples/${name}`,
+ sourceMapBaseURL: props.sourceMapBaseURL || null,
+ sourceMapURL: props.sourceMapURL || null,
+ introductionType: props.introductionType || null,
+ extensionName: null,
+ };
+ };
+}
+
+/**
+ * @memberof utils/test-head
+ * @static
+ */
+let creator;
+beforeEach(() => {
+ creator = createMakeSource();
+});
+afterEach(() => {
+ creator = null;
+});
+function makeSource(name, props) {
+ if (!creator) {
+ throw new Error("makeSource() cannot be called outside of a test");
+ }
+
+ return creator(name, props);
+}
+
+function makeOriginalSource(source) {
+ return {
+ id: `${source.id}/originalSource`,
+ url: `${source.url}-original`,
+ sourceActor: {
+ thread: "FakeThread",
+ },
+ };
+}
+
+function makeFuncLocation(startLine, endLine) {
+ if (!endLine) {
+ endLine = startLine + 1;
+ }
+ return {
+ start: {
+ line: startLine,
+ },
+ end: {
+ line: endLine,
+ },
+ };
+}
+
+function makeSymbolDeclaration(name, start, end, klass) {
+ return {
+ id: `${name}:${start}`,
+ name,
+ location: makeFuncLocation(start, end),
+ klass,
+ };
+}
+
+/**
+ * @memberof utils/test-head
+ * @static
+ */
+function waitForState(store, predicate) {
+ return new Promise(resolve => {
+ let ret = predicate(store.getState());
+ if (ret) {
+ resolve(ret);
+ }
+
+ const unsubscribe = store.subscribe(() => {
+ ret = predicate(store.getState());
+ if (ret) {
+ unsubscribe();
+ // NOTE: memoizableAction adds an additional tick for validating context
+ setTimeout(() => resolve(ret));
+ }
+ });
+ });
+}
+
+function watchForState(store, predicate) {
+ let sawState = false;
+ const checkState = function () {
+ if (!sawState && predicate(store.getState())) {
+ sawState = true;
+ }
+ return sawState;
+ };
+
+ let unsubscribe;
+ if (!checkState()) {
+ unsubscribe = store.subscribe(() => {
+ if (checkState()) {
+ unsubscribe();
+ }
+ });
+ }
+
+ return function read() {
+ if (unsubscribe) {
+ unsubscribe();
+ }
+
+ return sawState;
+ };
+}
+
+function getTelemetryEvents(eventName) {
+ return window.dbg._telemetry.events[eventName] || [];
+}
+
+function waitATick(callback) {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ callback();
+ resolve();
+ });
+ });
+}
+
+export {
+ actions,
+ selectors,
+ reducers,
+ createStore,
+ commonLog,
+ getTelemetryEvents,
+ makeFrame,
+ createSourceObject,
+ createOriginalSourceObject,
+ createMakeSource,
+ makeSourceURL,
+ makeSource,
+ makeOriginalSource,
+ makeSymbolDeclaration,
+ waitForState,
+ watchForState,
+ waitATick,
+};