]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
1 | /** |
2 | * @fileoverview Tests for the no-setter-return rule | |
3 | * @author Milos Djermanovic | |
4 | */ | |
5 | ||
6 | "use strict"; | |
7 | ||
8 | //------------------------------------------------------------------------------ | |
9 | // Requirements | |
10 | //------------------------------------------------------------------------------ | |
11 | ||
12 | const rule = require("../../../lib/rules/no-setter-return"); | |
13 | const { RuleTester } = require("../../../lib/rule-tester"); | |
14 | ||
15 | //------------------------------------------------------------------------------ | |
16 | // Helpers | |
17 | //------------------------------------------------------------------------------ | |
18 | ||
19 | /** | |
20 | * Creates an error object. | |
21 | * @param {number} [column] Reported column. | |
22 | * @param {string} [type= "ReturnStatement"] Reported node type. | |
23 | * @returns {Object} The error object. | |
24 | */ | |
25 | function error(column, type = "ReturnStatement") { | |
26 | const errorObject = { | |
27 | messageId: "returnsValue", | |
28 | type | |
29 | }; | |
30 | ||
31 | if (column) { | |
32 | errorObject.column = column; | |
33 | } | |
34 | ||
35 | return errorObject; | |
36 | } | |
37 | ||
38 | //------------------------------------------------------------------------------ | |
39 | // Tests | |
40 | //------------------------------------------------------------------------------ | |
41 | ||
609c276f | 42 | const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2022 } }); |
eb39fafa DC |
43 | |
44 | ruleTester.run("no-setter-return", rule, { | |
45 | valid: [ | |
46 | ||
47 | //------------------------------------------------------------------------------ | |
48 | // General | |
49 | //------------------------------------------------------------------------------ | |
50 | ||
51 | // not a setter | |
52 | "function foo() { return 1; }", | |
53 | "function set(val) { return 1; }", | |
54 | "var foo = function() { return 1; };", | |
55 | "var foo = function set() { return 1; };", | |
56 | "var set = function() { return 1; };", | |
57 | "var set = function set(val) { return 1; };", | |
58 | "var set = val => { return 1; };", | |
59 | "var set = val => 1;", | |
60 | ||
61 | // setters do not have effect on other functions (test function info tracking) | |
62 | "({ set a(val) { }}); function foo() { return 1; }", | |
63 | "({ set a(val) { }}); (function () { return 1; });", | |
64 | "({ set a(val) { }}); (() => { return 1; });", | |
65 | "({ set a(val) { }}); (() => 1);", | |
66 | ||
67 | // does not report global return | |
68 | { | |
69 | code: "return 1;", | |
70 | env: { node: true } | |
71 | }, | |
72 | { | |
73 | code: "return 1;", | |
74 | parserOptions: { ecmaFeatures: { globalReturn: true } } | |
75 | }, | |
76 | { | |
77 | code: "return 1; function foo(){ return 1; } return 1;", | |
78 | env: { node: true } | |
79 | }, | |
80 | { | |
81 | code: "function foo(){} return 1; var bar = function*(){ return 1; }; return 1; var baz = () => {}; return 1;", | |
82 | env: { node: true } | |
83 | }, | |
84 | ||
85 | //------------------------------------------------------------------------------ | |
86 | // Object literals and classes | |
87 | //------------------------------------------------------------------------------ | |
88 | ||
89 | // return without a value is allowed | |
90 | "({ set foo(val) { return; } })", | |
91 | "({ set foo(val) { if (val) { return; } } })", | |
92 | "class A { set foo(val) { return; } }", | |
93 | "(class { set foo(val) { if (val) { return; } else { return; } return; } })", | |
94 | "class A { set foo(val) { try {} catch(e) { return; } } }", | |
95 | ||
96 | // not a setter | |
97 | "({ get foo() { return 1; } })", | |
98 | "({ get set() { return 1; } })", | |
99 | "({ set(val) { return 1; } })", | |
100 | "({ set: function(val) { return 1; } })", | |
101 | "({ foo: function set(val) { return 1; } })", | |
102 | "({ set: function set(val) { return 1; } })", | |
103 | "({ set: (val) => { return 1; } })", | |
104 | "({ set: (val) => 1 })", | |
105 | "set = { foo(val) { return 1; } };", | |
106 | "class A { constructor(val) { return 1; } }", | |
107 | "class set { constructor(val) { return 1; } }", | |
108 | "class set { foo(val) { return 1; } }", | |
109 | "var set = class { foo(val) { return 1; } }", | |
110 | "(class set { foo(val) { return 1; } })", | |
111 | "class A { get foo() { return val; } }", | |
112 | "class A { get set() { return val; } }", | |
113 | "class A { set(val) { return 1; } }", | |
114 | "class A { static set(val) { return 1; } }", | |
115 | "({ set: set = function set(val) { return 1; } } = {})", | |
116 | "({ set: set = (val) => 1 } = {})", | |
609c276f | 117 | "class C { set; foo() { return 1; } }", |
eb39fafa DC |
118 | |
119 | // not returning from the setter | |
120 | "({ set foo(val) { function foo(val) { return 1; } } })", | |
121 | "({ set foo(val) { var foo = function(val) { return 1; } } })", | |
122 | "({ set foo(val) { var foo = (val) => { return 1; } } })", | |
123 | "({ set foo(val) { var foo = (val) => 1; } })", | |
124 | "({ set [function() { return 1; }](val) {} })", | |
125 | "({ set [() => { return 1; }](val) {} })", | |
126 | "({ set [() => 1](val) {} })", | |
127 | "({ set foo(val = function() { return 1; }) {} })", | |
128 | "({ set foo(val = v => 1) {} })", | |
129 | "(class { set foo(val) { function foo(val) { return 1; } } })", | |
130 | "(class { set foo(val) { var foo = function(val) { return 1; } } })", | |
131 | "(class { set foo(val) { var foo = (val) => { return 1; } } })", | |
132 | "(class { set foo(val) { var foo = (val) => 1; } })", | |
133 | "(class { set [function() { return 1; }](val) {} })", | |
134 | "(class { set [() => { return 1; }](val) {} })", | |
135 | "(class { set [() => 1](val) {} })", | |
136 | "(class { set foo(val = function() { return 1; }) {} })", | |
137 | "(class { set foo(val = (v) => 1) {} })", | |
138 | ||
139 | //------------------------------------------------------------------------------ | |
140 | // Property descriptors | |
141 | //------------------------------------------------------------------------------ | |
142 | ||
143 | // return without a value is allowed | |
144 | "Object.defineProperty(foo, 'bar', { set(val) { return; } })", | |
145 | { | |
146 | code: "Reflect.defineProperty(foo, 'bar', { set(val) { if (val) { return; } } })", | |
147 | env: { es6: true } | |
148 | }, | |
149 | "Object.defineProperties(foo, { bar: { set(val) { try { return; } catch(e){} } } })", | |
150 | "Object.create(foo, { bar: { set: function(val) { return; } } })", | |
151 | ||
152 | // not a setter | |
153 | "x = { set(val) { return 1; } }", | |
154 | "x = { foo: { set(val) { return 1; } } }", | |
155 | "Object.defineProperty(foo, 'bar', { value(val) { return 1; } })", | |
156 | { | |
157 | code: "Reflect.defineProperty(foo, 'bar', { value: function set(val) { return 1; } })", | |
158 | env: { es6: true } | |
159 | }, | |
160 | "Object.defineProperties(foo, { bar: { [set](val) { return 1; } } })", | |
161 | "Object.create(foo, { bar: { 'set ': function(val) { return 1; } } })", | |
162 | "Object.defineProperty(foo, 'bar', { [`set `]: (val) => { return 1; } })", | |
163 | { | |
164 | code: "Reflect.defineProperty(foo, 'bar', { Set(val) { return 1; } })", | |
165 | env: { es6: true } | |
166 | }, | |
167 | "Object.defineProperties(foo, { bar: { value: (val) => 1 } })", | |
168 | "Object.create(foo, { set: { value: function(val) { return 1; } } })", | |
169 | "Object.defineProperty(foo, 'bar', { baz(val) { return 1; } })", | |
170 | { | |
171 | code: "Reflect.defineProperty(foo, 'bar', { get(val) { return 1; } })", | |
172 | env: { es6: true } | |
173 | }, | |
174 | "Object.create(foo, { set: function(val) { return 1; } })", | |
175 | "Object.defineProperty(foo, { set: (val) => 1 })", | |
176 | ||
177 | // not returning from the setter | |
178 | "Object.defineProperty(foo, 'bar', { set(val) { function foo() { return 1; } } })", | |
179 | { | |
180 | code: "Reflect.defineProperty(foo, 'bar', { set(val) { var foo = function() { return 1; } } })", | |
181 | env: { es6: true } | |
182 | }, | |
183 | "Object.defineProperties(foo, { bar: { set(val) { () => { return 1 }; } } })", | |
184 | "Object.create(foo, { bar: { set: (val) => { (val) => 1; } } })", | |
185 | ||
186 | // invalid index | |
187 | "Object.defineProperty(foo, 'bar', 'baz', { set(val) { return 1; } })", | |
188 | "Object.defineProperty(foo, { set(val) { return 1; } }, 'bar')", | |
189 | "Object.defineProperty({ set(val) { return 1; } }, foo, 'bar')", | |
190 | { | |
191 | code: "Reflect.defineProperty(foo, 'bar', 'baz', { set(val) { return 1; } })", | |
192 | env: { es6: true } | |
193 | }, | |
194 | { | |
195 | code: "Reflect.defineProperty(foo, { set(val) { return 1; } }, 'bar')", | |
196 | env: { es6: true } | |
197 | }, | |
198 | { | |
199 | code: "Reflect.defineProperty({ set(val) { return 1; } }, foo, 'bar')", | |
200 | env: { es6: true } | |
201 | }, | |
202 | "Object.defineProperties(foo, bar, { baz: { set(val) { return 1; } } })", | |
203 | "Object.defineProperties({ bar: { set(val) { return 1; } } }, foo)", | |
204 | "Object.create(foo, bar, { baz: { set(val) { return 1; } } })", | |
205 | "Object.create({ bar: { set(val) { return 1; } } }, foo)", | |
206 | ||
207 | // not targeted method name | |
208 | "Object.DefineProperty(foo, 'bar', { set(val) { return 1; } })", | |
209 | { | |
210 | code: "Reflect.DefineProperty(foo, 'bar', { set(val) { if (val) { return 1; } } })", | |
211 | env: { es6: true } | |
212 | }, | |
213 | "Object.DefineProperties(foo, { bar: { set(val) { try { return 1; } catch(e){} } } })", | |
214 | "Object.Create(foo, { bar: { set: function(val) { return 1; } } })", | |
215 | ||
216 | // not targeted object name | |
217 | "object.defineProperty(foo, 'bar', { set(val) { return 1; } })", | |
218 | { | |
219 | code: "reflect.defineProperty(foo, 'bar', { set(val) { if (val) { return 1; } } })", | |
220 | env: { es6: true } | |
221 | }, | |
222 | { | |
223 | code: "Reflect.defineProperties(foo, { bar: { set(val) { try { return 1; } catch(e){} } } })", | |
224 | env: { es6: true } | |
225 | }, | |
226 | "object.create(foo, { bar: { set: function(val) { return 1; } } })", | |
227 | ||
228 | // global object doesn't exist | |
229 | "Reflect.defineProperty(foo, 'bar', { set(val) { if (val) { return 1; } } })", | |
230 | "/* globals Object:off */ Object.defineProperty(foo, 'bar', { set(val) { return 1; } })", | |
231 | { | |
232 | code: "Object.defineProperties(foo, { bar: { set(val) { try { return 1; } catch(e){} } } })", | |
233 | globals: { Object: "off" } | |
234 | }, | |
235 | ||
236 | // global object is shadowed | |
237 | "let Object; Object.defineProperty(foo, 'bar', { set(val) { return 1; } })", | |
238 | { | |
239 | code: "function f() { Reflect.defineProperty(foo, 'bar', { set(val) { if (val) { return 1; } } }); var Reflect;}", | |
240 | env: { es6: true } | |
241 | }, | |
242 | "function f(Object) { Object.defineProperties(foo, { bar: { set(val) { try { return 1; } catch(e){} } } }) }", | |
243 | "if (x) { const Object = getObject(); Object.create(foo, { bar: { set: function(val) { return 1; } } }) }", | |
244 | "x = function Object() { Object.defineProperty(foo, 'bar', { set(val) { return 1; } }) }" | |
245 | ], | |
246 | ||
247 | invalid: [ | |
248 | ||
249 | //------------------------------------------------------------------------------ | |
250 | // Object literals and classes | |
251 | //------------------------------------------------------------------------------ | |
252 | ||
253 | // full error test | |
254 | { | |
255 | code: "({ set a(val){ return val + 1; } })", | |
256 | errors: [{ messageId: "returnsValue", type: "ReturnStatement", column: 16, endColumn: 31 }] | |
257 | }, | |
258 | ||
259 | // basic tests | |
260 | { | |
261 | code: "({ set a(val) { return 1; } })", | |
262 | errors: [error()] | |
263 | }, | |
264 | { | |
265 | code: "class A { set a(val) { return 1; } }", | |
266 | errors: [error()] | |
267 | }, | |
268 | { | |
269 | code: "class A { static set a(val) { return 1; } }", | |
270 | errors: [error()] | |
271 | }, | |
272 | { | |
273 | code: "(class { set a(val) { return 1; } })", | |
274 | errors: [error()] | |
275 | }, | |
276 | ||
277 | // any value | |
278 | { | |
279 | code: "({ set a(val) { return val; } })", | |
280 | errors: [error()] | |
281 | }, | |
282 | { | |
283 | code: "class A { set a(val) { return undefined; } }", | |
284 | errors: [error()] | |
285 | }, | |
286 | { | |
287 | code: "(class { set a(val) { return null; } })", | |
288 | errors: [error()] | |
289 | }, | |
290 | { | |
291 | code: "({ set a(val) { return x + y; } })", | |
292 | errors: [error()] | |
293 | }, | |
294 | { | |
295 | code: "class A { set a(val) { return foo(); } }", | |
296 | errors: [error()] | |
297 | }, | |
298 | { | |
299 | code: "(class { set a(val) { return this._a; } })", | |
300 | errors: [error()] | |
301 | }, | |
302 | { | |
303 | code: "({ set a(val) { return this.a; } })", | |
304 | errors: [error()] | |
305 | }, | |
306 | ||
307 | // any location | |
308 | { | |
309 | code: "({ set a(val) { if (foo) { return 1; }; } })", | |
310 | errors: [error()] | |
311 | }, | |
312 | { | |
313 | code: "class A { set a(val) { try { return 1; } catch(e) {} } }", | |
314 | errors: [error()] | |
315 | }, | |
316 | { | |
317 | code: "(class { set a(val) { while (foo){ if (bar) break; else return 1; } } })", | |
318 | errors: [error()] | |
319 | }, | |
320 | ||
321 | // multiple invalid in same object literal/class | |
322 | { | |
323 | code: "({ set a(val) { return 1; }, set b(val) { return 1; } })", | |
324 | errors: [error(17), error(43)] | |
325 | }, | |
326 | { | |
327 | code: "class A { set a(val) { return 1; } set b(val) { return 1; } }", | |
328 | errors: [error(24), error(49)] | |
329 | }, | |
330 | { | |
331 | code: "(class { set a(val) { return 1; } static set b(val) { return 1; } })", | |
332 | errors: [error(23), error(55)] | |
333 | }, | |
334 | ||
335 | // multiple invalid in the same setter | |
336 | { | |
337 | code: "({ set a(val) { if(val) { return 1; } else { return 2 }; } })", | |
338 | errors: [error(27), error(46)] | |
339 | }, | |
340 | { | |
341 | code: "class A { set a(val) { switch(val) { case 1: return x; case 2: return y; default: return z } } }", | |
342 | errors: [error(46), error(64), error(83)] | |
343 | }, | |
344 | { | |
345 | code: "(class { static set a(val) { if (val > 0) { this._val = val; return val; } return false; } })", | |
346 | errors: [error(62), error(76)] | |
347 | }, | |
348 | ||
349 | // valid and invalid in the same setter | |
350 | { | |
351 | code: "({ set a(val) { if(val) { return 1; } else { return; }; } })", | |
352 | errors: [error(27)] | |
353 | }, | |
354 | { | |
355 | code: "class A { set a(val) { switch(val) { case 1: return x; case 2: return; default: return z } } }", | |
356 | errors: [error(46), error(81)] | |
357 | }, | |
358 | { | |
359 | code: "(class { static set a(val) { if (val > 0) { this._val = val; return; } return false; } })", | |
360 | errors: [error(72)] | |
361 | }, | |
362 | ||
363 | // inner functions do not have effect | |
364 | { | |
365 | code: "({ set a(val) { function b(){} return b(); } })", | |
366 | errors: [error(32)] | |
367 | }, | |
368 | { | |
369 | code: "class A { set a(val) { return () => {}; } }", | |
370 | errors: [error(24)] | |
371 | }, | |
372 | { | |
373 | code: "(class { set a(val) { function b(){ return 1; } return 2; } })", | |
374 | errors: [error(49)] | |
375 | }, | |
376 | { | |
377 | code: "({ set a(val) { function b(){ return; } return 1; } })", | |
378 | errors: [error(41)] | |
379 | }, | |
380 | { | |
381 | code: "class A { set a(val) { var x = function() { return 1; }; return 2; } }", | |
382 | errors: [error(58)] | |
383 | }, | |
384 | { | |
385 | code: "(class { set a(val) { var x = () => { return; }; return 2; } })", | |
386 | errors: [error(50)] | |
387 | }, | |
388 | ||
389 | // other functions and global returns do not have effect (test function info tracking) | |
390 | { | |
391 | code: "function f(){}; ({ set a(val) { return 1; } });", | |
392 | errors: [error()] | |
393 | }, | |
394 | { | |
395 | code: "x = function f(){}; class A { set a(val) { return 1; } };", | |
396 | errors: [error()] | |
397 | }, | |
398 | { | |
399 | code: "x = () => {}; A = class { set a(val) { return 1; } };", | |
400 | errors: [error()] | |
401 | }, | |
402 | { | |
403 | code: "return; ({ set a(val) { return 1; } }); return 2;", | |
404 | env: { node: true }, | |
405 | errors: [error(25)] | |
406 | }, | |
407 | ||
408 | //------------------------------------------------------------------------------ | |
409 | // Property descriptors | |
410 | //------------------------------------------------------------------------------ | |
411 | ||
412 | // basic tests | |
413 | { | |
414 | code: "Object.defineProperty(foo, 'bar', { set(val) { return 1; } })", | |
415 | errors: [error()] | |
416 | }, | |
417 | { | |
418 | code: "Reflect.defineProperty(foo, 'bar', { set(val) { return 1; } })", | |
419 | env: { es6: true }, | |
420 | errors: [error()] | |
421 | }, | |
422 | { | |
423 | code: "Object.defineProperties(foo, { baz: { set(val) { return 1; } } })", | |
424 | errors: [error()] | |
425 | }, | |
426 | { | |
427 | code: "Object.create(null, { baz: { set(val) { return 1; } } })", | |
428 | errors: [error()] | |
429 | }, | |
430 | ||
431 | // arrow implicit return// basic tests | |
432 | { | |
433 | code: "Object.defineProperty(foo, 'bar', { set: val => val })", | |
434 | errors: [error(49, "Identifier")] | |
435 | }, | |
436 | { | |
437 | code: "Reflect.defineProperty(foo, 'bar', { set: val => f(val) })", | |
438 | env: { es6: true }, | |
439 | errors: [error(50, "CallExpression")] | |
440 | }, | |
441 | { | |
442 | code: "Object.defineProperties(foo, { baz: { set: val => a + b } })", | |
443 | errors: [error(51, "BinaryExpression")] | |
444 | }, | |
445 | { | |
446 | code: "Object.create({}, { baz: { set: val => this._val } })", | |
447 | errors: [error(40, "MemberExpression")] | |
448 | }, | |
449 | ||
450 | // various locations, value types and multiple invalid/valid in same setter. | |
451 | { | |
452 | code: "Object.defineProperty(foo, 'bar', { set(val) { if (val) { return; } return false; }, get(val) { return 1; } })", | |
453 | errors: [error(69)] | |
454 | }, | |
455 | { | |
456 | code: "Reflect.defineProperty(foo, 'bar', { set(val) { try { return f(val) } catch (e) { return e }; } })", | |
457 | env: { es6: true }, | |
458 | errors: [error(55), error(83)] | |
459 | }, | |
460 | { | |
461 | code: "Object.defineProperties(foo, { bar: { get(){ return null; }, set(val) { return null; } } })", | |
462 | errors: [error(73)] | |
463 | }, | |
464 | { | |
465 | code: "Object.create(null, { baz: { set(val) { return this._val; return; return undefined; } } })", | |
466 | errors: [error(41), error(67)] | |
467 | }, | |
468 | ||
469 | // multiple invalid in the same descriptors object | |
470 | { | |
471 | code: "Object.defineProperties(foo, { baz: { set(val) { return 1; } }, bar: { set(val) { return 1; } } })", | |
472 | errors: [error(50), error(83)] | |
473 | }, | |
474 | { | |
475 | code: "Object.create({}, { baz: { set(val) { return 1; } }, bar: { set: (val) => 1 } })", | |
476 | errors: [ | |
477 | error(39), | |
478 | error(75, "Literal") | |
479 | ] | |
480 | }, | |
481 | ||
482 | // various syntax for properties | |
483 | { | |
484 | code: "Object['defineProperty'](foo, 'bar', { set: function bar(val) { return 1; } })", | |
485 | errors: [error()] | |
486 | }, | |
487 | { | |
488 | code: "Reflect.defineProperty(foo, 'bar', { 'set'(val) { return 1; } })", | |
489 | env: { es6: true }, | |
490 | errors: [error()] | |
491 | }, | |
492 | { | |
493 | code: "Object[`defineProperties`](foo, { baz: { ['set'](val) { return 1; } } })", | |
494 | errors: [error()] | |
495 | }, | |
496 | { | |
497 | code: "Object.create({}, { baz: { [`set`]: (val) => { return 1; } } })", | |
498 | errors: [error()] | |
499 | }, | |
500 | ||
501 | // edge cases for global objects | |
502 | { | |
503 | code: "Object.defineProperty(foo, 'bar', { set: function Object(val) { return 1; } })", | |
504 | errors: [error()] | |
505 | }, | |
506 | { | |
507 | code: "Object.defineProperty(foo, 'bar', { set: function(Object) { return 1; } })", | |
508 | errors: [error()] | |
6f036462 TL |
509 | }, |
510 | ||
511 | // Optional chaining | |
512 | { | |
513 | code: "Object?.defineProperty(foo, 'bar', { set(val) { return 1; } })", | |
514 | parserOptions: { ecmaVersion: 2020 }, | |
515 | errors: [error()] | |
516 | }, | |
517 | { | |
518 | code: "(Object?.defineProperty)(foo, 'bar', { set(val) { return 1; } })", | |
519 | parserOptions: { ecmaVersion: 2020 }, | |
520 | errors: [error()] | |
eb39fafa DC |
521 | } |
522 | ] | |
523 | }); |