Add initial Angular boilerplate files.

Adds boilerplate files from `angularjs-gulp-browserify-boilerplate`
to start work on Angular rewrite of the frontend.

Change-Id: I54392c24f397496582f9d06d561d5c14a92ccbe6
This commit is contained in:
Tim Buckley 2015-09-25 16:08:54 -06:00
parent 80ae14c030
commit 0034283601
52 changed files with 1055 additions and 1 deletions

3
.gitignore vendored
View File

@ -1,6 +1,9 @@
# Project-specific ignores # Project-specific ignores
.idea .idea
stackviz/static/components/* stackviz/static/components/*
node_modules
build
app/js/templates.js
*.py[cod] *.py[cod]
# C extensions # C extensions

20
.jshintrc Normal file
View File

@ -0,0 +1,20 @@
{
"node": true,
"jasmine": true,
"browser": true,
"esnext": true,
"bitwise": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 2,
"latedef": true,
"noarg": true,
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true,
"newcap": false
}

BIN
app/images/angular.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
app/images/browserify.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
app/images/gulp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

19
app/index.html Normal file
View File

@ -0,0 +1,19 @@
<!doctype html>
<html class="no-js">
<head>
<base href="/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title ng-bind="pageTitle"></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div ui-view></div>
<script src="js/main.js"></script>
</body>
</html>

8
app/js/constants.js Normal file
View File

@ -0,0 +1,8 @@
'use strict';
var AppSettings = {
appTitle: 'Example Application',
apiUrl: '/api/v1'
};
module.exports = AppSettings;

View File

@ -0,0 +1,8 @@
'use strict';
var angular = require('angular');
var bulk = require('bulk-require');
module.exports = angular.module('app.controllers', []);
bulk(__dirname, ['./**/!(*_index|*.spec).js']);

View File

@ -0,0 +1,18 @@
'use strict';
var controllersModule = require('./_index');
/**
* @ngInject
*/
function ExampleCtrl() {
// ViewModel
var vm = this;
vm.title = 'AngularJS, Gulp, and Browserify!';
vm.number = 1234;
}
controllersModule.controller('ExampleCtrl', ExampleCtrl);

View File

@ -0,0 +1,8 @@
'use strict';
var angular = require('angular');
var bulk = require('bulk-require');
module.exports = angular.module('app.directives', []);
bulk(__dirname, ['./**/!(*_index|*.spec).js']);

View File

@ -0,0 +1,21 @@
'use strict';
var directivesModule = require('./_index.js');
/**
* @ngInject
*/
function exampleDirective() {
return {
restrict: 'EA',
link: function(scope, element) {
element.on('click', function() {
console.log('element clicked');
});
}
};
}
directivesModule.directive('exampleDirective', exampleDirective);

34
app/js/main.js Normal file
View File

@ -0,0 +1,34 @@
'use strict';
var angular = require('angular');
// angular modules
require('angular-ui-router');
require('./templates');
require('./controllers/_index');
require('./services/_index');
require('./directives/_index');
// create and bootstrap application
angular.element(document).ready(function() {
var requires = [
'ui.router',
'templates',
'app.controllers',
'app.services',
'app.directives'
];
// mount on window for testing
window.app = angular.module('app', requires);
angular.module('app').constant('AppSettings', require('./constants'));
angular.module('app').config(require('./on_config'));
angular.module('app').run(require('./on_run'));
angular.bootstrap(document, ['app']);
});

22
app/js/on_config.js Normal file
View File

@ -0,0 +1,22 @@
'use strict';
/**
* @ngInject
*/
function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) {
$locationProvider.html5Mode(true);
$stateProvider
.state('Home', {
url: '/',
controller: 'ExampleCtrl as home',
templateUrl: 'home.html',
title: 'Home'
});
$urlRouterProvider.otherwise('/');
}
module.exports = OnConfig;

22
app/js/on_run.js Normal file
View File

