Skip to content

Commit

Permalink
Merge pull request #26 from levibuzolic/configurable-auto-fixing
Browse files Browse the repository at this point in the history
Disable auto-fixing by default, allow it to be configured if desired
  • Loading branch information
levibuzolic authored Apr 28, 2021
2 parents c1a2050 + 4ecbcdd commit a5c0bc6
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v2.6.0

* Disable auto fixing by default, allow it to be optionally enabled.

# v2.5.0

* Add support for auto fixing violations - #19 @tgreen7
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,21 @@ If you use a testing framework that uses an unsupported block name, or a differe
```

The above example will catch any uses of `test.only`, `test.focus`, `it.only`, `it.focus`, `assert.only` and `assert.focus`.

This rule supports autofixing only when the `fix` option is set to `true` to avoid changing runtime code unintentionally when configured in an editor.

```json
{
"rules": {
"no-only-tests/no-only-tests": ["error", {"fix": true}]
}
}
```

## Options

Option | Type | Description
---|---|---
`block` | `Array<string>` | Specify the block names that your testing framework uses. Defaults to `["describe", "it", "context", "test", "tape", "fixture", "serial"]`
`focus` | `Array<string>` | Specify the focus scope that your testing framework uses. Defaults to `["only"]`
`fix` | `boolean` | Enable this rule to auto-fix violations, useful for a pre-commit hook, not recommended for users with auto-fixing enabled in their editor. Defaults to `false`
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-no-only-tests",
"version": "2.5.0",
"version": "2.6.0",
"description": "ESLint rule for .only blocks in mocha tests",
"keywords": [
"eslint",
Expand Down
26 changes: 13 additions & 13 deletions rules/no-only-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ module.exports = {
},
uniqueItems: true,
},
fix: {
type: 'boolean',
},
},
additionalProperties: false,
},
Expand All @@ -47,42 +50,39 @@ module.exports = {
create(context) {
var block = (context.options[0] || {}).block || BLOCK_DEFAULTS;
var focus = (context.options[0] || {}).focus || FOCUS_DEFAULTS;
var fix = !!(context.options[0] || {}).fix;

return {
Identifier(node) {
var parentObject = node.parent && node.parent.object;
if (parentObject == null) return;
if (focus.indexOf(node.name) === -1) return;

var callPath = getCallPath(node.parent).join('.')

function fix(fixer) {
return fixer.removeRange([node.range[0] - 1, node.range[1]]);
}
var callPath = getCallPath(node.parent).join('.');

// comparison guarantees that matching is done with the beginning of call path
if (block.find((b) => callPath.split(b)[0] === '')) {
if (block.find(b => callPath.split(b)[0] === '')) {
context.report({
node,
message: callPath + ' not permitted',
fix
fix: fix ? fixer => fixer.removeRange([node.range[0] - 1, node.range[1]]) : undefined,
});
}
},
};
},
};

function getCallPath (node, path = []) {
function getCallPath(node, path = []) {
if (node) {
const nodeName = node.name || (node.property && node.property.name)
const nodeName = node.name || (node.property && node.property.name);
if (node.object) {
return getCallPath(node.object, [nodeName, ...path])
return getCallPath(node.object, [nodeName, ...path]);
}
if (node.callee) {
return getCallPath(node.callee, path)
return getCallPath(node.callee, path);
}
return [nodeName, ...path]
return [nodeName, ...path];
}
return path
return path;
}
77 changes: 72 additions & 5 deletions tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,58 +28,125 @@ ruleTester.run('no-only-tests', rules['no-only-tests'], {
invalid: [
{
code: 'describe.only("Some describe block", function() {});',
output: 'describe.only("Some describe block", function() {});',
errors: [{message: 'describe.only not permitted'}],
output: 'describe("Some describe block", function() {});'
},
{
code: 'it.only("Some assertion", function() {});',
output: 'it.only("Some assertion", function() {});',
errors: [{message: 'it.only not permitted'}],
},
{
code: 'context.only("Some context", function() {});',
output: 'context.only("Some context", function() {});',
errors: [{message: 'context.only not permitted'}],
},
{
code: 'test.only("Some test", function() {});',
output: 'test.only("Some test", function() {});',
errors: [{message: 'test.only not permitted'}],
},
{
code: 'tape.only("A tape", function() {});',
output: 'tape.only("A tape", function() {});',
errors: [{message: 'tape.only not permitted'}],
},
{
code: 'fixture.only("A fixture", function() {});',
output: 'fixture.only("A fixture", function() {});',
errors: [{message: 'fixture.only not permitted'}],
},
{
code: 'serial.only("A serial test", function() {});',
output: 'serial.only("A serial test", function() {});',
errors: [{message: 'serial.only not permitted'}],
},
{
options: [{block: ['obscureTestBlock']}],
code: 'obscureTestBlock.only("An obscure testing library test", function() {});',
output: 'obscureTestBlock.only("An obscure testing library test", function() {});',
errors: [{message: 'obscureTestBlock.only not permitted'}],
},
{
options: [{block: ['ava.default']}],
code: 'ava.default.only("Block with dot", function() {});',
output: 'ava.default.only("Block with dot", function() {});',
errors: [{message: 'ava.default.only not permitted'}],
},
{
code: 'it.default.before(console.log).only("Some describe block", function() {});',
output: 'it.default.before(console.log).only("Some describe block", function() {});',
errors: [{message: 'it.default.before.only not permitted'}],
},
{
options: [{focus: ['focus']}],
code: 'test.focus("An alternative focus function", function() {});',
output: 'test.focus("An alternative focus function", function() {});',
errors: [{message: 'test.focus not permitted'}],
},
// As above, but with fix: true option to enable auto-fixing
{
options: [{fix: true}],
code: 'describe.only("Some describe block", function() {});',
output: 'describe("Some describe block", function() {});',
errors: [{message: 'describe.only not permitted'}],
},
{
options: [{fix: true}],
code: 'it.only("Some assertion", function() {});',
output: 'it("Some assertion", function() {});',
errors: [{message: 'it.only not permitted'}],
},
{
options: [{fix: true}],
code: 'context.only("Some context", function() {});',
output: 'context("Some context", function() {});',
errors: [{message: 'context.only not permitted'}],
},
{
options: [{fix: true}],
code: 'test.only("Some test", function() {});',
output: 'test("Some test", function() {});',
errors: [{message: 'test.only not permitted'}],
},
{
options: [{fix: true}],
code: 'tape.only("A tape", function() {});',
output: 'tape("A tape", function() {});',
errors: [{message: 'tape.only not permitted'}],
},
{
options: [{fix: true}],
code: 'fixture.only("A fixture", function() {});',
output: 'fixture("A fixture", function() {});',
errors: [{message: 'fixture.only not permitted'}],
},
{
options: [{fix: true}],
code: 'serial.only("A serial test", function() {});',
output: 'serial("A serial test", function() {});',
errors: [{message: 'serial.only not permitted'}],
},
{
options: [{block: ['obscureTestBlock']}],
options: [{block: ['obscureTestBlock'], fix: true}],
code: 'obscureTestBlock.only("An obscure testing library test", function() {});',
output: 'obscureTestBlock("An obscure testing library test", function() {});',
errors: [{message: 'obscureTestBlock.only not permitted'}],
},
{
options: [{block: ['ava.default']}],
options: [{block: ['ava.default'], fix: true}],
code: 'ava.default.only("Block with dot", function() {});',
output: 'ava.default("Block with dot", function() {});',
errors: [{message: 'ava.default.only not permitted'}],
},
{
options: [{fix: true}],
code: 'it.default.before(console.log).only("Some describe block", function() {});',
errors: [{message: 'it.default.before.only not permitted'}],
output: 'it.default.before(console.log)("Some describe block", function() {});'
output: 'it.default.before(console.log)("Some describe block", function() {});',
},
{
options: [{focus: ['focus']}],
options: [{focus: ['focus'], fix: true}],
code: 'test.focus("An alternative focus function", function() {});',
output: 'test("An alternative focus function", function() {});',
errors: [{message: 'test.focus not permitted'}],
Expand Down

0 comments on commit a5c0bc6

Please sign in to comment.