"use strict";module.metadata={"stability":"deprecated"};const memory=require("./memory");const timer=require("../timers");const cfxArgs=require("../test/options");const{getTabs,closeTab,getURI}=require("../tabs/utils");const{windows,isBrowser}=require("../window/utils");const{defer,all,Debugging:PromiseDebugging}=require("../core/promise");const findAndRunTests=function findAndRunTests(options){var TestFinder=require("./unit-test-finder").TestFinder;var finder=new TestFinder({filter:options.filter,testInProcess:options.testInProcess,testOutOfProcess:options.testOutOfProcess});var runner=new TestRunner({fs:options.fs});finder.findTests().then(tests=>{runner.startMany({tests:tests,stopOnError:options.stopOnError,onDone:options.onDone});});};exports.findAndRunTests=findAndRunTests;const TestRunner=function TestRunner(options){if(options){this.fs=options.fs;}
this.console=(options&&"console"in options)?options.console:console;memory.track(this);this.passed=0;this.failed=0;this.testRunSummary=[];this.expectFailNesting=0;this.done=TestRunner.prototype.done.bind(this);};TestRunner.prototype={toString:function toString()"[object TestRunner]",DEFAULT_PAUSE_TIMEOUT:(cfxArgs.parseable?300000:15000),PAUSE_DELAY:500,_logTestFailed:function _logTestFailed(why){if(!(why in this.test.errors))
this.test.errors[why]=0;this.test.errors[why]++;},_uncaughtErrorObserver:function({message,date,fileName,stack,lineNumber}){this.fail("There was an uncaught Promise rejection: "+stack);},pass:function pass(message){if(!this.expectFailure){if("testMessage"in this.console)
this.console.testMessage(true,true,this.test.name,message);else
this.console.info("pass:",message);this.passed++;this.test.passed++;}
else{this.expectFailure=false;this._logTestFailed("failure");if("testMessage"in this.console){this.console.testMessage(true,false,this.test.name,message);}
else{this.console.error("fail:",'Failure Expected: '+message)
this.console.trace();}
this.failed++;this.test.failed++;}},fail:function fail(message){if(!this.expectFailure){this._logTestFailed("failure");if("testMessage"in this.console){this.console.testMessage(false,false,this.test.name,message);}
else{this.console.error("fail:",message)
this.console.trace();}
this.failed++;this.test.failed++;}
else{this.expectFailure=false;if("testMessage"in this.console)
this.console.testMessage(false,true,this.test.name,message);else
this.console.info("pass:",message);this.passed++;this.test.passed++;}},expectFail:function(callback){this.expectFailure=true;callback();this.expectFailure=false;},exception:function exception(e){this._logTestFailed("exception");if(cfxArgs.parseable)
this.console.print("TEST-UNEXPECTED-FAIL | "+this.test.name+" | "+e+"\n");this.console.exception(e);this.failed++;this.test.failed++;},assertMatches:function assertMatches(string,regexp,message){if(regexp.test(string)){if(!message)
message=uneval(string)+" matches "+uneval(regexp);this.pass(message);}else{var no=uneval(string)+" doesn't match "+uneval(regexp);if(!message)
message=no;else
message=message+" ("+no+")";this.fail(message);}},assertRaises:function assertRaises(func,predicate,message){try{func();if(message)
this.fail(message+" (no exception thrown)");else
this.fail("function failed to throw exception");}catch(e){var errorMessage;if(typeof(e)=="string")
errorMessage=e;else
errorMessage=e.message;if(typeof(predicate)=="string")
this.assertEqual(errorMessage,predicate,message);else
this.assertMatches(errorMessage,predicate,message);}},assert:function assert(a,message){if(!a){if(!message)
message="assertion failed, value is "+a;this.fail(message);}else
this.pass(message||"assertion successful");},assertNotEqual:function assertNotEqual(a,b,message){if(a!=b){if(!message)
message="a != b != "+uneval(a);this.pass(message);}else{var equality=uneval(a)+" == "+uneval(b);if(!message)
message=equality;else
message+=" ("+equality+")";this.fail(message);}},assertEqual:function assertEqual(a,b,message){if(a==b){if(!message)
message="a == b == "+uneval(a);this.pass(message);}else{var inequality=uneval(a)+" != "+uneval(b);if(!message)
message=inequality;else
message+=" ("+inequality+")";this.fail(message);}},assertNotStrictEqual:function assertNotStrictEqual(a,b,message){if(a!==b){if(!message)
message="a !== b !== "+uneval(a);this.pass(message);}else{var equality=uneval(a)+" === "+uneval(b);if(!message)
message=equality;else
message+=" ("+equality+")";this.fail(message);}},assertStrictEqual:function assertStrictEqual(a,b,message){if(a===b){if(!message)
message="a === b === "+uneval(a);this.pass(message);}else{var inequality=uneval(a)+" !== "+uneval(b);if(!message)
message=inequality;else
message+=" ("+inequality+")";this.fail(message);}},assertFunction:function assertFunction(a,message){this.assertStrictEqual('function',typeof a,message);},assertUndefined:function(a,message){this.assertStrictEqual('undefined',typeof a,message);},assertNotUndefined:function(a,message){this.assertNotStrictEqual('undefined',typeof a,message);},assertNull:function(a,message){this.assertStrictEqual(null,a,message);},assertNotNull:function(a,message){this.assertNotStrictEqual(null,a,message);},assertObject:function(a,message){this.assertStrictEqual('[object Object]',Object.prototype.toString.apply(a),message);},assertString:function(a,message){this.assertStrictEqual('[object String]',Object.prototype.toString.apply(a),message);},assertArray:function(a,message){this.assertStrictEqual('[object Array]',Object.prototype.toString.apply(a),message);},assertNumber:function(a,message){this.assertStrictEqual('[object Number]',Object.prototype.toString.apply(a),message);},done:function done(){if(!this.isDone){this.isDone=true;if(this.test.teardown){this.test.teardown(this);}
if(this.waitTimeout!==null){timer.clearTimeout(this.waitTimeout);this.waitTimeout=null;}
this.waitUntilCallback=null;if(this.test.passed==0&&this.test.failed==0){this._logTestFailed("empty test");if("testMessage"in this.console){this.console.testMessage(false,false,this.test.name,"Empty test");}
else{this.console.error("fail:","Empty test")}
this.failed++;this.test.failed++;}
let wins=windows(null,{includePrivate:true});let winPromises=wins.map(win=>{let{promise,resolve}=defer();if(["interactive","complete"].indexOf(win.document.readyState)>=0){resolve()}
else{win.addEventListener("DOMContentLoaded",function onLoad(){win.removeEventListener("DOMContentLoaded",onLoad,false);resolve();},false);}
return promise;});PromiseDebugging.flushUncaughtErrors();all(winPromises).then(_=>{let tabs=[];for(let win of wins.filter(isBrowser)){for(let tab of getTabs(win)){tabs.push(tab);}}
let leftover=tabs.slice(1);if(wins.length!=1)
this.fail("Should not be any unexpected windows open");if(tabs.length!=1)
this.fail("Should not be any unexpected tabs open");if(tabs.length!=1||wins.length!=1){console.log("Windows open:");for(let win of wins){if(isBrowser(win)){tabs=getTabs(win);console.log(win.location+" - "+tabs.map(getURI).join(", "));}
else{console.log(win.location);}}}
leftover.forEach(closeTab);this.testRunSummary.push({name:this.test.name,passed:this.test.passed,failed:this.test.failed,errors:[error for(error in this.test.errors)].join(", ")});if(this.onDone!==null){let onDone=this.onDone;this.onDone=null;timer.setTimeout(_=>onDone(this),0);}});}},
waitUntil:function waitUntil(){return this._waitUntil(this.assert,arguments);},waitUntilNotEqual:function waitUntilNotEqual(){return this._waitUntil(this.assertNotEqual,arguments);},waitUntilEqual:function waitUntilEqual(){return this._waitUntil(this.assertEqual,arguments);},waitUntilMatches:function waitUntilMatches(){return this._waitUntil(this.assertMatches,arguments);},_waitUntil:function waitUntil(assertionMethod,args){let{promise,resolve}=defer();let count=0;let maxCount=this.DEFAULT_PAUSE_TIMEOUT/this.PAUSE_DELAY; if(!this.waitTimeout)
this.waitUntilDone(this.DEFAULT_PAUSE_TIMEOUT);let finished=false;let test=this;let traceback=require("../console/traceback");let stack=traceback.get();stack.splice(-2,2);let currentWaitStack=traceback.format(stack);let timeout=null;function loop(stopIt){timeout=null;

 let mock={pass:function(msg){test.pass(msg);test.waitUntilCallback=null;if(!stopIt)
resolve();},fail:function(msg){
if(stopIt){test.console.error("test assertion never became true:\n",msg+"\n",currentWaitStack);if(timeout)
timer.clearTimeout(timeout);return;}
timeout=timer.setTimeout(loop,test.PAUSE_DELAY);}};
 let appliedArgs=[];for(let i=0,l=args.length;i<l;i++){let a=args[i];if(typeof a=="function"){try{a=a();}
catch(e){test.fail("Exception when calling asynchronous assertion: "+e+"\n"+e.stack);return resolve();}}
appliedArgs.push(a);} 
assertionMethod.apply(mock,appliedArgs);}
loop();this.waitUntilCallback=loop;return promise;},waitUntilDone:function waitUntilDone(ms){if(ms===undefined)
ms=this.DEFAULT_PAUSE_TIMEOUT;var self=this;function tiredOfWaiting(){self._logTestFailed("timed out");if("testMessage"in self.console){self.console.testMessage(false,false,self.test.name,"Test timed out");}
else{self.console.error("fail:","Timed out")}
if(self.waitUntilCallback){self.waitUntilCallback(true);self.waitUntilCallback=null;}
self.failed++;self.test.failed++;self.done();} 
if(this.waitTimeout)
timer.clearTimeout(this.waitTimeout);this.waitTimeout=timer.setTimeout(tiredOfWaiting,ms);},startMany:function startMany(options){function runNextTest(self){var test=options.tests.shift();if(options.stopOnError&&self.test&&self.test.failed){self.console.error("aborted: test failed and --stop-on-error was specified");options.onDone(self);}else if(test){self.start({test:test,onDone:runNextTest});}else{options.onDone(self);}}
runNextTest(this);},start:function start(options){this.test=options.test;this.test.passed=0;this.test.failed=0;this.test.errors={};PromiseDebugging.clearUncaughtErrorObservers();PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver.bind(this));this.isDone=false;this.onDone=function(self){if(cfxArgs.parseable)
self.console.print("TEST-END | "+self.test.name+"\n");options.onDone(self);}
this.waitTimeout=null;try{if(cfxArgs.parseable)
this.console.print("TEST-START | "+this.test.name+"\n");else
this.console.info("executing '"+this.test.name+"'");if(this.test.setup){this.test.setup(this);}
this.test.testFunction(this);}catch(e){this.exception(e);}
if(this.waitTimeout===null)
this.done();}};exports.TestRunner=TestRunner;