@ -0,0 +1,22 @@
'use strict';
/**
* @ngInject
*/
function OnRun($rootScope, AppSettings) {
// change page title based on state
$rootScope.$on('$stateChangeSuccess', function(event, toState) {
$rootScope.pageTitle = '';
if ( toState.title ) {
$rootScope.pageTitle += toState.title;
$rootScope.pageTitle += ' \u2014 ';
}
$rootScope.pageTitle += AppSettings.appTitle;
});
}
module.exports = OnRun;

View File

@ -0,0 +1,8 @@
'use strict';
var angular = require('angular');
var bulk = require('bulk-require');
module.exports = angular.module('app.services', []);
bulk(__dirname, ['./**/!(*_index|*.spec).js']);

View File

@ -0,0 +1,28 @@
'use strict';
var servicesModule = require('./_index.js');
/**
* @ngInject
*/
function ExampleService($q, $http) {
var service = {};
service.get = function() {
var deferred = $q.defer();
$http.get('apiPath').success(function(data) {
deferred.resolve(data);
}).error(function(err, status) {
deferred.reject(err, status);
});
return deferred.promise;
};
return service;
}
servicesModule.service('ExampleService', ExampleService);

View File

@ -0,0 +1,42 @@
p {
margin-bottom: 1em;
}
.heading {
margin-bottom: 0.618em;
&.-large {
font-size: $font-size--lg;
font-weight: bold;
line-height: $half-space * 3 / 2;
}
&.-medium {
font-size: $font-size--md;
font-weight: normal;
line-height: $half-space;
}
&.-small {
font-size: $font-size--sm;
font-weight: bold;
line-height: $half-space * 2 / 3;
}
&.-smallest {
font-size: $font-size--xs;
font-weight: bold;
}
}
h1 {
@extend .heading.-large;
}
h2 {
@extend .heading.-medium;
}
h3 {
@extend .heading.-small;
}

19
app/styles/_vars.scss Normal file
View File

@ -0,0 +1,19 @@
// colors
$font-color--dark: #333;
$font-color--light: #fff;
$background--light: #eee;
$background--dark: #222;
$blue: #1f8de2;
$green: #1fe27b;
$red: #e21f3f;
// spacing
$full-space: 40px;
$half-space: 20px;
// font sizing
$font-size--xs: 10px;
$font-size--sm: 12px;
$font-size--md: 16px;
$font-size--lg: 24px;
$font-size--xl: 32px;

9
app/styles/main.scss Normal file
View File

@ -0,0 +1,9 @@
@import 'vars';
@import 'typography';
body {
font-family: Helvetica, sans-serif;
color: $font-color--dark;
background-color: $background--light;
padding: $half-space;
}

7
app/views/home.html Normal file
View File

@ -0,0 +1,7 @@
<h1 class="heading -large">{{ home.title }}</h1>
<h3 class="heading -medium">Here is a fancy number served up courtesy of Angular: <span class="number-example">{{ home.number }}</span></h3>
<img src="images/angular.png" height="100" example-directive />
<img src="images/gulp.png" height="100" />
<img src="images/browserify.png" height="100" />

23
gulp/LICENSE Normal file
View File

@ -0,0 +1,23 @@
Imported from https://github.com/jakemmarsh/angularjs-gulp-browserify-boilerplate :
The MIT License (MIT)
Copyright (c) 2014 Jake Marsh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

59
gulp/config.js Normal file
View File

