hotstaq 0.9.10 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/src/HotStaq.js +1 -1
- package/build/src/HotTestDriver.d.ts +8 -0
- package/build/src/HotTestDriver.d.ts.map +1 -1
- package/build/src/HotTestDriver.js +1 -0
- package/build/src/HotTestDriver.js.map +1 -1
- package/build/src/HotTestSeleniumDriver.d.ts.map +1 -1
- package/build/src/HotTestSeleniumDriver.js +37 -2
- package/build/src/HotTestSeleniumDriver.js.map +1 -1
- package/build/src/HotTester.d.ts.map +1 -1
- package/build/src/HotTester.js +7 -0
- package/build/src/HotTester.js.map +1 -1
- package/build-web/HotStaq.js +2 -2
- package/build-web/HotStaq.min.js +6 -6
- package/package.json +1 -1
- package/src/HotStaq.ts +1 -1
- package/src/HotTestDriver.ts +9 -0
- package/src/HotTestSeleniumDriver.ts +47 -2
- package/src/HotTester.ts +7 -0
package/build-web/HotStaq.min.js
CHANGED
|
@@ -229,7 +229,7 @@ h=new B.HotTesterAPI(h.testerAPIBaseUrl,q);h.connection.api=h;g.testerAPI=h}}sta
|
|
|
229
229
|
h}static onInitalLoad(g){"complete"===document.readyState||"interactive"===document.readyState?g():window.addEventListener("load",g,{once:!0})}static displayUrl(g){return k(this,arguments,void 0,function*(h,q=null,f=null,y=null){return new Promise((C,G)=>{z.onInitalLoad(()=>k(this,void 0,void 0,function*(){var F={url:""};F.name=null==q?"string"==typeof h?h:h.name:q;""===F.name&&(F.name="string"==typeof h?h:h.name);"string"==typeof h?F.url=h:(F.url=h.url,null==f&&null!=h.processor&&(f=h.processor),
|
|
230
230
|
null==y&&null!=h.args&&(y=h.args),null!=h.testerMap&&(F.testerMap=h.testerMap),null!=h.testerName&&(F.testerName=h.testerName),null!=h.testerAPIBaseUrl&&(F.testerAPIBaseUrl=h.testerAPIBaseUrl));null==f&&(f=new z);f.mode===a.DeveloperMode.Development&&(a.Hot.Debugger.benchmark=!0);z.setupTesters(f,F);F.processor=f;F.args=y;F.url.indexOf("hstqserve")<0&&(F.url+="?hstqserve=nahfam");F=yield z.processUrl(F);F+=z.setupClientTesters(f);yield z.useOutput(F);C(f)}))})})}static displayContent(g){return k(this,
|
|
231
231
|
arguments,void 0,function*(h,q=null,f=null,y=null){return new Promise((C,G)=>{z.onInitalLoad(()=>k(this,void 0,void 0,function*(){var F={content:""};F.name=null==q?"string"==typeof h?"":h.name:q;""===F.name&&(F.name="string"==typeof h?"":h.name);"string"==typeof h?F.content=h:(F.content=h.content,null==f&&null!=h.processor&&(f=h.processor),null==y&&null!=h.args&&(y=h.args),null!=h.testerMap&&(F.testerMap=h.testerMap),null!=h.testerName&&(F.testerName=h.testerName),null!=h.testerAPIBaseUrl&&(F.testerAPIBaseUrl=
|
|
232
|
-
h.testerAPIBaseUrl));null==f&&(f=new z);z.setupTesters(f,F);F.processor=f;F.args=y;F=yield z.processContent(F);yield z.useOutput(F);C(f)}))})})}}p.HotStaq=z;z.version="0.9.
|
|
232
|
+
h.testerAPIBaseUrl));null==f&&(f=new z);z.setupTesters(f,F);F.processor=f;F.args=y;F=yield z.processContent(F);yield z.useOutput(F);C(f)}))})})}}p.HotStaq=z;z.version="0.9.13";z.isWeb=!1;z.isReadyForTesting=!1;z.onReadyForTesting=null;z.onOutputReceived=null;z.onReadyEvent=null;z.dispatchReadyEvents=!0;z.spaTarget=null;z.routerManager={};z.routerWildcards=[];z.spaProcessor=null;z.spaEnabled=!1;z.onBeforeNavigate=null;z.onAfterNavigate=null;z.onRouteNotFound=null;z.autoInstallFetchInterceptors=!0;
|
|
233
233
|
z.navAbort=null;z.fetchInterceptorsInstalled=!1;z.fetchInterceptorOptions={};z.errors={};z.preValidate=null;z.valids={};z.postValidate=null;z.setupValidators();"undefined"!=typeof document&&(window.HotAPI=J.HotAPI,window.addEventListener("load",r.hotStaqWebStart,{once:!0}))},[6019](J,p,v){Object.defineProperty(p,"__esModule",{value:!0});p.registerComponent=function(r,n){if(null==r||""===r)throw Error("All components must have a tag!");if(void 0===customElements.get(r)){var l=this.components;customElements.define(r,
|
|
234
234
|
class extends HTMLElement{constructor(){super();var d=l[r];if(this.component=new d.componentType(d.processor,d.api),this.hotComponent=this.component,this.component.htmlElements=[this],this.component.inner=this.innerHTML,null!=this.component.handleAttributes)this.component.handleAttributes(this.attributes);else for(d=0;d<this.attributes.length;d++){var b=this.attributes[d],c=b.name.toLowerCase();b=b.value;if("id"===c&&(this.component.name=b),"name"===c&&(this.component.name=b),"value"===c&&(this.component.value=
|
|
235
235
|
b),c.indexOf("hot-")>-1)c=c.substring(4),this.component[c]=b}if(null==this.component.onPreOutput||!1!==this.component.onPreOutput())for(c=this.component.output(),null!=this.component.onPostOutput&&(c=this.component.onPostOutput(c)),d=[],"string"==typeof c?d.push({html:c}):d=c instanceof Array?c:[c],c=0;c<d.length;c++){b=d[c];var e=b.html,u="",a=this.component["place-here"];null!=b.addFunctionsTo&&(u=b.addFunctionsTo);null!=a&&(b.documentSelector=`hot-place-here[name="${a}"]`);e=w.HotFile.parseContent(e,
|
|
@@ -252,12 +252,12 @@ q&&""!==q.replace(/\s/g,"")&&(y=!0);b=0;null!=window.Hot&&(b=x.Hot.Mode);q=null;
|
|
|
252
252
|
z),null!=H){P=new D.HotClient(q);if(null==L||""===L)throw Error("api-url was not set!");if(null==E||""===E)throw Error("api-js-url was not set!");E=yield k.HotFile.httpGet(E);if(""===E)throw Error("api-js-url content was empty!");M=null;!0===n.HotStaq.isWeb?null==M&&(M=window):null==M&&(M=v.g);eval.apply(M,[E]);E=window;if(null!=A&&(E=window[A],null==E))throw Error(`Unable to find the API library ${A}!`);A=new E[H](L,P);null!=A.onPreRegister&&(yield A.onPreRegister());A.connection.api=A;q.api=A}if(n.HotStaq.spaProcessor=
|
|
253
253
|
q,window.__hotstaqSpaProcessor=q,null!=m&&n.HotStaq.enableSPA(m,q),!1===y){if(""===c){c=window.location.pathname;m="";if(null!=f[404]&&null!=f[404].src?m=f[404].src:null!=f["*"]&&null!=f["*"].src&&(m=f["*"].src),""===m)return"function"==typeof n.HotStaq.onRouteNotFound?void n.HotStaq.onRouteNotFound(c):void n.HotStaq.displayDefault404(c);c=m}c.indexOf("hstqserve")<0&&(c+="?hstqserve=nahfam");e.url=c;n.HotStaq.displayUrl(e)}else n.HotStaq.displayContent(e)})},50)}}};var x=v(1814),D=v(3025),k=v(8296),
|
|
254
254
|
r=v(3622),n=v(9343)},[4744](J,p){Object.defineProperty(p,"__esModule",{value:!0});p.HotTestDestination=void 0;class v{constructor(w="",x=!0){"string"==typeof w?(this.destination=w,this.autoStart=x):w instanceof v?(this.destination=w.destination,this.autoStart=w.autoStart):(this.destination=w.path,this.autoStart=w.autoStart)}}p.HotTestDestination=v},[896](J,p){var v=this&&this.__awaiter||function(w,x,D,k){return new (D||(D=Promise))(function(r,n){function l(c){try{b(k.next(c))}catch(e){n(e)}}function d(c){try{b(k.throw(c))}catch(e){n(e)}}
|
|
255
|
-
function b(c){var e;c.done?r(c.value):(e=c.value,e instanceof D?e:new D(function(u){u(e)})).then(l,d)}b((k=k.apply(w,x||[])).next())})};Object.defineProperty(p,"__esModule",{value:!0});p.HotTestDriver=void 0;p.HotTestDriver=(()=>class{constructor(w,x=null){this.processor=w;this.page=x;this.commandDelay=20;this.pageTestDelay=700;this.persistentData={}}parseTestObject(w){var x="";w.indexOf("*")>-1&&(w=w.replace(/\*/,""),x="*");x=`[data-test-object-name${x}='${w}']`;return w.length>
|
|
256
|
-
w.substring(1)),x}wait(w){return v(this,void 0,void 0,function*(){return new Promise((x,D)=>{setTimeout(()=>{x()},w)})})}print(w){return v(this,void 0,void 0,function*(){process.stdout.write(w)})}println(w){return v(this,void 0,void 0,function*(){yield this.print(`${w}\n`)})}destroy(){return v(this,void 0,void 0,function*(){})}assert(w){return v(this,arguments,void 0,function*(x,D=""){if(!x)throw Error(D);})}})()},[1284](J,p){Object.defineProperty(p,"__esModule",{value:!0});p.HotTestElement=
|
|
257
|
-
void 0;p.HotTestElementOptions=(()=>class{constructor(v={}){this.mustBeVisible=v.mustBeVisible||!0;this.ignoreMissingElementError=v.ignoreMissingElementError||!1}})();p.HotTestElement=(()=>class{constructor(v,w="",x=null){"string"==typeof v?(this.name=v,this.func=w,this.value=x):(this.name=v.name,this.func=v.func||w,this.value=v.value||x)}})()},[6434](J,p,v){Object.defineProperty(p,"__esModule",{value:!0});p.HotTestMap=void 0;var w=v(4744);p.HotTestMap=class{constructor(x=
|
|
258
|
-
Array){this.destinations=[];for(var r=0;r<x.length;r++)this.destinations.push(new w.HotTestDestination(x[r]))}else for(r in this.destinations={},x)this.destinations[r]=new w.HotTestDestination(x[r]);this.destinationOrder=k;this.pages=D}}},[1153](J,p){Object.defineProperty(p,"__esModule",{value:!0})},[9962](J,p){Object.defineProperty(p,"__esModule",{value:!0})},[8969](J,p,v){var w=this&&this.__awaiter||function(k,r,n,l){return new (n||(n=Promise))(function(d,b){function c(a){try{u(l.next(a))}catch(m){b(m)}}
|
|
255
|
+
function b(c){var e;c.done?r(c.value):(e=c.value,e instanceof D?e:new D(function(u){u(e)})).then(l,d)}b((k=k.apply(w,x||[])).next())})};Object.defineProperty(p,"__esModule",{value:!0});p.HotTestDriver=void 0;p.HotTestDriver=(()=>class{constructor(w,x=null){this.processor=w;this.tester=null;this.page=x;this.commandDelay=20;this.pageTestDelay=700;this.persistentData={}}parseTestObject(w){var x="";w.indexOf("*")>-1&&(w=w.replace(/\*/,""),x="*");x=`[data-test-object-name${x}='${w}']`;return w.length>
|
|
256
|
+
0&&">"===w[0]&&(x=w.substring(1)),x}wait(w){return v(this,void 0,void 0,function*(){return new Promise((x,D)=>{setTimeout(()=>{x()},w)})})}print(w){return v(this,void 0,void 0,function*(){process.stdout.write(w)})}println(w){return v(this,void 0,void 0,function*(){yield this.print(`${w}\n`)})}destroy(){return v(this,void 0,void 0,function*(){})}assert(w){return v(this,arguments,void 0,function*(x,D=""){if(!x)throw Error(D);})}})()},[1284](J,p){Object.defineProperty(p,"__esModule",{value:!0});p.HotTestElement=
|
|
257
|
+
p.HotTestElementOptions=void 0;p.HotTestElementOptions=(()=>class{constructor(v={}){this.mustBeVisible=v.mustBeVisible||!0;this.ignoreMissingElementError=v.ignoreMissingElementError||!1}})();p.HotTestElement=(()=>class{constructor(v,w="",x=null){"string"==typeof v?(this.name=v,this.func=w,this.value=x):(this.name=v.name,this.func=v.func||w,this.value=v.value||x)}})()},[6434](J,p,v){Object.defineProperty(p,"__esModule",{value:!0});p.HotTestMap=void 0;var w=v(4744);p.HotTestMap=class{constructor(x=
|
|
258
|
+
[],D={},k=[]){if(x instanceof Array){this.destinations=[];for(var r=0;r<x.length;r++)this.destinations.push(new w.HotTestDestination(x[r]))}else for(r in this.destinations={},x)this.destinations[r]=new w.HotTestDestination(x[r]);this.destinationOrder=k;this.pages=D}}},[1153](J,p){Object.defineProperty(p,"__esModule",{value:!0})},[9962](J,p){Object.defineProperty(p,"__esModule",{value:!0})},[8969](J,p,v){var w=this&&this.__awaiter||function(k,r,n,l){return new (n||(n=Promise))(function(d,b){function c(a){try{u(l.next(a))}catch(m){b(m)}}
|
|
259
259
|
function e(a){try{u(l.throw(a))}catch(m){b(m)}}function u(a){var m;a.done?d(a.value):(m=a.value,m instanceof n?m:new n(function(t){t(m)})).then(c,e)}u((l=l.apply(k,r||[])).next())})};Object.defineProperty(p,"__esModule",{value:!0});p.HotTester=void 0;var x=v(9343);class D{constructor(k,r,n,l,d={}){if(null==d)throw Error("The testMaps parameter can be an empty object, but cannot be null! It is set to null.");this.processor=k;this.name=r;this.timeout=1E4;this.baseUrl=n;this.testMaps=d;this.driver=l;
|
|
260
|
-
this.hasBeenDestroyed=this.hasBeenSetup=this.finishedLoading=!1;this.currentPage=null;this.numFailures=0}setup(k,r,n){return w(this,void 0,void 0,function*(){})}destroy(){return w(this,void 0,void 0,function*(){})}waitForData(){return w(this,void 0,void 0,function*(){for(var k=parseInt(process.env.HOTSTAQ_WAIT_FOR_DATA_TIMEOUT_MS||"120000",10)||12E4,r=Date.now();!1===this.finishedLoading;){if(Date.now()-r>k)throw Error(`HotTester: waitForData timed out after ${k}ms \u2014 the test page never registered its test paths with HotTesterAPI. Check that HotStaq.min.js loaded, the page didn't error before Hot.CurrentPage.createTestPath, and testerAPIUrl in HotSite.yaml points at this server. Override the cap with HOTSTAQ_WAIT_FOR_DATA_TIMEOUT_MS.`);
|
|
260
|
+
null!=this.driver&&(this.driver.tester=this);this.hasBeenDestroyed=this.hasBeenSetup=this.finishedLoading=!1;this.currentPage=null;this.numFailures=0}setup(k,r,n){return w(this,void 0,void 0,function*(){})}destroy(){return w(this,void 0,void 0,function*(){})}waitForData(){return w(this,void 0,void 0,function*(){for(var k=parseInt(process.env.HOTSTAQ_WAIT_FOR_DATA_TIMEOUT_MS||"120000",10)||12E4,r=Date.now();!1===this.finishedLoading;){if(Date.now()-r>k)throw Error(`HotTester: waitForData timed out after ${k}ms \u2014 the test page never registered its test paths with HotTesterAPI. Check that HotStaq.min.js loaded, the page didn't error before Hot.CurrentPage.createTestPath, and testerAPIUrl in HotSite.yaml points at this server. Override the cap with HOTSTAQ_WAIT_FOR_DATA_TIMEOUT_MS.`);
|
|
261
261
|
yield x.HotStaq.wait(10)}})}static interpretDestination(k,r){k={mapName:k,url:"",api:"",paths:[]};r=r.destination.split(/\->/g);var n=r[0];if(n.length<2||"/"===n[0]&&"/"===n[1])return null;var l=(d,b)=>{var c=d.indexOf(b),e="";return c>-1&&(e=d.substr(c+b.length),e=e.trim()),e};k.url=l(n,"url:");k.api=l(n,"api:");for(n=1;n<r.length;n++){let d=r[n],b={cmd:"",dest:"",path:""};d=d.trim();b.dest=l(d,"dest:");b.cmd=l(d,"cmd:");b.path=l(d,"path:");""==b.dest&&""==b.cmd&&""==b.path&&(b.path=d);k.paths.push(b)}return k}executeTestAPIPath(k,
|
|
262
262
|
r,n){return w(this,arguments,void 0,function*(l,d,b,c=!1,e=!1){var u=!0;if(null==d)throw Error(`Trying to access null method on destination map ${l.mapName}.`);!1===c&&null!=this.onTestAPIPathStart&&(u=yield this.onTestAPIPathStart(l,d,b,e));var a=null;if(!0===u){u=d.testCases[b];if(null==u)throw Error(`HotTester: Test case object ${b} does not exist!`);a=yield u.func(this.driver)}return!1===c&&null!=this.onTestAPIPathEnd&&(yield this.onTestAPIPathEnd(l,d,b,a,e)),a})}executeTestAPIPaths(k){return w(this,
|
|
263
263
|
void 0,void 0,function*(){var r=[];if(null==this.testMaps[k.mapName])throw Error(`HotTester: API Map ${k.mapName} does not exist!`);if(null==this.processor.api)throw Error("HotTester: Associated processor does not have an API!");var n=this.processor.api.routes[k.api];if(null==n)throw Error(`HotTester: API does not have route ${k.api}!`);for(let d=0;d+1<k.paths.length;d+=2){var l=k.paths[d].path;let b=n.getMethod(l),c=k.paths[d+1].path;if(null==b)throw Error(`Unable to find method related to path ${l} in map ${k.mapName}`);
|
package/package.json
CHANGED
package/src/HotStaq.ts
CHANGED
package/src/HotTestDriver.ts
CHANGED
|
@@ -11,6 +11,14 @@ export class HotTestDriver
|
|
|
11
11
|
* The current page.
|
|
12
12
|
*/
|
|
13
13
|
processor: HotStaq;
|
|
14
|
+
/**
|
|
15
|
+
* The HotTester that owns this driver. Set when the tester
|
|
16
|
+
* attaches the driver to itself; navigating to a new URL needs
|
|
17
|
+
* this so we can flip `finishedLoading` back to false and the
|
|
18
|
+
* next executeTestPagePath waits for the new page's pageLoaded
|
|
19
|
+
* event instead of reading stale paths from the previous page.
|
|
20
|
+
*/
|
|
21
|
+
tester: any;
|
|
14
22
|
/**
|
|
15
23
|
* The current page.
|
|
16
24
|
*/
|
|
@@ -33,6 +41,7 @@ export class HotTestDriver
|
|
|
33
41
|
constructor (processor: HotStaq, page: HotTestPage | null = null)
|
|
34
42
|
{
|
|
35
43
|
this.processor = processor;
|
|
44
|
+
this.tester = null;
|
|
36
45
|
this.page = page;
|
|
37
46
|
this.commandDelay = 20;
|
|
38
47
|
this.pageTestDelay = 700;
|
|
@@ -326,6 +326,13 @@ export class HotTestSeleniumDriver extends HotTestDriver
|
|
|
326
326
|
}
|
|
327
327
|
catch (e) { /* fall through with the bare path */ }
|
|
328
328
|
}
|
|
329
|
+
// Reset the tester's finishedLoading so the next executeTestPagePath
|
|
330
|
+
// blocks on the *new* page's pageLoaded event, not the previous
|
|
331
|
+
// page's already-fired one — otherwise the runner immediately
|
|
332
|
+
// looks up the next test path against stale caches and fails
|
|
333
|
+
// with "Test path X does not have a function".
|
|
334
|
+
if (this.tester != null)
|
|
335
|
+
this.tester.finishedLoading = false;
|
|
329
336
|
await this.navigateToUrl (target);
|
|
330
337
|
}
|
|
331
338
|
|
|
@@ -411,7 +418,10 @@ export class HotTestSeleniumDriver extends HotTestDriver
|
|
|
411
418
|
}
|
|
412
419
|
}
|
|
413
420
|
|
|
414
|
-
|
|
421
|
+
if (foundElm != null)
|
|
422
|
+
this.processor.logger.verbose (`HotTestSeleniumDriver: findTestElement - Found ${nameStr}`);
|
|
423
|
+
else
|
|
424
|
+
this.processor.logger.verbose (`HotTestSeleniumDriver: findTestElement - Not found ${nameStr}`);
|
|
415
425
|
|
|
416
426
|
return (foundElm);
|
|
417
427
|
}
|
|
@@ -458,7 +468,42 @@ export class HotTestSeleniumDriver extends HotTestDriver
|
|
|
458
468
|
{
|
|
459
469
|
if (func !== "")
|
|
460
470
|
{
|
|
461
|
-
|
|
471
|
+
// Click hardening: layouts with sticky footers, fixed
|
|
472
|
+
// banners, or BotBlocker overlays routinely intercept the
|
|
473
|
+
// raw `elm.click()`. Scroll the target into the centre of
|
|
474
|
+
// the viewport first; if Selenium still rejects the click
|
|
475
|
+
// as intercepted, fall back to a JS click which bypasses
|
|
476
|
+
// hit-testing entirely.
|
|
477
|
+
if (func === "click")
|
|
478
|
+
{
|
|
479
|
+
try
|
|
480
|
+
{
|
|
481
|
+
await this.driver.executeScript (
|
|
482
|
+
"arguments[0].scrollIntoView({block:'center', inline:'center'});",
|
|
483
|
+
elm);
|
|
484
|
+
}
|
|
485
|
+
catch (_e) { /* best-effort scroll */ }
|
|
486
|
+
|
|
487
|
+
try
|
|
488
|
+
{
|
|
489
|
+
result = await elm.click ();
|
|
490
|
+
}
|
|
491
|
+
catch (clickErr)
|
|
492
|
+
{
|
|
493
|
+
const msg: string = (clickErr && (clickErr as any).message) || String (clickErr);
|
|
494
|
+
if (msg.indexOf ("intercepted") > -1 || msg.indexOf ("not clickable") > -1)
|
|
495
|
+
{
|
|
496
|
+
this.processor.logger.verbose (
|
|
497
|
+
`HotTestSeleniumDriver: click intercepted on ${name}; ` +
|
|
498
|
+
`falling back to JS click.`);
|
|
499
|
+
result = await this.driver.executeScript (
|
|
500
|
+
"arguments[0].click();", elm);
|
|
501
|
+
}
|
|
502
|
+
else
|
|
503
|
+
throw clickErr;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
else if (value != null)
|
|
462
507
|
{
|
|
463
508
|
/// @ts-ignore
|
|
464
509
|
result = await elm[func] (value);
|
package/src/HotTester.ts
CHANGED
|
@@ -71,6 +71,13 @@ export abstract class HotTester
|
|
|
71
71
|
this.baseUrl = baseUrl;
|
|
72
72
|
this.testMaps = testMaps;
|
|
73
73
|
this.driver = driver;
|
|
74
|
+
// Back-reference so the driver can flip our `finishedLoading`
|
|
75
|
+
// to false on cross-page navigations — without it, navigate("/foo")
|
|
76
|
+
// returns immediately with the previous page's stale paths cached
|
|
77
|
+
// and the next executeTestPagePath fails with "Test path X does
|
|
78
|
+
// not have a function".
|
|
79
|
+
if (this.driver != null)
|
|
80
|
+
this.driver.tester = this;
|
|
74
81
|
this.finishedLoading = false;
|
|
75
82
|
this.hasBeenSetup = false;
|
|
76
83
|
this.hasBeenDestroyed = false;
|