Skip to content

Commit

Permalink
Refactor and decompose globals
Browse files Browse the repository at this point in the history
  • Loading branch information
schipiga committed Mar 1, 2018
1 parent 31014b6 commit 66f2fc4
Show file tree
Hide file tree
Showing 9 changed files with 788 additions and 563 deletions.
539 changes: 0 additions & 539 deletions lib/globals.js

This file was deleted.

82 changes: 82 additions & 0 deletions lib/globals/chunk.js
@@ -0,0 +1,82 @@
"use strict";

var CONF = require("../config");

/**
* Defines test chunk.
*
* Contains actions and verifications, which will be executed separatly
* from another chunks. This function is used to organize test
* structure and to allocate independent test actions.
*
* @global
* @function
* @arg {string} [name] - Name of chunk.
* @arg {object} [opts] - Chunk options.
* @arg {number} [opts.retry] - Number of chunk retries on failure.
* @arg {number} [opts.timeout] - Time limit to execute chunk, sec.
* @arg {function} func - Callback function with test payload.
*
* @example <caption><b>Anonymous chunk</b></caption>
*
* test("My test", () => {
* chunk(() => {
* var a = 5;
* expect(a).to.be.equal(2);
* });
* });
*
* @example <caption><b>Named chunk</b></caption>
*
* test("My test", () => {
* chunk("My chunk", () => {
* var a = 5;
* expect(a).to.be.equal(2);
* });
* });
*
* @example <caption><b>Chunk with options</b></caption>
*
* test("My test", () => {
* chunk("My chunk", { retry: 2, timeout: 1 }, () => {
* var a = 5;
* expect(a).to.be.equal(2);
* });
* });
*/
var chunk = (name, opts, func) => {

if (name instanceof Function) {
func = name;
name = "";
opts = {};
};

if (opts instanceof Function) {
func = opts;
opts = {};
};

if (name instanceof Object) {
opts = name;
name = "";
};

name = name || "";
opts = opts || {};

it(name, _chunkCb(name, opts, func));
};

/**
* Chunk callback.
* @ignore
*/
var _chunkCb = (name, opts, func) => function () {
CONF.curTestCase.addChunk(name);
if (opts.retry) this.retries(opts.retry);
if (opts.timeout) this.timeout(opts.timeout * 1000);
func();
};

module.exports = chunk;
71 changes: 71 additions & 0 deletions lib/globals/forEachLanguage.js
@@ -0,0 +1,71 @@
"use strict";

var U = require("glace-utils");

var CONF = require("../config");

/**
* Iterates test chunks through all languages specified in config or options.
*
* It's applicable for multilingual application. If list of languages is
* specified, it will be used firstly. Otherwise from configuration.
*
* @global
* @function
* @arg {object} [ctx] - Test case context.
* @arg {object} [opts] - Options.
* @arg {?string[]} [opts.languages] - List of tested languages.
* @arg {function[]} [fixtures] - Involved fixtures list.
* @arg {function} func - Function with test steps.
* @example
*
* test("Some test", ctx => {
* forEachLanguage(ctx, lang => {
* chunk(() => {
* // payload
* });
* });
* });
*/
var forEachLanguage = (ctx, opts, fixtures, func) => {

if (ctx instanceof Function) {
func = ctx;
ctx = {};
opts = {};
fixtures = [];
};

if (opts instanceof Function) {
func = opts;
opts = {};
fixtures = [];
};

if (fixtures instanceof Function) {
func = fixtures;
fixtures = [];
};

ctx = ctx || {};
opts = opts || {};
fixtures = fixtures || [];

var languages = ctx.language ? [ctx.language]
: (opts.languages || CONF.languages);

languages.forEach(_langCb(fixtures, func));
};

var _langCb = (fixtures, func) => lang => {
scope(`for language "${lang}"`, () => {
before(() => {
if (CONF.curTestCase) {
CONF.curTestCase.testParams.language = lang;
};
});
U.wrap(fixtures, () => func(lang))();
});
};

module.exports = forEachLanguage;
122 changes: 122 additions & 0 deletions lib/globals/index.js
@@ -0,0 +1,122 @@
"use strict";
/**
* Contains global framework functions and helpers.
*
* @module
*/

var fs = require("fs");
var path = require("path");

var _ = require("lodash");
var chai = require("chai");
var chai_as_promised = require("chai-as-promised");
var sinon = require("sinon");
var sinon_chai = require("sinon-chai");
var U = require("glace-utils");
var LOG = U.logger;

