import * as plugins from './smartexpect.plugins'; export type TExecutionType = 'sync' | 'async'; export class Assertion { executionMode: TExecutionType; baseReference: any; propertyDrillDown: string[] = []; private notSetting = false; private timeoutSetting = 0; constructor(baseReferenceArg: any, executionModeArg: TExecutionType) { this.baseReference = baseReferenceArg; this.executionMode = executionModeArg; } private getObjectToTestReference() { let returnObjectToTestReference = this.baseReference; for (const property of this.propertyDrillDown) { returnObjectToTestReference = returnObjectToTestReference[property]; } return returnObjectToTestReference; } public get not() { this.notSetting = true; return this; } public timeout(millisArg: number) { this.timeoutSetting = millisArg; return this; } private runCheck(checkFunction: () => any) { const runDirectOrNegated = (checkFunction: () => any) => { if (!this.notSetting) { return checkFunction(); } else { let isOk = false; try { runDirectOrNegated(checkFunction()); } catch (e) { isOk = true; } if (!isOk) { throw new Error('Negated assertion is not ok!'); } } }; if (this.executionMode === 'async') { const done = plugins.smartpromise.defer(); if (!(this.baseReference instanceof Promise)) { done.reject(new Error(`${this.baseReference} is not of type promise.`)); } else { if (this.timeoutSetting) { plugins.smartdelay.delayFor(this.timeoutSetting).then(() => { if (done.status === 'pending') { done.reject(new Error(`${this.baseReference} timed out at ${this.timeoutSetting}!`)); } }); } this.baseReference.then((promiseResultArg) => { this.baseReference = promiseResultArg; done.resolve(runDirectOrNegated(checkFunction)); }); } return done.promise; } else { return runDirectOrNegated(checkFunction); } } public toBeTypeofString() { return this.runCheck(() => { if (typeof this.getObjectToTestReference() !== 'string') { throw new Error( `Assertion failed: ${this.baseReference} with drill down ${this.propertyDrillDown} is not of type string, but typeof ${typeof this .baseReference}` ); } }); } public toBeTypeofNumber() { return this.runCheck(() => { if (typeof this.getObjectToTestReference() !== 'number') { throw new Error( `Assertion failed: ${this.baseReference} with drill down ${this.propertyDrillDown} is not of type string, but typeof ${typeof this .baseReference}` ); } }); } public toBeTypeofBoolean() { return this.runCheck(() => { if (typeof this.getObjectToTestReference() !== 'boolean') { throw new Error( `Assertion failed: ${this.baseReference} with drill down ${this.propertyDrillDown} is not of type string, but typeof ${typeof this .baseReference}` ); } }); } public toEqual(comparisonObject: any) { return this.runCheck(() => { const result = plugins.fastDeepEqual(this.getObjectToTestReference(), comparisonObject); if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} does not equal ${comparisonObject}`); } }); } public toBeTrue() { return this.runCheck(() => { const result = typeof this.getObjectToTestReference() === 'boolean' && this.getObjectToTestReference() === true; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not true or not of type boolean`); } }); } public toBeFalse() { return this.runCheck(() => { const result = typeof this.getObjectToTestReference() === 'boolean' && this.getObjectToTestReference() === false; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not false or not of type boolean`); } }); } public toBeInstanceOf(classArg: any) { return this.runCheck(() => { const result = this.getObjectToTestReference() instanceof classArg; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not an instance of ${classArg}`); } }); } public toHaveProperty(propertyArg: string) { return this.runCheck(() => { const result = !!this.getObjectToTestReference()[propertyArg]; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} does not have property ${propertyArg}`); } }); } public toBeGreaterThan(numberArg: number) { return this.runCheck(() => { const result = this.getObjectToTestReference() > numberArg; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not greater than ${numberArg}`); } }); } public toBeLessThan(numberArg: number) { return this.runCheck(() => { const result = this.getObjectToTestReference() < numberArg; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not less than ${numberArg}`); } }); } public toBeNull() { return this.runCheck(() => { const result = this.getObjectToTestReference() === null; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not null`); } }); } public toBeUndefined() { return this.runCheck(() => { const result = this.getObjectToTestReference() === undefined; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not undefined`); } }); } public toBeNullOrUndefined() { return this.runCheck(() => { const result = this.getObjectToTestReference() === null || this.getObjectToTestReference() === undefined; if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not null or undefined`); } }); } public toContain(itemArg: any) { return this.runCheck(() => { const result = this.getObjectToTestReference() instanceof Array && this.getObjectToTestReference().includes(itemArg); if (!result) { throw new Error(`${this.baseReference} with drill down ${this.propertyDrillDown} is not contain ${itemArg}`); } }); } public property(propertyNameArg: string) { this.propertyDrillDown.push(propertyNameArg); return this; } }