Закрытая переменная javascript не указывает на общий объект в модульном тесте - PullRequest
0 голосов
/ 28 октября 2018

У нас есть приложение SPA с переменной общего объема var WIDGET . Каждый модуль добавляет себя к общему объекту WIDGET или создает WIDGET , если он не был создан.

При использовании нескольких платформ для модульных тестов общий WIDGET доступен, но переменная в требуемых файлах не указывает на него.

var WIDGET = WIDGET || {};

если я изменю эту строку кода на WIDGET = WIDGET || {} или если я удаляю все это вместе, то объекты будут работать так, как ожидается в модульном тесте

что нужно знать:

  • мы НЕ используем nodejs в производстве, это только для тестирования
  • код выполняется правильно в производстве
  • тестовые рамки были мокко и шутка

Q1 что я могу сделать, чтобы частная переменная указывала на общий объект при модульном тестировании?

Q2, почему это происходит при тестировании, а не в DOM во время выполнения приложения?

test application creation: TypeError: Cannot read property 'getInstance' of undefined at new widget_application (widgetApplication.js:23:41) at Object.getInstance (widgetApplication.js:33:16) at Context.<anonymous> (test\testApp.js:16:39)

первый модуль, который добавляет себя в WIDGET объект

var _WIDGET_ = _WIDGET_ || {};
//adds itself to the _WIDGET_ to be shared
_WIDGET_.widgetLogger = (function(){
    var INSTANCE;
    var _config = {};
    var _widgetLog = {};

    function widget_logger(config){
        if(config){_config = config;}
    }

    widget_logger.prototype.stageLog = stageLog;
    // widget_logger.prototype.startUpLog = startUpLog;
    // widget_logger.prototype.dataRefreshLog = dataRefreshLog;
    // widget_logger.prototype.widgetNotReadyLog = widgetNotReadyLog;
    // widget_logger.prototype.finalizeLog = finalizeLog;
    // widget_logger.prototype.getLog = getLog;

    return {
        getInstance:function(c){
            if(!INSTANCE){
                INSTANCE = new widget_logger(c);
            }
            return INSTANCE;
        }
    };

    function stageLog(data) {
        console.log("widget logger called to stage log");
        if(data){

            _widgetLog = {};
            _legacyLog = {};

            _widgetLog.widgetProgramCode = _config.versionData.programCode;
            _widgetLog.widgetVersion = _config.versionData.version;
            _widgetLog.startTime = data.startTime || new Date();

            console.log("widget logger staged this log ",_widgetLog);

        }
    }

})();

//export is only for testing - nodejs NOT used in production
var module = module || {};
module.exports = _WIDGET_;

следующий модуль, который добавляет себя и использует модуль логгера

var _WIDGET_ = _WIDGET_ || {};//remove this line of code and unit test run
var _API_ = _API_ || {};
_WIDGET_.smallApplication = (function(){

    var INSTANCE;
    var widgetLogger;
    var _config = {
        versionData:{
            programCode:"smallApplication",
            version:"1.0.2.0"
        }
    };

    function widget_application(config){
        console.log("make the instance ");
        // var elem = document.getElementById('apprunning');
        // elem.innerHTML += "    smallApplication is online ";
        if(config){_config = config;}
        //expects to have a shared object already
        //fails after this call because this module create a new _WIDGET_ variable
    //this does not happen in production - all components are created
        widgetLogger = _WIDGET_.widgetLogger.getInstance(_config);
    }

    widget_application.prototype.runApplication = runApplication;


    return {
        getInstance:function(c){
            console.log("get instance was called");
            if(!INSTANCE){
                INSTANCE = new widget_application(c);
            }
            return INSTANCE;
        }
    };

    //run some functions and hello world and all that happiness...
    function runApplication(){
        console.log("widget application runs - will call logger");
        widgetLogger.stageLog(true);
    }

})();

//export is only for testing - nodejs NOT used in production
var module = module || {};
module.exports = _WIDGET_;

Скрипт теста мокко

var assert = require('assert');

_WIDGET_ = {name: 'small application'};

describe('small application',function(){
    //_WIDGET_ = {name: 'small application'};
    //var _WIDGET_ {name: 'small application'};
    //global._WIDGET_ {name: 'small application'};
    it('test logger creation',function(){
        _WIDGET_ = require('../widgetLogger');
        console.log('_WIDGET_');
    });
    it('test application creation',function(){
        var app = require('../widgetApplication');
        _WIDGET_ = require('../widgetApplication');
    });
});

от А2 до Q2 найдено в свободный код лагеря - требуются модули В браузере, когда мы объявляем переменную в сценарии, например:

var answer = 42;

Эта переменная ответа будет доступна во всех сценариях после сценария, который ее определил.

Это не относится к Node. Когда мы определяем переменную в одном модуле, другие модули в программе не будут иметь доступа к этой переменной. Так почему же переменные в Node магически ограничены?

Ответ прост. Перед компиляцией модуля Node упаковывает код модуля в функцию, которую мы можем проверить с помощью свойства wrapper модуля module.

1 Ответ

0 голосов
/ 30 октября 2018

Большое Спасибо за бесплатный код лагеря

Они упростили задачу увидеть, что node.js require('module') упаковывает модуль в функцию ().

Это помогло мне понять, что мне нужно собрать мои модули в один файл для тестирования.Затем require ('minifiedModules')

в моих модульных тестах код выглядит как

var _Widget_ = require('minifiedModules');
var app;

test('verify _Widget_',function(){
    //testing with jest
    expect(_Widget_.widgetLogger).toBeDefined();
    expect(_Widget_.smallApplication).toBeDefined();
});

test('instantiate app',function(){
    app = _Widget_.smallApplication.getInstance();
});

test('run app',function(){
    app.runApplication();
});

, и теперь запуск npm test работает

> jest

 PASS  ./app.test.js
  √ _WIDGET_ objects (34ms)
  √ instantiate app (5ms)
  √ run app (5ms)

  console.log app.test.js:23
    Widget objects  { widgetLogger: { getInstance: [Function: getInstance] },
      smallApplication: { getInstance: [Function: getInstance] } }

  console.log test/scripts/services/services.min.js:87
    get instance was called

  console.log test/scripts/services/services.min.js:71
    make the instance

  console.log test/scripts/services/services.min.js:78
    no way this works, _WIDGET_,  { widgetLogger: { getInstance: [Function: getInstance] },
      smallApplication: { getInstance: [Function: getInstance] } }

  console.log test/scripts/services/services.min.js:97
    widget application runs - will call logger

  console.log test/scripts/services/services.min.js:30
    widget logger called to stage log

  console.log test/scripts/services/services.min.js:40
    widget logger staged this log  { widgetProgramCode: 'smallApplication',
      widgetVersion: '1.0.2.0',
      startTime: 2018-10-30T03:41:10.815Z }

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        2.067s
Ran all test suites.
...