diff --git a/src/rules.js b/src/rules.js index 328eebeb..42aa82d0 100644 --- a/src/rules.js +++ b/src/rules.js @@ -35,14 +35,12 @@ function isRuleEnabled(ruleConfig) { function runAllEnabledRules(feature, file, configuration, additionalRulesDirs) { var errors = []; - var ignoreFutureErrors = false; var rules = getAllRules(additionalRulesDirs); Object.keys(rules).forEach(function(ruleName) { var rule = rules[ruleName]; - if (isRuleEnabled(configuration[rule.name]) && !ignoreFutureErrors) { + if (isRuleEnabled(configuration[rule.name])) { var ruleConfig = Array.isArray(configuration[rule.name]) ? configuration[rule.name][1] : {}; var error = rule.run(feature, file, ruleConfig); - if (error) { errors = errors.concat(error); } @@ -56,5 +54,6 @@ module.exports = { doesRuleExist: doesRuleExist, isRuleEnabled: isRuleEnabled, runAllEnabledRules: runAllEnabledRules, - getRule: getRule + getRule: getRule, + getAllRules: getAllRules }; diff --git a/src/rules/max-scenarios-per-file.js b/src/rules/max-scenarios-per-file.js index e162a136..c736e3f9 100644 --- a/src/rules/max-scenarios-per-file.js +++ b/src/rules/max-scenarios-per-file.js @@ -22,7 +22,9 @@ function maxScenariosPerFile(feature, unused, config) { if (scenario.examples) { count = count - 1; scenario.examples.forEach(function (example) { - count = count + example.tableBody.length; + if (example.tableBody) { + count = count + example.tableBody.length; + } }); } }); diff --git a/src/rules/required-tags.js b/src/rules/required-tags.js index bf4774fa..88c45232 100644 --- a/src/rules/required-tags.js +++ b/src/rules/required-tags.js @@ -24,14 +24,20 @@ const checkTagExists = (requiredTag, scenarioTags, scenarioType) => { const checkRequiredTagsExistInScenarios = (feature, file, config) => { let errors = []; - feature.children.forEach((scenario) => { - // Check each Scenario for the required tags - const requiredTagErrors = config.tags.map((requiredTag) => { - return checkTagExists(requiredTag, scenario.tags || [], scenario.type); - }).filter((item) => typeof item === 'object' && item.message); - // Update errors - errors = errors.concat(requiredTagErrors); - }); + if (feature.children) { + feature.children.forEach((scenario) => { + // Check each Scenario for the required tags + const requiredTagErrors = config.tags + .map((requiredTag) => { + return checkTagExists(requiredTag, scenario.tags || [], scenario.type); + }) + .filter((item) => + typeof item === 'object' && item.message + ); + // Update errors + errors = errors.concat(requiredTagErrors); + }); + } return errors; }; diff --git a/src/rules/scenario-size.js b/src/rules/scenario-size.js index daab42b0..7cbd2fbf 100644 --- a/src/rules/scenario-size.js +++ b/src/rules/scenario-size.js @@ -1,3 +1,5 @@ +var _ = require('lodash'); + var rule = 'scenario-size'; var availableConfigs = { 'steps-length': { @@ -6,7 +8,10 @@ var availableConfigs = { } }; -function scenarioSize(feature, fileName, configuration = availableConfigs) { +function scenarioSize(feature, fileName, configuration) { + if (_.isEmpty(configuration)) { + configuration = availableConfigs; + } const errors = []; if (feature.children) { feature.children.forEach((child) => { diff --git a/test/rules/all-rules/ChildlessFeature.feature b/test/rules/all-rules/ChildlessFeature.feature new file mode 100644 index 00000000..5eb9db3b --- /dev/null +++ b/test/rules/all-rules/ChildlessFeature.feature @@ -0,0 +1 @@ +Feature: This is a childless feature \ No newline at end of file diff --git a/test/rules/all-rules/EmptyExamples.feature b/test/rules/all-rules/EmptyExamples.feature new file mode 100644 index 00000000..42f85b36 --- /dev/null +++ b/test/rules/all-rules/EmptyExamples.feature @@ -0,0 +1,6 @@ +Feature: Some Feature + +Scenario Outline: Some Scenario Outline + Given this is a step + + Examples: \ No newline at end of file diff --git a/test/rules/indentation/EmptyFeature.feature b/test/rules/all-rules/EmptyFeature.feature similarity index 100% rename from test/rules/indentation/EmptyFeature.feature rename to test/rules/all-rules/EmptyFeature.feature diff --git a/test/rules/all-rules/SteplessFeature.feature b/test/rules/all-rules/SteplessFeature.feature new file mode 100644 index 00000000..1f6669f5 --- /dev/null +++ b/test/rules/all-rules/SteplessFeature.feature @@ -0,0 +1,7 @@ +Feature: + +Background: + +Scenario: + +Scenario Outline: diff --git a/test/rules/all-rules/all-rules.js b/test/rules/all-rules/all-rules.js new file mode 100644 index 00000000..5190f47b --- /dev/null +++ b/test/rules/all-rules/all-rules.js @@ -0,0 +1,40 @@ +var rules = require('../../../dist/rules.js'); +var linter = require('../../../dist/linter.js'); + +// Test cases for incomplete feature files that have broken over time accross multiple rules +describe('All rules', function() { + + function runAllEnabledRulesAgainstFile(featureFile) { + var allRules = rules.getAllRules(); + var configuration = {}; + Object.keys(allRules).forEach(function(rule) { + if (rule == 'new-line-at-eof') { + configuration[rule] = ['on', 'yes']; + } else if (rule == 'required-tags') { + configuration[rule] = ['on', {'tags': [] }]; + } else { + configuration[rule] = 'on'; + } + }); + + const {feature, file} = linter.readAndParseFile('test/rules/all-rules/' + featureFile, 'utf8'); + + rules.runAllEnabledRules(feature, file, configuration); + } + + it('do not throw exceptions when processing an empty feature', function() { + runAllEnabledRulesAgainstFile('EmptyFeature.feature'); + }); + + it('do not throw exceptions when processing a feature with no children', function() { + runAllEnabledRulesAgainstFile('ChildlessFeature.feature'); + }); + + it('do not throw exceptions when processing a feature with no steps', function() { + runAllEnabledRulesAgainstFile('SteplessFeature.feature'); + }); + + it('do not throw exceptions when processing a scenario outline with an empty examples table', function() { + runAllEnabledRulesAgainstFile('EmptyExamples.feature'); + }); +}); \ No newline at end of file diff --git a/test/rules/indentation/indentation.js b/test/rules/indentation/indentation.js index 286f8cab..1f4854c1 100644 --- a/test/rules/indentation/indentation.js +++ b/test/rules/indentation/indentation.js @@ -59,10 +59,6 @@ describe('Indentation rule', function() { runTest('indentation/CorrectIndentationTabs.feature', {}, []); }); - it('doesn\'t raise errors when parsing an empty feature', function() { - runTest('indentation/EmptyFeature.feature', {}, []); - }); - it('detects errors for features, backgrounds, scenarios, scenario outlines and steps (spaces)', function() { runTest('indentation/WrongIndentationSpaces.feature', {}, wrongIndenatationErrors); }); diff --git a/test/rules/name-length/EmptyFeature.feature b/test/rules/name-length/EmptyFeature.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/test/rules/name-length/name-length.js b/test/rules/name-length/name-length.js index 8a0974b5..e3b15827 100644 --- a/test/rules/name-length/name-length.js +++ b/test/rules/name-length/name-length.js @@ -8,10 +8,6 @@ describe('Name length rule', function() { runTest('name-length/CorrectLength.feature', {}, []); }); - it('doesn\'t raise errors when parsing an empty feature', function() { - runTest('name-length/EmptyFeature.feature', {}, []); - }); - it('detects errors for features, scenarios, scenario outlines and steps', function() { runTest('name-length/WrongLength.feature', {}, [{ messageElements: {element: 'Feature', length: 89}, diff --git a/test/rules/no-unnamed-scenarios/EmptyFeature.feature b/test/rules/no-unnamed-scenarios/EmptyFeature.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/test/rules/no-unnamed-scenarios/no-unnamed-scenarios.js b/test/rules/no-unnamed-scenarios/no-unnamed-scenarios.js index 745bd467..a74ecc59 100644 --- a/test/rules/no-unnamed-scenarios/no-unnamed-scenarios.js +++ b/test/rules/no-unnamed-scenarios/no-unnamed-scenarios.js @@ -6,11 +6,7 @@ describe('No Unnamed Scenarios Rule', function() { it('doesn\'t raise errors when there are no violations', function() { runTest('no-unnamed-scenarios/NoViolations.feature', {}, []); }); - - it('doesn\'t raise errors for an empty feature', function() { - runTest('no-unnamed-scenarios/EmptyFeature.feature', {}, []); - }); - + it('doesn\'t raise errors for a feature with no scenarios', function() { runTest('no-unnamed-scenarios/FeatureWithNoScenarios.feature', {}, []); }); diff --git a/test/rules/no-unused-variables/EmptyFeature.feature b/test/rules/no-unused-variables/EmptyFeature.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/test/rules/no-unused-variables/no-unused-variables.js b/test/rules/no-unused-variables/no-unused-variables.js index e2c930b6..048baf08 100644 --- a/test/rules/no-unused-variables/no-unused-variables.js +++ b/test/rules/no-unused-variables/no-unused-variables.js @@ -7,11 +7,6 @@ describe('No Unused Variables Rule', function() { runTest('no-unused-variables/NoViolations.feature', {}, []); }); - it('doesn\'t raise errors when parsing an empty feature', function() { - var runTest = ruleTestBase.createRuleTest(rule, ''); - runTest('no-unused-variables/EmptyFeature.feature', {}, []); - }); - it('detects unused scenario variables', function() { var runTest = ruleTestBase.createRuleTest(rule, 'Step variable "<%= variable %>" does not exist the in examples table'); diff --git a/test/rules/one-space-between-tags/EmptyFeature.feature b/test/rules/one-space-between-tags/EmptyFeature.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/test/rules/one-space-between-tags/one-space-between-tags.js b/test/rules/one-space-between-tags/one-space-between-tags.js index 23a667e5..2bffa6a3 100644 --- a/test/rules/one-space-between-tags/one-space-between-tags.js +++ b/test/rules/one-space-between-tags/one-space-between-tags.js @@ -8,10 +8,6 @@ describe('One Space Between Tags Rule', function() { runTest('one-space-between-tags/NoViolations.feature', {}, []); }); - it('doesn\'t raise errors when parsing an empty feature', function() { - runTest('one-space-between-tags/EmptyFeature.feature', {}, []); - }); - it('detects errors for tags on features, scenarios, and scenario outlines', function() { runTest('one-space-between-tags/Violations.feature', {}, [{ line: 1, diff --git a/test/rules/use-and/EmptyFeature.feature b/test/rules/use-and/EmptyFeature.feature deleted file mode 100644 index e69de29b..00000000 diff --git a/test/rules/use-and/use-and.js b/test/rules/use-and/use-and.js index f67b9b33..9a43d5d3 100644 --- a/test/rules/use-and/use-and.js +++ b/test/rules/use-and/use-and.js @@ -8,10 +8,6 @@ describe('Use And Rule', function() { runTest('use-and/NoViolations.feature', {}, []); }); - it('doesn\'t raise errors when parsing an empty feature', function() { - runTest('use-and/EmptyFeature.feature', {}, []); - }); - it('raises erros when there are violations', function() { runTest('use-and/Violations.feature', {}, [ {