├── .bithoundrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist ├── mocha-extjs.css └── mocha-extjs.js ├── gulpfile.js ├── mocha-extjs.js ├── package.json ├── scripts └── copy-demo.sh ├── scss └── mocha-extjs.scss ├── src ├── chain.js ├── chain │ ├── actionItem.js │ ├── componentActionItem.js │ ├── componentItem.js │ └── item.js ├── drivers │ ├── extjs │ │ ├── components │ │ │ ├── base.js │ │ │ ├── button.js │ │ │ ├── cellEditor.js │ │ │ ├── checkBox.js │ │ │ ├── comboBox.js │ │ │ ├── dataview.js │ │ │ ├── grid.js │ │ │ ├── numberField.js │ │ │ ├── radio.js │ │ │ ├── tab.js │ │ │ ├── textField.js │ │ │ └── window.js │ │ └── driver.js │ └── html │ │ └── components │ │ └── base.js ├── mochaUI.js ├── mochaUi │ └── cursor.js └── utils │ ├── set.js │ └── utils.js └── test ├── sandbox ├── .sencha │ ├── .cvsignore │ ├── .gitignore │ ├── app │ │ ├── Boot.js │ │ ├── Microloader.js │ │ ├── app.defaults.json │ │ ├── bootstrap-impl.xml │ │ ├── build-impl.xml │ │ ├── build.properties │ │ ├── codegen.json │ │ ├── cordova-impl.xml │ │ ├── cordova.defaults.properties │ │ ├── defaults.properties │ │ ├── development.defaults.properties │ │ ├── development.properties │ │ ├── ext.properties │ │ ├── find-cmd-impl.xml │ │ ├── init-impl.xml │ │ ├── js-impl.xml │ │ ├── native.defaults.properties │ │ ├── native.properties │ │ ├── package.defaults.properties │ │ ├── package.properties │ │ ├── packager-impl.xml │ │ ├── page-impl.xml │ │ ├── phonegap-impl.xml │ │ ├── phonegap.defaults.properties │ │ ├── plugin.xml │ │ ├── production.defaults.properties │ │ ├── production.properties │ │ ├── refresh-impl.xml │ │ ├── resolve-impl.xml │ │ ├── resources-impl.xml │ │ ├── sass-impl.xml │ │ ├── sencha.cfg │ │ ├── slice-impl.xml │ │ ├── testing.defaults.properties │ │ ├── testing.properties │ │ └── watch-impl.xml │ └── workspace │ │ ├── plugin.xml │ │ └── sencha.cfg ├── app.js ├── app.json ├── app │ ├── Application.js │ └── view │ │ └── main │ │ ├── Main.js │ │ ├── MainController.js │ │ ├── MainModel.js │ │ ├── SuitePanel.js │ │ ├── custom │ │ ├── Button.js │ │ ├── Dataview.js │ │ └── Grid.js │ │ └── tab │ │ ├── Buttons.js │ │ ├── Content.js │ │ ├── Dataview.js │ │ ├── Fields.js │ │ ├── Grids.js │ │ ├── LoadMasks.js │ │ └── Windows.js ├── bootstrap.css ├── bootstrap.js ├── bootstrap.json ├── build.xml ├── classic.json ├── index.html └── workspace.json └── suites ├── 010-environment.js ├── 020-buttons.js ├── 030-windows.js ├── 040-fields.js ├── 050-grids.js ├── 060-dataview.js ├── 070-loadmasks.js └── 080-content.js /.bithoundrc: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "**/node_modules/**", 4 | "**/dist/**", 5 | "**/test/sandbox/.sencha/**", 6 | "**/test/sandbox/build/**", 7 | "**/test/sandbox/ext/**", 8 | "**/test/sandbox/*.js", 9 | "**/test/sandbox/*.json", 10 | "**/test/sandbox/*.css", 11 | "**/test/sandbox/*.xml", 12 | "**/test/sandbox/*.html" 13 | ], 14 | "test": [ 15 | "**/test/suites/**" 16 | ], 17 | "critics": { 18 | "lint": { 19 | "engine": "standard" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .sass-cache 3 | 4 | *.log 5 | 6 | /node_modules 7 | 8 | /test/sandbox/ext 9 | /test/sandbox/overrides 10 | /test/sandbox/packages 11 | /test/sandbox/resources 12 | /test/sandbox/sass 13 | 14 | /test/sandbox/build 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5.10.1" 4 | before_script: 5 | - npm run lint 6 | - cd test/sandbox 7 | - wget https://dl.dropboxusercontent.com/u/21095169/archive/sencha-extjs-6.0.1.250.tar.gz 8 | - tar -zxf sencha-extjs-6.0.1.250.tar.gz 9 | - wget https://dl.dropboxusercontent.com/u/21095169/archive/sencha-cmd-6.1.2.15.tar.gz 10 | - tar -zxf sencha-cmd-6.1.2.15.tar.gz 11 | - ./6.1.2.15/sencha app build 12 | - cd ../../ 13 | - npm install mocha-phantomjs@4.0.2 mocha-phantomjs-core@2.0.1 phantomjs-prebuilt@2.1.7 14 | - npm run fix-deps 15 | - ./node_modules/.bin/phantomjs --version 16 | - npm start & 17 | - sleep 20 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Anton Fisher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mocha-extjs 2 | 3 | [![npm](https://img.shields.io/npm/dt/mocha-extjs.svg?maxAge=86400)](https://www.npmjs.com/package/mocha-extjs) 4 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) 5 | [![GitHub license](https://img.shields.io/github/license/antonfisher/node-mocha-extjs.svg)](https://github.com/antonfisher/node-mocha-extjs/blob/master/LICENSE) 6 | ![status](https://img.shields.io/badge/status-alpha-lightgray.svg) 7 | 8 | ExtJs applications testing framework which simulates user actions. 9 | 10 | [Online demo](http://antonfisher.com/demo/mocha-extjs/) 11 | 12 | ![Demo](https://raw.githubusercontent.com/antonfisher/node-mocha-extjs/docs/images/mocha-extjs-v1.gif) 13 | 14 | Component search by _title_, _fieldLabel_, _reference_, _boxLabel_, _xtype_, _text_ properties: 15 | 16 | ```javascript 17 | // click on "Save" button 18 | eTT().button('Save').click(done); 19 | 20 | // select first item in the combobox with "Country" fieldLabel. 21 | eTT().combobox('Country').select(1, done); 22 | ``` 23 | 24 | ## Getting Started: 25 | 26 | Update _index.html_: 27 | 28 | ```html 29 | 30 | ... 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 65 | 66 | ``` 67 | Done. Run your application! 68 | 69 | ## PhantomJs 70 | 71 | It works now, but some hack is needed. 72 | First of all you will need _PhantonJs_ version 2 and `mocha-phantomjs` library. 73 | After `mocha-phantomjs` installation, upgrade one of its dependency to the latest version: 74 | 75 | ```bash 76 | $ npm install mocha-phantomjs@4.0.2 mocha-phantomjs-core@2.0.1 phantomjs-prebuilt@2.1.7 77 | $ rm -rf ./node_modules/mocha-phantomjs/node_modules/mocha-phantomjs-core 78 | 79 | # check PhantonJs version, should be like this: 80 | $ ./node_modules/.bin/phantomjs --version 81 | 2.1.1 82 | ``` 83 | 84 | Run tests in console: 85 | 86 | ```bash 87 | # http://localhost:3000 - application address 88 | $ ./node_modules/.bin/mocha-phantomjs --timeout 15000 --path ./node_modules/.bin/phantomjs --setting disk-cache=false --view 1024x768 http://localhost:3000 89 | ``` 90 | 91 | Library's self test with _PhantonJs_: 92 | 93 | ```bash 94 | $ npm test 95 | ``` 96 | 97 | ## Usage 98 | 99 | ### Init the library before running MochaJs 100 | 101 | ```javascript 102 | var eTT = new MochaExtJs(); // init testing framework 103 | ``` 104 | 105 | ### Add test suite: 106 | 107 | ```javascript 108 | // tests/suites/020-buttons.js 109 | describe('Buttons', function () { 110 | this.bail(true); // exit when first test fails 111 | this.timeout(20 * 1000); // necessary timeout for ui operations 112 | 113 | it('Switch to "Buttons" tab', function (done) { // done - async tests callback 114 | eTT().tab('Buttons').click(done); 115 | }); 116 | 117 | it('Click "Simple button" button', function (done) { 118 | eTT().button('Simple button').isEnabled().click(done); 119 | }); 120 | }); 121 | ``` 122 | 123 | ### Supported components and methods: 124 | 125 | ``` 126 | var eTT = new MochaExtJs(); 127 | 128 | eTT() -->--->|------->--->|- button ---> (|- '%title%' )----. 129 | | | | |- window |- '%fieldLabel%' | 130 | | |- no --' |- numberfield |- '%reference%' | 131 | | | |- textfield |- '%boxLabel%' | 132 | | | |- checkbox |- '%xtype%' | 133 | | | |- combobox `- '%text%' | 134 | | | |- dataview | 135 | | | |- radio | 136 | | | |- grid .----------------------x----------------------. 137 | | | `- tab | | 138 | | | |-->|- click -------> (...) ------------------v 139 | | | | |- isEnabled | 140 | | |- waitLoadMask() ------. | |- isDisabled | 141 | | | | | |- isHidden | 142 | | `- waitText('%text%')---v | |- isVisible | 143 | | | | |- select | 144 | | | | |- checkRowsCount | 145 | | | | |- clickAction | 146 | | | | |- edit | 147 | | | | `- fill | 148 | | | | | 149 | | | `--> cellEditor() --->|- select ---> (...) ---v 150 | | | |- click | 151 | | | `- fill | 152 | | | | 153 | x----------------------------<-------------------------------------------------' 154 | | 155 | | 156 | `--> done. 157 | ``` 158 | 159 | Examples: 160 | 161 | ```javascript 162 | eTT().button('Simple button').isEnabled().click(done); 163 | eTT().button('Hide me').click().isHidden(done); 164 | eTT().tab('Windows').click(done); 165 | eTT().window('Confirm').button('Yes').isEnabled().click(done); 166 | eTT().no.window('Confirm', done); 167 | eTT().textfield('Name').fill('my text', done); 168 | eTT().numberfield('Count').fill(13, done); 169 | eTT().checkbox('include').click(done); 170 | eTT().radio('check B').click(done); 171 | eTT().combobox('Select in list').select(1, done); 172 | eTT().grid('Names').select(1, 1, done); 173 | eTT().grid('Names').checkRowsCount(2, done); 174 | eTT().grid('Names').clickAction(0, 2, 1, done); // row, coll, action index 175 | eTT().grid('Cell editing').cellEditor(1, 0).select(0, done); 176 | eTT().grid('Cell editing').cellEditor(0, 2).fill('test1', done); 177 | eTT().grid('Cell editing').cellEditor(0, 3).click(done); 178 | eTT().grid('customDataviewReference').select(1, done); 179 | eTT().waitLoadMask(done); 180 | eTT().waitText('Result is here!', done); 181 | ``` 182 | 183 | ### Taking screenshots 184 | 185 | ```javascript 186 | MochaExtJs.screenshot(); 187 | MochaExtJs.screenshot('./mypath/'); 188 | ``` 189 | 190 | ## Installation 191 | 192 | - `$ npm install mocha-extjs` 193 | - use files from `./dist` folder. 194 | 195 | ## Development 196 | 197 | - install _NodeJs v5.10.1_ or newer 198 | - clone repository `$ git clone https://github.com/antonfisher/node-mocha-extjs.git` 199 | - copy _ExtJs v5_ or _v6_ framework to `./test/sandbox/ext` folder 200 | - build _Sandbox_ application 201 | ```bash 202 | $ cd ./node-mocha-extjs/test/sandbox 203 | $ sencha app build 204 | ``` 205 | - install dependencies `$ npm install` 206 | - run _lint_: `$ npm run lint` 207 | - run _gulp_: `$ npm start`. 208 | 209 | ## Contributing 210 | 211 | Please take care to maintain the existing coding style, tests for any changed functionality. 212 | `npm test` and `npm run lint` your code. 213 | Push your changes without `./dist/mocha-extjs.*` files, to keep commits cleaner between library releases. 214 | Thank you! 215 | 216 | ## Releases History 217 | 218 | * 0.2.0 New grid method - clickAction 219 | * 0.1.7 Move to _PhantomJs v2_, _ExtJs v6_, add _DataView_ support (thanks [@vadimpopa](https://github.com/antonfisher/node-mocha-extjs/pull/1)) 220 | * 0.1.6 _CellEditing_ plugin support in _PhantomJs_ 221 | * 0.1.5 Update click method, minor fixes 222 | * 0.1.4 New grid cell editor methods 223 | * 0.1.3 Fix previous release trouble 224 | * 0.1.2 Update documentation 225 | * ES2015 226 | * standardjs 227 | * grid select rows and cells 228 | * 0.1.1 Update documentation 229 | * 0.1.0 Initial Alpha release 230 | 231 | ## ToDo 232 | 233 | - [x] update Mocha UI style 234 | - [x] Self tests 235 | - [ ] Migrate to WebPack 236 | - [ ] Use Sencha test env 237 | - [ ] New components 238 | - [ ] Documentation 239 | 240 | ## License 241 | 242 | Copyright (c) 2016 Anton Fisher 243 | 244 | MIT License. Free use and change. 245 | -------------------------------------------------------------------------------- /dist/mocha-extjs.css: -------------------------------------------------------------------------------- 1 | #mocha { 2 | top: 0; 3 | right: 0; 4 | margin: 0; 5 | height: 100%; 6 | opacity: 0.87; 7 | overflow: auto; 8 | z-index: 100000; 9 | min-width: 300px; 10 | background: #FFF; 11 | position: absolute; 12 | padding-right: 15px; 13 | border-left: 1px solid #f0f0f0; } 14 | #mocha #mocha-stats { 15 | padding: 5px 10px 0 5px; 16 | border: 1px dashed #cccccc; } 17 | #mocha #mocha-report { 18 | height: 100%; 19 | padding: 60px 0 0 0; } 20 | #mocha #mocha-report li.suite:last-child { 21 | padding-bottom: 25px; } 22 | #mocha .test pre.error { 23 | font-size: 10px; 24 | max-width: 500px; 25 | box-shadow: none; 26 | border-radius: 0; 27 | line-height: 11px; } 28 | #mocha .test.pass.slow .duration { 29 | background: none; 30 | color: #b94a48; 31 | border: 1px solid #b94a48; } 32 | #mocha .test.pass.medium .duration { 33 | background: none; 34 | color: #c09853; 35 | border: 1px solid #c09853; } 36 | 37 | #mocha-error { 38 | top: 50px; 39 | left: 50px; 40 | opacity: 0.9; 41 | padding: 20px; 42 | color: #ff6666; 43 | z-index: 100000; 44 | font-size: 16px; 45 | position: absolute; 46 | background: #ffdddd; 47 | border: 5px solid #ff6666; } 48 | 49 | /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9jaGEtZXh0anMuY3NzIiwic291cmNlcyI6WyJtb2NoYS1leHRqcy5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIiRjb2xvckVycm9yOiAjYjk0YTQ4O1xuJGNvbG9yV2FybmluZzogI2MwOTg1MztcblxuI21vY2hhIHtcbiAgICB0b3A6IDA7XG4gICAgcmlnaHQ6IDA7XG4gICAgbWFyZ2luOiAwO1xuICAgIGhlaWdodDogMTAwJTtcbiAgICBvcGFjaXR5OiAwLjg3O1xuICAgIG92ZXJmbG93OiBhdXRvO1xuICAgIHotaW5kZXg6IDEwMDAwMDtcbiAgICBtaW4td2lkdGg6IDMwMHB4O1xuICAgIGJhY2tncm91bmQ6ICNGRkY7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHBhZGRpbmctcmlnaHQ6IDE1cHg7XG4gICAgYm9yZGVyLWxlZnQ6IDFweCBzb2xpZCAjZjBmMGYwO1xuXG4gICAgI21vY2hhLXN0YXRzIHtcbiAgICAgICAgcGFkZGluZzogNXB4IDEwcHggMCA1cHg7XG4gICAgICAgIGJvcmRlcjogMXB4IGRhc2hlZCAjY2NjY2NjO1xuICAgIH1cblxuICAgICNtb2NoYS1yZXBvcnQge1xuICAgICAgICBoZWlnaHQ6IDEwMCU7XG4gICAgICAgIHBhZGRpbmc6IDYwcHggMCAwIDA7XG5cbiAgICAgICAgbGkuc3VpdGU6bGFzdC1jaGlsZCB7XG4gICAgICAgICAgICBwYWRkaW5nLWJvdHRvbTogMjVweDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC50ZXN0IHByZS5lcnJvciB7XG4gICAgICAgIGZvbnQtc2l6ZTogMTBweDtcbiAgICAgICAgbWF4LXdpZHRoOiA1MDBweDtcbiAgICAgICAgYm94LXNoYWRvdzogbm9uZTtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogMDtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDExcHg7XG4gICAgfVxuXG4gICAgLnRlc3QucGFzcy5zbG93IC5kdXJhdGlvbiB7XG4gICAgICAgIGJhY2tncm91bmQ6IG5vbmU7XG4gICAgICAgIGNvbG9yOiAkY29sb3JFcnJvcjtcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgJGNvbG9yRXJyb3I7XG4gICAgfVxuICAgIC50ZXN0LnBhc3MubWVkaXVtIC5kdXJhdGlvbiB7XG4gICAgICAgIGJhY2tncm91bmQ6IG5vbmU7XG4gICAgICAgIGNvbG9yOiAkY29sb3JXYXJuaW5nO1xuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAkY29sb3JXYXJuaW5nO1xuICAgIH1cbn1cblxuI21vY2hhLWVycm9yIHtcbiAgICB0b3A6IDUwcHg7XG4gICAgbGVmdDogNTBweDtcbiAgICBvcGFjaXR5OiAwLjk7XG4gICAgcGFkZGluZzogMjBweDtcbiAgICBjb2xvcjogI2ZmNjY2NjtcbiAgICB6LWluZGV4OiAxMDAwMDA7XG4gICAgZm9udC1zaXplOiAxNnB4O1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBiYWNrZ3JvdW5kOiAjZmZkZGRkO1xuICAgIGJvcmRlcjogNXB4IHNvbGlkICNmZjY2NjY7XG59XG4iXSwibWFwcGluZ3MiOiJBQUdBLEFBQUEsTUFBTSxDQUFDO0VBQ0gsR0FBRyxFQUFFLENBQUU7RUFDUCxLQUFLLEVBQUUsQ0FBRTtFQUNULE1BQU0sRUFBRSxDQUFFO0VBQ1YsTUFBTSxFQUFFLElBQUs7RUFDYixPQUFPLEVBQUUsSUFBSztFQUNkLFFBQVEsRUFBRSxJQUFLO0VBQ2YsT0FBTyxFQUFFLE1BQU87RUFDaEIsU0FBUyxFQUFFLEtBQU07RUFDakIsVUFBVSxFQUFFLElBQUs7RUFDakIsUUFBUSxFQUFFLFFBQVM7RUFDbkIsYUFBYSxFQUFFLElBQUs7RUFDcEIsV0FBVyxFQUFFLGlCQUFrQixHQWtDbEM7RUE5Q0QsQUFjSSxNQWRFLENBY0YsWUFBWSxDQUFDO0lBQ1QsT0FBTyxFQUFFLGNBQWU7SUFDeEIsTUFBTSxFQUFFLGtCQUFtQixHQUM5QjtFQWpCTCxBQW1CSSxNQW5CRSxDQW1CRixhQUFhLENBQUM7SUFDVixNQUFNLEVBQUUsSUFBSztJQUNiLE9BQU8sRUFBRSxVQUFXLEdBS3ZCO0lBMUJMLEFBdUJnQixNQXZCVixDQW1CRixhQUFhLENBSVQsRUFBRSxBQUFBLE1BQU0sQUFBQSxXQUFXLENBQUM7TUFDaEIsY0FBYyxFQUFFLElBQUssR0FDeEI7RUF6QlQsQUE0QmEsTUE1QlAsQ0E0QkYsS0FBSyxDQUFDLEdBQUcsQUFBQSxNQUFNLENBQUM7SUFDWixTQUFTLEVBQUUsSUFBSztJQUNoQixTQUFTLEVBQUUsS0FBTTtJQUNqQixVQUFVLEVBQUUsSUFBSztJQUNqQixhQUFhLEVBQUUsQ0FBRTtJQUNqQixXQUFXLEVBQUUsSUFBSyxHQUNyQjtFQWxDTCxBQW9Db0IsTUFwQ2QsQ0FvQ0YsS0FBSyxBQUFBLEtBQUssQUFBQSxLQUFLLENBQUMsU0FBUyxDQUFDO0lBQ3RCLFVBQVUsRUFBRSxJQUFLO0lBQ2pCLEtBQUssRUF6Q0EsT0FBTztJQTBDWixNQUFNLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0ExQ1osT0FBTyxHQTJDZjtFQXhDTCxBQXlDc0IsTUF6Q2hCLENBeUNGLEtBQUssQUFBQSxLQUFLLEFBQUEsT0FBTyxDQUFDLFNBQVMsQ0FBQztJQUN4QixVQUFVLEVBQUUsSUFBSztJQUNqQixLQUFLLEVBN0NFLE9BQU87SUE4Q2QsTUFBTSxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBOUNWLE9BQU8sR0ErQ2pCOztBQUdMLEFBQUEsWUFBWSxDQUFDO0VBQ1QsR0FBRyxFQUFFLElBQUs7RUFDVixJQUFJLEVBQUUsSUFBSztFQUNYLE9BQU8sRUFBRSxHQUFJO0VBQ2IsT0FBTyxFQUFFLElBQUs7RUFDZCxLQUFLLEVBQUUsT0FBUTtFQUNmLE9BQU8sRUFBRSxNQUFPO0VBQ2hCLFNBQVMsRUFBRSxJQUFLO0VBQ2hCLFFBQVEsRUFBRSxRQUFTO0VBQ25CLFVBQVUsRUFBRSxPQUFRO0VBQ3BCLE1BQU0sRUFBRSxpQkFBa0IsR0FDN0IiLCJuYW1lcyI6W119 */ 50 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var gulp = require('gulp') 4 | var sass = require('gulp-sass') 5 | var webpack = require('webpack-stream') 6 | var sourcemaps = require('gulp-sourcemaps') 7 | var browserSync = require('browser-sync').create() 8 | 9 | gulp.task('css', () => { 10 | return gulp 11 | .src('./scss/**/*.scss') 12 | .pipe(sourcemaps.init()) 13 | .pipe(sass().on('error', sass.logError)) 14 | .pipe(sourcemaps.write()) 15 | .pipe(gulp.dest('./dist')) 16 | }) 17 | 18 | gulp.task('js', () => { 19 | return gulp 20 | .src('./mocha-extjs.js') 21 | .pipe(webpack({ 22 | resolveLoader: { 23 | root: './' 24 | }, 25 | module: { 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | query: { 31 | presets: ['es2015'] 32 | } 33 | }] 34 | }, 35 | output: { 36 | filename: 'mocha-extjs.js' 37 | } 38 | })) 39 | .pipe(gulp.dest('./dist/')) 40 | }) 41 | 42 | gulp.task('default', ['css', 'js'], () => { 43 | browserSync.init({ 44 | server: { 45 | baseDir: ['./test/sandbox', './'] 46 | } 47 | }) 48 | 49 | gulp.watch(['./mocha-extjs.js', './src/**/*', './test/suites/**/*', './test/sandbox/app/**/*'], ['js']) 50 | gulp.watch('./scss/*.scss', ['css']) 51 | gulp.watch(['./dist/*'], browserSync.reload) 52 | }) 53 | -------------------------------------------------------------------------------- /mocha-extjs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import 'babel-polyfill' 4 | 5 | import {Chain} from './src/chain.js' 6 | import {MochaUI} from './src/mochaUI.js' 7 | import {ExtJsDriver} from './src/drivers/extjs/driver.js' 8 | 9 | export class MochaExtJs { 10 | 11 | constructor ({driver} = {driver: new ExtJsDriver({mochaUi: new MochaUI()})}) { 12 | return function () { 13 | return new Chain({driver}) 14 | } 15 | } 16 | 17 | static screenshot (path = '/tmp/') { 18 | if (window.callPhantom) { 19 | const filename = (path + (new Date()).getTime()) 20 | console.log('Taking screenshot: ' + filename) 21 | window.callPhantom({'screenshot': filename}) 22 | } 23 | } 24 | 25 | } 26 | 27 | // browserify 28 | if (window) { 29 | window.MochaExtJs = MochaExtJs 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mocha-extjs", 3 | "version": "0.2.0", 4 | "description": "ExtJs Test Framework for Mocha", 5 | "main": "mocha-extjs.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "start": "./node_modules/.bin/gulp", 11 | "test": "npm run clear-phantomjs-cache && ./node_modules/.bin/mocha-phantomjs --timeout 15000 --path ./node_modules/.bin/phantomjs --setting disk-cache=false --view 1024x768 http://localhost:3000", 12 | "test-remote": "npm run clear-phantomjs-cache && ./node_modules/.bin/mocha-phantomjs --timeout 15000 --path ./node_modules/.bin/phantomjs --setting disk-cache=false --view 1024x768 http://antonfisher.com/demo/mocha-extjs/", 13 | "lint": "./node_modules/.bin/standard 'gulpfile.js' 'mocha-extjs.js' './src/**/*.js' './test/suites/**/*.js' './test/sandbox/app/**/*.js' | ./node_modules/.bin/snazzy", 14 | "copy-demo": "./scripts/copy-demo.sh", 15 | "fix-deps": "rm -rf ./node_modules/mocha-phantomjs/node_modules/mocha-phantomjs-core", 16 | "clear-phantomjs-cache": "rm -rf ~/.qws/share/data/Ofi\\ Labs/PhantomJS ~/.local/share/Ofi\\ Labs/PhantomJS", 17 | "postinstall": "npm run fix-deps" 18 | }, 19 | "standard": { 20 | "globals": [ 21 | "describe", 22 | "it", 23 | "expect", 24 | "eTT", 25 | "Ext", 26 | "Sandbox" 27 | ] 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/antonfisher/node-mocha-extjs.git" 32 | }, 33 | "keywords": [ 34 | "extjs", 35 | "sencha", 36 | "mocha", 37 | "test framework" 38 | ], 39 | "author": "Anton Fisher (http://antonfisher.com)", 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/antonfisher/node-mocha-extjs/issues" 43 | }, 44 | "homepage": "https://github.com/antonfisher/node-mocha-extjs", 45 | "devDependencies": { 46 | "babel-core": "6.x", 47 | "babel-loader": "6.x", 48 | "babel-polyfill": "6.13.0", 49 | "babel-preset-es2015": "6.x", 50 | "browser-sync": "2.x", 51 | "gulp": "3.x", 52 | "gulp-sass": "2.x", 53 | "gulp-sourcemaps": "1.x", 54 | "mocha-phantomjs": "4.0.2", 55 | "mocha-phantomjs-core": "2.0.1", 56 | "phantomjs-prebuilt": "2.1.12", 57 | "snazzy": "5.0.0", 58 | "standard": "8.1.0", 59 | "webpack-stream": "3.x" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /scripts/copy-demo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DEMO_DEST="../antonfisher.github.io/demo/mocha-extjs"; 4 | 5 | cd test/sandbox/ \ 6 | && sencha app build \ 7 | && cd - \ 8 | && mkdir -p ./"${DEMO_DEST}" \ 9 | && rm -rf ./"${DEMO_DEST}"/* \ 10 | && cp -r ./test/sandbox/build/production/Sandbox/* ./"${DEMO_DEST}"/ \ 11 | && mkdir -p ./"${DEMO_DEST}"/test/ \ 12 | && cp -r test/suites/ ./"${DEMO_DEST}"/test; 13 | exit_code="${?}"; 14 | 15 | if [[ "${exit_code}" == 0 ]]; then 16 | cd ./"${DEMO_DEST}"; 17 | python -m SimpleHTTPServer 3333; 18 | fi; 19 | 20 | exit "${exit_code}"; 21 | -------------------------------------------------------------------------------- /scss/mocha-extjs.scss: -------------------------------------------------------------------------------- 1 | $colorError: #b94a48; 2 | $colorWarning: #c09853; 3 | 4 | #mocha { 5 | top: 0; 6 | right: 0; 7 | margin: 0; 8 | height: 100%; 9 | opacity: 0.87; 10 | overflow: auto; 11 | z-index: 100000; 12 | min-width: 300px; 13 | background: #FFF; 14 | position: absolute; 15 | padding-right: 15px; 16 | border-left: 1px solid #f0f0f0; 17 | 18 | #mocha-stats { 19 | padding: 5px 10px 0 5px; 20 | border: 1px dashed #cccccc; 21 | } 22 | 23 | #mocha-report { 24 | height: 100%; 25 | padding: 60px 0 0 0; 26 | 27 | li.suite:last-child { 28 | padding-bottom: 25px; 29 | } 30 | } 31 | 32 | .test pre.error { 33 | font-size: 10px; 34 | max-width: 500px; 35 | box-shadow: none; 36 | border-radius: 0; 37 | line-height: 11px; 38 | } 39 | 40 | .test.pass.slow .duration { 41 | background: none; 42 | color: $colorError; 43 | border: 1px solid $colorError; 44 | } 45 | .test.pass.medium .duration { 46 | background: none; 47 | color: $colorWarning; 48 | border: 1px solid $colorWarning; 49 | } 50 | } 51 | 52 | #mocha-error { 53 | top: 50px; 54 | left: 50px; 55 | opacity: 0.9; 56 | padding: 20px; 57 | color: #ff6666; 58 | z-index: 100000; 59 | font-size: 16px; 60 | position: absolute; 61 | background: #ffdddd; 62 | border: 5px solid #ff6666; 63 | } 64 | -------------------------------------------------------------------------------- /src/chain.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {Set} from './utils/set.js' 4 | import {ChainActionItem} from './chain/actionItem.js' 5 | import {ChainComponentItem} from './chain/componentItem.js' 6 | import {ChainComponentActionItem} from './chain/componentActionItem.js' 7 | 8 | export class Chain { 9 | 10 | constructor ({driver, itemsRunDelay = 50}) { 11 | this._itemsSet = new Set() 12 | 13 | this._chainRunned = false 14 | this._chainCallback = () => { 15 | throw new Error('Chain callback is not presented.') 16 | } 17 | 18 | this.driver = driver 19 | this.itemsRunDelay = itemsRunDelay 20 | this.no = {} 21 | 22 | // entrance actions 23 | 24 | for (let component of driver.supportedComponents) { 25 | this[component] = this.createActionFunction(component) 26 | this.no[component] = this.createActionFunction(component, true) 27 | } 28 | 29 | for (let action of driver.supportedComponentActions) { 30 | this[action] = this.createActionFunction(action) 31 | } 32 | 33 | for (let action of driver.supportedActions) { 34 | this[action] = this.createActionFunction(action) 35 | } 36 | 37 | return this 38 | } 39 | 40 | createActionFunction (actionType, invert) { 41 | return (...args) => { 42 | if (this._chainRunned) { 43 | throw new Error('Cannot add an action after the action which calls Mocha test callback.') 44 | } 45 | 46 | let actionArgs = [] 47 | for (let arg of args) { 48 | if (typeof arg === 'function') { 49 | this._chainRunned = true 50 | this._chainCallback = arg 51 | break 52 | } 53 | actionArgs.push(arg) 54 | } 55 | 56 | const chainProperties = { 57 | type: actionType, 58 | chain: this, 59 | invert: invert, 60 | callArgs: actionArgs 61 | } 62 | 63 | if (this.driver.supportedComponents.includes(actionType)) { 64 | this._itemsSet.push(new ChainComponentItem(chainProperties)) 65 | } else if (this.driver.supportedComponentActions.includes(actionType)) { 66 | this._itemsSet.push(new ChainComponentActionItem(chainProperties)) 67 | } else if (this.driver.supportedActions.includes(actionType)) { 68 | this._itemsSet.push(new ChainActionItem(chainProperties)) 69 | } 70 | 71 | if (this._chainRunned) { 72 | this.run() 73 | } 74 | 75 | return this 76 | } 77 | } 78 | 79 | run () { 80 | const itemsGenerator = this._itemsSet.items() 81 | 82 | const runNextAction = () => { 83 | const item = itemsGenerator.next() 84 | 85 | if (item.done) { 86 | return this._chainCallback(null) 87 | } else { 88 | return item.value.run((err) => { 89 | if (err) { 90 | return this._chainCallback(err) 91 | } 92 | 93 | setTimeout(() => { 94 | runNextAction() 95 | }, this.itemsRunDelay) 96 | }) 97 | } 98 | } 99 | 100 | runNextAction() 101 | } 102 | 103 | get lastComponent () { 104 | for (let item of this._itemsSet.reversedItems()) { 105 | if (item.component) { 106 | return item.component 107 | } 108 | } 109 | 110 | return null 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/chain/actionItem.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ChainItem} from './item.js' 4 | import {waitForFn} from '../utils/utils.js' 5 | 6 | export class ChainActionItem extends ChainItem { 7 | 8 | run (callback) { 9 | return waitForFn( 10 | (done) => { 11 | this.chain.driver[this.type](done, ...this.callArgs) 12 | }, 13 | callback 14 | ) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/chain/componentActionItem.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ChainItem} from './item.js' 4 | import {waitForFn} from '../utils/utils.js' 5 | 6 | export class ChainComponentActionItem extends ChainItem { 7 | 8 | run (callback) { 9 | const lastComponent = this.chain.lastComponent 10 | 11 | if (!lastComponent) { 12 | return callback(`No "${this.type}" action target.`) 13 | } 14 | 15 | const action = lastComponent[this.type] 16 | 17 | if (!action) { 18 | return callback( 19 | `Component "${lastComponent.constructor.name.replace(/.*Component/, '').toLowerCase()}" ` + 20 | `does not support action "${this.type}".` 21 | ) 22 | } 23 | 24 | return waitForFn( 25 | (done) => { 26 | lastComponent[this.type](done, ...this.callArgs) 27 | }, 28 | callback 29 | ) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/chain/componentItem.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ChainItem} from './item.js' 4 | import {waitForFn} from '../utils/utils.js' 5 | 6 | export class ChainComponentItem extends ChainItem { 7 | 8 | constructor (...args) { 9 | super(...args) 10 | 11 | this.component = null 12 | } 13 | 14 | run (callback) { 15 | const type = this.type 16 | const chain = this.chain 17 | const callArgs = this.callArgs 18 | 19 | return waitForFn( 20 | (done) => { 21 | this.chain.driver.getComponent( 22 | (err, result) => { 23 | if (this.invert) { 24 | return done(err ? null : `Component ${this.type} "${this.callArgs[0]}" still presented.`) 25 | } else { 26 | return done(err, result) 27 | } 28 | }, 29 | {type, callArgs, chain} 30 | ) 31 | }, 32 | (err, component) => { 33 | this.component = component 34 | return callback(err) 35 | } 36 | ) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/chain/item.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | export class ChainItem { 4 | 5 | constructor ({chain, type, invert = false, callArgs = []}) { 6 | if (!chain) { 7 | throw new Error(`Class ${this.constructor.name} created with undefined property "chain".`) 8 | } 9 | 10 | if (!type) { 11 | throw new Error(`Class ${this.constructor.name} created with undefined property "type".`) 12 | } 13 | 14 | this.type = type 15 | this.chain = chain 16 | this.invert = invert 17 | this.callArgs = callArgs 18 | } 19 | 20 | run () { 21 | console.error(`called on implemented method: ${this.constructor.name}.run()`) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/base.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {HTMLComponentBase} from '../../html/components/base.js' 4 | 5 | export class ExtJsComponentBase { 6 | 7 | constructor ({driver, chain}) { 8 | this.chain = chain 9 | this.driver = driver 10 | this.selectors = [] 11 | 12 | this._htmlComponent = null 13 | } 14 | 15 | get htmlComponent () { 16 | if (!this._htmlComponent && this.extJsComponent) { 17 | let htmlElement = null 18 | 19 | if (this.extJsComponent.inputEl) { 20 | htmlElement = this.extJsComponent.inputEl.dom 21 | } else if (this.extJsComponent.el) { 22 | htmlElement = this.extJsComponent.el.dom 23 | } 24 | 25 | if (htmlElement) { 26 | this._htmlComponent = new HTMLComponentBase({ 27 | driver: this.driver, 28 | htmlElement 29 | }) 30 | } 31 | } 32 | 33 | return this._htmlComponent 34 | } 35 | 36 | get componentType () { 37 | return (this.constructor.name.replace(/.*Component/, '').toLowerCase()) 38 | } 39 | 40 | get titleProperties () { 41 | return ['tooltip', 'xtype'] 42 | } 43 | 44 | generateSelectors (titleOrSelector) { 45 | return [ 46 | `${this.componentType}[tooltip~="${titleOrSelector}"]`, 47 | `${this.componentType}[reference="${titleOrSelector}"]`, 48 | `${this.componentType}[xtype="${titleOrSelector}"]` 49 | ] 50 | } 51 | 52 | getComponent (callback, {callArgs}) { 53 | let selectors = [] 54 | let extJsComponent = null 55 | const titleOrSelector = callArgs[0] 56 | 57 | if (titleOrSelector[0] === '#') { 58 | selectors = [titleOrSelector] 59 | } else { 60 | selectors = this.generateSelectors(titleOrSelector) 61 | } 62 | 63 | selectors.every((item) => { 64 | extJsComponent = this.getVisibleComponents(item)[0] 65 | return !extJsComponent 66 | }) 67 | 68 | if (!extJsComponent) { 69 | (Ext.ComponentQuery.query(this.componentType) || []).every((item) => { 70 | this.titleProperties.every((prop) => { 71 | let title = item[prop] 72 | const fnName = `get${prop[0].toUpperCase()}${prop.slice(1)}` 73 | if (fnName && item[fnName] && typeof item[fnName] === 'function') { 74 | title = item[fnName]() 75 | } 76 | if ((new RegExp(titleOrSelector, 'g')).test(title)) { 77 | extJsComponent = item 78 | } 79 | return !extJsComponent 80 | }) 81 | return !extJsComponent 82 | }) 83 | } 84 | 85 | if (!extJsComponent) { 86 | return callback(new Error(`Selector "${selectors.join(', ')}" not found.`)) 87 | } else if (!extJsComponent.el || !extJsComponent.el.dom) { 88 | return callback(new Error(`No existing HTML element for selector "${selectors.join(', ')}".`)) 89 | } 90 | 91 | // TODO to method 92 | const rect = extJsComponent.el.dom.getBoundingClientRect() 93 | if (rect.left + rect.width < 0 || rect.top + rect.height < 0) { 94 | return callback(new Error( 95 | `No visible HTML element for selector "${selectors.join(', ')}", ` + 96 | `offset: ${rect.left},${rect.top}, size: ${rect.width},${rect.height}.` 97 | )) 98 | } 99 | 100 | this.selectors = selectors 101 | this.extJsComponent = extJsComponent 102 | 103 | return callback(null, this) 104 | } 105 | 106 | // BUG does not work properly 107 | getVisibleComponents (selector) { 108 | try { 109 | return Ext.ComponentQuery.query(selector).filter((item) => { 110 | if (!item.el || !item.el.dom) { 111 | return false 112 | } 113 | 114 | const r = item.el.dom.getBoundingClientRect() 115 | const x = (r.left + r.width / 2) 116 | const y = (r.top + r.height / 2) 117 | 118 | if (!window.document.elementsFromPoint) { 119 | return true 120 | } 121 | 122 | // this.mochaUi.hide() 123 | this.driver.mochaUi.hide() 124 | const visible = (window.document.elementsFromPoint(x, y) || []).filter((dom) => { 125 | return (dom === item.el.dom) 126 | }) 127 | // this.mochaUi.show() 128 | this.driver.mochaUi.show() 129 | 130 | return (visible.length > 0) 131 | }) 132 | } catch (e) { 133 | throw new Error(`${e}. Selector: ${selector}`) 134 | } 135 | } 136 | 137 | click (callback) { 138 | this.htmlComponent.click((err) => { 139 | if (err) { 140 | return callback(`cannot click on component "${this.componentType}": ${err}`) 141 | } else { 142 | return callback(null) 143 | } 144 | }) 145 | } 146 | 147 | fill (callback, value) { 148 | this.click((err) => { 149 | if (!err) { 150 | try { 151 | this.extJsComponent.setValue(value) 152 | err = false 153 | } catch (e) { 154 | err = 'failed to call setValue() method' 155 | } 156 | } 157 | 158 | return callback(err ? new Error(`cannot fill component "${this.componentType}": ${err}`) : null) 159 | }) 160 | } 161 | 162 | checkState ({stateFnName, expectedValue, callback}) { 163 | if (!this.extJsComponent[stateFnName]) { 164 | return callback(new Error(`ExtJs component does not have function "${stateFnName}".`)) 165 | } 166 | 167 | const result = this.extJsComponent[stateFnName]() 168 | 169 | if (result === expectedValue) { 170 | return callback(null) 171 | } else { 172 | return callback(new Error( 173 | `state of "${this.componentType}" function "${stateFnName}" expected to be "${expectedValue}" ` + 174 | `instead of "${result}"` 175 | )) 176 | } 177 | } 178 | 179 | isEnabled (callback) { 180 | return this.checkState({ 181 | stateFnName: 'isDisabled', 182 | expectedValue: false, 183 | callback: callback 184 | }) 185 | } 186 | 187 | isDisabled (callback) { 188 | return this.checkState({ 189 | stateFnName: 'isDisabled', 190 | expectedValue: true, 191 | callback: callback 192 | }) 193 | } 194 | 195 | isVisible (callback) { 196 | return this.checkState({ 197 | stateFnName: 'isHidden', 198 | expectedValue: false, 199 | callback: callback 200 | }) 201 | } 202 | 203 | isHidden (callback) { 204 | return this.checkState({ 205 | stateFnName: 'isHidden', 206 | expectedValue: true, 207 | callback: callback 208 | }) 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/button.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentButton extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['text', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[text~="${titleOrSelector}"]`, 14 | ...super.generateSelectors(titleOrSelector) 15 | ] 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/cellEditor.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {HTMLComponentBase} from '../../html/components/base.js' 4 | import {ExtJsComponentBase} from './base.js' 5 | 6 | export class ExtJsComponentCellEditor extends ExtJsComponentBase { 7 | 8 | getComponent (callback, {callArgs}) { 9 | const rowIndex = callArgs[0] 10 | const colIndex = callArgs[1] 11 | const cmp = this.chain.lastComponent.extJsComponent 12 | let htmlElement = null 13 | 14 | try { 15 | htmlElement = document 16 | .getElementById(cmp.el.id) 17 | .getElementsByClassName('x-grid-item')[rowIndex] 18 | .getElementsByClassName('x-grid-cell')[colIndex] 19 | } catch (e) { 20 | return callback(new Error( 21 | `Failed to find cell element of "${this.componentType}" row:#${rowIndex}, col:#${colIndex}`, 22 | e 23 | )) 24 | } 25 | 26 | new HTMLComponentBase({htmlElement, driver: this.driver}).click((err) => { 27 | if (err) { 28 | return callback(new Error( 29 | `Failed to click on cell element of "${this.componentType}" row: #${rowIndex}, col: #${colIndex}: ${err}` 30 | )) 31 | } 32 | 33 | let fieldElement = null 34 | try { 35 | const editorElements = document.getElementById(cmp.el.id).getElementsByClassName('x-editor') 36 | 37 | // "editorElements.item(i)" doesn't work in PhantonJS 38 | for (let i = 0; i < editorElements.length; i++) { 39 | const editorElement = editorElements[i] 40 | if (this.driver.isVisibleElement(editorElement)) { 41 | fieldElement = editorElement.getElementsByClassName('x-field')[0] 42 | break 43 | } 44 | } 45 | 46 | if (!fieldElement) { 47 | throw new Error('no "x-field" element found') 48 | } 49 | } catch (e) { 50 | return callback(new Error( 51 | `Failed to get editor element of "${this.componentType}" row:#${rowIndex}, col:#${colIndex}: ${e}` 52 | )) 53 | } 54 | 55 | this.selectors = `#${fieldElement.id}` 56 | this.extJsComponent = Ext.ComponentQuery.query(this.selectors)[0] 57 | 58 | if (!this.selectors) { 59 | return callback(new Error( 60 | `Failed to get editor component of "${this.componentType}" row:#${rowIndex}, col:#${colIndex}` 61 | )) 62 | } 63 | 64 | return callback(null, this) 65 | }) 66 | } 67 | 68 | select (callback, index = 0) { 69 | this.driver.getComponent( 70 | (err, fieldComponent) => { 71 | if (err) { 72 | return callback(new Error(`Failed to get editor combobox component of "${this.componentType}"`, err)) 73 | } 74 | 75 | fieldComponent.select((err) => { 76 | if (err) { 77 | return callback(new Error(`Failed to select editor combobox of "${this.componentType}"`, err)) 78 | } 79 | 80 | return callback(null) 81 | }, index) 82 | }, 83 | { 84 | type: 'comboBox', 85 | callArgs: [`#${this.extJsComponent.id}`], 86 | chain: this.chain 87 | } 88 | ) 89 | } 90 | 91 | fill (callback, value = '') { 92 | this.driver.getComponent( 93 | (err, fieldComponent) => { 94 | if (err) { 95 | return callback(new Error(`Failed to fill editor textfield component of "${this.componentType}"`, err)) 96 | } 97 | 98 | fieldComponent.fill((err) => { 99 | if (err) { 100 | return callback(new Error(`Failed to fill editor textfield component of "${this.componentType}"`, err)) 101 | } 102 | 103 | return callback(null) 104 | }, value) 105 | }, 106 | { 107 | type: 'textField', 108 | callArgs: [`#${this.extJsComponent.id}`], 109 | chain: this.chain 110 | } 111 | ) 112 | } 113 | 114 | click (callback) { 115 | this.driver.getComponent( 116 | (err, fieldComponent) => { 117 | if (err) { 118 | return callback(new Error(`Failed to click editor checkbox component of "${this.componentType}"`, err)) 119 | } 120 | 121 | fieldComponent.click((err) => { 122 | if (err) { 123 | return callback(new Error(`Failed to click editor checkbox component of "${this.componentType}"`, err)) 124 | } 125 | 126 | return callback(null) 127 | }) 128 | }, 129 | { 130 | type: 'checkBox', 131 | callArgs: [`#${this.extJsComponent.id}`], 132 | chain: this.chain 133 | } 134 | ) 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/checkBox.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentCheckBox extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['fieldLabel', 'boxLabel', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[boxLabel~="${titleOrSelector}"]`, 14 | `${this.componentType}[fieldLabel~="${titleOrSelector}"]`, 15 | ...super.generateSelectors(titleOrSelector) 16 | ] 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/comboBox.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {HTMLComponentBase} from '../../html/components/base.js' 4 | import {ExtJsComponentBase} from './base.js' 5 | 6 | export class ExtJsComponentComboBox extends ExtJsComponentBase { 7 | 8 | get titleProperties () { 9 | return ['fieldLabel', ...super.titleProperties] 10 | } 11 | 12 | generateSelectors (titleOrSelector) { 13 | return [`${this.componentType}[fieldLabel~="${titleOrSelector}"]`, ...super.generateSelectors(titleOrSelector)] 14 | } 15 | 16 | select (callback, index) { 17 | const cmp = this.extJsComponent 18 | 19 | this.click((err) => { 20 | if (err) { 21 | return callback(`cannot select item #${index} in component "${this.componentType}": ${err}`) 22 | } 23 | 24 | // TODO add validation method 25 | if (!cmp || !cmp.picker || !cmp.picker.el || !cmp.picker.el.id) { 26 | return callback(`cannot find picker of component "${this.componentType}"`) 27 | } 28 | 29 | let htmlElement = null 30 | 31 | try { 32 | htmlElement = document 33 | .getElementById(cmp.picker.el.id) 34 | .getElementsByClassName('x-boundlist-item')[index] 35 | } catch (e) { 36 | return callback(`Failed to get element of "${this.componentType}" row #${index}": ${e}`) 37 | } 38 | 39 | new HTMLComponentBase({htmlElement, driver: this.driver}).click((err) => { 40 | return callback(err ? `Failed to click on item #${index} of "${this.componentType}" ": ${err}` : null) 41 | }) 42 | }) 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/dataview.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {HTMLComponentBase} from '../../html/components/base.js' 4 | import {ExtJsComponentBase} from './base.js' 5 | 6 | export class ExtJsComponentDataView extends ExtJsComponentBase { 7 | select (callback, index) { 8 | const cmp = this.extJsComponent 9 | let htmlElement = null 10 | 11 | try { 12 | htmlElement = document 13 | .getElementById(cmp.el.id) 14 | .getElementsByClassName(cmp.itemCls)[index] 15 | } catch (e) { 16 | return callback(`Failed to get element of "${this.componentType}" index #${index}": ${e}`) 17 | } 18 | 19 | new HTMLComponentBase({htmlElement, driver: this.driver}).click((err) => { 20 | return callback(err ? `Failed to click on item index #${index} of "${this.componentType}" ": ${err}` : null) 21 | }) 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/grid.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {HTMLComponentBase} from '../../html/components/base.js' 4 | import {ExtJsComponentBase} from './base.js' 5 | 6 | export class ExtJsComponentGrid extends ExtJsComponentBase { 7 | 8 | get titleProperties () { 9 | return ['title', ...super.titleProperties] 10 | } 11 | 12 | generateSelectors (titleOrSelector) { 13 | return [`${this.componentType}[text~="${titleOrSelector}"]`, ...super.generateSelectors(titleOrSelector)] 14 | } 15 | 16 | select (callback, rowIndex = 0, colIndex = 0) { 17 | const cmp = this.extJsComponent 18 | let htmlElement = null 19 | 20 | try { 21 | htmlElement = document 22 | .getElementById(cmp.el.id) 23 | .getElementsByClassName('x-grid-item')[rowIndex] 24 | .getElementsByClassName('x-grid-cell')[colIndex] 25 | } catch (e) { 26 | return callback(`Failed to get element of "${this.componentType}" row #${rowIndex}": ${e}`) 27 | } 28 | 29 | new HTMLComponentBase({htmlElement, driver: this.driver}).click((err) => { 30 | return callback(err ? `Failed to click on item row #${rowIndex} of "${this.componentType}" ": ${err}` : null) 31 | }) 32 | } 33 | 34 | checkRowsCount (callback, countExpected) { 35 | const cmp = this.extJsComponent 36 | 37 | if (!cmp.getStore || !cmp.getStore()) { 38 | return callback(`No store binded to "${this.componentType}" (${this.selectors}).`) 39 | } 40 | 41 | const count = cmp.getStore().getCount() 42 | 43 | if (count === countExpected) { 44 | return callback(null) 45 | } else { 46 | return callback( 47 | `No store binded to "${this.componentType}" (selectors: ${this.selectors}):` + 48 | ` count of rows expected to be equal "${countExpected}" instead of "${count}".` 49 | ) 50 | } 51 | } 52 | 53 | clickAction (callback, rowIndex = 0, colIndex = 0, actionIndex = 0) { 54 | const cmp = this.extJsComponent 55 | let htmlElement = null 56 | 57 | try { 58 | htmlElement = document 59 | .getElementById(cmp.el.id) 60 | .getElementsByClassName('x-grid-item')[rowIndex] 61 | .getElementsByClassName('x-grid-cell')[colIndex] 62 | .getElementsByClassName('x-action-col-icon')[actionIndex] 63 | } catch (e) { 64 | return callback(`Failed to get element of "${this.componentType}" row #${rowIndex}": ${e}`) 65 | } 66 | 67 | new HTMLComponentBase({htmlElement, driver: this.driver}).click((err) => { 68 | return callback(err ? `Failed to click on action item in row #${rowIndex} of "${this.componentType}" ": ${err}` : null) 69 | }) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/numberField.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentNumberField extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['fieldLabel', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[fieldLabel~="${titleOrSelector}"]`, 14 | ...super.generateSelectors(titleOrSelector) 15 | ] 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/radio.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentRadio extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['fieldLabel', 'boxLabel', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[boxLabel~="${titleOrSelector}"]`, 14 | `${this.componentType}[fieldLabel~="${titleOrSelector}"]`, 15 | ...super.generateSelectors(titleOrSelector) 16 | ] 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/tab.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentTab extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['title', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[title~="${titleOrSelector}"]`, 14 | ...super.generateSelectors(titleOrSelector) 15 | ] 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/textField.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentTextField extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['fieldLabel', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[fieldLabel~="${titleOrSelector}"]`, 14 | ...super.generateSelectors(titleOrSelector) 15 | ] 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/drivers/extjs/components/window.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {ExtJsComponentBase} from './base.js' 4 | 5 | export class ExtJsComponentWindow extends ExtJsComponentBase { 6 | 7 | get titleProperties () { 8 | return ['title', ...super.titleProperties] 9 | } 10 | 11 | generateSelectors (titleOrSelector) { 12 | return [ 13 | `${this.componentType}[text~="${titleOrSelector}"]`, 14 | ...super.generateSelectors(titleOrSelector) 15 | ] 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/drivers/extjs/driver.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {waitForFn} from '../../utils/utils.js' 4 | 5 | import {ExtJsComponentTab} from './components/tab.js' 6 | import {ExtJsComponentGrid} from './components/grid.js' 7 | import {ExtJsComponentDataView} from './components/dataview.js' 8 | import {ExtJsComponentRadio} from './components/radio.js' 9 | import {ExtJsComponentButton} from './components/button.js' 10 | import {ExtJsComponentWindow} from './components/window.js' 11 | import {ExtJsComponentCheckBox} from './components/checkBox.js' 12 | import {ExtJsComponentComboBox} from './components/comboBox.js' 13 | import {ExtJsComponentTextField} from './components/textField.js' 14 | import {ExtJsComponentCellEditor} from './components/cellEditor.js' 15 | import {ExtJsComponentNumberField} from './components/numberField.js' 16 | 17 | export class ExtJsDriver { 18 | 19 | constructor ({mochaUi}) { 20 | if (!mochaUi) { 21 | throw new Error(`Class ${this.constructor.name} created with undefined property "mochaUi".`) 22 | } 23 | 24 | this.mochaUi = mochaUi 25 | } 26 | 27 | get supportedComponents () { 28 | return [ 29 | 'tab', 'grid', 'radio', 'button', 'window', 'checkBox', 'comboBox', 'textField', 'numberField', 30 | 'cellEditor', 'dataview' 31 | ] 32 | } 33 | 34 | get supportedComponentActions () { 35 | return [ 36 | 'click', 'fill', 'select', 'isEnabled', 'isDisabled', 'isHidden', 'isVisible', 'checkRowsCount', 'edit', 'clickAction' 37 | ] 38 | } 39 | 40 | get supportedActions () { 41 | return [ 42 | 'waitText', 'waitLoadMask' 43 | ] 44 | } 45 | 46 | getComponent (callback, {type, callArgs, chain}) { 47 | let componentObject = null 48 | const properties = { 49 | driver: this, 50 | chain: chain 51 | } 52 | 53 | if (type === 'tab') { 54 | componentObject = new ExtJsComponentTab(properties) 55 | } else if (type === 'grid') { 56 | componentObject = new ExtJsComponentGrid(properties) 57 | } else if (type === 'radio') { 58 | componentObject = new ExtJsComponentRadio(properties) 59 | } else if (type === 'button') { 60 | componentObject = new ExtJsComponentButton(properties) 61 | } else if (type === 'window') { 62 | componentObject = new ExtJsComponentWindow(properties) 63 | } else if (type === 'checkBox') { 64 | componentObject = new ExtJsComponentCheckBox(properties) 65 | } else if (type === 'comboBox') { 66 | componentObject = new ExtJsComponentComboBox(properties) 67 | } else if (type === 'textField') { 68 | componentObject = new ExtJsComponentTextField(properties) 69 | } else if (type === 'cellEditor') { 70 | componentObject = new ExtJsComponentCellEditor(properties) 71 | } else if (type === 'numberField') { 72 | componentObject = new ExtJsComponentNumberField(properties) 73 | } else if (type === 'dataview') { 74 | componentObject = new ExtJsComponentDataView(properties) 75 | } 76 | 77 | if (!componentObject) { 78 | return callback(new Error(`Type "${type}" is not supported by driver`)) 79 | } 80 | 81 | return componentObject.getComponent(callback, {callArgs}) 82 | } 83 | 84 | isVisibleElement (element) { 85 | const style = window.getComputedStyle(element) 86 | return ( 87 | Boolean(style) && 88 | (typeof style.opacity === 'undefined' || style.opacity !== 0) && 89 | (typeof style.display === 'undefined' || style.display !== 'none') && 90 | (typeof style.visibility === 'undefined' || style.visibility !== 'hidden') 91 | ) 92 | } 93 | 94 | waitLoadMask (callback) { 95 | return waitForFn( 96 | (done) => { 97 | const maskDisplayed = Ext.ComponentManager.getAll() 98 | .filter((item) => { 99 | return (item.xtype === 'loadmask' && item.isHidden() === false) 100 | }).length > 0 101 | 102 | if (maskDisplayed) { 103 | done('Load mask is still presented.') 104 | } else { 105 | // LoadMask need sone time to be hidden 106 | setTimeout(() => { 107 | done(null) 108 | }, 500) 109 | } 110 | }, 111 | callback, 112 | { 113 | delay: 500 // wait load mask display delay 114 | } 115 | ) 116 | } 117 | 118 | waitText (callback, text) { 119 | // TODO check parent 120 | return waitForFn( 121 | (done) => { 122 | let textPresented = false 123 | 124 | if (text instanceof RegExp) { 125 | textPresented = text.test(window.document.body.innerText) 126 | } else if (window.find) { 127 | textPresented = window.find(text, true, true, true) // arg aWholeWord - Unimplemented 128 | } else { 129 | textPresented = (new RegExp(text, 'g')).test(window.document.body.innerText) 130 | } 131 | 132 | done(textPresented ? null : `Text pattern "${text}" not found on page.`) 133 | }, 134 | callback 135 | ) 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/drivers/html/components/base.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | export class HTMLComponentBase { 4 | 5 | constructor ({htmlElement, driver}) { 6 | this.driver = driver 7 | this.htmlElement = htmlElement 8 | } 9 | 10 | click (callback) { 11 | const el = this.htmlElement 12 | 13 | // for PhantomJs: 14 | // ./node_modules/mocha-phantomjs/node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js:116 15 | // add "page.sendEvent.apply(this, data.sendEvent)" 16 | // 17 | const rect = el.getBoundingClientRect() 18 | const x = Math.round(rect.left + rect.width / 2) 19 | const y = Math.round(rect.top + rect.height / 2) 20 | 21 | this.driver.mochaUi.cursor.moveTo(x + 1, y + 1, () => { 22 | let err 23 | 24 | this.driver.mochaUi.hide() 25 | 26 | // BUG hide cellEditor in PhantomJs 27 | // if (el.focus) { 28 | // el.focus() 29 | // } 30 | 31 | if (el.scrollIntoView) { 32 | el.scrollIntoView() 33 | } 34 | 35 | if (window.callPhantom) { 36 | window.callPhantom({sendEvent: ['mousemove', x - 1, y - 1]}) 37 | window.callPhantom({sendEvent: ['mousemove', x, y]}) 38 | err = !window.callPhantom({sendEvent: ['click', x, y]}) 39 | } else { 40 | try { 41 | window.document.elementFromPoint(x, y).click() 42 | err = false 43 | } catch (e) { 44 | err = `[${x},${y}] (${e})` 45 | } 46 | } 47 | 48 | this.driver.mochaUi.show() 49 | 50 | return callback(err ? `cannot click on "${el.id}" ${err}` : null) 51 | }) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/mochaUI.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import {Cursor} from './mochaUi/cursor.js' 4 | 5 | export class MochaUI { 6 | 7 | constructor () { 8 | this.cursor = new Cursor() 9 | } 10 | 11 | get mochaElement () { 12 | return window.document.getElementById('mocha') 13 | } 14 | 15 | show () { 16 | if (this.mochaElement) { 17 | this.mochaElement.style.display = 'block' 18 | } 19 | 20 | this.cursor.show() 21 | } 22 | 23 | hide () { 24 | if (this.mochaElement) { 25 | this.mochaElement.style.display = 'none' 26 | } 27 | 28 | this.cursor.hide() 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/mochaUi/cursor.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | export class Cursor { 4 | 5 | constructor () { 6 | this._size = 14 7 | this._timeout = 400 8 | this._initTransition = `all ${this._timeout}ms ease-in-out` 9 | this._position = { 10 | x: 0, 11 | y: 0 12 | } 13 | 14 | this._point = window.document.getElementById('mocha-extjs-testing-tool-pointer') 15 | 16 | if (!this._point) { 17 | this._point = document.createElement('div') 18 | 19 | this._point.id = 'mocha-extjs-testing-tool-pointer' 20 | this._point.style.top = `${this._position.y}px` 21 | this._point.style.left = `${this._position.x}px` 22 | this._point.style.width = `${this._size}px` 23 | this._point.style.zIndex = '90000' 24 | this._point.style.height = `${this._size}px` 25 | this._point.style.border = '2px solid #ffffff' 26 | this._point.style.opacity = '1' 27 | this._point.style.position = 'absolute' 28 | this._point.style.transition = this._initTransition 29 | this._point.style.borderRadius = `0 ${this._size / 2}px ${this._size / 2}px ${this._size / 2}px` 30 | this._point.style.backgroundColor = '#ee3300' 31 | 32 | window.document.body.appendChild(this._point) 33 | } 34 | } 35 | 36 | moveTo (x, y, callback) { 37 | if (window.callPhantom) { 38 | this._point.style.left = `${x}px` 39 | this._point.style.top = `${y}px` 40 | return callback(null) 41 | } else { 42 | const translate = `translate(${x}px, ${y}px)` 43 | this._point.style.transform = translate 44 | setTimeout(() => { 45 | this._point.style.transition = 'all 50ms ease-in-out' 46 | this._point.style.transform = `${translate} scale(0.5)` 47 | setTimeout(() => { 48 | this._point.style.transform = `${translate} scale(1)` 49 | setTimeout(() => { 50 | this._point.style.transition = this._initTransition 51 | return callback(null) 52 | }, 50) 53 | }, 50) 54 | }, this._timeout) 55 | } 56 | } 57 | 58 | hide () { 59 | this._point.style.display = 'none' 60 | } 61 | 62 | show () { 63 | this._point.style.display = 'block' 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/utils/set.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | export class Set { 4 | 5 | constructor () { 6 | this._items = [] 7 | } 8 | 9 | push (component) { 10 | this._items.push(component) 11 | } 12 | 13 | * items () { 14 | for (let item of this._items) { 15 | yield item 16 | } 17 | } 18 | 19 | * reversedItems () { 20 | for (let i = this._items.length - 1; i >= 0; i--) { 21 | yield this._items[i] 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | export function waitForFn (waitFn, callback, 4 | {delay, timeout, ticInterval} = {delay: 10, timeout: 10 * 1000, ticInterval: 500}) { 5 | const startTimestamp = +(new Date()) 6 | let interval 7 | let lastError = '' 8 | let exectution = false 9 | 10 | const intervalFn = () => { 11 | if ((+new Date() - startTimestamp) > timeout) { 12 | exectution = false 13 | clearInterval(interval) 14 | return callback(`Out of time: ${timeout / 1000}s (${lastError})`) 15 | } 16 | 17 | if (!exectution) { 18 | try { 19 | exectution = true 20 | waitFn((err, result) => { 21 | if (!exectution) { 22 | console.warn('waitForFn(): Operation finished after time out.') 23 | return 24 | } 25 | exectution = false 26 | if (err) { 27 | lastError = err 28 | } else { 29 | clearInterval(interval) 30 | return callback(null, result) 31 | } 32 | }) 33 | } catch (e) { 34 | exectution = false 35 | throw e 36 | } 37 | } 38 | } 39 | 40 | setTimeout(() => { 41 | interval = setInterval(intervalFn, ticInterval) 42 | intervalFn() 43 | }, delay) 44 | } 45 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/.cvsignore: -------------------------------------------------------------------------------- 1 | /temp/ -------------------------------------------------------------------------------- /test/sandbox/.sencha/.gitignore: -------------------------------------------------------------------------------- 1 | /temp/ -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/bootstrap-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | @{launchcode} 33 | 34 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/build.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file provides an override point for default variables defined in these 3 | # lower priority files: 4 | # 5 | # - ext.properties 6 | # - *.defaults.properties 7 | # - defaults.properties 8 | # 9 | # To override a property based on build.environment instead add properties to 10 | # one of these higher priority files: 11 | # 12 | # - production.properties 13 | # - testing.properties 14 | # - native.properties 15 | # - package.properties 16 | # 17 | # IMPORTANT - Sencha Cmd will merge your changes with its own during upgrades. 18 | # To avoid potential merge conflicts avoid making large, sweeping changes to 19 | # this file. 20 | # ============================================================================= 21 | 22 | skip.slice=1 23 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/codegen.json: -------------------------------------------------------------------------------- 1 | { 2 | "sources": { 3 | "build.properties.merge": { 4 | "d4613dc19be3ddb60e7ff5716e28c8b15d954f3a": "eJytUstOw0AMvPMVI/WGoB+AxAFx4sBD0B9ws05idbOOdp2E/j1OH6pEEKfuzR57POP1Co/XfDcrbFopqCUy+qyjBC6gBB05Zw/QqyRDrRmBaxqiYaQstI1e5xlJHCAJ1nJhZ4s6cXYm0Sy2P/CWh5uVI8A9+NvWPqXnbMLllLxdn5jLEvsTmUXrRSHhBO6xpeJyNGE7SAxrTqNkTR27A0nFmAIoBFzIYOpsmhhaHz2glab9x4L3hqEy0bRUa1xMUrMEEpmMvMz3VO2o4d/uXl4/3j83T28bL/niVLWE5y5gkhjRcW4Yex0yPJ8a9zCJtRAr0CkhDNklYOibTP6X6+OyaFRx32q+CqEzS6WpjlJ55xHvaDf3RnLwDmVi7uf4POewKzufy8x83Vv8AQy16fs\u003d" 5 | }, 6 | "development.properties.merge": { 7 | "c45c602c9b6f6f73cace183e9f0bf09c00a3ccf6": "eJytkUuOAjEMBfec4one9w24wyy4QFDc0xbBjhyTEbcfp0F89mRny6l6liccvvl2E44rNyxcCNW0c6aGJNBOZlGgKotjUUOmJV2LoyfjdCoxFx0WymBBgJyas/zOj7k2B6+SOVObw0JtMzw6SEZQKTfwpap5UP5WEpyuXHJQgjecvhL2mToVrRcS34Oks6mMYt5NMfbzYr7l8edWns5DzGrst22vu+QtXjR8BAraFqloyoEZAT7l28cW3i9f4R+b7pUs" 8 | }, 9 | "native.properties.merge": { 10 | "2c8c063f9588eecff09624782d7369a8a000d61c": "eJytkEsOwjAMRPecYkT3vQF3YMEFguJSi2BXjgni9rgfFQ5AdrEm743T4fTPc+hwGbli4EKYTBtnqkgCbWQWF0zK4hjUkGlIz+JoyThdS+RiwkIZLAiQJOdG/RarfeAmMmeqfUioLoJtgmQElfIGPyY1D8hrJMH1ySWz3AI3K30kHFfuESSNTeVB4v2hi8T5i/tp4vs+nu6zk9XY38tGK/+nWQx87hK0pU3RlAMzu3fv8qaG8s9f/wFV3ZB9" 11 | }, 12 | "package.properties.merge": { 13 | "c6c1fb2fb1dda28480ad0f6e5caffc9b97d196ae": "eJytkUFygzAMRfc5hSZsOxygM11223aRCwgsQBNH8tiCTG5fGWjDAcLOsnjvS27g45XfqYHLxAUGjgQp68KBCqCALpSzHyApi8GgGQINOEeDBTNjF73PKywUgAUclLC/4kjt3lda5yXKxlRat1BZDXsFMBOoxAfwLWk2p9wnEuhmjoFldF512kRw3sFnIFk4q9xIrD013vLz5B2y2P9EhtcqZc1sj3WmTXCI5gWrYZy2xomKwTFV/hSvP5XN+fV9+Xzftjb7SDoc+jClWJmmIGi80N9SwnbVe1HlDUTdWfNvt1togpGEMkYoLP1K7tVfIHKXfeVU/S9+/V9rlbyW" 14 | }, 15 | "production.properties.merge": { 16 | "cbdf9712e9b5d37cecb4d0530ba1fccd0ed004a3": "eJytkUEOwjAMBO+8YkXv/QF/4MAHAnGpRbArxy3i97gFQbk3t6ycmbXS4LDl2TU49VzRcSEMphNnqkgCncgsLhiUxdGpIVOXxuKYknE6l5iLhIUyWBCgeJ7Hi7NK+xmtbWQDmTPVNkRUF8knQTKCSnmC74OaB+jRk+A8csks10DOWu8J+x97D5KJTeVO4u2uianjD7lq5N+9PN1mL6uxP5fN3o5Vuwh87hO0pVHRlAMz+//cy7sa2o2/4QV6LJW9" 17 | }, 18 | "sencha.cfg.tpl.merge": { 19 | "37e77998d0cc69cbe4c0c2d4481f2e6c43b55a8f": "eJytkMENwkAMBP9XxUp5Qwe8aIAWzMUhli7nk+0Qheq5gOgAf/xY72rHA2IWRzNtbLHDG2eZhB2ErMtCcG5kFDyiiAd0QqOYvas1SKrURxpg7Lpa7rbQrrT92DEz7quUEaMY51DbE7V2/h2fP0GXlIbLX6f3ua4euuD2xTpwTrgVyoz8UeRFIVoddy66fX9QpPJRm54qIxa2B/ekjjkVyeHYJGZU3tjwZPPDnt66VmnK" 20 | }, 21 | "testing.properties.merge": { 22 | "360e715956c81757e53736789fe20be045acb544": "eJytkMENwjAMRe+d4oveuwE7cGCBoLjUItiVY4q6PW6pKAM0t1g/732nxfnI07S4DlzRcyGMphNnqkgCncgsLhiVxdGrIVOfXsUxJeN0K5GLCQtlsCBATtVZ7t2Wq13wRjJnql1YqK6GbYJkBJUyg5+jmgflPZDg9uKSgxK8xekD4bSBTyCZ2FSeJN41bUQuO++vi/828vRYpKzGPq87fQV/1WLgS5mgrXWKphyYRb6L10c1nAf//gdqIpHi" 23 | }, 24 | "config.rb.tpl.merge": { 25 | "33f446bd02c3fd24eb27891582eff6a2e789796b": "eJxLLi2KT8ksUrBVcMvMSdUDMvMSc1M14uPdPH1c4+M1ufJLSwpKS+KLSypzUoGqrPJSi0tSU7gALskTcA\u003d\u003d" 26 | } 27 | }, 28 | "targets": { 29 | ".sencha/app/build.properties": { 30 | "source": "build.properties.merge", 31 | "version": "d4613dc19be3ddb60e7ff5716e28c8b15d954f3a", 32 | "parameters": { 33 | "appControllers": "", 34 | "appModels": "", 35 | "appName": "Sandbox", 36 | "appStores": "", 37 | "appViews": "", 38 | "classic": false, 39 | "controllerFileName": "Main", 40 | "controllerName": "Main", 41 | "controllerNamespace": "Sandbox.controller", 42 | "frameworkKey": "ext", 43 | "frameworkName": "ext", 44 | "frameworkPath": "ext", 45 | "modelNamespace": "Sandbox.model", 46 | "modern": false, 47 | "name": "Sandbox", 48 | "packagesRelPath": "ext/packages/", 49 | "senchadir": ".sencha", 50 | "themeName": "default", 51 | "toolkit": "", 52 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 53 | "universal": true, 54 | "viewFileName": "Main", 55 | "viewName": "Main", 56 | "viewNamespace": "Sandbox.view" 57 | } 58 | }, 59 | ".sencha/app/development.properties": { 60 | "source": "development.properties.merge", 61 | "version": "c45c602c9b6f6f73cace183e9f0bf09c00a3ccf6", 62 | "parameters": { 63 | "appControllers": "", 64 | "appModels": "", 65 | "appName": "Sandbox", 66 | "appStores": "", 67 | "appViews": "", 68 | "classic": false, 69 | "controllerFileName": "Main", 70 | "controllerName": "Main", 71 | "controllerNamespace": "Sandbox.controller", 72 | "frameworkKey": "ext", 73 | "frameworkName": "ext", 74 | "frameworkPath": "ext", 75 | "modelNamespace": "Sandbox.model", 76 | "modern": false, 77 | "name": "Sandbox", 78 | "packagesRelPath": "ext/packages/", 79 | "senchadir": ".sencha", 80 | "themeName": "default", 81 | "toolkit": "", 82 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 83 | "universal": true, 84 | "viewFileName": "Main", 85 | "viewName": "Main", 86 | "viewNamespace": "Sandbox.view" 87 | } 88 | }, 89 | ".sencha/app/native.properties": { 90 | "source": "native.properties.merge", 91 | "version": "2c8c063f9588eecff09624782d7369a8a000d61c", 92 | "parameters": { 93 | "appControllers": "", 94 | "appModels": "", 95 | "appName": "Sandbox", 96 | "appStores": "", 97 | "appViews": "", 98 | "classic": false, 99 | "controllerFileName": "Main", 100 | "controllerName": "Main", 101 | "controllerNamespace": "Sandbox.controller", 102 | "frameworkKey": "ext", 103 | "frameworkName": "ext", 104 | "frameworkPath": "ext", 105 | "modelNamespace": "Sandbox.model", 106 | "modern": false, 107 | "name": "Sandbox", 108 | "packagesRelPath": "ext/packages/", 109 | "senchadir": ".sencha", 110 | "themeName": "default", 111 | "toolkit": "", 112 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 113 | "universal": true, 114 | "viewFileName": "Main", 115 | "viewName": "Main", 116 | "viewNamespace": "Sandbox.view" 117 | } 118 | }, 119 | ".sencha/app/package.properties": { 120 | "source": "package.properties.merge", 121 | "version": "c6c1fb2fb1dda28480ad0f6e5caffc9b97d196ae", 122 | "parameters": { 123 | "appControllers": "", 124 | "appModels": "", 125 | "appName": "Sandbox", 126 | "appStores": "", 127 | "appViews": "", 128 | "classic": false, 129 | "controllerFileName": "Main", 130 | "controllerName": "Main", 131 | "controllerNamespace": "Sandbox.controller", 132 | "frameworkKey": "ext", 133 | "frameworkName": "ext", 134 | "frameworkPath": "ext", 135 | "modelNamespace": "Sandbox.model", 136 | "modern": false, 137 | "name": "Sandbox", 138 | "packagesRelPath": "ext/packages/", 139 | "senchadir": ".sencha", 140 | "themeName": "default", 141 | "toolkit": "", 142 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 143 | "universal": true, 144 | "viewFileName": "Main", 145 | "viewName": "Main", 146 | "viewNamespace": "Sandbox.view" 147 | } 148 | }, 149 | ".sencha/app/production.properties": { 150 | "source": "production.properties.merge", 151 | "version": "cbdf9712e9b5d37cecb4d0530ba1fccd0ed004a3", 152 | "parameters": { 153 | "appControllers": "", 154 | "appModels": "", 155 | "appName": "Sandbox", 156 | "appStores": "", 157 | "appViews": "", 158 | "classic": false, 159 | "controllerFileName": "Main", 160 | "controllerName": "Main", 161 | "controllerNamespace": "Sandbox.controller", 162 | "frameworkKey": "ext", 163 | "frameworkName": "ext", 164 | "frameworkPath": "ext", 165 | "modelNamespace": "Sandbox.model", 166 | "modern": false, 167 | "name": "Sandbox", 168 | "packagesRelPath": "ext/packages/", 169 | "senchadir": ".sencha", 170 | "themeName": "default", 171 | "toolkit": "", 172 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 173 | "universal": true, 174 | "viewFileName": "Main", 175 | "viewName": "Main", 176 | "viewNamespace": "Sandbox.view" 177 | } 178 | }, 179 | ".sencha/app/sencha.cfg": { 180 | "source": "sencha.cfg.tpl.merge", 181 | "version": "37e77998d0cc69cbe4c0c2d4481f2e6c43b55a8f", 182 | "parameters": { 183 | "appControllers": "", 184 | "appModels": "", 185 | "appName": "Sandbox", 186 | "appStores": "", 187 | "appViews": "", 188 | "classic": false, 189 | "controllerFileName": "Main", 190 | "controllerName": "Main", 191 | "controllerNamespace": "Sandbox.controller", 192 | "frameworkKey": "ext", 193 | "frameworkName": "ext", 194 | "frameworkPath": "ext", 195 | "modelNamespace": "Sandbox.model", 196 | "modern": false, 197 | "name": "Sandbox", 198 | "packagesRelPath": "ext/packages/", 199 | "senchadir": ".sencha", 200 | "themeName": "default", 201 | "toolkit": "", 202 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 203 | "universal": true, 204 | "viewFileName": "Main", 205 | "viewName": "Main", 206 | "viewNamespace": "Sandbox.view" 207 | } 208 | }, 209 | ".sencha/app/testing.properties": { 210 | "source": "testing.properties.merge", 211 | "version": "360e715956c81757e53736789fe20be045acb544", 212 | "parameters": { 213 | "appControllers": "", 214 | "appModels": "", 215 | "appName": "Sandbox", 216 | "appStores": "", 217 | "appViews": "", 218 | "classic": false, 219 | "controllerFileName": "Main", 220 | "controllerName": "Main", 221 | "controllerNamespace": "Sandbox.controller", 222 | "frameworkKey": "ext", 223 | "frameworkName": "ext", 224 | "frameworkPath": "ext", 225 | "modelNamespace": "Sandbox.model", 226 | "modern": false, 227 | "name": "Sandbox", 228 | "packagesRelPath": "ext/packages/", 229 | "senchadir": ".sencha", 230 | "themeName": "default", 231 | "toolkit": "", 232 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 233 | "universal": true, 234 | "viewFileName": "Main", 235 | "viewName": "Main", 236 | "viewNamespace": "Sandbox.view" 237 | } 238 | }, 239 | "sass/config.rb": { 240 | "source": "config.rb.tpl.merge", 241 | "version": "33f446bd02c3fd24eb27891582eff6a2e789796b", 242 | "parameters": { 243 | "appControllers": "", 244 | "appModels": "", 245 | "appName": "Sandbox", 246 | "appStores": "", 247 | "appViews": "", 248 | "classic": false, 249 | "controllerFileName": "Main", 250 | "controllerName": "Main", 251 | "controllerNamespace": "Sandbox.controller", 252 | "frameworkKey": "ext", 253 | "frameworkName": "ext", 254 | "frameworkPath": "ext", 255 | "modelNamespace": "Sandbox.model", 256 | "modern": false, 257 | "name": "Sandbox", 258 | "packagesRelPath": "ext/packages/", 259 | "senchadir": ".sencha", 260 | "themeName": "default", 261 | "toolkit": "", 262 | "uniqueId": "2afda357-f450-492c-a287-79bdcccf29b1", 263 | "universal": true, 264 | "viewFileName": "Main", 265 | "viewName": "Main", 266 | "viewNamespace": "Sandbox.view" 267 | } 268 | } 269 | } 270 | } -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/cordova-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | cordova ${cordova.cli.options} create "${app.cordova.config.path}" ${app.cordova.config.id} "${app.cordova.config.name}" 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | cordova ${cordova.cli.options} prepare ${cordova.platforms.clean} 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | cordova ${cordova.cli.options} emulate ${cordova.platforms.clean} --target=${app.cordova.config.target} 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | cordova ${cordova.cli.options} run ${cordova.platforms.clean} --target=${app.cordova.config.target} 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | cordova ${cordova.cli.options} build ${cordova.platforms.clean} 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 108 | 109 | 110 | cordova ${cordova.cli.options} platform list 111 | 112 | 113 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | cordova ${cordova.cli.options} platform add ${cordova.platforms.missing} 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/cordova.defaults.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2012-2014. Sencha Inc. 3 | # 4 | 5 | # Legacy support here for old build workflow. 6 | cordova.platforms=${app.cordova.config.platforms} -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/development.defaults.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file defines default property values that apply to the "development" build 3 | # environment. 4 | # 5 | # Please use testing.properties to customize these properties unless you want 6 | # your customizations to be for all environments. In that case, you can instead 7 | # override these properties in build.properties. 8 | # 9 | # The properties defined in this file take priority over defaults.properties 10 | # but are lower priority than build.properties which in turn is lower priority 11 | # than development.properties. 12 | # 13 | # IMPORTANT - This file should not be modified by an app as it is overwritten 14 | # during each app upgrade. 15 | # ============================================================================= 16 | 17 | build.options.logger=yes 18 | 19 | build.options.debug=true 20 | 21 | build.css.compress=false 22 | 23 | build.include.all.scss=true 24 | 25 | # By default we don't need to build an "all.js" file, or a new markup page or 26 | # slice images for IE8/9. These can be added to "development.properties" and 27 | # set to 0 to enable them if needed. 28 | skip.page=1 29 | skip.js=1 30 | skip.slice=1 31 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/development.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file provides an override point for default variables defined in 3 | # testing.defaults.properties. These properties are only imported when building 4 | # for the "development" environment. 5 | # 6 | # Properties defined in this file take priority over build.properties but are 7 | # only loaded for "development" builds. 8 | # ============================================================================= 9 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/ext.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file defines default property values that apply to all builds based on 3 | # Ext JS 5.x framework. 4 | # 5 | # Please use build.properties to customize these properties. 6 | # 7 | # To override a property based on build.environment instead add properties to 8 | # one of these higher priority files: 9 | # 10 | # - production.properties 11 | # - testing.properties 12 | # - native.properties 13 | # - package.properties 14 | # 15 | # The properties defined in this file take priority over defaults.properties 16 | # and *.defaults.properties. 17 | # 18 | # IMPORTANT - This file should not be modified by an app as it is overwritten 19 | # during each app upgrade. 20 | # ============================================================================= 21 | 22 | enable.ext42.themes=true 23 | 24 | enable.sencha-core.filter=true 25 | 26 | build.options.product=ext 27 | 28 | build.options.minVersion=5 29 | 30 | bootstrap.include.boot=true 31 | bootstrap.override.tpl=Ext.Loader.loadScriptsSync 32 | bootstrap.override.tpltype=jsonp 33 | 34 | app.microloader.name=Microloader.js 35 | app.microloader.dir=${app.config.dir} 36 | app.microloader.bootstrap=${app.microloader.dir}/${app.microloader.name} 37 | app.microloader.path=${app.microloader.dir}/${app.microloader.name} 38 | 39 | build.microloader.json.tpl.embedded=var Ext = Ext || '{' '}'; Ext.manifest = Ext.manifest || {0}; 40 | build.microloader.manifest.name=${app.manifest.name} 41 | build.microloader.json.tpl.external=var Ext = Ext || '{' '}'; Ext.manifest = Ext.manifest || "${build.microloader.manifest.name}"; 42 | 43 | build.skip.versions.file=true 44 | build.enable.appmanifest=true 45 | compass.compile.force=false 46 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/find-cmd-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 50 | 51 | 52 | source ~/.bash_profile; sencha which -p cmd.dir -o '$cmddir$' 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/js-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 80 | 81 | 82 | 83 | 84 | 100 | 101 | 102 | 103 | 104 | 105 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/native.defaults.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file defines default property values that apply to the "native" build 3 | # environment. 4 | # 5 | # Please use native.properties to customize these properties unless you want 6 | # your customizations to be for all environments. In that case, you can instead 7 | # override these properties in build.properties. 8 | # 9 | # The properties defined in this file take priority over defaults.properties 10 | # but are lower priority than build.properties which in turn is lower priority 11 | # than native.properties. 12 | # 13 | # IMPORTANT - This file should not be modified by an app as it is overwritten 14 | # during each app upgrade. 15 | # ============================================================================= 16 | 17 | build.options.logger=no 18 | 19 | build.options.debug=false 20 | 21 | # enable yui compression 22 | build.compression.yui=1 23 | 24 | enable.standalone.manifest=true 25 | 26 | app.microloader.name=testing.js 27 | 28 | skip.native-package=false 29 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/native.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file provides an override point for default variables defined in 3 | # native.defaults.properties. These properties are only imported when building 4 | # for the "native" environment. 5 | # 6 | # Properties defined in this file take priority over build.properties but are 7 | # only loaded for "native" builds. 8 | # ============================================================================= 9 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/package.defaults.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file defines default property values that apply to the "package" build 3 | # environment. 4 | # 5 | # Please use package.properties to customize these properties unless you want 6 | # your customizations to be for all environments. In that case, you can instead 7 | # override these properties in build.properties. 8 | # 9 | # The properties defined in this file take priority over defaults.properties 10 | # but are lower priority than build.properties which in turn is lower priority 11 | # than package.properties. 12 | # 13 | # IMPORTANT - This file should not be modified by an app as it is overwritten 14 | # during each app upgrade. 15 | # 16 | # NOTE: This use of "package" applies to native packaged application, not a 17 | # Package in the general since of code libraries. 18 | # ============================================================================= 19 | 20 | build.options.logger=no 21 | 22 | build.options.debug=false 23 | 24 | # enable yui compression 25 | build.compression.yui=1 26 | 27 | app.microloader.name=testing.js 28 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/package.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file provides an override point for default variables defined in 3 | # package.defaults.properties. These properties are only imported when building 4 | # for the "package" environment. 5 | # 6 | # Properties defined in this file take priority over build.properties but are 7 | # only loaded for "package" builds. 8 | # 9 | # NOTE: This use of "package" applies to native packaged application, not a 10 | # Package in the general since of code libraries. 11 | # ============================================================================= 12 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/packager-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/page-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 72 | 73 | 74 | 75 | 76 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 130 | 131 | 132 | 133 | 134 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 298 | 299 | 302 | 303 | 304 | 305 | 308 | 309 | 310 | 311 | 316 | 317 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/phonegap-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | phonegap ${phonegap.cli.options} create "${app.phonegap.config.path}" ${app.phonegap.config.id} ${app.phonegap.config.name} 47 | 48 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | Phonegap Build login credentials were was not found. If you have not logged in prior to running this command. 151 | Please either login via "phonegap remote login" or edit your [APP_ROOT]/local.properties and set "phonegap.username" and "phonegap.password" appropriately 152 | 153 | 154 | 155 | 156 | 157 | phonegap ${phonegap.cli.options} remote login --username="${phonegap.build.remote.username}" --password="${phonegap.build.remote.password}" 158 | 159 | 160 | 161 | 162 | 163 | 164 | phonegap ${phonegap.cli.options} remote build ${phonegap.platform} 165 | 166 | 167 | 168 | 169 | 170 | 171 | phonegap ${phonegap.cli.options} remote run ${phonegap.platform} 172 | 173 | 174 | 175 | 176 | 177 | 178 | phonegap ${phonegap.cli.options} remote run ${phonegap.platform} --emulator 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | phonegap ${phonegap.cli.options} local build ${phonegap.platform} 187 | 188 | 189 | 190 | 191 | 192 | 193 | phonegap ${phonegap.cli.options} local run ${phonegap.platform} 194 | 195 | 196 | 197 | 198 | 199 | 200 | phonegap ${phonegap.cli.options} local run ${phonegap.platform} --emulator 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/phonegap.defaults.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2012-2014. Sencha Inc. 3 | # 4 | 5 | # Original PhoneGap Packager used the following properties 6 | # here we map in the app space properties to allow for app.json 7 | # setting of these instead of properties files 8 | phonegap.platform=${app.phonegap.config.platform} 9 | phonegap.build.remote=${app.phonegap.config.remote} 10 | 11 | # These are simply shorthanded as the user must specify them in 12 | # a local.properties file anyway. 13 | # No need for the user to type all this out. 14 | phonegap.build.remote.username=${phonegap.username} 15 | phonegap.build.remote.password=${phonegap.password} -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 24 | 32 | 33 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/production.defaults.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file defines default property values that apply to the "production" build 3 | # environment. 4 | # 5 | # Please use production.properties to customize these properties unless you want 6 | # your customizations to be for all environments. In that case, you can instead 7 | # override these properties in build.properties. 8 | # 9 | # The properties defined in this file take priority over defaults.properties 10 | # but are lower priority than build.properties which in turn is lower priority 11 | # than production.properties. 12 | # 13 | # IMPORTANT - This file should not be modified by an app as it is overwritten 14 | # during each app upgrade. 15 | # ============================================================================= 16 | 17 | build.options.logger=no 18 | 19 | build.options.debug=false 20 | 21 | # enable the full class system optimizer 22 | app.output.js.optimize=true 23 | build.optimize=${build.optimize.enable} 24 | 25 | enable.resource.compression=true 26 | 27 | build.embedded.microloader.compressor=-closure 28 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/production.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file provides an override point for default variables defined in 3 | # production.defaults.properties. These properties are only imported when building 4 | # for the "production" environment. 5 | # 6 | # Properties defined in this file take priority over build.properties but are 7 | # only loaded for "production" builds. 8 | # ============================================================================= 9 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/refresh-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 47 | 48 | 49 | 50 | 51 | 58 | 59 | 60 | 61 | 62 | 65 | 66 | var Ext = Ext || {}; 67 | Ext.manifest = Ext.manifest || "${build.json.bootstrap.rel.path}"; 68 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 101 | 102 | 106 | 107 | 108 | /** 109 | * This file is generated by Sencha Cmd and should NOT be edited. It is a 110 | * combination of content from app.json, and all required package's package.json 111 | * files. Customizations should be placed in app.json. 112 | */ 113 | 114 | 115 | 124 | 125 | 126 | 127 | 131 | 135 | 136 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/resolve-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 39 | 40 | 41 | 49 | 50 | 51 | 52 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/resources-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/sass-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | include 22 | -all 23 | 24 | 25 | 26 | 27 | restore 28 | page 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 114 | 119 | 120 | 121 | 122 | 130 | 131 | 132 | 133 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 161 | 162 | 163 | 164 | Preprocessing @{cssfile} to ${css.output.name} 165 | 169 | 170 | 171 | 172 | 173 | 174 | Compressing @{cssfile} to ${css.output.name} 175 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 203 | 204 | 205 | 211 | 212 | 213 | fashion 214 | -compress=${build.css.compress} 215 | -split=${build.css.selector.limit} 216 | -saveFile=${app.dir}/${app.sass.save} 217 | ${app.out.scss} 218 | ${app.out.css} 219 | 220 | 221 | 223 | 224 | 225 | 226 | 227 | 236 | 237 | 241 | 242 | 243 | 244 | 245 | 246 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 271 | 272 | 273 | 274 | 275 | Compiling sass directory : @{theme}/sass 276 | 282 | 283 | 285 | 286 | 287 | 288 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 309 | 310 | 311 | 317 | 318 | 319 | 320 | 324 | 328 | 329 | 332 | 333 | 334 | 335 | 336 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/sencha.cfg: -------------------------------------------------------------------------------- 1 | # this property specifies a comma separated list of paths containing 2 | # resources to copy to the build directory 3 | app.resource.paths= 4 | 5 | #============================================================================== 6 | # Custom Properties - Place customizations below this line to avoid merge 7 | # conflicts with newer versions 8 | 9 | app.framework.version=6.0.1.250 10 | 11 | app.cmd.version=6.1.2.15 12 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/slice-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 74 | 75 | 76 | 77 | 86 | 87 | 88 | 89 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | fashion 106 | -compress=${build.css.compress} 107 | -split=${build.css.selector.limit} 108 | ${app.example.build.dir} 109 | ${app.example.build.dir} 110 | 111 | 112 | 113 | 114 | 115 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 133 | 134 | 141 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | exclude 166 | -tag=framework,package-sencha-core,package-core,package-${toolkit.name} 167 | 168 | 169 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 197 | 198 | 199 | 200 | 201 | Capture theme image to ${build.capture.png} 202 | 203 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | Capture theme image to ${build.capture.png} 221 | 224 | 225 | 226 | 227 | 228 | 229 | Slicing theme images to ${build.resources.dir} 230 | 231 | 239 | 240 | 241 | 242 | 243 | 247 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | Copying base framework images from ${framework.theme.dir} to ${tmp.img.dir} 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | Building sass for theme ${theme.name} 291 | 292 | 293 | 294 | 295 | 296 | Slicing images for theme ${theme.name} to ${tmp.img.dir} 297 | 298 | 306 | 307 | 308 | 309 | 310 | 311 | Copying user defined images from @{theme}/images to ${tmp.img.dir} 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 325 | 326 | 327 | 328 | 330 | 331 | 332 | 335 | 336 | 337 | 339 | 340 | 341 | 342 | 343 | 347 | 348 | Processing theme directories from ${app.theme.dir} 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/testing.defaults.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file defines default property values that apply to the "testing" build 3 | # environment. 4 | # 5 | # Please use testing.properties to customize these properties unless you want 6 | # your customizations to be for all environments. In that case, you can instead 7 | # override these properties in build.properties. 8 | # 9 | # The properties defined in this file take priority over defaults.properties 10 | # but are lower priority than build.properties which in turn is lower priority 11 | # than testing.properties. 12 | # 13 | # IMPORTANT - This file should not be modified by an app as it is overwritten 14 | # during each app upgrade. 15 | # ============================================================================= 16 | 17 | build.options.logger=yes 18 | 19 | build.options.debug=true 20 | 21 | build.css.compress=false 22 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/testing.properties: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # This file provides an override point for default variables defined in 3 | # testing.defaults.properties. These properties are only imported when building 4 | # for the "testing" environment. 5 | # 6 | # Properties defined in this file take priority over build.properties but are 7 | # only loaded for "testing" builds. 8 | # ============================================================================= 9 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/app/watch-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 28 | 29 | 30 | 31 | 32 | 33 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/workspace/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/sandbox/.sencha/workspace/sencha.cfg: -------------------------------------------------------------------------------- 1 | #Sat, 09 Jan 2016 22:51:46 -0800 2 | # ----------------------------------------------------------------------------- 3 | # This file contains configuration options that apply to all applications in 4 | # the workspace. By convention, these options start with "workspace." but any 5 | # option can be set here. Options specified in an application's sencha.cfg will 6 | # take priority over those values contained in this file. These options will 7 | # take priority over configuration values in Sencha Cmd or a framework plugin. 8 | 9 | # ----------------------------------------------------------------------------- 10 | # This configuration property (if set) is included by default in all compile 11 | # commands executed according to this formulation: 12 | # 13 | # sencha compile -classpath=...,${framework.classpath},${workspace.classpath},${app.classpath} 14 | 15 | #workspace.classpath= 16 | 17 | #------------------------------------------------------------------------------ 18 | # This is the folder for build outputs in the workspace 19 | 20 | workspace.build.dir=${workspace.dir}/build 21 | 22 | #------------------------------------------------------------------------------ 23 | # This folder contains all generated and extracted packages. 24 | 25 | workspace.packages.dir=${workspace.dir}/packages 26 | 27 | workspace.theme.dir=${workspace.packages.dir}/${args.themeName} 28 | 29 | # ============================================================================= 30 | # Customizations go below this divider to avoid merge conflicts on upgrade 31 | # ============================================================================= 32 | 33 | workspace.cmd.version=6.0.2.14 34 | 35 | ext.dir=${workspace.dir}/ext 36 | -------------------------------------------------------------------------------- /test/sandbox/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is generated and updated by Sencha Cmd. You can edit this file as 3 | * needed for your application, but these edits will have to be merged by 4 | * Sencha Cmd when upgrading. 5 | */ 6 | Ext.application({ 7 | name: 'Sandbox', 8 | 9 | extend: 'Sandbox.Application', 10 | 11 | autoCreateViewport: 'Sandbox.view.main.Main' 12 | 13 | //------------------------------------------------------------------------- 14 | // Most customizations should be made to Sandbox.Application. If you need to 15 | // customize this file, doing so below this section reduces the likelihood 16 | // of merge conflicts when upgrading to new versions of Sencha Cmd. 17 | //------------------------------------------------------------------------- 18 | }) 19 | -------------------------------------------------------------------------------- /test/sandbox/app/Application.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.Application', { 2 | extend: 'Ext.app.Application', 3 | name: 'Sandbox' 4 | }) 5 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/Main.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.Main', { 2 | extend: 'Ext.container.Container', 3 | 4 | requires: [ 5 | 'Ext.layout.container.VBox', 6 | 'Ext.layout.container.HBox', 7 | 'Sandbox.view.main.MainModel', 8 | 'Sandbox.view.main.MainController', 9 | 'Sandbox.view.main.tab.LoadMasks', 10 | 'Sandbox.view.main.tab.Buttons', 11 | 'Sandbox.view.main.tab.Windows', 12 | 'Sandbox.view.main.tab.Content', 13 | 'Sandbox.view.main.tab.Fields', 14 | 'Sandbox.view.main.tab.Grids', 15 | 'Sandbox.view.main.tab.Dataview' 16 | ], 17 | 18 | controller: 'main', 19 | viewModel: { 20 | type: 'main' 21 | }, 22 | 23 | layout: { 24 | type: 'fit' 25 | }, 26 | 27 | items: { 28 | xtype: 'tabpanel', 29 | bodyPadding: 5, 30 | defaults: { 31 | xtype: 'container', 32 | layout: 'vbox', 33 | defaults: { 34 | margin: 5 35 | } 36 | }, 37 | items: [{ 38 | xtype: 'tabButtons' 39 | }, { 40 | xtype: 'tabWindows' 41 | }, { 42 | xtype: 'tabFields' 43 | }, { 44 | xtype: 'tabGrids' 45 | }, { 46 | xtype: 'tabDataview' 47 | }, { 48 | xtype: 'tabLoadMasks' 49 | }, { 50 | xtype: 'tabContent' 51 | }] 52 | } 53 | }) 54 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/MainController.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.MainController', { 2 | extend: 'Ext.app.ViewController', 3 | alias: 'controller.main', 4 | 5 | requires: [ 6 | 'Ext.window.MessageBox' 7 | ], 8 | 9 | // buttons 10 | 11 | onButtonsSimpleButtonClick: function (btn) { 12 | btn.setDisabled(true) 13 | btn.setText(btn.getText() + ' [done]') 14 | }, 15 | 16 | onButtonsDisableButtonClick: function (btn) { 17 | btn.setDisabled(true) 18 | btn.setText('Wait for 1s..') 19 | setTimeout(function () { 20 | btn.setText(btn.getText() + ' [done]') 21 | btn.setDisabled(false) 22 | }, 1000) 23 | }, 24 | 25 | onButtonsSelectMeByTooltipButtonClick: function (btn) { 26 | btn.setDisabled(true) 27 | btn.setText(btn.getText() + ' [done]') 28 | }, 29 | 30 | onButtonsSelectMeByCustomXtypeButtonClick: function (btn) { 31 | btn.setDisabled(true) 32 | btn.setText(btn.getText() + ' [done]') 33 | }, 34 | 35 | // windows 36 | 37 | onWindowsShowConfirmButtonClick: function (btn) { 38 | Ext.getBody().mask('Wait window...') 39 | setTimeout(function () { 40 | Ext.getBody().unmask() 41 | Ext.Msg.confirm('Confirm', 'Are you sure?', function () { 42 | btn.setText(btn.getText() + ' [done]') 43 | }) 44 | }, 1000) 45 | }, 46 | 47 | // loadMasks 48 | 49 | onLoadMasksShowGlobalButtonClick: function (btn) { 50 | Ext.getBody().mask('Wait load mask...') 51 | setTimeout(function () { 52 | Ext.getBody().unmask() 53 | btn.setText(btn.getText() + ' [done]') 54 | }, 1000) 55 | }, 56 | 57 | onLoadMasksShowComponentButtonClick: function (btn) { 58 | var tab = btn.up('tabpanel') 59 | tab.setLoading('Wait setLoading load mask...') 60 | setTimeout(function () { 61 | tab.setLoading(false) 62 | btn.setText(btn.getText() + ' [done]') 63 | }, 1000) 64 | }, 65 | 66 | // content 67 | 68 | onTextsShowTextButtonClick: function (btn) { 69 | var self = this 70 | Ext.getBody().mask('Wait for text appears...') 71 | btn.setText('Wait for text appears...') 72 | setTimeout(function () { 73 | Ext.getBody().unmask() 74 | self.getViewModel().set('buttonResultText', 'Result is here!') 75 | btn.setText(btn.getText() + ' [done]') 76 | }, 1000) 77 | }, 78 | 79 | onContentHideMeButtonClick: function (btn) { 80 | Ext.getBody().mask('Hide button...') 81 | setTimeout(function () { 82 | btn.hide() 83 | Ext.getBody().mask('Show button...') 84 | setTimeout(function () { 85 | Ext.getBody().unmask() 86 | btn.show() 87 | }, 1000) 88 | }, 1000) 89 | } 90 | 91 | }) 92 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/MainModel.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.MainModel', { 2 | extend: 'Ext.app.ViewModel', 3 | alias: 'viewmodel.main', 4 | 5 | data: { 6 | buttonResultText: '' 7 | } 8 | 9 | }) 10 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/SuitePanel.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.SuitePanel', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'suitePanel', 4 | 5 | layout: 'hbox', 6 | minHeight: 40, 7 | 8 | initComponent: function () { 9 | var self = this 10 | 11 | if (Ext.isArray(self.suiteCode)) { 12 | self.suiteCode = self.suiteCode.join('\n') 13 | } 14 | 15 | self.suiteWidth = (self.suiteWidth || 250) 16 | 17 | self.items = [{ 18 | width: self.suiteWidth, 19 | defaults: { 20 | width: (self.suiteWidth - 20), 21 | labelWidth: 80 22 | }, 23 | items: self.suiteItems 24 | }, { 25 | html: '
' + self.suiteCode + '
', 26 | flex: 1 27 | }] 28 | 29 | self.callParent(arguments) 30 | } 31 | 32 | }) 33 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/custom/Button.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.custom.Button', { 2 | extend: 'Ext.button.Button', 3 | xtype: 'customButton' 4 | }) 5 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/custom/Dataview.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.custom.Dataview', { 2 | extend: 'Ext.view.View', 3 | xtype: 'customDataview', 4 | 5 | width: 300, 6 | height: 150, 7 | border: true, 8 | itemTpl: '
{name}
', 9 | 10 | store: Ext.create('Ext.data.Store', { 11 | fields: ['name', 'count'], 12 | data: [{ 13 | name: 'Jhon Lennon', 14 | count: 3 15 | }, { 16 | name: 'Bruce Lee', 17 | count: 5 18 | }] 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/custom/Grid.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.custom.Grid', { 2 | extend: 'Ext.grid.Panel', 3 | xtype: 'customGrid', 4 | 5 | width: 300, 6 | height: 150, 7 | border: true, 8 | selModel: 'cellmodel', 9 | plugins: { 10 | ptype: 'cellediting', 11 | clicksToEdit: 1 12 | }, 13 | 14 | columns: [{ 15 | header: 'Name', 16 | dataIndex: 'name', 17 | flex: 1 18 | }, { 19 | header: 'Count', 20 | dataIndex: 'count' 21 | }, { 22 | header: 'Actions', 23 | xtype: 'actioncolumn', 24 | items: [{ 25 | iconCls: 'x-fa fa-check', 26 | handler: function () { 27 | Ext.Msg.alert('Alert', 'Test Action Column') 28 | } 29 | }, { 30 | iconCls: 'x-fa fa-car' 31 | }] 32 | }], 33 | 34 | store: Ext.create('Ext.data.Store', { 35 | fields: ['name', 'count'], 36 | data: [{ 37 | name: 'Aaa', 38 | count: 3 39 | }, { 40 | name: 'Bbb', 41 | count: 5 42 | }] 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/Buttons.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.Buttons', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabButtons', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel', 7 | 'Sandbox.view.main.custom.Button' 8 | ], 9 | 10 | title: 'Buttons', 11 | 12 | items: [{ 13 | xtype: 'suitePanel', 14 | suiteCode: 'eTT().button(\'Simple button\').isEnabled().click(done)', 15 | suiteItems: { 16 | text: 'Simple button', 17 | xtype: 'button', 18 | handler: 'onButtonsSimpleButtonClick' 19 | } 20 | }, { 21 | xtype: 'suitePanel', 22 | suiteCode: 'eTT().button(\'Disable\').click().isDisabled().isEnabled(done)', 23 | suiteItems: { 24 | text: 'Disable', 25 | xtype: 'button', 26 | handler: 'onButtonsDisableButtonClick' 27 | } 28 | }, { 29 | xtype: 'suitePanel', 30 | suiteCode: 'eTT().button(\'Button tooltip\').click().isDisabled(done)', 31 | suiteItems: { 32 | text: 'Select me by tooltip', 33 | xtype: 'button', 34 | tooltip: 'Button tooltip', 35 | handler: 'onButtonsSelectMeByTooltipButtonClick' 36 | } 37 | }, { 38 | xtype: 'suitePanel', 39 | suiteCode: 'eTT().button(\'customButton\').click().isDisabled(done)', 40 | suiteItems: { 41 | text: 'Select me by custom xtype', 42 | xtype: 'customButton', 43 | handler: 'onButtonsSelectMeByCustomXtypeButtonClick' 44 | } 45 | }] 46 | }) 47 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/Content.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.Content', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabContent', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel' 7 | ], 8 | 9 | title: 'Content', 10 | 11 | items: [{ 12 | xtype: 'suitePanel', 13 | suiteWidth: 280, 14 | suiteCode: [ 15 | 'eTT().button(\'Show result\').click(done)' 16 | ], 17 | suiteItems: [{ 18 | xtype: 'button', 19 | text: 'Show result', 20 | handler: 'onTextsShowTextButtonClick' 21 | }, { 22 | xtype: 'displayfield', 23 | labelWidth: 145, 24 | fieldLabel: 'Wait new content here', 25 | bind: { 26 | value: '{buttonResultText}' 27 | } 28 | }] 29 | }, { 30 | xtype: 'suitePanel', 31 | suiteWidth: 280, 32 | suiteCode: [ 33 | 'eTT().button(\'Hide me\').click().isHidden(done)', 34 | 'eTT().button(\'Hide me\').isVisible(done)' 35 | ], 36 | suiteItems: { 37 | xtype: 'button', 38 | text: 'Hide me', 39 | handler: 'onContentHideMeButtonClick' 40 | } 41 | }] 42 | }) 43 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/Dataview.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.Dataview', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabDataview', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel', 7 | 'Sandbox.view.main.custom.Dataview' 8 | ], 9 | 10 | title: 'Dataview', 11 | 12 | items: [{ 13 | xtype: 'suitePanel', 14 | title: 'customDataview with default itemCls', 15 | suiteWidth: 400, 16 | suiteCode: [ 17 | 'eTT().grid(\'customDataviewReference\').select(1, done)' 18 | ], 19 | suiteItems: { 20 | xtype: 'customDataview', 21 | reference: 'customDataviewReference' 22 | } 23 | }, { 24 | xtype: 'suitePanel', 25 | title: 'customDataview with itemCls = "name-item"', 26 | suiteWidth: 400, 27 | suiteCode: [ 28 | 'eTT().grid(\'customDataviewReference1\').select(0, done)' 29 | ], 30 | suiteItems: { 31 | xtype: 'customDataview', 32 | itemCls: 'name-item', 33 | reference: 'customDataviewReference1' 34 | } 35 | }] 36 | }) 37 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/Fields.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.Fields', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabFields', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel' 7 | ], 8 | 9 | title: 'Fields', 10 | 11 | items: [{ 12 | xtype: 'suitePanel', 13 | suiteCode: 'eTT().textField(\'Name\').fill(\'my text\', done)', 14 | suiteItems: { 15 | xtype: 'textfield', 16 | fieldLabel: 'Name' 17 | } 18 | }, { 19 | xtype: 'suitePanel', 20 | suiteCode: 'eTT().numberField(\'Count\').fill(13, done)', 21 | suiteItems: { 22 | xtype: 'numberfield', 23 | fieldLabel: 'Count' 24 | } 25 | }, { 26 | xtype: 'suitePanel', 27 | suiteCode: 'eTT().checkBox(\'include\').click(done)', 28 | suiteItems: { 29 | xtype: 'checkbox', 30 | boxLabel: 'include' 31 | } 32 | }, { 33 | xtype: 'suitePanel', 34 | suiteCode: [ 35 | 'eTT().radio(\'check B\').click(done)', 36 | 'eTT().radio(\'check A\').click(done)' 37 | ], 38 | suiteItems: [{ 39 | xtype: 'radio', 40 | boxLabel: 'check A', 41 | name: 'checkMe', 42 | value: 'a' 43 | }, { 44 | xtype: 'radio', 45 | boxLabel: 'check B', 46 | name: 'checkMe', 47 | value: 'b' 48 | }] 49 | }, { 50 | xtype: 'suitePanel', 51 | suiteCode: 'eTT().comboBox(\'Select in list\').select(1, done)', 52 | suiteItems: { 53 | xtype: 'combobox', 54 | fieldLabel: 'Select in list', 55 | editable: false, 56 | store: [ 57 | ['a', 'Position A'], 58 | ['b', 'Position B'] 59 | ] 60 | } 61 | }] 62 | }) 63 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/Grids.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.Grids', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabGrids', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel', 7 | 'Sandbox.view.main.custom.Grid' 8 | ], 9 | 10 | title: 'Grids', 11 | 12 | items: [{ 13 | xtype: 'suitePanel', 14 | suiteWidth: 400, 15 | suiteCode: [ 16 | 'eTT().grid(\'Names\').select(1, done)', 17 | 'eTT().grid(\'Names\').select(0, done)', 18 | 'eTT().grid(\'Names\').checkRowsCount(2, done)' 19 | ], 20 | suiteItems: { 21 | xtype: 'customGrid', 22 | title: 'Names' 23 | } 24 | }, { 25 | xtype: 'suitePanel', 26 | suiteWidth: 400, 27 | suiteCode: 'eTT().grid(\'customGridReference\').select(0, 0).select(0, 1).select(1, 1).select(1, 0, done)', 28 | suiteItems: { 29 | xtype: 'customGrid', 30 | reference: 'customGridReference' 31 | } 32 | }, { 33 | xtype: 'suitePanel', 34 | suiteWidth: 400, 35 | suiteCode: [ 36 | 'eTT().grid(\'Cell editing\').cellEditor(1, 0).select(0, done)', 37 | 'eTT().grid(\'Cell editing\').cellEditor(0, 0).select(2, done)', 38 | 'eTT().grid(\'Cell editing\').cellEditor(0, 2).fill(\'test1\', done)', 39 | 'eTT().grid(\'Cell editing\').cellEditor(1, 2).fill(\'test2\', done)', 40 | 'eTT().grid(\'Cell editing\').cellEditor(0, 3).click(done)', 41 | 'eTT().grid(\'Cell editing\').cellEditor(1, 3).click(done)' 42 | ], 43 | suiteItems: { 44 | title: 'Cell editing', 45 | xtype: 'customGrid', 46 | columns: [{ 47 | header: 'Name', 48 | dataIndex: 'name', 49 | flex: 1, 50 | editor: { 51 | xtype: 'combobox', 52 | store: [['Aaa', 'Aaa'], ['Bbb', 'Bbb'], ['Ccc', 'Ccc']], 53 | editable: false 54 | } 55 | }, { 56 | header: 'Count', 57 | dataIndex: 'count' 58 | }, { 59 | header: 'Comment', 60 | dataIndex: 'comment', 61 | editor: { 62 | xtype: 'textfield' 63 | } 64 | }, { 65 | header: 'Enabled', 66 | dataIndex: 'enabled', 67 | editor: { 68 | xtype: 'checkbox' 69 | } 70 | }] 71 | } 72 | }] 73 | }) 74 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/LoadMasks.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.LoadMasks', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabLoadMasks', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel' 7 | ], 8 | 9 | title: 'LoadMasks', 10 | 11 | items: [{ 12 | xtype: 'suitePanel', 13 | suiteCode: [ 14 | 'eTT().button(\'Show component\').click(done)', 15 | 'eTT().waitLoadMask(done)' 16 | ], 17 | suiteItems: { 18 | xtype: 'button', 19 | text: 'Show global', 20 | handler: 'onLoadMasksShowGlobalButtonClick' 21 | } 22 | }, { 23 | xtype: 'suitePanel', 24 | suiteCode: [ 25 | 'eTT().button(\'Show global\').click(done)', 26 | 'eTT().waitLoadMask(done)' 27 | ], 28 | suiteItems: { 29 | xtype: 'button', 30 | text: 'Show component', 31 | handler: 'onLoadMasksShowComponentButtonClick' 32 | } 33 | }] 34 | }) 35 | -------------------------------------------------------------------------------- /test/sandbox/app/view/main/tab/Windows.js: -------------------------------------------------------------------------------- 1 | Ext.define('Sandbox.view.main.tab.Windows', { 2 | extend: 'Ext.panel.Panel', 3 | xtype: 'tabWindows', 4 | 5 | requires: [ 6 | 'Sandbox.view.main.SuitePanel' 7 | ], 8 | 9 | title: 'Windows', 10 | 11 | items: [{ 12 | xtype: 'suitePanel', 13 | suiteCode: [ 14 | 'eTT().button(\'Show confirm\').click(done)', 15 | 'eTT().window(\'Confirm\', done)', 16 | 'eTT().window(\'Confirm\').button(\'Yes\').isEnabled().click(done)', 17 | 'eTT().no.window(\'Confirm\', done)' 18 | ], 19 | suiteItems: { 20 | xtype: 'button', 21 | text: 'Show confirm', 22 | handler: 'onWindowsShowConfirmButtonClick' 23 | } 24 | }, { 25 | xtype: 'button', 26 | text: 'Yes' 27 | }] 28 | }) 29 | -------------------------------------------------------------------------------- /test/sandbox/bootstrap.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * This file is generated by Sencha Cmd and should NOT be edited. It redirects 5 | * to the most recently built CSS file for the application to allow index.html 6 | * in the development directory to load properly (i.e., "dev mode"). 7 | */ 8 | @import 'build/production/Sandbox/classic/resources/Sandbox-all.css'; 9 | 10 | -------------------------------------------------------------------------------- /test/sandbox/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/sandbox/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Sandbox 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test/sandbox/workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * An object containing key value pair framework descriptors. 4 | * 5 | * The value can be a string or an object containing at least one of "dir" or "pkg", 6 | * where "dir" can be a filesystem path to the framework sources and "pkg" can be a 7 | * package name. For example: 8 | * 9 | * "frameworks": { 10 | * 11 | * "ext-x": "/absolute/path/to/ext", 12 | * "ext-y": { 13 | * "source": "../relative/path/to/ext", 14 | * "path": "ext" 15 | * }, 16 | * "ext-z": { 17 | * "package": "ext@n.n.n", 18 | * "path": "ext-n.n.n" 19 | * }, 20 | * "touch": "touch" 21 | * } 22 | * 23 | */ 24 | "frameworks": { 25 | "ext": "ext" 26 | 27 | }, 28 | 29 | /** 30 | * This is the folder for build outputs in the workspace. 31 | */ 32 | "build": { 33 | "dir": "${workspace.dir}/build" 34 | }, 35 | 36 | /** 37 | * These configs determine where packages are generated and extracted to (when downloaded). 38 | */ 39 | "packages": { 40 | /** 41 | * This folder contains all local packages. 42 | * If a comma-separated string is used as value the first path will be used as the path to generate new packages. 43 | */ 44 | "dir": "${workspace.dir}/packages/local,${workspace.dir}/packages", 45 | 46 | /** 47 | * This folder contains all extracted (remote) packages. 48 | */ 49 | "extract": "${workspace.dir}/packages/remote" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/suites/010-environment.js: -------------------------------------------------------------------------------- 1 | describe('Check environment', function () { 2 | it('Ext', function () { 3 | expect(Ext).to.be.an('object') 4 | }) 5 | 6 | it('Sandbox', function () { 7 | expect(Sandbox).to.be.an('object') 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /test/suites/020-buttons.js: -------------------------------------------------------------------------------- 1 | describe('Buttons', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch to "Buttons" tab', function (done) { 6 | eTT().tab('Buttons').click(done) 7 | }) 8 | 9 | it('Click "Simple button" button', function (done) { 10 | eTT().button('Simple button').isEnabled().click(done) 11 | }) 12 | 13 | it('Click "Disable" button and wait state changed to "enabled"', function (done) { 14 | eTT().button('Disable').click().isDisabled().isEnabled(done) 15 | }) 16 | 17 | it('Click "Select me by tooltip" button and wait state changed to "disabled"', function (done) { 18 | eTT().button('Button tooltip').click().isDisabled(done) 19 | }) 20 | 21 | it('Click "Select me by custom xtype" button and wait state changed to "disabled"', function (done) { 22 | eTT().button('customButton').click().isDisabled(done) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/suites/030-windows.js: -------------------------------------------------------------------------------- 1 | describe('Windows', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch to "Windows" tab', function (done) { 6 | eTT().tab('Windows').click(done) 7 | }) 8 | 9 | it('Click "Show confirm" button', function (done) { 10 | eTT().button('Show confirm').click(done) 11 | }) 12 | 13 | it('window "Confirm" should be presented', function (done) { 14 | eTT().window('Confirm', done) 15 | }) 16 | 17 | it('click on "Yes" button in "Confirm" window', function (done) { 18 | eTT().window('Confirm').button('Yes').isEnabled().click(done) 19 | }) 20 | 21 | it('window "Confirm" should be hidden', function (done) { 22 | eTT().no.window('Confirm', done) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/suites/040-fields.js: -------------------------------------------------------------------------------- 1 | describe('Fields', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch to "Fields" tab', function (done) { 6 | eTT().tab('Fields').click(done) 7 | }) 8 | 9 | it('Fill "Text" filed', function (done) { 10 | eTT().textField('Name').fill('my text', done) 11 | }) 12 | 13 | it('Fill "Number" filed', function (done) { 14 | eTT().numberField('Count').fill(13, done) 15 | }) 16 | 17 | it('Click on checkbox "include"', function (done) { 18 | eTT().checkBox('include').click(done) 19 | }) 20 | 21 | it('Click on radio "check B"', function (done) { 22 | eTT().radio('check B').click(done) 23 | }) 24 | 25 | it('Click on radio "check A"', function (done) { 26 | eTT().radio('check A').click(done) 27 | }) 28 | 29 | it('Click on combobox "Select in list"', function (done) { 30 | eTT().comboBox('Select in list').select(1, done) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /test/suites/050-grids.js: -------------------------------------------------------------------------------- 1 | describe('Grids', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch to "Grids" tab', function (done) { 6 | eTT().tab('Grids').click(done) 7 | }) 8 | 9 | it('Click on second "Names" grid row', function (done) { 10 | eTT().grid('Names').select(1, done) 11 | }) 12 | 13 | it('Click on first "Names" grid row', function (done) { 14 | eTT().grid('Names').select(0, done) 15 | }) 16 | 17 | it('Rows number should be equal 2', function (done) { 18 | eTT().grid('Names').checkRowsCount(2, done) 19 | }) 20 | 21 | it('Click on first action in first row of "Names" grid', function (done) { 22 | eTT().grid('Names').clickAction(0, 2, 0, function () { 23 | eTT().button('OK').click(done) 24 | }) 25 | }) 26 | 27 | it('Click on second action in first row of "Names" grid', function (done) { 28 | eTT().grid('Names').clickAction(0, 2, 1, done) 29 | }) 30 | 31 | it('Click on second action in second row of "Names" grid', function (done) { 32 | eTT().grid('Names').clickAction(1, 2, 1, done) 33 | }) 34 | 35 | it('Click on cells of second grid', function (done) { 36 | eTT().grid('customGridReference').select(0, 0).select(0, 1).select(1, 1).select(1, 0, done) 37 | }) 38 | 39 | it('Edit "Cell editing" grid row #2, select item #1', function (done) { 40 | eTT().grid('Cell editing').cellEditor(1, 0).select(0, done) 41 | }) 42 | 43 | it('Edit "Cell editing" grid #1 row, select item #3', function (done) { 44 | eTT().grid('Cell editing').cellEditor(0, 0).select(2, done) 45 | }) 46 | 47 | it('Edit "Cell editing" grid #1 row, fill column #3 with "test1"', function (done) { 48 | eTT().grid('Cell editing').cellEditor(0, 2).fill('test1', done) 49 | }) 50 | 51 | it('Edit "Cell editing" grid #2 row, fill column #3 with "test2"', function (done) { 52 | eTT().grid('Cell editing').cellEditor(1, 2).fill('test2', done) 53 | }) 54 | 55 | it('Edit "Cell editing" grid #1 row, check column #3', function (done) { 56 | eTT().grid('Cell editing').cellEditor(0, 3).click(done) 57 | }) 58 | 59 | it('Edit "Cell editing" grid #2 row, check column #3', function (done) { 60 | eTT().grid('Cell editing').cellEditor(1, 3).click(done) 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /test/suites/060-dataview.js: -------------------------------------------------------------------------------- 1 | describe('Dataview', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch to "Dataview" tab', function (done) { 6 | eTT().tab('Dataview').click(done) 7 | }) 8 | 9 | it('Click on second "customDataviewReference" dataview item', function (done) { 10 | eTT().dataview('customDataviewReference').select(1, done) 11 | }) 12 | 13 | it('Click on first "customDataviewReference1" dataview item with itemCls', function (done) { 14 | eTT().dataview('customDataviewReference1').select(0, done) 15 | }) 16 | }) 17 | 18 | -------------------------------------------------------------------------------- /test/suites/070-loadmasks.js: -------------------------------------------------------------------------------- 1 | describe('LoadMasks', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch to "LoadMasks" tab', function (done) { 6 | eTT().tab('LoadMasks').click(done) 7 | }) 8 | 9 | it('Click on "Show component" button', function (done) { 10 | eTT().button('Show component').click(done) 11 | }) 12 | 13 | it('Load mask should disappear in 10s', function (done) { 14 | eTT().waitLoadMask(done) 15 | }) 16 | 17 | it('Click on "Show global" button', function (done) { 18 | eTT().button('Show global').click(done) 19 | }) 20 | 21 | it('Load mask should disappear in 10s', function (done) { 22 | eTT().waitLoadMask(done) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/suites/080-content.js: -------------------------------------------------------------------------------- 1 | describe('Content', function () { 2 | this.bail(true) 3 | this.timeout(20 * 1000) 4 | 5 | it('Switch ot "Content" tab', function (done) { 6 | eTT().tab('Content').click(done) 7 | }) 8 | 9 | it('Click on "Show result" button', function (done) { 10 | eTT().button('Show result').click(done) 11 | }) 12 | 13 | it('Text "Result is here!" should appears in 1s', function (done) { 14 | eTT().waitText('Result is here!', done) 15 | }) 16 | 17 | it('"Hide me" button should be hidden after click', function (done) { 18 | eTT().button('Hide me').click().isHidden(done) 19 | }) 20 | 21 | it('"Hide me" button should be visible again', function (done) { 22 | eTT().button('Hide me').isVisible(done) 23 | }) 24 | }) 25 | --------------------------------------------------------------------------------