2013-07-29 68 views
3

我想使用茉莉花爲Sencha Touch 2應用程序設置適當的測試環境。如何在使用茉莉花測試時配置我的Sencha Touch應用程序文件的加載順序

我用這個教程的前三部分我的第一個步驟:

我實際的問題是: 2配置項對於我的兩個類(一個存儲和一個視圖)需要調用我的主要應用程序對象respe的方法/讀取屬性激活Ext.Viewport對象。

混凝土:

1)我的商店之一在我的應用的主要命名空間(MyAppName.app.backendUrl)

Ext.define('MyAppName.store.MyStore', { 
    extend: 'Ext.data.Store', 

    config: { 
     model: 'MyAppName.model.MyModel', 

     proxy: { 
      type: 'ajax', 
      url: MyAppName.app.backendUrl + '/data.json', 
      reader: 'json' 
     }, 

     autoLoad: true 
    } 
}); 

2.)的我的視圖中的一個確實呼叫讀取值在Ext.Viewport的方法(Ext.Viewport.getOrientation()):

Ext.define('MyAppName.view.LoginView', { 
    extend: 'Ext.form.Panel', 
    alias: "widget.loginview", 
    config: { 
     title: 'Login', 
     items: [ 
      { 
       xtype: 'image', 
       src: Ext.Viewport.getOrientation() == 'portrait' ? '../../../img/login.png' : '../../../img/login-small.png', 
       style: Ext.Viewport.getOrientation() == 'portrait' ? 'width:80px;height:80px;margin:auto' : 'width:40px;height:40px;margin:auto' 
      } 
     ] 
    } 
}); 

不幸的是,這種崩潰,因爲這兩個對象(MyAppName和Ext.Viewport)時,這些調用是由尚未確定。 這只是測試設置的情況(正如本教程所概述的,僅針對測試有一個特定的app.js)。當我在瀏覽器中運行實際的應用程序時(通過'普通'app.js),這個問題不會發生。

這怎麼可能被修復(所以:我如何確保我的視圖/商店文件運行後,MyAppname.app和Ext.Viewport已經存在)?

非常感謝。

回答

1

您需要的投機/ JavaScript的/支持/ jasmime.yml的你以正確的順序需要的文件:

src_files: 
    - touch/sencha-touch-all-debug.js # Load Sencha library 
    - spec/app.js     # Load our spec Ext.Application 
    - app/util/Urls.js #custom dependency 
    - app/**/*.js     # Load source files 
+0