@ -0,0 +1,59 @@
'use strict';
module.exports = {
'browserPort' : 3000,
'UIPort' : 3001,
'serverPort' : 3002,
'styles': {
'src' : 'app/styles/**/*.scss',
'dest': 'build/css'
},
'scripts': {
'src' : 'app/js/**/*.js',
'dest': 'build/js'
},
'images': {
'src' : 'app/images/**/*',
'dest': 'build/images'
},
'fonts': {
'src' : ['app/fonts/**/*'],
'dest': 'build/fonts'
},
'views': {
'watch': [
'app/index.html',
'app/views/**/*.html'
],
'src': 'app/views/**/*.html',
'dest': 'app/js'
},
'gzip': {
'src': 'build/**/*.{html,xml,json,css,js,js.map}',
'dest': 'build/',
'options': {}
},
'dist': {
'root' : 'build'
},
'browserify': {
'entries' : ['./app/js/main.js'],
'bundleName': 'main.js',
'sourcemap' : true
},
'test': {
'karma': 'test/karma.conf.js',
'protractor': 'test/protractor.conf.js'
}
};

9
gulp/index.js Normal file
View File

@ -0,0 +1,9 @@
'use strict';
var fs = require('fs');
var onlyScripts = require('./util/scriptFilter');
var tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts);
tasks.forEach(function(task) {
require('./tasks/' + task);
});

17
gulp/tasks/browserSync.js Normal file
View File

@ -0,0 +1,17 @@
'use strict';
var config = require('../config');
var browserSync = require('browser-sync');
var gulp = require('gulp');
gulp.task('browserSync', function() {
browserSync({
port: config.browserPort,
ui: {
port: config.UIPort
},
proxy: 'localhost:' + config.serverPort
});
});

76
gulp/tasks/browserify.js Normal file
View File

@ -0,0 +1,76 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var gulpif = require('gulp-if');
var gutil = require('gulp-util');
var source = require('vinyl-source-stream');
var sourcemaps = require('gulp-sourcemaps');
var buffer = require('vinyl-buffer');
var streamify = require('gulp-streamify');
var watchify = require('watchify');
var browserify = require('browserify');
var babelify = require('babelify');
var uglify = require('gulp-uglify');
var handleErrors = require('../util/handleErrors');
var browserSync = require('browser-sync');
var debowerify = require('debowerify');
var ngAnnotate = require('browserify-ngannotate');
// Based on: http://blog.avisi.nl/2014/04/25/how-to-keep-a-fast-build-with-browserify-and-reactjs/
function buildScript(file) {
var bundler = browserify({
entries: config.browserify.entries,
debug: true,
cache: {},
packageCache: {},
fullPaths: true
}, watchify.args);
if ( !global.isProd ) {
bundler = watchify(bundler);
bundler.on('update', function() {
rebundle();
});
}
var transforms = [
babelify,
debowerify,
ngAnnotate,
'brfs',
'bulkify'
];
transforms.forEach(function(transform) {
bundler.transform(transform);
});
function rebundle() {
var stream = bundler.bundle();
var createSourcemap = global.isProd && config.browserify.sourcemap;
gutil.log('Rebundle...');
return stream.on('error', handleErrors)
.pipe(source(file))
.pipe(gulpif(createSourcemap, buffer()))
.pipe(gulpif(createSourcemap, sourcemaps.init()))
.pipe(gulpif(global.isProd, streamify(uglify({
compress: { drop_console: true }
}))))
.pipe(gulpif(createSourcemap, sourcemaps.write('./')))
.pipe(gulp.dest(config.scripts.dest))
.pipe(browserSync.reload({ stream: true, once: true }));
}
return rebundle();
}
gulp.task('browserify', function() {
return buildScript('main.js');
});

11
gulp/tasks/clean.js Normal file
View File

@ -0,0 +1,11 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var del = require('del');
gulp.task('clean', function(cb) {
del([config.dist.root], cb);
});

9
gulp/tasks/deploy.js Normal file
View File

@ -0,0 +1,9 @@
'use strict';
var gulp = require('gulp');
gulp.task('deploy', ['prod'], function() {
// Any deployment logic should go here
});

14
gulp/tasks/development.js Normal file
View File

@ -0,0 +1,14 @@
'use strict';
var gulp = require('gulp');
var runSequence = require('run-sequence');
gulp.task('dev', ['clean'], function(cb) {
cb = cb || function() {};
global.isProd = false;
runSequence(['styles', 'images', 'fonts', 'views', 'browserify'], 'watch', cb);
});