chai.use(chai_as_promised);
chai.use(sinon_chai);

require("../matcher");
var CONF = require("../config");
var hacking = require("../hacking");
var plugins = require("../plugins");
var Steps = require("../steps");
var TestCase = require("../testing").TestCase;
/**
* `chaijs` `expect` function.
*
* @global
* @function
* @arg {*} actualValue - Some actual value which should be checked.
* @see {@link http://chaijs.com/|chaijs} to get more details about
* `expect` usage.
* @example
expect(1).to.be.equal(1);
expect(2).to.be.gte(0);
*/
global.expect = chai.expect;
/**
* `SinonJS` is pretty nice lib for mocking.
*
* @global
*/
global.sinon = sinon;

global.rewire = require("./rewire");

/**
* `GlaceJS` config.
*
* @global
* @see {@link module:config|config} to get more details about its options.
*/
global.CONF = CONF;
/**
* Atomic steps collection.
*
* @global
* @type {Steps}
* @see {@link module:steps/index|steps} to get more details about its methods.
*/
global.SS = new Steps();

global.scope = require("./scope");
global.session = require("./session");
global.test = require("./test");
global.chunk = require("./chunk");
global.forEachLanguage = require("./forEachLanguage");

/**
* Executes before each test chunk.
*
* @global
* @function
* @arg {string} name - Name of test case.
* @arg {function} func - Hook function.
* @example
test("Some test", () => {
beforeChunk(() => {
someFunc();
});
chunk("Chunk #1", () => {
someFunc();
});
chunk("Chunk #2", () => {
someFunc();
});
});
*/
global.beforeChunk = beforeEach;
/**
* Executes after each test chunk.
*
* @global
* @function
* @arg {string} name - Name of test case.
* @arg {function} func - Hook function.
* @example
test("Some test", () => {
afterChunk(() => {
someFunc();
});
chunk("Chunk #1", () => {
someFunc();
});
chunk("Chunk #2", () => {
someFunc();
});
});
*/
global.afterChunk = afterEach;

/* Load globals from plugins */
plugins.getModules("globals");
46 changes: 46 additions & 0 deletions lib/globals/rewire.js
@@ -0,0 +1,46 @@
"use strict";

var path = require("path");
var _rewire = require("rewire");

/**
* `rewire` is great lib for monkey patching, but it should be a bit patched too :)
*
* @global
*/
var rewire = filename => {

var _ = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
var stack = new Error().stack.slice(1);
Error.prepareStackTrace = _;
var callerPath = stack[0].getFileName();

var callerDir = path.dirname(callerPath);
filename = path.resolve(callerDir, filename);

var mod = _rewire(filename);

var cache = {};

var set = mod.__set__;
mod.__set__ = function (name, stub) {

if (!Object.keys(cache).includes(name)) {
cache[name] = this.__get__(name);
};

set.call(this, name, stub);
};

mod.__reset__ = function () {
for (var [k, v] of Object.entries(cache)) {
this.__set__(k, v);
};
cache = {};
};

return mod;
};

module.exports = rewire;
54 changes: 54 additions & 0 deletions lib/globals/scope.js
@@ -0,0 +1,54 @@
"use strict";

var U = require("glace-utils");

/**
* Execute tests scope.
*
* @global
* @function
* @arg {string} name - Scope name.
* @arg {object} [opts] - Scope options.
* @arg {number} [opts.chunkRetry] - Number of chunk retries on failure.
* @arg {number} [opts.chunkTimeout] - Time to execute chunk or hook, sec.
* @arg {function[]} [fixtures] - List of fixtures.
* @arg {function} func - Function with test cases.
* @example
scope("Some test scope", () => {
test("Some test name", () => {
before(() => {
someFunc();
});
chunk("chunk #1", () => {
someFunc();
});
chunk("chunk #2", () => {
someFunc();
});
});
});
*/
var scope = (name, opts, fixtures, func) => {

if (opts instanceof Function) {
func = opts;
opts = {};
fixtures = [];
};
if (fixtures instanceof Function) {
func = fixtures;
fixtures = [];
};
opts = opts || {};
fixtures = fixtures || {};

describe(name, function () {
if (opts.chunkRetry) this.retries(opts.chunkRetry);
if (opts.chunkTimeout) this.timeout(opts.chunkTimeout * 1000);
U.wrap(fixtures, func)();
});
};

module.exports = scope;

0 comments on commit 66f2fc4

Please sign in to comment.