diff --git a/package.json b/package.json index 90ff03162..bf2dfd5e7 100755 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "karma": "~0.10.2", "grunt-karma": "~0.6.2", "karma-coverage": "~0.1.0", - "karma-spec-reporter": "0.0.5" + "karma-spec-reporter": "0.0.5", + "grunt-clear": "~0.2.1" } } diff --git a/spec/module.commented.js b/spec/module.commented.js index cc35894ca..b629c09bf 100755 --- a/spec/module.commented.js +++ b/spec/module.commented.js @@ -25,23 +25,6 @@ $.fn.example = function(parameters) { // Store a reference to the module group, this can be useful to refer to other modules inside each module $allModules = $(this), - // Extend settings to merge run-time settings with defaults - settings = ( $.isPlainObject(parameters) ) - ? $.extend(true, {}, $.fn.example.settings, parameters) - : $.fn.example.settings, - - // Alias settings object for convenience and performance - namespace = settings.namespace, - error = settings.error, - className = settings.className, - - // You may also find it useful to alias your own settings - text = settings.text, - - // Define namespaces for storing module instance and binding events - eventNamespace = '.' + namespace, - moduleNamespace = 'module-' + namespace, - // Preserve selector from outside each scope and mark current time for performance tracking moduleSelector = $allModules.selector || '', time = new Date().getTime(), @@ -59,6 +42,28 @@ $.fn.example = function(parameters) { $allModules .each(function() { var + + // Extend settings to merge run-time settings with defaults + settings = ( $.isPlainObject(parameters) ) + ? $.extend(true, {}, $.fn.example.settings, parameters) + : $.extend({}, $.fn.example.settings), + + // Alias settings object for convenience and performance + namespace = settings.namespace, + error = settings.error, + className = settings.className, + + // You may also find it useful to alias your own settings + text = settings.text, + + // Define namespaces for storing module instance and binding events + eventNamespace = '.' + namespace, + moduleNamespace = 'module-' + namespace, + + // Instance is stored and retreived in namespaced DOM metadata + instance = $(this).data(moduleNamespace), + element = this, + // Cache selectors using selector settings object for access inside instance of module $module = $(this), $text = $module.find(settings.selector.text), @@ -66,9 +71,6 @@ $.fn.example = function(parameters) { // Define private variables which can be used to maintain internal state, these cannot be changed from outside the module closure so use conservatively. Default values are set using `a || b` syntax foo = false, - // Instance is stored and retreived in namespaced DOM metadata - instance = $module.data(moduleNamespace), - element = this, module ; diff --git a/src/modules/accordion.js b/src/modules/accordion.js index fa335f882..77b659d6e 100755 --- a/src/modules/accordion.js +++ b/src/modules/accordion.js @@ -28,7 +28,7 @@ $.fn.accordion = function(parameters) { var settings = ( $.isPlainObject(parameters) ) ? $.extend(true, {}, $.fn.accordion.settings, parameters) - : $.fn.accordion.settings, + : $.extend({}, $.fn.accordion.settings), className = settings.className, namespace = settings.namespace, diff --git a/src/modules/dimmer.js b/src/modules/dimmer.js index f7a48dab1..526434cc3 100755 --- a/src/modules/dimmer.js +++ b/src/modules/dimmer.js @@ -30,7 +30,7 @@ $.fn.dimmer = function(parameters) { var settings = ( $.isPlainObject(parameters) ) ? $.extend(true, {}, $.fn.dimmer.settings, parameters) - : $.fn.dimmer.settings, + : $.extend({}, $.fn.dimmer.settings), selector = settings.selector, namespace = settings.namespace, @@ -111,6 +111,9 @@ $.fn.dimmer = function(parameters) { destroy: function() { module.verbose('Destroying previous module', $dimmer); + $module + .removeData(moduleNamespace) + ; $dimmable .off(eventNamespace) ; @@ -515,8 +518,8 @@ $.fn.dimmer.settings = { name : 'Dimmer', namespace : 'dimmer', - verbose : true, debug : true, + verbose : true, performance : true, transition : 'fade', diff --git a/src/modules/dropdown.js b/src/modules/dropdown.js index 3668a4bfa..69ef01511 100755 --- a/src/modules/dropdown.js +++ b/src/modules/dropdown.js @@ -31,7 +31,7 @@ $.fn.dropdown = function(parameters) { var settings = ( $.isPlainObject(parameters) ) ? $.extend(true, {}, $.fn.dropdown.settings, parameters) - : $.fn.dropdown.settings, + : $.extend({}, $.fn.dropdown.settings), className = settings.className, metadata = settings.metadata, diff --git a/src/modules/modal.js b/src/modules/modal.js index 42b28beca..fbf4362ed 100755 --- a/src/modules/modal.js +++ b/src/modules/modal.js @@ -63,6 +63,7 @@ $.fn.modal = function(parameters) { module.verbose('Initializing dimmer', $context); $dimmable = $context + .dimmer() .dimmer('add content', $module) ; $dimmer = $context @@ -93,7 +94,16 @@ $.fn.modal = function(parameters) { module.verbose('Destroying previous modal'); $module .off(eventNamespace) + .removeData(moduleNamespace) ; + $close + .off(eventNamespace) + ; + if($dimmable) { + $dimmable + .dimmer('destroy') + ; + } }, refresh: function() { diff --git a/src/modules/popup.js b/src/modules/popup.js index bd8d542cd..b6b15a18b 100755 --- a/src/modules/popup.js +++ b/src/modules/popup.js @@ -32,7 +32,7 @@ $.fn.popup = function(parameters) { var settings = ( $.isPlainObject(parameters) ) ? $.extend(true, {}, $.fn.popup.settings, parameters) - : $.fn.popup.settings, + : $.extend({}, $.fn.popup.settings), selector = settings.selector, className = settings.className, diff --git a/src/modules/sidebar.js b/src/modules/sidebar.js index 1f9282fa0..6d35599c7 100755 --- a/src/modules/sidebar.js +++ b/src/modules/sidebar.js @@ -30,7 +30,7 @@ $.fn.sidebar = function(parameters) { var settings = ( $.isPlainObject(parameters) ) ? $.extend(true, {}, $.fn.sidebar.settings, parameters) - : $.fn.sidebar.settings, + : $.extend({}, $.fn.sidebar.settings), selector = settings.selector, className = settings.className, diff --git a/src/modules/video.js b/src/modules/video.js index db4741f18..2fa9821ad 100755 --- a/src/modules/video.js +++ b/src/modules/video.js @@ -32,7 +32,7 @@ $.fn.video = function(parameters) { var settings = ( $.isPlainObject(parameters) ) ? $.extend(true, {}, $.fn.video.settings, parameters) - : $.fn.video.settings, + : $.extend({}, $.fn.video.settings), selector = settings.selector, className = settings.className, diff --git a/test/helpers/jasmine-clog.js b/test/helpers/jasmine-clog.js new file mode 100755 index 000000000..5f2ac1bee --- /dev/null +++ b/test/helpers/jasmine-clog.js @@ -0,0 +1,17 @@ +// Allow for console.log to not break IE +if (typeof window.console == "undefined" || typeof window.console.log == "undefined") { + window.console = { + log : function() {}, + info : function(){}, + warn : function(){} + }; +} +if(typeof window.console.group == 'undefined' || typeof window.console.groupEnd == 'undefined' || typeof window.console.groupCollapsed == 'undefined') { + window.console.group = function(){}; + window.console.groupEnd = function(){}; + window.console.groupCollapsed = function(){}; +} +if(typeof window.console.markTimeline == 'undefined') { + window.console.markTimeline = function(){}; +} +window.console.clear = function(){}; diff --git a/test/helpers/jquery-events.js b/test/helpers/jquery-events.js new file mode 100755 index 000000000..d956e5676 --- /dev/null +++ b/test/helpers/jquery-events.js @@ -0,0 +1,28 @@ +(function($) { + $.events = function(selector, root) { + var s = []; + $(selector || '*', root).addBack().each(function() { + // the following line is the only change + var e = $._data(this, 'events'); + if(!e) return; + s.push(this.tagName); + if(this.id) s.push('#', this.id); + if(this.className) s.push('.', this.className.replace(/ +/g, '.')); + for(var p in e) { + var r = e[p], + h = r.length - r.delegateCount; + if(h) + s.push('\n', h, ' ', p, ' handler', h > 1 ? 's' : ''); + if(r.delegateCount) { + for(var q = 0; q < r.length; q++) + if(r[q].selector) s.push('\n', p, ' for ', r[q].selector); + } + } + s.push('\n\n'); + }); + return s.join(''); + } + $.fn.events = function(selector) { + return $.events(selector, this); + } +})(jQuery); \ No newline at end of file diff --git a/test/karma.conf.js b/test/karma.conf.js deleted file mode 100755 index 0efcde65d..000000000 --- a/test/karma.conf.js +++ /dev/null @@ -1,68 +0,0 @@ -// Karma configuration -module.exports = function(config) { - config.set({ - - // base path, that will be used to resolve files and exclude - basePath: '', - - // frameworks to use - frameworks: [ - 'jasmine' - ], - - // list of files / patterns to load in the browser - files: [ - // require jquery - '../server/files/javascript/library/jquery.js', - // read css from compiled css - '../docs/build/**/*.css', - // read js from src js - '../src/**/*.js', - // require helpers - 'helpers/*.js', - // require tests - 'modules/*.js' - ], - - // list of files to exclude - exclude: [ - '**/*.swp', - 'karma.conf.js' - ], - - // test results reporter to use - // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' - reporters: ['spec'], - - // web server port - port: 9999, - - // enable / disable colors in the output (reporters and logs) - colors: true, - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - // Start these browsers, currently available: - // - Chrome - // - ChromeCanary - // - Firefox - // - Opera - // - Safari (only Mac) - // - PhantomJS - // - IE (only Windows) - browsers: ['PhantomJS'], - - - // If browser does not capture in given timeout [ms], kill it - captureTimeout: 60000, - - // Continuous Integration mode - // if true, it capture browsers, run tests and exit - singleRun: false - }); -}; diff --git a/test/modules/modal.js b/test/modules/modal.js deleted file mode 100755 index 32247edcb..000000000 --- a/test/modules/modal.js +++ /dev/null @@ -1,11 +0,0 @@ -describe("UI Modal", function() { - - it("contains spec with an expectation", function() { - expect(true).toBe(true); - }); - - it("contains another spec with another expectation", function() { - expect(true).toBe(true); - }); - -}); \ No newline at end of file diff --git a/test/modules/modal.spec.js b/test/modules/modal.spec.js index fa2847b62..d1693b6c7 100755 --- a/test/modules/modal.spec.js +++ b/test/modules/modal.spec.js @@ -1,12 +1,22 @@ describe("UI Modal", function() { + var + module = 'modal', + testValue = 'Test', + name = module.charAt(0).toUpperCase() + module.slice(1), + fixtures = jasmine.getFixtures(), - beforeEach(function() { - module = 'modal'; - testSetting = 'Test'; - name = module.charAt(0).toUpperCase() + module.slice(1); + $module + ; + + fixtures.fixturesPath = 'base/test/fixtures/'; - jasmine.getFixtures().fixturesPath = 'base/test/fixtures/'; - loadFixtures(module + '.html'); + beforeEach(function() { + // load fixtures + fixtures.load(module + '.html'); + // disable debug + $.fn[module].debug = false; + // module available in scope + $module = $('.ui.'+ module); }); afterEach(function() { @@ -17,52 +27,126 @@ describe("UI Modal", function() { Module *******************************/ + /*------------------- + Instantiation + --------------------*/ + it("should have an instance in metadata after init", function() { - var $module = $('.ui.'+ module)[module](); + $module[module](); expect($module).toHaveData('module-' + module); }); - it("should allow default settings to be changed", function() { - $.fn[module].settings.name = testSetting; - $module = $('.ui.'+ module)[module](); - retrievedSetting = $module[module]('setting', 'name'); - $.fn[module].settings.name = name; - expect(retrievedSetting).toBe(testSetting); - }); + /*------------------- + Settings + --------------------*/ + describe('Settings', function() { - it("should allow settings to be changed during init", function() { - $module = $('.ui.'+ module)[module]({ - name: testSetting + it("should allow default settings to be changed", function() { + $.fn[module].settings.name = testValue; + $module[module](); + + var retrievedValue = $module[module]('setting', 'name'); + $.fn[module].settings.name = name; + + expect(retrievedValue).toBe(testValue); + }); + + it("should allow settings to be changed during init", function() { + $module[module]({ + name: testValue + }); + + var retrievedValue = $module[module]('setting', 'name'); + + expect(retrievedValue).toBe(testValue); + }); + + it("should allow settings to be changed during runtime", function() { + $module[module](); + + var retrievedValue = $module[module]('setting', 'name'); + + expect(retrievedValue).toBe(name); }); - retrievedSetting = $module[module]('setting', 'name'); - expect(retrievedSetting).toBe(testSetting); - }); - it("should allow settings to be changed during runtime", function() { - $module = $('.ui.'+ module)[module](); - retrievedSetting = $module[module]('setting', 'name'); - expect(retrievedSetting).toBe(name); }); - it("should only change the settings for specified element", function() { - $module = $('.ui.' + module); - $moduleClone = $module.clone().appendTo( $(sandbox() )); - $modules = $moduleClone.add($module); + /*------------------- + Groups + --------------------*/ + + describe('Group Contamination', function() { - $modules[module](); + it("should create settings for all instances", function() { + $moduleClone = $module.clone().appendTo( $(sandbox() )); + $modules = $moduleClone.add($module); - $module[module]('setting', 'name', testSetting); + $modules[module]('setting', 'name', testValue); - retrievedSetting = $module[module]('setting', 'name'); - clonedSetting = $moduleClone[module]('setting', 'name'); + var retrievedValue = $module[module]('setting', 'name'); + var clonedSetting = $moduleClone[module]('setting', 'name'); + + expect(retrievedValue).toBe(testValue); + expect(clonedSetting).toBe(testValue); + + $modules[module]({ + 'name': testValue + }); + + expect(retrievedValue).toBe(testValue); + expect(clonedSetting).toBe(testValue); + + }); + + it("should not change other elements settings when changing one element", function() { + $moduleClone = $module.clone().appendTo( $(sandbox() )); + $modules = $moduleClone.add($module); + + $modules[module](); + $module[module]('setting', 'name', testValue); + + var retrievedValue = $module[module]('setting', 'name'); + var clonedSetting = $moduleClone[module]('setting', 'name'); + + expect(retrievedValue).toBe(testValue); + expect(clonedSetting).toBe(name); + + }); + + it("should not change other elements when re-initalized", function() { + $moduleClone = $module.clone().appendTo( $(sandbox() )); + $modules = $moduleClone.add($module); + + $modules[module](); + $module[module]({ + 'name': testValue + }); + + var retrievedValue = $module[module]('setting', 'name'); + var clonedSetting = $moduleClone[module]('setting', 'name'); + + expect(retrievedValue).toBe(testValue); + expect(clonedSetting).toBe(name); + + }); - expect(retrievedSetting).toBe(testSetting); - expect(clonedSetting).toBe(name); }); /*------------------- - Groups + Destroy --------------------*/ + describe('Destroy', function() { + it("destroy should remove all events from page", function() { + $module[module]('destroy'); + expect($.events().length).toBe(0); + }); + + it("destroy should remove instance metadata", function() { + $module[module]('destroy'); + expect( $module.data('module-'+ module) ).toBe(undefined); + }); + + }); }); \ No newline at end of file