15
gulp/tasks/fonts.js Normal file
View File

@ -0,0 +1,15 @@
'use strict';
var config = require('../config');
var changed = require('gulp-changed');
var gulp = require('gulp');
var browserSync = require('browser-sync');
gulp.task('fonts', function() {
return gulp.src(config.fonts.src)
.pipe(changed(config.fonts.dest)) // Ignore unchanged files
.pipe(gulp.dest(config.fonts.dest))
.pipe(browserSync.reload({ stream: true, once: true }));
});

13
gulp/tasks/gzip.js Normal file
View File

@ -0,0 +1,13 @@
'use strict';
var gulp = require('gulp');
var gzip = require('gulp-gzip');
var config = require('../config');
gulp.task('gzip', function() {
return gulp.src(config.gzip.src)
.pipe(gzip(config.gzip.options))
.pipe(gulp.dest(config.gzip.dest));
});

18
gulp/tasks/images.js Normal file
View File

@ -0,0 +1,18 @@
'use strict';
var config = require('../config');
var changed = require('gulp-changed');
var gulp = require('gulp');
var gulpif = require('gulp-if');
//var imagemin = require('gulp-imagemin');
var browserSync = require('browser-sync');
gulp.task('images', function() {
return gulp.src(config.images.src)
.pipe(changed(config.images.dest)) // Ignore unchanged files
//.pipe(gulpif(global.isProd, imagemin())) // Optimize
.pipe(gulp.dest(config.images.dest))
.pipe(browserSync.reload({ stream: true, once: true }));
});

11
gulp/tasks/lint.js Normal file
View File

@ -0,0 +1,11 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var jshint = require('gulp-jshint');
gulp.task('lint', function() {
return gulp.src([config.scripts.src, '!app/js/templates.js'])
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});

14
gulp/tasks/production.js Normal file
View File

@ -0,0 +1,14 @@
'use strict';
var gulp = require('gulp');
var runSequence = require('run-sequence');
gulp.task('prod', ['clean'], function(cb) {
cb = cb || function() {};
global.isProd = true;
runSequence(['styles', 'images', 'fonts', 'views', 'browserify'], 'gzip', cb);
});

23
gulp/tasks/protractor.js Normal file
View File

@ -0,0 +1,23 @@
'use strict';
var gulp = require('gulp');
var protractor = require('gulp-protractor').protractor;
var webdriver = require('gulp-protractor').webdriver;
var webdriverUpdate = require('gulp-protractor').webdriver_update;
var config = require('../config');
gulp.task('webdriver-update', webdriverUpdate);
gulp.task('webdriver', webdriver);
gulp.task('protractor', ['webdriver-update', 'webdriver', 'server'], function() {
return gulp.src('test/e2e/**/*.js')
.pipe(protractor({
configFile: config.test.protractor
}))
.on('error', function(err) {
// Make sure failed tests cause gulp to exit non-zero
throw err;
});
});

36
gulp/tasks/server.js Normal file
View File

@ -0,0 +1,36 @@
'use strict';
var config = require('../config');
var http = require('http');
var express = require('express');
var gulp = require('gulp');
var gutil = require('gulp-util');
var morgan = require('morgan');
gulp.task('server', function() {
var server = express();
// log all requests to the console
server.use(morgan('dev'));
server.use(express.static(config.dist.root));
// Serve index.html for all routes to leave routing up to Angular
server.all('/*', function(req, res) {
res.sendFile('index.html', { root: 'build' });
});
// Start webserver if not already running
var s = http.createServer(server);
s.on('error', function(err){
if(err.code === 'EADDRINUSE'){
gutil.log('Development server is already started at port ' + config.serverPort);
}
else {
throw err;
}
});
s.listen(config.serverPort);
});

24
gulp/tasks/styles.js Normal file
View File

