Skip to content

Commit

Permalink
FEATURE: add new public api, tests and docs. Typed dataTableArgument (#…
Browse files Browse the repository at this point in the history
…3047)

* FEATURE: add new public api tests and docs. Typed dataTableArgument

* DOCS: fix and updated docs due to npm run docs updates.

* FIX: DataTableArgument type def
  • Loading branch information
EgorBodnar authored Sep 19, 2021
1 parent 3429731 commit e4582c2
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 22 deletions.
56 changes: 55 additions & 1 deletion docs/bdd.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,10 @@ You can also use the `parse()` method to obtain an object that allow you to get
- `raw()` - returns the table as a 2-D array
- `rows()` - returns the table as a 2-D array, without the first row
- `hashes()` - returns an array of objects where each row is converted to an object (column header is the key)
- `rowsHash()` - returns an object where each row corresponds to an entry(first column is the key, second column is the value)
- `transpose()` - transpose the data, returns nothing. To work with the transposed table use the methods above.

If we use hashes() with the previous exemple :
If we use hashes() with the previous example :

```js
Given('I have products in my cart', (table) => { // eslint-disable-line
Expand All @@ -281,7 +283,59 @@ Given('I have products in my cart', (table) => { // eslint-disable-line
}
});
```
Examples of tables using:

```gherkin
Given I have a short employees card
| Harry | Potter |
| Chuck | Norris |
```
```js
const { DataTableArgument } = require('codeceptjs');
//...
Given('I have a short employees card', (table) => {
const dataTableArgument = new DataTableArgument(table);
const raw = dataTableArgument.raw();
// row = [['Harry', 'Potter'], ['Chuck', 'Norris']]
dataTableArgument.transpose();
const transposedRaw = dataTableArgument.raw();
// transposedRaw = [['Harry', 'Chuck'], ['Potter', 'Norris']];
}
);
```
```gherkin
Given I have an employee card
| name | surname | position |
| Harry | Potter | Seeker |
```
```js
const { DataTableArgument } = require('codeceptjs');
//...
Given('I have an employee card', (table) => {
const dataTableArgument = new DataTableArgument(table);
const hashes = dataTableArgument.hashes();
// hashes = [{ name: 'Harry', surname: 'Potter', position: 'Seeker' }];
const rows = dataTableArgument.rows();
// rows = [['Harry', 'Potter', Seeker]];
}
);
```
```gherkin
Given I have a formatted employee card
| name | Harry |
| surname | Potter |
| position | Seeker |
```
```js
const { DataTableArgument } = require('codeceptjs');
//...
Given('I have a formatted employee card', (table) => {
const dataTableArgument = new DataTableArgument(table);
const rawHash = dataTableArgument.rowsHash();
// rawHash = { name: 'Harry', surname: 'Potter', position: 'Seeker' };
}
);
```
### Examples

In case scenarios represent the same logic but differ on data, we can use *Scenario Outline* to provide different examples for the same behavior. Scenario outline is just like a basic scenario with some values replaced with placeholders, which are filled from a table. Each set of values is executed as a different test.
Expand Down
33 changes: 15 additions & 18 deletions docs/helpers/Appium.md
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,19 @@ let email = await I.grabValueFrom('input[name=email]');

Returns **[Promise][13]<[string][4]>** attribute value

### saveScreenshot

Saves a screenshot to ouput folder (set in codecept.json or codecept.conf.js).
Filename is relative to output folder.

```js
I.saveScreenshot('debug.png');
```

#### Parameters

- `fileName` **[string][4]** file name to save.

### scrollIntoView

Scroll element into viewport.
Expand Down Expand Up @@ -1663,25 +1676,11 @@ I.saveElementScreenshot(`#submit`,'debug.png');
- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator.
- `fileName` **[string][4]** file name to save.

### saveScreenshot

Saves a screenshot to ouput folder (set in codecept.json or codecept.conf.js).
Filename is relative to output folder.

```js
I.saveScreenshot('debug.png');
```

#### Parameters

- `fileName` **[string][4]** file name to save.
- `fullPage` **[boolean][20]** (optional, `false` by default) flag to enable fullscreen screenshot mode. (optional, default `false`)

### type

Types out the given text into an active field.
To slow down typing use a second parameter, to set interval between key presses.
_Note:_ Should be used when [`fillField`][21] is not an option.
_Note:_ Should be used when [`fillField`][20] is not an option.

```js
// passing in a string
Expand Down Expand Up @@ -1919,6 +1918,4 @@ Returns **([Promise][13]<DOMRect> | [Promise][13]<[number][8]>)** Element

[19]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined

[20]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean

[21]: #fillfield
[20]: #fillfield
18 changes: 17 additions & 1 deletion docs/helpers/Puppeteer.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ This helper should be configured in codecept.json or codecept.conf.js
}
```

> Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
#### Example #5: Target URL with provided basic authentication

```js
Expand All @@ -115,7 +117,21 @@ This helper should be configured in codecept.json or codecept.conf.js
}
```

Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
#### Troubleshooting

Error Message: `No usable sandbox!`

When running Puppeteer on CI try to disable sandbox if you see that message

helpers: {
Puppeteer: {
url: 'http://localhost',
show: false,
chrome: {
args: ['--no-sandbox', '--disable-setuid-sandbox']
}
},
}

## Access From Helpers

Expand Down
2 changes: 1 addition & 1 deletion docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ Dumps code coverage from Playwright/Puppeteer after every test.

