Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/eslint-plugin-import
Path: blob/main/tests/src/rules/no-unused-modules.js
829 views
1
import { test, testFilePath, getTSParsers } from '../utils';
2
import jsxConfig from '../../../config/react';
3
import typescriptConfig from '../../../config/typescript';
4
5
import { RuleTester } from 'eslint';
6
import fs from 'fs';
7
import eslintPkg from 'eslint/package.json';
8
import semver from 'semver';
9
10
// TODO: figure out why these tests fail in eslint 4
11
const isESLint4TODO = semver.satisfies(eslintPkg.version, '^4');
12
13
const ruleTester = new RuleTester();
14
const typescriptRuleTester = new RuleTester(typescriptConfig);
15
const jsxRuleTester = new RuleTester(jsxConfig);
16
const rule = require('rules/no-unused-modules');
17
18
const error = message => ({ message });
19
20
const missingExportsOptions = [{
21
missingExports: true,
22
}];
23
24
const unusedExportsOptions = [{
25
unusedExports: true,
26
src: [testFilePath('./no-unused-modules/**/*.js')],
27
ignoreExports: [testFilePath('./no-unused-modules/*ignored*.js')],
28
}];
29
30
const unusedExportsTypescriptOptions = [{
31
unusedExports: true,
32
src: [testFilePath('./no-unused-modules/typescript')],
33
ignoreExports: undefined,
34
}];
35
36
const unusedExportsJsxOptions = [{
37
unusedExports: true,
38
src: [testFilePath('./no-unused-modules/jsx')],
39
ignoreExports: undefined,
40
}];
41
42
// tests for missing exports
43
ruleTester.run('no-unused-modules', rule, {
44
valid: [
45
test({
46
code: 'export default function noOptions() {}',
47
}),
48
test({
49
options: missingExportsOptions,
50
code: 'export default () => 1',
51
}),
52
test({
53
options: missingExportsOptions,
54
code: 'export const a = 1',
55
}),
56
test({
57
options: missingExportsOptions,
58
code: 'const a = 1; export { a }',
59
}),
60
test({
61
options: missingExportsOptions,
62
code: 'function a() { return true }; export { a }',
63
}),
64
test({
65
options: missingExportsOptions,
66
code: 'const a = 1; const b = 2; export { a, b }',
67
}),
68
test({
69
options: missingExportsOptions,
70
code: 'const a = 1; export default a',
71
}),
72
test({
73
options: missingExportsOptions,
74
code: 'export class Foo {}',
75
}),
76
test({
77
options: missingExportsOptions,
78
code: 'export const [foobar] = [];',
79
}),
80
test({
81
options: missingExportsOptions,
82
code: 'export const [foobar] = foobarFactory();',
83
}),
84
test({
85
options: missingExportsOptions,
86
code: `
87
export default function NewComponent () {
88
return 'I am new component'
89
}
90
`,
91
}),
92
],
93
invalid: [
94
test({
95
options: missingExportsOptions,
96
code: 'const a = 1',
97
errors: [error(`No exports found`)],
98
}),
99
test({
100
options: missingExportsOptions,
101
code: '/* const a = 1 */',
102
errors: [error(`No exports found`)],
103
}),
104
],
105
});
106
107
108
// tests for exports
109
ruleTester.run('no-unused-modules', rule, {
110
valid: [
111
test({
112
options: unusedExportsOptions,
113
code: 'import { o2 } from "./file-o";export default () => 12',
114
filename: testFilePath('./no-unused-modules/file-a.js'),
115
parser: require.resolve('babel-eslint'),
116
}),
117
test({
118
options: unusedExportsOptions,
119
code: 'export const b = 2',
120
filename: testFilePath('./no-unused-modules/file-b.js'),
121
parser: require.resolve('babel-eslint'),
122
}),
123
test({
124
options: unusedExportsOptions,
125
code: 'const c1 = 3; function c2() { return 3 }; export { c1, c2 }',
126
filename: testFilePath('./no-unused-modules/file-c.js'),
127
parser: require.resolve('babel-eslint'),
128
}),
129
test({
130
options: unusedExportsOptions,
131
code: 'export function d() { return 4 }',
132
filename: testFilePath('./no-unused-modules/file-d.js'),
133
parser: require.resolve('babel-eslint'),
134
}),
135
test({
136
options: unusedExportsOptions,
137
code: 'export class q { q0() {} }',
138
filename: testFilePath('./no-unused-modules/file-q.js'),
139
parser: require.resolve('babel-eslint'),
140
}),
141
test({
142
options: unusedExportsOptions,
143
code: 'const e0 = 5; export { e0 as e }',
144
filename: testFilePath('./no-unused-modules/file-e.js'),
145
parser: require.resolve('babel-eslint'),
146
}),
147
test({
148
options: unusedExportsOptions,
149
code: 'const l0 = 5; const l = 10; export { l0 as l1, l }; export default () => {}',
150
filename: testFilePath('./no-unused-modules/file-l.js'),
151
parser: require.resolve('babel-eslint'),
152
}),
153
test({
154
options: unusedExportsOptions,
155
code: 'const o0 = 0; const o1 = 1; export { o0, o1 as o2 }; export default () => {}',
156
filename: testFilePath('./no-unused-modules/file-o.js'),
157
parser: require.resolve('babel-eslint'),
158
}),
159
],
160
invalid: [
161
test({
162
options: unusedExportsOptions,
163
code: `import eslint from 'eslint'
164
import fileA from './file-a'
165
import { b } from './file-b'
166
import { c1, c2 } from './file-c'
167
import { d } from './file-d'
168
import { e } from './file-e'
169
import { e2 } from './file-e'
170
import { h2 } from './file-h'
171
import * as l from './file-l'
172
export * from './file-n'
173
export { default, o0, o3 } from './file-o'
174
export { p } from './file-p'
175
import s from './file-s'`,
176
filename: testFilePath('./no-unused-modules/file-0.js'),
177
errors: [
178
error(`exported declaration 'default' not used within other modules`),
179
error(`exported declaration 'o0' not used within other modules`),
180
error(`exported declaration 'o3' not used within other modules`),
181
error(`exported declaration 'p' not used within other modules`),
182
],
183
}),
184
test({
185
options: unusedExportsOptions,
186
code: `const n0 = 'n0'; const n1 = 42; export { n0, n1 }; export default () => {}`,
187
filename: testFilePath('./no-unused-modules/file-n.js'),
188
errors: [error(`exported declaration 'default' not used within other modules`)],
189
}),
190
],
191
});
192
193
// test for unused exports
194
ruleTester.run('no-unused-modules', rule, {
195
valid: [],
196
invalid: [
197
test({
198
options: unusedExportsOptions,
199
code: 'export default () => 13',
200
filename: testFilePath('./no-unused-modules/file-f.js'),
201
errors: [error(`exported declaration 'default' not used within other modules`)],
202
}),
203
test({
204
options: unusedExportsOptions,
205
code: 'export const g = 2',
206
filename: testFilePath('./no-unused-modules/file-g.js'),
207
errors: [error(`exported declaration 'g' not used within other modules`)],
208
}),
209
test({
210
options: unusedExportsOptions,
211
code: 'const h1 = 3; function h2() { return 3 }; const h3 = true; export { h1, h2, h3 }',
212
filename: testFilePath('./no-unused-modules/file-h.js'),
213
errors: [error(`exported declaration 'h1' not used within other modules`)],
214
}),
215
test({
216
options: unusedExportsOptions,
217
code: 'const i1 = 3; function i2() { return 3 }; export { i1, i2 }',
218
filename: testFilePath('./no-unused-modules/file-i.js'),
219
errors: [
220
error(`exported declaration 'i1' not used within other modules`),
221
error(`exported declaration 'i2' not used within other modules`),
222
],
223
}),
224
test({
225
options: unusedExportsOptions,
226
code: 'export function j() { return 4 }',
227
filename: testFilePath('./no-unused-modules/file-j.js'),
228
errors: [error(`exported declaration 'j' not used within other modules`)],
229
}),
230
test({
231
options: unusedExportsOptions,
232
code: 'export class q { q0() {} }',
233
filename: testFilePath('./no-unused-modules/file-q.js'),
234
errors: [error(`exported declaration 'q' not used within other modules`)],
235
}),
236
test({
237
options: unusedExportsOptions,
238
code: 'const k0 = 5; export { k0 as k }',
239
filename: testFilePath('./no-unused-modules/file-k.js'),
240
errors: [error(`exported declaration 'k' not used within other modules`)],
241
}),
242
],
243
});
244
245
246
describe('dynamic imports', () => {
247
if (semver.satisfies(eslintPkg.version, '< 6')) {
248
beforeEach(function () {
249
this.skip();
250
});
251
return;
252
}
253
254
// test for unused exports with `import()`
255
ruleTester.run('no-unused-modules', rule, {
256
valid: [
257
test({
258
options: unusedExportsOptions,
259
code: `
260
export const a = 10
261
export const b = 20
262
export const c = 30
263
const d = 40
264
export default d
265
`,
266
parser: require.resolve('babel-eslint'),
267
filename: testFilePath('./no-unused-modules/exports-for-dynamic-js.js'),
268
}),
269
],
270
invalid: [
271
test({
272
options: unusedExportsOptions,
273
code: `
274
export const a = 10
275
export const b = 20
276
export const c = 30
277
const d = 40
278
export default d
279
`,
280
parser: require.resolve('babel-eslint'),
281
filename: testFilePath('./no-unused-modules/exports-for-dynamic-js-2.js'),
282
errors: [
283
error(`exported declaration 'a' not used within other modules`),
284
error(`exported declaration 'b' not used within other modules`),
285
error(`exported declaration 'c' not used within other modules`),
286
error(`exported declaration 'default' not used within other modules`),
287
] }),
288
],
289
});
290
typescriptRuleTester.run('no-unused-modules', rule, {
291
valid: [
292
test({
293
options: unusedExportsTypescriptOptions,
294
code: `
295
export const ts_a = 10
296
export const ts_b = 20
297
export const ts_c = 30
298
const ts_d = 40
299
export default ts_d
300
`,
301
parser: require.resolve('@typescript-eslint/parser'),
302
filename: testFilePath('./no-unused-modules/typescript/exports-for-dynamic-ts.ts'),
303
}),
304
],
305
invalid: [
306
],
307
});
308
});
309
310
// // test for export from
311
ruleTester.run('no-unused-modules', rule, {
312
valid: [
313
test({
314
options: unusedExportsOptions,
315
code: `export { default } from './file-o'`,
316
filename: testFilePath('./no-unused-modules/file-s.js'),
317
}),
318
],
319
invalid: [
320
test({
321
options: unusedExportsOptions,
322
code: `export { k } from '${testFilePath('./no-unused-modules/file-k.js')}'`,
323
filename: testFilePath('./no-unused-modules/file-j.js'),
324
errors: [error(`exported declaration 'k' not used within other modules`)],
325
}),
326
],
327
});
328
329
ruleTester.run('no-unused-modules', rule, {
330
valid: [
331
test({
332
options: unusedExportsOptions,
333
code: 'const k0 = 5; export { k0 as k }',
334
filename: testFilePath('./no-unused-modules/file-k.js'),
335
}),
336
],
337
invalid: [],
338
});
339
340
// test for ignored files
341
ruleTester.run('no-unused-modules', rule, {
342
valid: [
343
test({
344
options: unusedExportsOptions,
345
code: 'export default () => 14',
346
filename: testFilePath('./no-unused-modules/file-ignored-a.js'),
347
}),
348
test({
349
options: unusedExportsOptions,
350
code: 'export const b = 2',
351
filename: testFilePath('./no-unused-modules/file-ignored-b.js'),
352
}),
353
test({
354
options: unusedExportsOptions,
355
code: 'const c1 = 3; function c2() { return 3 }; export { c1, c2 }',
356
filename: testFilePath('./no-unused-modules/file-ignored-c.js'),
357
}),
358
test({
359
options: unusedExportsOptions,
360
code: 'export function d() { return 4 }',
361
filename: testFilePath('./no-unused-modules/file-ignored-d.js'),
362
}),
363
test({
364
options: unusedExportsOptions,
365
code: 'const f = 5; export { f as e }',
366
filename: testFilePath('./no-unused-modules/file-ignored-e.js'),
367
}),
368
test({
369
options: unusedExportsOptions,
370
code: 'const l0 = 5; const l = 10; export { l0 as l1, l }; export default () => {}',
371
filename: testFilePath('./no-unused-modules/file-ignored-l.js'),
372
}),
373
],
374
invalid: [],
375
});
376
377
// add named import for file with default export
378
ruleTester.run('no-unused-modules', rule, {
379
valid: [
380
test({
381
options: unusedExportsOptions,
382
code: `import { f } from '${testFilePath('./no-unused-modules/file-f.js')}'`,
383
filename: testFilePath('./no-unused-modules/file-0.js'),
384
}),
385
],
386
invalid: [
387
test({
388
options: unusedExportsOptions,
389
code: 'export default () => 15',
390
filename: testFilePath('./no-unused-modules/file-f.js'),
391
errors: [error(`exported declaration 'default' not used within other modules`)],
392
}),
393
],
394
});
395
396
// add default import for file with default export
397
ruleTester.run('no-unused-modules', rule, {
398
valid: [
399
test({
400
options: unusedExportsOptions,
401
code: `import f from '${testFilePath('./no-unused-modules/file-f.js')}'`,
402
filename: testFilePath('./no-unused-modules/file-0.js'),
403
}),
404
test({
405
options: unusedExportsOptions,
406
code: 'export default () => 16',
407
filename: testFilePath('./no-unused-modules/file-f.js'),
408
}),
409
],
410
invalid: [],
411
});
412
413
// add default import for file with named export
414
ruleTester.run('no-unused-modules', rule, {
415
valid: [
416
test({
417
options: unusedExportsOptions,
418
code: `import g from '${testFilePath('./no-unused-modules/file-g.js')}';import {h} from '${testFilePath('./no-unused-modules/file-gg.js')}'`,
419
filename: testFilePath('./no-unused-modules/file-0.js'),
420
}),
421
],
422
invalid: [
423
test({
424
options: unusedExportsOptions,
425
code: 'export const g = 2',
426
filename: testFilePath('./no-unused-modules/file-g.js'),
427
errors: [error(`exported declaration 'g' not used within other modules`)],
428
})],
429
});
430
431
// add named import for file with named export
432
ruleTester.run('no-unused-modules', rule, {
433
valid: [
434
test({
435
options: unusedExportsOptions,
436
code: `import { g } from '${testFilePath('./no-unused-modules/file-g.js')}'; import eslint from 'eslint'`,
437
filename: testFilePath('./no-unused-modules/file-0.js'),
438
}),
439
test({
440
options: unusedExportsOptions,
441
code: 'export const g = 2',
442
filename: testFilePath('./no-unused-modules/file-g.js'),
443
}),
444
],
445
invalid: [],
446
});
447
448
// add different named import for file with named export
449
ruleTester.run('no-unused-modules', rule, {
450
valid: [
451
test({
452
options: unusedExportsOptions,
453
code: `import { c } from '${testFilePath('./no-unused-modules/file-b.js')}'`,
454
filename: testFilePath('./no-unused-modules/file-0.js'),
455
}),
456
],
457
invalid: [
458
test({
459
options: unusedExportsOptions,
460
code: 'export const b = 2',
461
filename: testFilePath('./no-unused-modules/file-b.js'),
462
errors: [error(`exported declaration 'b' not used within other modules`)],
463
}),
464
],
465
});
466
467
// add renamed named import for file with named export
468
ruleTester.run('no-unused-modules', rule, {
469
valid: [
470
test({
471
options: unusedExportsOptions,
472
code: `import { g as g1 } from '${testFilePath('./no-unused-modules/file-g.js')}'; import eslint from 'eslint'`,
473
filename: testFilePath('./no-unused-modules/file-0.js'),
474
}),
475
test({
476
options: unusedExportsOptions,
477
code: 'export const g = 2',
478
filename: testFilePath('./no-unused-modules/file-g.js'),
479
}),
480
],
481
invalid: [],
482
});
483
484
// add different renamed named import for file with named export
485
ruleTester.run('no-unused-modules', rule, {
486
valid: [
487
test({
488
options: unusedExportsOptions,
489
code: `import { g1 as g } from '${testFilePath('./no-unused-modules/file-g.js')}'`,
490
filename: testFilePath('./no-unused-modules/file-0.js'),
491
}),
492
],
493
invalid: [
494
test({
495
options: unusedExportsOptions,
496
code: 'export const g = 2',
497
filename: testFilePath('./no-unused-modules/file-g.js'),
498
errors: [error(`exported declaration 'g' not used within other modules`)],
499
}),
500
],
501
});
502
503
// remove default import for file with default export
504
ruleTester.run('no-unused-modules', rule, {
505
valid: [
506
test({
507
options: unusedExportsOptions,
508
code: `import { a1, a2 } from '${testFilePath('./no-unused-modules/file-a.js')}'`,
509
filename: testFilePath('./no-unused-modules/file-0.js'),
510
}),
511
],
512
invalid: [
513
test({
514
options: unusedExportsOptions,
515
code: 'export default () => 17',
516
filename: testFilePath('./no-unused-modules/file-a.js'),
517
errors: [error(`exported declaration 'default' not used within other modules`)],
518
}),
519
],
520
});
521
522
// add namespace import for file with unused exports
523
ruleTester.run('no-unused-modules', rule, {
524
valid: [],
525
invalid: [
526
test({
527
options: unusedExportsOptions,
528
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
529
filename: testFilePath('./no-unused-modules/file-m.js'),
530
errors: [
531
error(`exported declaration 'm1' not used within other modules`),
532
error(`exported declaration 'm' not used within other modules`),
533
error(`exported declaration 'default' not used within other modules`),
534
],
535
}),
536
],
537
});
538
ruleTester.run('no-unused-modules', rule, {
539
valid: [
540
test({
541
options: unusedExportsOptions,
542
code: `import * as m from '${testFilePath('./no-unused-modules/file-m.js')}'; import unknown from 'unknown-module'`,
543
filename: testFilePath('./no-unused-modules/file-0.js'),
544
}),
545
test({
546
options: unusedExportsOptions,
547
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
548
filename: testFilePath('./no-unused-modules/file-m.js'),
549
}),
550
],
551
invalid: [],
552
});
553
554
// remove all exports
555
ruleTester.run('no-unused-modules', rule, {
556
valid: [
557
test({
558
options: unusedExportsOptions,
559
code: `/* import * as m from '${testFilePath('./no-unused-modules/file-m.js')}' */`,
560
filename: testFilePath('./no-unused-modules/file-0.js'),
561
}),
562
],
563
invalid: [
564
test({
565
options: unusedExportsOptions,
566
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
567
filename: testFilePath('./no-unused-modules/file-m.js'),
568
errors: [
569
error(`exported declaration 'm1' not used within other modules`),
570
error(`exported declaration 'm' not used within other modules`),
571
error(`exported declaration 'default' not used within other modules`),
572
],
573
}),
574
],
575
});
576
577
ruleTester.run('no-unused-modules', rule, {
578
valid: [
579
test({
580
options: unusedExportsOptions,
581
code: `export * from '${testFilePath('./no-unused-modules/file-m.js')}';`,
582
filename: testFilePath('./no-unused-modules/file-0.js'),
583
}),
584
],
585
invalid: [],
586
});
587
ruleTester.run('no-unused-modules', rule, {
588
valid: [],
589
invalid: [
590
test({
591
options: unusedExportsOptions,
592
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
593
filename: testFilePath('./no-unused-modules/file-m.js'),
594
errors: [error(`exported declaration 'default' not used within other modules`)],
595
}),
596
],
597
});
598
599
ruleTester.run('no-unused-modules', rule, {
600
valid: [],
601
invalid: [
602
test({
603
options: unusedExportsOptions,
604
code: `export { m1, m} from '${testFilePath('./no-unused-modules/file-m.js')}';`,
605
filename: testFilePath('./no-unused-modules/file-0.js'),
606
errors: [
607
error(`exported declaration 'm1' not used within other modules`),
608
error(`exported declaration 'm' not used within other modules`),
609
],
610
}),
611
test({
612
options: unusedExportsOptions,
613
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
614
filename: testFilePath('./no-unused-modules/file-m.js'),
615
errors: [error(`exported declaration 'default' not used within other modules`)],
616
}),
617
],
618
});
619
620
ruleTester.run('no-unused-modules', rule, {
621
valid: [
622
/* TODO:
623
test({
624
options: unusedExportsOptions,
625
code: `export { default, m1 } from '${testFilePath('./no-unused-modules/file-m.js')}';`,
626
filename: testFilePath('./no-unused-modules/file-0.js')
627
}),
628
*/
629
],
630
invalid: [
631
test({
632
options: unusedExportsOptions,
633
code: `export { default, m1 } from '${testFilePath('./no-unused-modules/file-m.js')}';`,
634
filename: testFilePath('./no-unused-modules/file-0.js'),
635
errors: [
636
error(`exported declaration 'default' not used within other modules`),
637
error(`exported declaration 'm1' not used within other modules`),
638
],
639
}),
640
test({
641
options: unusedExportsOptions,
642
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
643
filename: testFilePath('./no-unused-modules/file-m.js'),
644
errors: [error(`exported declaration 'm' not used within other modules`)],
645
}),
646
],
647
});
648
649
// Test that import and export in the same file both counts as usage
650
ruleTester.run('no-unused-modules', rule, {
651
valid: [
652
test({
653
options: unusedExportsOptions,
654
code: `export const a = 5;export const b = 't1'`,
655
filename: testFilePath('./no-unused-modules/import-export-1.js'),
656
}),
657
],
658
invalid: [],
659
});
660
661
describe('renameDefault', () => {
662
ruleTester.run('no-unused-modules', rule, {
663
valid: [
664
test({
665
options: unusedExportsOptions,
666
code: 'export { default as Component } from "./Component"',
667
filename: testFilePath('./no-unused-modules/renameDefault/components.js'),
668
}),
669
test({
670
options: unusedExportsOptions,
671
code: 'export default function Component() {}',
672
filename: testFilePath('./no-unused-modules/renameDefault/Component.js'),
673
}),
674
],
675
invalid: [],
676
});
677
ruleTester.run('no-unused-modules', rule, {
678
valid: [
679
test({
680
options: unusedExportsOptions,
681
code: 'export { default as ComponentA } from "./ComponentA";export { default as ComponentB } from "./ComponentB";',
682
filename: testFilePath('./no-unused-modules/renameDefault-2/components.js'),
683
}),
684
test({
685
options: unusedExportsOptions,
686
code: 'export default function ComponentA() {};',
687
filename: testFilePath('./no-unused-modules/renameDefault-2/ComponentA.js'),
688
}),
689
],
690
invalid: [],
691
});
692
});
693
694
describe('test behavior for new file', () => {
695
before(() => {
696
fs.writeFileSync(testFilePath('./no-unused-modules/file-added-0.js'), '', { encoding: 'utf8' });
697
});
698
699
// add import in newly created file
700
ruleTester.run('no-unused-modules', rule, {
701
valid: [
702
test({
703
options: unusedExportsOptions,
704
code: `import * as m from '${testFilePath('./no-unused-modules/file-m.js')}'`,
705
filename: testFilePath('./no-unused-modules/file-added-0.js'),
706
}),
707
test({
708
options: unusedExportsOptions,
709
code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
710
filename: testFilePath('./no-unused-modules/file-m.js'),
711
}),
712
],
713
invalid: [],
714
});
715
716
// add export for newly created file
717
ruleTester.run('no-unused-modules', rule, {
718
valid: [],
719
invalid: [
720
test({
721
options: unusedExportsOptions,
722
code: `export default () => {2}`,
723
filename: testFilePath('./no-unused-modules/file-added-0.js'),
724
errors: [error(`exported declaration 'default' not used within other modules`)],
725
}),
726
],
727
});
728
729
ruleTester.run('no-unused-modules', rule, {
730
valid: [
731
test({
732
options: unusedExportsOptions,
733
code: `import def from '${testFilePath('./no-unused-modules/file-added-0.js')}'`,
734
filename: testFilePath('./no-unused-modules/file-0.js'),
735
}),
736
test({
737
options: unusedExportsOptions,
738
code: `export default () => {}`,
739
filename: testFilePath('./no-unused-modules/file-added-0.js'),
740
}),
741
],
742
invalid: [],
743
});
744
745
// export * only considers named imports. default imports still need to be reported
746
ruleTester.run('no-unused-modules', rule, {
747
valid: [
748
test({
749
options: unusedExportsOptions,
750
code: `export * from '${testFilePath('./no-unused-modules/file-added-0.js')}'`,
751
filename: testFilePath('./no-unused-modules/file-0.js'),
752
}),
753
// Test export * from 'external-compiled-library'
754
test({
755
options: unusedExportsOptions,
756
code: `export * from 'external-compiled-library'`,
757
filename: testFilePath('./no-unused-modules/file-r.js'),
758
}),
759
],
760
invalid: [
761
test({
762
options: unusedExportsOptions,
763
code: `export const z = 'z';export default () => {}`,
764
filename: testFilePath('./no-unused-modules/file-added-0.js'),
765
errors: [error(`exported declaration 'default' not used within other modules`)],
766
}),
767
],
768
});
769
ruleTester.run('no-unused-modules', rule, {
770
valid: [
771
test({
772
options: unusedExportsOptions,
773
code: `export const a = 2`,
774
filename: testFilePath('./no-unused-modules/file-added-0.js'),
775
}),
776
],
777
invalid: [],
778
});
779
780
// remove export *. all exports need to be reported
781
ruleTester.run('no-unused-modules', rule, {
782
valid: [],
783
invalid: [
784
test({
785
options: unusedExportsOptions,
786
code: `export { a } from '${testFilePath('./no-unused-modules/file-added-0.js')}'`,
787
filename: testFilePath('./no-unused-modules/file-0.js'),
788
errors: [error(`exported declaration 'a' not used within other modules`)],
789
}),
790
test({
791
options: unusedExportsOptions,
792
code: `export const z = 'z';export default () => {}`,
793
filename: testFilePath('./no-unused-modules/file-added-0.js'),
794
errors: [
795
error(`exported declaration 'z' not used within other modules`),
796
error(`exported declaration 'default' not used within other modules`),
797
],
798
}),
799
],
800
});
801
802
803
describe('test behavior for new file', () => {
804
before(() => {
805
fs.writeFileSync(testFilePath('./no-unused-modules/file-added-1.js'), '', { encoding: 'utf8' });
806
});
807
ruleTester.run('no-unused-modules', rule, {
808
valid: [
809
test({
810
options: unusedExportsOptions,
811
code: `export * from '${testFilePath('./no-unused-modules/file-added-1.js')}'`,
812
filename: testFilePath('./no-unused-modules/file-0.js'),
813
}),
814
],
815
invalid: [
816
test({
817
options: unusedExportsOptions,
818
code: `export const z = 'z';export default () => {}`,
819
filename: testFilePath('./no-unused-modules/file-added-1.js'),
820
errors: [error(`exported declaration 'default' not used within other modules`)],
821
}),
822
],
823
});
824
after(() => {
825
if (fs.existsSync(testFilePath('./no-unused-modules/file-added-1.js'))) {
826
fs.unlinkSync(testFilePath('./no-unused-modules/file-added-1.js'));
827
}
828
});
829
});
830
831
after(() => {
832
if (fs.existsSync(testFilePath('./no-unused-modules/file-added-0.js'))) {
833
fs.unlinkSync(testFilePath('./no-unused-modules/file-added-0.js'));
834
}
835
});
836
});
837
838
describe('test behavior for new file', () => {
839
before(() => {
840
fs.writeFileSync(testFilePath('./no-unused-modules/file-added-2.js'), '', { encoding: 'utf8' });
841
});
842
ruleTester.run('no-unused-modules', rule, {
843
valid: [
844
test({
845
options: unusedExportsOptions,
846
code: `import added from '${testFilePath('./no-unused-modules/file-added-2.js')}'`,
847
filename: testFilePath('./no-unused-modules/file-added-1.js'),
848
}),
849
test({
850
options: unusedExportsOptions,
851
code: `export default () => {}`,
852
filename: testFilePath('./no-unused-modules/file-added-2.js'),
853
}),
854
],
855
invalid: [],
856
});
857
after(() => {
858
if (fs.existsSync(testFilePath('./no-unused-modules/file-added-2.js'))) {
859
fs.unlinkSync(testFilePath('./no-unused-modules/file-added-2.js'));
860
}
861
});
862
});
863
864
describe('test behavior for new file', () => {
865
before(() => {
866
fs.writeFileSync(testFilePath('./no-unused-modules/file-added-3.js'), '', { encoding: 'utf8' });
867
});
868
ruleTester.run('no-unused-modules', rule, {
869
valid: [
870
test({
871
options: unusedExportsOptions,
872
code: `import { added } from '${testFilePath('./no-unused-modules/file-added-3.js')}'`,
873
filename: testFilePath('./no-unused-modules/file-added-1.js'),
874
}),
875
test({
876
options: unusedExportsOptions,
877
code: `export const added = () => {}`,
878
filename: testFilePath('./no-unused-modules/file-added-3.js'),
879
}),
880
],
881
invalid: [],
882
});
883
after(() => {
884
if (fs.existsSync(testFilePath('./no-unused-modules/file-added-3.js'))) {
885
fs.unlinkSync(testFilePath('./no-unused-modules/file-added-3.js'));
886
}
887
});
888
});
889
890
describe('test behavior for destructured exports', () => {
891
ruleTester.run('no-unused-modules', rule, {
892
valid: [
893
test({
894
options: unusedExportsOptions,
895
code: `import { destructured } from '${testFilePath('./no-unused-modules/file-destructured-1.js')}'`,
896
filename: testFilePath('./no-unused-modules/file-destructured-2.js'),
897
}),
898
test({
899
options: unusedExportsOptions,
900
code: `export const { destructured } = {};`,
901
filename: testFilePath('./no-unused-modules/file-destructured-1.js'),
902
}),
903
],
904
invalid: [
905
test({
906
options: unusedExportsOptions,
907
code: `export const { destructured2 } = {};`,
908
filename: testFilePath('./no-unused-modules/file-destructured-1.js'),
909
errors: [`exported declaration 'destructured2' not used within other modules`],
910
}),
911
],
912
});
913
});
914
915
describe('test behavior for new file', () => {
916
before(() => {
917
fs.writeFileSync(testFilePath('./no-unused-modules/file-added-4.js.js'), '', { encoding: 'utf8' });
918
});
919
ruleTester.run('no-unused-modules', rule, {
920
valid: [
921
test({
922
options: unusedExportsOptions,
923
code: `import * as added from '${testFilePath('./no-unused-modules/file-added-4.js.js')}'`,
924
filename: testFilePath('./no-unused-modules/file-added-1.js'),
925
}),
926
test({
927
options: unusedExportsOptions,
928
code: `export const added = () => {}; export default () => {}`,
929
filename: testFilePath('./no-unused-modules/file-added-4.js.js'),
930
}),
931
],
932
invalid: [],
933
});
934
after(() => {
935
if (fs.existsSync(testFilePath('./no-unused-modules/file-added-4.js.js'))) {
936
fs.unlinkSync(testFilePath('./no-unused-modules/file-added-4.js.js'));
937
}
938
});
939
});
940
941
describe('do not report missing export for ignored file', () => {
942
ruleTester.run('no-unused-modules', rule, {
943
valid: [
944
test({
945
options: [{
946
src: [testFilePath('./no-unused-modules/**/*.js')],
947
ignoreExports: [testFilePath('./no-unused-modules/*ignored*.js')],
948
missingExports: true,
949
}],
950
code: 'export const test = true',
951
filename: testFilePath('./no-unused-modules/file-ignored-a.js'),
952
}),
953
],
954
invalid: [],
955
});
956
});
957
958
// lint file not available in `src`
959
ruleTester.run('no-unused-modules', rule, {
960
valid: [
961
test({
962
options: unusedExportsOptions,
963
code: `export const jsxFoo = 'foo'; export const jsxBar = 'bar'`,
964
filename: testFilePath('../jsx/named.jsx'),
965
}),
966
],
967
invalid: [],
968
});
969
970
describe('do not report unused export for files mentioned in package.json', () => {
971
ruleTester.run('no-unused-modules', rule, {
972
valid: [
973
test({
974
options: unusedExportsOptions,
975
code: 'export const bin = "bin"',
976
filename: testFilePath('./no-unused-modules/bin.js'),
977
}),
978
test({
979
options: unusedExportsOptions,
980
code: 'export const binObject = "binObject"',
981
filename: testFilePath('./no-unused-modules/binObject/index.js'),
982
}),
983
test({
984
options: unusedExportsOptions,
985
code: 'export const browser = "browser"',
986
filename: testFilePath('./no-unused-modules/browser.js'),
987
}),
988
test({
989
options: unusedExportsOptions,
990
code: 'export const browserObject = "browserObject"',
991
filename: testFilePath('./no-unused-modules/browserObject/index.js'),
992
}),
993
test({
994
options: unusedExportsOptions,
995
code: 'export const main = "main"',
996
filename: testFilePath('./no-unused-modules/main/index.js'),
997
}),
998
],
999
invalid: [
1000
test({
1001
options: unusedExportsOptions,
1002
code: 'export const privatePkg = "privatePkg"',
1003
filename: testFilePath('./no-unused-modules/privatePkg/index.js'),
1004
errors: [error(`exported declaration 'privatePkg' not used within other modules`)],
1005
}),
1006
],
1007
});
1008
});
1009
1010
describe('Avoid errors if re-export all from umd compiled library', () => {
1011
ruleTester.run('no-unused-modules', rule, {
1012
valid: [
1013
test({
1014
options: unusedExportsOptions,
1015
code: `export * from '${testFilePath('./no-unused-modules/bin.js')}'`,
1016
filename: testFilePath('./no-unused-modules/main/index.js'),
1017
}),
1018
],
1019
invalid: [],
1020
});
1021
});
1022
1023
context('TypeScript', function () {
1024
getTSParsers().forEach((parser) => {
1025
typescriptRuleTester.run('no-unused-modules', rule, {
1026
valid: [].concat(
1027
test({
1028
options: unusedExportsTypescriptOptions,
1029
code: `
1030
import {b} from './file-ts-b';
1031
import {c} from './file-ts-c';
1032
import {d} from './file-ts-d';
1033
import {e} from './file-ts-e';
1034
1035
const a = b + 1 + e.f;
1036
const a2: c = {};
1037
const a3: d = {};
1038
`,
1039
parser,
1040
filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
1041
}),
1042
test({
1043
options: unusedExportsTypescriptOptions,
1044
code: `export const b = 2;`,
1045
parser,
1046
filename: testFilePath('./no-unused-modules/typescript/file-ts-b.ts'),
1047
}),
1048
test({
1049
options: unusedExportsTypescriptOptions,
1050
code: `export interface c {};`,
1051
parser,
1052
filename: testFilePath('./no-unused-modules/typescript/file-ts-c.ts'),
1053
}),
1054
test({
1055
options: unusedExportsTypescriptOptions,
1056
code: `export type d = {};`,
1057
parser,
1058
filename: testFilePath('./no-unused-modules/typescript/file-ts-d.ts'),
1059
}),
1060
test({
1061
options: unusedExportsTypescriptOptions,
1062
code: `export enum e { f };`,
1063
parser,
1064
filename: testFilePath('./no-unused-modules/typescript/file-ts-e.ts'),
1065
}),
1066
test({
1067
options: unusedExportsTypescriptOptions,
1068
code: `
1069
import type {b} from './file-ts-b-used-as-type';
1070
import type {c} from './file-ts-c-used-as-type';
1071
import type {d} from './file-ts-d-used-as-type';
1072
import type {e} from './file-ts-e-used-as-type';
1073
1074
const a: typeof b = 2;
1075
const a2: c = {};
1076
const a3: d = {};
1077
const a4: typeof e = undefined;
1078
`,
1079
parser,
1080
filename: testFilePath('./no-unused-modules/typescript/file-ts-a-import-type.ts'),
1081
}),
1082
test({
1083
options: unusedExportsTypescriptOptions,
1084
code: `export const b = 2;`,
1085
parser,
1086
filename: testFilePath('./no-unused-modules/typescript/file-ts-b-used-as-type.ts'),
1087
}),
1088
test({
1089
options: unusedExportsTypescriptOptions,
1090
code: `export interface c {};`,
1091
parser,
1092
filename: testFilePath('./no-unused-modules/typescript/file-ts-c-used-as-type.ts'),
1093
}),
1094
test({
1095
options: unusedExportsTypescriptOptions,
1096
code: `export type d = {};`,
1097
parser,
1098
filename: testFilePath('./no-unused-modules/typescript/file-ts-d-used-as-type.ts'),
1099
}),
1100
test({
1101
options: unusedExportsTypescriptOptions,
1102
code: `export enum e { f };`,
1103
parser,
1104
filename: testFilePath('./no-unused-modules/typescript/file-ts-e-used-as-type.ts'),
1105
}),
1106
// Should also be valid when the exporting files are linted before the importing ones
1107
isESLint4TODO ? [] : test({
1108
options: unusedExportsTypescriptOptions,
1109
code: `export interface g {}`,
1110
parser,
1111
filename: testFilePath('./no-unused-modules/typescript/file-ts-g.ts'),
1112
}),
1113
test({
1114
options: unusedExportsTypescriptOptions,
1115
code: `import {g} from './file-ts-g';`,
1116
parser,
1117
filename: testFilePath('./no-unused-modules/typescript/file-ts-f.ts'),
1118
}),
1119
isESLint4TODO ? [] : test({
1120
options: unusedExportsTypescriptOptions,
1121
code: `export interface g {}; /* used-as-type */`,
1122
parser,
1123
filename: testFilePath('./no-unused-modules/typescript/file-ts-g-used-as-type.ts'),
1124
}),
1125
test({
1126
options: unusedExportsTypescriptOptions,
1127
code: `import type {g} from './file-ts-g';`,
1128
parser,
1129
filename: testFilePath('./no-unused-modules/typescript/file-ts-f-import-type.ts'),
1130
}),
1131
),
1132
invalid: [].concat(
1133
test({
1134
options: unusedExportsTypescriptOptions,
1135
code: `export const b = 2;`,
1136
parser,
1137
filename: testFilePath('./no-unused-modules/typescript/file-ts-b-unused.ts'),
1138
errors: [
1139
error(`exported declaration 'b' not used within other modules`),
1140
],
1141
}),
1142
test({
1143
options: unusedExportsTypescriptOptions,
1144
code: `export interface c {};`,
1145
parser,
1146
filename: testFilePath('./no-unused-modules/typescript/file-ts-c-unused.ts'),
1147
errors: [
1148
error(`exported declaration 'c' not used within other modules`),
1149
],
1150
}),
1151
test({
1152
options: unusedExportsTypescriptOptions,
1153
code: `export type d = {};`,
1154
parser,
1155
filename: testFilePath('./no-unused-modules/typescript/file-ts-d-unused.ts'),
1156
errors: [
1157
error(`exported declaration 'd' not used within other modules`),
1158
],
1159
}),
1160
test({
1161
options: unusedExportsTypescriptOptions,
1162
code: `export enum e { f };`,
1163
parser,
1164
filename: testFilePath('./no-unused-modules/typescript/file-ts-e-unused.ts'),
1165
errors: [
1166
error(`exported declaration 'e' not used within other modules`),
1167
],
1168
}),
1169
),
1170
});
1171
});
1172
});
1173
1174
describe('correctly work with JSX only files', () => {
1175
jsxRuleTester.run('no-unused-modules', rule, {
1176
valid: [
1177
test({
1178
options: unusedExportsJsxOptions,
1179
code: 'import a from "file-jsx-a";',
1180
parser: require.resolve('babel-eslint'),
1181
filename: testFilePath('./no-unused-modules/jsx/file-jsx-a.jsx'),
1182
}),
1183
],
1184
invalid: [
1185
test({
1186
options: unusedExportsJsxOptions,
1187
code: `export const b = 2;`,
1188
parser: require.resolve('babel-eslint'),
1189
filename: testFilePath('./no-unused-modules/jsx/file-jsx-b.jsx'),
1190
errors: [
1191
error(`exported declaration 'b' not used within other modules`),
1192
],
1193
}),
1194
],
1195
});
1196
});
1197
1198
describe('ignore flow types', () => {
1199
ruleTester.run('no-unused-modules', rule, {
1200
valid: [
1201
test({
1202
options: unusedExportsOptions,
1203
code: 'import { type FooType, type FooInterface } from "./flow-2";',
1204
parser: require.resolve('babel-eslint'),
1205
filename: testFilePath('./no-unused-modules/flow/flow-0.js'),
1206
}),
1207
test({
1208
options: unusedExportsOptions,
1209
code: `// @flow strict
1210
export type FooType = string;
1211
export interface FooInterface {};
1212
`,
1213
parser: require.resolve('babel-eslint'),
1214
filename: testFilePath('./no-unused-modules/flow/flow-2.js'),
1215
}),
1216
test({
1217
options: unusedExportsOptions,
1218
code: 'import type { FooType, FooInterface } from "./flow-4";',
1219
parser: require.resolve('babel-eslint'),
1220
filename: testFilePath('./no-unused-modules/flow/flow-3.js'),
1221
}),
1222
test({
1223
options: unusedExportsOptions,
1224
code: `// @flow strict
1225
export type FooType = string;
1226
export interface FooInterface {};
1227
`,
1228
parser: require.resolve('babel-eslint'),
1229
filename: testFilePath('./no-unused-modules/flow/flow-4.js'),
1230
}),
1231
test({
1232
options: unusedExportsOptions,
1233
code: `// @flow strict
1234
export type Bar = number;
1235
export interface BarInterface {};
1236
`,
1237
parser: require.resolve('babel-eslint'),
1238
filename: testFilePath('./no-unused-modules/flow/flow-1.js'),
1239
}),
1240
],
1241
invalid: [],
1242
});
1243
});
1244
1245
describe('support (nested) destructuring assignment', () => {
1246
ruleTester.run('no-unused-modules', rule, {
1247
valid: [
1248
test({
1249
options: unusedExportsOptions,
1250
code: 'import {a, b} from "./destructuring-b";',
1251
parser: require.resolve('babel-eslint'),
1252
filename: testFilePath('./no-unused-modules/destructuring-a.js'),
1253
}),
1254
test({
1255
options: unusedExportsOptions,
1256
code: 'const obj = {a: 1, dummy: {b: 2}}; export const {a, dummy: {b}} = obj;',
1257
parser: require.resolve('babel-eslint'),
1258
filename: testFilePath('./no-unused-modules/destructuring-b.js'),
1259
}),
1260
],
1261
invalid: [],
1262
});
1263
});
1264
1265