diff --git a/bower.json b/bower.json index d8b3fd8..7bb8613 100644 --- a/bower.json +++ b/bower.json @@ -2,6 +2,7 @@ "name": "ActionCenter-Mobile", "private": "true", "devDependencies": { + "angular-mocks": "v1.2.26", "ionic": "driftyco/ionic-bower#1.0.0-beta.11", "ngCordova": "v0.1.3-alpha", "open-sans-fontface": "1.1.0", diff --git a/config/default.json b/config/default.json index 4b2417d..9eaf3f9 100644 --- a/config/default.json +++ b/config/default.json @@ -4,7 +4,14 @@ "VERSION": 1, "ENDPOINT": "http://127.0.0.1:5000/api" }, - + + "APP": { + "PUSH_CAPABLE_PLATFORMS": [ + "ANDROID", + "IOS" + ] + }, + "SHARING": { "URL": "https://eff.org", "MESSAGES": { @@ -13,8 +20,9 @@ "SUBJECT": "EFF's Android App", "BODY": "Hey, did you know the Electronic Frontier Foundation has a mobile app? It alerts you when they need your help, and you can download it from this link: %s" }, - "TWITTER": "Help out @EFF by downloading their Android App and get instant action alerts: ", - "OTHER": "Download the EFF's mobile app and get instant alerts when they need your help" + "FACEBOOK": "Download the EFF's mobile app and get instant alerts when they need your help: %s", + "TWITTER": "Help out @EFF by downloading their Android App and get instant action alerts: %s", + "OTHER": "Download the EFF's mobile app and get instant alerts when they need your help: %s" } }, diff --git a/config/development.json b/config/development.json index e69de29..dd62d71 100644 --- a/config/development.json +++ b/config/development.json @@ -0,0 +1,5 @@ +{ + + "MODE": "development" + +} diff --git a/config/production.json b/config/production.json index 08694f4..dcc856a 100644 --- a/config/production.json +++ b/config/production.json @@ -1,5 +1,7 @@ { + "MODE": "production", + "API": { "VERSION": 1, "ENDPOINT": "http://127.0.0.1:5000/api" diff --git a/config/test.json b/config/test.json index e69de29..d236278 100644 --- a/config/test.json +++ b/config/test.json @@ -0,0 +1,19 @@ +{ + + "MODE": "test", + + "SHARING": { + "URL": "testURL", + "MESSAGES": { + "SMS": "test: %s", + "EMAIL": { + "SUBJECT": "test", + "BODY": "test: %s" + }, + "FACEBOOK": "test: %s", + "TWITTER": "test: %s", + "OTHER": "test: %s" + } + } + +} diff --git a/gulp/config.js b/gulp/config.js index cc32ece..99bf9c6 100644 --- a/gulp/config.js +++ b/gulp/config.js @@ -10,6 +10,7 @@ var COMPONENTS_DIR = path.join(BASE_DIR, 'bower_components'); var WWW_DIR = path.join(BASE_DIR, 'www'); var BUILD_DIR = path.join(WWW_DIR, 'build'); var DIST_DIR = path.join(WWW_DIR, 'dist'); +var TEST_DIR = path.join(BASE_DIR, 'test'); var SERVER_PORT = 4000; @@ -20,6 +21,7 @@ module.exports = { fileName: 'app_settings.js', settingsKeys: [ 'API', + 'APP', 'CREDENTIALS', 'SHARING' ] @@ -101,10 +103,40 @@ module.exports = { }, test: { - mochaOptions: { - reporter: 'spec' - }, - paths: path.join(BASE_DIR, 'test/**/*.js') + karma: { + + basePath: '', + + frameworks: ['mocha', 'chai', 'sinon'], + + // Order matters + files: [ + path.join(WWW_DIR, 'dist/js/libs.min.js'), + path.join(COMPONENTS_DIR, 'angular-mocks/angular-mocks.js'), + path.join(WWW_DIR, 'dist/js/acm.min.js'), + path.join(TEST_DIR, '**/*.js') + ], + + exclude: [], + + port: 9876, + + browsers: [ + 'PhantomJS' + ], + + plugins: [ + 'karma-phantomjs-launcher', + 'karma-mocha', + 'karma-chai', + 'karma-sinon' + ], + + singleRun: true, + + colors: true + + } } }; diff --git a/gulp/tasks/test.js b/gulp/tasks/test.js new file mode 100644 index 0000000..7f179d7 --- /dev/null +++ b/gulp/tasks/test.js @@ -0,0 +1,16 @@ +/** + * Runs mocha tests for the app. + */ + +var gulp = require('gulp'); +var karma = require('karma').server; + +var config = require('../config').test; + +gulp.task('test', ['build'], function(done) { + + karma.start(config.karma, function(exitCode) { + done(); + }); + +}); diff --git a/gulp/tasks/tests.js b/gulp/tasks/tests.js deleted file mode 100644 index f0a65d6..0000000 --- a/gulp/tasks/tests.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Runs mocha tests for the app. - */ - -var gulp = require('gulp'); -var gulpExit = require('gulp-exit'); -var gulpMocha = require('gulp-mocha'); - -var config = require('../config').test; - -gulp.task('test', ['build'], function() { - return gulp.src(config.paths) - .pipe(gulpMocha(config.mochaOptions)) - // NOTE: gulpExit is used here as otherwise the task hangs, see: - // github.com/sindresorhus/gulp-mocha/pull/31 - // exit will fail and test will hang if any error is emitted, even if it's from outside mocha - // tests - .pipe(gulpExit()); -}); diff --git a/gulpfile.js b/gulpfile.js index 015f19f..f9e0883 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,6 +2,8 @@ * Top level gulpfile - imports all tasks under gulp/tasks */ +// Force the env into test mode for the gulp test task prior to importing any tasks. This is to +// ensure that var argv = process.argv; if (argv[argv.length - 1] === 'test') { process.env.NODE_ENV = 'test'; diff --git a/package.json b/package.json index 073ee7c..7d61cbe 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "browser-sync": "^1.5.8", "browserify-shim": "^3.8.0", "config": "^1.7.0", - "gulp": "^3.5.6", + "gulp": "^3.8.10", "gulp-angular-templatecache": "^1.3.0", "gulp-browserify": "~0.5.0", "gulp-changed": "^1.0.0", @@ -26,7 +26,14 @@ "gulp-run": "^1.6.4", "gulp-sass": "^1.2.0", "gulp-util": "^3.0.1", + "karma": "^0.12.24", + "karma-chai": "^0.1.0", + "karma-mocha": "^0.1.9", + "karma-phantomjs-launcher": "^0.1.4", + "karma-sinon": "^1.0.3", "merge-stream": "^0.1.6", + "mocha": "^2.0.1", + "phantomjs": "^1.9.12", "pretty-hrtime": "^0.2.2", "require-dir": "^0.1.0", "vinyl": "0.3.0", diff --git a/test/services/sharing.js b/test/services/sharing.js new file mode 100644 index 0000000..ad6cad6 --- /dev/null +++ b/test/services/sharing.js @@ -0,0 +1,39 @@ +describe('Unit: Sharing Service', function() { + + beforeEach(module('acm')); + + var mock; + before(function() { + + window.plugins.socialsharing = { + shareViaEmail: function() {}, + shareViaSMS: function() {}, + shareViaFacebook: function() {}, + shareViaTwitter: function() {}, + share: function() {} + }; + + mock = sinon.mock(window.plugins.socialsharing); + + mock.expects('shareViaEmail').once().withExactArgs('test: testURL', 'test', null, null, null, null); + mock.expects('shareViaSMS').once().withExactArgs('test: testURL', undefined); + mock.expects('shareViaFacebook').once().withExactArgs('test: testURL', undefined, 'testURL'); + mock.expects('shareViaTwitter').once().withExactArgs('test: testURL', undefined, 'testURL'); + mock.expects('share').once().withExactArgs('test: testURL', null, null, 'testURL'); + }); + + var acmSharing; + beforeEach(inject(function(_acmSharing_) { + acmSharing = _acmSharing_; + })); + + it('should do something', function() { + acmSharing.shareApp('EMAIL'); + acmSharing.shareApp('SMS'); + acmSharing.shareApp('FACEBOOK'); + acmSharing.shareApp('TWITTER'); + acmSharing.shareApp('OTHER'); + mock.verify(); + }); + +}); diff --git a/test/setup.js b/test/setup.js index 1cecebb..48fd07f 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,3 +1,11 @@ /** * Mocha setup. */ + +before(function() { + window.plugins = window.plugins || {}; +}); + +after(function() { + +}); diff --git a/www/js/app.js b/www/js/app.js index eb233f8..a634b40 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -4,6 +4,9 @@ var angular = require('angular'); +var appSettings = require('../build/app_settings'); + + /** * Top level handler for all push notification events. * @@ -101,6 +104,8 @@ actionCenterMobile.run(function ($state, $ionicPlatform, acmPushNotification, ac $ionicPlatform.ready(function () { + var platform = ionic.Platform.platform().toUpperCase(); + // Hide the accessory bar by default if (window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); @@ -111,7 +116,8 @@ actionCenterMobile.run(function ($state, $ionicPlatform, acmPushNotification, ac StatusBar.styleDefault(); } - if (window.plugins !== undefined) { + if (window.plugins !== undefined && + appSettings['APP']['PUSH_CAPABLE_PLATFORMS'].indexOf(platform) != -1) { acmPushNotification.register(); } diff --git a/www/js/services/sharing.js b/www/js/services/sharing.js index f0927ff..8ad7be6 100644 --- a/www/js/services/sharing.js +++ b/www/js/services/sharing.js @@ -2,9 +2,11 @@ * Wrapper service for common sharing actions. */ -var shareSettings = require('../../build/app_settings')['SHARING']; +var angular = require('angular'); var sprintf = require('sprintf'); +var shareSettings = require('../../build/app_settings')['SHARING']; + var SharingService = function () { @@ -16,10 +18,17 @@ var SharingService = function () { var shareURL = shareSettings['URL']; var shareMessage = shareSettings['MESSAGES'][service] || DEFAULT_SHARE_MSG; - shareMessage = sprintf(shareMessage, shareURL); + + if (angular.isObject(shareMessage)) { + angular.forEach(shareMessage, function(val, key) { + shareMessage[key] = sprintf(val, shareURL); + }); + } else { + shareMessage = sprintf(shareMessage, shareURL); + } if (service === 'EMAIL') { - var title = shareMessage['TITLE'] || 'Download the EFF\'s Android app'; + var title = shareMessage['SUBJECT'] || 'Download the EFF\'s Android app'; var body = shareMessage['BODY'] || DEFAULT_SHARE_MSG; // On Android this opens up as either Drive or Gmail, and doesn't work for Drive.