Coder Social home page Coder Social logo

askagirl / cukedoctor Goto Github PK

View Code? Open in Web Editor NEW

This project forked from rmpestano/cukedoctor

0.0 1.0 0.0 13.32 MB

BDD living documentation using Cucumber and Asciidoctor

Home Page: http://rmpestano.github.io/cukedoctor/

License: Apache License 2.0

Java 54.95% CSS 41.52% HTML 0.01% Gherkin 3.52%

cukedoctor's Introduction

Cukedoctor

1. Narrative

In order to have awesome living documentation
As a bdd developer
I want to convert my test results into Asciidoc format.

2. Story

GIVEN I execute my cucumber tests using the json formatter

AND cucumber json output files are generated

WHEN I convert the files using Cukedoctor

THEN I should have awesome living documentation based on asciidoc.

3. Sample

cukedoctor sample

The feature file for the above sample can be found here.

Failing steps are rendered as follows:

cukedoctor sample with error

4. Cukedoctor Living Documentation

As a proof of concept, Cukedoctor bdd tests output are rendered by itself:

ℹ️
This documentation is published to gh-pages by travisci on each successful build.

5. Other Documentation Examples

Here are some bdd documentation examples generated by Cukedoctor:

Project Living documentation

Database Rider

html / pdf

Asciidoctor

html / pdf

Cucumber (Ruby)

html / pdf

Cucumber JS

html / pdf

Jekyll

html / pdf

Sdkman

html / pdf

6. Cukedoctor Converter

Cukedoctor converter is the basis for other modules, it generates asciidoc files based on Cucumber json execution files.

6.1. Usage

Just declare the plugin in your pom.xml:

  <dependency>
       <groupId>com.github.cukedoctor</groupId>
       <artifactId>cukedoctor-converter</artifactId>
       <version>1.0.6</version>
   </dependency>

6.2. Example

@Test
public void shouldSaveDocumentationIntoDisk(){
	List<String> pathToCucumberJsonFiles = FileUtil.findJsonFiles("target/test-classes/json-output/");
	List<Feature> features = FeatureParser.parse(pathToCucumberJsonFiles);
	DocumentAttributes attrs = GlobalConfig.getInstance().getDocumentAttributes;
	attrs.toc("left").backend("html5")
			.docType("book")
			.icons("font").numbered(false)
			.sourceHighlighter("coderay")
			.docTitle("Documentation Title")
		    .sectAnchors(true).sectLink(true);

	CukedoctorConverter converter = Cukedoctor.instance(features, attrs);
	converter.setFilename("target/living_documentation.adoc");

	converter.saveDocumentation();
	assertThat(FileUtil.loadFile("target/living_documentation.adoc")).exists();
}

To generate cucumber .json output files just execute your BDD tests with json formatter, example:

@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"json:target/cucumber.json"} )
ℹ️
plugin option replaced format option which was deprecated in newer cucumber versions.

6.3. Introduction Chapter

You can add a custom introduction chapter to your living documentations by placing a file named cukedoctor-intro.adoc anywhere on your classpath.

The content of the file will be placed between Documentation title and summary section. Here’s an example of cukedoctor-intro.adoc:

= *This is a sample introduction chapter*

Introduction chapter is the place where you can insert custom content for your living documentation.

=== Sub section
Introduction chapter can have subsections

Here is rendered documentation:

cukedoctor intro

6.4. Internationalization

Cukedoctor can use internationalization in two flavours:

6.4.1. Reading features

Cucumber feature languages are provided via comments in a feature file, see here for examples.

If your feature language is not supported by Cukedoctor you can contribute it here or use a custom bundle.

6.4.2. Custom resource bundle

Another way of internationalization is to provide a custom bundle.

If you do so Cukedoctor will ignore feature language and will use provided resource bundle.

The name of the file must be cukedoctor.properties and can be anywhere in your classpath.

Here are the key values you must provide to customize your documentation:

#sections
title.features = Features
title.summary = Summary
title.scenario = Scenario

#summary
summary.steps = Steps
summary.total = Totals
summary.duration = Duration

#result
result.passed = Passed
result.failed = Failed
result.skipped = Skipped
result.pending = Pending
result.undefined= Undefined
result.missing = Missing

6.4.3. Supported locales

Cukdoctor currently supports the following locales en, es, fr, ge and pt.

Here are the supported locales

6.5. Disable extensions

Cukedoctor comes with some extensions to enhance and customize its documentation content, for more details see Cukedoctor extensions module.

6.6. Enriching documentation

6.6.1. Asciidoc markup in comments

To enrich the documentation one can use asciidoc markup inside Cucumber feature files, consider the following feature:

feature without enrichment
Feature: Calculator

  Scenario: Adding numbers
   You can asciidoc markup in feature description.

    Given I have numbers 1 and 2
    When I sum the numbers
    Then I should have 3 as result

It will be rendered by Cukedoctor as follows:

no enrich

Now if you want to enrich your living documentation you can use asciidoc syntax in your feature:

enriched feature
Feature: Calculator

  Scenario: Adding numbers
   You can use *asciidoc markup* in _feature_ #description#.

   NOTE: This is a very important feature!

    #{IMPORTANT: Asciidoc markup inside *steps* must be surrounded by *curly brackets*.}
    Given I have numbers 1 and 2

    # {NOTE: Steps comments are placed *before* each steps so this comment is for the *WHEN* step.}

    When I sum the numbers

    # {* this is a list of itens inside a feature step}
    # {* there is no multiline comment in gherkin}
    # {** second level list item}
    Then I should have 3 as result

And it will be rendered as follows:

enrich

6.6.2. Asciidoc markup in DocStrings

You can use Asciidoc markup in feature DocStrings, see feature below:

Feature: Discrete class feature

  Scenario: Render source code

    # cukedoctor-discrete
    Given the following source code
    """
[source, java]
-----
public int sum(int x, int y){
        int result = x + y;
        return result; (1)
    }
-----
<1> We can have callouts in living documentation
    """

  Scenario: Render table

    # cukedoctor-discrete
    Given the following table
    """
|====

| Cell in column 1, row 1 | Cell in column 2, row 1
| Cell in column 1, row 2 | Cell in column 2, row 2
| Cell in column 1, row 3 | Cell in column 2, row 3

|====
    """

The docstrings will be rendered as follows:

discrete
By default Cukedoctor will render DocStrings as asciidoc listing. To enable this feature use # cukedoctor-discrete comment.

6.7. "Stepless" documentation

Imagine you don’t want to automate a feature (because e.g you don’t have time) or you simple don’t like the Given When Then BDD way of describing features.

You still can write the hole feature documentation (using asciidoc) in feature and scenario description without writing any cucumber step.

ℹ️
Not automated doesn’t mean you didn’t discussed the feature and it’s scenarios.

6.8. Customizing your Living Documentation

Cukedoctor let you customize its generated documentation through Java service provider mechanism, see Cukedoctor-spi-example for example code.

6.8.1. How it works

Cukedoctor documentation customization is done through Java service provider mechanism.

You just need to implement one of the interfaces in Cukedoctor SPI and declare it in META-INF/services.

6.8.2. Example

Given this cucumber feature:

Feature: Calculator

  Scenario: Adding numbers

    Given I have numbers 1 and 2
    When I sum the numbers
    Then I should have 3 as result

  Scenario: Subtracting numbers
    A feature with a failing step

    Given I have numbers 2 and 1
    When I subtract the numbers
    Then I should have 0 as result

When we generate documentation using default cukedoctor renderers we got the following result:

calc original output
Customizing the summary section

To customize summary one have to implement SummaryRenderer interface. Here is an example:

public class CustomSummaryRenderer extends AbstractBaseRenderer implements SummaryRenderer {

    @Override
    public String renderSummary(List<Feature> features) {
        docBuilder.textLine(H2(bold(i18n.getMessage("title.summary"))));
        docBuilder.textLine("This is a custom summary renderer").newLine();
        docBuilder.textLine("Number of features: "+features.size());
        docBuilder.newLine();
        ScenarioTotalizations totalization = new ScenarioTotalizations(features);
        docBuilder.append("Passed steps: ",totalization.getTotalPassedSteps(),newLine())
                .append(newLine()).append("Failed steps: ", totalization.getTotalFailedSteps(),newLine());
        return docBuilder.toString();
    }
}
ℹ️
Abstract renderer is a template class which provides implementation of helper methods.

Now Imagine we want to render features as Asciidoctor labeled lists instead of sections, see prototype below:

custom feature renderer

To do that you need to implement FeatureRenderer and also ScenarioRenderer.

public class CustomFeatureRenderer extends CukedoctorFeatureRenderer {(1)


    @Override
    public String renderFeature(Feature feature) {
        docBuilder.textLine((bold(feature.getName()))+"::").newLine();
        if (hasText(feature.getDescription())) {
            docBuilder.append("+").sideBarBlock(feature.getDescription().trim().replaceAll("\\n", " +" + newLine()));
        }

        if(feature.hasScenarios()){

            ScenarioRenderer scenarioRenderer = new CustomScenarioRenderer();
            for (Scenario scenario : feature.getScenarios()) {
                docBuilder.append(scenarioRenderer.renderScenario(scenario,feature));(2)
            }
        }

        return docBuilder.toString();
    }
}
  1. You can also extend default renderers as above.

  2. Here we provide a custom ScenarioRenderer but you could embed all markup in FeatureRenderer if you want but depending on complexity things can get messy.

And finally here is the custom ScenarioRenderer:

