tia
Version:
Time is All (logs driven test engine with ExtJs support)
370 lines (331 loc) • 10 kB
text/typescript
/**
* Test description.
* **[[GlobalTiaObjects|gT]].a**
*/
/**
* for typedoc.
*/
import { AssertionMode } from './common-types';
/* eslint-disable max-params, no-param-reassign */
interface StrBoolMap {
[key: string]: boolean;
}
/**
* Assertions can use results accumulators.
* I.e. the map which remembers if there was some error for current name.
*/
const resultAccumulators: StrBoolMap = {};
function checkAccName(name: string) {
if (typeof name !== 'string') {
throw new Error('Use string type for accumulator name');
}
}
export function initResultsAccumulator(name: string) {
checkAccName(name);
resultAccumulators[name] = true;
}
export function getResultFromAccumulator(name: string) {
checkAccName(name);
return resultAccumulators[name];
}
export function deleteResultAccumulator(name: string) {
checkAccName(name);
delete resultAccumulators[name];
}
export function mergeResultToAccumulator(res: boolean, name: string) {
checkAccName(name);
resultAccumulators[name] = resultAccumulators[name] && res;
}
/**
* For shortening the code.
* Adds result accumulators usage to fail call.
* @param msg
*/
function failWrapper(msg: string, mode?: AssertionMode) {
gT.l.fail(msg);
if (mode && mode.accName) {
checkAccName(mode.accName);
resultAccumulators[mode.accName] = false;
}
}
/**
* The parameter for all assertions.
* @param {Object} [mode] the mode for pass case.
* @param {Boolean} [mode.passSilently] - do not show message.
* @param {Boolean} [mode.noPassIncrement] - do not increment pass counter.
* @param {Boolean} [mode.accName] - the name for result accumulator which will be falsed
* if some assertion is failed.
* /
/**
* Checks that specified condition is true.
* @param condition
* @param msg - message to describe the entity which you expect.
*/
function checkIfTrue(condition: boolean, msg: string, mode?: AssertionMode) {
if (condition) {
gT.l.pass(msg, mode);
return true;
}
failWrapper(msg, mode);
return false;
}
export { checkIfTrue as true };
/**
* Checks that specified condition is false.
* @param condition
* @param msg - message to describe the entity which you expect.
* param {Object} mode - see 'true' assertion description.
*/
function checkIfFalse(condition: boolean, msg: string, mode?: AssertionMode) {
return checkIfTrue(!condition, msg, mode);
}
export { checkIfFalse as false };
/**
* Checks that value equals to expected value.
* @param {*} actVal - actual value.
* @param {*} expVal - expected value.
* @param {String} [msg] - message to describe the entity which you expect.
* @returns {Boolean} comparision result.
*/
export function value(actVal: any, expVal: any, msg: string, mode?: AssertionMode) {
if (typeof msg !== 'undefined') {
if (actVal === expVal) {
gT.l.pass(`${msg}: ${actVal}`, mode);
return true;
}
msg += `\nAct: ${actVal}\nExp: ${expVal}`;
failWrapper(msg, mode);
return false;
}
if (actVal === expVal) {
msg = `Act: "${actVal}" = Exp: "${expVal}"`;
// TODO: (Yellow color ??) It is strange situation to compare smth without message.
gT.l.pass(msg, mode);
return true;
}
msg = `Equality checking:\nAct: ${actVal}\nExp: ${expVal}`;
failWrapper(msg, mode);
return false;
}
/**
* Checks that string value representation equals to expected string.
* @param {*} actVal - actual value.
* @param {*} expVal - expected value.
* @param {String} [msg] - message to describe the entity which you expect.
* @returns {Boolean} comparision result.
*/
export function valueStr(actVal: any, expVal: any, msg: string, mode?: AssertionMode) {
actVal = String(actVal);
expVal = String(expVal);
return value(actVal, expVal, msg, mode);
}
/**
* Checks that number value representation equals to expected number.
* @param {*} actVal - actual value.
* @param {*} expVal - expected value.
* @param {String} [msg] - message to describe the entity which you expect.
* @returns {Boolean} comparision result.
*/
export function valueNumber(actVal: any, expVal: any, msg: string, mode?: AssertionMode) {
actVal = Number(actVal);
expVal = Number(expVal);
return value(actVal, expVal, msg, mode);
}
/**
* Checks that bool value representation equals to expected bool value.
* @param {*} actVal - actual value.
* @param {*} expVal - expected value.
* @param {String} [msg] - message to describe the entity which you expect.
* @returns {Boolean} comparision result.
*/
export function valueBool(actVal: any, expVal: any, msg: string, mode?: AssertionMode) {
actVal = Boolean(actVal);
expVal = Boolean(expVal);
return value(actVal, expVal, msg, mode);
}
/**
* Checks that two objects or values are equal.
* Functions are not supported.
* @param actVal - actual value.
* @param expVal - expected value.
* @param msg - message to describe the entity which you expect.
* @returns {boolean}
*/
export function valueDeep(actVal: any, expVal: any, msg: string, mode?: AssertionMode) {
function handleVals(actualValue: any, expectedValue: any, propPath: string) {
const actType = typeof actualValue;
const expType = typeof expectedValue;
if (actType !== expType) {
msg += `\nPath: '${propPath}', Act type: ${actType}, 'Exp type: ${expType}`;
failWrapper(msg, mode);
return false;
}
if (actType === 'object' && actualValue !== null && expectedValue !== null) {
const actProps = Object.getOwnPropertyNames(actualValue).sort();
const expProps = Object.getOwnPropertyNames(expectedValue).sort();
if (actProps.length !== expProps.length) {
// eslint-disable-next-line max-len
msg += `\nDifferent property counts, \nPath: '${propPath}', \nAct props: ${actProps}\nExp props: ${expProps}`;
failWrapper(msg, mode);
return false;
}
for (let i = 0, len = actProps.length; i < len; i++) {
const actSubProp = actProps[i];
const expSubProp = expProps[i];
if (actSubProp !== expSubProp) {
msg += `\nPath: '${propPath}', Property names are different: Act : ${actSubProp}, Exp : ${expSubProp}`;
failWrapper(msg, mode);
return false;
}
if (
!handleVals(
actualValue[actSubProp],
expectedValue[expSubProp],
`${propPath}/${actSubProp}`
)
) {
return false;
}
}
} else if (actualValue !== expectedValue) {
msg += `\nPath: ${propPath}, \nAct val: ${actualValue}\nExp val: ${expectedValue}`;
failWrapper(msg, mode);
return false;
}
return true;
}
const res = handleVals(actVal, expVal, '');
if (res) {
gT.l.pass(msg, mode); // There is no sense to print [object Object].
return true;
}
return false;
}
/**
* Checks that given func will throw given exception.
* @param func
* @param expExc
* @param mode
* @return {boolean}
*/
export function exception(func: Function, expExc?: string, mode?: AssertionMode) {
try {
func();
let msg;
if (typeof expExc === 'undefined') {
msg = 'There is not any exception';
} else {
msg = `There is not expected exception: '${expExc}'`;
}
failWrapper(msg, mode);
return false;
} catch (e) {
const str = e.toString();
if (typeof expExc === 'undefined') {
gT.l.pass(`Expected any exception: '${str}'`, mode);
return true;
}
if (str === expExc) {
gT.l.pass(`Expected exception: '${expExc}'`, mode);
return true;
}
failWrapper(`Actual Exception vs Expected one:\n'${str}'\n'${expExc}'`, mode);
return false;
}
}
// TODO exception in async func.
/**
* Checks that given async func will throw given exception.
* @param asyncFunc
* @param expExc
* @param mode
* @return {Promise}
*/
export function exceptionAsync(asyncFunc: Function, expExc?: string, mode?: AssertionMode) {
return asyncFunc().then(
() => {
let msg;
if (typeof expExc === 'undefined') {
msg = 'There is not any exception';
} else {
msg = `There is not expected exception: '${expExc}'`;
}
failWrapper(msg, mode);
return false;
},
(e: Error) => {
const str = e.toString();
if (typeof expExc === 'undefined') {
gT.l.pass(`Expected any exception: '${str}'`, mode);
return true;
}
if (str === expExc) {
gT.l.pass(`Expected exception: '${expExc}'`, mode);
return true;
}
failWrapper(`Actual Exception vs Expected one:\n'${str}'\n'${expExc}'`, mode);
return false;
}
);
}
export function equal(
val1: any,
val2: any,
msg1: string,
msg2: string,
doNotShowValues?: boolean,
mode?: AssertionMode
) {
if (val1 === val2) {
if (doNotShowValues) {
gT.l.pass(`${msg1} === ${msg2}`, mode);
return true;
}
gT.l.pass(`${msg1}: ${val1} === ${msg2}: ${val2}`, mode);
return true;
}
failWrapper(`${msg1}: ${val1} !== ${msg2}: ${val2}`, mode);
return false;
}
export function equalBool(
val1: any,
val2: any,
msg1: string,
msg2: string,
doNotShowValues: boolean,
mode?: AssertionMode
) {
val1 = Boolean(val1);
val2 = Boolean(val2);
if (val1 === val2) {
if (doNotShowValues) {
gT.l.pass(`${msg1} === ${msg2}`, mode);
return true;
}
gT.l.pass(`${msg1} === ${msg2} === ${val1}`, mode);
return true;
}
failWrapper(`${msg1}: ${val1} !== ${msg2}: ${val2}`, mode);
return false;
}
export function notEqualBool(
val1: any,
val2: any,
msg1: string,
msg2: string,
doNotShowValues: boolean,
mode?: AssertionMode
) {
val1 = Boolean(val1);
val2 = Boolean(val2);
if (val1 !== val2) {
if (doNotShowValues) {
gT.l.pass(`${msg1} !== ${msg2}`, mode);
return true;
}
gT.l.pass(`${msg1}: ${val1} !== ${msg2}: ${val2}`, mode);
return true;
}
failWrapper(`${msg1} === ${msg2} === ${val1}`, mode);
return false;
}