2020-02-25 02:06:23 +00:00
const PASS = "PASS"
const FAIL = "FAIL"
const ERROR = "ERROR"
2020-01-11 18:01:42 +00:00
2020-01-24 16:51:40 +00:00
const styles = {
2020-02-25 02:06:23 +00:00
[ PASS ] : { icon : "check" , class : "success-response" } ,
[ FAIL ] : { icon : "close" , class : "cl-error-response" } ,
[ ERROR ] : { icon : "close" , class : "cl-error-response" } ,
none : { icon : "" , class : "" } ,
2020-02-24 18:44:50 +00:00
}
2020-01-24 16:51:40 +00:00
2020-01-27 12:47:01 +00:00
// TODO: probably have to use a more global state for `test`
2020-01-19 15:46:04 +00:00
2020-01-26 18:51:14 +00:00
export default function runTestScriptWithVariables ( script , variables ) {
2020-01-09 01:40:50 +00:00
let pw = {
2020-01-11 17:18:29 +00:00
_errors : [ ] ,
2020-01-19 15:46:04 +00:00
_testReports : [ ] ,
2020-02-25 02:06:23 +00:00
_report : "" ,
2020-01-24 19:30:45 +00:00
expect ( value ) {
2020-01-19 16:28:23 +00:00
try {
2020-02-24 18:44:50 +00:00
return expect ( value , this . _testReports )
2020-01-19 16:28:23 +00:00
} catch ( e ) {
2020-02-24 18:44:50 +00:00
pw . _testReports . push ( { result : ERROR , message : e } )
2020-01-19 16:28:23 +00:00
}
} ,
2020-02-24 18:44:50 +00:00
test : ( descriptor , func ) => test ( descriptor , func , pw . _testReports ) ,
2020-01-09 01:40:50 +00:00
// globals that the script is allowed to have access to.
2020-02-24 18:44:50 +00:00
}
Object . assign ( pw , variables )
2020-01-09 01:40:50 +00:00
// run pre-request script within this function so that it has access to the pw object.
2020-02-25 02:06:23 +00:00
new Function ( "pw" , script ) ( pw )
2020-01-19 16:28:23 +00:00
//
2020-01-24 17:18:55 +00:00
const testReports = pw . _testReports . map ( item => {
if ( item . result ) {
2020-02-24 18:44:50 +00:00
item . styles = styles [ item . result ]
2020-01-24 16:51:40 +00:00
} else {
2020-02-24 18:44:50 +00:00
item . styles = styles . none
2020-01-24 16:51:40 +00:00
}
2020-02-24 18:44:50 +00:00
return item
} )
return { report : pw . _report , errors : pw . _errors , testResults : testReports }
2020-01-09 01:40:50 +00:00
}
2020-01-19 15:46:04 +00:00
function test ( descriptor , func , _testReports ) {
2020-02-24 18:44:50 +00:00
_testReports . push ( { startBlock : descriptor } )
2020-01-19 16:28:23 +00:00
try {
2020-02-24 18:44:50 +00:00
func ( )
2020-01-19 16:28:23 +00:00
} catch ( e ) {
2020-02-24 18:44:50 +00:00
_testReports . push ( { result : ERROR , message : e } )
2020-01-19 16:28:23 +00:00
}
2020-02-24 18:44:50 +00:00
_testReports . push ( { endBlock : true } )
2020-01-11 18:01:42 +00:00
2020-01-27 12:46:40 +00:00
// TODO: Organize and generate text report of each {descriptor: true} section in testReports.
2020-01-11 18:01:42 +00:00
// add checkmark or x depending on if each testReport is pass=true or pass=false
2020-01-09 01:40:50 +00:00
}
2020-01-18 18:26:07 +00:00
function expect ( expectValue , _testReports ) {
2020-02-24 18:44:50 +00:00
return new Expectation ( expectValue , null , _testReports )
2020-01-11 17:18:29 +00:00
}
class Expectation {
constructor ( expectValue , _not , _testReports ) {
2020-02-24 18:44:50 +00:00
this . expectValue = expectValue
this . not = _not || new Expectation ( this . expectValue , true , _testReports )
this . _testReports = _testReports // this values is used within Test.it, which wraps Expectation and passes _testReports value.
2020-01-11 18:01:42 +00:00
this . _satisfies = function ( expectValue , targetValue ) {
2020-01-11 17:18:29 +00:00
// Used for testing if two values match the expectation, which could be === OR !==, depending on if not
// was used. Expectation#_satisfies prevents the need to have an if(this.not) branch in every test method.
2020-01-11 18:01:42 +00:00
// Signature is _satisfies([expectValue,] targetValue): if only one argument is given, it is assumed the targetValue, and expectValue is set to this.expectValue
if ( ! targetValue ) {
2020-02-24 18:44:50 +00:00
targetValue = expectValue
expectValue = this . expectValue
2020-01-11 18:01:42 +00:00
}
2020-01-11 17:18:29 +00:00
if ( this . not === true ) {
// test the inverse. this.not is always truthly, but an Expectation that is inverted will always be strictly `true`
2020-02-24 18:44:50 +00:00
return expectValue !== targetValue
2020-01-11 17:18:29 +00:00
} else {
2020-02-24 18:44:50 +00:00
return expectValue === targetValue
2020-01-11 17:18:29 +00:00
}
2020-02-24 18:44:50 +00:00
}
2020-01-11 17:18:29 +00:00
}
_fmtNot ( message ) {
// given a string with "(not)" in it, replaces with "not" or "", depending if the expectation is expecting the positive or inverse (this._not)
if ( this . not === true ) {
2020-02-25 02:06:23 +00:00
return message . replace ( "(not)" , "not " )
2020-01-11 17:18:29 +00:00
} else {
2020-02-25 02:06:23 +00:00
return message . replace ( "(not)" , "" )
2020-01-11 17:18:29 +00:00
}
}
_fail ( message ) {
2020-02-24 18:44:50 +00:00
this . _testReports . push ( { result : FAIL , message } )
2020-01-11 17:18:29 +00:00
}
_pass ( message ) {
2020-02-24 18:44:50 +00:00
this . _testReports . push ( { result : PASS } )
2020-01-11 17:18:29 +00:00
}
// TEST METHODS DEFINED BELOW
// these are the usual methods that would follow expect(...)
toBe ( value ) {
2020-01-11 18:01:42 +00:00
return this . _satisfies ( value )
? this . _pass ( )
2020-02-24 18:44:50 +00:00
: this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } (not)to be ${ value } ` ) )
2020-01-11 17:18:29 +00:00
}
toHaveProperty ( value ) {
2020-01-11 18:01:42 +00:00
return this . _satisfies ( this . expectValue . hasOwnProperty ( value ) , true )
? this . _pass ( )
2020-01-24 19:30:45 +00:00
: this . _fail (
2020-02-24 18:44:50 +00:00
this . _fmtNot ( ` Expected object ${ this . expectValue } to (not)have property ${ value } ` )
)
2020-01-11 18:01:42 +00:00
}
toBeLevel2xx ( ) {
2020-02-24 18:44:50 +00:00
const code = parseInt ( this . expectValue )
2020-01-11 18:01:42 +00:00
if ( Number . isNaN ( code ) ) {
2020-02-24 18:44:50 +00:00
return this . _fail ( ` Expected 200-level status but could not parse value ${ this . expectValue } ` )
2020-01-11 18:01:42 +00:00
}
return this . _satisfies ( code >= 200 && code < 300 )
2020-01-24 19:30:45 +00:00
? this . _pass ( )
2020-02-24 18:44:50 +00:00
: this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 200-level status ` ) )
2020-01-11 18:01:42 +00:00
}
toBeLevel3xx ( ) {
2020-02-24 18:44:50 +00:00
const code = parseInt ( this . expectValue )
2020-01-11 18:01:42 +00:00
if ( Number . isNaN ( code ) ) {
2020-02-24 18:44:50 +00:00
return this . _fail ( ` Expected 300-level status but could not parse value ${ this . expectValue } ` )
2020-01-11 18:01:42 +00:00
}
return this . _satisfies ( code >= 300 && code < 400 )
2020-01-24 19:30:45 +00:00
? this . _pass ( )
2020-02-24 18:44:50 +00:00
: this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 300-level status ` ) )
2020-01-11 18:01:42 +00:00
}
toBeLevel4xx ( ) {
2020-02-24 18:44:50 +00:00
const code = parseInt ( this . expectValue )
2020-01-11 18:01:42 +00:00
if ( Number . isNaN ( code ) ) {
2020-02-24 18:44:50 +00:00
return this . _fail ( ` Expected 400-level status but could not parse value ${ this . expectValue } ` )
2020-01-11 18:01:42 +00:00
}
return this . _satisfies ( code >= 400 && code < 500 )
2020-01-24 19:30:45 +00:00
? this . _pass ( )
2020-02-24 18:44:50 +00:00
: this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 400-level status ` ) )
2020-01-11 18:01:42 +00:00
}
toBeLevel5xx ( ) {
2020-02-24 18:44:50 +00:00
const code = parseInt ( this . expectValue )
2020-01-11 18:01:42 +00:00
if ( Number . isNaN ( code ) ) {
2020-02-24 18:44:50 +00:00
return this . _fail ( ` Expected 500-level status but could not parse value ${ this . expectValue } ` )
2020-01-11 18:01:42 +00:00
}
return this . _satisfies ( code >= 500 && code < 600 )
? this . _pass ( )
2020-02-24 18:44:50 +00:00
: this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 500-level status ` ) )
2020-01-11 17:18:29 +00:00
}
}