test-head.js (6492B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 /** 6 * Utils for Jest 7 * 8 * @module utils/test-head 9 */ 10 11 import { combineReducers } from "devtools/client/shared/vendor/redux"; 12 import reducers from "../reducers/index"; 13 import actions from "../actions/index"; 14 import * as selectors from "../selectors/index"; 15 import { 16 searchWorker, 17 prettyPrintWorker, 18 parserWorker, 19 } from "../test/tests-setup"; 20 import configureStore from "../actions/utils/create-store"; 21 import sourceQueue from "../utils/source-queue"; 22 import { setupCreate } from "../client/firefox/create"; 23 import { createLocation } from "./location"; 24 25 // Import the internal module used by the source-map worker 26 // as node doesn't have Web Worker support and require path mapping 27 // doesn't work from nodejs worker thread and break mappings to devtools/ folder. 28 import sourceMapLoader from "devtools/client/shared/source-map-loader/source-map"; 29 30 /** 31 * This file contains older interfaces used by tests that have not been 32 * converted to use test-mockup.js 33 */ 34 35 /** 36 * @memberof utils/test-head 37 * @static 38 */ 39 function createStore(client, initialState = {}, sourceMapLoaderMock) { 40 const store = configureStore({ 41 log: false, 42 thunkArgs: { 43 client, 44 sourceMapLoader: 45 sourceMapLoaderMock !== undefined 46 ? sourceMapLoaderMock 47 : sourceMapLoader, 48 parserWorker, 49 prettyPrintWorker, 50 searchWorker, 51 }, 52 })(combineReducers(reducers), initialState); 53 sourceQueue.clear(); 54 sourceQueue.initialize({ 55 newOriginalSources: sources => 56 store.dispatch(actions.newOriginalSources(sources)), 57 }); 58 59 store.thunkArgs = () => ({ 60 dispatch: store.dispatch, 61 getState: store.getState, 62 client, 63 sourceMapLoader, 64 panel: {}, 65 }); 66 67 // Put the initial context in the store, for convenience to unit tests. 68 store.cx = selectors.getThreadContext(store.getState()); 69 70 setupCreate({ store }); 71 72 return store; 73 } 74 75 /** 76 * @memberof utils/test-head 77 * @static 78 */ 79 function commonLog(msg, data = {}) { 80 console.log(`[INFO] ${msg} ${JSON.stringify(data)}`); 81 } 82 83 function makeFrame({ id, sourceId, thread }, opts = {}) { 84 const source = createSourceObject(sourceId); 85 const sourceActor = { 86 id: `${sourceId}-actor`, 87 actor: `${sourceId}-actor`, 88 source: sourceId, 89 sourceObject: source, 90 }; 91 const location = createLocation({ source, sourceActor, line: 4 }); 92 return { 93 id, 94 scope: { bindings: { variables: {}, arguments: [] } }, 95 location, 96 generatedLocation: location, 97 thread: thread || "FakeThread", 98 ...opts, 99 }; 100 } 101 102 function createSourceObject(filename) { 103 return { 104 id: filename, 105 url: makeSourceURL(filename), 106 shortName: filename, 107 isPrettyPrinted: false, 108 isExtension: false, 109 isOriginal: filename.includes("originalSource"), 110 displayURL: makeSourceURL(filename), 111 }; 112 } 113 114 function makeSourceURL(filename) { 115 return `http://localhost:8000/examples/${filename}`; 116 } 117 118 function createMakeSource() { 119 const indicies = {}; 120 121 return function (name, props = {}) { 122 const index = (indicies[name] | 0) + 1; 123 indicies[name] = index; 124 125 // Mock a SOURCE Resource, which happens to be the SourceActor's form 126 // with resourceType and targetFront additional attributes 127 return { 128 resourceType: "source", 129 // Mock the targetFront to support makeSourceId function 130 targetFront: { 131 isDestroyed() { 132 return false; 133 }, 134 getCachedFront(typeName) { 135 return typeName == "thread" ? { actorID: "FakeThread" } : null; 136 }, 137 }, 138 // Allow to use custom ID's for reducer source objects 139 mockedJestID: name, 140 actor: `${name}-${index}-actor`, 141 url: `http://localhost:8000/examples/${name}`, 142 sourceMapBaseURL: props.sourceMapBaseURL || null, 143 sourceMapURL: props.sourceMapURL || null, 144 introductionType: props.introductionType || null, 145 extensionName: null, 146 }; 147 }; 148 } 149 150 /** 151 * @memberof utils/test-head 152 * @static 153 */ 154 let creator; 155 beforeEach(() => { 156 creator = createMakeSource(); 157 }); 158 afterEach(() => { 159 creator = null; 160 }); 161 function makeSource(name, props) { 162 if (!creator) { 163 throw new Error("makeSource() cannot be called outside of a test"); 164 } 165 166 return creator(name, props); 167 } 168 169 function makeOriginalSource(source) { 170 return { 171 id: `${source.id}/originalSource`, 172 url: `${source.url}-original`, 173 sourceActor: { 174 id: `${source.id}-1-actor`, 175 thread: "FakeThread", 176 }, 177 }; 178 } 179 180 function makeFuncLocation(startLine, endLine) { 181 if (!endLine) { 182 endLine = startLine + 1; 183 } 184 return { 185 start: { 186 line: startLine, 187 }, 188 end: { 189 line: endLine, 190 }, 191 }; 192 } 193 194 function makeSymbolDeclaration(name, start, end, klass) { 195 return { 196 id: `${name}:${start}`, 197 name, 198 location: makeFuncLocation(start, end), 199 klass, 200 }; 201 } 202 203 /** 204 * @memberof utils/test-head 205 * @static 206 */ 207 function waitForState(store, predicate) { 208 return new Promise(resolve => { 209 let ret = predicate(store.getState()); 210 if (ret) { 211 resolve(ret); 212 } 213 214 const unsubscribe = store.subscribe(() => { 215 ret = predicate(store.getState()); 216 if (ret) { 217 unsubscribe(); 218 // NOTE: memoizableAction adds an additional tick for validating context 219 setTimeout(() => resolve(ret)); 220 } 221 }); 222 }); 223 } 224 225 function watchForState(store, predicate) { 226 let sawState = false; 227 const checkState = function () { 228 if (!sawState && predicate(store.getState())) { 229 sawState = true; 230 } 231 return sawState; 232 }; 233 234 let unsubscribe; 235 if (!checkState()) { 236 unsubscribe = store.subscribe(() => { 237 if (checkState()) { 238 unsubscribe(); 239 } 240 }); 241 } 242 243 return function read() { 244 if (unsubscribe) { 245 unsubscribe(); 246 } 247 248 return sawState; 249 }; 250 } 251 252 function getTelemetryEvents(eventName) { 253 return window.dbg._telemetry.events[eventName] || []; 254 } 255 256 function waitATick(callback) { 257 return new Promise(resolve => { 258 setTimeout(() => { 259 callback(); 260 resolve(); 261 }); 262 }); 263 } 264 265 export { 266 actions, 267 selectors, 268 reducers, 269 createStore, 270 commonLog, 271 getTelemetryEvents, 272 makeFrame, 273 createSourceObject, 274 createMakeSource, 275 makeSourceURL, 276 makeSource, 277 makeOriginalSource, 278 makeSymbolDeclaration, 279 waitForState, 280 watchForState, 281 waitATick, 282 };