在使用Jasmine进行测试时,如何配置Sencha Touch应用程序文件的加载顺序

时间:2013-07-29 15:07:41

标签: extjs sencha-touch sencha-touch-2 jasmine sencha-touch-2.2

我想使用jasmine为Sencha Touch 2应用设置适当的测试环境。

我使用本教程的前三部分来完成我的第一步:

我的实际问题如下: 我的两个类(一个存储和一个视图)的两个配置条目需要分别调用我的主应用程序对象的方法/读取属性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已经存在之后运行)?

非常感谢。

3 个答案:

答案 0 :(得分:2)

我发现运行Ext.application通常会打开您在单元测试期间通常不需要的视图 - 否则您将进入集成测试,因此我避免使用Sencha开发加载器。相反,我使用Karma加载单元测试和应用程序类文件。您可以在karma.conf.js文件中配置这些文件(例如下面的例子)。

我改编了Pivotal Labs出色的单元测试教程中的例子。由于Karma有内置的Web服务器,因此their 1st tutorial描述的不需要Rails,Rake或pow。使用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()和.Return()来伪造视图在测试期间所需的Ext.Viewport.getOrientation()方法。这意味着您的单元测试可以轻松涵盖两种方向案例。您还可以在测试期间添加renderTo:属性以检查渲染视图:

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属性)。

我的setup.js文件如下所示,包含此处显示的SpecHelper.js代码。 您需要使用此renderTo属性。

控制器单元测试涵盖了如何将控制器连接到假应用程序实例。

<强> setup.js 此代码从here窃取了一个Karma加载技巧,但与其示例不同,它避免使用开发加载程序。

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
    });
};

答案 1 :(得分:1)

您需要以正确的顺序spec / javascripts / support / 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

答案 2 :(得分: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)
    }
});