Как настроить порядок загрузки файлов моего приложения Sencha Touch при тестировании с Jasmine

Я хотел бы настроить надлежащую среду тестирования для приложения Sencha Touch 2 с использованием jasmine.

Я использовал первые три части этого руководства для своих первых шагов:

Моя фактическая проблема заключается в следующем: две записи конфигурации для двух моих классов (одно хранилище и одно представление) должны вызывать методы/чтение свойств моего основного объекта приложения, соответственно, объекта 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.getOrientation()) в Ext.Viewport:

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 уже существуют)?

Большое спасибо.


person spaudanjo    schedule 29.07.2013    source источник


Ответы (3)


Я обнаружил, что запуск Ext.application обычно открывает представления, которые вам обычно не нужны во время модульного тестирования. В противном случае вы рискуете приступить к интеграционному тестированию, поэтому я избегаю использования разработки Sencha. погрузчик. Вместо этого я использую Karma для загрузки модульных тестов и файлов классов приложений. Вы настраиваете эти файлы внутри файла karma.conf.js (пример ниже).

Я адаптировал примеры из отличных руководств по модульному тестированию от Pivotal Labs. Поскольку у Karma есть встроенный веб-сервер, вам не нужны Rails, Rake или pow as их первый урок описывает. Использование Karma означает, что вы можете легко интегрировать свои модульные тесты с инструментами Javascript, такими как IntelliJ IDEA или WebStorm, а также с системами CI и облачными тестами, такими как https://saucelabs.com/ . Вы также можете настроить его для просмотра файлов кода и автоматического повторного запуска модульных тестов при их обновлении. Вы также можете использовать karma-istanbul для анализа покрытия кода.

Используя прием, который я изучил здесь , я запускаю файл setup.js, который настроен в моем файле karma.conf.js для загрузки перед модульными тестами. Он создает поддельный объект приложения, чтобы контроллеры могли назначать себя экземпляру приложения, и он намеренно не имеет метода launch(). Он также включает код SpecHelper.js из примера Pivotal Labs.

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

Для вопроса о модульном тесте представления вы можете создать поддельный объект Ext.Viewport и добавить spyOn().andReturn() для имитации метода 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 Этот код крадет трюк загрузки 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
    });
};
person Tony O'Hagan    schedule 29.09.2014
comment
Если вы используете IntelliJ IDEA/WebStorm/PhpStorm, вы можете ознакомиться с этими статьями JetBrains на странице покрытие кода и Карма - person Tony O'Hagan; 09.10.2014

Вам нужно указать /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
person Florent Lamoureux    schedule 02.08.2013
comment
Большое спасибо за подсказку. У меня в файле yml следующий порядок: - touch/sencha-touch-all-debug.js - spec/app.js - app/**/*.js Но моя проблема не во внешней зависимости (кроме Sencha framework, но это должно быть включено первой строкой 'touch/sencha-touch-all-debug.js'), но тот факт, что такие вещи, как Ext.Viewport.getOrientation(), не работают при их использовании в хеше конфигурации уровень (как описано в моем вопросе), потому что Ext еще не определен (он говорит, что не может вызвать метод «getOrientation» из неопределенного). Я не понимаю, почему. - person spaudanjo; 05.08.2013
comment
Ох, хорошо. Я думаю, это потому, что область просмотра (и, следовательно, Ext.Viewport) создается только тогда, когда вы вызываете запуск метода в Ext.application. Возможно, вам нужно запустить его вручную в тестах жасмина. docs.sencha.com/touch/2.2. 1/source/ вот исходный код для этого, если вы ищете autoCreateViewport, вы увидите, что теперь он создается во время запуска. Надеюсь, это поможет. - person Florent Lamoureux; 06.08.2013

Один из способов обойти эту проблему — определить элементы из 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)
    }
});
person Juan Mendes    schedule 12.10.2014