感謝很多的提示。我在YML文件按以下順序: - 觸摸/煎茶 - 觸摸全debug.js - 規格/ app.js - 應用程序/ **/* JS 但我的問題不是外部。依賴關係(Sencha框架本身除外,但應該包含在第一行'touch/sencha-touch-all-debug.js'中),但事實上類似於 Ext.Viewport.getOrientation()不起作用當在配置散列級別上使用它們時(如我的問題所述),因爲Ext尚未定義(它表示「無法調用未定義的方法'getOrientation')。我不明白爲什麼。 – spaudanjo

+0

哦,好的。我認爲這是因爲視口(因此Ext.Viewport)僅在您調用Ext.application上的方法啓動時才創建。也許你需要在茉莉花測試中手動觸發它。 http://docs.sencha.com/touch/2.2.1/source/Application.html#Ext-app-Application這裏是這個源代碼,如果你搜索「autoCreateViewport」,你會發現它現在是在發佈時創建。希望有所幫助。 –

2

我發現,運行Ext.application通常會打開一個中的觀點,你通常不希望單元測試 - 否則你冒險進入集成測試,所以我避免使用Sencha開發裝載機。相反,我使用Karma來加載單元測試和應用程序類文件。您可以在karma.conf.js文件中配置這些文件(如下所示)。

我調整了Pivotal Labs出色的單元測試教程中的例子。由於Karma具有內置的Web服務器,因此您不需要Rails,Rake或pow,如their 1st tutorial所述。使用Karma意味着您可以輕鬆地將單元測試與IntelliJ IDEA或WebStorm等Javascript工具以及CI系統和雲測試(如https://saucelabs.com/)相集成。你也可以配置它來觀察你的代碼文件和更新它們時自動重新運行單元測試。您也可以使用karma-istanbul來執行代碼覆蓋率分析。

使用我學到的技巧here,我運行了一個setup.js文件,該文件在我的karma.conf.js文件中配置以在單元測試之前加載。它創建一個虛假的應用程序對象,以便控制器可以將自己分配給應用程序實例,並且它故意沒有launch()方法。它還包含Pivotal Labs示例中的SpecHelper.js代碼。

// Create (but don't launch) the app 
Ext.application({name: 'MyAppName' }); 

對於視圖單元測試問題,則可以創建一個假Ext.Viewport對象並添加spyOn()。andReturn()來假由測試期間視圖所需的Ext.Viewport.getOrientation()方法。這意味着你的單元測試可以很容易地涵蓋兩種定位情況。

describe("when portrait orientation", function() { 
    var view; 
    beforeEach(function() { 
    if (!Ext.Viewport) Ext.Viewport = {};  
    spyOn(Ext.Viewport, 'getOrientation').andReturn('portrait'); 
    view = Ext.create('MyAppName.view.LoginView', { 
     renderTo: 'jasmine_content' 
    } 
    } 

    it("should render large image", function() { 
     expect(Ext.DomQuery.select('...')).toContain('img/login.png'); 
    }); 

    it("should render 80px style", function() { 
     expect(Ext.DomQuery.select('...')).toContain('80px'); 
    });   
}); 

查看單元測試(說明如何使用renderTo屬性):您還測試,以檢查渲染視圖中添加renderTo:屬性。

我下面setup.js文件顯示,包括來自SpecHelper.js這裏顯示的代碼。 您需要使用renderTo屬性。

控制器單元測試涉及如何將控制器連接到你的假的應用實例。

setup.js 此代碼竊取噶裝載伎倆從here但不像他們的榜樣它避免了用發展的裝載機。

Ext.Loader.setConfig({ 
    enabled: true,     // Turn on Ext.Loader 
    disableCaching: false   // Turn OFF cache BUSTING 
}); 

// 'base' is set by Karma to be __dirname of karm.conf.js file 
Ext.Loader.setPath({ 
    'Ext': 'base/touch/src', 
    'MyAppName': 'base/app' 
}); 

// Create (but don't launch) the app 
Ext.application({name: 'MyAppName' }); 

Ext.require('Ext.data.Model'); 
afterEach(function() { 
    Ext.data.Model.cache = {};  // Clear any cached models 
}); 

var domEl; 
beforeEach(function() {   // Reset the div with a new one. 
    domEl = document.createElement('div'); 
    domEl.setAttribute('id', 'jasmine_content'); 
    var oldEl = document.getElementById('jasmine_content'); 
    if (oldEl) oldEl.parentNode.replaceChild(domEl, oldEl); 
}); 

afterEach(function() {    // Make the test runner look pretty 
    domEl.setAttribute('style', 'display:none;'); 
}); 

// Karma normally starts the tests right after all files specified in 'karma.config.js' have been loaded 
// We only want the tests to start after Sencha Touch/ExtJS has bootstrapped the application. 
// 1. We temporary override the '__karma__.loaded' function 
// 2. When Ext is ready we call the '__karma__.loaded' function manually 
var karmaLoadedFunction = window.__karma__.loaded; 
window.__karma__.loaded = function() {}; 

Ext.onReady(function() { 
    console.info("Starting Tests ..."); 
    window.__karma__.loaded = karmaLoadedFunction; 
    window.__karma__.loaded(); 
}); 

karma.conf.js

module.exports = function(config) { 
    config.set({ 

     // base path that will be used to resolve all patterns (eg. files, exclude) 
     basePath: '', 

     // frameworks to use 
     // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 
     frameworks: ['jasmine'], 

     // Don't use Sencha Touch dynamic loading 
     files: [ 
      'touch/sencha-touch-all-debug.js', 
      'spec/Setup.js',  // Load stubbed app - does not call app.launch() 
      { pattern: 'spec/**/*.js',   watched: true, served: true, included: true }, 
      { pattern: 'app/**/*.js',   watched: true, served: true, included: false}, 
      // Some class are not loaded by sencha-touch-all-debug.js 
      // this tell Karma web server that it's ok to serve them. 
      { pattern: 'touch/src/**/*.*',  watched: false, served: true, included: false} 
     ], 

