1

We have an SPA application with a shared scope variable var WIDGET. Each module adds itself to the shared WIDGET object or creates the WIDGET if it was not created.

Using a couple of frameworks for unit tests the shared WIDGET is available but the variable on the required files do not point to it.

var WIDGET = WIDGET || {};

if I change this line of code to WIDGET = WIDGET || {} or if I remove it all together then the objects will work as expected in the unit test

things to know:

  • we do NOT use nodejs in production, it is just for testing
  • code executes properly in production
  • test frameworks have been mocha and jest

Q1 what can I do to ensure the private variable is pointing to the shared object when unit testing?

Q2 why does this happen in testing but not in the DOM during application execution?

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)

first module that adds itself to the WIDGET object

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_;

next module that adds itself and uses the logger module

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_;

mocha test script

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

A2 to Q2 found at free code camp - require modules In a browser, when we declare a variable in a script like this:

var answer = 42;

That answer variable will be globally available in all scripts after the script that defined it.

This is not the case in Node. When we define a variable in one module, the other modules in the program will not have access to that variable. So how come variables in Node are magically scoped?

The answer is simple. Before compiling a module, Node wraps the module code in a function, which we can inspect using the wrapper property of the module module.

1 Answer 1

1

Big Thanks to free code camp

They made it simple to see that node.js require('module') wraps the module in a function().

That helped me to realize I needed to concat my modules into 1 file for testing. Then require('minifiedModules')

in my unit tests the code looks like

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

and running npm test now works

> 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.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.