|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 /** |
|
5 * Make sure that the variables view knows how to edit getters and setters. |
|
6 */ |
|
7 |
|
8 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html"; |
|
9 |
|
10 let gTab, gDebuggee, gPanel, gDebugger; |
|
11 let gL10N, gEditor, gVars, gWatch; |
|
12 |
|
13 function test() { |
|
14 // Debug test slaves are a bit slow at this test. |
|
15 requestLongerTimeout(2); |
|
16 |
|
17 initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => { |
|
18 gTab = aTab; |
|
19 gDebuggee = aDebuggee; |
|
20 gPanel = aPanel; |
|
21 gDebugger = gPanel.panelWin; |
|
22 gL10N = gDebugger.L10N; |
|
23 gEditor = gDebugger.DebuggerView.editor; |
|
24 gVars = gDebugger.DebuggerView.Variables; |
|
25 gWatch = gDebugger.DebuggerView.WatchExpressions; |
|
26 |
|
27 gVars.switch = function() {}; |
|
28 gVars.delete = function() {}; |
|
29 |
|
30 waitForSourceAndCaretAndScopes(gPanel, ".html", 24) |
|
31 .then(() => addWatchExpressions()) |
|
32 .then(() => testEdit("set", "this._prop = value + ' BEER CAN'", { |
|
33 "myVar.prop": "xlerb BEER CAN", |
|
34 "myVar.prop + 42": "xlerb BEER CAN42", |
|
35 "myVar.prop = 'xlerb'": "xlerb" |
|
36 })) |
|
37 .then(() => testEdit("set", "{ this._prop = value + ' BEACON' }", { |
|
38 "myVar.prop": "xlerb BEACON", |
|
39 "myVar.prop + 42": "xlerb BEACON42", |
|
40 "myVar.prop = 'xlerb'": "xlerb" |
|
41 })) |
|
42 .then(() => testEdit("set", "{ this._prop = value + ' BEACON;'; }", { |
|
43 "myVar.prop": "xlerb BEACON;", |
|
44 "myVar.prop + 42": "xlerb BEACON;42", |
|
45 "myVar.prop = 'xlerb'": "xlerb" |
|
46 })) |
|
47 .then(() => testEdit("set", "{ return this._prop = value + ' BEACON;;'; }", { |
|
48 "myVar.prop": "xlerb BEACON;;", |
|
49 "myVar.prop + 42": "xlerb BEACON;;42", |
|
50 "myVar.prop = 'xlerb'": "xlerb" |
|
51 })) |
|
52 .then(() => testEdit("set", "function(value) { this._prop = value + ' BACON' }", { |
|
53 "myVar.prop": "xlerb BACON", |
|
54 "myVar.prop + 42": "xlerb BACON42", |
|
55 "myVar.prop = 'xlerb'": "xlerb" |
|
56 })) |
|
57 .then(() => testEdit("get", "'brelx BEER CAN'", { |
|
58 "myVar.prop": "brelx BEER CAN", |
|
59 "myVar.prop + 42": "brelx BEER CAN42", |
|
60 "myVar.prop = 'xlerb'": "xlerb" |
|
61 })) |
|
62 .then(() => testEdit("get", "{ 'brelx BEACON' }", { |
|
63 "myVar.prop": undefined, |
|
64 "myVar.prop + 42": NaN, |
|
65 "myVar.prop = 'xlerb'": "xlerb" |
|
66 })) |
|
67 .then(() => testEdit("get", "{ 'brelx BEACON;'; }", { |
|
68 "myVar.prop": undefined, |
|
69 "myVar.prop + 42": NaN, |
|
70 "myVar.prop = 'xlerb'": "xlerb" |
|
71 })) |
|
72 .then(() => testEdit("get", "{ return 'brelx BEACON;;'; }", { |
|
73 "myVar.prop": "brelx BEACON;;", |
|
74 "myVar.prop + 42": "brelx BEACON;;42", |
|
75 "myVar.prop = 'xlerb'": "xlerb" |
|
76 })) |
|
77 .then(() => testEdit("get", "function() { return 'brelx BACON'; }", { |
|
78 "myVar.prop": "brelx BACON", |
|
79 "myVar.prop + 42": "brelx BACON42", |
|
80 "myVar.prop = 'xlerb'": "xlerb" |
|
81 })) |
|
82 .then(() => testEdit("get", "bogus", { |
|
83 "myVar.prop": "ReferenceError: bogus is not defined", |
|
84 "myVar.prop + 42": "ReferenceError: bogus is not defined", |
|
85 "myVar.prop = 'xlerb'": "xlerb" |
|
86 })) |
|
87 .then(() => testEdit("set", "sugob", { |
|
88 "myVar.prop": "ReferenceError: bogus is not defined", |
|
89 "myVar.prop + 42": "ReferenceError: bogus is not defined", |
|
90 "myVar.prop = 'xlerb'": "ReferenceError: sugob is not defined" |
|
91 })) |
|
92 .then(() => testEdit("get", "", { |
|
93 "myVar.prop": undefined, |
|
94 "myVar.prop + 42": NaN, |
|
95 "myVar.prop = 'xlerb'": "ReferenceError: sugob is not defined" |
|
96 })) |
|
97 .then(() => testEdit("set", "", { |
|
98 "myVar.prop": "xlerb", |
|
99 "myVar.prop + 42": NaN, |
|
100 "myVar.prop = 'xlerb'": "xlerb" |
|
101 })) |
|
102 .then(() => deleteWatchExpression("myVar.prop = 'xlerb'")) |
|
103 .then(() => testEdit("self", "2507", { |
|
104 "myVar.prop": 2507, |
|
105 "myVar.prop + 42": 2549 |
|
106 })) |
|
107 .then(() => deleteWatchExpression("myVar.prop + 42")) |
|
108 .then(() => testEdit("self", "0910", { |
|
109 "myVar.prop": 910 |
|
110 })) |
|
111 .then(() => deleteLastWatchExpression("myVar.prop")) |
|
112 .then(() => testWatchExpressionsRemoved()) |
|
113 .then(() => resumeDebuggerThenCloseAndFinish(gPanel)) |
|
114 .then(null, aError => { |
|
115 ok(false, "Got an error: " + aError.message + "\n" + aError.stack); |
|
116 }); |
|
117 |
|
118 EventUtils.sendMouseEvent({ type: "click" }, |
|
119 gDebuggee.document.querySelector("button"), |
|
120 gDebuggee); |
|
121 }); |
|
122 } |
|
123 |
|
124 function addWatchExpressions() { |
|
125 return promise.resolve(null) |
|
126 .then(() => { |
|
127 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS); |
|
128 gWatch.addExpression("myVar.prop"); |
|
129 gEditor.focus(); |
|
130 return finished; |
|
131 }) |
|
132 .then(() => { |
|
133 let exprScope = gVars.getScopeAtIndex(0); |
|
134 ok(exprScope, |
|
135 "There should be a wach expressions scope in the variables view."); |
|
136 is(exprScope.name, gL10N.getStr("watchExpressionsScopeLabel"), |
|
137 "The scope's name should be marked as 'Watch Expressions'."); |
|
138 is(exprScope._store.size, 1, |
|
139 "There should be 1 evaluation available."); |
|
140 |
|
141 let w1 = exprScope.get("myVar.prop"); |
|
142 let w2 = exprScope.get("myVar.prop + 42"); |
|
143 let w3 = exprScope.get("myVar.prop = 'xlerb'"); |
|
144 |
|
145 ok(w1, "The first watch expression should be present in the scope."); |
|
146 ok(!w2, "The second watch expression should not be present in the scope."); |
|
147 ok(!w3, "The third watch expression should not be present in the scope."); |
|
148 |
|
149 is(w1.value, 42, "The first value is correct."); |
|
150 }) |
|
151 .then(() => { |
|
152 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS); |
|
153 gWatch.addExpression("myVar.prop + 42"); |
|
154 gEditor.focus(); |
|
155 return finished; |
|
156 }) |
|
157 .then(() => { |
|
158 let exprScope = gVars.getScopeAtIndex(0); |
|
159 ok(exprScope, |
|
160 "There should be a wach expressions scope in the variables view."); |
|
161 is(exprScope.name, gL10N.getStr("watchExpressionsScopeLabel"), |
|
162 "The scope's name should be marked as 'Watch Expressions'."); |
|
163 is(exprScope._store.size, 2, |
|
164 "There should be 2 evaluations available."); |
|
165 |
|
166 let w1 = exprScope.get("myVar.prop"); |
|
167 let w2 = exprScope.get("myVar.prop + 42"); |
|
168 let w3 = exprScope.get("myVar.prop = 'xlerb'"); |
|
169 |
|
170 ok(w1, "The first watch expression should be present in the scope."); |
|
171 ok(w2, "The second watch expression should be present in the scope."); |
|
172 ok(!w3, "The third watch expression should not be present in the scope."); |
|
173 |
|
174 is(w1.value, "42", "The first expression value is correct."); |
|
175 is(w2.value, "84", "The second expression value is correct."); |
|
176 }) |
|
177 .then(() => { |
|
178 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS); |
|
179 gWatch.addExpression("myVar.prop = 'xlerb'"); |
|
180 gEditor.focus(); |
|
181 return finished; |
|
182 }) |
|
183 .then(() => { |
|
184 let exprScope = gVars.getScopeAtIndex(0); |
|
185 ok(exprScope, |
|
186 "There should be a wach expressions scope in the variables view."); |
|
187 is(exprScope.name, gL10N.getStr("watchExpressionsScopeLabel"), |
|
188 "The scope's name should be marked as 'Watch Expressions'."); |
|
189 is(exprScope._store.size, 3, |
|
190 "There should be 3 evaluations available."); |
|
191 |
|
192 let w1 = exprScope.get("myVar.prop"); |
|
193 let w2 = exprScope.get("myVar.prop + 42"); |
|
194 let w3 = exprScope.get("myVar.prop = 'xlerb'"); |
|
195 |
|
196 ok(w1, "The first watch expression should be present in the scope."); |
|
197 ok(w2, "The second watch expression should be present in the scope."); |
|
198 ok(w3, "The third watch expression should be present in the scope."); |
|
199 |
|
200 is(w1.value, "xlerb", "The first expression value is correct."); |
|
201 is(w2.value, "xlerb42", "The second expression value is correct."); |
|
202 is(w3.value, "xlerb", "The third expression value is correct."); |
|
203 }); |
|
204 } |
|
205 |
|
206 function deleteWatchExpression(aString) { |
|
207 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS); |
|
208 gWatch.deleteExpression({ name: aString }); |
|
209 return finished; |
|
210 } |
|
211 |
|
212 function deleteLastWatchExpression(aString) { |
|
213 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); |
|
214 gWatch.deleteExpression({ name: aString }); |
|
215 return finished; |
|
216 } |
|
217 |
|
218 function testEdit(aWhat, aString, aExpected) { |
|
219 let localScope = gVars.getScopeAtIndex(1); |
|
220 let myVar = localScope.get("myVar"); |
|
221 |
|
222 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES).then(() => { |
|
223 let propVar = myVar.get("prop"); |
|
224 let getterOrSetterOrVar = aWhat != "self" ? propVar.get(aWhat) : propVar; |
|
225 |
|
226 let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS).then(() => { |
|
227 let exprScope = gVars.getScopeAtIndex(0); |
|
228 ok(exprScope, |
|
229 "There should be a wach expressions scope in the variables view."); |
|
230 is(exprScope.name, gL10N.getStr("watchExpressionsScopeLabel"), |
|
231 "The scope's name should be marked as 'Watch Expressions'."); |
|
232 is(exprScope._store.size, Object.keys(aExpected).length, |
|
233 "There should be a certain number of evaluations available."); |
|
234 |
|
235 function testExpression(aExpression) { |
|
236 if (!aExpression) { |
|
237 return; |
|
238 } |
|
239 let value = aExpected[aExpression.name]; |
|
240 if (isNaN(value)) { |
|
241 ok(isNaN(aExpression.value), |
|
242 "The expression value is correct after the edit."); |
|
243 } else if (value == null) { |
|
244 is(aExpression.value.type, value + "", |
|
245 "The expression value is correct after the edit."); |
|
246 } else { |
|
247 is(aExpression.value, value, |
|
248 "The expression value is correct after the edit."); |
|
249 } |
|
250 } |
|
251 |
|
252 testExpression(exprScope.get(Object.keys(aExpected)[0])); |
|
253 testExpression(exprScope.get(Object.keys(aExpected)[1])); |
|
254 testExpression(exprScope.get(Object.keys(aExpected)[2])); |
|
255 }); |
|
256 |
|
257 let editTarget = getterOrSetterOrVar.target; |
|
258 |
|
259 // Allow the target variable to get painted, so that clicking on |
|
260 // its value would scroll the new textbox node into view. |
|
261 executeSoon(() => { |
|
262 let varValue = editTarget.querySelector(".title > .value"); |
|
263 EventUtils.sendMouseEvent({ type: "mousedown" }, varValue, gDebugger); |
|
264 |
|
265 let varInput = editTarget.querySelector(".title > .element-value-input"); |
|
266 setText(varInput, aString); |
|
267 EventUtils.sendKey("RETURN", gDebugger); |
|
268 }); |
|
269 |
|
270 return finished; |
|
271 }); |
|
272 |
|
273 myVar.expand(); |
|
274 gVars.clearHierarchy(); |
|
275 |
|
276 return finished; |
|
277 } |
|
278 |
|
279 function testWatchExpressionsRemoved() { |
|
280 let scope = gVars.getScopeAtIndex(0); |
|
281 ok(scope, |
|
282 "There should be a local scope in the variables view."); |
|
283 isnot(scope.name, gL10N.getStr("watchExpressionsScopeLabel"), |
|
284 "The scope's name should not be marked as 'Watch Expressions'."); |
|
285 isnot(scope._store.size, 0, |
|
286 "There should be some variables available."); |
|
287 } |
|
288 |
|
289 registerCleanupFunction(function() { |
|
290 gTab = null; |
|
291 gDebuggee = null; |
|
292 gPanel = null; |
|
293 gDebugger = null; |
|
294 gL10N = null; |
|
295 gEditor = null; |
|
296 gVars = null; |
|
297 gWatch = null; |
|
298 }); |