Skip to content

Commit b1f34a0

Browse files
rahgurungsindresorhus
authored andcommitted
Add tests to enforce some rule guidelines (#246)
1 parent 1cf673f commit b1f34a0

File tree

2 files changed

+85
-11
lines changed

2 files changed

+85
-11
lines changed

readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ Configure it in `package.json`.
5959
"ava/prefer-power-assert": "off",
6060
"ava/test-ended": "error",
6161
"ava/test-title": "error",
62-
"ava/use-t-well": "error",
6362
"ava/use-t": "error",
63+
"ava/use-t-well": "error",
6464
"ava/use-test": "error",
6565
"ava/use-true-false": "error"
6666
}
@@ -94,8 +94,8 @@ The rules will only activate in test files.
9494
- [prefer-power-assert](docs/rules/prefer-power-assert.md) - Allow only use of the asserts that have no [power-assert](https://github.com/power-assert-js/power-assert) alternative.
9595
- [test-ended](docs/rules/test-ended.md) - Ensure callback tests are explicitly ended.
9696
- [test-title](docs/rules/test-title.md) - Ensure tests have a title.
97-
- [use-t-well](docs/rules/use-t-well.md) - Prevent the incorrect use of `t`. *(partly fixable)*
9897
- [use-t](docs/rules/use-t.md) - Ensure test functions use `t` as their parameter.
98+
- [use-t-well](docs/rules/use-t-well.md) - Prevent the incorrect use of `t`. *(partly fixable)*
9999
- [use-test](docs/rules/use-test.md) - Ensure that AVA is imported with `test` as the variable name.
100100
- [use-true-false](docs/rules/use-true-false.md) - Ensure that `t.true()`/`t.false()` are used instead of `t.truthy()`/`t.falsy()`.
101101

test/package.js

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,94 @@ import test from 'ava';
44
import pify from 'pify';
55
import index from '..';
66

7-
test('Every rule is defined in index file', async t => {
8-
const ruleDir = path.resolve(__dirname, '../rules');
9-
const files = await pify(fs.readdir)(ruleDir);
7+
let ruleFiles;
108

11-
const rules = files.filter(file =>
12-
file.indexOf('.js') === file.length - 3 &&
13-
!fs.readFileSync(path.join(ruleDir, file), 'utf8').includes('deprecated: true'));
9+
test.before(async () => {
10+
const files = await pify(fs.readdir)('rules');
11+
ruleFiles = files.filter(file => path.extname(file) === '.js');
12+
});
13+
14+
const testSorted = (t, actualOrder, sourceName) => {
15+
const sortedOrder = actualOrder.slice(0).sort();
16+
17+
for (const [wantedIndex, name] of sortedOrder.entries()) {
18+
const actualIndex = actualOrder.indexOf(name);
19+
const whereMessage = (wantedIndex === 0) ? '' : `, after '${sortedOrder[wantedIndex - 1]}'`;
20+
t.is(actualIndex, wantedIndex, `${sourceName} should be alphabetically sorted, '${name}' should be placed at index ${wantedIndex}${whereMessage}`);
21+
}
22+
};
23+
24+
test('Every rule is defined in index file in alphabetical order', t => {
25+
for (const file of ruleFiles) {
26+
const name = path.basename(file, '.js');
27+
28+
// Ignoring tests for no-ignored-test-files
29+
if (name === 'no-ignored-test-files') {
30+
return;
31+
}
1432

15-
for (const file of rules) {
16-
const name = file.slice(0, -3);
1733
t.truthy(index.rules[name], `'${name}' is not exported in 'index.js'`);
1834
t.truthy(index.configs.recommended.rules[`ava/${name}`], `'${name}' is not set in the recommended config`);
35+
t.truthy(fs.existsSync(path.join('docs/rules', `${name}.md`)), `There is no documentation for '${name}'`);
36+
t.truthy(fs.existsSync(path.join('test', file)), `There are no tests for '${name}'`);
1937
}
2038

21-
t.is(Object.keys(index.configs.recommended.rules).length, rules.length,
39+
t.is(Object.keys(index.rules).length, ruleFiles.length,
40+
'There are more exported rules than rule files.');
41+
t.is(Object.keys(index.configs.recommended.rules).length, ruleFiles.length,
2242
'There are more exported rules in the recommended config than rule files.');
43+
44+
testSorted(t, Object.keys(index.configs.recommended.rules), 'configs.recommended.rules');
45+
});
46+
47+
test('Every rule is defined in readme.md usage and list of rules in alphabetical order', async t => {
48+
const readme = await pify(fs.readFile)('readme.md', 'utf8');
49+
let usageRules;
50+
try {
51+
const usageRulesMatch = /## Usage.*?"rules": (\{.*?\})/ms.exec(readme);
52+
t.truthy(usageRulesMatch, 'List of rules should be defined in readme.md ## Usage');
53+
usageRules = JSON.parse(usageRulesMatch[1]);
54+
} catch (_) {}
55+
56+
t.truthy(usageRules, 'List of rules should be defined in readme.md ## Usage and be valid JSON');
57+
58+
const rulesMatch = /## Rules(.*?)## Recommended config/ms.exec(readme);
59+
t.truthy(rulesMatch, 'List of rules should be defined in readme.md in ## Rules before ## Recommended config');
60+
const rulesText = rulesMatch[1];
61+
const re = /- \[(.*?)\]\((.*?)\) - (.*)\n/gm;
62+
const rules = [];
63+
let match;
64+
do {
65+
match = re.exec(rulesText);
66+
if (match) {
67+
t.is(match[2], `docs/rules/${match[1]}.md`, `${match[1]} link to docs should be correct`);
68+
t.true(match[3].trim().length > 0, `${match[1]} should have description in readme.md ## Rules`);
69+
rules.push(match[1]);
70+
}
71+
} while (match);
72+
73+
for (const file of ruleFiles) {
74+
const name = path.basename(file, '.js');
75+
t.truthy(usageRules[`ava/${name}`], `'${name}' is not described in the readme.md ## Usage`);
76+
t.truthy(rules.includes(name), `'${name}' is not described in the readme.md ## Rules`);
77+
}
78+
79+
t.is(Object.keys(usageRules).length, ruleFiles.length, 'There are more rules in readme.md ## Usage than rule files.');
80+
t.is(Object.keys(rules).length, ruleFiles.length, 'There are more rules in readme.md ## Rules than rule files.');
81+
82+
testSorted(t, Object.keys(usageRules), 'readme.md ## Usage rules');
83+
testSorted(t, rules, 'readme.md ## Rules');
84+
});
85+
86+
test('Every rule has valid meta.type', t => {
87+
const validTypes = ['problem', 'suggestion', 'layout'];
88+
89+
for (const file of ruleFiles) {
90+
const name = path.basename(file, '.js');
91+
const rule = index.rules[name];
92+
93+
t.true(rule.meta !== null && rule.meta !== undefined, `${name} has no meta`);
94+
t.is(typeof rule.meta.type, 'string', `${name} meta.type is not string`);
95+
t.true(validTypes.includes(rule.meta.type), `${name} meta.type is not one of [${validTypes.join(', ')}]`);
96+
}
2397
});

0 commit comments

Comments
 (0)