Path: blob/main/tests/src/rules/no-duplicates.js
829 views
import * as path from 'path';1import { test as testUtil, getNonDefaultParsers } from '../utils';23import { RuleTester } from 'eslint';4import eslintPkg from 'eslint/package.json';5import semver from 'semver';67const ruleTester = new RuleTester();8const rule = require('rules/no-duplicates');910// autofix only possible with eslint 4+11const test = semver.satisfies(eslintPkg.version, '< 4')12? t => testUtil(Object.assign({}, t, { output: t.code }))13: testUtil;1415ruleTester.run('no-duplicates', rule, {16valid: [17test({ code: 'import "./malformed.js"' }),1819test({ code: "import { x } from './foo'; import { y } from './bar'" }),2021// #86: every unresolved module should not show up as 'null' and duplicate22test({ code: 'import foo from "234artaf";' +23'import { shoop } from "234q25ad"' }),2425// #225: ignore duplicate if is a flow type import26test({27code: "import { x } from './foo'; import type { y } from './foo'",28parser: require.resolve('babel-eslint'),29}),3031// #1107: Using different query strings that trigger different webpack loaders.32test({33code: "import x from './bar?optionX'; import y from './bar?optionY';",34options: [{ 'considerQueryString': true }],35settings: { 'import/resolver': 'webpack' },36}),37test({38code: "import x from './foo'; import y from './bar';",39options: [{ 'considerQueryString': true }],40settings: { 'import/resolver': 'webpack' },41}),4243// #1538: It is impossible to import namespace and other in one line, so allow this.44test({45code: "import * as ns from './foo'; import {y} from './foo'",46}),47test({48code: "import {y} from './foo'; import * as ns from './foo'",49}),50],51invalid: [52test({53code: "import { x } from './foo'; import { y } from './foo'",54output: "import { x , y } from './foo'; ",55errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],56}),5758test({59code: "import {x} from './foo'; import {y} from './foo'; import { z } from './foo'",60output: "import {x,y, z } from './foo'; ",61errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],62}),6364// ensure resolved path results in warnings65test({66code: "import { x } from './bar'; import { y } from 'bar';",67output: "import { x , y } from './bar'; ",68settings: { 'import/resolve': {69paths: [path.join( process.cwd()70, 'tests', 'files',71)] } },72errors: 2, // path ends up hardcoded73}),7475// #1107: Using different query strings that trigger different webpack loaders.76test({77code: "import x from './bar.js?optionX'; import y from './bar?optionX';",78settings: { 'import/resolver': 'webpack' },79errors: 2, // path ends up hardcoded80}),81test({82code: "import x from './bar?optionX'; import y from './bar?optionY';",83settings: { 'import/resolver': 'webpack' },84errors: 2, // path ends up hardcoded85}),8687// #1107: Using same query strings that trigger the same loader.88test({89code: "import x from './bar?optionX'; import y from './bar.js?optionX';",90options: [{ 'considerQueryString': true }],91settings: { 'import/resolver': 'webpack' },92errors: 2, // path ends up hardcoded93}),9495// #86: duplicate unresolved modules should be flagged96test({97code: "import foo from 'non-existent'; import bar from 'non-existent';",98// Autofix bail because of different default import names.99output: "import foo from 'non-existent'; import bar from 'non-existent';",100errors: [101"'non-existent' imported multiple times.",102"'non-existent' imported multiple times.",103],104}),105106test({107code: "import type { x } from './foo'; import type { y } from './foo'",108output: "import type { x , y } from './foo'; ",109parser: require.resolve('babel-eslint'),110errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],111}),112113test({114code: "import './foo'; import './foo'",115output: "import './foo'; ",116errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],117}),118119test({120code: "import { x, /* x */ } from './foo'; import {//y\ny//y2\n} from './foo'",121output: "import { x, /* x */ //y\ny//y2\n} from './foo'; ",122errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],123}),124125test({126code: "import {x} from './foo'; import {} from './foo'",127output: "import {x} from './foo'; ",128errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],129}),130131test({132code: "import {x} from './foo'; import {} from './foo'; import {/*c*/} from './foo'; import {y} from './foo'",133output: "import {x/*c*/,y} from './foo'; ",134errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],135}),136137test({138code: "import { } from './foo'; import {x} from './foo'",139output: "import { x} from './foo'; ",140errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],141}),142143test({144code: "import './foo'; import {x} from './foo'",145output: "import {x} from './foo'; ",146errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],147}),148149test({150code: "import'./foo'; import {x} from './foo'",151output: "import {x} from'./foo'; ",152errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],153}),154155test({156code: "import './foo'; import { /*x*/} from './foo'; import {//y\n} from './foo'; import {z} from './foo'",157output: "import { /*x*///y\nz} from './foo'; ",158errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],159}),160161test({162code: "import './foo'; import def, {x} from './foo'",163output: "import def, {x} from './foo'; ",164errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],165}),166167test({168code: "import './foo'; import def from './foo'",169output: "import def from './foo'; ",170errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],171}),172173test({174code: "import def from './foo'; import {x} from './foo'",175output: "import def, {x} from './foo'; ",176errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],177}),178179test({180code: "import {x} from './foo'; import def from './foo'",181output: "import def, {x} from './foo'; ",182errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],183}),184185test({186code: "import{x} from './foo'; import def from './foo'",187output: "import def,{x} from './foo'; ",188errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],189}),190191test({192code: "import {x} from './foo'; import def, {y} from './foo'",193output: "import def, {x,y} from './foo'; ",194errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],195}),196197test({198code: "import * as ns1 from './foo'; import * as ns2 from './foo'",199// Autofix bail because cannot merge namespace imports.200output: "import * as ns1 from './foo'; import * as ns2 from './foo'",201errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],202}),203204test({205code: "import * as ns from './foo'; import {x} from './foo'; import {y} from './foo'",206// Autofix could merge some imports, but not the namespace import.207output: "import * as ns from './foo'; import {x,y} from './foo'; ",208errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],209}),210211test({212code: "import {x} from './foo'; import * as ns from './foo'; import {y} from './foo'; import './foo'",213// Autofix could merge some imports, but not the namespace import.214output: "import {x,y} from './foo'; import * as ns from './foo'; ",215errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],216}),217218test({219code: `220// some-tool-disable-next-line221import {x} from './foo'222import {//y\ny} from './foo'223`,224// Autofix bail because of comment.225output: `226// some-tool-disable-next-line227import {x} from './foo'228import {//y\ny} from './foo'229`,230errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],231}),232233test({234code: `235import {x} from './foo'236// some-tool-disable-next-line237import {y} from './foo'238`,239// Autofix bail because of comment.240output: `241import {x} from './foo'242// some-tool-disable-next-line243import {y} from './foo'244`,245errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],246}),247248test({249code: `250import {x} from './foo' // some-tool-disable-line251import {y} from './foo'252`,253// Autofix bail because of comment.254output: `255import {x} from './foo' // some-tool-disable-line256import {y} from './foo'257`,258errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],259}),260261test({262code: `263import {x} from './foo'264import {y} from './foo' // some-tool-disable-line265`,266// Autofix bail because of comment.267output: `268import {x} from './foo'269import {y} from './foo' // some-tool-disable-line270`,271errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],272}),273274test({275code: `276import {x} from './foo'277/* comment */ import {y} from './foo'278`,279// Autofix bail because of comment.280output: `281import {x} from './foo'282/* comment */ import {y} from './foo'283`,284errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],285}),286287test({288code: `289import {x} from './foo'290import {y} from './foo' /* comment291multiline */292`,293// Autofix bail because of comment.294output: `295import {x} from './foo'296import {y} from './foo' /* comment297multiline */298`,299errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],300}),301302test({303code: `304import {x} from './foo'305import {y} from './foo'306// some-tool-disable-next-line307`,308// Not autofix bail.309output: `310import {x,y} from './foo'311// some-tool-disable-next-line312`,313errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],314}),315316test({317code: `318import {x} from './foo'319// comment320321import {y} from './foo'322`,323// Not autofix bail.324output: `325import {x,y} from './foo'326// comment327328`,329errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],330}),331332test({333code: `334import {x} from './foo'335import/* comment */{y} from './foo'336`,337// Autofix bail because of comment.338output: `339import {x} from './foo'340import/* comment */{y} from './foo'341`,342errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],343}),344345test({346code: `347import {x} from './foo'348import/* comment */'./foo'349`,350// Autofix bail because of comment.351output: `352import {x} from './foo'353import/* comment */'./foo'354`,355errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],356}),357358test({359code: `360import {x} from './foo'361import{y}/* comment */from './foo'362`,363// Autofix bail because of comment.364output: `365import {x} from './foo'366import{y}/* comment */from './foo'367`,368errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],369}),370371test({372code: `373import {x} from './foo'374import{y}from/* comment */'./foo'375`,376// Autofix bail because of comment.377output: `378import {x} from './foo'379import{y}from/* comment */'./foo'380`,381errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],382}),383384test({385code: `386import {x} from387// some-tool-disable-next-line388'./foo'389import {y} from './foo'390`,391// Autofix bail because of comment.392output: `393import {x} from394// some-tool-disable-next-line395'./foo'396import {y} from './foo'397`,398errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],399}),400401// #2027 long import list generate empty lines402test({403code: "import { Foo } from './foo';\nimport { Bar } from './foo';\nexport const value = {}",404output: "import { Foo , Bar } from './foo';\nexport const value = {}",405errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],406}),407408// #2027 long import list generate empty lines409test({410code: "import { Foo } from './foo';\nimport Bar from './foo';\nexport const value = {}",411output: "import Bar, { Foo } from './foo';\nexport const value = {}",412errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],413}),414],415});416417context('TypeScript', function () {418getNonDefaultParsers()419// Type-only imports were added in TypeScript ESTree 2.23.0420.filter((parser) => parser !== require.resolve('typescript-eslint-parser'))421.forEach((parser) => {422const parserConfig = {423parser,424settings: {425'import/parsers': { [parser]: ['.ts'] },426'import/resolver': { 'eslint-import-resolver-typescript': true },427},428};429430ruleTester.run('no-duplicates', rule, {431valid: [432// #1667: ignore duplicate if is a typescript type import433test({434code: "import type { x } from './foo'; import y from './foo'",435...parserConfig,436}),437test({438code: "import type x from './foo'; import type y from './bar'",439...parserConfig,440}),441test({442code: "import type {x} from './foo'; import type {y} from './bar'",443...parserConfig,444}),445test({446code: "import type x from './foo'; import type {y} from './foo'",447...parserConfig,448}),449test({450code: `451import type {} from './module';452import {} from './module2';453`,454...parserConfig,455}),456],457invalid: [458test({459code: "import type x from './foo'; import type y from './foo'",460...parserConfig,461errors: [462{463line: 1,464column: 20,465message: "'./foo' imported multiple times.",466},467{468line: 1,469column: 48,470message: "'./foo' imported multiple times.",471},472],473}),474test({475code: "import type x from './foo'; import type x from './foo'",476output: "import type x from './foo'; ",477...parserConfig,478errors: [479{480line: 1,481column: 20,482message: "'./foo' imported multiple times.",483},484{485line: 1,486column: 48,487message: "'./foo' imported multiple times.",488},489],490}),491test({492code: "import type {x} from './foo'; import type {y} from './foo'",493...parserConfig,494output: `import type {x,y} from './foo'; `,495errors: [496{497line: 1,498column: 22,499message: "'./foo' imported multiple times.",500},501{502line: 1,503column: 52,504message: "'./foo' imported multiple times.",505},506],507}),508],509});510});511});512513514