@ -0,0 +1,24 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var sass = require('gulp-sass');
var gulpif = require('gulp-if');
var handleErrors = require('../util/handleErrors');
var browserSync = require('browser-sync');
var autoprefixer = require('gulp-autoprefixer');
gulp.task('styles', function () {
return gulp.src(config.styles.src)
.pipe(sass({
sourceComments: global.isProd ? 'none' : 'map',
sourceMap: 'sass',
outputStyle: global.isProd ? 'compressed' : 'nested'
}))
.pipe(autoprefixer("last 2 versions", "> 1%", "ie 8"))
.on('error', handleErrors)
.pipe(gulp.dest(config.styles.dest))
.pipe(browserSync.reload({ stream: true }));
});

10
gulp/tasks/test.js Normal file
View File

@ -0,0 +1,10 @@
'use strict';
var gulp = require('gulp');
var runSequence = require('run-sequence');
gulp.task('test', ['server'], function() {
return runSequence('unit', 'protractor');
});

21
gulp/tasks/unit.js Normal file
View File

@ -0,0 +1,21 @@
'use strict';
var gulp = require('gulp');
var karma = require('gulp-karma');
var config = require('../config');
gulp.task('unit', ['views'], function() {
// Nonsensical source to fall back to files listed in karma.conf.js,
// see https://github.com/lazd/gulp-karma/issues/9
return gulp.src('./thisdoesntexist')
.pipe(karma({
configFile: config.test.karma,
action: 'run'
}))
.on('error', function(err) {
// Make sure failed tests cause gulp to exit non-zero
throw err;
});
});

21
gulp/tasks/views.js Normal file
View File

@ -0,0 +1,21 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var templateCache = require('gulp-angular-templatecache');
// Views task
gulp.task('views', function() {
// Put our index.html in the dist folder
gulp.src('app/index.html')
.pipe(gulp.dest(config.dist.root));
// Process any other view files from app/views
return gulp.src(config.views.src)
.pipe(templateCache({
standalone: true
}))
.pipe(gulp.dest(config.views.dest));
});

15
gulp/tasks/watch.js Normal file
View File

@ -0,0 +1,15 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
gulp.task('watch', ['browserSync', 'server'], function() {
// Scripts are automatically watched and rebundled by Watchify inside Browserify task
gulp.watch(config.scripts.src, ['lint']);
gulp.watch(config.styles.src, ['styles']);
gulp.watch(config.images.src, ['images']);
gulp.watch(config.fonts.src, ['fonts']);
gulp.watch(config.views.watch, ['views']);
});

25
gulp/util/bundleLogger.js Normal file
View File

@ -0,0 +1,25 @@
'use strict';
/* bundleLogger
* ------------
* Provides gulp style logs to the bundle method in browserify.js
*/
var gutil = require('gulp-util');
var prettyHrtime = require('pretty-hrtime');
var startTime;
module.exports = {
start: function() {
startTime = process.hrtime();
gutil.log('Running', gutil.colors.green('\'bundle\'') + '...');
},
end: function() {
var taskTime = process.hrtime(startTime);
var prettyTime = prettyHrtime(taskTime);
gutil.log('Finished', gutil.colors.green('\'bundle\''), 'in', gutil.colors.magenta(prettyTime));
}
};

27
gulp/util/handleErrors.js Normal file
View File

@ -0,0 +1,27 @@
'use strict';
var notify = require('gulp-notify');
module.exports = function(error) {
if( !global.isProd ) {
var args = Array.prototype.slice.call(arguments);
// Send error to notification center with gulp-notify
notify.onError({
title: 'Compile Error',
message: '<%= error.message %>'
}).apply(this, args);
// Keep gulp from hanging on this task
this.emit('end');
} else {
// Log the error and stop the process
// to prevent broken code from building
console.log(error);
process.exit(1);
}
};

11
gulp/util/scriptFilter.js Normal file
View File

