Cucumber DataTable Error - io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to cucumber.api.DataTable
Asked Answered
F

3

6

Trying to run a scenario with cucumber/selenium/java/intelliJ, but getting an error regarding the DataTable in one of the steps. The dataTable was working fine and converting the arguments for the step correctly before I started using a test runner and changed some things around, but I just can't get this to work.

This is the error:

cucumber.runtime.CucumberException: Could not convert arguments for step [^I enter the following login details:$] defined at 'Steps.MaStepdefs.iEnterTheFollowingLoginDetails(DataTable) in file:/C:/Users/Kristian.Senior/Desktop/CukesReporting/target/test-classes/'.
It appears you did not register a data table type. The details are in the stacktrace below.
    at cucumber.runner.PickleStepDefinitionMatch.registerTypeInConfiguration(PickleStepDefinitionMatch.java:59)
    at cucumber.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:44)
    at cucumber.runner.TestStep.executeStep(TestStep.java:63)
    at cucumber.runner.TestStep.run(TestStep.java:49)
    at cucumber.runner.PickleStepTestStep.run(PickleStepTestStep.java:43)
    at cucumber.runner.TestCase.run(TestCase.java:45)
    at cucumber.runner.Runner.runPickle(Runner.java:40)
    at cucumber.runtime.junit.PickleRunners$NoStepDescriptions.run(PickleRunners.java:146)
    at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:68)
    at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:23)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:73)
    at cucumber.api.junit.Cucumber.runChild(Cucumber.java:122)
    at cucumber.api.junit.Cucumber.runChild(Cucumber.java:64)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at cucumber.api.junit.Cucumber$1.evaluate(Cucumber.java:131)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to cucumber.api.DataTable.
Please register a DataTableType with a TableTransformer, TableEntryTransformer or TableRowTransformer for cucumber.api.DataTable.
    at io.cucumber.datatable.UndefinedDataTableTypeException.singletonNoConverterDefined(UndefinedDataTableTypeException.java:15)
    at io.cucumber.datatable.DataTableTypeRegistryTableConverter.toSingleton(DataTableTypeRegistryTableConverter.java:106)
    at io.cucumber.datatable.DataTableTypeRegistryTableConverter.convert(DataTableTypeRegistryTableConverter.java:75)
    at io.cucumber.datatable.DataTable.convert(DataTable.java:362)
    at io.cucumber.stepexpression.StepExpressionFactory$3.transform(StepExpressionFactory.java:73)
    at io.cucumber.stepexpression.DataTableArgument.getValue(DataTableArgument.java:19)
    at cucumber.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:41)
    ... 29 more

Here is my scenario:

Feature: LoginFeature
  This deals with logging in

  Scenario: Log in with correct username

    Given I navigate to the login page
    And I enter the following login details:
      | username | password |
      | cukey    | passwoid |
    And I click the login button
    Then I should land on the newest page

Here's my step definitions:

package Steps;

import Base.BaseUtil;
import Pages.LoginPageObjeks;
import cucumber.api.DataTable;
import cucumber.api.PendingException;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.ArrayList;
import java.util.List;


public class MaStepdefs extends BaseUtil {
    private BaseUtil base;

    public MaStepdefs(BaseUtil base) {
        this.base = base;
    }

    @And("^I click the login button$")
    public void iClickTheLoginButton() throws Throwable {
        LoginPageObjeks page = new LoginPageObjeks(base.Driver);
        page.ClickLogin();

    }

    @Given("^I navigate to the login page$")
    public void iNavigateToTheLoginPage() throws Throwable {

        base.Driver.navigate().to("http://www.executeautomation.com/demosite/Login.html");

    }

    @And("^I enter the following login details:$")
    public void iEnterTheFollowingLoginDetails(DataTable table) throws Throwable {

        List<User> users = new ArrayList<User>();

        users = table.asList(User.class);

        LoginPageObjeks page = new LoginPageObjeks(base.Driver);

        for (User user : users) {
            page.Login(user.username, user.password);

            //base.Driver.findElement(By.name("UserName")).sendKeys(user.username);
            //base.Driver.findElement(By.name("Password")).sendKeys(user.password);

            Thread.sleep(2000);


        }
    }
        @Then("^I should land on the newest page$")
        public void iShouldLandOnTheNewestPage () throws Throwable {
            Assert.assertEquals("It's not displayed", base.Driver.findElement(By.id("Initial")).isDisplayed(), true);
        }



    }

    class User {
        public String username;
        public String password;

        public User(String userName, String passWord) {
            username = userName;
            password = passWord;
        }
    }

Here is my pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>groupId</groupId>
    <artifactId>ownCukes</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19</version>
            </plugin>
        </plugins>
    </build>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>4.2.6</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>3.2.0</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-picocontainer</artifactId>
            <version>4.2.6</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>4.2.6</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>4.2.6</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-core -->

        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-core</artifactId>
            <version>1.2.5</version>
            <scope>test</scope>
        </dependency>


    </dependencies>


