diff --git a/CHANGELOG.md b/CHANGELOG.md index 79aa2c0..1e96880 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### 1.10.0 +* [#156](https://github.com/softlayer/sl-ember-test-helpers/issues/156) [ENHANCEMENT] Add `globalLibraries` helper * [#160](https://github.com/softlayer/sl-ember-test-helpers/pull/160) BUGFIX Lock down version of jQuery in bower.json * [#145](https://github.com/softlayer/sl-ember-test-helpers/pull/146) DOCUMENTATION Update *CONTRIBUTING.md* to add linting guidance * [#155](https://github.com/softlayer/sl-ember-test-helpers/pull/155) INTERNAL Upgrade `ember-qunit` dependency diff --git a/README.md b/README.md index fbb6876..b3f67af 100755 --- a/README.md +++ b/README.md @@ -85,6 +85,34 @@ The call to `requires` returns an object: } ``` +### Global Libraries + +Use this helper in your unit tests to determine if a component called globally-scoped `Ember.$`, `$` or `jQuery`. You must wrap your component with references to the setup and removal functions. + +``` +const component = this.subject(); + +globalLibraries.setupSpies(); + +globalLibraries.triggerEvents( component ); + +assert.notOk( + globalLibraries.called(), + 'There are no references to Ember.$, $ or jQuery' +); + +globalLibraries.restoreSpies(); +``` + +The `triggerEvents()` function takes a `component` as an argument and triggers the following events on it: `willInsertElement`, `didInsertElement`, `willClearRender` and `willDestroyElement`. Triggering of the various events +will ensure code that has handlers attached to those events will be exercised, making the helper more effective at detecting global references. + +The call to `called()` returns a boolean that is the result of the sinon spies detecting `Ember.$`, `$`, or `jQuery`. Validate `false` to verify that the code within the component does not have global references to +`Ember.$`, `$` or `jQuery`. + +``` + +``` ## Asynchronous diff --git a/blueprints/sl-ember-test-helpers/index.js b/blueprints/sl-ember-test-helpers/index.js index d0d0388..2156b0d 100755 --- a/blueprints/sl-ember-test-helpers/index.js +++ b/blueprints/sl-ember-test-helpers/index.js @@ -21,18 +21,17 @@ module.exports = { var thirdText = ' "contains",' + EOL + ' "requires",'; var thirdLocationText = '"predef": [' + EOL; - // Import statement return this.insertIntoFile( firstFile, firstText, { after: firstLocationText } ) - // Execution of registration function .then( function() { return this.insertIntoFile( secondFile, secondText, { after: secondLocationText } ); - }.bind(this)) - - // .jshintrc file + }.bind( this )) .then( function() { return this.insertIntoFile( thirdFile, thirdText, { after: thirdLocationText } ); - }.bind(this)); + }.bind( this )) + .then( function() { + return this.addAddonToProject( 'ember-sinon' ); + }.bind( this )); }, normalizeEntityName: function() {} diff --git a/index.js b/index.js index bf2ac56..1944a38 100644 --- a/index.js +++ b/index.js @@ -2,5 +2,5 @@ 'use strict'; module.exports = { - name: 'sl-ember-test-helpers' + name: 'sl-ember-test-helpers' }; diff --git a/test-support/helpers/sl/register-test-helpers.js b/test-support/helpers/sl/register-test-helpers.js index 6d0a2d4..bee80de 100755 --- a/test-support/helpers/sl/register-test-helpers.js +++ b/test-support/helpers/sl/register-test-helpers.js @@ -2,11 +2,13 @@ import Ember from 'ember'; import { contains, AjaxHelper, - requires + requires, + globalLibraries } from './synchronous'; export default function() { Ember.Test.registerHelper( 'contains', contains ); Ember.Test.registerHelper( 'Ajax', AjaxHelper ); Ember.Test.registerHelper( 'requires', requires ); -} \ No newline at end of file + Ember.Test.registerHelper( 'globalLibraries', globalLibraries ); +} diff --git a/test-support/helpers/sl/synchronous.js b/test-support/helpers/sl/synchronous.js index db7a58d..2a23daa 100755 --- a/test-support/helpers/sl/synchronous.js +++ b/test-support/helpers/sl/synchronous.js @@ -1,9 +1,11 @@ import AjaxHelper from './synchronous/ajax'; import contains from './synchronous/contains'; import requires from './synchronous/requires'; +import * as globalLibraries from './synchronous/global-libraries'; export { AjaxHelper, contains, - requires -}; \ No newline at end of file + requires, + globalLibraries +}; diff --git a/test-support/helpers/sl/synchronous/global-libraries.js b/test-support/helpers/sl/synchronous/global-libraries.js new file mode 100644 index 0000000..135ed72 --- /dev/null +++ b/test-support/helpers/sl/synchronous/global-libraries.js @@ -0,0 +1,43 @@ +import Ember from 'ember'; +import sinon from 'sinon'; + +export let called; +export let jqueryAliasSpy; +export let jquerySpy; +export let emberJquerySpy; + +export function setupSpies() { + jqueryAliasSpy = sinon.spy( window, '$' ); + jquerySpy = sinon.spy( window, 'jQuery' ); + emberJquerySpy = sinon.spy( Ember, '$' ); +} + +export function triggerEvents( component ) { + Ember.run( () => { + [ + 'willInsertElement', + 'didInsertElement', + 'willClearRender', + 'willDestroyElement' + ].map( ( event ) => { + component.trigger( event ); + }); + }); +} + +export function called() { + return jqueryAliasSpy.called || jquerySpy.called || emberJquerySpy.called; +} + +export function restoreSpies() { + window.$.restore(); + window.jQuery.restore(); + Ember.$.restore(); +} + +export function resetSpies() { + jqueryAliasSpy.reset(); + jquerySpy.reset(); + emberJquerySpy.reset(); +} + diff --git a/tests/unit/helpers/sl/synchronous/global-libaries-test.js b/tests/unit/helpers/sl/synchronous/global-libaries-test.js new file mode 100644 index 0000000..b7d1d66 --- /dev/null +++ b/tests/unit/helpers/sl/synchronous/global-libaries-test.js @@ -0,0 +1,102 @@ +import Ember from 'ember'; +import { test } from 'ember-qunit'; +import * as globalLibraries from '../../../../helpers/sl/synchronous/global-libraries'; +import sinon from 'sinon'; + +module( 'Unit | Helpers | sl/synchronous/global-libraries' ); + +test( 'it exists', function( assert ) { + assert.ok( + globalLibraries, + 'it exists' + ); +}); + +test( 'Passes when global libraries are not referenced', function( assert ) { + const component = Ember.Object.extend().create({ + trigger: function() {} + }); + + globalLibraries.setupSpies(); + + globalLibraries.triggerEvents( component ); + + assert.notOk( + globalLibraries.called() + ); + + globalLibraries.restoreSpies(); +}); + +test( 'triggerEvents triggers respective events', function( assert ) { + const events = { + 'willInsertElement': sinon.spy(), + 'didInsertElement': sinon.spy(), + 'willClearRender': sinon.spy(), + 'willDestroyElement': sinon.spy() + }; + + const component = { + trigger: function( eventName ) { + this.events[ eventName ](); + }, + + events + }; + + globalLibraries.triggerEvents( component ); + + Object.keys( events ).forEach( ( eventName ) => { + const spy = events[ eventName ]; + assert.ok( + spy.called, + `${ eventName } was triggered` + ); + }); +}); + +test( 'called() returns true when $ is referenced', function( assert ) { + globalLibraries.setupSpies(); + + window.$(); + + assert.ok( + globalLibraries.called() + ); + + globalLibraries.restoreSpies(); +}); + +test( 'called() returns true when jQuery is referenced', function( assert ) { + globalLibraries.setupSpies(); + + window.jQuery(); + + assert.ok( + globalLibraries.called() + ); + + globalLibraries.restoreSpies(); +}); + +test( 'called() returns true when Ember.$ is referenced', function( assert ) { + globalLibraries.setupSpies(); + + Ember.$(); + + assert.ok( + globalLibraries.called() + ); + + globalLibraries.restoreSpies(); +}); + +test( 'called() returns false when global libraries are not referenced', function( assert ) { + globalLibraries.setupSpies(); + + assert.notOk( + globalLibraries.called() + ); + + globalLibraries.restoreSpies(); +});