@ -0,0 +1,11 @@
'use strict';
var path = require('path');
// Filters out non .js files. Prevents
// accidental inclusion of possible hidden files
module.exports = function(name) {
return /(\.(js)$)/i.test(path.extname(name));
};

16
gulpfile.js Normal file
View File

@ -0,0 +1,16 @@
'use strict';
/*
* gulpfile.js
* ===========
* Rather than manage one giant configuration file responsible
* for creating multiple tasks, each task has been broken out into
* its own file in gulp/tasks. Any file in that folder gets automatically
* required by the loop in ./gulp/index.js (required below).
*
* To add a new task, simply add a new task file to gulp/tasks.
*/
global.isProd = false;
require('./gulp');

View File

@ -6,18 +6,62 @@
"repository": "none", "repository": "none",
"license": "Apache 2.0", "license": "Apache 2.0",
"devDependencies": { "devDependencies": {
"angular": "^1.3.15",
"angular-mocks": "^1.3.15",
"angular-ui-router": "^0.2.13",
"babelify": "^5.0.4",
"brfs": "^1.2.0",
"browser-sync": "^2.7.6",
"browserify": "^5.10.0",
"browserify-istanbul": "^0.2.0",
"browserify-ngannotate": "^0.1.0",
"bulk-require": "^0.2.1",
"bulkify": "^1.1.1",
"debowerify": "^1.2.0",
"del": "^0.1.3",
"eslint": "^0.23.0", "eslint": "^0.23.0",
"eslint-config-openstack": "1.2.0", "eslint-config-openstack": "1.2.0",
"express": "^4.7.2",
"gulp": "^3.8.8",
"gulp-angular-templatecache": "^1.3.0",
"gulp-autoprefixer": "^2.0.0",
"gulp-changed": "^1.0.0",
"gulp-gzip": "^0.0.8",
"gulp-if": "^1.2.5",
"gulp-imagemin": "^1.1.0",
"gulp-jshint": "^1.8.3",
"gulp-karma": "0.0.4",
"gulp-notify": "^2.0.0",
"gulp-protractor": "0.0.11",
"gulp-rename": "^1.2.0",
"gulp-sass": "^1.3.3",
"gulp-sourcemaps": "^1.3.0",
"gulp-streamify": "0.0.5",
"gulp-uglify": "^1.0.1",
"gulp-util": "^3.0.1",
"isparta": "^3.0.3",
"jasmine-ajax": "^3.1.1", "jasmine-ajax": "^3.1.1",
"jasmine-core": "^2.3.4", "jasmine-core": "^2.3.4",
"jasmine-fixture": "^1.3.2", "jasmine-fixture": "^1.3.2",
"jshint-stylish": "^1.0.0",
"karma": "^0.13.4", "karma": "^0.13.4",
"karma-babel-preprocessor": "^4.0.1",
"karma-browserify": "^4.0.0",
"karma-chrome-launcher": "0.1.8", "karma-chrome-launcher": "0.1.8",
"karma-cli": "0.0.4", "karma-cli": "0.0.4",
"karma-coverage": "0.3.1", "karma-coverage": "0.3.1",
"karma-jasmine": "^0.3.6", "karma-jasmine": "^0.3.6",
"karma-phantomjs-launcher": "0.2.0", "karma-phantomjs-launcher": "0.2.0",
"phantomjs": "1.9.17" "morgan": "^1.6.1",
"phantomjs": "1.9.17",
"pretty-hrtime": "^1.0.0",
"protractor": "^2.2.0",
"run-sequence": "^1.1.2",
"tiny-lr": "^0.1.6",
"uglifyify": "^3.0.1",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.3.1"
}, },
"scripts": { "scripts": {
"postinstall": "if [ ! -d .venv ]; then tox -epy27 --notest; fi", "postinstall": "if [ ! -d .venv ]; then tox -epy27 --notest; fi",

21
test/e2e/example_spec.js Normal file
View File

@ -0,0 +1,21 @@
/*global browser, by */
'use strict';
describe('E2E: Example', function() {
beforeEach(function() {
browser.get('/');
browser.waitForAngular();
});
it('should route correctly', function() {
expect(browser.getLocationAbsUrl()).toMatch('/');
});
it('should show the number defined in the controller', function() {
var element = browser.findElement(by.css('.number-example'));
expect(element.getText()).toEqual('1234');
});
});

12
test/e2e/routes_spec.js Normal file
View File

@ -0,0 +1,12 @@
/*global browser */
'use strict';
describe('E2E: Routes', function() {
it('should have a working home route', function() {
browser.get('#/');
expect(browser.getLocationAbsUrl()).toMatch('/');
});
});

51
test/karma.conf.js Normal file
View File

@ -0,0 +1,51 @@
'use strict';
var istanbul = require('browserify-istanbul');
var isparta = require('isparta');
module.exports = function(config) {
config.set({
basePath: '../',
frameworks: ['jasmine', 'browserify'],
preprocessors: {
'app/js/**/*.js': ['browserify', 'babel', 'coverage']
},
browsers: ['Chrome'],
reporters: ['progress', 'coverage'],
autoWatch: true,
browserify: {
debug: true,
transform: [
'bulkify',
istanbul({
instrumenter: isparta,
ignore: ['**/node_modules/**', '**/test/**']
})
]
},
proxies: {
'/': 'http://localhost:9876/'
},
urlRoot: '/__karma__/',
files: [
// 3rd-party resources
'node_modules/angular/angular.min.js',
'node_modules/angular-mocks/angular-mocks.js',
// app-specific code
'app/js/main.js',
// test files
'test/unit/**/*.js'
]
});
};

32
test/protractor.conf.js Normal file
View File

@ -0,0 +1,32 @@
'use strict';
var gulpConfig = require('../gulp/config');
exports.config = {
allScriptsTimeout: 11000,
baseUrl: 'http://localhost:' + gulpConfig.serverPort + '/',
directConnect: true,
capabilities: {
browserName: 'chrome',
version: '',
platform: 'ANY'
},
framework: 'jasmine',
jasmineNodeOpts: {
isVerbose: false,
showColors: true,
includeStackTrace: true,
defaultTimeoutInterval: 30000
},
specs: [
'e2e/**/*.js'
]
};

View File

@ -0,0 +1,27 @@
/*global angular */
'use strict';
describe('Unit: Constants', function() {
var constants;
beforeEach(function() {
// instantiate the app module
angular.mock.module('app');
// mock the directive
angular.mock.inject(function(AppSettings) {
constants = AppSettings;
});
});
it('should exist', function() {
expect(constants).toBeDefined();
});
it('should have an application name', function() {
expect(constants.appTitle).toEqual('Example Application');
});
});

View File

@ -0,0 +1,30 @@
/*global angular */
'use strict';
describe('Unit: ExampleCtrl', function() {
var ctrl;
beforeEach(function() {
// instantiate the app module
angular.mock.module('app');
angular.mock.inject(function($controller) {
ctrl = $controller('ExampleCtrl');
});
});
it('should exist', function() {
expect(ctrl).toBeDefined();
});
it('should have a number variable equal to 1234', function() {
expect(ctrl.number).toEqual(1234);
});
it('should have a title variable equal to \'AngularJS, Gulp, and Browserify!\'', function() {
expect(ctrl.title).toEqual('AngularJS, Gulp, and Browserify!');
});
});

View File

@ -0,0 +1,23 @@
/*global angular */
'use strict';
describe('Unit: ExampleService', function() {
var service;
beforeEach(function() {
// instantiate the app module
angular.mock.module('app');
// mock the service
angular.mock.inject(function(ExampleService) {
service = ExampleService;
});
});
it('should exist', function() {
expect(service).toBeDefined();
});
});