diff --git a/functions/postwomanTesting.js b/functions/postwomanTesting.js index 01c792afd..d5311b729 100644 --- a/functions/postwomanTesting.js +++ b/functions/postwomanTesting.js @@ -1,8 +1,12 @@ +import {parse} from "graphql"; + export default function runTestScriptWitVariables(script, variables) { let pw = { _errors: [], - assert + _report: '', + expect, + test // globals that the script is allowed to have access to. }; Object.assign(pw, variables); @@ -16,13 +20,23 @@ export default function runTestScriptWitVariables(script, variables) { errors = e; } return errors; - } -function assert(expression) { - if (!expression) { - throw {name: "PostWomanTestError", message: "expression evaluated to false"} - } +function test(descriptor, func) { + let testReports = []; + let expect = (expectValue) => new Expectation(expectValue, undefined, testReports); + let it = (descriptor, func) => { + testReports.push({descriptor: true, message: descriptor}); + func(); + }; + let xit = (descriptor, func) => { + testReports.push({descriptor: true, message: `⊖ ${descriptor} [skipped]`}) + }; + + func(); + + // 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 } function expect(expectValue) { @@ -32,16 +46,21 @@ function expect(expectValue) { class Expectation { constructor(expectValue, _not, _testReports) { this.expectValue = expectValue; - this.not = _not || new Expectation(this.expectValue, true); + 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. - this._satisfies = function(targetValue) { + this._satisfies = function(expectValue, targetValue) { // 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. + // 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; + } if (this.not === true) { // test the inverse. this.not is always truthly, but an Expectation that is inverted will always be strictly `true` - return this.expectValue !== targetValue; + return expectValue !== targetValue; } else { - return this.expectValue === targetValue; + return expectValue === targetValue; } } } @@ -70,10 +89,50 @@ class Expectation { // TEST METHODS DEFINED BELOW // these are the usual methods that would follow expect(...) toBe(value) { - return this._satisfies(value) ? this._pass() : this._fail(this._fmtNot(`Expected ${this.expectValue} (not)to be ${value}`)); + return this._satisfies(value) + ? this._pass() + : this._fail(this._fmtNot(`Expected ${this.expectValue} (not)to be ${value}`)); } toHaveProperty(value) { - return this._satisfies(this.expectValue.hasOwnProperty(value)) ? this._pass() : this._fail(`Expected object ${this.expectValue} to (not)have property ${value}`) + 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`)); } }