Path: blob/main/tests/src/rules/no-unresolved.js
829 views
import * as path from 'path';12import { getTSParsers, test, SYNTAX_CASES, testVersion } from '../utils';34import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve';56import { RuleTester } from 'eslint';78const ruleTester = new RuleTester();9const rule = require('rules/no-unresolved');1011function runResolverTests(resolver) {12// redefine 'test' to set a resolver13// thus 'rest'. needed something 4-chars-long for formatting simplicity14function rest(specs) {15specs.settings = Object.assign({},16specs.settings,17{ 'import/resolver': resolver, 'import/cache': { lifetime: 0 } },18);1920return test(specs);21}2223ruleTester.run(`no-unresolved (${resolver})`, rule, {24valid: [].concat(25test({ code: 'import "./malformed.js"' }),2627rest({ code: 'import foo from "./bar";' }),28rest({ code: "import bar from './bar.js';" }),29rest({ code: "import {someThing} from './test-module';" }),30rest({ code: "import fs from 'fs';" }),31rest({ code: "import('fs');",32parser: require.resolve('babel-eslint') }),3334// check with eslint parser35testVersion('>= 7', () => rest({36code: "import('fs');",37parserOptions: { ecmaVersion: 2021 },38})) || [],3940rest({ code: 'import * as foo from "a"' }),4142rest({ code: 'export { foo } from "./bar"' }),43rest({ code: 'export * from "./bar"' }),44rest({ code: 'let foo; export { foo }' }),4546// stage 1 proposal for export symmetry,47rest({ code: 'export * as bar from "./bar"',48parser: require.resolve('babel-eslint') }),49rest({ code: 'export bar from "./bar"',50parser: require.resolve('babel-eslint') }),51rest({ code: 'import foo from "./jsx/MyUnCoolComponent.jsx"' }),5253// commonjs setting54rest({ code: 'var foo = require("./bar")',55options: [{ commonjs: true }] }),56rest({ code: 'require("./bar")',57options: [{ commonjs: true }] }),58rest({ code: 'require("./does-not-exist")',59options: [{ commonjs: false }] }),60rest({ code: 'require("./does-not-exist")' }),6162// amd setting63rest({ code: 'require(["./bar"], function (bar) {})',64options: [{ amd: true }] }),65rest({ code: 'define(["./bar"], function (bar) {})',66options: [{ amd: true }] }),67rest({ code: 'require(["./does-not-exist"], function (bar) {})',68options: [{ amd: false }] }),69// magic modules: https://git.io/vByan70rest({ code: 'define(["require", "exports", "module"], function (r, e, m) { })',71options: [{ amd: true }] }),7273// don't validate without callback param74rest({ code: 'require(["./does-not-exist"])',75options: [{ amd: true }] }),76rest({ code: 'define(["./does-not-exist"], function (bar) {})' }),7778// stress tests79rest({ code: 'require("./does-not-exist", "another arg")',80options: [{ commonjs: true, amd: true }] }),81rest({ code: 'proxyquire("./does-not-exist")',82options: [{ commonjs: true, amd: true }] }),83rest({ code: '(function() {})("./does-not-exist")',84options: [{ commonjs: true, amd: true }] }),85rest({ code: 'define([0, foo], function (bar) {})',86options: [{ amd: true }] }),87rest({ code: 'require(0)',88options: [{ commonjs: true }] }),89rest({ code: 'require(foo)',90options: [{ commonjs: true }] }),91),9293invalid: [].concat(94rest({95code: 'import reallyfake from "./reallyfake/module"',96settings: { 'import/ignore': ['^\\./fake/'] },97errors: [{ message: 'Unable to resolve path to module ' +98'\'./reallyfake/module\'.' }],99}),100101rest({102code: "import bar from './baz';",103errors: [{ message: "Unable to resolve path to module './baz'.",104type: 'Literal' }],105}),106rest({ code: "import bar from './baz';",107errors: [{ message: "Unable to resolve path to module './baz'.",108type: 'Literal',109}] }),110rest({111code: "import bar from './empty-folder';",112errors: [{ message: "Unable to resolve path to module './empty-folder'.",113type: 'Literal',114}] }),115116// sanity check that this module is _not_ found without proper settings117rest({118code: "import { DEEP } from 'in-alternate-root';",119errors: [{ message: 'Unable to resolve path to ' +120"module 'in-alternate-root'.",121type: 'Literal',122}] }),123rest({124code: "import('in-alternate-root').then(function({DEEP}) {});",125errors: [{126message: 'Unable to resolve path to module \'in-alternate-root\'.',127type: 'Literal',128}],129parser: require.resolve('babel-eslint') }),130131rest({ code: 'export { foo } from "./does-not-exist"',132errors: ["Unable to resolve path to module './does-not-exist'."] }),133rest({134code: 'export * from "./does-not-exist"',135errors: ["Unable to resolve path to module './does-not-exist'."],136}),137138// check with eslint parser139testVersion('>= 7', () => rest({140code: "import('in-alternate-root').then(function({DEEP}) {});",141errors: [{142message: 'Unable to resolve path to module \'in-alternate-root\'.',143type: 'Literal',144}],145parserOptions: { ecmaVersion: 2021 },146})) || [],147148// export symmetry proposal149rest({ code: 'export * as bar from "./does-not-exist"',150parser: require.resolve('babel-eslint'),151errors: ["Unable to resolve path to module './does-not-exist'."],152}),153rest({ code: 'export bar from "./does-not-exist"',154parser: require.resolve('babel-eslint'),155errors: ["Unable to resolve path to module './does-not-exist'."],156}),157158// commonjs setting159rest({160code: 'var bar = require("./baz")',161options: [{ commonjs: true }],162errors: [{163message: "Unable to resolve path to module './baz'.",164type: 'Literal',165}],166}),167rest({168code: 'require("./baz")',169options: [{ commonjs: true }],170errors: [{171message: "Unable to resolve path to module './baz'.",172type: 'Literal',173}],174}),175176// amd177rest({178code: 'require(["./baz"], function (bar) {})',179options: [{ amd: true }],180errors: [{181message: "Unable to resolve path to module './baz'.",182type: 'Literal',183}],184}),185rest({186code: 'define(["./baz"], function (bar) {})',187options: [{ amd: true }],188errors: [{189message: "Unable to resolve path to module './baz'.",190type: 'Literal',191}],192}),193rest({194code: 'define(["./baz", "./bar", "./does-not-exist"], function (bar) {})',195options: [{ amd: true }],196errors: [{197message: "Unable to resolve path to module './baz'.",198type: 'Literal',199},{200message: "Unable to resolve path to module './does-not-exist'.",201type: 'Literal',202}],203}),204),205});206207ruleTester.run(`issue #333 (${resolver})`, rule, {208valid: [209rest({ code: 'import foo from "./bar.json"' }),210rest({ code: 'import foo from "./bar"' }),211rest({212code: 'import foo from "./bar.json"',213settings: { 'import/extensions': ['.js'] },214}),215rest({216code: 'import foo from "./bar"',217settings: { 'import/extensions': ['.js'] },218}),219],220invalid: [221rest({222code: 'import bar from "./foo.json"',223errors: ["Unable to resolve path to module './foo.json'."],224}),225],226});227228if (!CASE_SENSITIVE_FS) {229const relativePath = './tests/files/jsx/MyUnCoolComponent.jsx';230const cwd = process.cwd();231const mismatchedPath = path.join(cwd.toUpperCase(), relativePath).replace(/\\/g, '/');232233ruleTester.run('case sensitivity', rule, {234valid: [235rest({ // test with explicit flag236code: 'import foo from "./jsx/MyUncoolComponent.jsx"',237options: [{ caseSensitive: false }],238}),239],240241invalid: [242rest({ // test default243code: 'import foo from "./jsx/MyUncoolComponent.jsx"',244errors: [`Casing of ./jsx/MyUncoolComponent.jsx does not match the underlying filesystem.`],245}),246rest({ // test with explicit flag247code: 'import foo from "./jsx/MyUncoolComponent.jsx"',248options: [{ caseSensitive: true }],249errors: [`Casing of ./jsx/MyUncoolComponent.jsx does not match the underlying filesystem.`],250}),251],252});253254ruleTester.run('case sensitivity strict', rule, {255valid: [256// #1259 issue257rest({ // caseSensitiveStrict is disabled by default258code: `import foo from "${mismatchedPath}"`,259}),260],261262invalid: [263// #1259 issue264rest({ // test with enabled caseSensitiveStrict option265code: `import foo from "${mismatchedPath}"`,266options: [{ caseSensitiveStrict: true }],267errors: [`Casing of ${mismatchedPath} does not match the underlying filesystem.`],268}),269rest({ // test with enabled caseSensitiveStrict option and disabled caseSensitive270code: `import foo from "${mismatchedPath}"`,271options: [{ caseSensitiveStrict: true, caseSensitive: false }],272errors: [`Casing of ${mismatchedPath} does not match the underlying filesystem.`],273}),274],275});276}277278}279280['node', 'webpack'].forEach(runResolverTests);281282ruleTester.run('no-unresolved (import/resolve legacy)', rule, {283valid: [284test({285code: "import { DEEP } from 'in-alternate-root';",286settings: {287'import/resolve': {288'paths': [path.join( process.cwd()289, 'tests', 'files', 'alternate-root')],290},291},292}),293294test({295code: "import { DEEP } from 'in-alternate-root'; " +296"import { bar } from 'src-bar';",297settings: { 'import/resolve': { 'paths': [298path.join('tests', 'files', 'src-root'),299path.join('tests', 'files', 'alternate-root'),300] } } }),301302test({303code: 'import * as foo from "jsx-module/foo"',304settings: { 'import/resolve': { 'extensions': ['.jsx'] } },305}),306],307308invalid: [309test({310code: 'import * as foo from "jsx-module/foo"',311errors: [ "Unable to resolve path to module 'jsx-module/foo'." ],312}),313],314});315316ruleTester.run('no-unresolved (webpack-specific)', rule, {317valid: [318test({319// default webpack config in files/webpack.config.js knows about jsx320code: 'import * as foo from "jsx-module/foo"',321settings: { 'import/resolver': 'webpack' },322}),323test({324// should ignore loaders325code: 'import * as foo from "some-loader?with=args!jsx-module/foo"',326settings: { 'import/resolver': 'webpack' },327}),328],329invalid: [330test({331// default webpack config in files/webpack.config.js knows about jsx332code: 'import * as foo from "jsx-module/foo"',333settings: {334'import/resolver': { 'webpack': { 'config': 'webpack.empty.config.js' } },335},336errors: [ "Unable to resolve path to module 'jsx-module/foo'." ],337}),338],339});340341342ruleTester.run('no-unresolved ignore list', rule, {343valid: [344test({345code: 'import "./malformed.js"',346options: [{ ignore: ['.png$', '.gif$'] }],347}),348test({349code: 'import "./test.giffy"',350options: [{ ignore: ['.png$', '.gif$'] }],351}),352353test({354code: 'import "./test.gif"',355options: [{ ignore: ['.png$', '.gif$'] }],356}),357358test({359code: 'import "./test.png"',360options: [{ ignore: ['.png$', '.gif$'] }],361}),362],363364invalid:[365test({366code: 'import "./test.gif"',367options: [{ ignore: ['.png$'] }],368errors: [ "Unable to resolve path to module './test.gif'." ],369}),370371test({372code: 'import "./test.png"',373options: [{ ignore: ['.gif$'] }],374errors: [ "Unable to resolve path to module './test.png'." ],375}),376],377});378379ruleTester.run('no-unresolved unknown resolver', rule, {380valid: [],381382invalid:[383384// logs resolver load error385test({386code: 'import "./malformed.js"',387settings: { 'import/resolver': 'doesnt-exist' },388errors: [389`Resolve error: unable to load resolver "doesnt-exist".`,390`Unable to resolve path to module './malformed.js'.`,391],392}),393394// only logs resolver message once395test({396code: 'import "./malformed.js"; import "./fake.js"',397settings: { 'import/resolver': 'doesnt-exist' },398errors: [399`Resolve error: unable to load resolver "doesnt-exist".`,400`Unable to resolve path to module './malformed.js'.`,401`Unable to resolve path to module './fake.js'.`,402],403}),404],405});406407ruleTester.run('no-unresolved electron', rule, {408valid: [409test({410code: 'import "electron"',411settings: { 'import/core-modules': ['electron'] },412}),413],414invalid:[415test({416code: 'import "electron"',417errors: [`Unable to resolve path to module 'electron'.`],418}),419],420});421422ruleTester.run('no-unresolved syntax verification', rule, {423valid: SYNTAX_CASES,424invalid:[],425});426427// https://github.com/import-js/eslint-plugin-import/issues/2024428ruleTester.run('import() with built-in parser', rule, {429valid: [].concat(430testVersion('>=7', () => ({431code: "import('fs');",432parserOptions: { ecmaVersion: 2021 },433})) || [],434),435invalid: [].concat(436testVersion('>=7', () => ({437code: 'import("./does-not-exist-l0w9ssmcqy9").then(() => {})',438parserOptions: { ecmaVersion: 2021 },439errors: ["Unable to resolve path to module './does-not-exist-l0w9ssmcqy9'."],440})) || [],441),442});443444context('TypeScript', () => {445// Type-only imports were added in TypeScript ESTree 2.23.0446getTSParsers().filter(x => x !== require.resolve('typescript-eslint-parser')).forEach((parser) => {447ruleTester.run(`${parser}: no-unresolved ignore type-only`, rule, {448valid: [449test({450code: 'import type { JSONSchema7Type } from "@types/json-schema";',451parser,452}),453],454invalid: [455test({456code: 'import { JSONSchema7Type } from "@types/json-schema";',457errors: [ "Unable to resolve path to module '@types/json-schema'." ],458parser,459}),460],461});462});463});464465466