├── .bowerrc
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── app
├── components
│ ├── core
│ │ ├── core.scss
│ │ └── index.js
│ ├── header
│ │ ├── header.jade
│ │ ├── header.js
│ │ ├── header.scss
│ │ ├── header.spec.js
│ │ └── index.js
│ └── util
│ │ ├── register.js
│ │ └── test-helpers.js
├── index.jade
├── main.js
├── state1
│ ├── index.js
│ ├── state1.jade
│ ├── state1.js
│ ├── state1.scss
│ └── state1.spec.js
└── state2
│ ├── index.js
│ ├── state2.jade
│ ├── state2.js
│ ├── state2.scss
│ └── state2.spec.js
├── bower.json
├── config
├── _bootstrap-customizations.scss
├── bootstrap-sass.config.js
├── environments.json
├── karma.config.js
├── protractor-local.config.js
├── protractor-remote.config.js
├── superstatic.json
├── webpack-dev.config.js
├── webpack-make-config.js
├── webpack-prod.config.js
├── webpack-stage.config.js
└── webpack-test.config.js
├── gulpfile.js
├── package.json
└── test
├── e2e
├── state1.spec.js
└── state2.spec.js
└── unit.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "vendor"
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "rules": {
4 | "no-underscore-dangle": 0,
5 | "no-use-before-define": "nofunc",
6 | "no-unused-expressions": 0,
7 | "no-empty-class": 0,
8 | "quotes": "single"
9 | },
10 | "env": {
11 | "node": true
12 | },
13 | "globals": {
14 | "angular": true,
15 | "$": true,
16 | "jQuery": true,
17 | "moment": true,
18 | "window": true,
19 | "document": true,
20 | "Modernizr": true,
21 | "__TESTING__": true,
22 | "beforeEach": true,
23 | "expect": true,
24 | "describe": true,
25 | "it": true,
26 | "element": true,
27 | "by": true,
28 | "browser": true,
29 | "inject": true,
30 | "register": true,
31 | "sinon": true,
32 | "_": false
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .build
2 | build
3 | node_modules
4 | vendor
5 | .tmp
6 | .sass-cache
7 | bower_components
8 | coverage
9 | .DS_Store
10 | mocha.json
11 |
12 | # IDE
13 | .idea
14 |
15 | .ntvs_analysis.dat
16 | .vs/bin
17 | .vs/obj
18 | *.suo
19 | /nbproject
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Alexandru Badiu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # webpack-angularjs
2 |
3 | A boilerplate to kickstart development using Webpack, Gulp, AngularJS and ES6. Needs better documentation.
4 |
5 | Features
6 | ---
7 | * Gulp and Webpack as a build system.
8 | * Superstatic, webpack-dev-server and BrowserSync for development.
9 | * ES6 via babel and [register.js](http://www.michaelbromley.co.uk/blog/350/using-es6-classes-in-angularjs-1-x), with ESLint.
10 | * SASS with Bootstrap and Bourbon.
11 | * Support for jQuery, Modernizr.
12 | * Support for [lazy loading via ocLazyLoad and webpack's code splitting mechanism](https://github.com/voidberg/webpack-angularjs-lazyload).
13 | * Modular code structure inspired by Google's recommendations.
14 | * Unit tests with support for Bamboo and code coverage via Istanbul.
15 | * E2E tests, local and remote (SauceLabs), with support for Bamboo.
16 |
17 | See this presentation for the background: [Towards AngularJS 2, with Webpack and ES6](http://alexandrubadiu.ro/talks/angular_webpack/#/).
18 |
19 | Global dependencies installation
20 | ---
21 |
22 | * Install node
23 | * npm install -g gulp webpack
24 |
25 | Installation of local dependencies
26 | ---
27 |
28 | * Install node dependencies: ```npm install```
29 | * Install bower dependencies: ```bower install```
30 |
31 | #### You might get an error when installing webdriver
32 |
33 | There is a known bug with higher versions of node, where the chromedriver fails to uncompress.
34 |
35 | In these cases, you can :
36 | 1) Download the chrome driver from http://chromedriver.storage.googleapis.com/index.html
37 | 2) Manually decompress it
38 | 3) copy the driver to `node_modules/protractor/selenium/chromedriver`
39 |
40 | Details of the bug here : https://github.com/angular/protractor/issues/1005
41 |
42 | Workflow
43 | ---
44 |
45 | * Run development server: ```gulp```
46 | * Build project: ```gulp build```
47 | * Example: production-type build with development environment variables: ```gulp build --build-type=production --build-environment=development```
48 |
49 | Environments and build types
50 | ---
51 | * **Build type:** Using ```--build-type``` you can specify whether to use ```development``` (default) or ```production``` build type.
52 | * **Build environment variables:** Using ```--build-environment``` you can specify whether to use ```development``` (default), ```stage``` or ```production``` environment variables.
53 |
54 | Unit tests
55 | ---
56 | * Tests are written using Mocha, Chai and Sinon (in ```tests/unit```).
57 | * They are ran by Karma.
58 | * Run ```gulp test --type=unit``` for one round of tests or ```gulp test --type=unit --watch``` for continuous testing.
59 | * Add the ```--bamboo``` option if the tests are ran for Bamboo (will create mocha.json).
60 | * They will generate coverage reports in the ```coverage``` directory.
61 |
62 | Browser tests
63 | ---
64 | * Tests are written as features using Mocha, Chai and Sinon (in ```tests/{folder}```).
65 | * They are run by Protractor.
66 | * Run ```gulp test --type={folder}``` for local testing or ```gulp test --type={folder} --where=remote``` for remote testing using SauceLabs.
67 | * Add the ```--bamboo``` option if the tests are ran for Bamboo (will create mocha.json).
68 |
69 | Testing using SauceLabs needs credentials to be set via the shell.
70 |
71 | Bash
72 | ```
73 | export SAUCE_USERNAME=username
74 | export SAUCE_ACCESS_KEY=foo-bar-baz
75 | ```
76 |
77 | Fish
78 | ```
79 | set -x SAUCE_USERNAME username
80 | set -x SAUCE_ACCESS_KEY foo-bar-baz
81 | ```
82 |
--------------------------------------------------------------------------------
/app/components/core/core.scss:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | }
--------------------------------------------------------------------------------
/app/components/core/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('./core.scss');
4 |
5 | var mod = angular.module('core', []);
6 |
7 | module.exports = mod;
8 |
--------------------------------------------------------------------------------
/app/components/header/header.jade:
--------------------------------------------------------------------------------
1 | nav.navbar.navbar-inverse.navbar-fixed-top
2 | .container
3 | .navbar-header
4 | button.navbar-toggle.collapsed(type="button", data-toggle="collapse", data-target="#navbar", aria-expanded="false", aria-controls="navbar")
5 | span.sr-only Toggle navigation
6 | span.icon-bar
7 | span.icon-bar
8 | span.icon-bar
9 | a.navbar-brand(href="/") Webpack AngularJS Boilerplate
10 |
11 | #navbar.collapse.navbar-collapse
12 | ul.nav.navbar-nav
13 | li(ui-sref-active="active")
14 | a(ui-sref="state1") Home
15 | li(ui-sref-active="active")
16 | a(ui-sref="state2") Page 2
17 |
--------------------------------------------------------------------------------
/app/components/header/header.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | class Header {
4 | /*@ngInject*/
5 | constructor() {
6 | this.template = require('./header.jade');
7 | this.restrict = 'E';
8 | this.controller = HeaderController;
9 | this.controllerAs = 'ctrl';
10 | this.bindToController = true;
11 | this.scope = {
12 | };
13 | }
14 | }
15 |
16 | class HeaderController {
17 | /*@ngInject*/
18 | constructor() {
19 | }
20 | }
21 |
22 | module.exports = Header;
23 |
--------------------------------------------------------------------------------
/app/components/header/header.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngBucharest/webpack-angularjs/7d04d0493dc5babb45b5aab18ed7b403b85f05a1/app/components/header/header.scss
--------------------------------------------------------------------------------
/app/components/header/header.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('angular');
4 | require('ui-router');
5 | require('angular-mocks/angular-mocks');
6 |
7 | angular.module('foo.header', []);
8 |
9 | register('foo.header').directive('header', require('./header.js'));
10 |
11 | describe('Directive: header', function () {
12 | beforeEach(window.module('foo.header'));
13 |
14 | var elementHtml = '';
15 |
16 | it('should fail to run as a function', function () {
17 | var cls = require('./header.js');
18 | expect(function(){
19 | cls();
20 | }).to.throw('Cannot call a class as a function');
21 | });
22 |
23 | it('should correctly render', inject(function ($compile, _$rootScope_) {
24 | var element = angular.element(elementHtml);
25 | var $scope = _$rootScope_.$new();
26 |
27 | element = $compile(element)($scope);
28 | $scope.$digest();
29 |
30 | expect(element.find('nav').length).to.equal(1);
31 |
32 | expect(element.find('li a').eq(0).text()).to.equal('Home');
33 | expect(element.find('li a').eq(1).text()).to.equal('Page 2');
34 | }));
35 | });
36 |
--------------------------------------------------------------------------------
/app/components/header/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('./header.scss');
4 |
5 | var mod = angular.module('foo.header', [
6 | ]);
7 |
8 | register(mod.name).directive('header', require('./header.js'));
9 |
10 | module.exports = mod;
11 |
--------------------------------------------------------------------------------
/app/components/util/register.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * A helper class to simplify registering Angular components and provide a consistent syntax for doing so.
5 | */
6 | function register(appName) {
7 |
8 | var app = angular.module(appName);
9 |
10 | return {
11 | directive: directive,
12 | controller: controller,
13 | service: service,
14 | provider: provider,
15 | factory: factory
16 | };
17 |
18 | function directive(name, constructorFn) {
19 |
20 | constructorFn = _normalizeConstructor(constructorFn);
21 |
22 | if (!constructorFn.prototype.compile) {
23 | // create an empty compile function if none was defined.
24 | constructorFn.prototype.compile = () => {};
25 | }
26 |
27 | var originalCompileFn = _cloneFunction(constructorFn.prototype.compile);
28 |
29 | // Decorate the compile method to automatically return the link method (if it exists)
30 | // and bind it to the context of the constructor (so `this` works correctly).
31 | // This gets around the problem of a non-lexical "this" which occurs when the directive class itself
32 | // returns `this.link` from within the compile function.
33 | _override(constructorFn.prototype, 'compile', function () {
34 | return function () {
35 | originalCompileFn.apply(this, arguments);
36 |
37 | if (constructorFn.prototype.link) {
38 | return constructorFn.prototype.link.bind(this);
39 | }
40 | };
41 | });
42 |
43 | var factoryArray = _createFactoryArray(constructorFn);
44 | app.directive(name, factoryArray);
45 | return this;
46 | }
47 |
48 | function controller(name, contructorFn) {
49 | app.controller(name, contructorFn);
50 | return this;
51 | }
52 |
53 | function service(name, contructorFn) {
54 | app.service(name, contructorFn);
55 | return this;
56 | }
57 |
58 | function provider(name, constructorFn) {
59 | app.provider(name, constructorFn);
60 | return this;
61 | }
62 |
63 | function factory(name, constructorFn) {
64 | constructorFn = _normalizeConstructor(constructorFn);
65 | var factoryArray = _createFactoryArray(constructorFn);
66 | app.factory(name, factoryArray);
67 | return this;
68 | }
69 |
70 | /**
71 | * If the constructorFn is an array of type ['dep1', 'dep2', ..., constructor() {}]
72 | * we need to pull out the array of dependencies and add it as an $inject property of the
73 | * actual constructor function.
74 | * @param input
75 | * @returns {*}
76 | * @private
77 | */
78 | function _normalizeConstructor(input) {
79 | var constructorFn;
80 |
81 | if (input.constructor === Array) {
82 | //
83 | var injected = input.slice(0, input.length - 1);
84 | constructorFn = input[input.length - 1];
85 | constructorFn.$inject = injected;
86 | } else {
87 | constructorFn = input;
88 | }
89 |
90 | return constructorFn;
91 | }
92 |
93 | /**
94 | * Convert a constructor function into a factory function which returns a new instance of that
95 | * constructor, with the correct dependencies automatically injected as arguments.
96 | *
97 | * In order to inject the dependencies, they must be attached to the constructor function with the
98 | * `$inject` property annotation.
99 | *
100 | * @param constructorFn
101 | * @returns {Array.}
102 | * @private
103 | */
104 | function _createFactoryArray(constructorFn) {
105 | // get the array of dependencies that are needed by this component (as contained in the `$inject` array)
106 | var args = constructorFn.$inject || [];
107 | var factoryArray = args.slice(); // create a copy of the array
108 | // The factoryArray uses Angular's array notation whereby each element of the array is the name of a
109 | // dependency, and the final item is the factory function itself.
110 | factoryArray.push((...args) => { //eslint-disable-line no-shadow
111 | //return new constructorFn(...args);
112 | var instance = new constructorFn(...args); //eslint-disable-line new-cap
113 | for (var key in instance) {
114 | instance[key] = instance[key];
115 | }
116 | return instance;
117 | });
118 |
119 | return factoryArray;
120 | }
121 |
122 | /**
123 | * Clone a function
124 | * @param original
125 | * @returns {Function}
126 | */
127 | function _cloneFunction(original) {
128 | return function() {
129 | return original.apply(this, arguments);
130 | };
131 | }
132 |
133 | /**
134 | * Override an object's method with a new one specified by `callback`.
135 | * @param object
136 | * @param methodName
137 | * @param callback
138 | */
139 | function _override(object, methodName, callback) {
140 | object[methodName] = callback(object[methodName]);
141 | }
142 |
143 | }
144 |
145 | module.exports = register;
146 |
--------------------------------------------------------------------------------
/app/components/util/test-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | triggerKeyDown: function triggerKeyDown(element, keyCode) {
5 | var e = $.Event('keydown'); // eslint-disable-line new-cap
6 |
7 | e.which = keyCode;
8 | e.keyCode = keyCode;
9 | element.trigger(e);
10 | },
11 |
12 | triggerKeyPress: function triggerKeyPress(element, keyCode) {
13 | var e = $.Event('keypress'); // eslint-disable-line new-cap
14 | e.which = keyCode;
15 | e.keyCode = keyCode;
16 | element.trigger(e);
17 | },
18 |
19 | triggerKeyUp: function triggerKeyUp(element, keyCode) {
20 | var e = $.Event('keyup'); // eslint-disable-line new-cap
21 | e.which = keyCode;
22 | e.keyCode = keyCode;
23 | element.trigger(e);
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/app/index.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(ng-app="webpack.angular", ng-strict-di)
3 | head
4 | meta(charset="UTF-8")
5 | meta(http-equiv="Content-type" content="text/html;charset=UTF-8")
6 | meta(http-equiv="X-UA-Compatible" content="IE=edge,chrome=1")
7 |
8 | title Webpack AngularJS Boilerplate
9 |
10 | base(href="/")
11 |
12 | link(href="/favicon.ico" rel="shortcut icon" type="image/x-icon")
13 | style.
14 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
15 | display: none !important;
16 | }
17 |
18 | //
19 | [if lt IE 9]>
20 |
21 | "
6 | ],
7 | "moduleType": [
8 | "es6"
9 | ],
10 | "license": "MIT",
11 | "private": true,
12 | "ignore": [
13 | "**/.*",
14 | "node_modules",
15 | "bower_components",
16 | "app/vendors",
17 | "test",
18 | "tests"
19 | ],
20 | "dependencies": {
21 | "angularjs": "~1.3.15",
22 | "lodash": "~3.5.0",
23 | "angular-ui-router": "~0.2.13",
24 | "ocLazyLoad": "~0.6.3",
25 | "jquery": "~2.1.3",
26 | "angular-mocks": "~1.3.15",
27 | "modernizr": "~2.8.3"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/config/_bootstrap-customizations.scss:
--------------------------------------------------------------------------------
1 | // Customize Bootstrap Variables
--------------------------------------------------------------------------------
/config/bootstrap-sass.config.js:
--------------------------------------------------------------------------------
1 | // Example file. Copy this to your project. Change then names of the referenced files or comment them out.
2 | // Convention is to name sass partials to start with an "_"
3 | module.exports = {
4 | verbose: false, // Set to true to show diagnostic information
5 |
6 | // IMPORTANT: Set next two configuration so you can customize
7 | // bootstrapCustomizations: gets loaded before bootstrap so you can configure the variables used by bootstrap
8 | // mainSass: gets loaded after bootstrap, so you can override a bootstrap style.
9 | // NOTE, these are optional.
10 |
11 | // Use preBootstrapCustomizations to change $brand-primary. Ensure this preBootstrapCustomizations does not
12 | // depend on other bootstrap variables.
13 | // preBootstrapCustomizations: "./app/components/core/bootstrap/_variables.scss",
14 |
15 | // Use bootstrapCustomizations to utilize other sass variables defined in preBootstrapCustomizations or the
16 | // _variables.scss file. This is useful to set one customization value based on another value.
17 | // bootstrapCustomizations: "./app/components/core/bootstrap/_variables.scss",
18 |
19 | //mainSass: "./_main.scss",
20 |
21 | // Default for the style loading
22 | styleLoader: "style-loader!css-loader!sass-loader",
23 | //
24 | // If you want to use the ExtractTextPlugin
25 | // and you want compressed
26 | // styleLoader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader"),
27 | //
28 | // If you want expanded CSS
29 | // styleLoader: ExtractTextPlugin.extract("style-loader", "css-loader!sass?outputStyle=expanded"),
30 |
31 | scripts: {
32 | 'affix': false,
33 | 'alert': false,
34 | 'button': false,
35 | 'carousel': false,
36 | 'collapse': false,
37 | 'dropdown': false,
38 | 'modal': false,
39 | 'popover': false,
40 | 'scrollspy': false,
41 | 'tab': false,
42 | 'tooltip': false,
43 | 'transition': false
44 | },
45 | styles: {
46 | "mixins": true,
47 |
48 | "normalize": true,
49 | "print": true,
50 |
51 | "scaffolding": true,
52 | "type": true,
53 | "code": false,
54 | "grid": true,
55 | "tables": false,
56 | "forms": true,
57 | "buttons": true,
58 |
59 | "component-animations": true,
60 | "glyphicons": false,
61 | "dropdowns": true,
62 | "button-groups": true,
63 | "input-groups": true,
64 | "navs": true,
65 | "navbar": true,
66 | "breadcrumbs": false,
67 | "pagination": false,
68 | "pager": false,
69 | "labels": false,
70 | "badges": false,
71 | "jumbotron": false,
72 | "thumbnails": false,
73 | "alerts": false,
74 | "progress-bars": false,
75 | "media": false,
76 | "list-group": false,
77 | "panels": true,
78 | "wells": false,
79 | "close": true,
80 |
81 | "modals": false,
82 | "tooltip": false,
83 | "popovers": false,
84 | "carousel": false,
85 |
86 | "utilities": true,
87 | "responsive-utilities": true
88 | }
89 | };
90 |
91 |
--------------------------------------------------------------------------------
/config/environments.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "gtmID": "GTM-FOODEV"
4 | },
5 | "stage": {
6 | "gtmID": "GTM-FOOSTAGE"
7 | },
8 | "production": {
9 | "gtmID": "GTM-FOOPROD"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/config/karma.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | var webpackConfig = require('./webpack-test.config');
5 |
6 | var entry = '../test/unit.js';
7 |
8 | webpackConfig.resolve.alias['test-helpers'] = path.resolve(__dirname, '../app/components/util/test-helpers');
9 |
10 | var preprocessors = {};
11 | preprocessors[entry] = ['webpack'];
12 |
13 | module.exports = function(config) {
14 | config.set({
15 | browserNoActivityTimeout: 155000,
16 |
17 | // base path that will be used to resolve all patterns (eg. files, exclude)
18 | basePath: '',
19 |
20 |
21 | // frameworks to use
22 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
23 | frameworks: ['mocha', 'chai', 'sinon-chai'],
24 |
25 |
26 | // list of files / patterns to load in the browser
27 | files: [
28 | entry
29 | ],
30 | webpack: webpackConfig,
31 |
32 |
33 | // list of files to exclude
34 | exclude: [
35 | ],
36 |
37 |
38 | // preprocess matching files before serving them to the browser
39 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
40 | preprocessors: preprocessors,
41 |
42 |
43 | // test results reporter to use
44 | // possible values: 'dots', 'progress'
45 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
46 | reporters: ['mocha', 'coverage'],
47 |
48 | coverageReporter: {
49 | dir: '../coverage/',
50 | reporters: [
51 | { type: 'html', subdir: '.' },
52 | { type: 'text' },
53 | ],
54 | watermarks: {
55 | statements: [ 50, 90 ],
56 | functions: [ 50, 90 ],
57 | branches: [ 50, 90 ],
58 | lines: [ 50, 90 ]
59 | }
60 | },
61 |
62 | // web server port
63 | port: 9876,
64 |
65 |
66 | // enable / disable colors in the output (reporters and logs)
67 | colors: true,
68 |
69 |
70 | // level of logging
71 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
72 | logLevel: config.LOG_INFO,
73 |
74 |
75 | // enable / disable watching file and executing tests whenever any file changes
76 | autoWatch: true,
77 |
78 |
79 | // start these browsers
80 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
81 | browsers: ['Chrome'],
82 |
83 |
84 | // Continuous Integration mode
85 | // if true, Karma captures browsers, runs the tests and exits
86 | singleRun: false,
87 |
88 | plugins: [
89 | require('karma-webpack'),
90 | require('istanbul-instrumenter-loader'),
91 | require('karma-coverage'),
92 | require('karma-bamboo-reporter'),
93 | 'karma-chai',
94 | 'karma-sinon-chai',
95 | 'karma-mocha',
96 | 'karma-mocha-reporter',
97 | 'karma-chrome-launcher'
98 | ]
99 | });
100 | };
--------------------------------------------------------------------------------
/config/protractor-local.config.js:
--------------------------------------------------------------------------------
1 | var argv = require('optimist').argv;
2 |
3 | exports.config = {
4 | allScriptsTimeout: 50000,
5 |
6 | capabilities: {
7 | 'browserName': 'chrome'
8 | },
9 |
10 | onPrepare: function () {
11 | browser.driver.manage().window().maximize();
12 | },
13 |
14 | rootElement: 'html',
15 |
16 | framework: 'mocha',
17 |
18 | mochaOpts: {
19 | reporter: argv['bamboo'] ? 'mocha-bamboo-reporter' : 'spec',
20 | slow: 3000,
21 | timeout: 1000000
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/config/protractor-remote.config.js:
--------------------------------------------------------------------------------
1 | var argv = require('optimist').argv;
2 |
3 | exports.config = {
4 | allScriptsTimeout: 11000,
5 |
6 | sauceUser: process.env.SAUCE_USERNAME,
7 | sauceKey: process.env.SAUCE_ACCESS_KEY,
8 |
9 | multiCapabilities: [{
10 | 'browserName': 'firefox'
11 | }, {
12 | 'browserName': 'chrome'
13 | }],
14 |
15 | framework: 'mocha',
16 |
17 | mochaOpts: {
18 | reporter: argv['bamboo'] ? 'mocha-bamboo-reporter' : 'spec',
19 | slow: 3000,
20 | timeout: 1000000
21 | }
22 | };
--------------------------------------------------------------------------------
/config/superstatic.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": "build",
3 | "live": false,
4 | "routes": [
5 | {
6 | "/**!(.*)": "index.html"
7 | }
8 | ]
9 | }
--------------------------------------------------------------------------------
/config/webpack-dev.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Example webpack config for the dev environment.
3 | * This is not directly used since we need to be able to override values.
4 | * It can be used for quick testing via webpack-dev-server or webpack CLI tools.
5 | *
6 | * @author Alexandru Badiu
7 | */
8 |
9 | var path = require('path');
10 | var environmentConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './environments.json'), 'utf8'));
11 |
12 | module.exports = require('./webpack-make-config')({
13 | dir: path.resolve(__dirname, '../build'),
14 |
15 | defines: {
16 | __TESTING__: false,
17 | __DEV__: true,
18 | __STAGE__: false,
19 | __PRODUCTION__: false
20 | },
21 |
22 | sourcemaps: true,
23 | devtool: 'eval',
24 | debug: true,
25 | minimize: false,
26 | chunk: true
27 | });
--------------------------------------------------------------------------------
/config/webpack-make-config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 | var bourbon = require('node-bourbon').includePaths;
4 |
5 | module.exports = function(options) {
6 | var output = {
7 | path: options.dir,
8 | pathinfo: true,
9 | filename: '[name].js'
10 | };
11 |
12 | if (options.sourcemaps) {
13 | output.sourceMapFilename = '[name].map';
14 | }
15 |
16 | var entry = {
17 | main: './main.js',
18 | vendor: [
19 | 'angular',
20 | 'ocLazyLoad',
21 | 'ui-router',
22 | 'lodash',
23 | 'modernizr',
24 | 'jquery'
25 | ]
26 | };
27 |
28 | var modulesDirectories = [
29 | '../node_modules',
30 | '../vendor'
31 | ];
32 |
33 | var aliases = {
34 | 'angular': path.resolve(__dirname, '../vendor/angular/'),
35 | 'jquery': path.resolve(__dirname, '../vendor/jquery/dist/jquery.js'),
36 | 'lodash': path.resolve(__dirname, '../vendor/lodash/lodash.js'),
37 | 'modernizr': path.resolve(__dirname, '../vendor/modernizr/modernizr.js'),
38 | 'ocLazyLoad': path.resolve(__dirname, '../vendor/ocLazyLoad/dist/ocLazyLoad.js'),
39 | 'registerjs': path.resolve(__dirname, '../app/components/util/register.js'),
40 | 'ui-router': path.resolve(__dirname, '../vendor/angular-ui-router/release/angular-ui-router.js')
41 | };
42 |
43 | var loaders = [
44 | {
45 | test: /\.js$/,
46 | exclude: [
47 | /[\\\/]node_modules/,
48 | /[\\\/]vendor/,
49 | /bootstrap-sass.config.js/
50 | ],
51 | loader: 'ng-annotate!babel'
52 | },
53 | {
54 | test: /\.es6$/,
55 | loader: 'ng-annotate!babel'
56 | },
57 | {
58 | test: /[\\\/]vendor[\\\/]angular[\\\/]angular\.js$/,
59 | loader: "imports?$=jquery"
60 | },
61 | {
62 | test: /[\\\/]vendor[\\\/]jquery[\\\/]dist[\\\/]jquery\.js$/,
63 | loader: 'expose?jQuery!expose?$'
64 | },
65 | {
66 | test: /[\\\/]vendor[\\\/]modernizr[\\\/]modernizr\.js$/,
67 | loader: "imports?this=>window!exports?window.Modernizr"
68 | },
69 | {
70 | test: /\.jade$/,
71 | loader: 'html!jade-html'
72 | },
73 | {
74 | test: /\.html$/,
75 | loader: 'html'
76 | },
77 | {
78 | test: /\.css$/,
79 | exclude: [
80 | /bootstrap[\\\/]js[\\\/]/
81 | ],
82 | loader: 'style!css'
83 | },
84 | {
85 | test: /\.scss$/,
86 | exclude: [
87 | /bootstrap[\\\/]js[\\\/]/
88 | ],
89 | loader: 'style!css!autoprefixer!sass?includePaths[]=' + bourbon
90 | },
91 | {
92 | test: /\.png$/,
93 | loader: 'url?limit=100000&mimetype=image/png&name=assets/[name].[hash].[ext]'
94 | },
95 | {
96 | test: /\.jpg$/,
97 | exclude: [
98 | '/app\/assets/'
99 | ],
100 | loader: 'file?name=assets/[name].[hash].[ext]'
101 | },
102 | {
103 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
104 | loader: 'url?limit=10000&minetype=application/font-woff&name=assets/[name].[hash].[ext]'
105 | },
106 | {
107 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
108 | loader: 'url?limit=10000&minetype=application/font-woff2&name=assets/[name].[hash].[ext]'
109 | },
110 | {
111 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
112 | loader: 'url?limit=10000&minetype=application/octet-stream&name=assets/[name].[hash].[ext]'
113 | },
114 | {
115 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
116 | loader: 'file?name=assets/[name].[hash].[ext]'
117 | },
118 | {
119 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
120 | loader: 'url?limit=10000&minetype=image/svg+xml&name=assets/[name].[hash].[ext]'
121 | }
122 | ];
123 |
124 | var plugins = [
125 | new webpack.ProvidePlugin({
126 | _: 'lodash',
127 | Modernizr: 'modernizr',
128 | $: 'jquery',
129 | jQuery: 'jquery',
130 | register: 'registerjs'
131 | }),
132 | new webpack.optimize.OccurenceOrderPlugin(true)
133 | ];
134 |
135 | if(options.chunk) {
136 | plugins.push(new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'));
137 | plugins.push(new webpack.optimize.AggressiveMergingPlugin({}));
138 | }
139 |
140 | if (options.minimize) {
141 | plugins.push(new webpack.optimize.UglifyJsPlugin({
142 | minimize: true,
143 | warnings: false,
144 | mangle: {
145 | except: ['$q', '$ocLazyLoad']
146 | },
147 | sourceMap: false
148 | }));
149 | }
150 |
151 | if (options.defines) {
152 | plugins.push(new webpack.DefinePlugin(options.defines));
153 | }
154 |
155 | var postLoaders = [];
156 | if (options.testing) {
157 | postLoaders.push({
158 | test: /\.js/,
159 | exclude: /(test|node_modules|vendor|config|\.spec|index\.js|register\.js)/,
160 | loader: 'istanbul-instrumenter'
161 | });
162 | postLoaders.push({
163 | test: /\.es6/,
164 | exclude: /(test|node_modules|vendor|config|\.spec|index\.js|register\.js)/,
165 | loader: 'istanbul-instrumenter'
166 | });
167 | }
168 |
169 | return {
170 | entry: entry,
171 | context: __dirname + '/../app',
172 | output: output,
173 |
174 | devtool: options.devtool,
175 | debug: options.debug,
176 |
177 | module: {
178 | loaders: loaders,
179 | postLoaders: postLoaders,
180 | noParse: /\.min\.js/
181 | },
182 |
183 | resolve: {
184 | extensions: ['', '.js', '.json'],
185 | modulesDirectories: modulesDirectories,
186 | alias: aliases
187 | },
188 |
189 | plugins: plugins
190 | };
191 | };
192 |
--------------------------------------------------------------------------------
/config/webpack-prod.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Example webpack config for the production environment.
3 | * This is not directly used since we need to be able to override values.
4 | * It can be used for quick testing via webpack-dev-server or webpack CLI tools.
5 | *
6 | * @author Alexandru Badiu
7 | */
8 |
9 | var path = require('path');
10 | var environmentConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './environments.json'), 'utf8'));
11 |
12 | module.exports = require('./webpack-make-config')({
13 | dir: path.resolve(__dirname, '../build'),
14 |
15 | defines: {
16 | __TESTING__: false,
17 | __DEV__: false,
18 | __STAGE__: false,
19 | __PRODUCTION__: true
20 | },
21 |
22 | sourcemaps: false,
23 | devtool: '',
24 | debug: false,
25 | minimize: true,
26 | chunk: true
27 | });
--------------------------------------------------------------------------------
/config/webpack-stage.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Example webpack config for the stage environment.
3 | * This is not directly used since we need to be able to override values.
4 | * It can be used for quick testing via webpack-dev-server or webpack CLI tools.
5 | *
6 | * @author Alexandru Badiu
7 | */
8 |
9 | var path = require('path');
10 | var environmentConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './environments.json'), 'utf8'));
11 |
12 | module.exports = require('./webpack-make-config')({
13 | dir: path.resolve(__dirname, '../build'),
14 |
15 | defines: {
16 | __TESTING__: false,
17 | __DEV__: false,
18 | __STAGE__: true,
19 | __PRODUCTION__: false
20 | },
21 |
22 | sourcemaps: true,
23 | devtool: 'eval',
24 | debug: true,
25 | minimize: false,
26 | chunk: true
27 | });
--------------------------------------------------------------------------------
/config/webpack-test.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Webpack config for the unit test environment.
3 | *
4 | * @author Alexandru Badiu
5 | */
6 |
7 | var path = require('path');
8 |
9 | module.exports = require('./webpack-make-config')({
10 | dir: path.resolve(__dirname, '../.build'),
11 |
12 | sourcemaps: true,
13 | devtool: 'eval',
14 | debug: true,
15 | minimize: false,
16 | chunk: false,
17 | testing: true
18 | });
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var path = require('path');
3 |
4 | var gutil = require('gutil');
5 | var opn = require('opn');
6 |
7 | var jade = require('gulp-jade');
8 |
9 | var eslint = require('gulp-eslint');
10 |
11 | var webpack = require('webpack');
12 | var webpackDevServer = require("webpack-dev-server");
13 |
14 | var browserSync = require('browser-sync');
15 | var reload = browserSync.reload;
16 |
17 | var fs = require('fs');
18 | var runSequence = require('run-sequence');
19 | var clean = require('gulp-clean');
20 | var argv = require('optimist').argv;
21 |
22 | var protractor = require('gulp-protractor').protractor;
23 | var webdriver_standalone = require('gulp-protractor').webdriver_standalone;
24 | var webdriver_update = require('gulp-protractor').webdriver_update;
25 | var sauceConnectLauncher = require('sauce-connect-launcher');
26 | var karma = require('karma').server;
27 |
28 | var superstatic = require('superstatic').server;
29 |
30 | var buildConfig = {};
31 |
32 | /** Type of build: production or development. */
33 | buildConfig.type = argv['build-type'] || 'development';
34 | /** The environent that the build uses. */
35 | buildConfig.environment = argv['build-environment'] || 'development';
36 | buildConfig.testing = false;
37 |
38 | var testConfig = {};
39 | /** Type of test: unit or e2e. */
40 | testConfig.type = argv['type'] || 'unit';
41 | /** Where to test: local or remote. */
42 | testConfig.where = argv['where'] || 'local';
43 | /** Exit after tests? Works only on unit. */
44 | testConfig.watch = argv['watch'] ? true : false;
45 | /** If we're running tests for bamboo. */
46 | testConfig.bamboo = argv['bamboo'] ? true : false;
47 |
48 | /** Read the environment variables. */
49 | var environmentConfig = JSON.parse(fs.readFileSync('./config/environments.json', 'utf8'));
50 | buildConfig.gtmID = environmentConfig[buildConfig.environment].gtmID;
51 |
52 | /** Override the host. */
53 | var host = argv['host'] ? argv['host'] : '127.0.0.1';
54 |
55 | /** HTTP server for testing. */
56 | var app = superstatic({
57 | config: './config/superstatic.json',
58 | port: 3000,
59 | host: host
60 | });
61 |
62 | /**
63 | * Vars
64 | * Sets watch / development specific variables.
65 | * Used for the dev task.
66 | */
67 | gulp.task('vars:dev', function() {
68 | /** The build directory. */
69 | buildConfig.dir = '.build';
70 | });
71 |
72 | /**
73 | * Vars
74 | * Sets build specific variables.
75 | * Used for the build task.
76 | */
77 | gulp.task('vars:build', function() {
78 | /** The build directory. */
79 | buildConfig.dir = 'build';
80 | });
81 |
82 | /**
83 | * Clean
84 | * Cleans the build directory before a build.
85 | * Used for the build task.
86 | */
87 | gulp.task('clean', function() {
88 | return gulp.src(buildConfig.dir).pipe(clean());
89 | });
90 |
91 | /**
92 | * Index
93 | * Converts the main index template to a html file and copies it to the build directory.
94 | * Used for the build and dev tasks.
95 | */
96 | gulp.task('index', function () {
97 | var stream = gulp.src('app/index.jade')
98 | .pipe(jade({
99 | pretty: true,
100 | locals: {
101 | buildType: buildConfig.type,
102 | buildEnvironment: buildConfig.environment,
103 | gtmID: buildConfig.gtmID
104 | }
105 | }))
106 | .pipe(gulp.dest(buildConfig.dir));
107 |
108 | return stream;
109 | });
110 |
111 | /**
112 | * ESLint
113 | * Checks the sourcecode for errors with ESLint. Used for the build and dev tasks.
114 | */
115 | gulp.task('lint', function () {
116 | return gulp.src(['app/**/*.js'])
117 | .pipe(eslint({ useEslintrc: true }))
118 | .pipe(eslint.format());
119 | });
120 |
121 | /**
122 | * Testing
123 | * Unit tests.
124 | */
125 | gulp.task('test', function (done) {
126 | if (testConfig.type === 'unit') {
127 | gulp.start('test-unit');
128 | }
129 | else {
130 | if (testConfig.where === 'local') {
131 | gulp.start('test-local-browser');
132 | }
133 | else {
134 | gulp.start('test-remote-browser');
135 | }
136 | }
137 | });
138 |
139 | /**
140 | * Testing
141 | * Unit tests.
142 | */
143 | gulp.task('test-unit', function (done) {
144 | var config = {
145 | configFile: __dirname + '/config/karma.config.js',
146 | singleRun: !testConfig.watch
147 | };
148 |
149 | if (testConfig.bamboo) {
150 | config.reporters = ['mocha', 'bamboo'];
151 | }
152 |
153 | karma.start(config, done);
154 | });
155 |
156 | /**
157 | * Testing
158 | * Selenium update tasks.
159 | */
160 | gulp.task('webdriver_update', webdriver_update);
161 | gulp.task('webdriver_standalone', webdriver_standalone);
162 |
163 | /**
164 | * Testing
165 | * Runs a webserver.
166 | */
167 | gulp.task('e2e-serve', [], function (done) {
168 | server = app.listen(function () {
169 | done();
170 | });
171 | });
172 |
173 |
174 | /**
175 | * Testing
176 | * Runs the state tests locally.
177 | */
178 | gulp.task('test-local-browser', ['e2e-serve', 'webdriver_update'], function (done) {
179 | var args = [
180 | '--baseUrl',
181 | 'http://127.0.0.1:3000',
182 | ];
183 |
184 | if (testConfig.bamboo) {
185 | args.push('--bamboo');
186 | }
187 |
188 | gulp.src("./test/e2e/*.spec.js")
189 | .pipe(protractor({
190 | configFile: "config/protractor-local.config.js",
191 | args: args
192 | }))
193 | .on('error', function (e) {
194 | gutil.log(e);
195 |
196 | server.close();
197 | done();
198 | })
199 | .on('end', function () {
200 | server.close();
201 | done();
202 | });
203 | });
204 |
205 | /**
206 | * Testing
207 | * Runs the state tests in the cloud via SauceLabs.
208 | */
209 | gulp.task('test-remote-browser', ['e2e-serve'], function (done) {
210 | var args = [
211 | '--baseUrl',
212 | 'http://127.0.0.1:3000',
213 | ];
214 |
215 | if (testConfig.bamboo) {
216 | args.push('--bamboo');
217 | }
218 |
219 | sauceConnectLauncher({
220 | logger: gutil.log
221 | }, function (err, sauceConnectProcess) {
222 | if (err) {
223 | gutil.log(err.message);
224 | return done();
225 | }
226 |
227 | gutil.log("Sauce Connect ready");
228 |
229 | gulp.src("./test/e2e/*.spec.js")
230 | .pipe(protractor({
231 | configFile: "config/protractor-remote.config.js",
232 | args: args
233 | }))
234 | .on('error', function(e) {
235 | gutil.log(e);
236 | sauceConnectProcess.close(function () {
237 | gutil.log("Closed Sauce Connect process");
238 |
239 | server.close();
240 | done();
241 | });
242 | })
243 | .on('end', function (e) {
244 | sauceConnectProcess.close(function () {
245 | gutil.log("Closed Sauce Connect process");
246 |
247 | server.close();
248 | done();
249 | });
250 | });
251 | });
252 | });
253 |
254 | /**
255 | * Build
256 | * Performs all the build tasks except webpack.
257 | */
258 | gulp.task('pre-build', function(done) {
259 | runSequence(
260 | 'vars:build',
261 | 'clean',
262 | ['lint', 'index'],
263 | done
264 | );
265 | });
266 |
267 | /**
268 | * Webpack
269 | * Processes the Webpack configuration file.
270 | */
271 | function webpackConfig() {
272 | var options = {};
273 |
274 | options.dir = path.resolve(__dirname, buildConfig.dir);
275 |
276 | options.defines = {
277 | __TESTING__: buildConfig.testing,
278 | __DEV__: buildConfig.environment === 'development' ? true : false,
279 | __STAGE__: buildConfig.environment === 'stage' ? true : false,
280 | __PRODUCTION__: buildConfig.environment === 'production' ? true : false
281 | };
282 |
283 | if (buildConfig.type === 'development') {
284 | options.sourcemaps = true;
285 | options.devtool = 'eval';
286 | options.debug = true;
287 | options.minimize = false;
288 | options.chunk = !buildConfig.testing;
289 | }
290 | else if (buildConfig.type === 'stage') {
291 | options.sourcemaps = true;
292 | options.devtool = 'eval';
293 | options.debug = true;
294 | options.minimize = false;
295 | options.chunk = !buildConfig.testing;
296 | }
297 | else {
298 | options.sourcemaps = false;
299 | options.devtool = '';
300 | options.debug = false;
301 | options.minimize = true;
302 | options.chunk = !buildConfig.testing;
303 | }
304 |
305 | return require('./config/webpack-make-config')(options);
306 | }
307 |
308 | /**
309 | * Webpack
310 | * Builds an app bundle once. Used for the build task.
311 | */
312 | gulp.task('webpack-build', ['pre-build'], function(callback) {
313 | var compiler = webpack(webpackConfig());
314 |
315 | compiler.run(function(err, stats) {
316 | if (err) {
317 | throw new gutil.PluginError('webpack-build', err);
318 | }
319 |
320 | gutil.log("[webpack:build]", stats.toString({
321 | colors: true
322 | }));
323 |
324 | callback();
325 | });
326 | });
327 |
328 | /**
329 | * Webpack
330 | * Starts a webpack dev server that rebuilds the app bundle on file changes.
331 | * Used for the dev task.
332 | */
333 | gulp.task('webpack-dev-server', ['vars:dev', 'index'], function(done) {
334 | var compiler = webpack(webpackConfig());
335 |
336 | compiler.plugin("done", function(stats) {
337 | /** Reload all connected browsers. */
338 | reload();
339 | });
340 |
341 | new webpackDevServer(compiler, {
342 | contentBase: buildConfig.dir,
343 | quiet: false,
344 | noInfo: false,
345 | watchDelay: 300,
346 | historyApiFallback: true,
347 | stats: {
348 | colors: true
349 | }
350 | }).listen(8080, host, function(err) {
351 | if(err) {
352 | throw new gutil.PluginError('webpack-dev-server', err);
353 | }
354 |
355 | done();
356 | });
357 | });
358 |
359 | /**
360 | * BrowserSync
361 | * Reloads the browsers after the other tasks have finished.
362 | */
363 | gulp.task('index-watch', ['index'], browserSync.reload);
364 |
365 | /**
366 | * Build
367 | * Builds the project.
368 | */
369 | gulp.task('build', ['webpack-build'], function () {
370 | gutil.log((buildConfig.type == 'development' ? 'Development' : 'Production') + ' build done for environment ' + buildConfig.environment + ' in ./' + buildConfig.dir + '.');
371 | });
372 |
373 | /**
374 | * Development
375 | * Starts a development environment that reloads on code changes.
376 | */
377 | gulp.task('dev', ['webpack-dev-server'], function () {
378 | gulp.watch(['app/index.jade'], ['index-watch']);
379 |
380 | browserSync({
381 | proxy: '127.0.0.1:8080',
382 | open: false
383 | }, function () {
384 | opn('http://127.0.0.1:3000');
385 | });
386 | });
387 |
388 | /** Default task: development. */
389 | gulp.task('default', ['dev']);
390 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-angularjs",
3 | "version": "1.0.0",
4 | "description": "A boilerplate to kickstart development using Webpack, Gulp and AngularJS.",
5 | "repository": {
6 | "type" : "git",
7 | "url" : "https://github.com/voidberg/webpack-angularjs.git"
8 | },
9 | "scripts": {
10 | "start": "gulp",
11 | "build": "gulp build"
12 | },
13 | "author": "Alexandru Badiu ",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "autoprefixer-loader": "^1.2.0",
17 | "babel-core": "^4.7.16",
18 | "babel-eslint": "^3.1.1",
19 | "babel-loader": "^4.2.0",
20 | "bootstrap-sass": "^3.3.4",
21 | "bootstrap-sass-loader": "1.0.4",
22 | "browser-sync": "^2.5.3",
23 | "chai": "^2.2.0",
24 | "chai-as-promised": "^4.3.0",
25 | "css-loader": "^0.9.1",
26 | "exports-loader": "^0.6.2",
27 | "expose-loader": "^0.6.0",
28 | "file-loader": "^0.8.1",
29 | "gulp": "^3.8.11",
30 | "gulp-clean": "^0.3.1",
31 | "gulp-eslint": "^0.11.1",
32 | "gulp-jade": "^1.0.0",
33 | "gulp-protractor": "^1.0.0",
34 | "gulp-rimraf": "^0.1.1",
35 | "gutil": "^1.6.4",
36 | "html-loader": "^0.2.3",
37 | "imports-loader": "^0.6.3",
38 | "istanbul": "^0.3.13",
39 | "istanbul-instrumenter-loader": "^0.1.2",
40 | "jade": "^1.9.2",
41 | "jade-html-loader": "0.0.2",
42 | "karma": "^0.12.31",
43 | "karma-bamboo-reporter": "^0.1.0",
44 | "karma-chai": "^0.1.0",
45 | "karma-chrome-launcher": "^0.1.8",
46 | "karma-coverage": "^0.2.7",
47 | "karma-mocha": "^0.1.10",
48 | "karma-mocha-reporter": "^1.0.2",
49 | "karma-phantomjs-launcher": "^0.1.4",
50 | "karma-sinon-chai": "^0.3.0",
51 | "karma-spec-reporter": "0.0.19",
52 | "karma-webpack": "^1.5.0",
53 | "lodash": "^3.5.0",
54 | "mocha": "^2.2.4",
55 | "mocha-bamboo-reporter": "^1.1.0",
56 | "ng-annotate-loader": "0.0.2",
57 | "node-bourbon": "4.2.2",
58 | "opn": "^1.0.1",
59 | "optimist": "^0.6.1",
60 | "protractor": "~1.0.0",
61 | "run-sequence": "^1.1.0",
62 | "sass-loader": "0.4.2",
63 | "sauce-connect-launcher": "^0.10.3",
64 | "style-loader": "^0.9.0",
65 | "superstatic": "^2.2.0",
66 | "url-loader": "^0.5.5",
67 | "webpack": "^1.7.3",
68 | "webpack-dev-server": "^1.8.0",
69 | "eslint": "^0.21.0"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/test/e2e/state1.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var chai = require('chai');
4 | var chaiAsPromised = require('chai-as-promised');
5 |
6 | chai.use(chaiAsPromised);
7 | var expect = chai.expect;
8 |
9 | describe('State 1', function () {
10 | beforeEach(function() {
11 | browser.get('/');
12 | });
13 |
14 | it('should render all expected components', function () {
15 | expect(element.all(by.css('.starter-template h1')).first().getText()).to.eventually.equal('Bootstrap starter template');
16 | expect(element.all(by.css('.starter-template h2')).first().getText()).to.eventually.equal('Some documentation will come here');
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/test/e2e/state2.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var chai = require('chai');
4 | var chaiAsPromised = require('chai-as-promised');
5 |
6 | chai.use(chaiAsPromised);
7 | var expect = chai.expect;
8 |
9 | describe('State 1', function () {
10 | beforeEach(function() {
11 | browser.get('/state2');
12 | });
13 |
14 | it('should render all expected components', function () {
15 | expect(element.all(by.css('.starter-template-alt h1')).first().getText()).to.eventually.equal('Another state');
16 | expect(element.all(by.css('.starter-template-alt p.lead')).first().getText()).to.eventually.equal('Some new information here.');
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/test/unit.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var testsContext = require.context('../app/', true, /.spec$/);
4 | testsContext.keys().forEach(testsContext);
--------------------------------------------------------------------------------