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