From 3a51be2397979b950b4c8ab5e060c03380ab73fc Mon Sep 17 00:00:00 2001 From: Xavier Garcia Buils Date: Sun, 12 May 2019 13:16:41 +0200 Subject: [PATCH] Add docstring option in indentation rule --- src/rules/indentation.js | 57 +++++++++++++++++-- .../CorrectIndentationDocStrings.feature | 17 ++++++ .../WrongIndentationDocStrings.feature | 17 ++++++ test/rules/indentation/indentation.js | 31 ++++++++-- 4 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 test/rules/indentation/CorrectIndentationDocStrings.feature create mode 100644 test/rules/indentation/WrongIndentationDocStrings.feature diff --git a/src/rules/indentation.js b/src/rules/indentation.js index 6d7c81f8..f23a1f9d 100644 --- a/src/rules/indentation.js +++ b/src/rules/indentation.js @@ -34,19 +34,43 @@ const defaultConfig = { 'then': 2, 'and': 2, 'but': 2, + 'DocString': 4, }; const availableConfigs = Object.assign({}, defaultConfig, { // The values here are unused by the config parsing logic. 'feature tag': -1, 'scenario tag': -1, + 'DocString line': -1, }); +const parseDocString = (lines) => (docString) => { + if (!docString) { + return; + } + const {line} = docString.location; + const docStringLines = docString.content.split(/\r\n|\r|\n/); + const rawDocStringLines = lines.slice(line, line + docStringLines.length); + return Object.assign({}, docString, { + lines: rawDocStringLines.map((rawLine, index) => { + const column = rawLine.indexOf(docStringLines[index]) + 1; + return { + content: docStringLines[index], + location: { + line: line + index + 1, + column, + }, + }; + }), + }); +}; + const mergeConfiguration = (configuration) => { const mergedConfiguration = Object.assign({}, defaultConfig, configuration); return Object.assign({ 'feature tag': mergedConfiguration['Feature'], 'scenario tag': mergedConfiguration['Scenario'], + 'DocString line': mergedConfiguration['DocString'], }, mergedConfiguration); }; @@ -77,13 +101,30 @@ const findKey = (obj, predicate) => { return Object.keys(obj).find((key) => predicate(obj[key])); }; -const testStep = (feature, configuration, testNode) => (step) => { +const testDocString = (parseDocString, test) => (step) => { + const docString = parseDocString(step.argument); + const getLines = (docString) => (docString || {lines: []}).lines; + const docStringErrors = test('DocString')(docString); + if (docStringErrors.length > 0) { + return docStringErrors; + } + return getLines(docString).map(test('DocString line')); +}; + +const getStepType = (feature, configuration) => (step) => { const keyword = step.keyword; - let stepType = findKey(languageMapping[feature.language], (values) => { + const stepType = findKey(languageMapping[feature.language], (values) => { return values instanceof Array && values.indexOf(keyword) !== -1; }); - stepType = stepType in configuration ? stepType : 'Step'; - return testNode(stepType)(step); + return stepType in configuration ? stepType : 'Step'; +}; + +const testStep = (getStepType, testDocstring, testNode) => (step) => { + const stepType = getStepType(step); + return applyOver([ + testNode(stepType), + testDocstring, + ])(step); }; const testFeature = (testStep, test) => { @@ -120,14 +161,18 @@ const testFeature = (testStep, test) => { ]); }; -const run = (feature, unused, configuration) => { +const run = (feature, {lines}, configuration) => { if (Object.keys(feature).length === 0) { return []; } const test = checkNodeIndentation(mergeConfiguration(configuration)); return testFeature( - testStep(feature, configuration, test), + testStep( + getStepType(feature, configuration), + testDocString(parseDocString(lines), test), + test + ), test )(feature); }; diff --git a/test/rules/indentation/CorrectIndentationDocStrings.feature b/test/rules/indentation/CorrectIndentationDocStrings.feature new file mode 100644 index 00000000..cfebb59e --- /dev/null +++ b/test/rules/indentation/CorrectIndentationDocStrings.feature @@ -0,0 +1,17 @@ +Feature: My team is never consistent with anything + +Scenario: Quotes are indented 6 spaces + When I use this docstring: + """ + This is + a docstring + """ + Then the rule should pass + +Scenario: Content of Docstring is indented at least 6 spaces + When I use this docstring: + """ + This is + a docstring + """ + Then the rule should pass diff --git a/test/rules/indentation/WrongIndentationDocStrings.feature b/test/rules/indentation/WrongIndentationDocStrings.feature new file mode 100644 index 00000000..430ca2a9 --- /dev/null +++ b/test/rules/indentation/WrongIndentationDocStrings.feature @@ -0,0 +1,17 @@ +Feature: My team is never consistent with anything + +Scenario: Quotes are indented 6 spaces + When I use this docstring: + """ + This is + a docstring + """ + Then the rule should pass + +Scenario: Content of Docstring is indente at least 6 spaces + When I use this docstring: + """ + This is + a docstring + """ + Then the rule should pass diff --git a/test/rules/indentation/indentation.js b/test/rules/indentation/indentation.js index 26948662..cae3c00c 100644 --- a/test/rules/indentation/indentation.js +++ b/test/rules/indentation/indentation.js @@ -285,8 +285,31 @@ describe('Indentation rule', () => { }]); }); - /* TODO: add tests for partial configurations and fallbacks - * (eg rule for Step is used for Given, Then etc is rule for Given, Then, etc - * has not been specified) - */ + context('DocString', () => { + it('Correct indentation', function() { + runTest('indentation/CorrectIndentationDocStrings.feature', { + DocString: 4, + }, []); + }); + + it('Wrong indentation', function() { + runTest('indentation/WrongIndentationDocStrings.feature', { + DocString: 4, + }, [{ + messageElements: {element: 'DocString', expected: 4, actual: 2}, + rule: ruleName, + location: { + line: 5, + column: 3, + }, + }, { + messageElements: {element: 'DocString line', expected: 4, actual: 2}, + rule: ruleName, + location: { + line: 14, + column: 3, + }, + }]); + }); + }); });