@kronoslive/codeceptjs
Version:
Supercharged End 2 End Testing Framework for NodeJS
150 lines (135 loc) • 4.49 kB
JavaScript
const colors = require('chalk');
const readline = require('readline');
const container = require('./container');
const history = require('./history');
const store = require('./store');
const recorder = require('./recorder');
const event = require('./event');
const output = require('./output');
const { methodsOfObject } = require('./utils');
// npm install colors
let rl;
let nextStep;
let finish;
let next;
let registeredVariables = {};
/**
* Pauses test execution and starts interactive shell
*/
const pause = function (passedObject = {}) {
if (store.dryRun) return;
next = false;
// add listener to all next steps to provide next() functionality
event.dispatcher.on(event.step.after, () => {
recorder.add('Start next pause session', () => {
if (!next) return;
return pauseSession();
});
});
recorder.add('Start new session', () => pauseSession(passedObject));
};
function pauseSession(passedObject = {}) {
registeredVariables = passedObject;
recorder.session.start('pause');
if (!next) {
let vars = Object.keys(registeredVariables).join(', ');
if (vars) vars = `(vars: ${vars})`;
output.print(colors.yellow(' Interactive shell started'));
output.print(colors.yellow(' Use JavaScript syntax to try steps in action'));
output.print(colors.yellow(` - Press ${colors.bold('ENTER')} to run the next step`));
output.print(colors.yellow(` - Press ${colors.bold('TAB')} twice to see all available commands`));
output.print(colors.yellow(` - Type ${colors.bold('exit')} + Enter to exit the interactive shell`));
output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`));
}
rl = readline.createInterface(process.stdin, process.stdout, completer);
rl.on('line', parseInput);
rl.on('close', () => {
if (!next) console.log('Exiting interactive shell....');
});
return new Promise(((resolve) => {
finish = resolve;
return askForStep();
}));
}
/* eslint-disable */
function parseInput(cmd) {
rl.pause();
next = false;
store.debugMode = false;
if (cmd === '') next = true;
if (!cmd || cmd === 'resume' || cmd === 'exit') {
finish();
recorder.session.restore();
rl.close();
history.save();
return nextStep();
}
for (const k of Object.keys(registeredVariables)) {
eval(`var ${k} = registeredVariables['${k}'];`); // eslint-disable-line no-eval
}
store.debugMode = true;
let isCustomCommand = false;
let lastError = null;
try {
const locate = global.locate; // enable locate in this context
const I = container.support('I');
if (cmd.trim().startsWith('=>')) {
isCustomCommand = true;
cmd = cmd.trim().substring(2, cmd.length);
} else {
cmd = `I.${cmd}`;
}
const executeCommand = eval(cmd); // eslint-disable-line no-eval
const result = executeCommand instanceof Promise ? executeCommand : Promise.resolve(executeCommand);
result.then((val) => {
if (isCustomCommand) {
console.log(val);
return;
}
if (cmd.startsWith('I.see') || cmd.startsWith('I.dontSee')) {
output.print(output.styles.success(' OK '), cmd);
return;
}
if (cmd.startsWith('I.grab')) {
output.print(output.styles.debug(val));
}
}).catch((err) => {
if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
lastError = err.message;
});
history.push(cmd); // add command to history when successful
} catch (err) {
if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
lastError = err.message;
}
recorder.session.catch((err) => {
const msg = err.cliMessage ? err.cliMessage() : err.message;
// pop latest command from history because it failed
history.pop();
if (!lastError) output.print(output.styles.error(' FAIL '), msg);
lastError = err.message;
});
recorder.add('ask for next step', askForStep);
nextStep();
}
/* eslint-enable */
function askForStep() {
return new Promise(((resolve) => {
nextStep = resolve;
rl.setPrompt(' I.', 3);
rl.resume();
rl.prompt([false]);
}));
}
function completer(line) {
const I = container.support('I');
const completions = methodsOfObject(I);
const hits = completions.filter((c) => {
if (c.indexOf(line) === 0) {
return c;
}
return null;
});
return [hits && hits.length ? hits : completions, line];
}
module.exports = pause;