public class CustomScenarioRenderer extends CukedoctorScenarioRenderer{

    @Override
    public String renderScenario(Scenario scenario, Feature feature) {
        //need to clear because we will execute this method in a for loop
        //and contents will be appended
        docBuilder.clear();
        docBuilder.append("  "+scenario.getName()+":::",newLine());
        if(scenario.hasSteps()) {
            //here we will reuse builtin step renderer
            docBuilder.textLine("+");
            StepsRenderer stepsRenderer = new CukedoctorStepsRenderer();(1)
            docBuilder.append(stepsRenderer.renderSteps(scenario.getSteps()));
        }
        return docBuilder.toString();
    }
}
  1. Here we leverage default StepsRenderer that comes with Cukedoctor.

Now the output of our customized living documentation:

calc custom output
Don’t forget to register your custom implementations in META-INF/services directory.

7. Maven plugin

This module brings the ability to execute Cukedoctor converter through a maven plugin.

The plugin just scans .json cucumber execution files in target dir and generates asciidoc documentation on target/cukedoctor folder.

7.1. Usage

Just declare the plugin in your pom.xml:

<plugin>
    <groupId>com.github.cukedoctor</groupId>
    <artifactId>cukedoctor-maven-plugin</artifactId>
    <version>1.0.6</version>
    <executions>
        <execution>
            <goals>
                <goal>execute</goal>
            </goals>
            <phase>install</phase> (1)
        </execution>
    </executions>
</plugin>
  1. You need to use a phase that runs after your tests, see maven lifecycle.

To generate cucumber .json output files just execute your tests with json formatter, example:

@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"json:target/cucumber.json"} )
ℹ️
plugin option replaced format option which was deprecated in newer cucumber versions.

7.2. Example of configuration

<plugin>
    <groupId>com.github.cukedoctor</groupId>
    <artifactId>cukedoctor-maven-plugin</artifactId>
    <version>1.0.6</version>
         <configuration>
            <outputFileName>documentation</outputFileName> (1)
            <outputDir>docs</outputDir> (2)
            <format>pdf</format> (3)
            <toc>left</toc> (4)
            <numbered>true</numbered> (5)
            <docVersion>${project.version}</docVersion> (6)
         </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>execute</goal>
                </goals>
                <phase>verify</phase>
            </execution>
        </executions>
</plugin>
  1. documentation filename

  2. directory name (relative to /target) to generate documetation (default is cukedoctor)

  3. document format, default is html5

  4. table of content position, default is right

  5. section numbering, default is false

  6. documentation version (asciidoctor revNumber)

ℹ️

You can also execute the plugin without building the project but make sure you already have cucumber json files in build dir.

mvn cukedoctor:execute

7.3. Configuration options

Table 1. Supported plugin configuration
Name Description Default

outputFileName

Generated documentation file name

documentation

outputDir

Directory of where documentation will be saved

${buildDir}/cukedoctor

documentTitle

Documentation title (first section)

Living Documentation

format

Generated documetation format. Possible values: pdf, html, all

html

docVersion

Documentarion version

sourceHighlighter

highlighter for source code rendering

highlightjs (coderay is also supported)

toc

Table of contents position

right

numbered

Section numbering

true

featuresDir

Directory to start searching (recursively) for cucumber json output

project root directory

disableFilter

Flag to disable filter

disableMinimizable

Flag to disable minimizable feature sections

disableTheme

Flag to disable theme support

hideSummarySection

When present, this flag hides Summary section

hideFeaturesSection

When present, this flag hides Features section

hideScenarioKeyword

When present, this flag Scenario (and scenario outline) keyword which prefixes each scenario;

hideStepTime

When present, this flag hides step time calculation on each step;

hideTags

When present, this flag hides tags rendering

7.4. Disable extensions

You can disable Cukedoctor extensions using the following configuration in maven plugin:

  <configuration>
       <outputFileName>documentation</outputFileName> (1)
       <outputDir>docs</outputDir>
       <format>all</format>
       <toc>left</toc> (4)
       <disableTheme>true</disableTheme>
       <disableFilter>true</disableFilter>
       <disableMinimizable>true</disableMinimizable>
       <disableStyle>true</disableStyle>
  </configuration>
ℹ️
The value doesn’t matter, if there is something in the attribute the extension will be disabled

8. Standalone jar (a.k.a cli)

This module brings the ability to execute cukedoctor converter as a Java main application (using command line: java -jar).

To use Cukedoctor as a standalone jar you can download it here.

8.1. Usage

This module converts generated adoc files into html and pdf, here’s an example:

@Test
public void shouldRenderHtmlForOneFeature(){
	CukedoctorMain main = new CukedoctorMain();
	main.execute(new String[]{
			"-o", "\"target/document-one\"", (1)
			"-p", "\"target/test-classes/json-output/one_passing_one_failing.json\"", (2)
			"-t", "Living Documentation", (3)
			"-f", "html", (4)
			"-toc", "left", (5)
            "-numbering", "true", (6)
            "-sourceHighlighter", "coderay" (7)
		});

	File generatedFile = FileUtil.loadFile("target/document-one.html");
	assertThat(generatedFile).exists();
	}
  1. output file name (default is 'documentation')

  2. path to cucumber json files or directory (default is current dir - the search is recursive)

  3. Document title (default is 'Living Documentation')

  4. document format (Default is html)

  5. table of contents position (Default is right)

  6. Section numbering (Default is false)

  7. Source highlighter (Default is highlightjs)

8.1.1. Command line

Using in command line, the above test should be something like:

java -jar cukedoctor-main.jar
		-o "target/document-one"
		-p "target/test-classes/json-output/one_passing_one_failing.json"
		-t "Living Documentation" -f html
		-hideSummarySection
		-hideScenarioKeyword

8.1.2. Maven exec plugin

You can use maven exec plugin, see example:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.4.0</version>
    <configuration>
        <executable>java</executable>
        <arguments>
            <argument>-classpath</argument>
            <classpath />
            <argument>com.github.cukedoctor.cukedoctorMain</argument>
        </arguments>
    </configuration>
</plugin>
cukedoctor-main must be on your classpath

To invoke Cukedoctor just use:

mvn exec:exec

It will run with default args. To provide arguments, in this approach, you’ll have a bit more work: see here.

8.2. Disable extensions

You can disable cukedoctor extensions by using -D option when executing Cukedoctor main at command line:

java -jar -Dcukedoctor.disable.filter=123  -Dcukedoctor.disable.theme=abc
		cukedoctor-main-1.0.6.jar
		-p cucumber-output.json

You can download Cukedoctor main jar here

8.3. Layout configuration

Some pieces of documentation can be hidden via configuration.

You can hide Features and Summary sections, as well as scenario keyword which prefixes each scenario and hide tags or step time. To do so just specify the following arg parameters respectively:

java -jar -Dcukedoctor.disable.filter=123  -Dcukedoctor.disable.theme=abc
		cukedoctor-main-1.0.6.jar
		-p cucumber-output.json
		-hideFeaturesSection (1)
		-hideSummarySection (2)
		-hideScenarioKeyword (3)
		-hideStepTime (4)
		-hideTags (5)
  1. Removes Features section so each feature is a section instead of a sub section of Features;

  2. Removes summary section

  3. Removes scenario keyword which prefixes each scenario;

  4. Removes step time calculation on each step;

  5. Removes tags rendering;

9. Extension

Cukedoctor extension adds new features to generated documentation in order to let original document cleaner and make it easier to enable/disable those features.

This module extend cukedoctor generated documentation via Asciidoctor extensions mechanism.

Cukedoctor comes with 5 extensions to enhance documentation content:

  • Filter extension which lets features to be filtered using an input at top right of the page;

  • Minimizable extension which lets you minimize/maximize features sections (minus/plus icon next to feature name);

  • Theme extension to add theme support.

  • Footer add cukedoctor footer.

  • Style customizes Asciidoctor stylesheet.

ℹ️
All extensions target html documentation.

9.1. Disable extensions

To disable extensions just set the following system properties:

   System.setProperty("cukedoctor.disable.theme","anyValue");

   System.setProperty("cukedoctor.disable.filter","anyValue");

   System.setProperty("cukedoctor.disable.minmax","anyValue");

   System.setProperty("cukedoctor.disable.footer","anyValue");

   System.setProperty("cukedoctor.disable.style","anyValue");
ℹ️
The value doesn’t matter, if there is something in the system property the extension will be disabled.
💡

You can re-enable the extensions by calling

    System.clearProperty("cukedoctor.disable.theme");

    System.clearProperty("cukedoctor.disable.filter");

    System.clearProperty("cukedoctor.disable.minmax");

    System.clearProperty("cukedoctor.disable.footer");

    System.clearProperty("cukedoctor.disable.style");

10. Jenkins plugin

Cukedoctor brings Living documentation to Jenkins via Cucumber living documentation plugin.

11. Distribution

Cukedoctor is available at Bintray and at Maven central.

Snapshots are available at maven central and published on each successful commit&build on travis.

You can use snapshots by adding the following snippets in pom.xml:

<repositories>
    <repository>
        <snapshots/>
        <id>snapshots</id>
        <name>libs-snapshot</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>
💡
You can download snapshots directly from Sonatype here.

12. Contributing

  • Found a bug? open an issue and attach your feature json output to it;

  • Have an idea? open an issue and lets discuss it;

  • Any form of feedback is more than welcome!

cukedoctor's People

Contributors

rmpestano avatar callain avatar kitenco avatar birlibirloque avatar gitter-badger avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.