Skip to content

Commit 1cf673f

Browse files
Make the no-import-test rule take into account AVA extensions and babel config (#225)
Co-authored-by: Sindre Sorhus <[email protected]>
1 parent 5bdf745 commit 1cf673f

File tree

4 files changed

+81
-16
lines changed

4 files changed

+81
-16
lines changed

docs/rules/no-import-test-files.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This rule will verify that you don't import any test files. It will consider the
66

77
Note that this rule will not be able to warn correctly if you use AVA by specifying the files in the command line ( `ava "lib/**/*.test.js"` ). Prefer configuring AVA as described [here](https://github.com/avajs/ava/blob/master/docs/06-configuration.md).
88

9+
910
## Fail
1011

1112
```js
@@ -26,16 +27,28 @@ test('foo', t => {
2627

2728
```js
2829
// File: utils/index.js
29-
// with { "files": ["lib/**/*.test.js", "utils/**/*.test.js"] }
30-
// in either `package.json` under 'ava key' or in the rule options
31-
// Invalid because the imported file matches lib/**/*.test.js
30+
// with `{"files": ["lib/**/*.test.js", "utils/**/*.test.js"]}`
31+
// in either `package.json` under the `"ava"` key or in the rule options
32+
// Invalid because the imported file matches `lib/**/*.test.js`
3233
import tests from '../lib/index.test.js';
3334

3435
test('foo', t => {
3536
t.pass();
3637
});
3738
```
3839

40+
```js
41+
// File: utils/index.js
42+
// with `{"extensions": ["js", "mjs"]}`
43+
// in either `package.json` under the `"ava"` key or in the rule options
44+
// Invalid because the imported file extension matches `mjs`
45+
import tests from 'index.test.mjs';
46+
47+
test('foo', t => {
48+
t.pass();
49+
});
50+
```
51+
3952

4053
## Pass
4154

@@ -52,11 +65,19 @@ import utils from './utils';
5265

5366
```js
5467
// File: lib/index.js
55-
// with { "files": ["lib/**/*.test.js", "utils/**/*.test.js"] }
68+
// with `{"files": ["lib/**/*.test.js", "utils/**/*.test.js"]}`
5669
// in either `package.json` under 'ava key' or in the rule options
57-
import utils from '../utils/index.js';
70+
import utils from 'test.js';
5871
```
5972

73+
```js
74+
// File: lib/index.js
75+
// `with {"extensions": ["js", "mjs"]}`
76+
// in either `package.json` under 'ava key' or in the rule options
77+
import utils from 'test.jsx';
78+
```
79+
80+
6081
## Options
6182

6283
This rule supports the following options:
@@ -65,6 +86,24 @@ This rule supports the following options:
6586

6687
You can set the options like this:
6788

68-
```js
89+
```json
6990
"ava/no-ignored-test-files": ["error", {"files": ["lib/**/*.test.js", "utils/**/*.test.js"]}]
7091
```
92+
93+
`extensions`: An array of strings representing the file extensions that AVA will use to find the test files. It overrides the default and the configuration found in the `package.json` or `ava.config.js` files.
94+
95+
This extension will filter out files from the `files` option.
96+
97+
You can set the options like this:
98+
99+
```json
100+
"ava/no-ignored-test-files": [
101+
"error",
102+
{
103+
"extensions": [
104+
"js",
105+
"mjs"
106+
]
107+
}
108+
]
109+
```

rules/no-import-test-files.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,28 @@ function isExternalModule(name) {
1010
return externalModuleRegExp.test(name);
1111
}
1212

13-
function isTestFile(files, rootDir, sourceFile, importedFile) {
13+
function isTestFile(files, extensions, rootDir, sourceFile, importedFile) {
1414
const absoluteImportedPath = path.resolve(path.dirname(sourceFile), importedFile);
1515
const relativePath = path.relative(rootDir, absoluteImportedPath);
1616

17-
return multimatch([relativePath], files).length === 1;
17+
return multimatch([relativePath], files).filter(file => {
18+
const extension = path.extname(file).slice(1);
19+
return extensions.includes(extension);
20+
}).length === 1;
1821
}
1922

2023
function getProjectInfo() {
2124
const packageFilePath = pkgUp.sync();
25+
const {files, babel} = util.getAvaConfig(packageFilePath);
2226

2327
return {
2428
rootDir: packageFilePath && path.dirname(packageFilePath),
25-
files: util.getAvaConfig(packageFilePath).files
29+
files,
30+
babel
2631
};
2732
}
2833

29-
function createImportValidator(context, files, projectInfo, filename) {
34+
function createImportValidator(context, files, extensions, projectInfo, filename) {
3035
return (node, importPath) => {
3136
if (!importPath || typeof importPath !== 'string') {
3237
return;
@@ -37,7 +42,7 @@ function createImportValidator(context, files, projectInfo, filename) {
3742
return;
3843
}
3944

40-
const isImportingTestFile = isTestFile(files, projectInfo.rootDir, filename, importPath);
45+
const isImportingTestFile = isTestFile(files, extensions, projectInfo.rootDir, filename, importPath);
4146
if (isImportingTestFile) {
4247
context.report({
4348
node,
@@ -56,14 +61,17 @@ const create = context => {
5661

5762
const projectInfo = getProjectInfo();
5863
const options = context.options[0] || {};
64+
65+
const extensions = arrify(options.extensions || (projectInfo.babel && projectInfo.babel.extensions) || util.defaultExtensions);
66+
5967
const files = arrify(options.files || projectInfo.files || util.defaultFiles);
6068

6169
if (!projectInfo.rootDir) {
6270
// Could not find a package.json folder
6371
return {};
6472
}
6573

66-
const validateImportPath = createImportValidator(context, files, projectInfo, filename);
74+
const validateImportPath = createImportValidator(context, files, extensions, projectInfo, filename);
6775

6876
return {
6977
ImportDeclaration: node => {

test/no-import-test-files.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ const toPath = subPath => path.join(rootDir, subPath);
1818

1919
util.getAvaConfig = () => ({
2020
files: [
21-
'lib/*.test.js',
21+
'lib/*.test.*',
2222
'test/**/*.js'
23-
]
23+
],
24+
babel: {
25+
extensions: [
26+
'js',
27+
'jsx'
28+
]
29+
}
2430
});
2531

2632
const errors = [
@@ -35,9 +41,11 @@ ruleTester.run('no-import-test-files', rule, {
3541
'const test = require(\'ava\');',
3642
'console.log()',
3743
'const value = require(somePath);',
38-
'var highlight = require(\'highlight.js\')',
44+
// Ok because not a valid extension
45+
'import test from \'./foo.test.mjs\';',
46+
'const highlight = require(\'highlight.js\')',
3947
{
40-
code: 'var highlight = require(\'highlight.js\')',
48+
code: 'const highlight = require(\'highlight.js\')',
4149
filename: toPath('test/index.js')
4250
},
4351
'const value = require(true);',
@@ -58,6 +66,11 @@ ruleTester.run('no-import-test-files', rule, {
5866
code: 'import test from \'./bar.js\';',
5967
filename: toPath('test/foo.js'),
6068
errors
69+
},
70+
{
71+
code: 'import test from \'./foo.test.jsx\';',
72+
filename: toPath('lib/foo.js'),
73+
errors
6174
}
6275
]
6376
});

util.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const defaultFiles = [
2222
'**/*.test.js'
2323
];
2424

25+
const defaultExtensions = [
26+
'js'
27+
];
28+
2529
exports.getRootNode = node => {
2630
if (node.object.type === 'MemberExpression') {
2731
return exports.getRootNode(node.object);
@@ -174,5 +178,6 @@ const assertionMethodNames = [...assertionMethodsNumArguments.keys()];
174178

175179
exports.assertionMethodsNumArguments = assertionMethodsNumArguments;
176180
exports.defaultFiles = defaultFiles;
181+
exports.defaultExtensions = defaultExtensions;
177182
exports.assertionMethods = new Set(assertionMethodNames);
178183
exports.executionMethods = new Set(assertionMethodNames.concat(['end', 'plan', 'log']));

0 commit comments

Comments
 (0)