Skip to content

Gherkin quitely ignores unfinished table cells #22

Open
@mpkorstanje

Description

@mpkorstanje

The following is a valid gherkin document with two empty tables according to the gherkin/java 18.1.1 parser. However at a glance the tables do not look empty.

Feature: Empty tables?
  Scenario: This is valid Gherkin
    Given a non-empty list
      | hello 
Feature: Empty tables?
  Scenario Outline: This is also valid Gherkin
    Given a step <hello>
    Examples: 
      | hello 

For more complex tables this will confuse users about what their tables actually contain. This can be especially insidious when tables are automatically transformed into POJO's and used as DTOs. It also has knock on effects on other parts of Cucumber. For example in this SO question, the user is confused about incorrect step definitions generated by ignoring the unfinished table cell.

It is essential that a users are not mislead about the contents of a table. So when encountering an unfinished table cell, i.e. any non-whitespace characters after the last | on a table row line I would expect the parser to throw an exception and explain the problem.

import io.cucumber.gherkin.Gherkin;
import io.cucumber.messages.Messages;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static io.cucumber.gherkin.Gherkin.makeSourceEnvelope;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;

class FeatureParserTest {

    @Test
    void non_empty_table() {
        String source = "" +
                "Feature: Empty table?\n" +
                "  Scenario: This is valid Gherkin\n" +
                "    Given a non-empty list\n" +
                "      | hello \n";

        Messages.PickleStepArgument.PickleTable pickleTable = Gherkin.fromSources(
                singletonList(makeSourceEnvelope(source, "table.feature")),
                false,
                false,
                true,
                () -> UUID.randomUUID().toString()
        )
                .map(Messages.Envelope::getPickle)
                .map(pickle -> pickle.getSteps(0))
                .map(Messages.Pickle.PickleStep::getArgument)
                .map(Messages.PickleStepArgument::getDataTable)
                .findFirst()
                .get();

        assertEquals(1, pickleTable.getRowsList().size());
        assertEquals(1, pickleTable.getRows(0).getCellsCount()); // fails, table is empty
    }

    @Test
    void one_example() {
        String source = "" +
                "Feature: Single example?\n" +
                "  Scenario Outline: This is valid Gherkin\n" +
                "    Given a step <hello>\n" +
                "    Examples: \n" +
                "      | hello \n";

        Messages.GherkinDocument.Feature.TableRow row = Gherkin.fromSources(
                singletonList(makeSourceEnvelope(source, "table.feature")),
                false,
                true,
                false,
                () -> UUID.randomUUID().toString()
        )
                .filter(Messages.Envelope::hasGherkinDocument)
                .map(Messages.Envelope::getGherkinDocument)
                .map(Messages.GherkinDocument::getFeature)
                .map(feature -> feature.getChildren(0))
                .map(Messages.GherkinDocument.Feature.FeatureChild::getScenario)
                .map(Messages.GherkinDocument.Feature.Scenario::getExamplesList)
                .map(examples -> examples.get(0))
                .map(Messages.GherkinDocument.Feature.Scenario.Examples::getTableHeader)
                .findFirst()
                .get();

        assertEquals(1, row.getCellsCount());  // fails, table is empty
    }

}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions