test.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. /**
  2. * @class Ext.ux.event.Driver
  3. * This is the base class for {@link Recorder} and {@link Player}.
  4. */
  5. Ext.define('Ext.ux.event.Driver', {
  6. active: null,
  7. mixins: {
  8. observable: 'Ext.util.Observable'
  9. },
  10. constructor: function (config) {
  11. var me = this;
  12. me.mixins.observable.constructor.apply(this, arguments);
  13. me.addEvents(
  14. /**
  15. * @event start
  16. * Fires when this object is started.
  17. * @param {Ext.ux.event.Driver} this
  18. */
  19. 'start',
  20. /**
  21. * @event stop
  22. * Fires when this object is stopped.
  23. * @param {Ext.ux.event.Driver} this
  24. */
  25. 'stop'
  26. );
  27. },
  28. /**
  29. * Returns the number of milliseconds since start was called.
  30. */
  31. getTimestamp: function () {
  32. var d = new Date();
  33. return d.getTime() - this.startTime;
  34. },
  35. onStart: function () {},
  36. onStop: function () {},
  37. /**
  38. * Starts this object. If this object is already started, nothing happens.
  39. */
  40. start: function () {
  41. var me = this;
  42. if (!me.active) {
  43. me.active = new Date();
  44. me.startTime = me.active.getTime();
  45. me.onStart();
  46. me.fireEvent('start', me);
  47. }
  48. },
  49. /**
  50. * Stops this object. If this object is not started, nothing happens.
  51. */
  52. stop: function () {
  53. var me = this;
  54. if (me.active) {
  55. me.active = null;
  56. me.onStop();
  57. me.fireEvent('stop', me);
  58. }
  59. }
  60. });
  61. /**
  62. * @class Ext.ux.event.Player
  63. * @extends Ext.ux.event.Driver
  64. *
  65. * This class manages the playback of an array of "event descriptors". For details on the
  66. * contents of an "event descriptor", see {@link Recorder}. The events recorded by the
  67. * {@link Recorder} class are designed to serve as input for this class.
  68. *
  69. * The simplest use of this class is to instantiate it with an {@link #eventQueue} and call
  70. * {@link #start}. Like so:
  71. *
  72. * var player = Ext.create('Ext.ux.event.Player', {
  73. * eventQueue: [ ... ],
  74. * speed: 2, // play at 2x speed
  75. * listeners: {
  76. * stop: function () {
  77. * player = null; // all done
  78. * }
  79. * }
  80. * });
  81. *
  82. * player.start();
  83. *
  84. * A more complex use would be to incorporate keyframe generation after playing certain
  85. * events.
  86. *
  87. * var player = Ext.create('Ext.ux.event.Player', {
  88. * eventQueue: [ ... ],
  89. * keyFrameEvents: {
  90. * click: true
  91. * },
  92. * listeners: {
  93. * stop: function () {
  94. * // play has completed... probably time for another keyframe...
  95. * player = null;
  96. * },
  97. * keyframe: onKeyFrame
  98. * }
  99. * });
  100. *
  101. * player.start();
  102. *
  103. * If a keyframe can be handled immediately (synchronously), the listener would be:
  104. *
  105. * function onKeyFrame () {
  106. * handleKeyFrame();
  107. * }
  108. *
  109. * If the keyframe event is always handled asynchronously, then the event listener is only
  110. * a bit more:
  111. *
  112. * function onKeyFrame (p, eventDescriptor) {
  113. * eventDescriptor.defer(); // pause event playback...
  114. *
  115. * handleKeyFrame(function () {
  116. * eventDescriptor.finish(); // ...resume event playback
  117. * });
  118. * }
  119. *
  120. * Finally, if the keyframe could be either handled synchronously or asynchronously (perhaps
  121. * differently by browser), a slightly more complex listener is required.
  122. *
  123. * function onKeyFrame (p, eventDescriptor) {
  124. * var async;
  125. *
  126. * handleKeyFrame(function () {
  127. * // either this callback is being called immediately by handleKeyFrame (in
  128. * // which case async is undefined) or it is being called later (in which case
  129. * // async will be true).
  130. *
  131. * if (async) {
  132. * eventDescriptor.finish();
  133. * } else {
  134. * async = false;
  135. * }
  136. * });
  137. *
  138. * // either the callback was called (and async is now false) or it was not
  139. * // called (and async remains undefined).
  140. *
  141. * if (async !== false) {
  142. * eventDescriptor.defer();
  143. * async = true; // let the callback know that we have gone async
  144. * }
  145. * }
  146. *
  147. * @markdown
  148. */
  149. Ext.define('Ext.ux.event.Player', {
  150. extend: 'Ext.ux.event.Driver',
  151. /**
  152. * @cfg {Array} eventQueue The event queue to playback. This must be provided before
  153. * the {@link #start} method is called.
  154. */
  155. /**
  156. * @cfg {Object} keyFrameEvents An object that describes the events that should generate
  157. * keyframe events. For example, `{ click: true }` would generate keyframe events after
  158. * each `click` event.
  159. */
  160. keyFrameEvents: {
  161. click: true
  162. },
  163. /**
  164. * @cfg {Boolean} pauseForAnimations True to pause event playback during animations, false
  165. * to ignore animations. Default is true.
  166. */
  167. pauseForAnimations: true,
  168. /**
  169. * @cfg {Number} speed The playback speed multiplier. Default is 1.0 (to playback at the
  170. * recorded speed). A value of 2 would playback at 2x speed.
  171. */
  172. speed: 1.0,
  173. tagPathRegEx: /(\w+)(?:\[(\d+)\])?/,
  174. screenshotTimeout: 500,
  175. constructor: function (config) {
  176. var me = this;
  177. me.callParent(arguments);
  178. me.addEvents(
  179. /**
  180. * @event beforeplay
  181. * Fires before an event is played.
  182. * @param {Ext.ux.event.Player} this
  183. * @param {Object} eventDescriptor The event descriptor about to be played.
  184. */
  185. 'beforeplay',
  186. /**
  187. * @event keyframe
  188. * Fires when this player reaches a keyframe. Typically, this is after events
  189. * like `click` are injected and any resulting animations have been completed.
  190. * @param {Ext.ux.event.Player} this
  191. * @param {Object} eventDescriptor The keyframe event descriptor.
  192. */
  193. 'keyframe'
  194. );
  195. me.eventObject = new Ext.EventObjectImpl();
  196. me.timerFn = function () {
  197. me.onTick();
  198. };
  199. me.attachTo = me.attachTo || window;
  200. },
  201. /**
  202. * Returns the element given is XPath-like description.
  203. * @param {String} xpath The XPath-like description of the element.
  204. * @return {HTMLElement}
  205. */
  206. getElementFromXPath: function (xpath) {
  207. var me = this,
  208. parts = xpath.split('/'),
  209. regex = me.tagPathRegEx,
  210. i, n, m, count, tag, child,
  211. el = me.attachTo.document;
  212. el = (parts[0] == '~') ? el.body
  213. : el.getElementById(parts[0].substring(1)); // remove '#'
  214. for (i = 1, n = parts.length; el && i < n; ++i) {
  215. m = regex.exec(parts[i]);
  216. count = m[2] ? parseInt(m[2], 10) : 1;
  217. tag = m[1].toUpperCase();
  218. for (child = el.firstChild; child; child = child.nextSibling) {
  219. if (child.tagName == tag) {
  220. if (count == 1) {
  221. break;
  222. }
  223. --count;
  224. }
  225. }
  226. el = child;
  227. }
  228. return el;
  229. },
  230. /**
  231. * This method is called after an event has been played to prepare for the next event.
  232. * @param {Object} eventDescriptor The descriptor of the event just played.
  233. */
  234. nextEvent: function (eventDescriptor) {
  235. var me = this, index;
  236. if (eventDescriptor.screenshot) {
  237. eventDescriptor.played = true;
  238. return;
  239. }
  240. if (eventDescriptor.after) {
  241. eventDescriptor.after();
  242. delete eventDescriptor.after;
  243. return;
  244. }
  245. index = ++me.queueIndex;
  246. // keyframe events are inserted after a keyFrameEvent is played.
  247. if (me.keyFrameEvents[eventDescriptor.type]) {
  248. Ext.Array.insert(me.eventQueue, index, [
  249. { keyframe: true, ts: eventDescriptor.ts }
  250. ]);
  251. }
  252. },
  253. /**
  254. * This method returns the event descriptor at the front of the queue. This does not
  255. * dequeue the event. Repeated calls return the same object (until {@link #nextEvent}
  256. * is called).
  257. */
  258. peekEvent: function () {
  259. var me = this,
  260. queue = me.eventQueue,
  261. index = me.queueIndex,
  262. eventDescriptor = queue[index],
  263. type = eventDescriptor && eventDescriptor.type,
  264. tmp;
  265. if (type == 'mduclick') {
  266. tmp = [
  267. Ext.applyIf({ type: 'mousedown' }, eventDescriptor),
  268. Ext.applyIf({ type: 'mouseup' }, eventDescriptor),
  269. Ext.applyIf({ type: 'click' }, eventDescriptor)
  270. ];
  271. delete tmp[0].screenshot;
  272. delete tmp[0].after;
  273. delete tmp[1].screenshot;
  274. delete tmp[1].after;
  275. Ext.Array.replace(queue, index, 1, tmp);
  276. }
  277. // if (type == 'drag') {
  278. //
  279. // Ext.Array.replace(queue, index, 1, me.createDrag(eventDescriptor));
  280. // return queue[index];
  281. // }
  282. return queue[index] || null;
  283. },
  284. // TODO
  285. // dragStep: 5,
  286. //
  287. // createDrag: function(eventDescriptor) {
  288. // var me = this,
  289. // tmp = [
  290. // Ext.applyIf({ type: 'mousedown' }, eventDescriptor)
  291. // ],
  292. //
  293. // from = me.getTarget(eventDescriptor).xy,
  294. // to = me.getTarget(eventDescriptor.dropTo).xy,
  295. // i = 0,
  296. // xinc, yinc, x, y;
  297. //
  298. //
  299. //
  300. // xinc = (to[0] - from[0]) / me.dragStep;
  301. //
  302. // yinc = (to[1] - from[1]) / me.dragStep;
  303. //
  304. // x = from[0] + xinc;
  305. // y = from[1] + yinc;
  306. //
  307. //
  308. // for (i = 0; i < me.dragStep; i++) {
  309. // tmp.push(Ext.applyIf({ type: 'mousemove', xy: [x,y]}, eventDescriptor));
  310. // x += xinc;
  311. // y += yinc;
  312. // }
  313. //
  314. // tmp.push(Ext.applyIf({ type: 'mouseup' }, eventDescriptor.dropTo));
  315. //
  316. // return tmp;
  317. // },
  318. /**
  319. * This method dequeues and injects events until it has arrived at the time index. If
  320. * no events are ready (based on the time index), this method does nothing.
  321. * @return {Boolean} True if there is more to do; false if not (at least for now).
  322. */
  323. processEvents: function () {
  324. var me = this,
  325. animations = me.pauseForAnimations && me.attachTo.Ext.fx.Manager.items,
  326. eventDescriptor;
  327. while ((eventDescriptor = me.peekEvent()) !== null) {
  328. if (animations && animations.getCount()) {
  329. return true;
  330. }
  331. if (eventDescriptor.screenshot && eventDescriptor.played) {
  332. delete eventDescriptor.screenshot;
  333. delete eventDescriptor.played;
  334. me.snap();
  335. me.nextEvent(eventDescriptor);
  336. continue;
  337. }
  338. if (eventDescriptor.keyframe) {
  339. if (!me.processKeyFrame(eventDescriptor)) {
  340. return false;
  341. }
  342. me.nextEvent(eventDescriptor);
  343. } else if (eventDescriptor.ts <= me.timeIndex || !eventDescriptor.ts &&
  344. me.fireEvent('beforeplay', me, eventDescriptor) !== false &&
  345. me.playEvent(eventDescriptor)) {
  346. me.nextEvent(eventDescriptor);
  347. if (eventDescriptor.played) {
  348. return true;
  349. }
  350. } else {
  351. return true;
  352. }
  353. }
  354. me.stop();
  355. return false;
  356. },
  357. snap: function() {
  358. if (window.__x && __x.poll) {
  359. __x.poll.sendSyncRequest({cmd: 'screenshot'});
  360. } else {
  361. alert('sreenshot');
  362. }
  363. },
  364. /**
  365. * This method is called when a keyframe is reached. This will fire the keyframe event.
  366. * If the keyframe has been handled, true is returned. Otherwise, false is returned.
  367. * @param {Object} The event descriptor of the keyframe.
  368. * @return {Boolean} True if the keyframe was handled, false if not.
  369. */
  370. processKeyFrame: function (eventDescriptor) {
  371. var me = this;
  372. // only fire keyframe event (and setup the eventDescriptor) once...
  373. if (!eventDescriptor.defer) {
  374. eventDescriptor.done = true;
  375. eventDescriptor.defer = function () {
  376. eventDescriptor.done = false;
  377. };
  378. eventDescriptor.finish = function () {
  379. eventDescriptor.done = true;
  380. me.schedule();
  381. };
  382. me.fireEvent('keyframe', me, eventDescriptor);
  383. }
  384. return eventDescriptor.done;
  385. },
  386. /**
  387. * Called to inject the given event on the specified target.
  388. * @param {HTMLElement} target The target of the event.
  389. * @param {Ext.EventObject} The event to inject.
  390. */
  391. injectEvent: function (target, event) {
  392. event.injectEvent(target);
  393. },
  394. playEvent: function (eventDescriptor) {
  395. var me = this,
  396. target,
  397. event;
  398. if (eventDescriptor.cmpQuery || eventDescriptor.domQuery) {
  399. me.getTarget(eventDescriptor);
  400. }
  401. if (eventDescriptor.target) {
  402. target = me.getElementFromXPath(eventDescriptor.target);
  403. }
  404. if (!target) {
  405. // not present (yet)... wait for element present...
  406. // TODO - need a timeout here
  407. return false;
  408. }
  409. event = me.translateEvent(eventDescriptor, target);
  410. me.injectEvent(target, event);
  411. return true;
  412. },
  413. schedule: function () {
  414. var me = this;
  415. if (!me.timer) {
  416. me.timer = setTimeout(me.timerFn, 250);
  417. }
  418. },
  419. translateEvent: function (eventDescriptor, target) {
  420. var me = this,
  421. event = me.eventObject,
  422. modKeys = eventDescriptor.modKeys || '',
  423. xy;
  424. if ('xy' in eventDescriptor) {
  425. event.xy = xy = Ext.fly(target).getXY();
  426. xy[0] += eventDescriptor.xy[0];
  427. xy[1] += eventDescriptor.xy[1];
  428. }
  429. if ('wheel' in eventDescriptor) {
  430. // see getWheelDelta
  431. }
  432. event.type = eventDescriptor.type;
  433. event.button = eventDescriptor.button;
  434. event.altKey = modKeys.indexOf('A') > 0;
  435. event.ctrlKey = modKeys.indexOf('C') > 0;
  436. event.metaKey = modKeys.indexOf('M') > 0;
  437. event.shiftKey = modKeys.indexOf('S') > 0;
  438. return event;
  439. },
  440. getTarget: function(eventDescriptor) {
  441. var me = this;
  442. eventDescriptor.el = eventDescriptor.el || 'el';
  443. if (eventDescriptor.cmpQuery) {
  444. me.findTarget(eventDescriptor, Ext.ComponentQuery.query(eventDescriptor.cmpQuery)[0]);
  445. } else {
  446. me.findTarget(eventDescriptor);
  447. }
  448. return eventDescriptor;
  449. },
  450. findTarget: function(eventDescriptor, cmp) {
  451. var me = this,
  452. x, y, el, offsetX, offsetY;
  453. if (cmp) {
  454. if (!eventDescriptor.domQuery) {
  455. el = cmp[eventDescriptor.el];
  456. } else {
  457. el = cmp.el.down(eventDescriptor.domQuery);
  458. }
  459. } else {
  460. el = Ext.get(Ext.DomQuery.selectNode(eventDescriptor.domQuery));
  461. }
  462. try {
  463. eventDescriptor.target = '#' + el.dom.id;
  464. if (!eventDescriptor.xy) {
  465. if (eventDescriptor.offset) {
  466. offsetX = eventDescriptor.offset[0];
  467. offsetY = eventDescriptor.offset[1];
  468. if (offsetX > 0) {
  469. x = offsetX;
  470. } else {
  471. x = el.getWidth() - offsetX;
  472. }
  473. if (offsetY > 0) {
  474. y = offsetY;
  475. } else {
  476. y = el.getHeight() - offsetY;
  477. }
  478. // default centering
  479. } else {
  480. x = (el.getWidth() / 2);
  481. y = (el.getHeight() / 2);
  482. }
  483. eventDescriptor.xy = [x,y];
  484. }
  485. } catch(e) {}
  486. return eventDescriptor;
  487. },
  488. //---------------------------------
  489. // Driver overrides
  490. onStart: function () {
  491. var me = this;
  492. me.queueIndex = 0;
  493. me.schedule();
  494. },
  495. onStop: function () {
  496. var me = this;
  497. if (me.timer) {
  498. clearTimeout(me.timer);
  499. me.timer = null;
  500. }
  501. if (window.__x && __x.poll) {
  502. __x.poll.sendSyncRequest({cmd: 'finish'});
  503. }
  504. },
  505. //---------------------------------
  506. onTick: function () {
  507. var me = this;
  508. me.timer = null;
  509. me.timeIndex = me.getTimestamp() * me.speed;
  510. if (me.processEvents()) {
  511. me.schedule();
  512. }
  513. }
  514. });
  515. Ext.define('Ext.ux.event.Maker', {
  516. eventQueue: [],
  517. startAfter: 0,
  518. timerIncrement: 2000,
  519. currentTiming: 0,
  520. constructor: function(config) {
  521. var me = this;
  522. me.currentTiming = me.startAfter;
  523. if(!Ext.isArray(config)) {
  524. config = [config];
  525. }
  526. Ext.Array.each(config, function(item) {
  527. item.el = item.el || 'el';
  528. if (item.cmpQuery) {
  529. Ext.Array.each(Ext.ComponentQuery.query(item.cmpQuery), function(cmp) {
  530. me.generateEvent(item, cmp);
  531. });
  532. } else {
  533. me.generateEvent(item);
  534. }
  535. if (item.endingScreenshot) {
  536. me.eventQueue[me.eventQueue.length - 1].screenshot = true;
  537. }
  538. });
  539. return me.eventQueue;
  540. },
  541. generateEvent: function(item, cmp) {
  542. var me = this,
  543. event = {}, x, y, el;
  544. if (cmp) {
  545. if (!item.domQuery) {
  546. el = cmp[item.el];
  547. } else {
  548. el = cmp.el.down(item.domQuery);
  549. }
  550. } else {
  551. el = Ext.get(Ext.DomQuery.selectNode(item.domQuery));
  552. }
  553. event.target = '#' + el.dom.id;
  554. // event.type = item.type;
  555. // event.key = item.key;
  556. // event.button = item.button || 0;
  557. x = el.getX() + (el.getWidth() / 2);
  558. y = el.getY() + (el.getHeight() / 2);
  559. event.xy = [x,y];
  560. event.ts = me.currentTiming;
  561. event.screenshot = item.screenshot;
  562. me.currentTiming += me.timerIncrement;
  563. me.eventQueue.push(event);
  564. }
  565. });
  566. Ext.onReady(function() {
  567. if (!window.__x) {
  568. __x = {};
  569. } else {
  570. __x.poll.interval = 50;
  571. __x.poll.connect();
  572. }
  573. //
  574. //
  575. __x.player = Ext.create('Ext.ux.event.Player', {
  576. eventQueue: [{
  577. cmpQuery: 'panel[title="Collapsed Panel"] > header > tool[type=expand-bottom]',
  578. domQuery: 'img',
  579. type: 'mduclick',
  580. screenshot: true
  581. },{
  582. cmpQuery: 'panel[title="Collapsed Panel"] > header > tool[type=collapse-top]',
  583. domQuery: 'img',
  584. type: 'mduclick',
  585. screenshot: true
  586. },{
  587. cmpQuery: 'panel[title="Masked Panel"] > header > tool[type=collapse-top]',
  588. domQuery: 'img',
  589. type: 'mduclick',
  590. screenshot: true
  591. },{
  592. cmpQuery: 'panel[title="Masked Panel"] > header > tool[type=collapse-bottom]',
  593. domQuery: 'img',
  594. type: 'mduclick',
  595. screenshot: true
  596. },{
  597. cmpQuery: 'panel[title="Collapsed Framed Panel"] > header > tool[type=expand-bottom]',
  598. domQuery: 'img',
  599. type: 'mduclick',
  600. screenshot: true
  601. },{
  602. cmpQuery: 'panel[title="Collapsed Framed Panel"] > header > tool[type=collapse-top]',
  603. domQuery: 'img',
  604. type: 'mduclick',
  605. screenshot: true
  606. },{
  607. cmpQuery: 'window[title=Window] > toolbar > button[text=Submit]',
  608. type: 'mduclick',
  609. screenshot: true
  610. },{
  611. cmpQuery: 'button[text=Yes]',
  612. type: 'mduclick',
  613. screenshot: true
  614. },{
  615. cmpQuery: 'window[title=Window] > header > tool[type=collapse-top]',
  616. domQuery: 'img',
  617. type: 'mduclick',
  618. screenshot: true
  619. },{
  620. cmpQuery: 'window[title=Window] > header > tool[type=collapse-bottom]',
  621. domQuery: 'img',
  622. type: 'mduclick',
  623. screenshot: true
  624. },{
  625. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Menu Button]',
  626. offset: [-2, -2],
  627. type: 'mouseover'
  628. },{
  629. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Menu Button]',
  630. offset: [-2, -3],
  631. type: 'mousemove'
  632. },{
  633. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Menu Button]',
  634. offset: [-2, -2],
  635. type: 'mduclick',
  636. screenshot: true
  637. },{
  638. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Menu Button]',
  639. offset: [-2, -2],
  640. type: 'mduclick',
  641. screenshot: true
  642. },{
  643. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Menu Button]',
  644. offset: [-2, -2],
  645. type: 'mouseout',
  646. screenshot: true
  647. },{
  648. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Cut]',
  649. offset: [-2, -2],
  650. type: 'mouseover'
  651. },{
  652. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Cut]',
  653. offset: [-2, -3],
  654. type: 'mousemove'
  655. },{
  656. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Cut]',
  657. offset: [-2, -2],
  658. type: 'mduclick',
  659. screenshot: true
  660. },{
  661. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Cut]',
  662. offset: [-2, -2],
  663. type: 'mduclick',
  664. screenshot: true
  665. },{
  666. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=top] > buttongroup > button[text=Cut]',
  667. offset: [-2, -2],
  668. type: 'mouseout',
  669. screenshot: true
  670. },{
  671. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  672. offset: [-2, -2],
  673. type: 'mouseover'
  674. },{
  675. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  676. offset: [-2, -3],
  677. type: 'mousemove'
  678. },{
  679. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  680. offset: [-2, -2],
  681. type: 'mduclick',
  682. screenshot: true
  683. },{
  684. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  685. offset: [-2, -2],
  686. type: 'mduclick',
  687. screenshot: true
  688. },{
  689. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  690. offset: [-2, -2],
  691. type: 'mouseout',
  692. screenshot: true
  693. },{
  694. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  695. offset: [-2, -2],
  696. type: 'mouseover'
  697. },{
  698. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  699. offset: [-2, -3],
  700. type: 'mousemove'
  701. },{
  702. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  703. offset: [-2, -2],
  704. type: 'mduclick',
  705. screenshot: true
  706. },{
  707. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  708. offset: [-2, -2],
  709. type: 'mduclick',
  710. screenshot: true
  711. },{
  712. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  713. offset: [-2, -2],
  714. type: 'mouseout',
  715. screenshot: true
  716. },{
  717. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Toggle Button]',
  718. type: 'mduclick',
  719. screenshot: true
  720. },{
  721. cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Toggle Button]',
  722. type: 'mduclick',
  723. screenshot: true
  724. // },{
  725. // cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  726. //
  727. // domQuery: '.x-btn-split',
  728. //
  729. // type: 'mduclick',
  730. //
  731. // screenshot: true
  732. // },{
  733. // cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Menu Button]',
  734. //
  735. // domQuery: '.x-btn-split',
  736. //
  737. // type: 'mduclick',
  738. //
  739. // screenshot: true
  740. // },{
  741. // cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  742. //
  743. // domQuery: '.x-btn-split',
  744. //
  745. // type: 'mduclick',
  746. //
  747. // screenshot: true
  748. // },{
  749. // cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Split Button]',
  750. //
  751. // domQuery: '.x-btn-split',
  752. //
  753. // type: 'mduclick',
  754. //
  755. // screenshot: true
  756. // },{
  757. // cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Toggle Button]',
  758. //
  759. // type: 'mduclick',
  760. //
  761. // screenshot: true
  762. // },{
  763. // cmpQuery: 'panel[title=Basic Panel With Toolbars] > toolbar[dock=bottom] > button[text=Toggle Button]',
  764. //
  765. // type: 'mduclick',
  766. //
  767. // screenshot: true
  768. // },{
  769. // cmpQuery: 'combo',
  770. //
  771. // domQuery: '.x-form-trigger',
  772. //
  773. // type: 'mduclick',
  774. //
  775. // screenshot: true
  776. // }, {
  777. // cmpQuery: 'boundlist',
  778. //
  779. // domQuery: '.x-boundlist-item',
  780. //
  781. // type: 'mduclick',
  782. //
  783. // screenshot: true
  784. // }, {
  785. // cmpQuery: 'grid[title=Array Grid] > headercontainer > gridcolumn[text=Company]',
  786. //
  787. // domQuery: '.x-column-header-text',
  788. //
  789. // type: 'drag',
  790. //
  791. // dropTo: {
  792. // cmpQuery: 'grid[title=Array Grid] > headercontainer > gridcolumn[text=Price]',
  793. //
  794. // domQuery: '.x-column-header-text'
  795. // },
  796. //
  797. // screenshot: true
  798. }]
  799. });
  800. if (!window.__x.poll) {
  801. __x.player.start();
  802. }
  803. });