diff --git a/README.md b/README.md index a7b658b5c4..a4f1f64f85 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Then go to [http://localhost:3000](http://localhost:3000) in your browser * [Running the app](#running-the-app) * [Running in production mode](#running-in-production-mode) * [Cleaning](#cleaning) +* [Testing](#testing) * [Other commands](#other-commands) * [Recommended Editors/IDEs](#recommended-editorsides) * [Collaborating](#collaborating) @@ -85,6 +86,49 @@ npm run clean:prod npm run clean:dist ``` +## Testing +### Unit Test +Unit tests use Karma. You can find the configuration file at the same level of this README file: +`./karma.conf.js` +If you are going to use a remote test enviroment you need to edit the './karma.conf.js'. Follow the instructions you will find inside it. +To executing tests whenever any file changes you can modify the 'autoWatch' option to 'true' and 'singleRun' option to 'false'. +A coverage report is also available at: +http://localhost:9876/ +after you run: +`npm run coverage`. + +To correctly run the tests you need to run the build once with: +`npm run build`. + +The default browser is Google Chrome. + +Place your tests in the same location of the application source code files that they test. + +and run: +`npn run test` + +### E2E test +E2E tests use Protractor + Selenium server + browsers. You can find the configuration file at the same level of this README file: +`./protractor.conf.js` +Protractor is installed as 'local' as a dev dependency. +If you are going to execute tests locally you need to run (once time only): +`npm run webdriver:update`. + +If you are going to use a remote test enviroment you need to edit the './protractor.conf.js'. Follow the instructions you will find inside it. + +The default browser is Google Chrome. + +Protractor needs a functional instance of the DSpace interface to run the E2E tests, so you need to run: +`npm run watch:dev` + +or any command that bring up the DSpace interface. + +Place your tests at the following path: +`./e2e` + +and run: +`npm run e2e` + ## Other commands There are many more commands in the `scripts` section of `package.json`. Most of these are executed by one of the commands mentioned above. A command with a name that starts with `pre` or `post` will be executed automatically before or after the script with the matching name. e.g. if you type `npm run start` the `prestart` script will run first, then the `start` script will trigger. @@ -111,8 +155,11 @@ See [the guide on the wiki](https://wiki.duraspace.org/display/DSPACE/DSpace+7+- dspace-angular ├── README.md * This document ├── app.json * Application manifest file +├── e2e * Folder for e2e test files +├── karma.conf.js * Unit Test configuration file ├── nodemon.json * Nodemon (https://nodemon.io/) configuration ├── package.json * This file describes the npm package for this project, its dependencies, scripts, etc. +├── protractor.conf.js * E2E tests configuration file ├── resources * Folder for static resources │   ├── i18n * Folder for i18n translations │   └── images * Folder for images @@ -138,6 +185,7 @@ dspace-angular ├── tsconfig.json * TypeScript config for development build ├── tslint.json * TSLint (https://palantir.github.io/tslint/) configuration ├── webpack.config.ts * Webpack (https://webpack.github.io/) config for development builds +├── webpack.test.config.ts * Webpack (https://webpack.github.io/) config for testing └── webpack.prod.config.ts * Webpack (https://webpack.github.io/) config for production builds ``` diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts new file mode 100644 index 0000000000..ee7b101f96 --- /dev/null +++ b/e2e/app.e2e-spec.ts @@ -0,0 +1,19 @@ +import { ProtractorPage } from './app.po'; + +describe('protractor App', function() { + let page: ProtractorPage; + + beforeEach(() => { + page = new ProtractorPage(); + }); + + it('should display title "DSpace"', () => { + page.navigateTo(); + expect(page.getPageTitleText()).toEqual('DSpace'); + }); + + it('should display title "Hello, World!"', () => { + page.navigateTo(); + expect(page.getFirstPText()).toEqual('Hello, World!'); + }); +}); diff --git a/e2e/app.po.ts b/e2e/app.po.ts new file mode 100644 index 0000000000..164c524620 --- /dev/null +++ b/e2e/app.po.ts @@ -0,0 +1,15 @@ +import { browser, element, by } from 'protractor'; + +export class ProtractorPage { + navigateTo() { + return browser.get('/'); + } + + getPageTitleText() { + return browser.getTitle(); + } + + getFirstPText() { + return element(by.xpath('//p[1]')).getText(); + } +} \ No newline at end of file diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json new file mode 100644 index 0000000000..656bdb14ff --- /dev/null +++ b/e2e/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "commonjs", + "moduleResolution": "node", + "outDir": "../dist/out-tsc-e2e", + "sourceMap": true, + "target": "es5", + "typeRoots": [ + "../node_modules/@types" + ] + } +} diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000000..ed4330d342 --- /dev/null +++ b/helpers.js @@ -0,0 +1,24 @@ +/** + * @author: @AngularClass + */ +var path = require('path'); + +// Helper functions +var ROOT = path.resolve(__dirname, '.'); + +function hasProcessFlag(flag) { + return process.argv.join('').indexOf(flag) > -1; +} + +function isWebpackDevServer() { + return process.argv[1] && !! (/webpack-dev-server/.exec(process.argv[1])); +} + +function root(args) { + args = Array.prototype.slice.call(arguments, 0); + return path.join.apply(path, [ROOT].concat(args)); +} + +exports.hasProcessFlag = hasProcessFlag; +exports.isWebpackDevServer = isWebpackDevServer; +exports.root = root; diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000000..43ad307a3c --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,149 @@ +/** + * @author: @AngularClass + */ + +module.exports = function(config) { + + var testWebpackConfig = require('./webpack.test.config.js')({env: 'test'}); + + // Uncomment and change to run tests on a remote Selenium server + var webdriverConfig = { + hostname: 'localhost', + port: 4444 + }; + + var configuration = { + + // base path that will be used to resolve all patterns (e.g. files, exclude) + basePath: '.', + + /* + * Frameworks to use + * + * available frameworks: https://npmjs.org/browse/keyword/karma-adapter + */ + frameworks: ['jasmine'], + + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-phantomjs-launcher'), + require('karma-webdriver-launcher'), + require('karma-coverage'), + require('karma-mocha-reporter'), + require('karma-remap-istanbul'), + require('karma-sourcemap-loader'), + require('karma-webpack') + ], + + // list of files to exclude + exclude: [ ], + + /* + * list of files / patterns to load in the browser + * + * we are building the test environment in ./spec-bundle.js + */ + files: [ { pattern: './spec-bundle.js', watched: false } ], + + /* + * preprocess matching files before serving them to the browser + * available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + */ + preprocessors: { './spec-bundle.js': ['coverage', 'webpack', 'sourcemap'] }, + + // Webpack Config at ./webpack.test.js + webpack: testWebpackConfig, + + coverageReporter: { + reporters:[ + {type: 'in-memory'}, + {type: 'json', subdir: '.', file: 'coverage-final.json'}, + {type: 'html', dir : 'coverage/'} + ] + }, + + remapCoverageReporter: { + 'text-summary': null, + json: './coverage/coverage.json', + html: './coverage/html' + }, + + remapIstanbulReporter: { + reports: { + html: 'coverage' + } + }, + + // Webpack please don't spam the console when running in karma! + webpackMiddleware: { stats: 'errors-only'}, + + /* + * test results reporter to use + * + * possible values: 'dots', 'progress' + * available reporters: https://npmjs.org/browse/keyword/karma-reporter + */ + reporters: [ 'mocha', 'coverage', 'karma-remap-istanbul' ], + + // Karma web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + /* + * level of logging + * possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + */ + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + //autoWatch: true, + + /* + * start these browsers + * available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + */ + browsers: [ + 'Chrome' + //'ChromeTravisCi', + //'SeleniumChrome', + //'SeleniumFirefox' + ], + + customLaunchers: { + // Continuous integraation with Chrome - launcher + 'ChromeTravisCi': { + base: 'Chrome', + flags: ['--no-sandbox'] + }, + // Remote Selenium Server with Chrome - launcher + 'SeleniumChrome': { + base: 'WebDriver', + config: webdriverConfig, + browserName: 'chrome' + }, + // Remote Selenium Server with Firefox - launcher + 'SeleniumFirefox': { + base: 'WebDriver', + config: webdriverConfig, + browserName: 'firefox' + } + }, + + /* + * Continuous Integration mode + * if true, Karma captures browsers, runs the tests and exits + */ + //singleRun: true + }; + + if (process.env.TRAVIS){ + configuration.browsers = [ + 'ChromeTravisCi' + ]; + } + + config.set(configuration); +}; diff --git a/package.json b/package.json index 520f7b3677..44316b310e 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,14 @@ "clean:node": "rimraf node_modules/*", "clean:ngc": "rimraf **/*.ngfactory.ts", "clean:json": "rimraf *.records.json", - "clean:css": "rimraf **/*.css", - "clean:css:ts": "rimraf **/*.css.ts", - "clean:scss:ts": "rimraf **/*.scss.ts", - "clean:css:shim:ts": "rimraf **/*.css.shim.ts", - "clean:scss:shim:ts": "rimraf **/*.scss.shim.ts", + "clean:css": "rimraf src/**/*.css", + "clean:css:ts": "rimraf src/**/*.css.ts", + "clean:scss:ts": "rimraf src/**/*.scss.ts", + "clean:css:shim:ts": "rimraf src/**/*.css.shim.ts", + "clean:scss:shim:ts": "rimraf src/**/*.scss.shim.ts", + "clean:coverage": "rimraf coverage", "clean:prod": "npm run clean:ngc && npm run clean:json && npm run clean:css && npm run clean:css:ts && npm run clean:scss:ts && npm run clean:css:shim:ts && npm run clean:scss:shim:ts && npm run clean:dist", - "clean": "npm run clean:log && npm run clean:prod && npm run clean:node", + "clean": "npm run clean:log && npm run clean:prod && npm run clean:coverage && npm run clean:node", "sass": "node-sass src -o src --include-path node_modules --output-style compressed -q", "sass:watch": "node-sass -w src -o src --include-path node_modules --output-style compressed -q", "rollup": "rollup -c rollup-server.js && rollup -c rollup-client.js", @@ -49,7 +50,14 @@ "debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --config webpack.prod.config.ts", "docs": "typedoc --options typedoc.json ./src", "lint": "tslint \"src/**/*.ts\" || true", - "global": "npm install -g angular-cli nodemon npm-check-updates rimraf ts-node typedoc typescript webpack webpack-bundle-size-analyzer rollup marked node-gyp" + "global": "npm install -g angular-cli nodemon npm-check-updates rimraf ts-node typedoc typescript webpack webpack-bundle-size-analyzer rollup marked node-gyp", + "protractor": "node node_modules/protractor/bin/protractor", + "e2e": "npm run protractor", + "test": "karma start --single-run", + "test:watch": "karma start --no-single-run --auto-watch", + "coverage": "http-server -c-1 -o -p 9875 ./coverage", + "webdriver:start": "node node_modules/protractor/bin/webdriver-manager start --seleniumPort 4444", + "webdriver:update": "node node_modules/protractor/bin/webdriver-manager update --standalone" }, "dependencies": { "@angular/common": "2.2.3", @@ -80,6 +88,7 @@ "compression": "1.6.2", "express": "4.14.0", "font-awesome": "4.7.0", + "http-server": "^0.9.0", "js.clone": "0.0.3", "methods": "1.1.2", "morgan": "1.7.0", @@ -97,6 +106,7 @@ "@types/express": "4.0.34", "@types/express-serve-static-core": "4.0.39", "@types/hammerjs": "2.0.33", + "@types/jasmine": "^2.2.34", "@types/memory-cache": "0.0.29", "@types/mime": "0.0.29", "@types/morgan": "1.7.32", @@ -105,15 +115,35 @@ "@types/webfontloader": "1.6.27", "angular2-template-loader": "0.6.0", "autoprefixer": "6.5.4", + "ajv": "4.2.0", + "ajv-keywords": "1.1.1", "awesome-typescript-loader": "2.2.4", "codelyzer": "2.0.0-beta.3", "concurrently": "3.1.0", "cookie-parser": "1.4.3", "copy-webpack-plugin": "4.0.1", + "css-loader": "^0.26.0", + "html-webpack-plugin": "^2.21.0", "imports-loader": "0.7.0", + "istanbul-instrumenter-loader": "^0.2.0", + "jasmine-core": "~2.5.2", + "jasmine-spec-reporter": "~2.7.0", "json-loader": "0.5.4", + "karma": "^1.2.0", + "karma-chrome-launcher": "^2.0.0", + "karma-cli": "^1.0.1", + "karma-coverage": "^1.1.1", + "karma-jasmine": "^1.0.2", + "karma-mocha-reporter": "^2.0.0", + "karma-phantomjs-launcher": "^1.0.2", + "karma-remap-istanbul": "^0.2.1", + "karma-sourcemap-loader": "^0.3.7", + "karma-webdriver-launcher": "^1.0.4", + "karma-webpack": "1.8.0", "node-sass": "4.0.0", "nodemon": "1.11.0", + "protractor": "~4.0.14", + "protractor-istanbul-plugin": "~2.0.0", "raw-loader": "0.5.1", "reflect-metadata": "0.1.8", "rimraf": "2.5.4", @@ -122,7 +152,9 @@ "rollup-plugin-node-globals": "1.1.0", "rollup-plugin-node-resolve": "2.0.0", "rollup-plugin-uglify": "1.0.1", + "source-map-loader": "^0.1.5", "string-replace-loader": "1.0.5", + "to-string-loader": "^1.1.4", "ts-helpers": "1.1.2", "ts-node": "1.7.2", "tslint": "4.0.2", diff --git a/protractor.conf.js b/protractor.conf.js new file mode 100644 index 0000000000..56a84875a1 --- /dev/null +++ b/protractor.conf.js @@ -0,0 +1,85 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/docs/referenceConf.js + +/*global jasmine */ +var SpecReporter = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + // ----------------------------------------------------------------- + // Uncomment to run tests using a remote Selenium server + //seleniumAddress: 'http://selenium.address:4444/wd/hub', + // Change to 'false' to run tests using a remote Selenium server + directConnect: true, + // Change if the website to test is not on the localhost + baseUrl: 'http://localhost:3000/', + // ----------------------------------------------------------------- + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + // ----------------------------------------------------------------- + // Browser and Capabilities: PhantomJS + // ----------------------------------------------------------------- + // capabilities: { + // 'browserName': 'phantomjs', + // 'version': '', + // 'platform': 'ANY' + // }, + // ----------------------------------------------------------------- + // Browser and Capabilities: Chrome + // ----------------------------------------------------------------- + capabilities: { + 'browserName': 'chrome', + 'version': '', + 'platform': 'ANY' + }, + // ----------------------------------------------------------------- + // Browser and Capabilities: Firefox + // ----------------------------------------------------------------- + // capabilities: { + // 'browserName': 'firefox', + // 'version': '', + // 'platform': 'ANY' + // }, + + // ----------------------------------------------------------------- + // Browser and Capabilities: MultiCapabilities + // ----------------------------------------------------------------- + //multiCapabilities: [ + // { + // 'browserName': 'phantomjs', + // 'version': '', + // 'platform': 'ANY' + // }, + // { + // 'browserName': 'chrome', + // 'version': '', + // 'platform': 'ANY' + // } + // { + // 'browserName': 'firefox', + // 'version': '', + // 'platform': 'ANY' + // } + //], + + plugins : [{ + path: 'node_modules/protractor-istanbul-plugin' + }], + + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + useAllAngular2AppRoots: true, + beforeLaunch: function() { + require('ts-node').register({ + project: 'e2e' + }); + }, + onPrepare: function() { + jasmine.getEnv().addReporter(new SpecReporter()); + } +}; diff --git a/spec-bundle.js b/spec-bundle.js new file mode 100644 index 0000000000..36026d530f --- /dev/null +++ b/spec-bundle.js @@ -0,0 +1,62 @@ +/** + * @author: @AngularClass + */ + +/* + * When testing with webpack and ES6, we have to do some extra + * things to get testing to work right. Because we are gonna write tests + * in ES6 too, we have to compile those as well. That's handled in + * karma.conf.js with the karma-webpack plugin. This is the entry + * file for webpack test. Just like webpack will create a bundle.js + * file for our client, when we run test, it will compile and bundle them + * all here! Crazy huh. So we need to do some setup + */ +Error.stackTraceLimit = Infinity; + +require('core-js/es6'); +require('core-js/es7/reflect'); + +// Typescript emit helpers polyfill +require('ts-helpers'); + +require('zone.js/dist/zone'); +require('zone.js/dist/long-stack-trace-zone'); +require('zone.js/dist/proxy'); // since zone.js 0.6.15 +require('zone.js/dist/sync-test'); +require('zone.js/dist/jasmine-patch'); // put here since zone.js 0.6.14 +require('zone.js/dist/async-test'); +require('zone.js/dist/fake-async-test'); + +// RxJS +require('rxjs/Rx'); + +var testing = require('@angular/core/testing'); +var browser = require('@angular/platform-browser-dynamic/testing'); + +testing.TestBed.initTestEnvironment( + browser.BrowserDynamicTestingModule, + browser.platformBrowserDynamicTesting() +); + +/* + * Ok, this is kinda crazy. We can use the context method on + * require that webpack created in order to tell webpack + * what files we actually want to require or import. + * Below, context will be a function/object with file names as keys. + * Using that regex we are saying look in ../src then find + * any file that ends with spec.ts and get its path. By passing in true + * we say do this recursively + */ +var testContext = require.context('./src', true, /\.spec\.ts/); + +/* + * get all the files, for each file, call the context function + * that will require the file and load it up here. Context will + * loop and require those spec files here + */ +function requireAll(requireContext) { + return requireContext.keys().map(requireContext); +} + +// requires and returns all modules that match +var modules = requireAll(testContext); diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts new file mode 100644 index 0000000000..4f53b0ba93 --- /dev/null +++ b/src/app/app.component.spec.ts @@ -0,0 +1,53 @@ +// ... test imports +import { + async, + ComponentFixture, + inject, + TestBed +} from '@angular/core/testing'; +import { + CUSTOM_ELEMENTS_SCHEMA, + DebugElement +} from "@angular/core"; +import { TranslateModule } from "ng2-translate"; +import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; +import { Store } from "@ngrx/store"; + + +// Load the implementations that should be tested +import { AppComponent } from './app.component'; +import { HeaderComponent } from './header/header.component'; + +import { CommonModule } from '@angular/common'; + +let comp: AppComponent; +let fixture: ComponentFixture; +let de: DebugElement; +let el: HTMLElement; + + +describe('App component', () => { + + beforeEach(() => { + return TestBed.configureTestingModule({ + imports: [ CommonModule, TranslateModule.forRoot(), NgbCollapseModule.forRoot()], + declarations: [ AppComponent, HeaderComponent ], // declare the test component + providers: [ + AppComponent, + { + provide: Store, + useClass: class { dispatch = jasmine.createSpy('dispatch') } + } + ], + schemas: [ CUSTOM_ELEMENTS_SCHEMA ] + }).compileComponents().then(() => { + fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + }); + }); + + it('should create component', inject([AppComponent], (app: AppComponent) => { + // Perform test using fixture and service + expect(app).toBeTruthy(); + })); +}); diff --git a/tsconfig.json b/tsconfig.json index 226f3dbe19..6926f8cfff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "removeComments": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, "allowUnreachableCode": false, "allowUnusedLabels": false, "noEmitHelpers": true, diff --git a/webpack.config.ts b/webpack.config.ts index 1d4b927e13..065ac1cf6e 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -67,6 +67,7 @@ export var commonConfig = { } ], }, + plugins: [ // Use commonPlugins. ] diff --git a/webpack.test.config.js b/webpack.test.config.js new file mode 100644 index 0000000000..cd288ce894 --- /dev/null +++ b/webpack.test.config.js @@ -0,0 +1,242 @@ +/** + * @author: @AngularClass + */ + +const helpers = require('./helpers'); +const path = require('path'); + +/** + * Webpack Plugins + */ +const ProvidePlugin = require('webpack/lib/ProvidePlugin'); +const DefinePlugin = require('webpack/lib/DefinePlugin'); +const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin'); +const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin'); + +/** + * Webpack Constants + */ +const ENV = process.env.ENV = process.env.NODE_ENV = 'test'; + +/** + * Webpack configuration + * + * See: http://webpack.github.io/docs/configuration.html#cli + */ +module.exports = function (options) { + return { + + /** + * Source map for Karma from the help of karma-sourcemap-loader & karma-webpack + * + * Do not change, leave as is or it wont work. + * See: https://github.com/webpack/karma-webpack#source-maps + */ + devtool: 'inline-source-map', + + /** + * Options affecting the resolving of modules. + * + * See: http://webpack.github.io/docs/configuration.html#resolve + */ + resolve: { + + /** + * An array of extensions that should be used to resolve modules. + * + * See: http://webpack.github.io/docs/configuration.html#resolve-extensions + */ + extensions: ['.ts', '.js'], + + /** + * Make sure root is src + */ + modules: [ path.resolve(__dirname, 'src'), 'node_modules' ] + + }, + + /** + * Options affecting the normal modules. + * + * See: http://webpack.github.io/docs/configuration.html#module + * + * 'use:' revered back to 'loader:' as a temp. workaround for #1188 + * See: https://github.com/AngularClass/angular2-webpack-starter/issues/1188#issuecomment-262872034 + */ + module: { + + rules: [ + + /** + * Source map loader support for *.js files + * Extracts SourceMaps for source files that as added as sourceMappingURL comment. + * + * See: https://github.com/webpack/source-map-loader + */ + { + enforce: 'pre', + test: /\.js$/, + loader: 'source-map-loader', + exclude: [ + // these packages have problems with their sourcemaps + helpers.root('node_modules/rxjs'), + helpers.root('node_modules/@angular') + ] + }, + + /** + * Typescript loader support for .ts and Angular 2 async routes via .async.ts + * + * See: https://github.com/s-panferov/awesome-typescript-loader + */ + { + test: /\.ts$/, + loaders: [ + { + loader: 'awesome-typescript-loader', + query: { + // use inline sourcemaps for "karma-remap-coverage" reporter + sourceMap: false, + inlineSourceMap: true, + sourceRoot: false, + compilerOptions: { + // Remove TypeScript helpers to be injected + // below by DefinePlugin + removeComments: true + } + } + }, + 'angular2-template-loader' + ], + exclude: [/\.e2e\.ts$/] + }, + + /** + * Json loader support for *.json files. + * + * See: https://github.com/webpack/json-loader + */ + { + test: /\.json$/, + loader: 'json-loader', + exclude: [helpers.root('src/index.html')] + }, + + /** + * Raw loader support for *.css files + * Returns file content as string + * + * See: https://github.com/webpack/raw-loader + */ + { + test: /\.css$/, + loader: ['to-string-loader', 'css-loader'], + exclude: [helpers.root('src/index.html')] + }, + + /** + * Raw loader support for *.html + * Returns file content as string + * + * See: https://github.com/webpack/raw-loader + */ + { + test: /\.html$/, + loader: 'raw-loader', + exclude: [helpers.root('src/index.html')] + }, + + /** + * Instruments JS files with Istanbul for subsequent code coverage reporting. + * Instrument only testing sources. + * + * See: https://github.com/deepsweet/istanbul-instrumenter-loader + */ + { + enforce: 'post', + test: /\.(js|ts)$/, + loader: 'istanbul-instrumenter-loader', + include: helpers.root('src'), + exclude: [ + /\.(e2e|spec)\.ts$/, + /node_modules/ + ] + } + + ] + }, + + /** + * Add additional plugins to the compiler. + * + * See: http://webpack.github.io/docs/configuration.html#plugins + */ + plugins: [ + + /** + * Plugin: DefinePlugin + * Description: Define free variables. + * Useful for having development builds with debug logging or adding global constants. + * + * Environment helpers + * + * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin + */ + // NOTE: when adding more properties make sure you include them in custom-typings.d.ts + new DefinePlugin({ + 'ENV': JSON.stringify(ENV), + 'HMR': false, + 'process.env': { + 'ENV': JSON.stringify(ENV), + 'NODE_ENV': JSON.stringify(ENV), + 'HMR': false, + } + }), + + /** + * Plugin: ContextReplacementPlugin + * Description: Provides context to Angular's use of System.import + * + * See: https://webpack.github.io/docs/list-of-plugins.html#contextreplacementplugin + * See: https://github.com/angular/angular/issues/11580 + */ + new ContextReplacementPlugin( + // The (\\|\/) piece accounts for path separators in *nix and Windows + /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, + helpers.root('src'), // location of your src + { + // your Angular Async Route paths relative to this root directory + } + ), + + /** + * Plugin LoaderOptionsPlugin (experimental) + * + * See: https://gist.github.com/sokra/27b24881210b56bbaff7 + */ + new LoaderOptionsPlugin({ + debug: true, + options: { + + } + }), + + ], + + /** + * Include polyfills or mocks for various node stuff + * Description: Node configuration + * + * See: https://webpack.github.io/docs/configuration.html#node + */ + node: { + global: true, + process: false, + crypto: 'empty', + module: false, + clearImmediate: false, + setImmediate: false + } + + }; +}