UNPKG

21.2 kBJavaScriptView Raw
1/**
2 * @fileoverview Tests for no-invalid-this rule.
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const cloneDeep = require("lodash.clonedeep");
13const rule = require("../../rules/no-invalid-this");
14const RuleTester = require("../RuleTester");
15
16//------------------------------------------------------------------------------
17// Helpers
18//------------------------------------------------------------------------------
19
20/**
21 * A constant value for non strict mode environment.
22 * @returns {void}
23 */
24function NORMAL(pattern) {
25 pattern.parserOptions.sourceType = "script";
26}
27
28/**
29 * A constant value for strict mode environment.
30 * This modifies pattern object to make strict mode.
31 * @param {Object} pattern - A pattern object to modify.
32 * @returns {void}
33 */
34function USE_STRICT(pattern) {
35 pattern.code = "\"use strict\"; " + pattern.code;
36}
37
38/**
39 * A constant value for implied strict mode.
40 * This modifies pattern object to impose strict mode.
41 * @param {Object} pattern - A pattern object to modify.
42 * @returns {void}
43 */
44function IMPLIED_STRICT(pattern) {
45 pattern.code = "/* implied strict mode */ " + pattern.code;
46 pattern.parserOptions.ecmaFeatures = pattern.parserOptions.ecmaFeatures || {};
47 pattern.parserOptions.ecmaFeatures.impliedStrict = true;
48}
49
50/**
51 * A constant value for modules environment.
52 * This modifies pattern object to make modules.
53 * @param {Object} pattern - A pattern object to modify.
54 * @returns {void}
55 */
56function MODULES(pattern) {
57 pattern.code = "/* modules */ " + pattern.code;
58}
59
60/**
61 * Extracts patterns each condition for a specified type. The type is `valid` or `invalid`.
62 * @param {Object[]} patterns - Original patterns.
63 * @param {string} type - One of `"valid"` or `"invalid"`.
64 * @returns {Object[]} Test patterns.
65 */
66function extractPatterns(patterns, type) {
67
68 // Clone and apply the pattern environment.
69 const patternsList = patterns.map(function(pattern) {
70 return pattern[type].map(function(applyCondition) {
71 const thisPattern = cloneDeep(pattern);
72
73 applyCondition(thisPattern);
74
75 if (type === "valid") {
76 thisPattern.errors = [];
77 } else {
78 thisPattern.code += " /* should error */";
79 }
80
81 delete thisPattern.invalid;
82 delete thisPattern.valid;
83
84 return thisPattern;
85 });
86 });
87
88 // Flatten.
89 return Array.prototype.concat.apply([], patternsList);
90}
91
92
93//------------------------------------------------------------------------------
94// Tests
95//------------------------------------------------------------------------------
96
97const errors = [
98 {message: "Unexpected 'this'.", type: "ThisExpression"},
99 {message: "Unexpected 'this'.", type: "ThisExpression"}
100];
101
102const patterns = [
103
104 // Global.
105 {
106 code: "console.log(this); z(x => console.log(x, this));",
107 parserOptions: { ecmaVersion: 6 },
108 errors,
109 valid: [NORMAL],
110 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
111 },
112 {
113 code: "console.log(this); z(x => console.log(x, this));",
114 parserOptions: {
115 ecmaVersion: 6,
116 ecmaFeatures: {globalReturn: true}
117 },
118 errors,
119 valid: [NORMAL],
120 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
121 },
122
123 // IIFE.
124 {
125 code: "(function() { console.log(this); z(x => console.log(x, this)); })();",
126 parserOptions: { ecmaVersion: 6 },
127 errors,
128 valid: [NORMAL],
129 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
130 },
131
132 // Just functions.
133 {
134 code: "function foo() { console.log(this); z(x => console.log(x, this)); }",
135 parserOptions: { ecmaVersion: 6 },
136 errors,
137 valid: [NORMAL],
138 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
139 },
140 {
141 code: "function foo() { \"use strict\"; console.log(this); z(x => console.log(x, this)); }",
142 parserOptions: { ecmaVersion: 6 },
143 errors,
144 valid: [],
145 invalid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES]
146 },
147 {
148 code: "return function() { console.log(this); z(x => console.log(x, this)); };",
149 parserOptions: {
150 ecmaVersion: 6,
151 ecmaFeatures: {globalReturn: true}
152 },
153 errors,
154 valid: [NORMAL],
155 invalid: [USE_STRICT, IMPLIED_STRICT] // modules cannot return on global.
156 },
157 {
158 code: "var foo = (function() { console.log(this); z(x => console.log(x, this)); }).bar(obj);",
159 parserOptions: { ecmaVersion: 6 },
160 errors,
161 valid: [NORMAL],
162 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
163 },
164
165 // Functions in methods.
166 {
167 code: "var obj = {foo: function() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};",
168 parserOptions: { ecmaVersion: 6 },
169 errors,
170 valid: [NORMAL],
171 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
172 },
173 {
174 code: "var obj = {foo() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};",
175 parserOptions: { ecmaVersion: 6 },
176 errors,
177 valid: [NORMAL],
178 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
179 },
180 {
181 code: "var obj = {foo: function() { return function() { console.log(this); z(x => console.log(x, this)); }; }};",
182 parserOptions: { ecmaVersion: 6 },
183 errors,
184 valid: [NORMAL],
185 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
186 },
187 {
188 code: "var obj = {foo: function() { \"use strict\"; return function() { console.log(this); z(x => console.log(x, this)); }; }};",
189 parserOptions: { ecmaVersion: 6 },
190 errors,
191 valid: [],
192 invalid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES]
193 },
194 {
195 code: "obj.foo = function() { return function() { console.log(this); z(x => console.log(x, this)); }; };",
196 parserOptions: { ecmaVersion: 6 },
197 errors,
198 valid: [NORMAL],
199 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
200 },
201 {
202 code: "obj.foo = function() { \"use strict\"; return function() { console.log(this); z(x => console.log(x, this)); }; };",
203 parserOptions: { ecmaVersion: 6 },
204 errors,
205 valid: [],
206 invalid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES]
207 },
208 {
209 code: "class A { foo() { return function() { console.log(this); z(x => console.log(x, this)); }; } }",
210 parserOptions: { ecmaVersion: 6 },
211 errors,
212 valid: [],
213 invalid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES]
214 },
215
216 // Class Static methods.
217 {
218 code: "class A {static foo() { console.log(this); z(x => console.log(x, this)); }};",
219 parserOptions: { ecmaVersion: 6 },
220 errors,
221 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
222 invalid: []
223 },
224
225 // Constructors.
226 {
227 code: "function Foo() { console.log(this); z(x => console.log(x, this)); }",
228 parserOptions: { ecmaVersion: 6 },
229 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
230 invalid: []
231 },
232 {
233 code: "var Foo = function Foo() { console.log(this); z(x => console.log(x, this)); };",
234 parserOptions: { ecmaVersion: 6 },
235 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
236 invalid: []
237 },
238 {
239 code: "class A {constructor() { console.log(this); z(x => console.log(x, this)); }};",
240 parserOptions: { ecmaVersion: 6 },
241 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
242 invalid: []
243 },
244
245 // On a property.
246 {
247 code: "var obj = {foo: function() { console.log(this); z(x => console.log(x, this)); }};",
248 parserOptions: { ecmaVersion: 6 },
249 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
250 invalid: []
251 },
252 {
253 code: "var obj = {foo() { console.log(this); z(x => console.log(x, this)); }};",
254 parserOptions: { ecmaVersion: 6 },
255 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
256 invalid: []
257 },
258 {
259 code: "var obj = {foo: foo || function() { console.log(this); z(x => console.log(x, this)); }};",
260 parserOptions: { ecmaVersion: 6 },
261 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
262 invalid: []
263 },
264 {
265 code: "var obj = {foo: hasNative ? foo : function() { console.log(this); z(x => console.log(x, this)); }};",
266 parserOptions: { ecmaVersion: 6 },
267 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
268 invalid: []
269 },
270 {
271 code: "var obj = {foo: (function() { return function() { console.log(this); z(x => console.log(x, this)); }; })()};",
272 parserOptions: { ecmaVersion: 6 },
273 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
274 invalid: []
275 },
276 {
277 code: "Object.defineProperty(obj, \"foo\", {value: function() { console.log(this); z(x => console.log(x, this)); }})",
278 parserOptions: { ecmaVersion: 6 },
279 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
280 invalid: []
281 },
282 {
283 code: "Object.defineProperties(obj, {foo: {value: function() { console.log(this); z(x => console.log(x, this)); }}})",
284 parserOptions: { ecmaVersion: 6 },
285 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
286 invalid: []
287 },
288
289 // Assigns to a property.
290 {
291 code: "obj.foo = function() { console.log(this); z(x => console.log(x, this)); };",
292 parserOptions: { ecmaVersion: 6 },
293 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
294 invalid: []
295 },
296 {
297 code: "obj.foo = foo || function() { console.log(this); z(x => console.log(x, this)); };",
298 parserOptions: { ecmaVersion: 6 },
299 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
300 invalid: []
301 },
302 {
303 code: "obj.foo = foo ? bar : function() { console.log(this); z(x => console.log(x, this)); };",
304 parserOptions: { ecmaVersion: 6 },
305 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
306 invalid: []
307 },
308 {
309 code: "obj.foo = (function() { return function() { console.log(this); z(x => console.log(x, this)); }; })();",
310 parserOptions: { ecmaVersion: 6 },
311 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
312 invalid: []
313 },
314
315 // Class Instance Methods.
316 {
317 code: "class A {foo() { console.log(this); z(x => console.log(x, this)); }};",
318 parserOptions: { ecmaVersion: 6 },
319 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
320 invalid: []
321 },
322
323 // Bind/Call/Apply
324 {
325 code: "var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(obj);",
326 parserOptions: { ecmaVersion: 6 },
327 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
328 invalid: []
329 },
330 {
331 code: "var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(null);",
332 parserOptions: { ecmaVersion: 6 },
333 errors,
334 valid: [NORMAL],
335 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
336 },
337 {
338 code: "(function() { console.log(this); z(x => console.log(x, this)); }).call(obj);",
339 parserOptions: { ecmaVersion: 6 },
340 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
341 invalid: []
342 },
343 {
344 code: "(function() { console.log(this); z(x => console.log(x, this)); }).call(undefined);",
345 parserOptions: { ecmaVersion: 6 },
346 errors,
347 valid: [NORMAL],
348 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
349 },
350 {
351 code: "(function() { console.log(this); z(x => console.log(x, this)); }).apply(obj);",
352 parserOptions: { ecmaVersion: 6 },
353 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
354 invalid: []
355 },
356 {
357 code: "(function() { console.log(this); z(x => console.log(x, this)); }).apply(void 0);",
358 parserOptions: { ecmaVersion: 6 },
359 errors,
360 valid: [NORMAL],
361 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
362 },
363 {
364 code: "Reflect.apply(function() { console.log(this); z(x => console.log(x, this)); }, obj, []);",
365 parserOptions: { ecmaVersion: 6 },
366 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
367 invalid: []
368 },
369
370 // Array methods.
371 {
372 code: "Array.from([], function() { console.log(this); z(x => console.log(x, this)); });",
373 parserOptions: { ecmaVersion: 6 },
374 errors,
375 valid: [NORMAL],
376 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
377 },
378 {
379 code: "foo.every(function() { console.log(this); z(x => console.log(x, this)); });",
380 parserOptions: { ecmaVersion: 6 },
381 errors,
382 valid: [NORMAL],
383 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
384 },
385 {
386 code: "foo.filter(function() { console.log(this); z(x => console.log(x, this)); });",
387 parserOptions: { ecmaVersion: 6 },
388 errors,
389 valid: [NORMAL],
390 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
391 },
392 {
393 code: "foo.find(function() { console.log(this); z(x => console.log(x, this)); });",
394 parserOptions: { ecmaVersion: 6 },
395 errors,
396 valid: [NORMAL],
397 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
398 },
399 {
400 code: "foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); });",
401 parserOptions: { ecmaVersion: 6 },
402 errors,
403 valid: [NORMAL],
404 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
405 },
406 {
407 code: "foo.forEach(function() { console.log(this); z(x => console.log(x, this)); });",
408 parserOptions: { ecmaVersion: 6 },
409 errors,
410 valid: [NORMAL],
411 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
412 },
413 {
414 code: "foo.map(function() { console.log(this); z(x => console.log(x, this)); });",
415 parserOptions: { ecmaVersion: 6 },
416 errors,
417 valid: [NORMAL],
418 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
419 },
420 {
421 code: "foo.some(function() { console.log(this); z(x => console.log(x, this)); });",
422 parserOptions: { ecmaVersion: 6 },
423 errors,
424 valid: [NORMAL],
425 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
426 },
427 {
428 code: "Array.from([], function() { console.log(this); z(x => console.log(x, this)); }, obj);",
429 parserOptions: { ecmaVersion: 6 },
430 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
431 invalid: []
432 },
433 {
434 code: "foo.every(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
435 parserOptions: { ecmaVersion: 6 },
436 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
437 invalid: []
438 },
439 {
440 code: "foo.filter(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
441 parserOptions: { ecmaVersion: 6 },
442 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
443 invalid: []
444 },
445 {
446 code: "foo.find(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
447 parserOptions: { ecmaVersion: 6 },
448 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
449 invalid: []
450 },
451 {
452 code: "foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
453 parserOptions: { ecmaVersion: 6 },
454 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
455 invalid: []
456 },
457 {
458 code: "foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
459 parserOptions: { ecmaVersion: 6 },
460 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
461 invalid: []
462 },
463 {
464 code: "foo.map(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
465 parserOptions: { ecmaVersion: 6 },
466 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
467 invalid: []
468 },
469 {
470 code: "foo.some(function() { console.log(this); z(x => console.log(x, this)); }, obj);",
471 parserOptions: { ecmaVersion: 6 },
472 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
473 invalid: []
474 },
475 {
476 code: "foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, null);",
477 parserOptions: { ecmaVersion: 6 },
478 errors,
479 valid: [NORMAL],
480 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
481 },
482
483 // @this tag.
484 {
485 code: "/** @this Obj */ function foo() { console.log(this); z(x => console.log(x, this)); }",
486 parserOptions: { ecmaVersion: 6 },
487 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
488 invalid: []
489 },
490 {
491 code: "/**\n * @returns {void}\n * @this Obj\n */\nfunction foo() { console.log(this); z(x => console.log(x, this)); }",
492 parserOptions: { ecmaVersion: 6 },
493 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
494 invalid: []
495 },
496 {
497 code: "/** @returns {void} */ function foo() { console.log(this); z(x => console.log(x, this)); }",
498 parserOptions: { ecmaVersion: 6 },
499 errors,
500 valid: [NORMAL],
501 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
502 },
503 {
504 code: "/** @this Obj */ foo(function() { console.log(this); z(x => console.log(x, this)); });",
505 parserOptions: { ecmaVersion: 6 },
506 errors,
507 valid: [NORMAL],
508 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
509 },
510 {
511 code: "foo(/* @this Obj */ function() { console.log(this); z(x => console.log(x, this)); });",
512 parserOptions: { ecmaVersion: 6 },
513 errors,
514 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
515 invalid: []
516 },
517
518 // https://github.com/eslint/eslint/issues/3254
519 {
520 code: "function foo() { console.log(this); z(x => console.log(x, this)); }",
521 parserOptions: { ecmaVersion: 6 },
522 errors,
523 valid: [NORMAL],
524 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
525 },
526
527 // https://github.com/eslint/eslint/issues/3287
528 {
529 code: "function foo() { /** @this Obj*/ return function bar() { console.log(this); z(x => console.log(x, this)); }; }",
530 parserOptions: { ecmaVersion: 6 },
531 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
532 invalid: []
533 },
534
535 // https://github.com/eslint/eslint/issues/6824
536 {
537 code: "var Ctor = function() { console.log(this); z(x => console.log(x, this)); }",
538 parserOptions: { ecmaVersion: 6 },
539 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
540 invalid: []
541 },
542 {
543 code: "var func = function() { console.log(this); z(x => console.log(x, this)); }",
544 parserOptions: { ecmaVersion: 6 },
545 errors,
546 valid: [NORMAL],
547 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
548 },
549 {
550 code: "Ctor = function() { console.log(this); z(x => console.log(x, this)); }",
551 parserOptions: { ecmaVersion: 6 },
552 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
553 invalid: []
554 },
555 {
556 code: "func = function() { console.log(this); z(x => console.log(x, this)); }",
557 parserOptions: { ecmaVersion: 6 },
558 errors,
559 valid: [NORMAL],
560 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
561 },
562 {
563 code: "function foo(Ctor = function() { console.log(this); z(x => console.log(x, this)); }) {}",
564 parserOptions: { ecmaVersion: 6 },
565 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
566 invalid: []
567 },
568 {
569 code: "function foo(func = function() { console.log(this); z(x => console.log(x, this)); }) {}",
570 parserOptions: { ecmaVersion: 6 },
571 errors,
572 valid: [NORMAL],
573 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
574 },
575 {
576 code: "[obj.method = function() { console.log(this); z(x => console.log(x, this)); }] = a",
577 parserOptions: { ecmaVersion: 6 },
578 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
579 invalid: []
580 },
581 {
582 code: "[func = function() { console.log(this); z(x => console.log(x, this)); }] = a",
583 parserOptions: { ecmaVersion: 6 },
584 errors,
585 valid: [NORMAL],
586 invalid: [USE_STRICT, IMPLIED_STRICT, MODULES]
587 },
588
589 // babel/no-invalid-this
590
591 // Class Instance Properties.
592 {
593 code: "class A {a = this.b;};",
594 parserOptions: { ecmaVersion: 6 },
595 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
596 invalid: []
597 },
598
599 {
600 code: "class A {a = () => {return this.b;};};",
601 parserOptions: { ecmaVersion: 6 },
602 valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
603 invalid: []
604 },
605];
606
607const ruleTester = new RuleTester();
608
609ruleTester.run("no-invalid-this", rule, {
610 valid: extractPatterns(patterns, "valid"),
611 invalid: extractPatterns(patterns, "invalid")
612});