2022-07-24 10:45:29 +00:00
import * as plugins from './smartexpect.plugins.js' ;
2022-01-21 02:33:24 +00:00
export type TExecutionType = 'sync' | 'async' ;
export class Assertion {
executionMode : TExecutionType ;
baseReference : any ;
2022-02-15 15:13:48 +00:00
propertyDrillDown : string [ ] = [ ] ;
2022-01-21 02:33:24 +00:00
private notSetting = false ;
private timeoutSetting = 0 ;
constructor ( baseReferenceArg : any , executionModeArg : TExecutionType ) {
this . baseReference = baseReferenceArg ;
this . executionMode = executionModeArg ;
}
2022-02-15 15:13:48 +00:00
private getObjectToTestReference() {
let returnObjectToTestReference = this . baseReference ;
for ( const property of this . propertyDrillDown ) {
returnObjectToTestReference = returnObjectToTestReference [ property ] ;
}
return returnObjectToTestReference ;
}
2022-01-21 02:33:24 +00:00
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 {
2022-02-02 03:24:39 +00:00
runDirectOrNegated ( checkFunction ( ) ) ;
2022-01-21 02:33:24 +00:00
} catch ( e ) {
isOk = true ;
}
if ( ! isOk ) {
throw new Error ( 'Negated assertion is not ok!' ) ;
}
}
2022-02-02 03:24:39 +00:00
} ;
2022-01-21 02:33:24 +00:00
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' ) {
2022-02-02 03:24:39 +00:00
done . reject ( new Error ( ` ${ this . baseReference } timed out at ${ this . timeoutSetting } ! ` ) ) ;
}
2022-01-21 02:33:24 +00:00
} ) ;
}
2022-02-02 03:24:39 +00:00
this . baseReference . then ( ( promiseResultArg ) = > {
2022-01-21 02:33:24 +00:00
this . baseReference = promiseResultArg ;
done . resolve ( runDirectOrNegated ( checkFunction ) ) ;
2022-02-02 03:24:39 +00:00
} ) ;
2022-01-21 02:33:24 +00:00
}
return done . promise ;
} else {
return runDirectOrNegated ( checkFunction ) ;
}
}
public toBeTypeofString() {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
if ( typeof this . getObjectToTestReference ( ) !== 'string' ) {
2022-01-21 02:33:24 +00:00
throw new Error (
2022-07-24 10:45:29 +00:00
` Assertion failed: ${ this . baseReference } with drill down ${
this . propertyDrillDown
} is not of type string , but typeof $ { typeof this . baseReference } `
2022-01-21 02:33:24 +00:00
) ;
}
} ) ;
}
public toBeTypeofNumber() {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
if ( typeof this . getObjectToTestReference ( ) !== 'number' ) {
2022-01-21 02:33:24 +00:00
throw new Error (
2022-07-24 10:45:29 +00:00
` Assertion failed: ${ this . baseReference } with drill down ${
this . propertyDrillDown
} is not of type string , but typeof $ { typeof this . baseReference } `
2022-01-21 02:33:24 +00:00
) ;
}
} ) ;
}
public toBeTypeofBoolean() {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
if ( typeof this . getObjectToTestReference ( ) !== 'boolean' ) {
2022-01-21 02:33:24 +00:00
throw new Error (
2022-07-24 10:45:29 +00:00
` Assertion failed: ${ this . baseReference } with drill down ${
this . propertyDrillDown
} is not of type string , but typeof $ { typeof this . baseReference } `
2022-01-21 02:33:24 +00:00
) ;
}
} ) ;
}
2022-01-21 16:37:30 +00:00
public toEqual ( comparisonObject : any ) {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = plugins . fastDeepEqual ( this . getObjectToTestReference ( ) , comparisonObject ) ;
2022-01-21 16:37:30 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not equal ${ comparisonObject } `
) ;
2022-01-21 16:37:30 +00:00
}
} ) ;
}
2022-01-21 18:40:30 +00:00
2023-06-22 09:57:29 +00:00
public toMatch ( comparisonObject : RegExp ) {
return this . runCheck ( ( ) = > {
const result = comparisonObject . test ( this . getObjectToTestReference ( ) ) ;
if ( ! result ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not equal ${ comparisonObject } `
) ;
}
} ) ;
}
2022-01-21 18:40:30 +00:00
public toBeTrue() {
return this . runCheck ( ( ) = > {
2022-07-24 10:45:29 +00:00
const result =
typeof this . getObjectToTestReference ( ) === 'boolean' &&
this . getObjectToTestReference ( ) === true ;
2022-01-21 18:40:30 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not true or not of type boolean `
) ;
2022-01-21 18:40:30 +00:00
}
} ) ;
}
public toBeFalse() {
return this . runCheck ( ( ) = > {
2022-07-24 10:45:29 +00:00
const result =
typeof this . getObjectToTestReference ( ) === 'boolean' &&
this . getObjectToTestReference ( ) === false ;
2022-01-21 18:40:30 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not false or not of type boolean `
) ;
2022-01-21 18:40:30 +00:00
}
} ) ;
}
public toBeInstanceOf ( classArg : any ) {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = this . getObjectToTestReference ( ) instanceof classArg ;
2022-01-21 18:40:30 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not an instance of ${ classArg } `
) ;
2022-01-21 18:40:30 +00:00
}
} ) ;
}
2022-02-02 01:45:45 +00:00
2022-07-24 10:45:29 +00:00
public toHaveProperty ( propertyArg : string , equalsArg? : any ) {
2022-02-02 01:45:45 +00:00
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = ! ! this . getObjectToTestReference ( ) [ propertyArg ] ;
2022-02-02 01:45:45 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not have property ${ propertyArg } `
) ;
}
if ( equalsArg ) {
if ( result !== equalsArg ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does have property ${ propertyArg } , but it does not equal ${ equalsArg } `
) ;
}
2022-02-02 01:45:45 +00:00
}
} ) ;
}
2023-08-12 07:49:27 +00:00
public toHaveDeepProperty ( properties : string [ ] ) {
return this . runCheck ( ( ) = > {
let obj = this . getObjectToTestReference ( ) ;
let currentPath = '' ;
for ( const property of properties ) {
if ( currentPath ) {
currentPath += ` . ${ property } ` ;
} else {
currentPath = property ;
}
if ( ! obj || ! ( property in obj ) ) {
throw new Error ( ` Missing property at path " ${ currentPath } " in ${ this . baseReference } ` ) ;
}
obj = obj [ property ] ;
}
} ) ;
}
2022-02-02 01:45:45 +00:00
public toBeGreaterThan ( numberArg : number ) {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = this . getObjectToTestReference ( ) > numberArg ;
2022-02-02 01:45:45 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not greater than ${ numberArg } `
) ;
2022-02-02 01:45:45 +00:00
}
} ) ;
}
public toBeLessThan ( numberArg : number ) {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = this . getObjectToTestReference ( ) < numberArg ;
2022-02-02 01:45:45 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not less than ${ numberArg } `
) ;
2022-02-02 01:45:45 +00:00
}
} ) ;
}
2022-02-02 03:24:39 +00:00
public toBeNull() {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = this . getObjectToTestReference ( ) === null ;
2022-02-02 03:24:39 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not null `
) ;
2022-02-02 03:24:39 +00:00
}
} ) ;
}
public toBeUndefined() {
return this . runCheck ( ( ) = > {
2022-02-15 15:13:48 +00:00
const result = this . getObjectToTestReference ( ) === undefined ;
2022-02-02 03:24:39 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not undefined `
) ;
2022-02-02 03:24:39 +00:00
}
} ) ;
}
public toBeNullOrUndefined() {
return this . runCheck ( ( ) = > {
2022-07-24 10:45:29 +00:00
const result =
this . getObjectToTestReference ( ) === null || this . getObjectToTestReference ( ) === undefined ;
2022-02-02 03:24:39 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not null or undefined `
) ;
2022-02-02 03:24:39 +00:00
}
} ) ;
}
2023-08-12 07:49:27 +00:00
// Array
2022-02-02 03:24:39 +00:00
public toContain ( itemArg : any ) {
return this . runCheck ( ( ) = > {
2022-02-02 03:26:22 +00:00
const result =
2022-02-15 15:13:48 +00:00
this . getObjectToTestReference ( ) instanceof Array &&
this . getObjectToTestReference ( ) . includes ( itemArg ) ;
2022-02-02 03:24:39 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not contain ${ itemArg } `
) ;
2022-02-02 03:24:39 +00:00
}
} ) ;
}
2022-02-15 15:13:48 +00:00
2023-08-12 07:49:27 +00:00
public toBeEmptyArray() {
return this . runCheck ( ( ) = > {
const arrayRef = this . getObjectToTestReference ( ) ;
if ( ! Array . isArray ( arrayRef ) || arrayRef . length !== 0 ) {
throw new Error ( ` Expected ${ this . baseReference } to be an empty array, but it was not. ` ) ;
}
} ) ;
}
public toContainAll ( values : any [ ] ) {
return this . runCheck ( ( ) = > {
const arrayRef = this . getObjectToTestReference ( ) ;
if ( ! Array . isArray ( arrayRef ) ) {
throw new Error ( ` Expected ${ this . baseReference } to be an array. ` ) ;
}
for ( const value of values ) {
if ( ! arrayRef . includes ( value ) ) {
throw new Error (
` Expected ${ this . baseReference } to include value " ${ value } ", but it did not. `
) ;
}
}
} ) ;
}
public toExclude ( value : any ) {
return this . runCheck ( ( ) = > {
const arrayRef = this . getObjectToTestReference ( ) ;
if ( ! Array . isArray ( arrayRef ) ) {
throw new Error ( ` Expected ${ this . baseReference } to be an array. ` ) ;
}
if ( arrayRef . includes ( value ) ) {
throw new Error (
` Expected ${ this . baseReference } to exclude value " ${ value } ", but it included it. `
) ;
}
} ) ;
}
2022-03-14 12:07:46 +00:00
public toStartWith ( itemArg : any ) {
return this . runCheck ( ( ) = > {
const testObject = this . getObjectToTestReference ( ) ;
2022-07-24 10:45:29 +00:00
const result = typeof testObject === 'string' && testObject . startsWith ( itemArg ) ;
2022-03-14 12:07:46 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not contain ${ itemArg } `
) ;
2022-03-14 12:07:46 +00:00
}
} ) ;
}
public toEndWith ( itemArg : any ) {
return this . runCheck ( ( ) = > {
const testObject = this . getObjectToTestReference ( ) ;
2022-07-24 10:45:29 +00:00
const result = typeof testObject === 'string' && testObject . endsWith ( itemArg ) ;
2022-03-14 12:07:46 +00:00
if ( ! result ) {
2022-07-24 10:45:29 +00:00
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not contain ${ itemArg } `
) ;
2022-03-14 12:07:46 +00:00
}
} ) ;
}
2023-08-11 16:08:50 +00:00
// ... previous code ...
public toBeOneOf ( values : any [ ] ) {
return this . runCheck ( ( ) = > {
const result = values . includes ( this . getObjectToTestReference ( ) ) ;
if ( ! result ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not one of ${ values } `
) ;
}
} ) ;
}
public toHaveLength ( length : number ) {
return this . runCheck ( ( ) = > {
const obj = this . getObjectToTestReference ( ) ;
if ( typeof obj . length !== 'number' || obj . length !== length ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not have a length of ${ length } `
) ;
}
} ) ;
}
public toBeCloseTo ( value : number , precision = 2 ) {
return this . runCheck ( ( ) = > {
const difference = Math . abs ( this . getObjectToTestReference ( ) - value ) ;
if ( difference > Math . pow ( 10 , - precision ) / 2 ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not close to ${ value } up to ${ precision } decimal places `
) ;
}
} ) ;
}
public toThrow ( expectedError? : any ) {
return this . runCheck ( ( ) = > {
let thrown = false ;
try {
this . getObjectToTestReference ( ) ( ) ;
} catch ( e ) {
thrown = true ;
if ( expectedError && ! ( e instanceof expectedError ) ) {
throw new Error (
` Expected function to throw ${ expectedError . name } , but it threw ${ e . name } `
) ;
}
}
if ( ! thrown ) {
throw new Error ( ` Expected function to throw, but it didn't. ` ) ;
}
} ) ;
}
public toBeTruthy() {
return this . runCheck ( ( ) = > {
if ( ! this . getObjectToTestReference ( ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not truthy `
) ;
}
} ) ;
}
public toBeFalsy() {
return this . runCheck ( ( ) = > {
if ( this . getObjectToTestReference ( ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not falsy `
) ;
}
} ) ;
}
public toBeGreaterThanOrEqual ( numberArg : number ) {
return this . runCheck ( ( ) = > {
if ( this . getObjectToTestReference ( ) <= numberArg ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not greater than or equal to ${ numberArg } `
) ;
}
} ) ;
}
public toBeLessThanOrEqual ( numberArg : number ) {
return this . runCheck ( ( ) = > {
if ( this . getObjectToTestReference ( ) >= numberArg ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not less than or equal to ${ numberArg } `
) ;
}
} ) ;
}
public toMatchObject ( objectArg : object ) {
return this . runCheck ( ( ) = > {
2023-08-11 16:12:04 +00:00
const partialMatch = plugins . fastDeepEqual ( this . getObjectToTestReference ( ) , objectArg ) ; // Note: Implement a deep comparison function or use one from a library
2023-08-11 16:08:50 +00:00
if ( ! partialMatch ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not match the object ${ objectArg } `
) ;
}
} ) ;
}
public toContainEqual ( value : any ) {
return this . runCheck ( ( ) = > {
const arr = this . getObjectToTestReference ( ) ;
const found = arr . some ( ( item : any ) = > plugins . fastDeepEqual ( item , value ) ) ; // Assuming fastDeepEqual checks deep equality
if ( ! found ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not contain the value ${ value } `
) ;
}
} ) ;
}
public toBeArray() {
return this . runCheck ( ( ) = > {
if ( ! Array . isArray ( this . getObjectToTestReference ( ) ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not an array `
) ;
}
} ) ;
}
public toInclude ( substring : string ) {
return this . runCheck ( ( ) = > {
if ( ! this . getObjectToTestReference ( ) . includes ( substring ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not include the substring ${ substring } `
) ;
}
} ) ;
}
2023-08-11 16:10:08 +00:00
public toHaveLengthGreaterThan ( length : number ) {
return this . runCheck ( ( ) = > {
const obj = this . getObjectToTestReference ( ) ;
if ( typeof obj . length !== 'number' || obj . length <= length ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not have a length greater than ${ length } `
) ;
}
} ) ;
}
public toHaveLengthLessThan ( length : number ) {
return this . runCheck ( ( ) = > {
const obj = this . getObjectToTestReference ( ) ;
if ( typeof obj . length !== 'number' || obj . length >= length ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } does not have a length less than ${ length } `
) ;
}
} ) ;
}
2023-08-11 16:08:50 +00:00
public toBeDate() {
return this . runCheck ( ( ) = > {
if ( ! ( this . getObjectToTestReference ( ) instanceof Date ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not a date `
) ;
}
} ) ;
}
public toBeBeforeDate ( date : Date ) {
return this . runCheck ( ( ) = > {
if ( ! ( this . getObjectToTestReference ( ) < date ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not before ${ date } `
) ;
}
} ) ;
}
public toBeAfterDate ( date : Date ) {
return this . runCheck ( ( ) = > {
if ( ! ( this . getObjectToTestReference ( ) > date ) ) {
throw new Error (
` ${ this . baseReference } with drill down ${ this . propertyDrillDown } is not after ${ date } `
) ;
}
} ) ;
}
2023-08-12 07:49:27 +00:00
public customAssertion ( assertionFunction : ( value : any ) = > boolean , errorMessage : string ) {
return this . runCheck ( ( ) = > {
if ( ! assertionFunction ( this . getObjectToTestReference ( ) ) ) {
throw new Error ( errorMessage ) ;
}
} ) ;
}
2022-02-15 15:13:48 +00:00
public property ( propertyNameArg : string ) {
this . propertyDrillDown . push ( propertyNameArg ) ;
return this ;
}
2022-01-21 02:33:24 +00:00
}