Press "Enter" to skip to content

Compare the 4 main methods from the Cucumber DataTable class and when to use them

Vladimir Simonovski

A drief info

Before I dive into the 4 main DataTable class methods for handling multiple input values per one step provided from the Cucumber framework, I’ll explain what is the purpose of the Cucumber DataTable class.

DataTable class

DataTable class from Cucumber is the class where all the table-related methods are included. The data table itself is beneficial if we want to pass a list of data into one single step instead of having a separate stepper separate value. The data table can be used for passing multiple input values, for asserting multiple values, or maybe click on multiple elements sequentially as part of one scenario flow. Nevertheless, it reduces the number of steps, the scenario still looks understandable to everyone and the implementation code is reduced.

hashes()

This method returns an array of objects. Each of the data table rows is converted to an object. Mostly used when we have headers in our data tables.

Let’s say we want to convert all of the values from www.qamind.com‘s archive widget that contains all the months where a blog was posted. The scenario will look like this: (see a more detailed explanation for the background step and more in the Selenium & Cucumber framework from scratch blog post):

    Background: QAMIND is open and cache and cookies are deleted
        Given QAMIND is opened in Chrome
            And Cache and cookies are removed and window is maximized
            And Home Page is visible

    Scenario: Print all months from the archives widget
        Then The months from the archive widget are printed
            | number | month         |
            | 1      | July 2021     |
            | 2      | June 2021     |
            | 3      | May 2021      |
            | 4      | April 2021    |
            | 5      | March 2021    |
            | 6      | February 2021 |
            | 7      | January 2021  |
            | 8      | December 2020 |
            | 9      | November 2020 |
            | 10     | October 2020  |
            | 11     | August 2020   |
            | 12     | July 2020     |
            | 13     | June 2020     |
            | 14     | May 2020      |

Then(
    "The months from the archive widget are printed",
    async (dataTable: DataTable): Promise<void> => {
        console.log(dataTable.hashes());
    },
);

The step implementation will convert the values and will print:

[                                         
  { number: '1', month: 'July 2021' },    
  { number: '2', month: 'June 2021' },    
  { number: '3', month: 'May 2021' },     
  { number: '4', month: 'April 2021' },   
  { number: '5', month: 'March 2021' },   
  { number: '6', month: 'February 2021' },
  { number: '7', month: 'January 2021' }, 
  { number: '8', month: 'December 2020' },
  { number: '9', month: 'November 2020' },
  { number: '10', month: 'October 2020' },
  { number: '11', month: 'August 2020' }, 
  { number: '12', month: 'July 2020' },   
  { number: '13', month: 'June 2020' },   
  { number: '14', month: 'May 2020' }     
]                                         

Since this would be an expected data, you can easily fetch every single month by locating, let’s say, by <ul> <li>, and then you can iterate through it and compare it with the actual data above.

rows()

This method returns a 2D array from the table but not including the first row (in most of the cases, the first row is the place where the headers are included) where each row is an array. Let’s take another example. Let’s say we want to assert the values from the data table below:

| topic                  |
| Accessibility Testing  |
| Agile Testing          |
| API Testing            |
| Automation Testing     |
| E2E Testing            |
| Functional Testing     |
| GUI Testing            |
| Manual Testing         |
| Non-Functional Testing |                          

In the step implementation we can write something like:

const testingArray = new Array<string>(); // creating an array
dataTable.rows().forEach((row) => {
    testingArray.push(row.toString()); // iterate & push each row value to the array from the table
});

const expectedTestingTopics = new Array<string>(); // create the expected values array
for (const value of testingArray) {
    expectedTestingTopics.push(value); // loop trought the array & add the values into the new array
}

const actualTestingTopics = await homePage.getTestingTopics(); // fetch the actual elements and return an array containing them

iterateActualAndCheckIfEqualsExpected(
    actualTestingTopics,
    expectedTestingTopics,
); // iterate trough both of them and assert each value from actual vs eexpected array

raw()

This method returns a 2D array from the table including the first row. This is practically the same but it returns the headers from the table(console.log(dataTable.raw())). Taking the first example, the output would be:

[
  [ 'number', 'month' ],
  [ '1', 'July 2021' ],
  [ '2', 'June 2021' ],
  [ '3', 'May 2021' ],
  [ '4', 'April 2021' ],
  [ '5', 'March 2021' ],
  [ '6', 'February 2021' ],
  [ '7', 'January 2021' ],
  [ '8', 'December 2020' ],
  [ '9', 'November 2020' ],
  [ '10', 'October 2020' ],
  [ '11', 'August 2020' ],
  [ '12', 'July 2020' ],
  [ '13', 'June 2020' ],
  [ '14', 'May 2020' ]
]

rowsHash()

This method returns an object from the data table(console.log(dataTable.rowsHash())). Each row is converted to a key-value pair. This method can only be called when we have a table with exactly two columns. It is very beneficial to use when we don’t know the total number of properties upfront and we usually work with dynamic data. Taking the same example from above, the output would look like this:

{
  '1': 'July 2021',
  '2': 'June 2021',
  '3': 'May 2021',
  '4': 'April 2021',
  '5': 'March 2021',
  '6': 'February 2021',
  '7': 'January 2021',
  '8': 'December 2020',
  '9': 'November 2020',
  '10': 'October 2020',
  '11': 'August 2020',
  '12': 'July 2020',
  '13': 'June 2020',
  '14': 'May 2020',
  number: 'month'
}

If we add another column, we would get an error saying:

Error: rowsHash can only be called on a data table where all rows have exactly two columns

Conclusion

All of the 4 methods from the Cucumber DataTable class are valuable and will make your life easier when you work with a large number of input values or verifying various different examples for a particular scenario. Whichever you choose, depends on the scenario structure itself and on agreed implementation strategies across the organizations.

Share This Post


Latest Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.