diff --git a/.eslintrc b/.eslintrc index 6a304a0..54d6c4f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -51,6 +51,7 @@ "no-script-url": 2, "no-sequences": 2, "no-undef": 2, + "no-underscore-dangle": 0, "no-unused-vars": 2, "no-with": 2, "quotes": [2, "single"], diff --git a/karma.conf.js b/karma.conf.js index 28f7182..045db95 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,5 +1,6 @@ 'use strict'; +var RewirePlugin = require('rewire-webpack'); var webpackConfig = require('./webpack.config.js'); // Remove the bits from the shared config @@ -7,6 +8,11 @@ var webpackConfig = require('./webpack.config.js'); delete webpackConfig.output; delete webpackConfig.entry; +// Add this just for testing: +webpackConfig.plugins = [ + new RewirePlugin(), +]; + module.exports = function (config) { config.set({ diff --git a/package.json b/package.json index 0eb55cc..07e6cc3 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,8 @@ "mocha": "^2.2.5", "node-libs-browser": "0.5.0", "payment-icons": "git://github.com/muffinresearch/payment-icons.git#0.0.4", + "rewire": "^2.1.3", + "rewire-webpack": "^1.0.0", "sinon": "1.14.1", "webpack": "^1.9.5", "webpack-dev-server": "^1.8.2" diff --git a/public/js/user-actions.js b/public/js/user-actions.js index 012e98b..10c97b4 100644 --- a/public/js/user-actions.js +++ b/public/js/user-actions.js @@ -5,26 +5,17 @@ var assign = require('object-assign'); var dispatcher = require('dispatcher'); +// +// A helper object to perform user-related actions. +// Each action will dispatch messages so that stores can +// update their state accordingly. +// -function UserActions(localDispatcher) { - // - // A helper object to perform user-related actions. - // Each action will dispatch messages so that stores can - // update their state accordingly. - // - this.dispatcher = localDispatcher; -} +module.exports = assign({}, { + signIn: function(accessToken) { -UserActions.prototype = assign({}, { - - signIn: function(accessToken, opt) { - opt = opt || {}; - if (!opt.jquery) { - opt.jquery = $; - } - - opt.jquery.ajax({ + $.ajax({ data: { access_token: accessToken, }, @@ -41,7 +32,7 @@ UserActions.prototype = assign({}, { console.log('setting CSRF token for subsequent requests:', data.csrf_token); - opt.jquery.ajaxSetup({ + $.ajaxSetup({ headers: { 'X-CSRFToken': data.csrf_token, }, @@ -59,14 +50,10 @@ UserActions.prototype = assign({}, { setCurrentUser: function(user) { console.log('UserActions: setting current user', user); - this.dispatcher.dispatch({ + dispatcher.dispatch({ actionType: 'set-user', user: user, }); }, }); - - -module.exports = new UserActions(dispatcher); -module.exports.Class = UserActions; diff --git a/public/js/user-store.js b/public/js/user-store.js index d6d0d43..17e0c23 100644 --- a/public/js/user-store.js +++ b/public/js/user-store.js @@ -46,4 +46,3 @@ UserStore.prototype = assign({}, EventEmitter.prototype, { module.exports = new UserStore(dispatcher); -module.exports.Class = UserStore; diff --git a/public/jsx/views/login.jsx b/public/jsx/views/login.jsx index f35da84..d6c8619 100644 --- a/public/jsx/views/login.jsx +++ b/public/jsx/views/login.jsx @@ -14,8 +14,6 @@ module.exports = React.createClass({ displayName: 'LoginView', mixins: [Navigation], - UserActions: UserActions, - UserStore: UserStore, contextTypes: { router: React.PropTypes.func, @@ -23,12 +21,12 @@ module.exports = React.createClass({ componentDidMount: function() { var { router } = this.context; - this.UserStore.addSetUserListener(this.onSetUser); - this.UserActions.signIn(router.getCurrentQuery().access_token); + UserStore.addSetUserListener(this.onSetUser); + UserActions.signIn(router.getCurrentQuery().access_token); }, componentWillUnmount: function() { - this.UserStore.removeSetUserListener(this.onSetUser); + UserStore.removeSetUserListener(this.onSetUser); }, onSetUser: function() { @@ -36,7 +34,7 @@ module.exports = React.createClass({ console.log('ignoring events while unmounted'); return; } - var user = this.UserStore.getCurrentUser(); + var user = UserStore.getCurrentUser(); if (user.is_logged_in) { console.log('current user is logged in; continuing to card-listing'); this.transitionTo('card-listing'); diff --git a/tests/test.login.jsx b/tests/test.login.jsx index 9b17c71..6dd000f 100644 --- a/tests/test.login.jsx +++ b/tests/test.login.jsx @@ -1,43 +1,47 @@ 'use strict'; -var Login = require('views/login'); +var rewire = require('rewire'); var helpers = require('./helpers'); describe('Login', function() { beforeEach(function() { + var stubs = helpers.getUserStubs(); + this.UserActions = stubs.UserActions; + this.UserStore = stubs.UserStore; + + var Login = rewire('views/login'); + Login.__set__({ + UserActions: this.UserActions, + UserStore: this.UserStore, + }); + var routed = helpers.getRoutedComponent(Login); this.Login = routed.component; - - var stubs = helpers.getUserStubs(); - - this.Login.UserActions = stubs.UserActions; - this.Login.UserStore = stubs.UserStore; }); it('should sign in on mount', function() { this.Login.componentDidMount(); - assert.ok(this.Login.UserActions.signIn.called); + assert.ok(this.UserActions.signIn.called); }); it('should listen to user change', function() { this.Login.componentDidMount(); - var store = this.Login.UserStore; + var store = this.UserStore; assert.equal(store.addSetUserListener.firstCall.args[0], this.Login.onSetUser); }); it('should clean up user listeners', function() { this.Login.componentWillUnmount(); - var store = this.Login.UserStore; - assert.equal(store.removeSetUserListener.firstCall.args[0], + assert.equal(this.UserStore.removeSetUserListener.firstCall.args[0], this.Login.onSetUser); }); it('should navigate to card-listing when user signs in', function() { var transition = sinon.spy(this.Login, 'transitionTo'); - this.Login.UserStore.getCurrentUser = function() { + this.UserStore.getCurrentUser = function() { return { is_logged_in: true, }; diff --git a/tests/test.user-actions.js b/tests/test.user-actions.js index aca0d79..498d9a4 100644 --- a/tests/test.user-actions.js +++ b/tests/test.user-actions.js @@ -1,6 +1,6 @@ 'use strict'; -var UserActions = require('user-actions'); +var rewire = require('rewire'); var helpers = require('./helpers'); @@ -15,7 +15,14 @@ describe('UserActions', function() { dispatch: function() {}, }; sinon.spy(dispatcher, 'dispatch'); - userActions = new UserActions.Class(dispatcher); + + userActions = rewire('user-actions'); + userActions.__set__({ + dispatcher: dispatcher, + // Replace with a non-functioning stub by default until overidden. + '$': {}, + }); + }); function fakeSignInResult() { @@ -35,11 +42,13 @@ describe('UserActions', function() { }); it('should set user from sign-in', function() { - var setUser = sinon.spy(userActions, 'setCurrentUser'); var data = fakeSignInResult(); var jquery = helpers.fakeJquery({returnedData: data}); + userActions.__set__('$', jquery.stub); - userActions.signIn('access-token', {jquery: jquery.stub}); + var setUser = sinon.spy(userActions, 'setCurrentUser'); + + userActions.signIn('access-token'); assert.deepEqual(setUser.firstCall.args[0], {email: data.buyer_email, is_logged_in: true}); @@ -47,8 +56,9 @@ describe('UserActions', function() { it('should sign-in with access token', function() { var jquery = helpers.fakeJquery({returnedData: fakeSignInResult()}); + userActions.__set__('$', jquery.stub); - userActions.signIn('access-token', {jquery: jquery.stub}); + userActions.signIn('access-token'); assert.equal(jquery.ajaxSpy.firstCall.args[0].data.access_token, 'access-token'); @@ -57,18 +67,20 @@ describe('UserActions', function() { it('should configure CSRF headers on sign-in', function() { var data = fakeSignInResult(); var jquery = helpers.fakeJquery({returnedData: data}); + userActions.__set__('$', jquery.stub); - userActions.signIn('access-token', {jquery: jquery.stub}); + userActions.signIn('access-token'); assert.deepEqual(jquery.ajaxSetupSpy.firstCall.args[0].headers, {'X-CSRFToken': data.csrf_token}); }); it('should set signed out user on failure', function() { - var setUser = sinon.spy(userActions, 'setCurrentUser'); var jquery = helpers.fakeJquery({result: 'fail'}); + userActions.__set__('$', jquery.stub); + var setUser = sinon.spy(userActions, 'setCurrentUser'); - userActions.signIn('access-token', {jquery: jquery.stub}); + userActions.signIn('access-token'); assert.deepEqual(setUser.firstCall.args[0], {email: null, is_logged_in: false}); diff --git a/tests/test.user-store.js b/tests/test.user-store.js index 1b39b50..96958fe 100644 --- a/tests/test.user-store.js +++ b/tests/test.user-store.js @@ -1,6 +1,6 @@ 'use strict'; -var UserStore = require('user-store'); +var rewire = require('rewire'); describe('UserStore', function() { @@ -18,13 +18,17 @@ describe('UserStore', function() { } beforeEach(function() { + var module = rewire('user-store'); + var dispatcher = { register: function(receiver) { // Reference the callback so we can dispatch messages directly. dispatch = receiver; }, }; - userStore = new UserStore.Class(dispatcher); + + var UserStore = module.__get__('UserStore'); + userStore = new UserStore(dispatcher); // Stub out the event emitter. userStore.emit = function(event) {