</project>

And here's my TestRunner:

package Runner;


import cucumber.api.CucumberOptions;
import org.junit.runner.RunWith;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(features = {"src/test/java/features"}, glue = "Steps")

public class TestRunner {
}

I'm not sure what a data table type is or how to register one? I've tried messing around with DataTableType and TypeRegistry but I'm not an expert. Any help would be appreciated, thanks

Fauve answered 9/4, 2019 at 11:15 Comment(3)
The DataTable import is "import io.cucumber.datatable.DataTable;" instead of what u are using which is from an old version of cucumber like version 2. U should look at the maven dependencies and clean it up.Fantoccini
Just tried this. Gave me a new error - io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to List<Steps.User>.Fauve
U need to register a datatabletype in a class that implements TypeRegistryConfigurer. The transformation logic will be included in that. docs.cucumber.io/cucumber/configurationFantoccini
S
10

You are using outdated version, it is now:

import io.cucumber.datatable.DataTable;

See CHANGELOG for cucumber jvm, quote:

[Core] Replace DataTable with io.cucumber.datatable.DataTable (#1248 M.P. Korstanje, Björn Rasmusson, Marit van Dijk) Custom data table types can be defined by implementing the TypeRegistryConfigurer.

There is slightly different way of using it now, example:

Sample gherkin step:

And I update ADDRESS tab data in building form
  | Input         | Value        |
  | Building name | New name     |
  | Ref           | Some ref     |

Step implementation:

@And("^some test step$")
public void someTestStep(DataTable table)
{
    List<List<String>> data = table.asLists(String.class);
    String buildingName = data.get(1).get(1);
    String reference = data.get(2).get(1);
}
Signification answered 9/4, 2019 at 13:24 Comment(9)
Right thanks. Could you possibly show me an example of how I'd fix my step definition above? for entering the login details?Fauve
I've tried the new format but it stops the 'for (User user : users)' line below it from workingFauve
Probably because I posted example of list of Strings, not Users as you did in your question.Signification
No I changed it to User but still no luckFauve
Try to create User 'manually' based on variables retrieved from the table just like I did, as a Strings, and use those two retrieved Strings to create User, and insert it into list of users. Saying that it breaks 'for (User user : users)' does not make sense, if you are using correct types everywhere. You might want to paste your code now on pastebin and I will review it.Signification
Here it is on paste bin. Fyi know this isn't correct I'm just not sure what to change - pastebin.com/miGi8YCiFauve
As I said in previous response, here's correct way of doing that: pastebin.com/BKzC0LSNSignification
Yep this is working now. Thank you very very much for your helpFauve
Please accept my answer if it was correct, regards.Signification
H
1

You are trying to convert a io.Cucumber.DataTable into a list of Strings, however your DataTable contains 2 columns. Using the asList() method only works on DataTables which have 1 column, hence the error message indicating that the table is too wide to convert.

You can convert your Datatable with 2 columns by using the asLists method:

List<List> list = dt.asLists(String.class);

System.out.println("Username - " + list.get(0).get(0));

System.out.println("Password - " + list.get(0).get(1));

more details: Cucumber: Can't convert DataTable to List<java.lang.String>. There was a table cell converter but the table was too wide to use it

Hobart answered 19/7, 2023 at 7:2 Comment(0)
M
0

I have created a code which will not use DataTable concept. You can update this below implementation so that you will not have any failures in your scripts in future.

CucumberUtil.java:

import java.util.HashMap;
import java.util.List;
import java.util.Map;
    
public class CucumberUtil {
//     removed this concept because of version issues in DataTable
//     public static synchronized Map<String, String> TableDictionaryConverter(DataTable table) {                    
       public static synchronized Map<String, String> TableDictionaryConverter(List<List<String>> data) {
             Map<String, String> mapTable = new HashMap<String, String>();
             for(List<String> rows: data) {
                   mapTable.put(rows.get(0), rows.get(1)); 
             }
             return mapTable;
      }

Feature:

And I enter the following login details:
 | username | cukey     |
 | password | passwoid |

Step definition:

@And("^I enter the following login details:$")
public void iEnterTheFollowingLoginDetails(List<List<String>> table) throws Throwable {

  Map<String, String> mapTable = CucumberUtil.TableDictionaryConverter(table);

  LoginPageObjeks page = new LoginPageObjeks(base.Driver);
        
  page.Login(mapTable.get("username"), mapTable.get("password"));
        
  Thread.sleep(2000);

  }
}
Magaretmagas answered 18/3, 2020 at 12:26 Comment(1)
Please edit your answer so that only the code is formatted as codeTrue

© 2022 - 2024 — McMap. All rights reserved.