All files / lib/steps index.js

100% Statements 52/52
100% Branches 12/12
100% Functions 11/11
100% Lines 50/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179                        2x   2x 2x 2x   2x 2x 2x 2x   2x 3x   2x   2x                 1x     2x                     3x 2x     2x                                     1x 1x 1x 1x     2x                       1x                             2x 5x 4x                               2x 9x       7x   7x 5x 2x     3x 2x 2x   1x 1x 1x   1x           2x   2x           2x 1x 1x 2x 2x 1x   1x       1x           1x    
"use strict";
/**
 * Creates new instance of `Steps` class.
 *
 * @class
 * @classdesc Contains collection of steps which may be called inside tests via
 * its instance [$](global.html#$). It mixes steps from plugins too.
 * @name Steps
 * @mixes TimerSteps
 * @prop {object} ctx - Storage to share some data between steps.
 */
 
var util = require("util");
 
require("colors");
var _ = require("lodash");
var U = require("glace-utils");
 
var CONF = require("../config");
var plugins = require("../plugins");
var tools = require("../tools");
const utils = require("../utils");
 
var Steps = function () {
    this.ctx = {};
};
module.exports = Steps;
 
Steps.prototype.resetCtx = function () {
    /**
     * Helper to reset steps context.
     *
     * @memberOf Steps
     * @method resetCtx
     * @instance
     */
 
    this.ctx = {};
};
 
Steps.prototype.isTestFailed = function () {
    /**
     * Helper to check whether test was failed before current step.
     *
     * @memberOf Steps
     * @method isTestFailed
     * @instance
     * @return {undefined|boolean} `undefined` if test is absent,
     *  `true` if test was failed, `false` otherwise.
     */
 
    if (!CONF.test.curCase) return;
    return !!CONF.test.curCase.errors.length;
};
 
Steps.prototype.debug = async function () {
    /**
     * Step to enter to interactive debugging mode. May be used inside test if you
     * need to debug test in runtime.
     *
     * @async
     * @memberOf Steps
     * @method debug
     * @instance
     * @return {Promise<void>}
     * @example
     *
     * test("my test", () => {
     *     chunk(async () => {
     *         await $.debug();
     *     });
     * });
     */
 
    var onFail = CONF.session.debugOnFail;
    CONF.session.debugOnFail = false;
    await U.debug(setupDebug());
    CONF.session.debugOnFail = onFail;
};
 
Steps.prototype.listSteps = function (filter, namesOnly) {
    /**
     * Step to list available steps [debug mode].
     *
     * @memberOf Steps
     * @method listSteps
     * @instance
     * @arg {string} filter - Steps filter.
     * @arg {boolean} [namesOnly=false] - Search among step names only. By default
     * full-text search is used.
     */
 
    tools.printSteps(filter, namesOnly);
};
/**
 * Registers steps (mixes them).
 *
 * @method
 * @static
 * @arg {...object} steps - Sequence of steps to register.
 * @example
 *
 * var MyStepsMixin = require("./my-steps-mixin");
 * var AnotherStepsMixin = require("./another-steps-mixin");
 *
 * Steps.register(MyStepsMixin, AnotherStepsMixin);
 */
Steps.register = function () {
    for (var obj of arguments) {
        _.assign(this.prototype, obj);
    }
};
 
/**
 * Helper to get steps instance.
 *
 * It wraps steps class with proxy object. Proxy observes steps call and in
 * debug mode if steps is failed it entered test to interactive debug mode.
 *
 * @method
 * @static
 * @arg {function} [cls] - Class with steps. By default original glace `Steps`
 *  will be used.
 * @return {Proxy} Wrapped steps instance.
 */
Steps.getInstance = function (cls) {
    return new Proxy(
        new (cls || Steps),
        {
            get: (target, property) => {
                var func = target[property];
 
                if (!util.isFunction(func)) return func;
                if (property === "debug" || !CONF.session.debugOnFail) {
                    return func;
                }
 
                return async function () {
                    try {
                        var result = await func.apply(target, arguments);
                    } catch (e) {
                        console.log(util.format(e).red);
                        await target.debug();
                        throw e;
                    }
                    return result;
                };
            },
        });
};
 
Steps.register(require("./timer"));
/* Load plugins steps */
Steps.register.apply(Steps, plugins.getModules("Steps"));
 
/**
 * Set up debug mode for glace.
 * @ignore
 */
const setupDebug = () => {
    global.search = $.listSteps.bind($);
    global.doc = f => {
        const doc = utils.getDoc(f);
        if (doc) {
            console.log(doc.green);
        } else {
            console.log("No docs found".yellow);
        }
    };
 
    const helpMsg = "In interactive mode you can execute any nodejs code or glace step.\n" +
        "Available commands:\n" +
        "- search([query string]) - Searchs a glace step according to query. " +
        "For ex: > search('step to start timer');\n" +
        "- doc(function) - Prints function documentation;\n";
 
    return helpMsg;
};