Skip to content

Commit

Permalink
Minor refactoring for tests (#1516)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Sep 8, 2021
1 parent cddaf63 commit 7bece2a
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 92 deletions.
75 changes: 75 additions & 0 deletions test/utils/parsers.mjs
@@ -0,0 +1,75 @@
import {createRequire} from 'node:module';
import defaultParserOptions from './default-parser-options.mjs';

const require = createRequire(import.meta.url);

const babel = {
name: '@babel/eslint-parser',
get parser() {
return require.resolve(this.name);
},
mergeParserOptions(options) {
options = options || {};
options.babelOptions = options.babelOptions || {};
options.babelOptions.parserOpts = options.babelOptions.parserOpts || {};

let babelPlugins = options.babelOptions.parserOpts.plugins || [];
babelPlugins = [
['estree', {classFeatures: true}],
'jsx',
'exportDefaultFrom',
...babelPlugins,
];

return {
...defaultParserOptions,
requireConfigFile: false,
sourceType: 'module',
allowImportExportEverywhere: true,
...options,
babelOptions: {
babelrc: false,
configFile: false,
...options.babelOptions,
parserOpts: {
...options.babelOptions.parserOpts,
plugins: babelPlugins,
},
},
};
},
};

const typescript = {
name: '@typescript-eslint/parser',
get parser() {
return require.resolve(this.name);
},
mergeParserOptions(options) {
return {
...defaultParserOptions,
...options,
};
},
};

const vue = {
name: 'vue-eslint-parser',
get parser() {
return require.resolve(this.name);
},
mergeParserOptions(options) {
return {
...defaultParserOptions,
...options,
};
},
};

const parsers = {
babel,
typescript,
vue,
};

export default parsers;
150 changes: 58 additions & 92 deletions test/utils/test.mjs
@@ -1,13 +1,15 @@
import path from 'node:path';
import url from 'node:url';
import {createRequire} from 'node:module';
import test from 'ava';
import avaRuleTester from 'eslint-ava-rule-tester';
import {loadRule} from '../../rules/utils/rule.js';
import SnapshotRuleTester from './snapshot-rule-tester.mjs';
import defaultParserOptions from './default-parser-options.mjs';
import parsers from './parsers.mjs';

const require = createRequire(import.meta.url);
function normalizeTests(tests) {
return tests.map(test => typeof test === 'string' ? {code: test} : test);
}

function normalizeInvalidTest(test, rule) {
const {code, output, errors} = test;
Expand All @@ -31,17 +33,24 @@ function normalizeInvalidTest(test, rule) {
};
}

const parsers = {
get typescript() {
return require.resolve('@typescript-eslint/parser');
},
get babel() {
return require.resolve('@babel/eslint-parser');
},
get vue() {
return require.resolve('vue-eslint-parser');
},
};
function normalizeParser(options) {
const {
parser,
parserOptions,
} = options;

if (parser) {
if (parser.name) {
options.parser = parser.name;
}

if (parser.mergeParserOptions) {
options.parserOptions = parser.mergeParserOptions(parserOptions);
}
}

return options;
}

class Tester {
constructor(ruleId) {
Expand Down Expand Up @@ -70,76 +79,23 @@ class Tester {
);
}

typescript(tests) {
const {testerOptions = {}} = tests;
testerOptions.parserOptions = testerOptions.parserOptions || {};

return this.runTest({
...tests,
testerOptions: {
...testerOptions,
parser: parsers.typescript,
parserOptions: {
...defaultParserOptions,
...testerOptions.parserOptions,
},
},
});
}

babel(tests) {
const {testerOptions = {}} = tests;
testerOptions.parserOptions = testerOptions.parserOptions || {};
testerOptions.parserOptions.babelOptions = testerOptions.parserOptions.babelOptions || {};
testerOptions.parserOptions.babelOptions.parserOpts = testerOptions.parserOptions.babelOptions.parserOpts || {};
let babelPlugins = testerOptions.parserOptions.babelOptions.parserOpts.plugins || [];
babelPlugins = [
['estree', {classFeatures: true}],
'jsx',
'exportDefaultFrom',
...babelPlugins,
];

return this.runTest({
...tests,
testerOptions: {
...testerOptions,
parser: parsers.babel,
parserOptions: {
...defaultParserOptions,
requireConfigFile: false,
sourceType: 'module',
allowImportExportEverywhere: true,
...testerOptions.parserOptions,
babelOptions: {
babelrc: false,
configFile: false,
...testerOptions.parserOptions.babelOptions,
parserOpts: {
...testerOptions.parserOptions.babelOptions.parserOpts,
plugins: babelPlugins,
},
},
},
},
});
}
snapshot(tests) {
let {
testerOptions = {},
valid,
invalid,
} = tests;

vue(tests) {
return this.runTest({
...tests,
testerOptions: {
parser: parsers.vue,
parserOptions: defaultParserOptions,
},
});
}
testerOptions = normalizeParser(testerOptions);
valid = normalizeTests(valid).map(test => normalizeParser(test));
invalid = normalizeTests(invalid).map(test => normalizeParser(test));

snapshot(tests) {
const {testerOptions, valid, invalid} = tests;
const tester = new SnapshotRuleTester(test, {
parserOptions: defaultParserOptions,
...testerOptions,
parserOptions: {
...defaultParserOptions,
...testerOptions.parserOptions,
},
});
return tester.run(this.ruleId, this.rule, {valid, invalid});
}
Expand All @@ -149,24 +105,35 @@ function getTester(importMeta) {
const filename = url.fileURLToPath(importMeta.url);
const ruleId = path.basename(filename, '.mjs');
const tester = new Tester(ruleId);
const test = Tester.prototype.runTest.bind(tester);
test.typescript = Tester.prototype.typescript.bind(tester);
test.babel = Tester.prototype.babel.bind(tester);
test.vue = Tester.prototype.vue.bind(tester);
test.snapshot = Tester.prototype.snapshot.bind(tester);
const runTest = Tester.prototype.runTest.bind(tester);
runTest.snapshot = Tester.prototype.snapshot.bind(tester);

for (const [parserName, parserSettings] of Object.entries(parsers)) {
Reflect.defineProperty(runTest, parserName, {
value(tests) {
const testerOptions = tests.testerOptions || {};
const {parser, mergeParserOptions} = parserSettings;

return runTest({
...tests,
testerOptions: {
...testerOptions,
parser,
parserOptions: mergeParserOptions(testerOptions.parserOptions),
},
});
},
});
}

return {
ruleId,
rule: tester.rule,
test,
test: runTest,
};
}

const addComment = (test, comment) => {
if (typeof test === 'string') {
return `${test}\n/* ${comment} */`;
}

const {code, output} = test;
const fixedTest = {
...test,
Expand All @@ -183,13 +150,12 @@ const avoidTestTitleConflict = (tests, comment) => {
const {valid, invalid} = tests;
return {
...tests,
valid: valid.map(test => addComment(test, comment)),
invalid: invalid.map(test => addComment(test, comment)),
valid: normalizeTests(valid).map(test => addComment(test, comment)),
invalid: normalizeTests(invalid).map(test => addComment(test, comment)),
};
};

export {
defaultParserOptions,
getTester,
avoidTestTitleConflict,
parsers,
Expand Down

0 comments on commit 7bece2a

Please sign in to comment.