2020-01-11 18:01:42 +00:00
import { parse } from "graphql" ;
2020-01-18 18:26:07 +00:00
const PASS = 'PASS' ,
FAIL = 'FAIL' ,
ERROR = 'ERROR' ;
2020-01-11 18:01:42 +00:00
2020-01-19 15:46:04 +00:00
//TODO: probably have to use a more global state for `test`
2020-01-09 01:40:50 +00:00
export default function runTestScriptWitVariables ( script , variables ) {
let pw = {
2020-01-11 17:18:29 +00:00
_errors : [ ] ,
2020-01-19 15:46:04 +00:00
_testReports : [ ] ,
2020-01-11 18:01:42 +00:00
_report : '' ,
2020-01-19 15:46:04 +00:00
expect : function ( value ) {
return expect ( value , this . _testReports , arguments ) } ,
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.
} ;
Object . assign ( pw , variables ) ;
// run pre-request script within this function so that it has access to the pw object.
let errors = null ;
try {
new Function ( "pw" , script ) ( pw ) ;
}
catch ( e ) {
errors = e ;
}
2020-01-19 15:46:04 +00:00
return { report : pw . _report , errors : pw . _errors , testResults : pw . _testReports } ;
2020-01-09 01:40:50 +00:00
}
2020-01-19 15:46:04 +00:00
function test ( descriptor , func , _testReports ) {
_testReports . push ( { startBlock : descriptor } ) ;
2020-01-11 18:01:42 +00:00
func ( ) ;
2020-01-19 15:46:04 +00:00
_testReports . push ( { endBlock : true } ) ;
2020-01-11 18:01:42 +00:00
// TODO: Organieze and generate text report of each {descriptor: true} section in testReports.
// 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 ) {
return new Expectation ( expectValue , null , _testReports ) ;
2020-01-11 17:18:29 +00:00
}
class Expectation {
constructor ( expectValue , _not , _testReports ) {
this . expectValue = expectValue ;
2020-01-11 18:01:42 +00:00
this . not = _not || new Expectation ( this . expectValue , true , _testReports ) ;
2020-01-11 17:18:29 +00:00
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 ) {
targetValue = expectValue ;
expectValue = this . expectValue ;
}
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-01-11 18:01:42 +00:00
return expectValue !== targetValue ;
2020-01-11 17:18:29 +00:00
} else {
2020-01-11 18:01:42 +00:00
return expectValue === targetValue ;
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 ) {
return message . replace ( "(not)" , "not " ) ;
} else {
return message . replace ( "(not)" , "" )
}
}
_fail ( message ) {
2020-01-18 18:26:07 +00:00
this . _testReports . push ( { result : FAIL , message } )
2020-01-11 17:18:29 +00:00
}
_pass ( message ) {
2020-01-18 18:26:07 +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 ( )
: 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 ( )
: this . _fail ( this . _fmtNot ( ` Expected object ${ this . expectValue } to (not)have property ${ value } ` ) )
}
toBeLevel2xx ( ) {
let code = parseInt ( this . expectValue ) ;
if ( Number . isNaN ( code ) ) {
return this . _fail ( ` Expecteded 200-level status but could not parse value ${ this . expectValue } ` ) ;
}
return this . _satisfies ( code >= 200 && code < 300 )
? this . _pass ( ) :
this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 200-level status ` ) ) ;
}
toBeLevel3xx ( ) {
let code = parseInt ( this . expectValue ) ;
if ( Number . isNaN ( code ) ) {
return this . _fail ( ` Expected 300-level status but could not parse value ${ this . expectValue } ` ) ;
}
return this . _satisfies ( code >= 300 && code < 400 )
? this . _pass ( ) :
this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 300-level status ` ) ) ;
}
toBeLevel4xx ( ) {
let code = parseInt ( this . expectValue ) ;
if ( Number . isNaN ( code ) ) {
return this . _fail ( ` Expected 400-level status but could not parse value ${ this . expectValue } ` ) ;
}
return this . _satisfies ( code >= 400 && code < 500 )
? this . _pass ( ) :
this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 400-level status ` ) ) ;
}
toBeLevel5xx ( ) {
let code = parseInt ( this . expectValue ) ;
if ( Number . isNaN ( code ) ) {
return this . _fail ( ` Expected 200-level status but could not parse value ${ this . expectValue } ` ) ;
}
return this . _satisfies ( code >= 500 && code < 600 )
? this . _pass ( )
: this . _fail ( this . _fmtNot ( ` Expected ${ this . expectValue } to (not)be 500-level status ` ) ) ;
2020-01-11 17:18:29 +00:00
}
}
2020-01-09 01:40:50 +00:00
class PostwomanTestFailure {
constructor ( message ) {
return { message }
}
}