```js
plugins: {
playwrightCoverage: {
coverage: {
enabled: true
}
}
Expand Down
35 changes: 35 additions & 0 deletions lib/data/dataTableArgument.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/**
* DataTableArgument class to store the Cucumber data table from
* a step as an object with methods that can be used to access the data.
*/
class DataTableArgument {
/** @param {*} gherkinDataTable */
constructor(gherkinDataTable) {
this.rawData = gherkinDataTable.rows.map((row) => {
return row.cells.map((cell) => {
Expand All @@ -7,16 +12,25 @@ class DataTableArgument {
});
}

/** Returns the table as a 2-D array
* @returns {string[][]}
*/
raw() {
return this.rawData.slice(0);
}

/** Returns the table as a 2-D array, without the first row
* @returns {string[][]}
*/
rows() {
const copy = this.raw();
copy.shift();
return copy;
}

/** Returns an array of objects where each row is converted to an object (column header is the key)
* @returns {any[]}
*/
hashes() {
const copy = this.raw();
const header = copy.shift();
Expand All @@ -26,6 +40,27 @@ class DataTableArgument {
return r;
});
}

/** Returns an object where each row corresponds to an entry
* (first column is the key, second column is the value)
* @returns {Record<string, string>}
*/
rowsHash() {
const rows = this.raw();
const everyRowHasTwoColumns = rows.every((row) => row.length === 2);
if (!everyRowHasTwoColumns) {
throw new Error('rowsHash can only be called on a data table where all rows have exactly two columns');
}
/** @type {Record<string, string>} */
const result = {};
rows.forEach((x) => (result[x[0]] = x[1]));
return result;
}

/** Transposed the data */
transpose() {
this.rawData = this.rawData[0].map((x, i) => this.rawData.map((y) => y[i]));
}
}

module.exports = DataTableArgument;
2 changes: 2 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ module.exports = {
within: require('./within'),
/** @type {typeof CodeceptJS.DataTable} */
dataTable: require('./data/table'),
/** @type {typeof CodeceptJS.DataTableArgument} */
dataTableArgument: require('./data/dataTableArgument'),
/** @type {typeof CodeceptJS.store} */
store: require('./store'),
/** @type {typeof CodeceptJS.Locator} */
Expand Down
2 changes: 1 addition & 1 deletion lib/plugin/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function buildFileName(test, uniqueFileName) {
*
* ```js
* plugins: {
* playwrightCoverage: {
* coverage: {
* enabled: true
* }
* }
Expand Down
37 changes: 37 additions & 0 deletions test/unit/data/dataTableArgument_test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { expect } = require('chai');
const { it } = require('mocha');
const DataTableArgument = require('../../../lib/data/dataTableArgument');

describe('DataTableArgument', () => {
Expand Down Expand Up @@ -44,6 +45,27 @@ describe('DataTableArgument', () => {
],
};

const gherkinDataTableWithColumnHeader = {
rows: [
{
type: 'TableRow',
location: { line: 59, column: 13 },
cells: [
{ type: 'TableCell', location: [Object], value: 'firstName' },
{ type: 'TableCell', location: [Object], value: 'Chuck' },
],
},
{
type: 'TableRow',
location: { line: 59, column: 13 },
cells: [
{ type: 'TableCell', location: [Object], value: 'lastName' },
{ type: 'TableCell', location: [Object], value: 'Norris' },
],
},
],
};

it('should return a 2D array containing each row', () => {
const dta = new DataTableArgument(gherkinDataTable);
const raw = dta.raw();
Expand All @@ -64,4 +86,19 @@ describe('DataTableArgument', () => {
const expectedRows = [{ firstName: 'Chuck', lastName: 'Norris' }];
expect(rows).to.deep.equal(expectedRows);
});

it('transpose should transpose the gherkin data table', () => {
const dta = new DataTableArgument(gherkinDataTable);
dta.transpose();
const raw = dta.raw();
const expectedRaw = [['John', 'Chuck'], ['Doe', 'Norris']];
expect(raw).to.deep.equal(expectedRaw);
});

it('rowsHash returns an object where the keys are the first column', () => {
const dta = new DataTableArgument(gherkinDataTableWithColumnHeader);
const rawHash = dta.rowsHash();
const expectedRaw = { firstName: 'Chuck', lastName: 'Norris' };
expect(rawHash).to.deep.equal(expectedRaw);
});
});
2 changes: 2 additions & 0 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ declare const pause: typeof CodeceptJS.pause;
declare const within: typeof CodeceptJS.within;
declare const session: typeof CodeceptJS.session;
declare const DataTable: typeof CodeceptJS.DataTable;
declare const DataTableArgument: typeof CodeceptJS.DataTableArgument;
declare const codeceptjs: typeof CodeceptJS.index;
declare const locate: typeof CodeceptJS.Locator.build;
declare function inject(): CodeceptJS.SupportObject;
Expand Down Expand Up @@ -160,6 +161,7 @@ declare namespace NodeJS {
within: typeof within;
session: typeof session;
DataTable: typeof DataTable;
DataTableArgument: typeof DataTableArgument;
locate: typeof locate;
inject: typeof inject;
secret: typeof secret;
Expand Down
1 change: 1 addition & 0 deletions typings/jsdoc.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
'./lib/config.js',
'./lib/container.js',
'./lib/data/table.js',
'./lib/data/dataTableArgument.js',
'./lib/event.js',
'./lib/helper/clientscripts/nightmare.js',
'./lib/index.js',
Expand Down

0 comments on commit e4582c2

Please sign in to comment.