Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

codeceptjs

Package Overview
Dependencies
Maintainers
1
Versions
235
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

codeceptjs - npm Package Compare versions

Comparing version 1.3.3 to 1.4.0

docs/plugins.md

1

bin/codecept.js

@@ -92,2 +92,3 @@ #!/usr/bin/env node

.option('--tests', 'run only JS test files and skip features')
.option('-p, --plugins <k=v,k2=v2,...>', 'enable plugins, comma-separated')

@@ -94,0 +95,0 @@ // mocha options

@@ -0,4 +1,16 @@

## 1.4.0
* [**Allure Reporter Integration**](https://codecept.io/reports/#allure). Full inegration with Allure Server. Get nicely looking UI for tests,including steps, nested steps, and screenshots. Thanks **Natarajan Krishnamurthy @krish** for sponsoring this feature.
* [Plugins API introduced](https://codecept.io/hooks/#plugins). Create custom plugins for CodeceptJS by hooking into event dispatcher, and using promise recorder.
* **Official [CodeceptJS plugins](https://codecept.io/plugins) added**:
* **`stepByStepReport` - creates nicely looking report to see test execution as a slideshow**. Use this plugin to debug tests in headless environment without recording a video.
* `allure` - Allure reporter added as plugin.
* `screenshotOnFail` - saves screenshot on fail. Replaces similar functionality from helpers.
* `retryFailedStep` - to rerun each failed step.
* [Puppeteer] Fix `executeAsyncScript` unexpected token by @jonathanz
* Added `override` option to `run-multiple` command by @svarlet
## 1.3.3
* Added `initGLobals()` function to API of [custom runner](https://codecept.io/hooks/#custom-runner).
* Added `initGlobals()` function to API of [custom runner](https://codecept.io/hooks/#custom-runner).

@@ -5,0 +17,0 @@ ## 1.3.2

@@ -123,2 +123,14 @@ # Advanced Usage

For Visual Studio Code, add the following configuration in launch.json:
```json
{
"type": "node",
"request": "launch",
"name": "codeceptjs",
"args": ["run", "--grep", "@your_test_tag"],
"program": "${workspaceFolder}/node_modules/.bin/codeceptjs"
}
```
## Parallel Execution

@@ -125,0 +137,0 @@

@@ -39,2 +39,10 @@ # Codecept

## initGlobals
Creates global variables
**Parameters**
- `dir` **Any**
## loadTests

@@ -41,0 +49,0 @@

@@ -26,2 +26,3 @@ # Container

- `newSupport` **Any**
- `newPlugins`

@@ -49,2 +50,10 @@ ## create

## plugins
Get all plugins
**Parameters**
- `name` **[string]**
## support

@@ -51,0 +60,0 @@

8

docs/api/output.md

@@ -50,10 +50,2 @@ # debug

# stepExecutionTime
Print a step execution time
**Parameters**
- `step`
# success

@@ -60,0 +52,0 @@

@@ -1470,16 +1470,3 @@ const requireg = require('requireg');

async _failed(test) {
const promisesList = [];
if (withinStatus !== false) promisesList.push(this._withinEnd());
if (!this.options.disableScreenshots) {
let fileName = clearString(test.title);
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`);
if (this.options.uniqueScreenshotNames) {
const uuid = test.uuid || test.ctx.test.uuid;
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`;
} else {
fileName += '.failed.png';
}
promisesList.push(this.saveScreenshot(fileName, true));
}
return Promise.all(promisesList);
if (withinStatus !== false) await this._withinEnd();
}

@@ -1486,0 +1473,0 @@

@@ -51,3 +51,3 @@ # Puppeteer

#### Example #2: Wait for DOMContentLoaded event and 0 netowrk connections
#### Example #2: Wait for DOMContentLoaded event and 0 network connections

@@ -60,3 +60,3 @@ ```json

"restart": false,
"waitForNavigation": "networkidle0",
"waitForNavigation": [ "domcontentloaded", "networkidle0" ],
"waitForAction": 500

@@ -63,0 +63,0 @@ }

@@ -170,6 +170,53 @@ # Hooks

## Plugins
Plugins allow to use CodeceptJS internal API to extend functionality. Use internal event dispatcher, container, output, promise recorder, to create your own reporters, test listeners, etc.
CodeceptJS includes [built-in plugins](https://codecept.io/plugins/) which extend basic functionality and can be turned on and off on purpose. Taking them as [examples](https://github.com/Codeception/CodeceptJS/tree/master/lib/plugin) you can develop your custom plugins.
A plugin is a basic JS module returning a function. Plugins can have individual configs which are passed into this function:
```js
const defaultConfig = {
someDefaultOption: true
}
module.exports = function(config) {
config = Object.assign(defaultConfig, config);
// do stuff
}
```
Plugin can register event listeners or hook into promise chain with recorder. See [API reference](https://github.com/Codeception/CodeceptJS/tree/master/lib/helper).
To enable your custom plugin in config add it to `plugins` section. Specify path to node module using `require`.
```js
"plugins": {
"myPlugin": {
"require": "./path/to/my/module",
"enabled": true
}
}
```
* `require` - specifies relative path to a plugin file. Path is relative to config file.
* `enabled` - to enable this plugin.
If a plugin is disabled (`enabled` is not set or false) this plugin can be enabled from command line:
```
./node_modules/.bin/codeceptjs run --plugin myPlugin
```
Several plugins can be enabled as well:
```
./node_modules/.bin/codeceptjs run --plugin myPlugin,allure
```
## Custom Hooks
To extend internal CodeceptJS functionality you can use hooks.
CodeceptJS provides API to connect to its internal event dispatcher, container, output, promise recorder, so you could hook into it to create your own reporters, test listeners, etc.
*(deprecated, use [plugins](#plugins))*

@@ -186,6 +233,8 @@ Hooks are JavaScript files same as for bootstrap and teardown, which can be registered inside `hooks` section of config. Unlike `bootstrap` you can have multiple hooks registered:

Inside those JS files you can use CodeceptJS API to access its internals.
Inside those JS files you can use CodeceptJS API (see below) to access its internals.
## API
**Use local CodeceptJS installation to get access to `codeceptjs` module**
CodeceptJS provides an API which can be loaded via `require('codeceptjs')` when CodeceptJS is installed locally.

@@ -206,15 +255,2 @@ These internal objects are available:

### Config
CodeceptJS config can be accessed from `require('codeceptjs').config.get()`:
```js
let config = require('codeceptjs').config.get();
if (config.myKey == 'value') {
// run hook
}
```
### Event Listeners

@@ -363,2 +399,5 @@

let UserPage = container.support('UserPage');
// get all registered plugins
let plugins = container.plugins();
```

@@ -387,2 +426,15 @@

### Config
CodeceptJS config can be accessed from `require('codeceptjs').config.get()`:
```js
let config = require('codeceptjs').config.get();
if (config.myKey == 'value') {
// run hook
}
```
## Custom Runner

@@ -403,8 +455,8 @@

// initialize codeceptjs in current dir
codecept.initGlobals(__dirname);
// create helpers, support files, mocha
Container.create(config, opts);
// initialize codeceptjs in current dir
codecept.initGlobals(__dirname);
// initialize listeners

@@ -411,0 +463,0 @@ codecept.bootstrap();

@@ -106,2 +106,27 @@ # Mobile Testing

## BrowserStack Configuration
If you wish to use BrowserStack's [Automated Mobile App Testing](https://www.browserstack.com/app-automate) platform. Configure the Appium helper like this:
```js
"helpers": {
"Appium":
"app": "bs://<hashed app-id>",
"host": "hub-cloud.browserstack.com",
"port": 4444,
"user": "BROWSERSTACK_USER",
"key": "BROWSERSTACK_KEY",
"device": "iPhone 7"
}
```
Here is the full list of [capabilities](https://www.browserstack.com/app-automate/capabilities).
You need to upload your Android app (.apk) or iOS app (.ipa) to the BrowserStack servers using the REST API before running your tests. The App URL (`bs://hashed appid`) is returned in the response of this call.
```sh
curl -u "USERNAME:ACCESS_KEY" \
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
-F "file=@/path/to/app/file/Application-debug.apk"
```
## Writing a Test

@@ -108,0 +133,0 @@

@@ -72,3 +72,3 @@ # Robust Chrome Testing with Puppeteer

WHen a test runs faster than application it is recommended to increase `waitForAction` config value.
When a test runs faster than application it is recommended to increase `waitForAction` config value.
It will wait for a small amount of time (100ms) by default after each user action is taken.

@@ -155,3 +155,3 @@

In case some actions should be taken inside one element (a container or modal window) you can use `within` block to narrow the scope.
Please take a not that you can't use within inside another within in Puppeteer helper:
Please take a note that you can't use within inside another within in Puppeteer helper:

@@ -201,2 +201,2 @@ ```js

Yes, also the [demo project is available on GitHub](https://github.com/DavertMik/codeceptjs-todomvc-puppeteer)
Yes, also the [demo project is available on GitHub](https://github.com/DavertMik/codeceptjs-todomvc-puppeteer)
# Reporters
## Cli (default)
## Cli
(default)
By default CodeceptJS provides cli reporter with console output.

@@ -84,2 +86,57 @@ Test names and failures will be printed to screen.

## Allure
(recommended)
[Allure reporter](http://allure.qatools.ru/#) is a tool to store and display test reports.
It provides nice web UI which contains all important information on test execution.
CodeceptJS has built-in support for Allure reports. Inside reports you will have all steps, substeps and screenshots.
![](https://user-images.githubusercontent.com/220264/45676511-8e052800-bb3a-11e8-8cbb-db5f73de2add.png)
*Disclaimer: Allure is a standalone tool. Please refer to [Allure documentation](https://docs.qameta.io/allure/) to learn more about using Allure reports.*
Allure requires **Java 8** to work. Then Allure can be installed via NPM:
```
npm install -g allure-commandline --save-dev
```
Add [Allure plugin](https://codecept.io/plugins/#allure) in config under `plugins` section.
```js
"plugins": {
"allure": {
}
}
```
Run tests with allure plugin enabled:
```
codeceptjs run --plugin allure
```
(optionally) To enable allure plugin permanently include `"enabled": true` into plugin config:
```js
"plugins": {
"allure": {
"enabled": true
}
}
```
Launch Allure server and see the report like on a screenshot above:
```
allure serve output
```
Allure reporter aggregates data from other plugins like [*stepByStepReport*](https://codecept.io/plugins/#stepByStepReport) and [*screenshotOnFail*](https://codecept.io/plugins/#screenshotOnFail)
## XML

@@ -86,0 +143,0 @@

@@ -66,4 +66,6 @@ const Step = require('./step');

recorder.add(task, () => {
event.emit(event.step.started, step);
step.startTime = Date.now();
if (!step.startTime) { // step can be retries
event.emit(event.step.started, step);
step.startTime = Date.now();
}
return val = step.run(...args);

@@ -70,0 +72,0 @@ });

@@ -137,2 +137,3 @@ const fsPath = require('path');

}
event.emit(event.all.before, this);
mocha.run(() => {

@@ -139,0 +140,0 @@ const done = () => {

@@ -17,3 +17,3 @@ const {

const childOpts = {};
const copyOptions = ['steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'debug'];
const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'debug'];

@@ -20,0 +20,0 @@ // codeceptjs run:multiple smoke:chrome regression:firefox - will launch smoke run in chrome and regression in firefox

@@ -37,3 +37,2 @@ const getConfig = require('./utils').getConfig;

if (err) throw new Error(`Error while running bootstrap file :${err}`);
event.emit(event.all.before, this);
codecept.loadTests();

@@ -40,0 +39,0 @@ codecept.run(test);

@@ -16,2 +16,7 @@ const fs = require('fs');

gherkin: {},
plugins: {
screenshotOnFail: {
enabled: true, // will be disabled by default in 2.0
},
},
};

@@ -18,0 +23,0 @@

@@ -10,2 +10,3 @@ const path = require('path');

support: {},
plugins: {},
mocha: {},

@@ -35,2 +36,3 @@ translation: {},

container.support = createSupportObjects(config.include || {});
container.plugins = createPlugins(config.plugins || {}, opts);
if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []);

@@ -40,2 +42,15 @@ }

/**
* Get all plugins
*
* @api
* @param {string} [name]
*/
static plugins(name) {
if (!name) {
return container.plugins;
}
return container.plugins[name];
}
/**
* Get all support objects or get support object by name

@@ -100,5 +115,6 @@ *

*/
static clear(newHelpers, newSupport) {
static clear(newHelpers, newSupport, newPlugins) {
container.helpers = newHelpers || {};
container.support = newSupport || {};
container.plugins = newPlugins || {};
container.translation = loadTranslation();

@@ -194,2 +210,29 @@ }

function createPlugins(config, options = {}) {
const plugins = {};
const enabledPluginsByOptions = (options.plugins || '').split(',');
for (const pluginName in config) {
if (!config[pluginName]) config[pluginName] = {};
if (!config[pluginName].enabled && (enabledPluginsByOptions.indexOf(pluginName) < 0)) {
continue; // plugin is disabled
}
let module;
try {
if (config[pluginName].require) {
module = config[pluginName].require;
if (module.startsWith('.')) { // local
module = path.resolve(global.codecept_dir, module); // custom plugin
}
} else {
module = `./plugin/${pluginName}`;
}
plugins[pluginName] = require(module)(config);
} catch (err) {
throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}`);
}
}
return plugins;
}
function getSupportObject(config, name) {

@@ -196,0 +239,0 @@ const module = config[name];

const container = require('./container');
const debug = require('./output').debug;
const output = require('./output');

@@ -151,7 +151,7 @@ /**

debug(msg) {
debug(msg);
output.debug(msg);
}
debugSection(section, msg) {
debug(`[${section}] ${msg}`);
output.debug(`[${section}] ${msg}`);
}

@@ -158,0 +158,0 @@ }

@@ -1057,16 +1057,3 @@ const requireg = require('requireg');

async _failed(test) {
const promisesList = [];
if (withinStatus !== false) promisesList.push(this._withinEnd());
if (!this.options.disableScreenshots) {
let fileName = clearString(test.title);
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`);
if (this.options.uniqueScreenshotNames) {
const uuid = test.uuid || test.ctx.test.uuid;
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`;
} else {
fileName += '.failed.png';
}
promisesList.push(this.saveScreenshot(fileName, true));
}
return Promise.all(promisesList);
if (withinStatus !== false) await this._withinEnd();
}

@@ -1073,0 +1060,0 @@

@@ -270,21 +270,2 @@ let EC;

await this._withinEnd();
if (this.options.disableScreenshots) return;
let fileName = clearString(test.title);
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`);
if (this.options.uniqueScreenshotNames) {
const uuid = test.uuid || test.ctx.test.uuid;
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`;
} else {
fileName += '.failed.png';
}
return this.saveScreenshot(fileName, true).catch((err) => {
if (err &&
err.type &&
err.type === 'RuntimeError' &&
err.message &&
(err.message.indexOf('was terminated due to') > -1 || err.message.indexOf('no such window: target window already closed') > -1)
) {
this.isRunning = false;
}
});
}

@@ -291,0 +272,0 @@

@@ -81,3 +81,3 @@ const requireg = require('requireg');

*
* #### Example #2: Wait for DOMContentLoaded event and 0 netowrk connections
* #### Example #2: Wait for DOMContentLoaded event and 0 network connections
*

@@ -90,3 +90,3 @@ * ```json

* "restart": false,
* "waitForNavigation": "networkidle0",
* "waitForNavigation": [ "domcontentloaded", "networkidle0" ],
* "waitForAction": 500

@@ -190,3 +190,3 @@ * }

retries: 3,
when: err => err.message.indexOf('Cannot find context with specified id') > -1,
when: err => err.message.indexOf('context') > -1, // ignore context errors
});

@@ -1178,3 +1178,3 @@ if (this.options.restart && !this.options.manualStart) return this._startBrowser();

const args = Array.from(arguments);
const fn = eval(args.shift()); // eslint-disable-line no-eval
const fn = eval(`(${args.shift()})`); // eslint-disable-line no-eval
return new Promise((done) => {

@@ -1337,15 +1337,3 @@ args.push(done);

async _failed(test) {
const promisesList = [];
await this._withinEnd();
if (!this.options.disableScreenshots) {
let fileName = clearString(test.title);
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`);
if (this.options.uniqueScreenshotNames) {
const uuid = test.uuid || test.ctx.test.uuid;
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`;
} else {
fileName += '.failed.png';
}
await this.saveScreenshot(fileName, true);
}
}

@@ -1352,0 +1340,0 @@

@@ -29,2 +29,13 @@ const getParamNames = require('./utils').getParamNames;

function loadCustomHook(module) {
try {
if (module.startsWith('.')) {
module = fsPath.resolve(global.codecept_dir, module); // custom plugin
}
return require(module);
} catch (err) {
throw new Error(`Could not load hook from module '${module}':\n${err.message}`);
}
}
function callSync(callable, done) {

@@ -31,0 +42,0 @@ if (isAsync(callable)) {

@@ -32,4 +32,6 @@ const { Parser } = require('gherkin');

metaStep.actor = step.keyword.trim();
metaStep.humanize = () => step.text;
const setMetaStep = step => step.metaStep = metaStep;
const setMetaStep = (step) => {
if (step.metaStep) step = step.metaStep; // assign metastep to metastep for nested steps
step.metaStep = metaStep;
};
const fn = matchStep(step.text);

@@ -36,0 +38,0 @@ if (step.argument) {

const colors = require('chalk');
const symbols = require('mocha/lib/reporters/base').symbols;
const figures = require('figures');

@@ -26,3 +26,3 @@ const styles = {

*/
level: (level) => {
level(level) {
if (level !== undefined) outputLevel = level;

@@ -36,3 +36,3 @@ return outputLevel;

*/
process: (process) => {
process(process) {
if (process) outputProcess = `[${process}]`;

@@ -45,5 +45,5 @@ return outputProcess;

*/
debug: (msg) => {
debug(msg) {
if (outputLevel >= 2) {
print(' '.repeat(this.stepShift), styles.debug(`> ${msg}`));
print(' '.repeat(this.stepShift), styles.debug(truncate(`${figures.pointerSmall} ${msg}`, this.spaceShift)));
}

@@ -55,4 +55,4 @@ },

*/
log: (msg) => {
if (outputLevel >= 3) print(' '.repeat(this.stepShift), styles.log(` ${msg}`));
log(msg) {
if (outputLevel >= 3) print(' '.repeat(this.stepShift), styles.log(truncate(` ${msg}`, this.spaceShift)));
},

@@ -63,3 +63,3 @@

*/
error: (msg) => {
error(msg) {
print(styles.error(msg));

@@ -71,6 +71,10 @@ },

*/
success: (msg) => {
success(msg) {
print(styles.success(msg));
},
plugin(name, msg) {
this.debug(`<${name}> ${msg}`);
},
/**

@@ -85,3 +89,4 @@ * Print a step

if (outputLevel < 2) return;
stepLine = ' '.repeat(2) + colors.green(stepLine);
this.stepShift += 2;
stepLine = colors.green(truncate(stepLine, this.spaceShift));
}

@@ -91,31 +96,4 @@ if (step.comment) {

}
if (step.isMetaStep && step.isMetaStep() && outputLevel === 2) {
stepLine += '\n'; // meta steps don't have execution time
}
const sym = ' ';
if (outputLevel === 2) {
newline = false;
return process.stdout.write(`${' '.repeat(this.stepShift)} ${sym} ${stepLine}`);
}
print(' '.repeat(this.stepShift), `${sym} ${stepLine}`);
},
/**
* Print a step execution time
*/
stepExecutionTime(step) {
if (outputLevel < 2) return;
if (!step) return;
const time = (step.endTime - step.startTime) / 1000;
if (Number.isNaN(time)) return;
if (outputLevel === 2) {
newline = true;
process.stdout.write(`${styles.debug(` ("${time} sec")\n`)}`);
return;
}
this.log(`Step finished in ${time} sec`);
print(' '.repeat(this.stepShift), truncate(stepLine, this.spaceShift));
},

@@ -132,12 +110,12 @@

test: {
started: (test) => {
started(test) {
print(` ${colors.magenta.bold(test.title)}`);
},
passed: (test) => {
print(` ${colors.green.bold(symbols.ok)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
passed(test) {
print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
},
failed: (test) => {
print(` ${colors.red.bold(symbols.err)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
failed(test) {
print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
},
skipped: (test) => {
skipped(test) {
print(` ${colors.yellow.bold('S')} ${test.title}`);

@@ -148,11 +126,9 @@ },

scenario: {
started: (test) => {
},
passed: (test) => {
print(` ${colors.green.bold(`${symbols.ok} OK`)} ${colors.grey(`in ${test.duration}ms`)}`);
started(test) {},
passed(test) {
print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`);
print();
},
failed: (test) => {
print(` ${colors.red.bold(`${symbols.err} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`);
failed(test) {
print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`);
print();

@@ -162,7 +138,7 @@ },

say: (message) => {
say(message) {
if (outputLevel >= 1) print(` ${colors.cyan.bold(message)}`);
},
result: (passed, failed, skipped, duration) => {
result(passed, failed, skipped, duration) {
let style = colors.bgGreen;

@@ -195,7 +171,15 @@ let msg = ` ${passed || 0} passed`;

}
console.log.apply(this, msg);
}
function ind() {
return ' ';
function truncate(msg, gap = 0) {
if (msg.indexOf('\n') > 0) {
return msg; // don't cut multi line steps
}
const width = (process.stdout.columns || 200) - gap - 1;
if (msg.length > width) {
msg = msg.substr(0, width - 1) + figures.ellipsis;
}
return msg;
}

@@ -8,3 +8,3 @@ const Base = require('mocha/lib/reporters/base');

const cursor = Base.cursor;
let currentMetaStep = null;
let currentMetaStep = [];

@@ -31,2 +31,9 @@ class Cli extends Base {

if (showSteps) {
const Containter = require('../container');
output.print();
output.print(output.styles.debug(`Enabled Helpers: ${Object.keys(Containter.helpers()).join(', ')}`));
output.print(output.styles.debug(`Enabled Plugins: ${Object.keys(Containter.plugins()).join(', ')}`));
}
runner.on('start', () => {

@@ -63,3 +70,3 @@ console.log();

runner.on('test', (test) => {
currentMetaStep = '';
currentMetaStep = [];
if (test.steps) {

@@ -71,14 +78,19 @@ output.test.started(test);

event.dispatcher.on(event.step.started, (step) => {
if (step.metaStep) {
if (currentMetaStep !== step.metaStep.toString()) {
output.step(step.metaStep);
currentMetaStep = step.metaStep.toString();
output.stepShift = 3;
const printMetaStep = (metaStep) => {
if (!metaStep) return currentMetaStep.shift();
if (currentMetaStep.indexOf(metaStep.toString()) >= 0) return; // step is the same
if (metaStep.metaStep) {
printMetaStep(metaStep.metaStep);
}
} else {
currentMetaStep = '';
}
currentMetaStep.unshift(metaStep.toString());
output.step(metaStep);
};
printMetaStep(step.metaStep);
output.step(step);
});
event.dispatcher.on(event.step.passed, step => output.stepExecutionTime(step));
event.dispatcher.on(event.step.failed, step => output.stepExecutionTime(step));
event.dispatcher.on(event.step.finished, (step) => {
output.stepShift = 0;
});
}

@@ -106,6 +118,8 @@

// remove error message from stacktrace
const lines = err.stack.split('\n');
lines.splice(0, 1);
err.stack = lines.join('\n');
if (err.stack) {
// remove error message from stacktrace
const lines = err.stack.split('\n');
lines.splice(0, 1);
err.stack = lines.join('\n');
}
}

@@ -112,0 +126,0 @@ if (output.level() < 3) {

@@ -1,8 +0,7 @@

const Config = require('./config');
const path = require('path');
const STACK_LINE = 4;
// using support objetcs for metastep detection
// deprecated
let support;
const STACK_LINE = 3;
/**

@@ -40,5 +39,5 @@ * Each command in test executed through `I.` object is wrapped in Step.

result = this.helper[this.helperMethod].apply(this.helper, this.args);
this.status = 'success';
this.setStatus('success');
} catch (err) {
this.status = 'failed';
this.setStatus('failed');
throw err;

@@ -49,2 +48,7 @@ }

setStatus(status) {
this.status = status;
if (this.metaStep) this.metaStep.setStatus(status);
}
humanize() {

@@ -86,3 +90,2 @@ return this.name

const lines = this.stack.split('\n');
// 3rd line is line where step has been called in test
if (lines[STACK_LINE]) return lines[STACK_LINE].trim();

@@ -112,2 +115,6 @@ return '';

humanize() {
return this.name;
}
setTrace() {

@@ -124,3 +131,28 @@ }

function detectMetaStep(stack) {
if (!support) loadSupportObjects(); // deprecated
for (let i = STACK_LINE; i < stack.length; i++) {
const line = stack[i].trim();
if (isTest(line) || isBDD(line)) break;
const fnName = line.match(/^at (\w+)\.(\w+)\s\(/);
if (!fnName) continue;
if (fnName[1] === 'Generator') return; // don't track meta steps inside generators
if (fnName[1] === 'recorder') return; // don't track meta steps inside generators
if (fnName[1] === 'Object') {
// detect PO name from includes
for (const name in support) {
const file = support[name];
if (line.indexOf(file) > -1) {
return new MetaStep(`${name}:`, fnName[2]);
}
}
}
return new MetaStep(`${fnName[1]}:`, fnName[2]);
}
}
function loadSupportObjects() {
const Config = require('./config');
const path = require('path');
support = Config.get('include', {});

@@ -135,29 +167,8 @@ if (support) {

function detectMetaStep(stack) {
if (!support) loadSupportObjects();
for (let i = STACK_LINE; i < stack.length; i++) {
const line = stack[i].trim();
if (!isTest(line)) continue;
// console.log('aaa');
if (i === STACK_LINE) return;
for (const name in support) {
const file = support[name];
const caller = stack[i - 1].trim();
// const caller = stack[i-1].trim().match(/^at (\w+\.\w+)\s\(/);
if (caller.indexOf(file) > -1) {
// console.log('YEAAAH!!!!', name);
let fnName = caller.match(/^at \w+\.(.*?)\(/);
if (fnName[1]) {
fnName = fnName[1].trim();
}
return new MetaStep(name, fnName);
}
}
return;
}
}
function isTest(line) {
return line.trim().match(/^at Test\.Scenario/);
}
function isBDD(line) {
return line.trim().match(/^at (Given|When|Then)/);
}

@@ -256,1 +256,15 @@ const fs = require('fs');

};
module.exports.deleteDir = function (dir_path) {
if (fs.existsSync(dir_path)) {
fs.readdirSync(dir_path).forEach(function (entry) {
const entry_path = path.join(dir_path, entry);
if (fs.lstatSync(entry_path).isDirectory()) {
this.deleteDir(entry_path);
} else {
fs.unlinkSync(entry_path);
}
});
fs.rmdirSync(dir_path);
}
};

@@ -5,2 +5,3 @@ const output = require('./output');

const event = require('./event');
const Step = require('./step');
const { isGenerator, isAsyncFunction } = require('./utils');

@@ -14,6 +15,7 @@ const resumeTest = require('./scenario').resumeTest;

return recorder.add('register within wrapper', () => {
const metaStep = new Step.MetaStep('Within', `"${locator}"`);
const defineMetaStep = step => step.metaStep = metaStep;
recorder.session.start('within');
output.stepShift = 2;
if (output.level() > 0) output.print(` Within ${output.colors.yellow.bold(locator)}:`);
event.dispatcher.on(event.step.before, defineMetaStep);

@@ -25,2 +27,3 @@ Object.keys(helpers).forEach((helper) => {

const finalize = () => {
event.dispatcher.removeListener(event.step.before, defineMetaStep);
recorder.add('Finalize session within session', () => {

@@ -27,0 +30,0 @@ output.stepShift = 1;

{
"name": "codeceptjs",
"version": "1.3.3",
"version": "1.4.0",
"description": "Modern Era Acceptance Testing Framework for NodeJS",

@@ -39,7 +39,9 @@ "keywords": [

"dependencies": {
"allure-js-commons": "^1.3.2",
"chalk": "^1.1.3",
"commander": "^2.16.0",
"commander": "^2.18.0",
"css-to-xpath": "^0.1.0",
"cucumber-expressions": "^6.0.1",
"escape-string-regexp": "^1.0.3",
"figures": "^2.0.0",
"fn-args": "^3.0.0",

@@ -58,3 +60,3 @@ "gherkin": "^5.1.0",

"@types/inquirer": "^0.0.35",
"@types/node": "^8.10.21",
"@types/node": "^8.10.29",
"chai": "^3.4.1",

@@ -66,3 +68,3 @@ "chai-as-promised": "^5.2.0",

"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-import": "^2.14.0",
"faker": "^4.1.0",

@@ -75,4 +77,4 @@ "gulp": "^3.9.1",

"nyc": "^11.9.0",
"protractor": "^5.3.2",
"puppeteer": "^1.6.0",
"protractor": "^5.4.1",
"puppeteer": "^1.8.0",
"rosie": "^1.6.0",

@@ -83,3 +85,3 @@ "sinon": "^1.17.2",

"unirest": "^0.5.1",
"webdriverio": "^4.13.1",
"webdriverio": "^4.13.2",
"xmldom": "^0.1.27",

@@ -86,0 +88,0 @@ "xpath": "0.0.27"

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc