Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cucumber-JVM 3 - io.cucumber.datatable.UndefinedDataTableTypeException

I updated from Cucumber-JVM 2.4.0 to 3.0.2 in my pom.xml and DataTables started throwing this exception:

io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to List< jcucumberng.steps.pojos.Income >. Please register a DataTableType with a TableEntryTransformer or TableRowTransformer for class jcucumberng.steps.pojos.Income

I changed all my imports to

import io.cucumber.datatable.DataTable;

I did an mvn clean install and compilation was successful but steps involving DataTables no longer work after the update.

Current code:

// Feature
When I Enter My Regular Income Sources
  | name   | amount | frequency     |
  | Salary | 25000  | every 2 weeks |


// Stepdef
@When("^I Enter My Regular Income Sources$")
public void I_Enter_My_Regular_Income_Sources(DataTable dataTable) throws Throwable {
    List<Income> incomes = dataTable.asList(Income.class);

    // More code    
}


// Custom type
public class Income {

    private String name = null;
    private String amount = null;
    private String frequency = null;

    public Income(String name, String amount, String frequency) {
        this.name = name;
        this.amount = amount;
        this.frequency = frequency;
    }

    // Getters and setters
}

Is there a new way to use the DataTables in Cucumber-JVM v3.x.x?

UPDATE: enter image description here

like image 249
silver Avatar asked Jun 09 '18 07:06

silver


3 Answers

Migrating from v2.x.x to v3.x.x for DataTable

Posting my answer to serve as reference for those who may encounter the same. For their release announcement, click here.

I decided to put DataTableConfigurer.java in its own package so it does not mix with my stepdefs: enter image description here

Runner:

@CucumberOptions(features = { "src/test/resources/features" }, tags = { "not @ignore" }, glue = {
        "jcucumberng/steps/defs", "jcucumberng/steps/config", "jcucumberng/steps/hooks" }, ...

DataTableConfigurer:

import java.util.Locale;
import java.util.Map;

import cucumber.api.TypeRegistry;
import cucumber.api.TypeRegistryConfigurer;
import io.cucumber.datatable.DataTableType;
import io.cucumber.datatable.TableEntryTransformer;
import jcucumberng.steps.domain.Expense;
import jcucumberng.steps.domain.Income;

/*
 * Maps datatables in feature files to custom domain objects.
 */
public class DataTableConfigurer implements TypeRegistryConfigurer {

    @Override
    public Locale locale() {
        return Locale.ENGLISH;
    }

    @Override
    public void configureTypeRegistry(TypeRegistry registry) {
        registry.defineDataTableType(new DataTableType(Income.class, new TableEntryTransformer<Income>() {
            @Override
            public Income transform(Map<String, String> entry) {
                return new Income(entry.get("name"), entry.get("amount"), entry.get("frequency"));
            }
        }));

        registry.defineDataTableType(new DataTableType(Expense.class, new TableEntryTransformer<Expense>() {
            @Override
            public Expense transform(Map<String, String> entry) {
                return new Expense(entry.get("name"), entry.get("amount"), entry.get("frequency"));
            }
        }));
    }

}

I had another custom domain type Expense (which happened to have the same fields), so I just registered it again based on the example.

like image 38
silver Avatar answered Sep 28 '22 10:09

silver


Use DataTableType annotation

@DataTableType
public Income incomeEntry(Map<String, String> entry) {
    return new Income(entry.get("name"), entry.get("amount"), entry.get("frequency"));
}

Then you can directly use the list of the custom class in step definition

@When("^I Enter My Regular Income Sources$")
public void I_Enter_My_Regular_Income_Sources(List<Income> incomes) throws Throwable {
    // More code    
}
like image 40
Sujay Sawant Avatar answered Sep 28 '22 08:09

Sujay Sawant


It has been totally revamped. XStream has been removed , so earlier code will not work.

You will need to add logic for datatable and parameter conversion. Refer to these - https://github.com/cucumber/cucumber/tree/master/datatable and https://github.com/cucumber/cucumber/tree/master/cucumber-expressions . Place below class code inside a package defined in the glue option.

public class Configurer implements TypeRegistryConfigurer {

    @Override
            public void configureTypeRegistry(TypeRegistry registry) {

    registry.defineDataTableType(new DataTableType(Income.class, new TableEntryTransformer<Income>() {
                    @Override
                    public Income transform(Map<String, String> entry) {
                        return new Income(entry.get("name"),entry.get("amount"),entry.get("frequency"));
                    }
                }));
            }

            @Override
            public Locale locale() {
                return Locale.ENGLISH;
            }

        }

UPDATED Imports... Not all are required, keep what is relevant

import cucumber.api.TypeRegistry;
import cucumber.api.TypeRegistryConfigurer;
import io.cucumber.cucumberexpressions.ParameterType;
import io.cucumber.datatable.DataTable;
import io.cucumber.datatable.DataTableType;
import io.cucumber.datatable.TableCellTransformer;
import io.cucumber.datatable.TableEntryTransformer;
import io.cucumber.datatable.TableRowTransformer;
import io.cucumber.datatable.TableTransformer;
like image 156
Grasshopper Avatar answered Sep 28 '22 10:09

Grasshopper