//  // Use Sencha Touch static 'testing' app.js 
//  files: [ 
//   './build/testing/PT/app.js', 
//   './spec/SetUp.js', 
//   './spec/**/*.js' 
//  ], 

     // list of files to exclude 
     exclude: [ 
     ], 

     // preprocess matching files before serving them to the browser 
     // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 
     preprocessors: { 
     }, 

     // test results reporter to use 
     // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 
     // available reporters: https://npmjs.org/browse/keyword/karma-reporter 
     reporters: ['progress'], 

     // web server port 
     port: 9876, 

     // enable/disable colors in the output (reporters and logs) 
     colors: true, 

     // level of logging 
     // possible values: config.LOG_DISABLE/.LOG_ERROR/.LOG_WARN/.LOG_INFO/.LOG_DEBUG 
     logLevel: config.LOG_INFO, 

     // enable/disable watching file and executing tests whenever any file changes 
     autoWatch: true, 

     // start these browsers 
     // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 
     // Start these browsers, currently available: 
     // - Chrome 
     // - ChromeCanary 
     // - Firefox 
     // - Opera (has to be installed with `npm install karma-opera-launcher`) 
     // - Safari (only Mac; has to be installed with `npm install 
     // karma-safari-launcher`) 
     // - PhantomJS 
     // - IE (only Windows; has to be installed with `npm install 
     // karma-ie-launcher`) 
     //browsers: [ 'PhantomJS' ], 
     browsers: ['Chrome'], 

     // If browser does not capture in given timeout [ms], kill it 
     captureTimeout: 60000, 

     // Continuous Integration mode 
     // if true, Karma captures browsers, runs the tests and exits 
     singleRun: false 
    }); 
}; 
+0

如果您使用的是IntelliJ IDEA/WebStorm/PhpStorm,您可能想查看這些JetBrains文章[代碼覆蓋率](https://www.jetbrains.com/idea/webhelp/monitoring-code-coverage-for-javascript .html)和[Karma](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7) –

0

一個辦法來解決這個問題將是從initComponent定義項目。這樣它不會被調用,直到實例化,而不是在啓動時。

Ext.define('MyAppName.view.LoginView', { 
    extend: 'Ext.form.Panel', 
    alias: "widget.loginview", 
    config: { 
     title: 'Login' 
    }, 

    initComponent: function() { 
     this.items = [ 
      { 
       xtype: 'image', 
       src: Ext.Viewport.getOrientation() == 'portrait' ? '../../../img/login.png' : '../../../img/login-small.png', 
       style: Ext.Viewport.getOrientation() == 'portrait' ? 'width:80px;height:80px;margin:auto' : 'width:40px;height:40px;margin:auto' 
      } 
     ]; 
     this.callParent(); 

    } 
}); 

而對於實體店同樣的事情,但在構造

Ext.define('MyAppName.store.MyStore', { 
    extend: 'Ext.data.Store', 

    config: { 
     model: 'MyAppName.model.MyModel', 

     autoLoad: true 
    }, 

    constructor: function(cfg) { 
     this.proxy = { 
      type: 'ajax', 
      url: MyAppName.app.backendUrl + '/data.json', 
      reader: 'json' 
     }; 
     this.callParent(arguments) 
    } 
});