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

golf umbrella
  • 233
  • 2
  • 4
  • 16
  • 1
    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. – Grasshopper Apr 09 '19 at 11:33
  • Just tried this. Gave me a new error - io.cucumber.datatable.UndefinedDataTableTypeException: Can't convert DataTable to List. – golf umbrella Apr 09 '19 at 12:56
  • U need to register a datatabletype in a class that implements TypeRegistryConfigurer. The transformation logic will be included in that. https://docs.cucumber.io/cucumber/configuration/ – Grasshopper Apr 09 '19 at 13:43

3 Answers3

9

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);
}
Matthewek
  • 1,519
  • 2
  • 22
  • 42
  • Right thanks. Could you possibly show me an example of how I'd fix my step definition above? for entering the login details? – golf umbrella Apr 09 '19 at 13:44
  • I've tried the new format but it stops the 'for (User user : users)' line below it from working – golf umbrella Apr 09 '19 at 13:46
  • Probably because I posted example of list of Strings, not Users as you did in your question. – Matthewek Apr 09 '19 at 14:00
  • No I changed it to User but still no luck – golf umbrella Apr 09 '19 at 14:02
  • 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. – Matthewek Apr 09 '19 at 14:09
  • Here it is on paste bin. Fyi know this isn't correct I'm just not sure what to change - https://pastebin.com/miGi8YCi – golf umbrella Apr 09 '19 at 14:24
  • As I said in previous response, here's correct way of doing that: https://pastebin.com/BKzC0LSN – Matthewek Apr 09 '19 at 14:49
  • Yep this is working now. Thank you very very much for your help – golf umbrella Apr 09 '19 at 15:04
  • Please accept my answer if it was correct, regards. – Matthewek Apr 09 '19 at 17:24
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

General Grievance
  • 4,555
  • 31
  • 31
  • 45
ItzmeSk
  • 11
  • 2
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);

  }
}
Renatas M.
  • 11,694
  • 1
  • 43
  • 62