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.
@@ -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.10";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;
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>0&&">"===w[0]&&(x=
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=p.HotTestElementOptions=
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=[],D={},k=[]){if(x instanceof
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hotstaq",
3
- "version": "0.9.10",
3
+ "version": "0.9.13",
4
4
  "description": "A friendly web framework that fits nicely into devops and CI/CD pipelines.",
5
5
  "bin": {
6
6
  "hotstaq": "./bin/hotstaq"
package/src/HotStaq.ts CHANGED
@@ -238,7 +238,7 @@ export class HotStaq implements IHotStaq
238
238
  /**
239
239
  * The current version of HotStaq.
240
240
  */
241
- static version: string = "0.9.10";
241
+ static version: string = "0.9.13";
242
242
  /**
243
243
  * Indicates if this is a web build.
244
244
  */
@@ -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
- this.processor.logger.verbose (`HotTestSeleniumDriver: findTestElement - Found ${nameStr}`);
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
- if (value != null)
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;