Skip to main content

Data Tables

Autometa sports a more sophisticated data table model than the default Cucumber.js implementation. Specifically, there are multiple table types which can be configured on a per step basis.

When a step contains a table, it will be passed to the matching definition callback according to the following rules:

  • If the Gherkin step contains a table, and none is defined in the matching definition an error will be thrown
  • If no expressions exist, then the Data Table will be injected as the first argument in the definition callback
  • If at least one expression exists, the Data Table will be the next argument passed after all expressions

The currently supported table types are:

HTable

A standard 'horizontal' table, where the first row of the table is treated as a header cell, and values can be accessed by indexing against that header

Given a step with a table
| Username | Is Admin |
| Bob | true |
| Jill | false |

VTable

A standard 'vertical' whose header cells are stacked vertically on the leftmost column

Given a step with a table
| Username | Bob | Jill |
| Is Admin | true | false |

MTable

A Matrix tyle table, where the first row and first column are both treated as headers, indexing against both will return the value of a single cell.

Given a step with a table
| | Big | Small |
| Blue | Ocean | Puddle |
| Green | Ireland | Cabbage |
## Table Value Types

By default, tables will attempt to convert their cell values into a primitive type. I.e. | 2 | will attempt to parse this cell as a number, true will become a bool etc.

To access the unconverted raw value, pass true to the end of the .get method

Given("step with table", (table) => {
const firstUsername = table.get<string>("Username", 0);
const firstAge = table.get<string>("Age", 0, true);
// ...
});

Custom Tables

It is possible to implement your own table. Simply create a class which accepts as a constructor parameter and instance of CompiledDataTable.

The compiled table contains two 2d arrays:

  • table
    • List of converted types. I.e | 2 | will become 2 not "2"
  • rawTable
    • List of unconverted types. I.e | 2 | will remain "2" not 2
import { CompiledDataTable } from "@autometa/runner";

export class MyTable {
constructor(private readonly compiledTable: CompiledDataTable) {}

get<T>(header: string, row: number, raw = false): T {
// Your get logic here
}
}

There is no common interface for what methods can be on a table, so you will need to decide your own.

Table Documents

Table documents are a way of automatically mapping a table to a js object with named properties. Only vertical (VTable) and horizontal (HTable) tables are supported for table documents.

Defining Table Documents

To declare a table document, you can create a class which extends from the return value of the static .Document method which exists on HTable and VTable.

Properties can be defined by using the respective tables static .cell method, which accepts a title for the row or column which defines the document.

import { HTable } from "@autometa/runner";

class UserTable extends HTable.Document() {
@HTable.cell("Username")
username: string;

@HTable.cell("Is Admin")
isAdmin: boolean;
}

// VTable

import { VTable } from "@autometa/runner";

class UserTable extends VTable.Document() {
@VTable.cell("Username")
username: string;

@VTable.cell("Is Admin")
isAdmin: boolean;
}

Using Table Documents

If a table type blueprint (uninstantiated class reference) passed to a Step Definition is a TableDocument, then the table will automatically be converted to an array of TableDocument instances. This array will be provided to the Step Definition callback where a table would normally be if defined.

// user.document.ts
import { HTable } from "@autometa/runner";

class UserTable extends HTable.Document() {
@HTable.cell("Username")
username: string;

@HTable.cell("Is Admin")
isAdmin: boolean;
}

// user.given.ts
Given(
"a step with a table",
(table) => {
const firstUser = table[0];
const firstUsername = firstUser.username;
const firstIsAdmin = firstUser.isAdmin;
},
UserTable
);

As documents are provided as an array, loops. maps, filters and destructuring will all work as expected.

Transformers

Transformers can be used to convert the raw value of a cell into a different type. This can be useful for converting strings into numbers, dates etc.

import { HTable } from "@autometa/runner";

class UserTable extends HTable.Document() {
@HTable.cell("Username")
username: string;

@HTable.cell("Date Of Birth", (dob) => new Date(dob))
age: Date;
}