diff --git a/features/support/usageSteps.js b/features/support/usageSteps.js index f2a22fa..d18e06a 100644 --- a/features/support/usageSteps.js +++ b/features/support/usageSteps.js @@ -61,6 +61,24 @@ When('the box is checked to show tags', function () { this.outputHTML.getElementById('tagsCheckbox').click(); }); +When(/^the report is opened with a link for the (first|second) feature title$/, function (featureIndex) { + const index = featureIndex === 'first' ? 0 : 1; + const featureWrappers = this.outputHTML.getElementsByClassName('feature-wrapper'); + const featureAnchor = featureWrappers[index].getElementsByClassName('anchor')[0]; + + this.createWindow(`https://localhost/#${featureAnchor.id}`); +}); + +When(/^the report is opened with a link for the (first|second) scenario title in the (first|second) feature$/, function (scenarioIndex, featureIndex) { + const fIndex = featureIndex === 'first' ? 0 : 1; + const featureWrappers = this.outputHTML.getElementsByClassName('feature-wrapper'); + const sIndex = scenarioIndex === 'first' ? 0 : 1; + const scenarioAnchors = Array.from(featureWrappers[fIndex].getElementsByClassName('anchor')) + .filter((anchor) => anchor.hasAttribute('scenario-button')); + + this.createWindow(`https://localhost/#${scenarioAnchors[sIndex].id}`); +}); + Then(/^the (first|second) feature (?:is|will be) displayed$/, function (featureIndex) { const index = featureIndex === 'first' ? 0 : 1; const featureWrappers = this.outputHTML.getElementsByClassName('feature-wrapper'); diff --git a/features/support/world.js b/features/support/world.js index f82f20d..ce47f78 100644 --- a/features/support/world.js +++ b/features/support/world.js @@ -1,5 +1,5 @@ const { setWorldConstructor, After, Before } = require('cucumber'); -const { JSDOM } = require('jsdom'); +const { JSDOM, VirtualConsole } = require('jsdom'); const fs = require('fs'); class CustomWorld { @@ -14,11 +14,21 @@ class CustomWorld { this.exceptionScenario = false; } + createWindow(url, outputConsole) { + const virtualConsole = new VirtualConsole(); + if (outputConsole) { + virtualConsole.sendTo(outputConsole); + } + this.window = new JSDOM(this.output, { + url, virtualConsole, runScripts: 'dangerously', pretendToBeVisual: true, + }).window; + this.outputHTML = this.window.document; + } + setOutput(output) { this.output = output; if (this.output.length > 0) { - this.window = new JSDOM(this.output, { url: 'https://localhost/', runScripts: 'dangerously', pretendToBeVisual: true }).window; - this.outputHTML = this.window.document; + this.createWindow('https://localhost/', console); } else { this.window = null; this.outputHTML = null; diff --git a/features/use_report.feature b/features/use_report.feature index 727df9f..5a65ee2 100644 --- a/features/use_report.feature +++ b/features/use_report.feature @@ -122,3 +122,23 @@ Feature: Report Usage Then the tags displayed for the feature will be '@pet_care @dogs' Then the tags displayed for the first scenario will be '@feeding' Then the tags displayed for the second scenario will be '@petting' + + Scenario: Opening a report with a feature title link + Given there is a report for the 'feature' directory + When the report is opened with a link for the second feature title + Then the second feature will be displayed + And the scenario buttons for the second feature will be expanded in the sidebar + When the report is opened with a link for the first feature title + Then the first feature will be displayed + And the scenario buttons for the first feature will be expanded in the sidebar + + Scenario: Opening a report with a scenario title link + Given there is a report for the 'feature' directory + When the report is opened with a link for the second scenario title in the second feature + Then the second feature will be displayed + And the scenario buttons for the second feature will be expanded in the sidebar + And the second scenario button will be highlighted + When the report is opened with a link for the first scenario title in the first feature + Then the first feature will be displayed + And the scenario buttons for the first feature will be expanded in the sidebar + And the first scenario button will be highlighted \ No newline at end of file diff --git a/src/Generator.js b/src/Generator.js index b183476..aa437f4 100644 --- a/src/Generator.js +++ b/src/Generator.js @@ -198,6 +198,8 @@ const populateHtmlIdentifiers = (feature) => { idSequence += 1; feature.featureWrapperId = idSequence; idSequence += 1; + feature.featureButtonId = idSequence; + idSequence += 1; feature.scenarios.forEach((scenario) => { scenario.scenarioId = idSequence; idSequence += 1; @@ -289,6 +291,7 @@ const getFeatureButtons = (featureFileTree) => { const { feature } = child; const translations = i18n.getFixedT(feature.language); const featureButton = { + id: feature.featureButtonId, featureId: feature.featureId, featureWrapperId: feature.featureWrapperId, title: trimCucumberKeywords(translations, feature.name, 'feature'), diff --git a/src/templates/feature_template.html b/src/templates/feature_template.html index 9a7eb5f..7053308 100644 --- a/src/templates/feature_template.html +++ b/src/templates/feature_template.html @@ -3,8 +3,12 @@ {{#if tagString}}
{{tagString}}
{{/if}} - -

{{name}}

+

+ {{name}} + + + +

{{description}}
@@ -41,8 +45,12 @@

{{this.background.name}}

{{#if tagString}}
{{tagString}}
{{/if}} - -

{{this.name}}

+

+ {{this.name}} + + + +

{{#if this.description}}
{{this.description}}
diff --git a/src/templates/scripts.js b/src/templates/scripts.js index b6061b4..6fbdde3 100644 --- a/src/templates/scripts.js +++ b/src/templates/scripts.js @@ -179,15 +179,45 @@ const init = () => { tagsCheckbox.addEventListener('click', tagsCheckboxClicked); } - // Open the first feature. - const firstFeatureButton = document.getElementsByClassName('feature-button')[0]; - if (firstFeatureButton) { - // Open any parent directory buttons - const directoryButton = firstFeatureButton.parentNode.parentNode.previousElementSibling; - toggleParentDirectoryButtons(directoryButton); - - toggleFunctionAccordion(firstFeatureButton); - toggleDisplayedFeature(firstFeatureButton); + // Open the identified feature/scenario (if specified in the URL) else open the first feature + const { hash } = window.location; + let openDefaultFeature = true; + if (hash) { + const elementId = hash.substring(1, hash.length); + const element = document.getElementById(elementId); + if (element) { + const scenarioButtonId = element.getAttribute('scenario-button'); + const featureButtonId = element.getAttribute('feature-button'); + if (scenarioButtonId) { + // It is a scenario link + const scenarioButton = document.getElementById(scenarioButtonId); + const featureButton = scenarioButton.parentNode.parentNode.previousElementSibling; + const directoryButton = featureButton.parentNode.parentNode.previousElementSibling; + toggleParentDirectoryButtons(directoryButton); + featureButton.click(); + scenarioButton.click(); + openDefaultFeature = false; + } else if (featureButtonId) { + // It is a feature link + const featureButton = document.getElementById(featureButtonId); + const directoryButton = featureButton.parentNode.parentNode.previousElementSibling; + toggleParentDirectoryButtons(directoryButton); + featureButton.click(); + openDefaultFeature = false; + } + } + } + if (openDefaultFeature) { + // Open the first feature. + const firstFeatureButton = document.getElementsByClassName('feature-button')[0]; + if (firstFeatureButton) { + // Open any parent directory buttons + const directoryButton = firstFeatureButton.parentNode.parentNode.previousElementSibling; + toggleParentDirectoryButtons(directoryButton); + + toggleFunctionAccordion(firstFeatureButton); + toggleDisplayedFeature(firstFeatureButton); + } } // Initialize the settings diff --git a/src/templates/style.css b/src/templates/style.css index 6aa3d77..f0d63ed 100644 --- a/src/templates/style.css +++ b/src/templates/style.css @@ -179,10 +179,13 @@ i.fa-angle-right, i.fa-angle-down { .feature-wrapper.active { display: block; } -.feature-wrapper a.anchor { - display: block; - position: relative; - top: -1.5em; +.anchor { + color: transparent; + padding-top: 1em; + outline: none; +} +.title:hover + .anchor, .anchor:hover { + color: -webkit-link; } .tags { color: grey;