Comparing version 2.0.1 to 3.0.0
{ | ||
"testloglevel": "info" | ||
"logging": { | ||
"level": "info", | ||
"pluginNames": [] | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
import { ProcessingResult } from '../helpers/processing-result'; | ||
export declare module TestConfig { | ||
@@ -6,3 +7,3 @@ /** | ||
*/ | ||
function getConfiguration<T>(jsonFile: string): Promise<T>; | ||
function loadJsonFile<T>(jsonFile: string): Promise<T>; | ||
/** | ||
@@ -14,15 +15,36 @@ * parses a 'aftconfig.json' file from the local execution directory | ||
/** | ||
* will look for the specified configuration value in the environment variables | ||
* and then in the 'aftconfig.json' file and if not found will return the passed | ||
* in 'defaultVal' or null. | ||
* @param key the property name or environment variable to get the value from | ||
* @param defaultVal if no value set in config or environment vars, this is returned instead | ||
* function will lookup the value for a specified set of keys within the aftconfig.json | ||
* by recursing down until the last key is used. for example to get the value of "baz" from | ||
* {"foo": {"bar": {"baz": 123}}} you would specify a key of 'foo.bar.baz' which would | ||
* return 123. alternatively, to get the value of "bar" you would specify a key of | ||
* 'foo.bar' which would return {"baz": 123} | ||
* @param keys the keys to be used in looking up values separated by the . character | ||
* @param defaultVal if no value found for the specified keys then this will be returned instead; default null | ||
*/ | ||
function getValueOrDefault(key: string, defaultVal?: string): Promise<string>; | ||
function get<T>(keys: string, defaultVal?: T): Promise<T>; | ||
/** | ||
* will set an environment variable for the specified key value pair | ||
* @param key the property name to set | ||
* @param val the value to set for the specified key | ||
* function will lookup the value for a specified set of keys within the passed in object | ||
* by recursing down until the last key is used. for example to get the value of "baz" from | ||
* {"foo": {"bar": {"baz": 123}}} you would specify a key of 'foo.bar.baz' which would | ||
* return 123. alternatively, to get the value of "bar" you would specify a key of | ||
* 'foo.bar' which would return {"baz": 123} | ||
* @param obj the object to search for values within | ||
* @param keys the keys to be used in looking up values separated by the . character | ||
*/ | ||
function setGlobalValue(key: string, val: string): void; | ||
function getFrom(obj: any, keys: string): Promise<any>; | ||
/** | ||
* function will check if the passed in 'str' string is a | ||
* reference to an environment variable key and if so will | ||
* lookup the value and return otherwise it will return null | ||
* @param str the value to be parsed to determine if it is an | ||
* Environment Variable reference | ||
*/ | ||
function isEnvVar(str: string): ProcessingResult; | ||
/** | ||
* function verifies that the passed in string is a valid | ||
* JSON object that can successfully be parsed with the | ||
* JSON.parse command | ||
* @param str the string to be tested for validity | ||
*/ | ||
function isJsonString(str: string): ProcessingResult; | ||
} |
@@ -39,7 +39,17 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TestConfig = void 0; | ||
var fs = require("fs"); | ||
var path = require("path"); | ||
var test_log_1 = require("../logging/test-log"); | ||
var logging_level_1 = require("../logging/logging-level"); | ||
var TestConfig; | ||
(function (TestConfig) { | ||
var _aftConfig; | ||
var _testLog; | ||
function _logger() { | ||
if (!_testLog) { | ||
_testLog = new test_log_1.TestLog({ name: 'TestConfig', pluginNames: [] }); | ||
} | ||
return _testLog; | ||
} | ||
/** | ||
@@ -49,3 +59,3 @@ * loads the specified file and attempts to return it as the declared type | ||
*/ | ||
function getConfiguration(jsonFile) { | ||
function loadJsonFile(jsonFile) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -61,3 +71,12 @@ var config; | ||
} | ||
resolve(JSON.parse(data.toString('utf8'))); | ||
if (data) { | ||
var fileContents = data.toString('utf8'); | ||
var jsonRes = isJsonString(fileContents); | ||
if (jsonRes.success) { | ||
resolve(jsonRes.obj); | ||
} | ||
else { | ||
reject(jsonRes.message); | ||
} | ||
} | ||
}); | ||
@@ -76,3 +95,3 @@ } | ||
} | ||
TestConfig.getConfiguration = getConfiguration; | ||
TestConfig.loadJsonFile = loadJsonFile; | ||
/** | ||
@@ -85,2 +104,3 @@ * parses a 'aftconfig.json' file from the local execution directory | ||
var currentDir; | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
@@ -94,5 +114,15 @@ switch (_a.label) { | ||
} | ||
return [4 /*yield*/, getConfiguration(currentDir + 'aftconfig.json')]; | ||
return [4 /*yield*/, loadJsonFile(currentDir + 'aftconfig.json') | ||
.catch(function (err) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, _logger().warn(err)]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/, {}]; // empty config | ||
} | ||
}); | ||
}); })]; | ||
case 1: | ||
_aftConfig = (_a.sent()) || {}; | ||
_aftConfig = _a.sent(); | ||
_a.label = 2; | ||
@@ -106,31 +136,95 @@ case 2: return [2 /*return*/, _aftConfig]; | ||
/** | ||
* will look for the specified configuration value in the environment variables | ||
* and then in the 'aftconfig.json' file and if not found will return the passed | ||
* in 'defaultVal' or null. | ||
* @param key the property name or environment variable to get the value from | ||
* @param defaultVal if no value set in config or environment vars, this is returned instead | ||
* function will lookup the value for a specified set of keys within the aftconfig.json | ||
* by recursing down until the last key is used. for example to get the value of "baz" from | ||
* {"foo": {"bar": {"baz": 123}}} you would specify a key of 'foo.bar.baz' which would | ||
* return 123. alternatively, to get the value of "bar" you would specify a key of | ||
* 'foo.bar' which would return {"baz": 123} | ||
* @param keys the keys to be used in looking up values separated by the . character | ||
* @param defaultVal if no value found for the specified keys then this will be returned instead; default null | ||
*/ | ||
function getValueOrDefault(key, defaultVal) { | ||
function get(keys, defaultVal) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var val, c; | ||
var conf, val; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, aftConfig()]; | ||
case 1: | ||
conf = _a.sent(); | ||
return [4 /*yield*/, getFrom(conf, keys)]; | ||
case 2: | ||
val = _a.sent(); | ||
return [2 /*return*/, val || defaultVal]; | ||
} | ||
}); | ||
}); | ||
} | ||
TestConfig.get = get; | ||
/** | ||
* function will lookup the value for a specified set of keys within the passed in object | ||
* by recursing down until the last key is used. for example to get the value of "baz" from | ||
* {"foo": {"bar": {"baz": 123}}} you would specify a key of 'foo.bar.baz' which would | ||
* return 123. alternatively, to get the value of "bar" you would specify a key of | ||
* 'foo.bar' which would return {"baz": 123} | ||
* @param obj the object to search for values within | ||
* @param keys the keys to be used in looking up values separated by the . character | ||
*/ | ||
function getFrom(obj, keys) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var result, keysArray, currentKey, _a, envRes, jsonRes, envRes, jsonRes; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
val = null; | ||
if (defaultVal === undefined) { | ||
defaultVal = null; | ||
result = null; | ||
keysArray = keys.split('.'); | ||
currentKey = keysArray.shift(); | ||
if (!(currentKey.length > 0)) return [3 /*break*/, 8]; | ||
_a = typeof obj; | ||
switch (_a) { | ||
case "object": return [3 /*break*/, 1]; | ||
case "string": return [3 /*break*/, 3]; | ||
} | ||
// check in environment vars | ||
val = process.env[key] || null; | ||
if (!(val === null)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.aftConfig()]; | ||
case 1: | ||
c = _a.sent(); | ||
val = c[key] || null; | ||
_a.label = 2; | ||
return [3 /*break*/, 5]; | ||
case 1: return [4 /*yield*/, getFrom(obj[currentKey], keysArray.join('.'))]; | ||
case 2: | ||
if (val === null) { | ||
val = defaultVal; | ||
result = _b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 3: | ||
envRes = isEnvVar(obj); | ||
if (!envRes.success) return [3 /*break*/, 5]; | ||
jsonRes = isJsonString(envRes.obj); | ||
if (!jsonRes.success) return [3 /*break*/, 5]; | ||
return [4 /*yield*/, getFrom(jsonRes.obj, keys)]; | ||
case 4: | ||
result = _b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 5: | ||
result = null; | ||
return [4 /*yield*/, _logger().log(logging_level_1.LoggingLevel.trace, "invalid Argument: " + obj + ", Type: " + typeof obj + " passed to getFrom}")]; | ||
case 6: | ||
_b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 7: return [3 /*break*/, 9]; | ||
case 8: | ||
switch (typeof obj) { | ||
case "string": | ||
envRes = isEnvVar(obj); | ||
if (envRes.success) { | ||
jsonRes = isJsonString(envRes.obj); | ||
if (jsonRes.success) { | ||
result = jsonRes.obj; | ||
} | ||
else { | ||
result = envRes.obj; | ||
} | ||
} | ||
else { | ||
result = obj; | ||
} | ||
break; | ||
default: | ||
result = obj; | ||
break; | ||
} | ||
return [2 /*return*/, val]; | ||
_b.label = 9; | ||
case 9: return [2 /*return*/, result]; | ||
} | ||
@@ -140,13 +234,45 @@ }); | ||
} | ||
TestConfig.getValueOrDefault = getValueOrDefault; | ||
TestConfig.getFrom = getFrom; | ||
/** | ||
* will set an environment variable for the specified key value pair | ||
* @param key the property name to set | ||
* @param val the value to set for the specified key | ||
* function will check if the passed in 'str' string is a | ||
* reference to an environment variable key and if so will | ||
* lookup the value and return otherwise it will return null | ||
* @param str the value to be parsed to determine if it is an | ||
* Environment Variable reference | ||
*/ | ||
function setGlobalValue(key, val) { | ||
process.env[key] = val; | ||
function isEnvVar(str) { | ||
if (str) { | ||
var matchResults = str.match(/^%(.*)%$/); | ||
if (matchResults && matchResults.length > 0) { | ||
var envValStr = process.env[matchResults[1]]; | ||
return { obj: envValStr, success: true }; | ||
} | ||
} | ||
return { success: false }; | ||
} | ||
TestConfig.setGlobalValue = setGlobalValue; | ||
TestConfig.isEnvVar = isEnvVar; | ||
/** | ||
* function verifies that the passed in string is a valid | ||
* JSON object that can successfully be parsed with the | ||
* JSON.parse command | ||
* @param str the string to be tested for validity | ||
*/ | ||
function isJsonString(str) { | ||
var err = null; | ||
if (str) { | ||
try { | ||
var jsonObj = JSON.parse(str); | ||
return { obj: jsonObj, success: true }; | ||
} | ||
catch (e) { | ||
err = "[isJsonString] for string value of '" + str + "' threw an error of: " + e; | ||
} | ||
} | ||
else { | ||
err = "[isJsonString] for string value of '" + str + "' is not valid."; | ||
} | ||
return { success: false, message: err }; | ||
} | ||
TestConfig.isJsonString = isJsonString; | ||
})(TestConfig = exports.TestConfig || (exports.TestConfig = {})); | ||
//# sourceMappingURL=test-config.js.map |
@@ -0,1 +1,25 @@ | ||
/** | ||
* allows for creation of functions that can create new instances of | ||
* generic types. Ex: | ||
* ``` | ||
* function get<T>(type: Constructor<T>, ...args: any[]): T { | ||
* return new type(...args); | ||
* } | ||
* ``` | ||
* which can then be used like: | ||
* ``` | ||
* let obj: CustomObj = get(CustomObj, 'foo', 123); | ||
* ``` | ||
* assuming that `CustomObj` looks like: | ||
* ``` | ||
* class CustomObj { | ||
* someStr: string; | ||
* someNum: number; | ||
* constructor(inputStr: string, inputNum: number) { | ||
* this.someStr = inputStr; | ||
* this.someNum = inputNum; | ||
* } | ||
* } | ||
* ``` | ||
*/ | ||
export declare type Constructor<T> = { | ||
@@ -2,0 +26,0 @@ new (...args: any[]): T; |
@@ -0,3 +1,4 @@ | ||
import { IPlugin } from './iplugin'; | ||
export declare module PluginLoader { | ||
function load<T>(...pluginNames: string[]): Promise<T[]>; | ||
function load<T extends IPlugin>(pluginName: string): Promise<T>; | ||
} |
@@ -39,31 +39,15 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.PluginLoader = void 0; | ||
var path = require("path"); | ||
var PluginLoader; | ||
(function (PluginLoader) { | ||
function load() { | ||
var pluginNames = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
pluginNames[_i] = arguments[_i]; | ||
} | ||
function load(pluginName) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var plugins, i, p; | ||
var p; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
plugins = []; | ||
i = 0; | ||
_a.label = 1; | ||
case 0: return [4 /*yield*/, validatePlugin(pluginName)]; | ||
case 1: | ||
if (!(i < pluginNames.length)) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, validatePlugin(pluginNames[i])]; | ||
case 2: | ||
p = _a.sent(); | ||
if (p) { | ||
plugins.push(p); | ||
} | ||
_a.label = 3; | ||
case 3: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 4: return [2 /*return*/, plugins]; | ||
return [2 /*return*/, p]; | ||
} | ||
@@ -76,3 +60,3 @@ }); | ||
return __awaiter(this, void 0, void 0, function () { | ||
var plugin, e_1, pathToPlugin, ee_1, constructorName; | ||
var plugin, e_1, pathToPlugin, ee_1, constructorName, p, e_2; | ||
return __generator(this, function (_a) { | ||
@@ -102,12 +86,17 @@ switch (_a.label) { | ||
case 7: | ||
if (plugin) { | ||
try { | ||
constructorName = Object.keys(plugin)[0]; | ||
return [2 /*return*/, new plugin[constructorName]()]; | ||
} | ||
catch (e) { | ||
console.warn("unable to create instance of loaded plugin '" + pluginName + "' due to: " + e); | ||
} | ||
} | ||
return [2 /*return*/, null]; | ||
if (!plugin) return [3 /*break*/, 11]; | ||
_a.label = 8; | ||
case 8: | ||
_a.trys.push([8, 10, , 11]); | ||
constructorName = Object.keys(plugin)[0]; | ||
p = new plugin[constructorName](); | ||
return [4 /*yield*/, p.onLoad()]; | ||
case 9: | ||
_a.sent(); | ||
return [2 /*return*/, p]; | ||
case 10: | ||
e_2 = _a.sent(); | ||
console.warn("unable to create instance of loaded plugin '" + pluginName + "' due to: " + e_2); | ||
return [3 /*break*/, 11]; | ||
case 11: return [2 /*return*/, null]; | ||
} | ||
@@ -114,0 +103,0 @@ }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.EllipsisLocation = void 0; | ||
var EllipsisLocation; | ||
@@ -4,0 +5,0 @@ (function (EllipsisLocation) { |
@@ -0,3 +1,10 @@ | ||
/** | ||
* Type to represent any function accepting a single argument | ||
* of type `T` that returns void. an alternative to writing: | ||
* ``` | ||
* (input: T): void | ||
* ``` | ||
*/ | ||
export interface Action<T> { | ||
(item: T): void; | ||
} |
@@ -0,4 +1,17 @@ | ||
/** | ||
* [OBSOLETE] use `BuildInfoPluginManager.instance()` instead | ||
*/ | ||
export declare module BuildInfo { | ||
/** | ||
* returns the build name as supplied by any loaded | ||
* `IBuildInfoHandlerPlugin` or empty string if none | ||
* loaded | ||
*/ | ||
function name(): Promise<string>; | ||
/** | ||
* returns the build number as supplied by any loaded | ||
* `IBuildInfoHandlerPlugin` or empty string if none | ||
* loaded | ||
*/ | ||
function number(): Promise<string>; | ||
} |
@@ -39,10 +39,21 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var test_config_1 = require("../configuration/test-config"); | ||
exports.BuildInfo = void 0; | ||
var build_info_plugin_manager_1 = require("./build-info-plugin-manager"); | ||
/** | ||
* [OBSOLETE] use `BuildInfoPluginManager.instance()` instead | ||
*/ | ||
var BuildInfo; | ||
(function (BuildInfo) { | ||
/** | ||
* returns the build name as supplied by any loaded | ||
* `IBuildInfoHandlerPlugin` or empty string if none | ||
* loaded | ||
*/ | ||
function name() { | ||
return __awaiter(this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
// TODO: use Build Server plugin to get value | ||
return [2 /*return*/, test_config_1.TestConfig.getValueOrDefault('JOB_NAME')]; | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, build_info_plugin_manager_1.BuildInfoPluginManager.instance().getBuildName()]; | ||
case 1: return [2 /*return*/, _a.sent()]; | ||
} | ||
}); | ||
@@ -52,7 +63,14 @@ }); | ||
BuildInfo.name = name; | ||
/** | ||
* returns the build number as supplied by any loaded | ||
* `IBuildInfoHandlerPlugin` or empty string if none | ||
* loaded | ||
*/ | ||
function number() { | ||
return __awaiter(this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
// TODO: use Build Server plugin to get value | ||
return [2 /*return*/, test_config_1.TestConfig.getValueOrDefault('BUILD_NUMBER')]; | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, build_info_plugin_manager_1.BuildInfoPluginManager.instance().getBuildNumber()]; | ||
case 1: return [2 /*return*/, _a.sent()]; | ||
} | ||
}); | ||
@@ -59,0 +77,0 @@ }); |
@@ -0,1 +1,2 @@ | ||
import { SafeStringOption } from "./safe-string-option"; | ||
export declare module Convert { | ||
@@ -19,2 +20,10 @@ /** | ||
function toElapsedMs(startTime: number): number; | ||
/** | ||
* function will replace any occurrences of the passed in 'excludes' strings with | ||
* the value of the passed in 'replaceWith' string | ||
* @param input the original string to process | ||
* @param options an array of {exclude: string | RegExp, replaceWith: string} objects to | ||
* use in processing the input string | ||
*/ | ||
function toSafeString(input: string, options?: SafeStringOption[]): string; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Convert = void 0; | ||
var safe_string_option_1 = require("./safe-string-option"); | ||
var Convert; | ||
@@ -31,3 +33,19 @@ (function (Convert) { | ||
Convert.toElapsedMs = toElapsedMs; | ||
/** | ||
* function will replace any occurrences of the passed in 'excludes' strings with | ||
* the value of the passed in 'replaceWith' string | ||
* @param input the original string to process | ||
* @param options an array of {exclude: string | RegExp, replaceWith: string} objects to | ||
* use in processing the input string | ||
*/ | ||
function toSafeString(input, options) { | ||
if (options === void 0) { options = safe_string_option_1.SafeStringOption.defaults; } | ||
for (var i = 0; i < options.length; i++) { | ||
var o = options[i]; | ||
input = input.replace(o.exclude, o.replaceWith); | ||
} | ||
return input; | ||
} | ||
Convert.toSafeString = toSafeString; | ||
})(Convert = exports.Convert || (exports.Convert = {})); | ||
//# sourceMappingURL=convert.js.map |
@@ -0,3 +1,11 @@ | ||
/** | ||
* Type representing a function accepting a single input | ||
* of type `T` and returning a result of type `TResult`. | ||
* an alternative to writing: | ||
* ``` | ||
* (input: T): TResult | ||
* ``` | ||
*/ | ||
export interface Func<T, TResult> { | ||
(item: T): TResult; | ||
} |
@@ -1,3 +0,11 @@ | ||
export interface IClonable { | ||
/** | ||
* interface to be implemented by any class | ||
* that needs to override the cloning process | ||
* used by `Cloner.clone`. if implemented, | ||
* the `ICloneable.clone` function will be called | ||
* instead of the `Cloner` attempting to clone | ||
* on it's own | ||
*/ | ||
export interface ICloneable { | ||
clone(): object; | ||
} |
@@ -0,3 +1,18 @@ | ||
/** | ||
* interface should be implemented by classes that require | ||
* some disposal after their use. automatic disposal is | ||
* handled by using the `IDisposable` within the `using` | ||
* object like follows: | ||
* ``` | ||
* async using(new ImplementsIDisposable(), async (disp) => { | ||
* await disp.doSomethingAsync(); | ||
* disp.doSomethingSync(); | ||
* }); | ||
* ``` | ||
* where the `dispose` function would be called | ||
* automatically upon completion or in the case of an | ||
* Error | ||
*/ | ||
export interface IDisposable { | ||
dispose(error?: Error): Promise<void>; | ||
} |
@@ -39,2 +39,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.MachineInfo = void 0; | ||
var os = require("os"); | ||
@@ -41,0 +42,0 @@ var MachineInfo; |
export declare module RandomGenerator { | ||
var ALPHAS: string; | ||
var NUMERICS: string; | ||
var SPECIALS: string; | ||
var EXTENDED: string; | ||
var RANDOM_LENGTH: number; | ||
function getString(length: number, alphas?: boolean, numerics?: boolean, specials?: boolean, extended?: boolean): string; | ||
const ALPHAS: string; | ||
const NUMERICS: string; | ||
const SPECIALS: string; | ||
const EXTENDED: string; | ||
function getString(length?: number, alphas?: boolean, numerics?: boolean, specials?: boolean, extended?: boolean): string; | ||
function getInt(min: number, max: number): number; | ||
function getFloat(min: number, max: number): number; | ||
function getStringFrom(length: number, selectionCharacters: string): string; | ||
function getStringFrom(length?: number, selectionCharacters?: string): string; | ||
function getGuid(): string; | ||
function getEnum<T>(anEnum: T): T[keyof T]; | ||
function getBoolean(): boolean; | ||
} | ||
export declare const RG: typeof RandomGenerator; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.RG = exports.RandomGenerator = void 0; | ||
var uuid = require("uuid"); | ||
@@ -10,3 +11,2 @@ var RandomGenerator; | ||
RandomGenerator.EXTENDED = "ÀÁÂÃÄÅĀƁƂÇĈĊĎĐÈÉÊËƑĜĞĠĤĦÌÍÎÏĴĶĹĿŁÑŃÒÓÔÕÖƤɊŔŖŚŜŢŤŦÙÚÛÜŴŶŽ"; | ||
RandomGenerator.RANDOM_LENGTH = -1; | ||
function getString(length, alphas, numerics, specials, extended) { | ||
@@ -38,11 +38,9 @@ if (alphas === undefined) { | ||
} | ||
return getStringFrom(length, choices); | ||
return this.getStringFrom(length, choices); | ||
} | ||
RandomGenerator.getString = getString; | ||
; | ||
function getInt(min, max) { | ||
return Math.floor(RandomGenerator.getFloat(min, max)); | ||
return Math.floor(this.getFloat(min, max)); | ||
} | ||
RandomGenerator.getInt = getInt; | ||
; | ||
function getFloat(min, max) { | ||
@@ -53,4 +51,5 @@ return Math.random() * (max - min) + min; | ||
function getStringFrom(length, selectionCharacters) { | ||
if (length <= RandomGenerator.RANDOM_LENGTH) { | ||
length = RandomGenerator.getInt(1, 101); | ||
if (selectionCharacters === void 0) { selectionCharacters = RandomGenerator.ALPHAS + RandomGenerator.NUMERICS + RandomGenerator.SPECIALS + RandomGenerator.EXTENDED; } | ||
if (length === undefined) { | ||
length = this.getInt(1, 101); | ||
} | ||
@@ -61,3 +60,3 @@ var characters = ''; | ||
if (selectionCharacters) { | ||
ch = selectionCharacters[getInt(0, selectionCharacters.length)]; | ||
ch = selectionCharacters[this.getInt(0, selectionCharacters.length)]; | ||
} | ||
@@ -76,3 +75,18 @@ else { | ||
RandomGenerator.getGuid = getGuid; | ||
function getEnum(anEnum) { | ||
var enumValues = Object.keys(anEnum) | ||
.map(function (n) { return Number.parseInt(n); }) | ||
.filter(function (n) { return !Number.isNaN(n); }); | ||
var randomIndex = Math.floor(Math.random() * enumValues.length); | ||
var randomEnumValue = enumValues[randomIndex]; | ||
return randomEnumValue; | ||
} | ||
RandomGenerator.getEnum = getEnum; | ||
function getBoolean() { | ||
var i = this.getInt(0, 100); | ||
return i < 50; | ||
} | ||
RandomGenerator.getBoolean = getBoolean; | ||
})(RandomGenerator = exports.RandomGenerator || (exports.RandomGenerator = {})); | ||
exports.RG = RandomGenerator; | ||
//# sourceMappingURL=random-generator.js.map |
@@ -0,2 +1,17 @@ | ||
import { Func } from "./func"; | ||
import { IDisposable } from "./idisposable"; | ||
export declare function using<T extends IDisposable>(disposable: T, func: (disposable: T) => Promise<void>): Promise<void>; | ||
/** | ||
* function will execute a passed in function passing in the supplied `IDisposable` | ||
* and then calling the `dispose` method on the `IDisposable` when execution of the | ||
* function is done. | ||
* Usage Example: | ||
* ``` | ||
* await using(new ImplementsIDisposable(), async (disposable) => { | ||
* await disposable.interact(); | ||
* // do stuff... | ||
* }); | ||
* ``` | ||
* @param disposable object implementing the `IDisposable` interface | ||
* @param func a function to be passed the `IDisposable` for use before disposal | ||
*/ | ||
export declare function using<T extends IDisposable>(disposable: T, func: Func<T, void | Promise<void>>): Promise<void>; |
@@ -39,23 +39,40 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.using = void 0; | ||
/** | ||
* function will execute a passed in function passing in the supplied `IDisposable` | ||
* and then calling the `dispose` method on the `IDisposable` when execution of the | ||
* function is done. | ||
* Usage Example: | ||
* ``` | ||
* await using(new ImplementsIDisposable(), async (disposable) => { | ||
* await disposable.interact(); | ||
* // do stuff... | ||
* }); | ||
* ``` | ||
* @param disposable object implementing the `IDisposable` interface | ||
* @param func a function to be passed the `IDisposable` for use before disposal | ||
*/ | ||
function using(disposable, func) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var e_1; | ||
var err, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 3, , 5]); | ||
return [4 /*yield*/, func(disposable)]; | ||
err = null; | ||
_a.label = 1; | ||
case 1: | ||
_a.sent(); | ||
return [4 /*yield*/, disposable.dispose()]; | ||
_a.trys.push([1, 3, 4, 6]); | ||
return [4 /*yield*/, Promise.resolve(func(disposable))]; | ||
case 2: | ||
_a.sent(); | ||
return [3 /*break*/, 5]; | ||
return [3 /*break*/, 6]; | ||
case 3: | ||
e_1 = _a.sent(); | ||
return [4 /*yield*/, disposable.dispose(e_1)]; | ||
case 4: | ||
err = e_1; | ||
throw e_1; | ||
case 4: return [4 /*yield*/, disposable.dispose(err)]; | ||
case 5: | ||
_a.sent(); | ||
throw e_1; | ||
case 5: return [2 /*return*/]; | ||
return [7 /*endfinally*/]; | ||
case 6: return [2 /*return*/]; | ||
} | ||
@@ -62,0 +79,0 @@ }); |
@@ -39,2 +39,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Wait = void 0; | ||
var Wait; | ||
@@ -63,3 +64,3 @@ (function (Wait) { | ||
attempts++; | ||
return [4 /*yield*/, condition()]; | ||
return [4 /*yield*/, Promise.resolve(condition())]; | ||
case 2: | ||
@@ -66,0 +67,0 @@ result = _a.sent(); |
/** configuration */ | ||
export * from './configuration/test-config'; | ||
/** construction */ | ||
export * from './construction/iinitialise-options'; | ||
export * from './construction/constructor'; | ||
@@ -11,14 +10,14 @@ export * from './construction/plugin-loader'; | ||
export * from './extensions/string-extensions'; | ||
/** external */ | ||
export * from './integrations/defects/issue'; | ||
export * from './integrations/test-cases/test-result-metadata'; | ||
export * from './integrations/test-cases/test-result'; | ||
export * from './integrations/test-cases/test-status'; | ||
/** helpers */ | ||
export * from './helpers/build-info'; | ||
export * from './helpers/build-info-plugin-manager'; | ||
export * from './helpers/ibuild-info-handler-plugin'; | ||
export * from './helpers/cloner'; | ||
export * from './helpers/convert'; | ||
export * from './helpers/icloneable'; | ||
export * from './helpers/idisposable'; | ||
export * from './helpers/processing-result'; | ||
export * from './helpers/machine-info'; | ||
export * from './helpers/random-generator'; | ||
export * from './helpers/safe-string-option'; | ||
export * from './helpers/using'; | ||
@@ -28,7 +27,18 @@ export * from './helpers/wait'; | ||
export * from './helpers/action'; | ||
/** integrations */ | ||
export * from './integrations/defects/plugins/idefect-handler-plugin'; | ||
export * from './integrations/defects/defect-plugin-manager'; | ||
export * from './integrations/defects/defect-status'; | ||
export * from './integrations/defects/idefect'; | ||
export * from './integrations/test-cases/plugins/itest-case-handler-plugin'; | ||
export * from './integrations/test-cases/itest-case'; | ||
export * from './integrations/test-cases/test-case-plugin-manager'; | ||
export * from './integrations/test-cases/test-exception'; | ||
export * from './integrations/test-cases/itest-result'; | ||
export * from './integrations/test-cases/test-status'; | ||
/** logging */ | ||
export * from './logging/plugins/ilogging-plugin'; | ||
export * from './logging/test-log'; | ||
export * from './logging/test-log-options'; | ||
export * from './logging/test-log-level'; | ||
export * from './logging/logging-options'; | ||
export * from './logging/logging-level'; | ||
/** wrappers */ | ||
@@ -38,3 +48,1 @@ export * from './wrappers/test-wrapper'; | ||
export * from './wrappers/should'; | ||
export * from './wrappers/validation-error'; | ||
export * from './wrappers/validator'; |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** configuration */ | ||
__export(require("./configuration/test-config")); | ||
__export(require("./construction/plugin-loader")); | ||
__exportStar(require("./configuration/test-config"), exports); | ||
/** construction */ | ||
__exportStar(require("./construction/constructor"), exports); | ||
__exportStar(require("./construction/plugin-loader"), exports); | ||
/** extensions */ | ||
__export(require("./extensions/ellipsis-location")); | ||
/** external */ | ||
__export(require("./integrations/defects/issue")); | ||
__export(require("./integrations/test-cases/test-result-metadata")); | ||
__export(require("./integrations/test-cases/test-result")); | ||
__export(require("./integrations/test-cases/test-status")); | ||
__exportStar(require("./extensions/ellipsis-location"), exports); | ||
__exportStar(require("./extensions/set-extensions"), exports); | ||
__exportStar(require("./extensions/string-extensions"), exports); | ||
/** helpers */ | ||
__export(require("./helpers/build-info")); | ||
__export(require("./helpers/convert")); | ||
__export(require("./helpers/machine-info")); | ||
__export(require("./helpers/random-generator")); | ||
__export(require("./helpers/using")); | ||
__export(require("./helpers/wait")); | ||
__export(require("./logging/test-log")); | ||
__export(require("./logging/test-log-options")); | ||
__export(require("./logging/test-log-level")); | ||
__exportStar(require("./helpers/build-info"), exports); | ||
__exportStar(require("./helpers/build-info-plugin-manager"), exports); | ||
__exportStar(require("./helpers/ibuild-info-handler-plugin"), exports); | ||
__exportStar(require("./helpers/cloner"), exports); | ||
__exportStar(require("./helpers/convert"), exports); | ||
__exportStar(require("./helpers/icloneable"), exports); | ||
__exportStar(require("./helpers/idisposable"), exports); | ||
__exportStar(require("./helpers/processing-result"), exports); | ||
__exportStar(require("./helpers/machine-info"), exports); | ||
__exportStar(require("./helpers/random-generator"), exports); | ||
__exportStar(require("./helpers/safe-string-option"), exports); | ||
__exportStar(require("./helpers/using"), exports); | ||
__exportStar(require("./helpers/wait"), exports); | ||
__exportStar(require("./helpers/func"), exports); | ||
__exportStar(require("./helpers/action"), exports); | ||
/** integrations */ | ||
__exportStar(require("./integrations/defects/plugins/idefect-handler-plugin"), exports); | ||
__exportStar(require("./integrations/defects/defect-plugin-manager"), exports); | ||
__exportStar(require("./integrations/defects/defect-status"), exports); | ||
__exportStar(require("./integrations/defects/idefect"), exports); | ||
__exportStar(require("./integrations/test-cases/plugins/itest-case-handler-plugin"), exports); | ||
__exportStar(require("./integrations/test-cases/itest-case"), exports); | ||
__exportStar(require("./integrations/test-cases/test-case-plugin-manager"), exports); | ||
__exportStar(require("./integrations/test-cases/test-exception"), exports); | ||
__exportStar(require("./integrations/test-cases/itest-result"), exports); | ||
__exportStar(require("./integrations/test-cases/test-status"), exports); | ||
/** logging */ | ||
__exportStar(require("./logging/plugins/ilogging-plugin"), exports); | ||
__exportStar(require("./logging/test-log"), exports); | ||
__exportStar(require("./logging/logging-options"), exports); | ||
__exportStar(require("./logging/logging-level"), exports); | ||
/** wrappers */ | ||
__export(require("./wrappers/test-wrapper")); | ||
__export(require("./wrappers/test-wrapper-options")); | ||
__export(require("./wrappers/should")); | ||
__export(require("./wrappers/validation-error")); | ||
__export(require("./wrappers/validator")); | ||
__exportStar(require("./wrappers/test-wrapper"), exports); | ||
__exportStar(require("./wrappers/test-wrapper-options"), exports); | ||
__exportStar(require("./wrappers/should"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -6,3 +6,3 @@ import '../../extensions/string-extensions'; | ||
StackTrace: string; | ||
constructor(err: Error, full: boolean); | ||
constructor(err: Error, full?: boolean); | ||
private removeBadCharacters; | ||
@@ -9,0 +9,0 @@ asSimpleString(): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TestException = void 0; | ||
require("../../extensions/string-extensions"); | ||
var TestException = /** @class */ (function () { | ||
function TestException(err, full) { | ||
if (full === void 0) { full = true; } | ||
if (err) { | ||
@@ -7,0 +9,0 @@ var message = this.removeBadCharacters(err.message); |
export declare enum TestStatus { | ||
Passed = 0, | ||
Blocked = 1, | ||
Untested = 2, | ||
Untested = 0, | ||
Passed = 1, | ||
Blocked = 2, | ||
Retest = 3, | ||
@@ -6,0 +6,0 @@ Failed = 4, |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TestStatus = void 0; | ||
var TestStatus; | ||
(function (TestStatus) { | ||
TestStatus[TestStatus["Passed"] = 0] = "Passed"; | ||
TestStatus[TestStatus["Blocked"] = 1] = "Blocked"; | ||
TestStatus[TestStatus["Untested"] = 2] = "Untested"; | ||
TestStatus[TestStatus["Untested"] = 0] = "Untested"; | ||
TestStatus[TestStatus["Passed"] = 1] = "Passed"; | ||
TestStatus[TestStatus["Blocked"] = 2] = "Blocked"; | ||
TestStatus[TestStatus["Retest"] = 3] = "Retest"; | ||
@@ -9,0 +10,0 @@ TestStatus[TestStatus["Failed"] = 4] = "Failed"; |
@@ -1,10 +0,9 @@ | ||
import { TestLogLevel } from "../test-log-level"; | ||
import { TestResult } from "../../integrations/test-cases/test-result"; | ||
export interface ILoggingPlugin { | ||
name: string; | ||
level(): Promise<TestLogLevel>; | ||
enabled(): Promise<boolean>; | ||
log(level: TestLogLevel, message: string): Promise<void>; | ||
logResult(result: TestResult): Promise<void>; | ||
import { IPlugin } from "../../construction/iplugin"; | ||
import { ITestResult } from "../../integrations/test-cases/itest-result"; | ||
import { LoggingLevel } from "../logging-level"; | ||
export interface ILoggingPlugin extends IPlugin { | ||
level(): Promise<LoggingLevel>; | ||
log(level: LoggingLevel, message: string): Promise<void>; | ||
logResult(result: ITestResult): Promise<void>; | ||
finalise(): Promise<void>; | ||
} |
@@ -1,29 +0,81 @@ | ||
import { TestLogOptions } from "./test-log-options"; | ||
import { TestResult } from "../integrations/test-cases/test-result"; | ||
import { ITestResult } from "../integrations/test-cases/itest-result"; | ||
import { ILoggingPlugin } from "./plugins/ilogging-plugin"; | ||
import { IDisposable } from "../helpers/idisposable"; | ||
import { TestLogLevel } from "./test-log-level"; | ||
export declare class TestLog implements IDisposable { | ||
name: string; | ||
stepCount: number; | ||
options: TestLogOptions; | ||
constructor(options: TestLogOptions); | ||
private _lvl; | ||
level(): Promise<TestLogLevel>; | ||
import { LoggingLevel } from "./logging-level"; | ||
import { LoggingOptions } from "./logging-options"; | ||
export declare class TestLog { | ||
private _name; | ||
private _stepCount; | ||
private _options; | ||
private _level; | ||
private _plugins; | ||
constructor(options?: LoggingOptions); | ||
name(): string; | ||
stepCount(): number; | ||
initName(name: string): void; | ||
options(): Promise<LoggingOptions>; | ||
level(): Promise<LoggingLevel>; | ||
plugins(): Promise<ILoggingPlugin[]>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Trace` | ||
* @param message the message to be logged | ||
*/ | ||
trace(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Debug` | ||
* @param message the message to be logged | ||
*/ | ||
debug(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Info` | ||
* @param message the message to be logged | ||
*/ | ||
info(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Step` | ||
* @param message the message to be logged | ||
*/ | ||
step(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Warn` | ||
* @param message the message to be logged | ||
*/ | ||
warn(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Pass` | ||
* @param message the message to be logged | ||
*/ | ||
pass(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Fail` | ||
* @param message the message to be logged | ||
*/ | ||
fail(message: string): Promise<void>; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Error` | ||
* @param message the message to be logged | ||
*/ | ||
error(message: string): Promise<void>; | ||
log(level: TestLogLevel, message: string): Promise<void>; | ||
logResult(result: TestResult): Promise<void>; | ||
dispose(error?: Error): Promise<void>; | ||
/** | ||
* function will log the passed in `message` if its `level` is equal to | ||
* or higher than the configured `logging.level` before sending the `level` | ||
* and `message` on to any loaded `ILoggingPlugin` objects | ||
* @param level the `LoggingLevel` of this message | ||
* @param message the string to be logged | ||
*/ | ||
log(level: LoggingLevel, message: string): Promise<void>; | ||
/** | ||
* function will send the passed in `TestResult` to any loaded `ILoggingPlugin` objects | ||
* allowing them to process the result | ||
* @param result a `TestResult` object to be sent | ||
*/ | ||
logResult(result: ITestResult): Promise<void>; | ||
/** | ||
* loops through any loaded `ILoggingPlugin` objects and calls | ||
* their `finalise` function. This should be called upon completion | ||
* of any logging actions before destroying the `TestLog` instance | ||
*/ | ||
finalise(): Promise<void>; | ||
} | ||
export declare module TestLog { | ||
function format(name: string, level: TestLogLevel, message: string): string; | ||
function format(name: string, level: LoggingLevel, message: string): string; | ||
} |
@@ -38,50 +38,40 @@ "use strict"; | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spread = (this && this.__spread) || function () { | ||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var test_log_options_1 = require("./test-log-options"); | ||
var test_log_level_1 = require("./test-log-level"); | ||
exports.TestLog = void 0; | ||
var logging_level_1 = require("./logging-level"); | ||
var plugin_loader_1 = require("../construction/plugin-loader"); | ||
var test_config_1 = require("../configuration/test-config"); | ||
var convert_1 = require("../helpers/convert"); | ||
var cloner_1 = require("../helpers/cloner"); | ||
var random_generator_1 = require("../helpers/random-generator"); | ||
var ellipsis_location_1 = require("../extensions/ellipsis-location"); | ||
var TestLog = /** @class */ (function () { | ||
function TestLog(options) { | ||
this.stepCount = 0; | ||
this.name = options.name; | ||
this.options = options; | ||
var _a; | ||
this._stepCount = 0; | ||
this._options = options; | ||
this.initName(((_a = this._options) === null || _a === void 0 ? void 0 : _a.name) || "TestLog_" + random_generator_1.RG.getGuid()); | ||
} | ||
TestLog.prototype.level = function () { | ||
TestLog.prototype.name = function () { | ||
return this._name; | ||
}; | ||
TestLog.prototype.stepCount = function () { | ||
return this._stepCount; | ||
}; | ||
TestLog.prototype.initName = function (name) { | ||
this._name = convert_1.Convert.toSafeString(name).ellide(50, ellipsis_location_1.EllipsisLocation.middle); | ||
}; | ||
TestLog.prototype.options = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _a, _b; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (!!this._lvl) return [3 /*break*/, 3]; | ||
if (!!this._options) return [3 /*break*/, 2]; | ||
_a = this; | ||
_b = this.options.level; | ||
if (_b) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, test_log_options_1.TestLogOptions.level()]; | ||
return [4 /*yield*/, test_config_1.TestConfig.get("logging")]; | ||
case 1: | ||
_b = (_c.sent()); | ||
_c.label = 2; | ||
case 2: | ||
_a._lvl = _b; | ||
_c.label = 3; | ||
case 3: return [2 /*return*/, this._lvl]; | ||
_a._options = _b.sent(); | ||
_b.label = 2; | ||
case 2: return [2 /*return*/, this._options]; | ||
} | ||
@@ -91,23 +81,50 @@ }); | ||
}; | ||
TestLog.prototype.level = function () { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _b, _c, _d; | ||
return __generator(this, function (_e) { | ||
switch (_e.label) { | ||
case 0: | ||
if (!!this._level) return [3 /*break*/, 2]; | ||
_b = this; | ||
_d = (_c = logging_level_1.LoggingLevel).parse; | ||
return [4 /*yield*/, this.options()]; | ||
case 1: | ||
_b._level = _d.apply(_c, [((_a = (_e.sent())) === null || _a === void 0 ? void 0 : _a.level) || logging_level_1.LoggingLevel.info.name]); | ||
_e.label = 2; | ||
case 2: return [2 /*return*/, this._level]; | ||
} | ||
}); | ||
}); | ||
}; | ||
TestLog.prototype.plugins = function () { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var names, _a, _b; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var names, i, name_1, p; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (!!this._plugins) return [3 /*break*/, 4]; | ||
_a = this.options.pluginNames; | ||
if (_a) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, test_log_options_1.TestLogOptions.pluginNames()]; | ||
if (!!this._plugins) return [3 /*break*/, 5]; | ||
this._plugins = []; | ||
return [4 /*yield*/, this.options()]; | ||
case 1: | ||
_a = (_c.sent()); | ||
_c.label = 2; | ||
names = ((_a = (_b.sent())) === null || _a === void 0 ? void 0 : _a.pluginNames) || []; | ||
i = 0; | ||
_b.label = 2; | ||
case 2: | ||
names = _a; | ||
_b = this; | ||
return [4 /*yield*/, plugin_loader_1.PluginLoader.load.apply(plugin_loader_1.PluginLoader, __spread(names))]; | ||
if (!(i < names.length)) return [3 /*break*/, 5]; | ||
name_1 = names[i]; | ||
if (!name_1) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, plugin_loader_1.PluginLoader.load(name_1)]; | ||
case 3: | ||
_b._plugins = _c.sent(); | ||
_c.label = 4; | ||
case 4: return [2 /*return*/, this._plugins]; | ||
p = _b.sent(); | ||
if (p) { | ||
this._plugins.push(p); | ||
} | ||
_b.label = 4; | ||
case 4: | ||
i++; | ||
return [3 /*break*/, 2]; | ||
case 5: return [2 /*return*/, this._plugins]; | ||
} | ||
@@ -117,2 +134,6 @@ }); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Trace` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.trace = function (message) { | ||
@@ -122,3 +143,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.trace, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.trace, message)]; | ||
case 1: | ||
@@ -131,2 +152,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Debug` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.debug = function (message) { | ||
@@ -136,3 +161,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.debug, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.debug, message)]; | ||
case 1: | ||
@@ -145,2 +170,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Info` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.info = function (message) { | ||
@@ -150,3 +179,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.info, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.info, message)]; | ||
case 1: | ||
@@ -159,2 +188,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Step` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.step = function (message) { | ||
@@ -164,3 +197,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.step, ++this.stepCount + ': ' + message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.step, ++this._stepCount + ': ' + message)]; | ||
case 1: | ||
@@ -173,2 +206,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Warn` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.warn = function (message) { | ||
@@ -178,3 +215,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.warn, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.warn, message)]; | ||
case 1: | ||
@@ -187,2 +224,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Pass` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.pass = function (message) { | ||
@@ -192,3 +233,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.pass, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.pass, message)]; | ||
case 1: | ||
@@ -201,2 +242,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Fail` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.fail = function (message) { | ||
@@ -206,3 +251,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.fail, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.fail, message)]; | ||
case 1: | ||
@@ -215,2 +260,6 @@ _a.sent(); | ||
}; | ||
/** | ||
* calls the `log` function with a `level` of `LoggingLevel.Error` | ||
* @param message the message to be logged | ||
*/ | ||
TestLog.prototype.error = function (message) { | ||
@@ -220,3 +269,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.log(test_log_level_1.TestLogLevel.error, message)]; | ||
case 0: return [4 /*yield*/, this.log(logging_level_1.LoggingLevel.error, message)]; | ||
case 1: | ||
@@ -229,2 +278,9 @@ _a.sent(); | ||
}; | ||
/** | ||
* function will log the passed in `message` if its `level` is equal to | ||
* or higher than the configured `logging.level` before sending the `level` | ||
* and `message` on to any loaded `ILoggingPlugin` objects | ||
* @param level the `LoggingLevel` of this message | ||
* @param message the string to be logged | ||
*/ | ||
TestLog.prototype.log = function (level, message) { | ||
@@ -238,4 +294,4 @@ return __awaiter(this, void 0, void 0, function () { | ||
l = _a.sent(); | ||
if (level.value >= l.value && level != test_log_level_1.TestLogLevel.none) { | ||
console.log(TestLog.format(this.name, level, message)); | ||
if (level.value >= l.value && level != logging_level_1.LoggingLevel.none) { | ||
console.log(TestLog.format(this.name(), level, message)); | ||
} | ||
@@ -250,6 +306,7 @@ return [4 /*yield*/, this.plugins()]; | ||
p = plugins[i]; | ||
if (!p) return [3 /*break*/, 9]; | ||
_a.label = 4; | ||
case 4: | ||
_a.trys.push([4, 8, , 9]); | ||
return [4 /*yield*/, p.enabled()]; | ||
return [4 /*yield*/, p.isEnabled()]; | ||
case 5: | ||
@@ -265,3 +322,3 @@ enabled = _a.sent(); | ||
e_1 = _a.sent(); | ||
console.log(TestLog.format(this.name, test_log_level_1.TestLogLevel.warn, "unable to send log message to '" + p.name + "' plugin due to: " + e_1)); | ||
console.warn(TestLog.format(this.name(), logging_level_1.LoggingLevel.warn, "unable to send log message to '" + (p.name || 'unknown') + "' plugin due to: " + e_1)); | ||
return [3 /*break*/, 9]; | ||
@@ -276,2 +333,7 @@ case 9: | ||
}; | ||
/** | ||
* function will send the passed in `TestResult` to any loaded `ILoggingPlugin` objects | ||
* allowing them to process the result | ||
* @param result a `TestResult` object to be sent | ||
*/ | ||
TestLog.prototype.logResult = function (result) { | ||
@@ -290,10 +352,11 @@ return __awaiter(this, void 0, void 0, function () { | ||
p = plugins[i]; | ||
if (!p) return [3 /*break*/, 8]; | ||
_a.label = 3; | ||
case 3: | ||
_a.trys.push([3, 7, , 8]); | ||
return [4 /*yield*/, p.enabled()]; | ||
return [4 /*yield*/, p.isEnabled()]; | ||
case 4: | ||
enabled = _a.sent(); | ||
if (!enabled) return [3 /*break*/, 6]; | ||
r = result.clone(); | ||
r = cloner_1.Cloner.clone(result); | ||
return [4 /*yield*/, p.logResult(r)]; | ||
@@ -306,3 +369,3 @@ case 5: | ||
e_2 = _a.sent(); | ||
console.log(TestLog.format(this.name, test_log_level_1.TestLogLevel.warn, "unable to send result to '" + p.name + "' plugin due to: " + e_2)); | ||
console.warn(TestLog.format(this._name, logging_level_1.LoggingLevel.warn, "unable to send result to '" + (p.name || 'unknown') + "' plugin due to: " + e_2)); | ||
return [3 /*break*/, 8]; | ||
@@ -317,3 +380,8 @@ case 8: | ||
}; | ||
TestLog.prototype.dispose = function (error) { | ||
/** | ||
* loops through any loaded `ILoggingPlugin` objects and calls | ||
* their `finalise` function. This should be called upon completion | ||
* of any logging actions before destroying the `TestLog` instance | ||
*/ | ||
TestLog.prototype.finalise = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -334,3 +402,3 @@ var plugins, i, p, enabled, e_3; | ||
_a.trys.push([3, 7, , 8]); | ||
return [4 /*yield*/, p.enabled()]; | ||
return [4 /*yield*/, p.isEnabled()]; | ||
case 4: | ||
@@ -346,3 +414,3 @@ enabled = _a.sent(); | ||
e_3 = _a.sent(); | ||
console.log(TestLog.format(this.name, test_log_level_1.TestLogLevel.warn, "unable to call finalise on " + p.name + " due to: " + e_3)); | ||
console.log(TestLog.format(this.name(), logging_level_1.LoggingLevel.warn, "unable to call finalise on " + p.name + " due to: " + e_3)); | ||
return [3 /*break*/, 8]; | ||
@@ -349,0 +417,0 @@ case 8: |
@@ -1,3 +0,16 @@ | ||
import { Validator } from "./validator"; | ||
import { Func } from "../helpers/func"; | ||
export declare function should(result: Func<void, boolean>): Validator; | ||
import { ProcessingResult } from "../helpers/processing-result"; | ||
import { TestWrapperOptions } from "./test-wrapper-options"; | ||
import { TestWrapper } from "./test-wrapper"; | ||
/** | ||
* function creates a new TestWrapper that can be used like: | ||
* ``` | ||
* await should(() => expect(true).toBeTruthy(), {description: 'expect true will always be truthy'}); | ||
* await should(() => expect(false).toBeFalsy(), {testCases: ['C1234'], description: 'expect false is always falsy'}); | ||
* await should(() => expect('foo').toBe('foo')); | ||
* await should((tw) => tw.logger().warn('foo'); expect('foo').not.toBe('bar')); | ||
* ``` | ||
* @param expectation a function containing a test expectation like Jasmine `expect` or Chai `expect` | ||
* @param options an optional `ITestWrapperOptions` object containing additional options | ||
*/ | ||
export declare const should: (expectation: Func<TestWrapper, any>, options?: TestWrapperOptions) => Promise<ProcessingResult>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var validator_1 = require("./validator"); | ||
function should(result) { | ||
return new validator_1.Validator(result); | ||
} | ||
exports.should = should; | ||
exports.should = void 0; | ||
var test_wrapper_1 = require("./test-wrapper"); | ||
/** | ||
* function creates a new TestWrapper that can be used like: | ||
* ``` | ||
* await should(() => expect(true).toBeTruthy(), {description: 'expect true will always be truthy'}); | ||
* await should(() => expect(false).toBeFalsy(), {testCases: ['C1234'], description: 'expect false is always falsy'}); | ||
* await should(() => expect('foo').toBe('foo')); | ||
* await should((tw) => tw.logger().warn('foo'); expect('foo').not.toBe('bar')); | ||
* ``` | ||
* @param expectation a function containing a test expectation like Jasmine `expect` or Chai `expect` | ||
* @param options an optional `ITestWrapperOptions` object containing additional options | ||
*/ | ||
exports.should = function (expectation, options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var t; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
t = new test_wrapper_1.TestWrapper(expectation, options); | ||
return [4 /*yield*/, t.run()]; | ||
case 1: return [2 /*return*/, _a.sent()]; | ||
} | ||
}); | ||
}); | ||
}; | ||
//# sourceMappingURL=should.js.map |
@@ -0,8 +1,13 @@ | ||
import { BuildInfoPluginManager } from "../helpers/build-info-plugin-manager"; | ||
import { DefectPluginManager } from "../integrations/defects/defect-plugin-manager"; | ||
import { TestCasePluginManager } from "../integrations/test-cases/test-case-plugin-manager"; | ||
import { TestLog } from "../logging/test-log"; | ||
export declare class TestWrapperOptions { | ||
name: string; | ||
logger: TestLog; | ||
testCases: Set<string>; | ||
defects: Set<string>; | ||
constructor(name: string); | ||
export interface TestWrapperOptions { | ||
buildInfoPluginManager?: BuildInfoPluginManager; | ||
defects?: string[]; | ||
defectPluginManager?: DefectPluginManager; | ||
logger?: TestLog; | ||
testCases?: string[]; | ||
testCasePluginManager?: TestCasePluginManager; | ||
description?: string; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var TestWrapperOptions = /** @class */ (function () { | ||
function TestWrapperOptions(name) { | ||
this.testCases = new Set(); | ||
this.defects = new Set(); | ||
this.name = name; | ||
} | ||
return TestWrapperOptions; | ||
}()); | ||
exports.TestWrapperOptions = TestWrapperOptions; | ||
//# sourceMappingURL=test-wrapper-options.js.map |
import { TestLog } from "../logging/test-log"; | ||
import { Func } from "../helpers/func"; | ||
import { TestWrapperOptions } from "./test-wrapper-options"; | ||
import { TestStatus } from "../integrations/test-cases/test-status"; | ||
import { IDisposable } from "../helpers/idisposable"; | ||
import '../extensions/string-extensions'; | ||
import '../extensions/set-extensions'; | ||
import { Action } from "../helpers/action"; | ||
import { ProcessingResult } from "../helpers/processing-result"; | ||
/** | ||
* provides helper methods and properties for use when integration or functional testing | ||
* provides pre-test execution filtering based on specified | ||
* test IDs or defect IDs and post-test results logging. usage | ||
* is intended to be managed through the `should(expectation, options)` | ||
* function via: | ||
* ``` | ||
* should(() => expect(true).toBeTruthy(), {description: 'expect true is truthy'}); | ||
* ``` | ||
*/ | ||
export declare class TestWrapper implements IDisposable { | ||
name: string; | ||
logger: TestLog; | ||
testCases: Set<string>; | ||
defects: Set<string>; | ||
errors: Error[]; | ||
private startTime; | ||
private loggedCases; | ||
constructor(options: TestWrapperOptions); | ||
private initialiseLogger; | ||
private initialiseTestCases; | ||
private initialiseDefects; | ||
export declare class TestWrapper { | ||
private _expectation; | ||
private _description; | ||
private _logger; | ||
private _testCases; | ||
private _defects; | ||
private _errors; | ||
private _startTime; | ||
private _loggedCases; | ||
private _testCaseManager; | ||
private _defectManager; | ||
private _buildInfoManager; | ||
/** | ||
* logs the passed in message and then sends an ExternalTestResult | ||
* to any referenced ILoggingPlugins for handling with external systems | ||
* @param testId the ID of the current test | ||
* @param status the ExternalTestStatus for the result | ||
* @param message the message to be sent in the result | ||
* this class is intended to be utilised via the `should(expectation, options)` function | ||
* and not directly... | ||
* @param expectation a function containing some expectation like `expect(true).toBeFalsy()` or | ||
* `'foo' == 'foo'` where the function either accepts no arguments or one argument of type `TestWrapper` | ||
* ex: | ||
* ``` | ||
* let tw: TestWrapper = new TestWrapper((t) => { | ||
* await t.logger().info("using the TestWrapper's logger"); | ||
* let foo = 'foo'; | ||
* return foo == 'foo'; | ||
* }); | ||
* await tw.run(); | ||
* ``` | ||
* @param options optional `ITestWrapperOptions` allowing test IDs, defect IDs and a `description` to be passed in | ||
*/ | ||
addTestResult(testId: string, status: TestStatus, message?: string): Promise<void>; | ||
constructor(expectation: Func<TestWrapper, any>, options?: TestWrapperOptions); | ||
expectation(): Func<TestWrapper, any>; | ||
description(): string; | ||
logger(): TestLog; | ||
testCases(): string[]; | ||
defects(): string[]; | ||
errors(): string[]; | ||
startTime(): number; | ||
loggedCases(): string[]; | ||
/** | ||
* DANGER!!: this method does not catch 'jasmine.expect' failures unless | ||
* you've wrapped the expect call using 'should(expect(actual).toBe(expected)).because('reason');' | ||
* this function runs the passed in test action and then calls 'addTestResult' | ||
* based on the results of the call | ||
* @param testId the test ID being validated | ||
* @param action the test action being performed | ||
* checks if the expectation should be executed and if so runs it | ||
* and returns the result via an `IProcessingResult` | ||
*/ | ||
check(testId: string, action: Action<void>): Promise<void>; | ||
run(): Promise<ProcessingResult>; | ||
private _initialiseName; | ||
private _initialiseLogger; | ||
private _initialiseTestCases; | ||
private _initialiseDefects; | ||
private _initialiseBuildInfo; | ||
/** | ||
* runs the passed in action, passing in a new Validator | ||
* as an argument and returns any Errors thrown | ||
* instead of letting the Error out | ||
* @param action the action to run | ||
* creates `ITestResult` objects for each `testId` and sends these | ||
* to the `TestLog.logResult` function | ||
* @param result an `IProcessingResult` returned from executing the | ||
* expectation | ||
*/ | ||
runAction(action: Action<void>): Promise<Error>; | ||
dispose(error?: Error): Promise<void>; | ||
private generateTestResult; | ||
private logRemainingCases; | ||
private disposeLogger; | ||
private _logResult; | ||
private _logMessage; | ||
/** | ||
* checks the specified test IDs to determine if the | ||
* expectation should be executed and returns a result | ||
* based on execution or why it should not be run | ||
*/ | ||
private _beginProcessing; | ||
private _shouldRun; | ||
private _shouldRun_tests; | ||
private _shouldRun_defects; | ||
private _generateTestResults; | ||
private _generateTestResult; | ||
} |
@@ -38,112 +38,214 @@ "use strict"; | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spread = (this && this.__spread) || function () { | ||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TestWrapper = void 0; | ||
var test_log_1 = require("../logging/test-log"); | ||
var test_log_options_1 = require("../logging/test-log-options"); | ||
var random_generator_1 = require("../helpers/random-generator"); | ||
var test_status_1 = require("../integrations/test-cases/test-status"); | ||
var test_result_1 = require("../integrations/test-cases/test-result"); | ||
var test_result_metadata_1 = require("../integrations/test-cases/test-result-metadata"); | ||
require("../extensions/string-extensions"); | ||
require("../extensions/set-extensions"); | ||
var test_exception_1 = require("../integrations/test-cases/test-exception"); | ||
var convert_1 = require("../helpers/convert"); | ||
var test_case_plugin_manager_1 = require("../integrations/test-cases/test-case-plugin-manager"); | ||
var defect_plugin_manager_1 = require("../integrations/defects/defect-plugin-manager"); | ||
var defect_status_1 = require("../integrations/defects/defect-status"); | ||
var random_generator_1 = require("../helpers/random-generator"); | ||
var build_info_plugin_manager_1 = require("../helpers/build-info-plugin-manager"); | ||
/** | ||
* provides helper methods and properties for use when integration or functional testing | ||
* provides pre-test execution filtering based on specified | ||
* test IDs or defect IDs and post-test results logging. usage | ||
* is intended to be managed through the `should(expectation, options)` | ||
* function via: | ||
* ``` | ||
* should(() => expect(true).toBeTruthy(), {description: 'expect true is truthy'}); | ||
* ``` | ||
*/ | ||
var TestWrapper = /** @class */ (function () { | ||
function TestWrapper(options) { | ||
this.testCases = new Set(); | ||
this.defects = new Set(); | ||
this.errors = []; | ||
this.loggedCases = new Set(); | ||
this.name = options.name || random_generator_1.RandomGenerator.getGuid(); | ||
this.initialiseLogger(options); | ||
this.initialiseTestCases(options); | ||
this.initialiseDefects(options); | ||
this.startTime = new Date().getTime(); | ||
/** | ||
* this class is intended to be utilised via the `should(expectation, options)` function | ||
* and not directly... | ||
* @param expectation a function containing some expectation like `expect(true).toBeFalsy()` or | ||
* `'foo' == 'foo'` where the function either accepts no arguments or one argument of type `TestWrapper` | ||
* ex: | ||
* ``` | ||
* let tw: TestWrapper = new TestWrapper((t) => { | ||
* await t.logger().info("using the TestWrapper's logger"); | ||
* let foo = 'foo'; | ||
* return foo == 'foo'; | ||
* }); | ||
* await tw.run(); | ||
* ``` | ||
* @param options optional `ITestWrapperOptions` allowing test IDs, defect IDs and a `description` to be passed in | ||
*/ | ||
function TestWrapper(expectation, options) { | ||
this._testCases = []; | ||
this._defects = []; | ||
this._errors = []; | ||
this._loggedCases = []; | ||
this._testCaseManager = null; | ||
this._defectManager = null; | ||
this._buildInfoManager = null; | ||
this._expectation = expectation; | ||
this._initialiseName(options); | ||
this._initialiseLogger(options); | ||
this._initialiseTestCases(options); | ||
this._initialiseDefects(options); | ||
this._initialiseBuildInfo(options); | ||
} | ||
TestWrapper.prototype.initialiseLogger = function (options) { | ||
this.logger = options.logger || new test_log_1.TestLog(new test_log_options_1.TestLogOptions(this.name)); | ||
TestWrapper.prototype.expectation = function () { | ||
return this._expectation; | ||
}; | ||
TestWrapper.prototype.initialiseTestCases = function (options) { | ||
TestWrapper.prototype.description = function () { | ||
return this._description; | ||
}; | ||
TestWrapper.prototype.logger = function () { | ||
return this._logger; | ||
}; | ||
TestWrapper.prototype.testCases = function () { | ||
return this._testCases; | ||
}; | ||
TestWrapper.prototype.defects = function () { | ||
return this._defects; | ||
}; | ||
TestWrapper.prototype.errors = function () { | ||
return this._errors; | ||
}; | ||
TestWrapper.prototype.startTime = function () { | ||
return this._startTime; | ||
}; | ||
TestWrapper.prototype.loggedCases = function () { | ||
return this._loggedCases; | ||
}; | ||
/** | ||
* checks if the expectation should be executed and if so runs it | ||
* and returns the result via an `IProcessingResult` | ||
*/ | ||
TestWrapper.prototype.run = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var result; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
this._startTime = new Date().getTime(); | ||
return [4 /*yield*/, this._beginProcessing()]; | ||
case 1: | ||
result = _a.sent(); | ||
return [4 /*yield*/, this._logResult(result)]; | ||
case 2: | ||
_a.sent(); | ||
return [2 /*return*/, result]; | ||
} | ||
}); | ||
}); | ||
}; | ||
TestWrapper.prototype._initialiseName = function (options) { | ||
var _a, _b; | ||
this._description = options === null || options === void 0 ? void 0 : options.description; | ||
if (!this._description && ((_a = options === null || options === void 0 ? void 0 : options.testCases) === null || _a === void 0 ? void 0 : _a.length) > 0) { | ||
this._description = "Tests [" + ((_b = options === null || options === void 0 ? void 0 : options.testCases) === null || _b === void 0 ? void 0 : _b.join(',')) + "]"; | ||
} | ||
if (!this._description) { | ||
this._description = "TestWrapper_" + random_generator_1.RandomGenerator.getGuid(); | ||
} | ||
}; | ||
TestWrapper.prototype._initialiseLogger = function (options) { | ||
this._logger = (options === null || options === void 0 ? void 0 : options.logger) || new test_log_1.TestLog({ name: this.description() }); | ||
}; | ||
TestWrapper.prototype._initialiseTestCases = function (options) { | ||
var _this = this; | ||
options.testCases.forEach(function (c) { | ||
_this.testCases.add(c); | ||
var _a; | ||
this._testCaseManager = (options === null || options === void 0 ? void 0 : options.testCasePluginManager) || test_case_plugin_manager_1.TestCasePluginManager.instance(); | ||
(_a = options === null || options === void 0 ? void 0 : options.testCases) === null || _a === void 0 ? void 0 : _a.forEach(function (c) { | ||
_this.testCases().push(c); | ||
}); | ||
// TODO: implement plugin system for TestCaseHandler Plugins | ||
}; | ||
TestWrapper.prototype.initialiseDefects = function (options) { | ||
TestWrapper.prototype._initialiseDefects = function (options) { | ||
var _this = this; | ||
options.defects.forEach(function (d) { | ||
_this.defects.add(d); | ||
var _a; | ||
this._defectManager = (options === null || options === void 0 ? void 0 : options.defectPluginManager) || defect_plugin_manager_1.DefectPluginManager.instance(); | ||
(_a = options === null || options === void 0 ? void 0 : options.defects) === null || _a === void 0 ? void 0 : _a.forEach(function (d) { | ||
_this.defects().push(d); | ||
}); | ||
// TODO: implement plugin system for DefectHandler Plugins | ||
}; | ||
TestWrapper.prototype._initialiseBuildInfo = function (options) { | ||
this._buildInfoManager = (options === null || options === void 0 ? void 0 : options.buildInfoPluginManager) || build_info_plugin_manager_1.BuildInfoPluginManager.instance(); | ||
}; | ||
/** | ||
* logs the passed in message and then sends an ExternalTestResult | ||
* to any referenced ILoggingPlugins for handling with external systems | ||
* @param testId the ID of the current test | ||
* @param status the ExternalTestStatus for the result | ||
* @param message the message to be sent in the result | ||
* creates `ITestResult` objects for each `testId` and sends these | ||
* to the `TestLog.logResult` function | ||
* @param result an `IProcessingResult` returned from executing the | ||
* expectation | ||
*/ | ||
TestWrapper.prototype.addTestResult = function (testId, status, message) { | ||
TestWrapper.prototype._logResult = function (result) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var fullMessage, result, e_1; | ||
var status, message, i, testId, results, i, result_1, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!!this.loggedCases.has(testId)) return [3 /*break*/, 7]; | ||
if (!message) { | ||
message = ''; | ||
} | ||
fullMessage = test_status_1.TestStatus[status] + ' - ' + testId + ': ' + message; | ||
if (!(this.testCases.size == 0 || this.testCases.has(testId))) return [3 /*break*/, 5]; | ||
switch (status) { | ||
case test_status_1.TestStatus.Blocked: | ||
case test_status_1.TestStatus.Retest: | ||
case test_status_1.TestStatus.Skipped: | ||
case test_status_1.TestStatus.Untested: | ||
this.logger.warn(fullMessage); | ||
break; | ||
case test_status_1.TestStatus.Failed: | ||
this.logger.error(fullMessage); | ||
break; | ||
case test_status_1.TestStatus.Passed: | ||
default: | ||
this.logger.pass(fullMessage); | ||
break; | ||
} | ||
status = result.obj || test_status_1.TestStatus.Untested; | ||
message = test_status_1.TestStatus[status] + " - " + (result.message || ''); | ||
if (!(this.testCases().length > 0)) return [3 /*break*/, 5]; | ||
i = 0; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 3, , 4]); | ||
result = this.generateTestResult(testId, status, fullMessage); | ||
return [4 /*yield*/, this.logger.logResult(result)]; | ||
if (!(i < this.testCases().length)) return [3 /*break*/, 4]; | ||
testId = this.testCases()[i]; | ||
return [4 /*yield*/, this._logMessage(status, testId + " " + message)]; | ||
case 2: | ||
_a.sent(); | ||
this.loggedCases.add(testId); | ||
return [3 /*break*/, 4]; | ||
_a.label = 3; | ||
case 3: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 4: return [3 /*break*/, 7]; | ||
case 5: return [4 /*yield*/, this._logMessage(status, message)]; | ||
case 6: | ||
_a.sent(); | ||
_a.label = 7; | ||
case 7: return [4 /*yield*/, this._generateTestResults.apply(this, __spread([status, message], this.testCases()))]; | ||
case 8: | ||
results = _a.sent(); | ||
i = 0; | ||
_a.label = 9; | ||
case 9: | ||
if (!(i < results.length)) return [3 /*break*/, 15]; | ||
result_1 = results[i]; | ||
_a.label = 10; | ||
case 10: | ||
_a.trys.push([10, 12, , 14]); | ||
return [4 /*yield*/, this.logger().logResult(result_1)]; | ||
case 11: | ||
_a.sent(); | ||
if (result_1.testId) { | ||
this._loggedCases.push(result_1.testId); | ||
} | ||
return [3 /*break*/, 14]; | ||
case 12: | ||
e_1 = _a.sent(); | ||
this.logger.warn("unable to 'addTestResult' for test '" + testId + "' due to: " + e_1); | ||
return [3 /*break*/, 4]; | ||
case 4: return [3 /*break*/, 6]; | ||
case 5: | ||
this.logger.warn("test '" + testId + "' is not a valid test ID; please use one of [" + this.testCases.join(',') + "] instead; no result will be submitted."); | ||
_a.label = 6; | ||
case 6: return [3 /*break*/, 8]; | ||
case 7: | ||
this.logger.warn("you are attempting to add a second result for test '" + testId + "' which already has a result; no result will be submitted."); | ||
_a.label = 8; | ||
case 8: return [2 /*return*/]; | ||
return [4 /*yield*/, this.logger().warn("unable to log test result for test '" + (result_1.testId || result_1.resultId) + "' due to: " + e_1)]; | ||
case 13: | ||
_a.sent(); | ||
return [3 /*break*/, 14]; | ||
case 14: | ||
i++; | ||
return [3 /*break*/, 9]; | ||
case 15: | ||
this.logger().finalise(); | ||
return [2 /*return*/]; | ||
} | ||
@@ -153,29 +255,84 @@ }); | ||
}; | ||
TestWrapper.prototype._logMessage = function (status, message) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_a = status; | ||
switch (_a) { | ||
case test_status_1.TestStatus.Blocked: return [3 /*break*/, 1]; | ||
case test_status_1.TestStatus.Retest: return [3 /*break*/, 1]; | ||
case test_status_1.TestStatus.Skipped: return [3 /*break*/, 1]; | ||
case test_status_1.TestStatus.Untested: return [3 /*break*/, 1]; | ||
case test_status_1.TestStatus.Failed: return [3 /*break*/, 3]; | ||
case test_status_1.TestStatus.Passed: return [3 /*break*/, 5]; | ||
} | ||
return [3 /*break*/, 5]; | ||
case 1: return [4 /*yield*/, this.logger().warn(message)]; | ||
case 2: | ||
_b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 3: return [4 /*yield*/, this.logger().fail(message)]; | ||
case 4: | ||
_b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 5: return [4 /*yield*/, this.logger().pass(message)]; | ||
case 6: | ||
_b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 7: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
/** | ||
* DANGER!!: this method does not catch 'jasmine.expect' failures unless | ||
* you've wrapped the expect call using 'should(expect(actual).toBe(expected)).because('reason');' | ||
* this function runs the passed in test action and then calls 'addTestResult' | ||
* based on the results of the call | ||
* @param testId the test ID being validated | ||
* @param action the test action being performed | ||
* checks the specified test IDs to determine if the | ||
* expectation should be executed and returns a result | ||
* based on execution or why it should not be run | ||
*/ | ||
TestWrapper.prototype.check = function (testId, action) { | ||
TestWrapper.prototype._beginProcessing = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var err; | ||
var status, message, shouldRun, result, e_2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.runAction(action)]; | ||
case 0: | ||
status = test_status_1.TestStatus.Untested; | ||
if (!this._expectation) return [3 /*break*/, 8]; | ||
return [4 /*yield*/, this._shouldRun()]; | ||
case 1: | ||
err = _a.sent(); | ||
if (!err) return [3 /*break*/, 3]; | ||
this.errors.push(err); | ||
return [4 /*yield*/, this.addTestResult(testId, test_status_1.TestStatus.Failed, err.message)]; | ||
shouldRun = _a.sent(); | ||
if (!shouldRun.success) return [3 /*break*/, 6]; | ||
_a.label = 2; | ||
case 2: | ||
_a.sent(); | ||
_a.trys.push([2, 4, , 5]); | ||
return [4 /*yield*/, Promise.resolve(this._expectation(this))]; | ||
case 3: | ||
result = _a.sent(); | ||
if (result !== false) { | ||
status = test_status_1.TestStatus.Passed; | ||
} | ||
else { | ||
status = test_status_1.TestStatus.Failed; | ||
} | ||
return [3 /*break*/, 5]; | ||
case 3: return [4 /*yield*/, this.addTestResult(testId, test_status_1.TestStatus.Passed)]; | ||
case 4: | ||
_a.sent(); | ||
_a.label = 5; | ||
case 5: return [2 /*return*/]; | ||
e_2 = _a.sent(); | ||
status = test_status_1.TestStatus.Failed; | ||
message = e_2.message; | ||
return [3 /*break*/, 5]; | ||
case 5: return [3 /*break*/, 7]; | ||
case 6: | ||
status = test_status_1.TestStatus.Skipped; | ||
message = shouldRun.message; | ||
_a.label = 7; | ||
case 7: return [3 /*break*/, 9]; | ||
case 8: | ||
message = 'no test expectation supplied so nothing could be tested'; | ||
_a.label = 9; | ||
case 9: | ||
if (message) { | ||
this.errors().push(message); | ||
} | ||
return [2 /*return*/, { obj: status, message: message, success: status == test_status_1.TestStatus.Passed }]; | ||
} | ||
@@ -185,28 +342,49 @@ }); | ||
}; | ||
/** | ||
* runs the passed in action, passing in a new Validator | ||
* as an argument and returns any Errors thrown | ||
* instead of letting the Error out | ||
* @param action the action to run | ||
*/ | ||
TestWrapper.prototype.runAction = function (action) { | ||
TestWrapper.prototype._shouldRun = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var err, e_2; | ||
var tcShouldRun, dShouldRun; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this._shouldRun_tests()]; | ||
case 1: | ||
tcShouldRun = _a.sent(); | ||
if (!tcShouldRun.success) { | ||
return [2 /*return*/, tcShouldRun]; | ||
} | ||
return [4 /*yield*/, this._shouldRun_defects()]; | ||
case 2: | ||
dShouldRun = _a.sent(); | ||
if (!dShouldRun.success) { | ||
return [2 /*return*/, dShouldRun]; | ||
} | ||
return [2 /*return*/, { success: true }]; | ||
} | ||
}); | ||
}); | ||
}; | ||
TestWrapper.prototype._shouldRun_tests = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var shouldRun, reasons, i, testId, tcShouldRun; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
err = null; | ||
if (!action) return [3 /*break*/, 4]; | ||
shouldRun = false; | ||
reasons = []; | ||
if (!(this._testCases.length > 0)) return [3 /*break*/, 5]; | ||
i = 0; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, Promise.resolve(action())]; | ||
if (!(i < this._testCases.length)) return [3 /*break*/, 4]; | ||
testId = this._testCases[i]; | ||
return [4 /*yield*/, this._testCaseManager.shouldRun(testId)]; | ||
case 2: | ||
_a.sent(); | ||
return [3 /*break*/, 4]; | ||
tcShouldRun = _a.sent(); | ||
shouldRun = shouldRun || tcShouldRun.success; | ||
reasons.push(tcShouldRun.message); | ||
_a.label = 3; | ||
case 3: | ||
e_2 = _a.sent(); | ||
err = e_2; | ||
return [3 /*break*/, 4]; | ||
case 4: return [2 /*return*/, err]; | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 4: return [2 /*return*/, { success: shouldRun, message: reasons.join(', ') }]; | ||
case 5: return [2 /*return*/, { success: true }]; | ||
} | ||
@@ -216,21 +394,45 @@ }); | ||
}; | ||
TestWrapper.prototype.dispose = function (error) { | ||
TestWrapper.prototype._shouldRun_defects = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var status, message; | ||
var i, defectId, defect, i, testId, defects, j, d; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
status = test_status_1.TestStatus.Passed; | ||
message = ''; | ||
if (error) { | ||
status = test_status_1.TestStatus.Failed; | ||
message = error.message; | ||
} | ||
return [4 /*yield*/, this.logRemainingCases(status, message)]; | ||
if (!(this._defects.length > 0)) return [3 /*break*/, 4]; | ||
i = 0; | ||
_a.label = 1; | ||
case 1: | ||
_a.sent(); | ||
return [4 /*yield*/, this.disposeLogger(error)]; | ||
if (!(i < this._defects.length)) return [3 /*break*/, 4]; | ||
defectId = this._defects[i]; | ||
return [4 /*yield*/, this._defectManager.getDefect(defectId)]; | ||
case 2: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
defect = _a.sent(); | ||
if ((defect === null || defect === void 0 ? void 0 : defect.status) == defect_status_1.DefectStatus.open) { | ||
return [2 /*return*/, { success: false, message: "Defect: '" + defectId + "' is open so test should not be run." }]; | ||
} | ||
_a.label = 3; | ||
case 3: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 4: | ||
if (!(this._testCases.length > 0)) return [3 /*break*/, 8]; | ||
i = 0; | ||
_a.label = 5; | ||
case 5: | ||
if (!(i < this._testCases.length)) return [3 /*break*/, 8]; | ||
testId = this._testCases[i]; | ||
return [4 /*yield*/, this._defectManager.findDefects(testId)]; | ||
case 6: | ||
defects = (_a.sent()) || []; | ||
for (j = 0; j < defects.length; j++) { | ||
d = defects[j]; | ||
if ((d === null || d === void 0 ? void 0 : d.status) == defect_status_1.DefectStatus.open) { | ||
return [2 /*return*/, { success: false, message: "TestId: '" + testId + "' has open defect '" + d.id + "' so test should not be run." }]; | ||
} | ||
} | ||
_a.label = 7; | ||
case 7: | ||
i++; | ||
return [3 /*break*/, 5]; | ||
case 8: return [2 /*return*/, { success: true }]; | ||
} | ||
@@ -240,53 +442,34 @@ }); | ||
}; | ||
TestWrapper.prototype.generateTestResult = function (testId, status, logMessage) { | ||
var result = new test_result_1.TestResult(); | ||
result.TestId = testId; | ||
result.TestStatus = status; | ||
result.ResultMessage = logMessage.ellide(100); | ||
result.MetaData[test_result_metadata_1.TestResultMetaData[test_result_metadata_1.TestResultMetaData.DurationMs]] = convert_1.Convert.toElapsedMs(this.startTime).toString(); | ||
result.MetaData[test_result_metadata_1.TestResultMetaData[test_result_metadata_1.TestResultMetaData.TestStatusStr]] = test_status_1.TestStatus[status]; | ||
if (this.errors.length > 0) { | ||
var exceptionsArray = []; | ||
for (var i = 0; i < this.errors.length; i++) { | ||
var te = this.errors[i]; | ||
if (te) { | ||
exceptionsArray.push(test_exception_1.TestException.generate(te).asSimpleString()); | ||
} | ||
} | ||
var exceptionsStr = exceptionsArray.join('\n'); | ||
result.MetaData[test_result_metadata_1.TestResultMetaData[test_result_metadata_1.TestResultMetaData.ExceptionsStr]] = exceptionsStr; | ||
var lastError = this.errors[this.errors.length - 1]; | ||
if (lastError) { | ||
var lastEx = test_exception_1.TestException.generateFull(lastError); | ||
result.MetaData[test_result_metadata_1.TestResultMetaData[test_result_metadata_1.TestResultMetaData.LastException]] = lastEx; | ||
} | ||
TestWrapper.prototype._generateTestResults = function (status, logMessage) { | ||
var testIds = []; | ||
for (var _i = 2; _i < arguments.length; _i++) { | ||
testIds[_i - 2] = arguments[_i]; | ||
} | ||
return result; | ||
}; | ||
TestWrapper.prototype.logRemainingCases = function (status, message) { | ||
var e_3, _a; | ||
try { | ||
for (var _b = __values(this.testCases), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var c = _c.value; | ||
if (!this.loggedCases.has(c)) { | ||
this.addTestResult(c, status, message); | ||
} | ||
} | ||
} | ||
catch (e_3_1) { e_3 = { error: e_3_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_3) throw e_3.error; } | ||
} | ||
}; | ||
TestWrapper.prototype.disposeLogger = function (error) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var results, i, testId, result, result; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.logger.dispose(error)]; | ||
case 0: | ||
results = []; | ||
if (!(testIds.length > 0)) return [3 /*break*/, 5]; | ||
i = 0; | ||
_a.label = 1; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
if (!(i < testIds.length)) return [3 /*break*/, 4]; | ||
testId = testIds[i]; | ||
return [4 /*yield*/, this._generateTestResult(status, logMessage, testId)]; | ||
case 2: | ||
result = _a.sent(); | ||
results.push(result); | ||
_a.label = 3; | ||
case 3: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 4: return [3 /*break*/, 7]; | ||
case 5: return [4 /*yield*/, this._generateTestResult(status, logMessage)]; | ||
case 6: | ||
result = _a.sent(); | ||
results.push(result); | ||
_a.label = 7; | ||
case 7: return [2 /*return*/, results]; | ||
} | ||
@@ -296,2 +479,36 @@ }); | ||
}; | ||
TestWrapper.prototype._generateTestResult = function (status, logMessage, testId) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var result, _a, _b, exceptionsStr; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
_a = { | ||
testId: testId, | ||
created: new Date(), | ||
resultId: random_generator_1.RG.getGuid(), | ||
resultMessage: logMessage.ellide(100), | ||
status: status | ||
}; | ||
_b = { | ||
durationMs: convert_1.Convert.toElapsedMs(this._startTime), | ||
statusStr: test_status_1.TestStatus[status] | ||
}; | ||
return [4 /*yield*/, this._buildInfoManager.getBuildName()]; | ||
case 1: | ||
_b.buildName = (_c.sent()) || 'unknown'; | ||
return [4 /*yield*/, this._buildInfoManager.getBuildNumber()]; | ||
case 2: | ||
result = (_a.metadata = (_b.buildNumber = (_c.sent()) || 'unknown', | ||
_b), | ||
_a); | ||
if (this.errors().length > 0) { | ||
exceptionsStr = this.errors().join('\n'); | ||
result.metadata['errors'] = exceptionsStr; | ||
} | ||
return [2 /*return*/, result]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return TestWrapper; | ||
@@ -298,0 +515,0 @@ }()); |
@@ -6,5 +6,6 @@ { | ||
], | ||
"stopSpecOnExpectationFailure": false, | ||
"stopSpecOnExpectationFailure": true, | ||
"random": true, | ||
"defaultTimeoutInterval": "180000" | ||
"defaultTimeoutInterval": "180000", | ||
"allowRespy": true | ||
} |
{ | ||
"name": "aft-core", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"description": "Automation Framework for Testing (AFT) package supporting JavaScript unit, integration and functional testing", | ||
@@ -12,6 +12,7 @@ "repository": { | ||
"scripts": { | ||
"pretest": "tsc --declaration", | ||
"posttest": "", | ||
"build": "tsc --declaration", | ||
"test": "jasmine JASMINE_CONFIG_PATH=./jasmine.json" | ||
"clean": "rimraf ./dist", | ||
"build": "npm run clean && tsc --declaration", | ||
"pretest": "npm run build", | ||
"test": "./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=./jasmine.json", | ||
"coverage": "nyc npm run test" | ||
}, | ||
@@ -40,5 +41,7 @@ "keywords": [ | ||
"@types/uuid": "3.4.6", | ||
"jasmine": "^3.5.0", | ||
"typescript": "^3.6.4" | ||
"jasmine": "^3.6.3", | ||
"nyc": "^15.1.0", | ||
"rimraf": "^3.0.2", | ||
"typescript": "^3.9.7" | ||
} | ||
} |
167
README.md
# AFT-Core | ||
Automation Framework for Test (AFT) provides integrations with common testing systems to enable test execution flow and reporting as well as streamlined test development for JavaScript and TypeScript Unit, Integration and Functional tests. | ||
the Automated Functional Testing (AFT) library provides a framework for creating Functional Test Automation that needs to integrate with external systems and can be used for post-deployment verification testing, end-user acceptance testing, end-to-end testing as well as high-level integration testing scenarios. it enables test execution flow control and reporting as well as streamlined test development for JavaScript and TypeScript test automation by integrating with common test framworks as well as external test and defect tracking systems (via a robust plugin structure). | ||
@@ -8,25 +8,16 @@ ## Example Jasmine Test: | ||
it('can perform a demonstration of AFT-Core', async () => { | ||
let options: TestWrapperOptions = new TestWrapperOptions('can perform a demonstration of AFT-Core'); | ||
options.testCases.addRange('C2217763', 'C3131'); | ||
await using(new TestWrapper(options), async (tw) => { | ||
await tw.check('C2217763', async () => { | ||
tw.logger.step('performing some action that throws Error...'); | ||
throw new Error("the tw.check will not allow this to halt the test"); | ||
// because of the above Error a TestResult of Failed will be logged for Test ID: C2217763 | ||
}); | ||
await tw.check('C3131', async () => { | ||
tw.logger.step('performing action that requires waiting for condition...'); | ||
let result: Result; | ||
let count: number = 0; | ||
await Wait.forCondition(async () => { | ||
tw.logger.info(`attempt ${++count}`); | ||
result = await someAsyncActionReturningResultOrNull(); | ||
if (result) { | ||
return true; | ||
} | ||
return false; | ||
}, 10000); // maximum wait of 10 seconds | ||
tw.logger.info(`we retried the action ${count} times before it returned a valid Result or until 10 seconds had elapsed.`); | ||
}); | ||
let feature: FeatureObj = new FeatureObj(); | ||
/** | ||
* the `should(expectation, options)` function | ||
* checks any specified `ITestCaseHandlerPlugin` | ||
* and `IDefectHandlerPlugin` implementations | ||
* to ensure the test should be run. It will then | ||
* report to any `ILoggingPlugin` implementations | ||
* with a `TestResult` indicating the success, | ||
* failure or skipped status | ||
*/ | ||
await should(() => expect(feature.performAction()).toBe('result of action'), | ||
{ | ||
testCases: ['C1234'], | ||
description: 'expect that performAction will return \'result of action\'' | ||
}); | ||
@@ -36,14 +27,39 @@ }); | ||
``` | ||
the above results in the following console output: | ||
the above results in the following console output if the expectation does not return false or throw an exception: | ||
``` | ||
5:29:55 PM STEP - [can_perform_a_demonstration_of_AFT-Core] 1: performing some action that throws Error... | ||
5:29:56 PM FAIL - [can_perform_a_demonstration_of_AFT-Core] Failed - C3456: the tw.check will not allow this to halt the test | ||
5:29:56 PM STEP - [can_perform_a_demonstration_of_AFT-Core] 2: performing action that requires waiting for condition... | ||
5:29:56 PM INFO - [can_perform_a_demonstration_of_AFT-Core] attempt 1 | ||
5:31:24 PM INFO - [can_perform_a_demonstration_of_AFT-Core] attempt 2 | ||
5:33:02 PM INFO - [can_perform_a_demonstration_of_AFT-Core] we retried the action 2 times before it returned a valid Result or until 10 seconds had elapsed. | ||
5:29:56 PM PASS - [can_perform_a_demonstration_of_AFT-Core] Passed - C3131: | ||
5:29:55 PM PASS - [expect_that_performAction_will_return_result_of_action] C1234 Passed - | ||
``` | ||
## Actual Benefit of AFT | ||
the AFT-Core package on it's own contains some helpers for testing, but the actual benefit comes from the plugins. Because the above logging will also send to any registered logging plugins, it becomes easy to create loggers that send to any external system such as TestRail or to log results to Elasticsearch. | ||
in more complex scenarios you can perform multiple actions inside the _expectation_ like in the following example: | ||
```typescript | ||
describe('Sample Test', () => { | ||
it('can perform a more complex demonstration of AFT-Core', async () => { | ||
let feature: FeatureObj = new FeatureObj(); | ||
/** | ||
* the passed in expectation can accept a `TestWrapper` which can be used | ||
* during more complex actions | ||
*/ | ||
await should(async (tw) => { | ||
await tw.logger.step('about to call performAction'); | ||
let result: string = feature.performAction(); | ||
await tw.logger.info(`result of performAction was '${result}'`); | ||
expect(result).toBe('result of action'); | ||
await tw.logger.trace('successfully executed expectation'); | ||
}, | ||
{ | ||
testCases: ['C2345', 'C3344'], | ||
description: 'more complex expectation actions' | ||
}); | ||
}); | ||
}); | ||
``` | ||
which would output the following logs | ||
``` | ||
5:29:55 PM STEP - [more_complex_expectation_actions] 1: about to call performAction | ||
5:29:55 PM INFO - [more_complex_expectation_actions] result of performAction was 'result of action' | ||
5:29:56 PM TRACE - [more_complex_expectation_actions] successfully executed expectation | ||
5:29:56 PM PASS - [more_complex_expectation_actions] Passed C2345 - | ||
5:29:56 PM PASS - [more_complex_expectation_actions] Passed C3344 - | ||
``` | ||
## Benefits of AFT | ||
the AFT-Core package on it's own contains some helpers for testing, but the actual benefit comes from the plugins. Because the above logging will also send to any registered logging plugins, it becomes easy to create loggers that send to any external system such as TestRail or to log results to Elasticsearch. Additionally, before running any _expectation_ passed to a `should(expectation, options)` function, AFT will confirm if the expectation should actually be run based on the results of a query to any supplied `ITestCaseHandlerPlugin` implementations and a subsequent query to any supplied `IDefectHandlerPlugin` implementations. | ||
### Logging Plugin | ||
@@ -53,7 +69,13 @@ to create a logging plugin you simply need to implment the `ILoggingPlugin` interface in a class with a constructor accepting no arguments. Then, in your `aftconfig.json` add the following (where your `ILoggingPlugin` implementations are contained in files at `./relative/path/to/logging-plugin1.ts` and `/full/path/to/logging-plugin2.ts`): | ||
{ | ||
"logging_plugins": "./relative/path/to/logging-plugin1,/full/path/to/logging-plugin2" | ||
"logging": { | ||
"plugins": [ | ||
"./relative/path/to/logging-plugin1", | ||
"/full/path/to/logging-plugin2" | ||
], | ||
"level": "info" | ||
} | ||
} | ||
``` | ||
``` | ||
NOTE: if the plugins are referenced as external npm packages you may leave off the path and just reference by package name | ||
NOTE: if the plugins are referenced as an external npm packages you may leave off the path and just reference by package name | ||
``` | ||
@@ -87,2 +109,73 @@ #### Example Logging Plugin | ||
} | ||
``` | ||
``` | ||
### Test Case Handler Plugin | ||
the purpose of an `ITestCaseHandlerPlugin` is to provide execution control over any expectations by way of supplied _Test IDs_. to specify an implementation of the plugin to load you can add the following to your `aftconfig.json` (where the plugin can be found in a file called `plugin.ts` at relative path `./path/to`): | ||
```json | ||
{ | ||
"testCaseManager": { | ||
"pluginName": "./path/to/plugin" | ||
} | ||
} | ||
``` | ||
if no plugin is specified then external Test Case Management integration will be disabled and expectations will be executed without checking their status before execution | ||
``` | ||
NOTE: if the plugin is referenced as an external npm package you may leave off the path and just reference by package name | ||
``` | ||
#### Example Test Case Handler Plugin (TestRail) | ||
```typescript | ||
export class MockTestCaseHandlerPlugin implements ITestCaseHandlerPlugin { | ||
name: string = 'testrail-test-case-handler-plugin'; | ||
private testRailApi: TestRailClient; | ||
constructor(): void { | ||
this.testRailApi = new TestRailClient(); | ||
} | ||
async enabled(): Promise<boolean> { | ||
return true; | ||
} | ||
async getTestCase(testId: string): Promise<ITestCase> { | ||
return await testRailApi.getCaseById(testId); | ||
} | ||
async findTestCases(searchTerm: string): Promise<ITestCase[]> { | ||
return await testRailApi.searchByTerm(searchTerm); | ||
} | ||
async shouldRun(testId: string): Promise<IProcessingResult> { | ||
let c: ITestCase = await this.getTestCase(testId); | ||
if (c.status == TestStatus.Untested) { | ||
return {obj: c, success: true, message: 'test has not yet been run'}; | ||
} | ||
return {obj: c, success: false, message: 'test already has a result'}; | ||
} | ||
} | ||
``` | ||
### Defect Handler Plugin | ||
the purpose of an `IDefectHandlerPlugin` is to provide execution control over any expectations by way of supplied _Test IDs_ referenced in an external ticket tracking system like Bugzilla or Jira. to specify an implementation of the plugin to load you can add the following to your `aftconfig.json` (where the plugin can be found in a file called `plugin.ts` at relative path `./path/to`): | ||
```json | ||
{ | ||
"defectManager": { | ||
"pluginName": "./path/to/plugin" | ||
} | ||
} | ||
``` | ||
if no plugin is specified then external Defect Management integration will be disabled and expectations will be executed without checking their status before execution, however if a Defect Management plugin is specified, the execution of any expectations passed into a `should(expectation, options)` function will be halted if any non-closed defects are found when searching for defects that contain reference to the specified _Test IDs_ | ||
``` | ||
NOTE: if the plugin is referenced as an external npm package you may leave off the path and just reference by package name | ||
``` | ||
#### Example Defect Handler Plugin (Bugzilla) | ||
```typescript | ||
export class MockDefectHandlerPlugin implements IDefectHandlerPlugin { | ||
name: string = 'bugzilla-defect-handler-plugin'; | ||
private bugzillaApi: BugzillaClient; | ||
constructor(): void { | ||
this.bugzillaApi = new BugzillaClient(); | ||
} | ||
async enabled(): Promise<boolean> { | ||
return true; | ||
} | ||
async getDefect(defectId: string): Promise<IDefect> { | ||
return await bugzillaApi.getDefectById(defectId); | ||
} | ||
async findDefects(searchTerm: string): Promise<IDefect[]> { | ||
return await bugzillaApi.searchByTerm(searchTerm); | ||
} | ||
} | ||
``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
219390
133
3500
178
4
7
1