From de3f67e835fcfd504f1603abf3e29be1d7b1914c Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Thu, 15 Dec 2016 10:35:21 +0100 Subject: [PATCH 01/33] Starting commit for e2e and unit tests --- e2e/app.e2e-spec.ts | 14 ++++++++++++++ e2e/app.po.ts | 11 +++++++++++ e2e/tsconfig.json | 16 ++++++++++++++++ package.json | 5 ++++- protractor.conf.js | 32 ++++++++++++++++++++++++++++++++ src/tests/.gitkeep | 0 6 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 e2e/app.e2e-spec.ts create mode 100644 e2e/app.po.ts create mode 100644 e2e/tsconfig.json create mode 100644 protractor.conf.js create mode 100644 src/tests/.gitkeep diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts new file mode 100644 index 0000000000..748e4b7861 --- /dev/null +++ b/e2e/app.e2e-spec.ts @@ -0,0 +1,14 @@ +import { ProtractorPage } from './app.po'; + +describe('protractor App', function() { + let page: ProtractorPage; + + beforeEach(() => { + page = new ProtractorPage(); + }); + + it('should display message saying app works', () => { + page.navigateTo(); + expect(page.getParagraphText()).toEqual('app works!'); + }); +}); diff --git a/e2e/app.po.ts b/e2e/app.po.ts new file mode 100644 index 0000000000..b4ee755213 --- /dev/null +++ b/e2e/app.po.ts @@ -0,0 +1,11 @@ +import { browser, element, by } from 'protractor'; + +export class ProtractorPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.css('app-root h1')).getText(); + } +} 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/package.json b/package.json index f3972c23b5..6a6509fad0 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,10 @@ "debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js", "debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --config webpack.prod.config.ts", "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 marked node-gyp" + "global": "npm install -g angular-cli nodemon npm-check-updates rimraf ts-node typedoc typescript webpack webpack-bundle-size-analyzer marked node-gyp protractor", + "postglobal": "npm run webdriver:update -- --standalone", + "webdriver:start": "webdriver-manager start", + "webdriver:update": "webdriver-manager update" }, "dependencies": { "@angular/common": "2.2.4", diff --git a/protractor.conf.js b/protractor.conf.js new file mode 100644 index 0000000000..169743b34d --- /dev/null +++ b/protractor.conf.js @@ -0,0 +1,32 @@ +// 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, + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + 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/src/tests/.gitkeep b/src/tests/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 From 4b5d9d5dc67c67eb75a2bc1573aeb24199a6b1cf Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Tue, 20 Dec 2016 14:43:25 +0100 Subject: [PATCH 02/33] Protractor configuration --- e2e/app.e2e-spec.ts | 9 +++++-- e2e/app.po.ts | 10 ++++--- package.json | 12 ++++++--- protractor.conf.js | 63 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts index 748e4b7861..ee7b101f96 100644 --- a/e2e/app.e2e-spec.ts +++ b/e2e/app.e2e-spec.ts @@ -7,8 +7,13 @@ describe('protractor App', function() { page = new ProtractorPage(); }); - it('should display message saying app works', () => { + it('should display title "DSpace"', () => { page.navigateTo(); - expect(page.getParagraphText()).toEqual('app works!'); + 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 index b4ee755213..164c524620 100644 --- a/e2e/app.po.ts +++ b/e2e/app.po.ts @@ -5,7 +5,11 @@ export class ProtractorPage { return browser.get('/'); } - getParagraphText() { - return element(by.css('app-root h1')).getText(); + getPageTitleText() { + return browser.getTitle(); } -} + + getFirstPText() { + return element(by.xpath('//p[1]')).getText(); + } +} \ No newline at end of file diff --git a/package.json b/package.json index 6a6509fad0..2441f93a50 100644 --- a/package.json +++ b/package.json @@ -46,9 +46,11 @@ "debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --config webpack.prod.config.ts", "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 marked node-gyp protractor", - "postglobal": "npm run webdriver:update -- --standalone", - "webdriver:start": "webdriver-manager start", - "webdriver:update": "webdriver-manager update" + "postglobal": "npm link protractor", + "protractor": "protractor", + "e2e": "npm run protractor", + "webdriver:start": "webdriver-manager start --seleniumPort 4444", + "webdriver:update": "webdriver-manager update --standalone" }, "dependencies": { "@angular/common": "2.2.4", @@ -128,6 +130,8 @@ "webpack-bundle-analyzer": "1.4.1", "webpack-dev-middleware": "1.8.4", "webpack-dev-server": "2.1.0-beta.11", - "webpack-merge": "1.0.2" + "webpack-merge": "1.0.2", + "jasmine-spec-reporter": "~2.7.0", + "protractor-istanbul-plugin": "~2.0.0" } } diff --git a/protractor.conf.js b/protractor.conf.js index 169743b34d..b128c26297 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -6,14 +6,67 @@ 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:4200/', + // ----------------------------------------------------------------- specs: [ './e2e/**/*.e2e-spec.ts' ], - capabilities: { - 'browserName': 'chrome' - }, - directConnect: true, - baseUrl: 'http://localhost:4200/', + // ----------------------------------------------------------------- + // 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, From d624a196189720c3a1c8be6ad93a303a7d90201a Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 21 Dec 2016 11:32:47 +0100 Subject: [PATCH 03/33] unit test added --- helpers.js | 24 ++++ karma.conf.js | 140 +++++++++++++++++++ package.json | 22 ++- protractor.conf.js | 4 +- spec-bundle.js | 62 +++++++++ src/tests/app.component.spec.ts | 51 +++++++ webpack.test.config.js | 238 ++++++++++++++++++++++++++++++++ webpack.test.js | 238 ++++++++++++++++++++++++++++++++ 8 files changed, 774 insertions(+), 5 deletions(-) create mode 100644 helpers.js create mode 100644 karma.conf.js create mode 100644 spec-bundle.js create mode 100644 src/tests/app.component.spec.ts create mode 100644 webpack.test.config.js create mode 100644 webpack.test.js diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000000..41c9c7741b --- /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..03727fa355 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,140 @@ +/** + * @author: @AngularClass + */ + +module.exports = function(config) { + var webdriverConfig = { + hostname: '4science-devel1', + port: 4202 + } + + var testWebpackConfig = require('./webpack.test.config.js')({env: 'test'}); + + 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-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: [ 'coverage', 'karma-remap-istanbul' ], + + // web server port + port: 4212, + + // 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' + ], + + customLaunchers: { + ChromeTravisCi: { + base: 'Chrome', + flags: ['--no-sandbox'] + }, + 'chrome': { + base: 'WebDriver', + config: webdriverConfig, + browserName: 'chrome', + }, + 'firefox': { + base: 'WebDriver', + config: webdriverConfig, + browserName: 'firefox', + } + }, + + /* + * Continuous Integration mode + * if true, Karma captures browsers, runs the tests and exits + */ + singleRun: false + }; + + if (process.env.TRAVIS){ + configuration.browsers = [ + 'ChromeTravisCi' + ]; + } + + config.set(configuration); +}; diff --git a/package.json b/package.json index 2441f93a50..f29465acfc 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,8 @@ "postglobal": "npm link protractor", "protractor": "protractor", "e2e": "npm run protractor", + "test": "karma start", + "coverage": "http-server -c-1 -o -p 4211 ./coverage", "webdriver:start": "webdriver-manager start --seleniumPort 4444", "webdriver:update": "webdriver-manager update --standalone" }, @@ -98,6 +100,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", @@ -112,12 +115,27 @@ "cookie-parser": "1.4.3", "copy-webpack-plugin": "4.0.1", "imports-loader": "0.6.5", + "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-coverage": "^1.1.1", + "karma-jasmine": "^1.0.2", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "1.8.0", + "karma-cli": "^1.0.1", + "karma-remap-istanbul": "^0.2.1", + "karma-webdriver-launcher": "^1.0.4", + "karma-phantomjs-launcher": "^1.0.2", "node-sass": "3.13.0", "nodemon": "1.11.0", + "protractor-istanbul-plugin": "~2.0.0", "raw-loader": "0.5.1", "reflect-metadata": "0.1.8", "rimraf": "2.5.4", + "source-map-loader": "^0.1.5", "string-replace-loader": "1.0.5", "ts-helpers": "1.1.2", "ts-node": "1.7.0", @@ -130,8 +148,6 @@ "webpack-bundle-analyzer": "1.4.1", "webpack-dev-middleware": "1.8.4", "webpack-dev-server": "2.1.0-beta.11", - "webpack-merge": "1.0.2", - "jasmine-spec-reporter": "~2.7.0", - "protractor-istanbul-plugin": "~2.0.0" + "webpack-merge": "1.0.2" } } diff --git a/protractor.conf.js b/protractor.conf.js index b128c26297..56a84875a1 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -12,7 +12,7 @@ exports.config = { // 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:4200/', + baseUrl: 'http://localhost:3000/', // ----------------------------------------------------------------- specs: [ './e2e/**/*.e2e-spec.ts' @@ -66,7 +66,7 @@ exports.config = { plugins : [{ path: 'node_modules/protractor-istanbul-plugin' }], - + framework: 'jasmine', jasmineNodeOpts: { showColors: true, diff --git a/spec-bundle.js b/spec-bundle.js new file mode 100644 index 0000000000..45954f4088 --- /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/tests', 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/tests/app.component.spec.ts b/src/tests/app.component.spec.ts new file mode 100644 index 0000000000..833b2f0253 --- /dev/null +++ b/src/tests/app.component.spec.ts @@ -0,0 +1,51 @@ +import { + async, + TestBed +} from '@angular/core/testing'; +import { + Component, + ChangeDetectionStrategy, + ViewEncapsulation, + OnDestroy, + OnInit, HostListener +} from "@angular/core"; +import { TranslateService } from "ng2-translate"; +import { HostWindowState } from "../app/shared/host-window.reducer"; +import { Store } from "@ngrx/store"; +import { HostWindowActions } from "../app/shared/host-window.actions"; + +// Load the implementations that should be tested +import { AppComponent } from '../app/app.component'; + + +describe('App', () => { + // provide our implementations or mocks to the dependency injector + /*beforeEach(() => TestBed.configureTestingModule({ + providers: [ + AppComponent, + { + provide: TranslateService, + useClass: class { dispatch = jasmine.createSpy('dispatch') } + }, + { + provide: Store, + useClass: class { dispatch = jasmine.createSpy('dispatch') } + } + ]}));*/ + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }); + TestBed.compileComponents(); + }); + + it('should create the app', async(() => { + let fixture = TestBed.createComponent(AppComponent); + let app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + +}); diff --git a/webpack.test.config.js b/webpack.test.config.js new file mode 100644 index 0000000000..79fb87df6a --- /dev/null +++ b/webpack.test.config.js @@ -0,0 +1,238 @@ +/** + * @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$/, + loader: 'awesome-typescript-loader', + query: { + // use inline sourcemaps for "karma-remap-coverage" reporter + sourceMap: false, + inlineSourceMap: true, + compilerOptions: { + + // Remove TypeScript helpers to be injected + // below by DefinePlugin + removeComments: true + + } + }, + 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 + } + + }; +} diff --git a/webpack.test.js b/webpack.test.js new file mode 100644 index 0000000000..79fb87df6a --- /dev/null +++ b/webpack.test.js @@ -0,0 +1,238 @@ +/** + * @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$/, + loader: 'awesome-typescript-loader', + query: { + // use inline sourcemaps for "karma-remap-coverage" reporter + sourceMap: false, + inlineSourceMap: true, + compilerOptions: { + + // Remove TypeScript helpers to be injected + // below by DefinePlugin + removeComments: true + + } + }, + 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 + } + + }; +} From 37a19a3fbbf201c2b671239a8a3c21f7a6a65f24 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 21 Dec 2016 17:11:19 +0100 Subject: [PATCH 04/33] added postcss --- package.json | 15 +++++++++------ postcss.config.json | 9 +++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 postcss.config.json diff --git a/package.json b/package.json index 520f7b3677..f2cb71159d 100644 --- a/package.json +++ b/package.json @@ -20,14 +20,16 @@ "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", "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", + "postcss": "postcss -c postcss.config.json", + "style": "npm run sass && npm run postcss", + "style:watch": "nodemon -e scss -w src -x \"npm run style\"", "rollup": "rollup -c rollup-server.js && rollup -c rollup-client.js", - "prebuild": "npm run clean:dist && npm run sass", + "prebuild": "npm run clean:dist && npm run style", "build": "webpack --progress", "build:prod": "webpack --config webpack.prod.config.ts", "build:prod:rollup": "npm run build:prod && npm run rollup", - "build:prod:ngc": "npm run clean:prod && npm run sass && npm run ngc && npm run build:prod:rollup", - "build:prod:ngc:json": "npm run clean:prod && npm run sass && npm run ngc && npm run build:prod:json:rollup", + "build:prod:ngc": "npm run clean:prod && npm run style && npm run ngc && npm run build:prod:rollup", + "build:prod:ngc:json": "npm run clean:prod && npm run style && npm run ngc && npm run build:prod:json:rollup", "build:prod:json": "webpack --config webpack.prod.config.ts --json | webpack-bundle-size-analyzer", "build:prod:json:rollup": "npm run build:prod:json && npm run rollup", "ngc": "ngc -p tsconfig.aot.json", @@ -36,7 +38,7 @@ "server:dev": "nodemon --debug dist/server/index.js", "start": "npm run server", "start:dev": "npm run clean:prod && npm run build && npm run server", - "watch": "webpack -w & npm run sass:watch", + "watch": "webpack -w & npm run style:watch", "watch:dev:server": "concurrently \"npm run server:dev\" \"npm run watch\"", "watch:dev": "npm run clean:prod && npm run build && npm run watch:dev:server", "watch:prod:server": "concurrently \"npm run server\" \"npm run watch\"", @@ -49,7 +51,7 @@ "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 postcss-cli" }, "dependencies": { "@angular/common": "2.2.3", @@ -75,6 +77,7 @@ "angular2-platform-node": "2.1.0-rc.1", "angular2-universal": "2.1.0-rc.1", "angular2-universal-polyfills": "2.1.0-rc.1", + "autoprefixer": "^6.5.4", "body-parser": "1.15.2", "bootstrap": "4.0.0-alpha.5", "compression": "1.6.2", diff --git a/postcss.config.json b/postcss.config.json new file mode 100644 index 0000000000..70df875975 --- /dev/null +++ b/postcss.config.json @@ -0,0 +1,9 @@ +{ + "use": ["autoprefixer"], + "input": "src/**/*.css", + "replace": true, + "local-plugins": true, + "autoprefixer": { + "browsers": "last 2 versions" + } +} From 376255700b12a6caae86c273a7bf1f6286698abb Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 21 Dec 2016 17:50:20 +0100 Subject: [PATCH 05/33] added entry to file structure --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a7b658b5c4..74e9ef1e2d 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ dspace-angular ├── app.json * Application manifest file ├── nodemon.json * Nodemon (https://nodemon.io/) configuration ├── package.json * This file describes the npm package for this project, its dependencies, scripts, etc. +├── postcss.config.json * PostCSS (http://postcss.org/) configuration file ├── resources * Folder for static resources │   ├── i18n * Folder for i18n translations │   └── images * Folder for images From f2e7e5dc31083499dda3cba8555553349c6a5233 Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Thu, 22 Dec 2016 10:00:37 +0100 Subject: [PATCH 06/33] Config file fix --- karma.conf.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 03727fa355..2b3b24a057 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -3,13 +3,15 @@ */ module.exports = function(config) { - var webdriverConfig = { - hostname: '4science-devel1', - port: 4202 - } - + 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) @@ -83,8 +85,8 @@ module.exports = function(config) { */ reporters: [ 'coverage', 'karma-remap-istanbul' ], - // web server port - port: 4212, + // Karma web server port + port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, @@ -104,19 +106,25 @@ module.exports = function(config) { */ browsers: [ 'Chrome' + //'ChromeTravisCi', + //'SeleniumChrome', + //'SeleniumFirefox' ], customLaunchers: { - ChromeTravisCi: { + // Continuous integraation with Chrome - launcher + 'ChromeTravisCi': { base: 'Chrome', flags: ['--no-sandbox'] }, - 'chrome': { + // Remote Selenium Server with Chrome - launcher + 'SeleniumChrome': { base: 'WebDriver', config: webdriverConfig, browserName: 'chrome', }, - 'firefox': { + // Remote Selenium Server with Firefox - launcher + 'SeleniumFirefox': { base: 'WebDriver', config: webdriverConfig, browserName: 'firefox', From 95a39ef88ce34996ab87fdcf1c52aa2eb6095b4f Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Thu, 22 Dec 2016 12:05:58 +0100 Subject: [PATCH 07/33] Config file fix --- karma.conf.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 2b3b24a057..9061846541 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -58,7 +58,7 @@ module.exports = function(config) { reporters:[ {type: 'in-memory'}, {type: 'json', subdir: '.', file: 'coverage-final.json'}, - {type : 'html', dir : 'coverage/'} + {type: 'html', dir : 'coverage/'} ] }, @@ -98,7 +98,7 @@ module.exports = function(config) { logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, + autoWatch: false, /* * start these browsers From 2eabedd3cc5c473aa14a78c93b9efa69db18df2d Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 12:07:33 +0100 Subject: [PATCH 08/33] unit test modified --- karma.conf.js | 10 +++-- package.json | 20 ++++++---- spec-bundle.js | 2 +- src/tests/app.component.spec.ts | 65 +++++++++++++++++++++++++++------ webpack.test.config.js | 5 ++- 5 files changed, 78 insertions(+), 24 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 03727fa355..d0a75826fb 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -28,6 +28,7 @@ module.exports = function(config) { 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') @@ -67,6 +68,9 @@ module.exports = function(config) { }, remapIstanbulReporter: { + remapOptions: { + basePath: './src/app' + }, reports: { html: 'coverage' } @@ -81,7 +85,7 @@ module.exports = function(config) { * possible values: 'dots', 'progress' * available reporters: https://npmjs.org/browse/keyword/karma-reporter */ - reporters: [ 'coverage', 'karma-remap-istanbul' ], + reporters: [ 'mocha', 'coverage', 'karma-remap-istanbul' ], // web server port port: 4212, @@ -96,7 +100,7 @@ module.exports = function(config) { logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, + autoWatch: false, /* * start these browsers @@ -127,7 +131,7 @@ module.exports = function(config) { * Continuous Integration mode * if true, Karma captures browsers, runs the tests and exits */ - singleRun: false + singleRun: true }; if (process.env.TRAVIS){ diff --git a/package.json b/package.json index f29465acfc..b4b6d456ef 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,9 @@ "clean:scss:ts": "rimraf **/*.scss.ts", "clean:css:shim:ts": "rimraf **/*.css.shim.ts", "clean:scss:shim:ts": "rimraf **/*.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:dist && npm run clean:prod && npm run clean:node", + "clean": "npm run clean:log && npm run clean:dist && 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", "prebuild": "npm run clean:dist && npm run sass", @@ -83,6 +84,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", @@ -114,21 +116,24 @@ "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.6.5", - "istanbul-instrumenter-loader": "0.2.0", + "istanbul-instrumenter-loader": "1.1.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-sourcemap-loader": "^0.3.7", - "karma-webpack": "1.8.0", - "karma-cli": "^1.0.1", - "karma-remap-istanbul": "^0.2.1", - "karma-webdriver-launcher": "^1.0.4", + "karma-mocha-reporter": "^2.0.0", "karma-phantomjs-launcher": "^1.0.2", + "karma-remap-istanbul": "^0.4.0", + "karma-sourcemap-loader": "^0.3.7", + "karma-webdriver-launcher": "^1.0.4", + "karma-webpack": "1.8.0", "node-sass": "3.13.0", "nodemon": "1.11.0", "protractor-istanbul-plugin": "~2.0.0", @@ -137,6 +142,7 @@ "rimraf": "2.5.4", "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.0", "tslint": "4.0.2", diff --git a/spec-bundle.js b/spec-bundle.js index 45954f4088..36026d530f 100644 --- a/spec-bundle.js +++ b/spec-bundle.js @@ -47,7 +47,7 @@ testing.TestBed.initTestEnvironment( * 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/tests', true, /\.spec\.ts/); +var testContext = require.context('./src', true, /\.spec\.ts/); /* * get all the files, for each file, call the context function diff --git a/src/tests/app.component.spec.ts b/src/tests/app.component.spec.ts index 833b2f0253..42bcc40a66 100644 --- a/src/tests/app.component.spec.ts +++ b/src/tests/app.component.spec.ts @@ -1,21 +1,20 @@ import { async, + ComponentFixture, + inject, TestBed } from '@angular/core/testing'; import { - Component, - ChangeDetectionStrategy, - ViewEncapsulation, - OnDestroy, - OnInit, HostListener + CUSTOM_ELEMENTS_SCHEMA, } from "@angular/core"; -import { TranslateService } from "ng2-translate"; -import { HostWindowState } from "../app/shared/host-window.reducer"; +import { TranslateModule } from "ng2-translate"; +import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; import { Store } from "@ngrx/store"; -import { HostWindowActions } from "../app/shared/host-window.actions"; + // Load the implementations that should be tested import { AppComponent } from '../app/app.component'; +import { HeaderComponent } from '../app/header/header.component'; describe('App', () => { @@ -35,17 +34,61 @@ describe('App', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [ - AppComponent + providers: [ + AppComponent, + { + provide: Store, + useClass: class { dispatch = jasmine.createSpy('dispatch') } + } ], + declarations: [ + HeaderComponent + ], + imports: [TranslateModule.forRoot(), NgbCollapseModule.forRoot()], + schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }); TestBed.compileComponents(); }); - it('should create the app', async(() => { + /*it('should create the app', async(() => { let fixture = TestBed.createComponent(AppComponent); let app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); + }));*/ + + it('should create the app', inject([ AppComponent ], (app: AppComponent) => { + expect(app).toBeTruthy(); })); + /* beforeEach(() => { + return TestBed.configureTestingModule({ + declarations: [AppComponent], + providers: [ + { + provide: TranslateService, + useClass: class { dispatch = jasmine.createSpy('dispatch') } + }, + { + provide: Store, + useClass: class { dispatch = jasmine.createSpy('dispatch') } + } + ] + }); + });*/ + + /*it('should create component', async(() => { + TestBed.compileComponents().then(() => { + const fixture = TestBed.createComponent(AppComponent); + + // Access the dependency injected component instance + const app = fixture.componentInstance; + + // Perform test using fixture and service + expect(true).toBe(true); + }); + }));*/ + + it('true is true', () => expect(true).toBe(true)); + }); + diff --git a/webpack.test.config.js b/webpack.test.config.js index 79fb87df6a..768ff712cd 100644 --- a/webpack.test.config.js +++ b/webpack.test.config.js @@ -91,7 +91,8 @@ module.exports = function (options) { */ { test: /\.ts$/, - loader: 'awesome-typescript-loader', + loaders: ['awesome-typescript-loader', 'angular2-template-loader'], + /*loader: 'awesome-typescript-loader', query: { // use inline sourcemaps for "karma-remap-coverage" reporter sourceMap: false, @@ -103,7 +104,7 @@ module.exports = function (options) { removeComments: true } - }, + },*/ exclude: [/\.e2e\.ts$/] }, From e9df2915e8a2c02933084b69073d64a7c3bcb01e Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 12:11:48 +0100 Subject: [PATCH 09/33] test2.spec.ts added --- src/tests/test2.spec.ts | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/tests/test2.spec.ts diff --git a/src/tests/test2.spec.ts b/src/tests/test2.spec.ts new file mode 100644 index 0000000000..0169943357 --- /dev/null +++ b/src/tests/test2.spec.ts @@ -0,0 +1,58 @@ +/** + * Created by Giuseppe on 21/12/2016. + */ +// ... 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/app.component'; +import { HeaderComponent } from '../app/header/header.component'; + +import { CommonModule } from '@angular/common'; + +let comp: AppComponent; +let fixture: ComponentFixture; +let de: DebugElement; +let el: HTMLElement; + + +describe('greeting component', () => { + + let fixture: ComponentFixture; + + 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(); + })); +}); From 1404e257319088502b6189ea0b55a4701242aaa6 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 12:17:29 +0100 Subject: [PATCH 10/33] test2.spec.ts removed --- src/tests/test2.spec.ts | 58 ----------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/tests/test2.spec.ts diff --git a/src/tests/test2.spec.ts b/src/tests/test2.spec.ts deleted file mode 100644 index 0169943357..0000000000 --- a/src/tests/test2.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Created by Giuseppe on 21/12/2016. - */ -// ... 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/app.component'; -import { HeaderComponent } from '../app/header/header.component'; - -import { CommonModule } from '@angular/common'; - -let comp: AppComponent; -let fixture: ComponentFixture; -let de: DebugElement; -let el: HTMLElement; - - -describe('greeting component', () => { - - let fixture: ComponentFixture; - - 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(); - })); -}); From a58daf037d40050fcf47dcec3242c6e0bc03a920 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 17:55:48 +0100 Subject: [PATCH 11/33] unit test modified --- helpers.js | 2 +- karma.conf.js | 13 +- package.json | 16 +-- spec-bundle.js | 2 +- src/tests/app.component.spec.ts | 77 +++-------- webpack.test.js | 238 -------------------------------- 6 files changed, 33 insertions(+), 315 deletions(-) delete mode 100644 webpack.test.js diff --git a/helpers.js b/helpers.js index 41c9c7741b..ed4330d342 100644 --- a/helpers.js +++ b/helpers.js @@ -4,7 +4,7 @@ var path = require('path'); // Helper functions -var ROOT = path.resolve(__dirname, '..'); +var ROOT = path.resolve(__dirname, '.'); function hasProcessFlag(flag) { return process.argv.join('').indexOf(flag) > -1; diff --git a/karma.conf.js b/karma.conf.js index 425e9aa335..fa0920e1b1 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -3,15 +3,15 @@ */ 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) @@ -70,9 +70,6 @@ module.exports = function(config) { }, remapIstanbulReporter: { - remapOptions: { - basePath: './src/app' - }, reports: { html: 'coverage' } @@ -125,13 +122,13 @@ module.exports = function(config) { 'SeleniumChrome': { base: 'WebDriver', config: webdriverConfig, - browserName: 'chrome', + browserName: 'chrome' }, // Remote Selenium Server with Firefox - launcher 'SeleniumFirefox': { base: 'WebDriver', config: webdriverConfig, - browserName: 'firefox', + browserName: 'firefox' } }, diff --git a/package.json b/package.json index b4b6d456ef..5e8b4da1ca 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "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:dist && npm run clean:prod && npm run clean:coverage && npm run clean:node", @@ -51,7 +51,7 @@ "protractor": "protractor", "e2e": "npm run protractor", "test": "karma start", - "coverage": "http-server -c-1 -o -p 4211 ./coverage", + "coverage": "http-server -c-1 -o ./coverage", "webdriver:start": "webdriver-manager start --seleniumPort 4444", "webdriver:update": "webdriver-manager update --standalone" }, @@ -119,7 +119,7 @@ "css-loader": "^0.26.0", "html-webpack-plugin": "^2.21.0", "imports-loader": "0.6.5", - "istanbul-instrumenter-loader": "1.1.0", + "istanbul-instrumenter-loader": "^0.2.0", "jasmine-core": "~2.5.2", "jasmine-spec-reporter": "~2.7.0", "json-loader": "0.5.4", @@ -130,7 +130,7 @@ "karma-jasmine": "^1.0.2", "karma-mocha-reporter": "^2.0.0", "karma-phantomjs-launcher": "^1.0.2", - "karma-remap-istanbul": "^0.4.0", + "karma-remap-istanbul": "^0.2.1", "karma-sourcemap-loader": "^0.3.7", "karma-webdriver-launcher": "^1.0.4", "karma-webpack": "1.8.0", diff --git a/spec-bundle.js b/spec-bundle.js index 36026d530f..45954f4088 100644 --- a/spec-bundle.js +++ b/spec-bundle.js @@ -47,7 +47,7 @@ testing.TestBed.initTestEnvironment( * 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/); +var testContext = require.context('./src/tests', true, /\.spec\.ts/); /* * get all the files, for each file, call the context function diff --git a/src/tests/app.component.spec.ts b/src/tests/app.component.spec.ts index 42bcc40a66..973753a252 100644 --- a/src/tests/app.component.spec.ts +++ b/src/tests/app.component.spec.ts @@ -1,3 +1,4 @@ +// ... test imports import { async, ComponentFixture, @@ -6,6 +7,7 @@ import { } from '@angular/core/testing'; import { CUSTOM_ELEMENTS_SCHEMA, + DebugElement } from "@angular/core"; import { TranslateModule } from "ng2-translate"; import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; @@ -16,24 +18,20 @@ import { Store } from "@ngrx/store"; import { AppComponent } from '../app/app.component'; import { HeaderComponent } from '../app/header/header.component'; +import { CommonModule } from '@angular/common'; -describe('App', () => { - // provide our implementations or mocks to the dependency injector - /*beforeEach(() => TestBed.configureTestingModule({ - providers: [ - AppComponent, - { - provide: TranslateService, - useClass: class { dispatch = jasmine.createSpy('dispatch') } - }, - { - provide: Store, - useClass: class { dispatch = jasmine.createSpy('dispatch') } - } - ]}));*/ +let comp: AppComponent; +let fixture: ComponentFixture; +let de: DebugElement; +let el: HTMLElement; + + +describe('greeting component', () => { beforeEach(() => { - TestBed.configureTestingModule({ + return TestBed.configureTestingModule({ + imports: [ CommonModule, TranslateModule.forRoot(), NgbCollapseModule.forRoot()], + declarations: [ AppComponent, HeaderComponent ], // declare the test component providers: [ AppComponent, { @@ -41,54 +39,15 @@ describe('App', () => { useClass: class { dispatch = jasmine.createSpy('dispatch') } } ], - declarations: [ - HeaderComponent - ], - imports: [TranslateModule.forRoot(), NgbCollapseModule.forRoot()], schemas: [ CUSTOM_ELEMENTS_SCHEMA ] + }).compileComponents().then(() => { + fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); }); - TestBed.compileComponents(); }); - /*it('should create the app', async(() => { - let fixture = TestBed.createComponent(AppComponent); - let app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - }));*/ - - it('should create the app', inject([ AppComponent ], (app: AppComponent) => { + it('should create component', inject([AppComponent], (app: AppComponent) => { + // Perform test using fixture and service expect(app).toBeTruthy(); })); - - /* beforeEach(() => { - return TestBed.configureTestingModule({ - declarations: [AppComponent], - providers: [ - { - provide: TranslateService, - useClass: class { dispatch = jasmine.createSpy('dispatch') } - }, - { - provide: Store, - useClass: class { dispatch = jasmine.createSpy('dispatch') } - } - ] - }); - });*/ - - /*it('should create component', async(() => { - TestBed.compileComponents().then(() => { - const fixture = TestBed.createComponent(AppComponent); - - // Access the dependency injected component instance - const app = fixture.componentInstance; - - // Perform test using fixture and service - expect(true).toBe(true); - }); - }));*/ - - it('true is true', () => expect(true).toBe(true)); - }); - diff --git a/webpack.test.js b/webpack.test.js deleted file mode 100644 index 79fb87df6a..0000000000 --- a/webpack.test.js +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @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$/, - loader: 'awesome-typescript-loader', - query: { - // use inline sourcemaps for "karma-remap-coverage" reporter - sourceMap: false, - inlineSourceMap: true, - compilerOptions: { - - // Remove TypeScript helpers to be injected - // below by DefinePlugin - removeComments: true - - } - }, - 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 - } - - }; -} From dab61554689c99557f3167781d37ad070e475f0f Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 18:17:45 +0100 Subject: [PATCH 12/33] unit test modified --- karma.conf.js | 2 +- src/tests/app.component.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index fa0920e1b1..826d74a601 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -84,7 +84,7 @@ module.exports = function(config) { * possible values: 'dots', 'progress' * available reporters: https://npmjs.org/browse/keyword/karma-reporter */ - reporters: [ 'mocha', 'coverage', 'karma-remap-istanbul' ], + reporters: [ 'mocha', 'coverage' ], // Karma web server port port: 9876, diff --git a/src/tests/app.component.spec.ts b/src/tests/app.component.spec.ts index 973753a252..d69b35850d 100644 --- a/src/tests/app.component.spec.ts +++ b/src/tests/app.component.spec.ts @@ -26,7 +26,7 @@ let de: DebugElement; let el: HTMLElement; -describe('greeting component', () => { +describe('App component', () => { beforeEach(() => { return TestBed.configureTestingModule({ From 8df306ba9a78fbf5964e194a7f32bbcb7db638f5 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 18:33:27 +0100 Subject: [PATCH 13/33] package.json merged --- package.json | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index c587d10b02..c8a95414bb 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,7 @@ "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", -<<<<<<< HEAD - "clean": "npm run clean:log && npm run clean:dist && npm run clean:prod && npm run clean:coverage && npm run clean:node", -======= - "clean": "npm run clean:log && npm run clean:prod && npm run clean:node", ->>>>>>> 8cd58f824333de235535bdec5975c3b42fe0ba29 + "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", @@ -54,8 +50,7 @@ "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", -<<<<<<< HEAD - "global": "npm install -g angular-cli nodemon npm-check-updates rimraf ts-node typedoc typescript webpack webpack-bundle-size-analyzer marked node-gyp protractor", + "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", "postglobal": "npm link protractor", "protractor": "protractor", "e2e": "npm run protractor", @@ -63,9 +58,6 @@ "coverage": "http-server -c-1 -o ./coverage", "webdriver:start": "webdriver-manager start --seleniumPort 4444", "webdriver:update": "webdriver-manager update --standalone" -======= - "global": "npm install -g angular-cli nodemon npm-check-updates rimraf ts-node typedoc typescript webpack webpack-bundle-size-analyzer rollup marked node-gyp" ->>>>>>> 8cd58f824333de235535bdec5975c3b42fe0ba29 }, "dependencies": { "@angular/common": "2.2.3", @@ -128,10 +120,9 @@ "concurrently": "3.1.0", "cookie-parser": "1.4.3", "copy-webpack-plugin": "4.0.1", -<<<<<<< HEAD "css-loader": "^0.26.0", "html-webpack-plugin": "^2.21.0", - "imports-loader": "0.6.5", + "imports-loader": "0.7.0", "istanbul-instrumenter-loader": "^0.2.0", "jasmine-core": "~2.5.2", "jasmine-spec-reporter": "~2.7.0", @@ -147,26 +138,18 @@ "karma-sourcemap-loader": "^0.3.7", "karma-webdriver-launcher": "^1.0.4", "karma-webpack": "1.8.0", - "node-sass": "3.13.0", -======= - "imports-loader": "0.7.0", - "json-loader": "0.5.4", "node-sass": "4.0.0", ->>>>>>> 8cd58f824333de235535bdec5975c3b42fe0ba29 "nodemon": "1.11.0", "protractor-istanbul-plugin": "~2.0.0", "raw-loader": "0.5.1", "reflect-metadata": "0.1.8", "rimraf": "2.5.4", -<<<<<<< HEAD - "source-map-loader": "^0.1.5", -======= "rollup": "0.37.0", "rollup-plugin-commonjs": "6.0.0", "rollup-plugin-node-globals": "1.1.0", "rollup-plugin-node-resolve": "2.0.0", "rollup-plugin-uglify": "1.0.1", ->>>>>>> 8cd58f824333de235535bdec5975c3b42fe0ba29 + "source-map-loader": "^0.1.5", "string-replace-loader": "1.0.5", "to-string-loader": "^1.1.4", "ts-helpers": "1.1.2", From 697a398dc7d7a258dc79851ff4c666b082bd235d Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Thu, 22 Dec 2016 18:37:56 +0100 Subject: [PATCH 14/33] README.md update with tests --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/README.md b/README.md index a7b658b5c4..abb2d6130e 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,52 @@ npm run clean:prod npm run clean:dist ``` +## Tests +# 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'. +keeping Karma running, it's possible to see a tests report here: +http://localhost:9876/debug.html +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 at the following path: +`./src/tests` + +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 must be installed as 'global' so, make sure you have runned: +`npm run global` +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. From b65e2f9442a9ce67150ffd93d34ec44ac375f294 Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Thu, 22 Dec 2016 18:48:15 +0100 Subject: [PATCH 15/33] README.md update --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index abb2d6130e..894f506f1e 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,21 +86,19 @@ npm run clean:prod npm run clean:dist ``` -## Tests -# Unit Test +## 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'. -keeping Karma running, it's possible to see a tests report here: -http://localhost:9876/debug.html A coverage report is also available at: http://localhost:9876/ after you run: -`npm run coverage` +`npm run coverage`. To correctly run the tests you need to run the build once with: -`npm run build` +`npm run build`. The default browser is Google Chrome. @@ -109,13 +108,13 @@ Place your tests at the following path: and run: `npn run test` -# E2E 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 must be installed as 'global' so, make sure you have runned: -`npm run global` +`npm run global`. If you are going to execute tests locally you need to run (once time only): -`npm run webdriver:update` +`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. @@ -157,8 +156,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 @@ -179,6 +181,7 @@ dspace-angular │   ├── styles * Folder containing global styles. │   │   ├── main.scss * Global scss file │   │   └── variables.scss * Global sass variables file +│   ├── tests * Folder for unit test files │   └── typings.d.ts * File that allows you to add custom typings for libraries without TypeScript support ├── tsconfig.aot.json * TypeScript config for production builds ├── tsconfig.json * TypeScript config for development build From 48edf039ba005166df25f5621ffd201ec7b90051 Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Thu, 22 Dec 2016 18:53:59 +0100 Subject: [PATCH 16/33] README.md update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 894f506f1e..3cb7861bdc 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ 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: @@ -187,6 +188,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 ``` From 29eee0dda66ae3c9b5c2491ae04ab3d41c58ae96 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 19:20:06 +0100 Subject: [PATCH 17/33] package.json modified --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8a95414bb..a7b60f7313 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "protractor": "protractor", "e2e": "npm run protractor", "test": "karma start", - "coverage": "http-server -c-1 -o ./coverage", + "coverage": "http-server -c-1 -o -p 4211 ./coverage", "webdriver:start": "webdriver-manager start --seleniumPort 4444", "webdriver:update": "webdriver-manager update --standalone" }, From dcbb33d7ba19b96d4c0775d87a64f3e0a98ca844 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 22 Dec 2016 19:25:54 +0100 Subject: [PATCH 18/33] package.json modified --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a7b60f7313..292e8ccb89 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "protractor": "protractor", "e2e": "npm run protractor", "test": "karma start", - "coverage": "http-server -c-1 -o -p 4211 ./coverage", + "coverage": "http-server -c-1 -o -p 9875 ./coverage", "webdriver:start": "webdriver-manager start --seleniumPort 4444", "webdriver:update": "webdriver-manager update --standalone" }, From 11c5e2ff7957b3122d005cf0f01c96d741e5988d Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 5 Jan 2017 11:29:25 +0100 Subject: [PATCH 19/33] Karma remap istanbul bug fix --- karma.conf.js | 4 ++-- tsconfig.json | 1 + webpack.test.config.js | 31 +++++++++++++++++-------------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 826d74a601..ccc4f2e193 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function(config) { var configuration = { // base path that will be used to resolve all patterns (e.g. files, exclude) - basePath: '', + basePath: '.', /* * Frameworks to use @@ -84,7 +84,7 @@ module.exports = function(config) { * possible values: 'dots', 'progress' * available reporters: https://npmjs.org/browse/keyword/karma-reporter */ - reporters: [ 'mocha', 'coverage' ], + reporters: [ 'mocha', 'coverage', 'karma-remap-istanbul' ], // Karma web server port port: 9876, 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.test.config.js b/webpack.test.config.js index 768ff712cd..cd288ce894 100644 --- a/webpack.test.config.js +++ b/webpack.test.config.js @@ -91,20 +91,23 @@ module.exports = function (options) { */ { test: /\.ts$/, - loaders: ['awesome-typescript-loader', 'angular2-template-loader'], - /*loader: 'awesome-typescript-loader', - query: { - // use inline sourcemaps for "karma-remap-coverage" reporter - sourceMap: false, - inlineSourceMap: true, - compilerOptions: { - - // Remove TypeScript helpers to be injected - // below by DefinePlugin - removeComments: true - - } - },*/ + 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$/] }, From b5357e183685d9b867fbd70db635963ae2b2df52 Mon Sep 17 00:00:00 2001 From: Matteo Perelli Date: Tue, 10 Jan 2017 09:11:11 +0100 Subject: [PATCH 20/33] README.md update --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3cb7861bdc..a4f1f64f85 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,7 @@ To correctly run the tests you need to run the build once with: The default browser is Google Chrome. -Place your tests at the following path: -`./src/tests` +Place your tests in the same location of the application source code files that they test. and run: `npn run test` @@ -111,8 +110,7 @@ and run: ### 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 must be installed as 'global' so, make sure you have runned: -`npm run global`. +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`. @@ -182,7 +180,6 @@ dspace-angular │   ├── styles * Folder containing global styles. │   │   ├── main.scss * Global scss file │   │   └── variables.scss * Global sass variables file -│   ├── tests * Folder for unit test files │   └── typings.d.ts * File that allows you to add custom typings for libraries without TypeScript support ├── tsconfig.aot.json * TypeScript config for production builds ├── tsconfig.json * TypeScript config for development build From 144324e0233dc7ae18bdb4d0195702a396ccb340 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 10 Jan 2017 09:45:29 +0100 Subject: [PATCH 21/33] Dir tests deleted test:watch added webpack library updated protractor installed locally --- karma.conf.js | 4 ++-- package.json | 17 +++++++++-------- spec-bundle.js | 2 +- src/{tests => app}/app.component.spec.ts | 4 ++-- src/tests/.gitkeep | 0 webpack.config.ts | 5 +++++ webpack.test.config.js | 4 ++++ 7 files changed, 23 insertions(+), 13 deletions(-) rename src/{tests => app}/app.component.spec.ts (91%) delete mode 100644 src/tests/.gitkeep diff --git a/karma.conf.js b/karma.conf.js index ccc4f2e193..43ad307a3c 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -99,7 +99,7 @@ module.exports = function(config) { logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, + //autoWatch: true, /* * start these browsers @@ -136,7 +136,7 @@ module.exports = function(config) { * Continuous Integration mode * if true, Karma captures browsers, runs the tests and exits */ - singleRun: true + //singleRun: true }; if (process.env.TRAVIS){ diff --git a/package.json b/package.json index 292e8ccb89..237bc43133 100644 --- a/package.json +++ b/package.json @@ -50,14 +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 protractor", - "postglobal": "npm link protractor", - "protractor": "protractor", + "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", + "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": "webdriver-manager start --seleniumPort 4444", - "webdriver:update": "webdriver-manager update --standalone" + "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", @@ -140,6 +140,7 @@ "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", @@ -159,10 +160,10 @@ "typedoc": "0.5.1", "typescript": "2.0.10", "v8-lazy-parse-webpack-plugin": "0.3.0", - "webpack": "2.1.0-beta.27", + "webpack": "2.2.0-rc.3", "webpack-bundle-analyzer": "1.4.1", "webpack-dev-middleware": "1.9.0", - "webpack-dev-server": "2.1.0-beta.11", + "webpack-dev-server": "2.2.0-rc.0", "webpack-merge": "1.1.1" } } diff --git a/spec-bundle.js b/spec-bundle.js index 45954f4088..36026d530f 100644 --- a/spec-bundle.js +++ b/spec-bundle.js @@ -47,7 +47,7 @@ testing.TestBed.initTestEnvironment( * 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/tests', true, /\.spec\.ts/); +var testContext = require.context('./src', true, /\.spec\.ts/); /* * get all the files, for each file, call the context function diff --git a/src/tests/app.component.spec.ts b/src/app/app.component.spec.ts similarity index 91% rename from src/tests/app.component.spec.ts rename to src/app/app.component.spec.ts index d69b35850d..4f53b0ba93 100644 --- a/src/tests/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -15,8 +15,8 @@ import { Store } from "@ngrx/store"; // Load the implementations that should be tested -import { AppComponent } from '../app/app.component'; -import { HeaderComponent } from '../app/header/header.component'; +import { AppComponent } from './app.component'; +import { HeaderComponent } from './header/header.component'; import { CommonModule } from '@angular/common'; diff --git a/src/tests/.gitkeep b/src/tests/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/webpack.config.ts b/webpack.config.ts index 1d4b927e13..e6128264b1 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -67,6 +67,11 @@ export var commonConfig = { } ], }, + + performance: { + hints: false + }, + plugins: [ // Use commonPlugins. ] diff --git a/webpack.test.config.js b/webpack.test.config.js index cd288ce894..4f3530e8de 100644 --- a/webpack.test.config.js +++ b/webpack.test.config.js @@ -166,6 +166,10 @@ module.exports = function (options) { ] }, + performance: { + hints: false + }, + /** * Add additional plugins to the compiler. * From 9994947ece063fbd2d8f7d106ec4c5d8e8e7018e Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 10 Jan 2017 17:40:56 +0100 Subject: [PATCH 22/33] roll back to webpack 2.1.0-beta.27 --- package.json | 6 ++++-- webpack.config.ts | 4 ---- webpack.test.config.js | 4 ---- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 237bc43133..44316b310e 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,8 @@ "@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", @@ -160,10 +162,10 @@ "typedoc": "0.5.1", "typescript": "2.0.10", "v8-lazy-parse-webpack-plugin": "0.3.0", - "webpack": "2.2.0-rc.3", + "webpack": "2.1.0-beta.27", "webpack-bundle-analyzer": "1.4.1", "webpack-dev-middleware": "1.9.0", - "webpack-dev-server": "2.2.0-rc.0", + "webpack-dev-server": "2.1.0-beta.11", "webpack-merge": "1.1.1" } } diff --git a/webpack.config.ts b/webpack.config.ts index e6128264b1..065ac1cf6e 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -68,10 +68,6 @@ export var commonConfig = { ], }, - performance: { - hints: false - }, - plugins: [ // Use commonPlugins. ] diff --git a/webpack.test.config.js b/webpack.test.config.js index 4f3530e8de..cd288ce894 100644 --- a/webpack.test.config.js +++ b/webpack.test.config.js @@ -166,10 +166,6 @@ module.exports = function (options) { ] }, - performance: { - hints: false - }, - /** * Add additional plugins to the compiler. * From 4b62d964a9df26aa060d55c13873be51c1ae1794 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 11 Jan 2017 09:40:23 +0100 Subject: [PATCH 23/33] added tests for headerReducer and HeaderActions --- package.json | 2 + src/app/header/header.actions.spec.ts | 22 ++++++++ src/app/header/header.reducer.spec.ts | 76 +++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 src/app/header/header.actions.spec.ts create mode 100644 src/app/header/header.reducer.spec.ts diff --git a/package.json b/package.json index 44316b310e..d72b0e2f02 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "@types/body-parser": "0.0.33", "@types/compression": "0.0.33", "@types/cookie-parser": "1.3.30", + "@types/deep-freeze": "0.0.29", "@types/express": "4.0.34", "@types/express-serve-static-core": "4.0.39", "@types/hammerjs": "2.0.33", @@ -123,6 +124,7 @@ "cookie-parser": "1.4.3", "copy-webpack-plugin": "4.0.1", "css-loader": "^0.26.0", + "deep-freeze": "0.0.1", "html-webpack-plugin": "^2.21.0", "imports-loader": "0.7.0", "istanbul-instrumenter-loader": "^0.2.0", diff --git a/src/app/header/header.actions.spec.ts b/src/app/header/header.actions.spec.ts new file mode 100644 index 0000000000..8ea2094ee4 --- /dev/null +++ b/src/app/header/header.actions.spec.ts @@ -0,0 +1,22 @@ +import { HeaderActions } from "./header.actions"; +describe("HeaderActions", () => { + + describe("collapse", () => { + it("should return a COLLAPSE action", () => { + expect(HeaderActions.collapse().type).toEqual(HeaderActions.COLLAPSE); + }); + }); + + describe("expand", () => { + it("should return an EXPAND action", () => { + expect(HeaderActions.expand().type).toEqual(HeaderActions.EXPAND); + }); + }); + + describe("toggle", () => { + it("should return a TOGGLE action", () => { + expect(HeaderActions.toggle().type).toEqual(HeaderActions.TOGGLE); + }); + }) + +}); diff --git a/src/app/header/header.reducer.spec.ts b/src/app/header/header.reducer.spec.ts new file mode 100644 index 0000000000..03efcf1359 --- /dev/null +++ b/src/app/header/header.reducer.spec.ts @@ -0,0 +1,76 @@ +import * as deepFreeze from "deep-freeze"; + +import { headerReducer } from "./header.reducer"; +import { HeaderActions } from "./header.actions"; + +describe("headerReducer", () => { + + it("should return the current state when no valid actions have been made", () => { + const state = { navCollapsed: false }; + const newState = headerReducer(state, {type: 'undefined-action'}); + + expect(newState).toEqual(state); + }); + + it("should start with navCollapsed = true", () => { + const initialState = headerReducer(undefined, {type: 'undefined-action'}); + + // The navigation starts collapsed + expect(initialState.navCollapsed).toEqual(true); + }); + + it("should set navCollapsed to true in response to the COLLAPSE action", () => { + const state = { navCollapsed: false }; + const action = HeaderActions.collapse(); + const newState = headerReducer(state, action); + + expect(newState.navCollapsed).toEqual(true); + }); + + it("should perform the COLLAPSE action without mutating the previous state", () => { + const state = { navCollapsed: false }; + deepFreeze(state); + + const action = HeaderActions.collapse(); + headerReducer(state, action); + + //no expect required, deepFreeze will ensure an exception is thrown if the state + //is mutated, and any uncaught exception will cause the test to fail + }); + + it("should set navCollapsed to false in response to the EXPAND action", () => { + const state = { navCollapsed: true }; + const action = HeaderActions.expand(); + const newState = headerReducer(state, action); + + expect(newState.navCollapsed).toEqual(false); + }); + + it("should perform the EXPAND action without mutating the previous state", () => { + const state = { navCollapsed: true }; + deepFreeze(state); + + const action = HeaderActions.expand(); + headerReducer(state, action); + }); + + it("should flip the value of navCollapsed in response to the TOGGLE action", () => { + const state1 = { navCollapsed: true }; + const action = HeaderActions.toggle(); + + const state2 = headerReducer(state1, action); + const state3 = headerReducer(state2, action); + + expect(state2.navCollapsed).toEqual(false); + expect(state3.navCollapsed).toEqual(true); + }); + + it("should perform the TOGGLE action without mutating the previous state", () => { + const state = { navCollapsed: true }; + deepFreeze(state); + + const action = HeaderActions.toggle(); + headerReducer(state, action); + }); + +}); From 8e4bec9c304f7f1b0bfcebdbde96b7c6fe35c2b9 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Fri, 13 Jan 2017 11:25:07 +0100 Subject: [PATCH 24/33] added tests for hostReducer and Header Effects, and switch to typed actions --- .gitignore | 1 + src/app/app.component.ts | 4 +- src/app/header/header.actions.spec.ts | 22 --------- src/app/header/header.actions.ts | 57 ++++++++++++++-------- src/app/header/header.component.ts | 13 +++-- src/app/header/header.effects.spec.ts | 53 ++++++++++++++++++++ src/app/header/header.effects.ts | 10 ++-- src/app/header/header.reducer.spec.ts | 24 +++++---- src/app/header/header.reducer.ts | 11 ++--- src/app/shared/host-window.actions.ts | 27 ++++++---- src/app/shared/host-window.reducer.spec.ts | 40 +++++++++++++++ src/app/shared/host-window.reducer.ts | 7 ++- src/app/shared/ngrx/type.ts | 24 +++++++++ 13 files changed, 211 insertions(+), 82 deletions(-) delete mode 100644 src/app/header/header.actions.spec.ts create mode 100644 src/app/header/header.effects.spec.ts create mode 100644 src/app/shared/host-window.reducer.spec.ts create mode 100644 src/app/shared/ngrx/type.ts diff --git a/.gitignore b/.gitignore index 0e713600f8..f691aae4b2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ npm-debug.log /dist/ +/coverage/ .idea *.ngfactory.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 15485eb6a6..0b861bb75c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -8,7 +8,7 @@ import { import { TranslateService } from "ng2-translate"; import { HostWindowState } from "./shared/host-window.reducer"; import { Store } from "@ngrx/store"; -import { HostWindowActions } from "./shared/host-window.actions"; +import { HostWindowResizeAction } from "./shared/host-window.actions"; @Component({ changeDetection: ChangeDetectionStrategy.Default, @@ -52,7 +52,7 @@ export class AppComponent implements OnDestroy, OnInit { @HostListener('window:resize', ['$event']) private onResize(event): void { this.store.dispatch( - HostWindowActions.resize(event.target.innerWidth, event.target.innerHeight) + new HostWindowResizeAction(event.target.innerWidth, event.target.innerHeight) ); } diff --git a/src/app/header/header.actions.spec.ts b/src/app/header/header.actions.spec.ts deleted file mode 100644 index 8ea2094ee4..0000000000 --- a/src/app/header/header.actions.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { HeaderActions } from "./header.actions"; -describe("HeaderActions", () => { - - describe("collapse", () => { - it("should return a COLLAPSE action", () => { - expect(HeaderActions.collapse().type).toEqual(HeaderActions.COLLAPSE); - }); - }); - - describe("expand", () => { - it("should return an EXPAND action", () => { - expect(HeaderActions.expand().type).toEqual(HeaderActions.EXPAND); - }); - }); - - describe("toggle", () => { - it("should return a TOGGLE action", () => { - expect(HeaderActions.toggle().type).toEqual(HeaderActions.TOGGLE); - }); - }) - -}); diff --git a/src/app/header/header.actions.ts b/src/app/header/header.actions.ts index e3f64c1019..c333fc5df7 100644 --- a/src/app/header/header.actions.ts +++ b/src/app/header/header.actions.ts @@ -1,24 +1,43 @@ import { Action } from "@ngrx/store"; +import { type } from "../shared/ngrx/type"; -export class HeaderActions { - static COLLAPSE = 'dspace/header/COLLAPSE'; - static collapse(): Action { - return { - type: HeaderActions.COLLAPSE - } - } + /** + * For each action type in an action group, make a simple + * enum object for all of this group's action types. + * + * The 'type' utility function coerces strings into string + * literal types and runs a simple check to guarantee all + * action types in the application are unique. + */ +export const HeaderActionTypes = { + COLLAPSE: type('dspace/header/COLLAPSE'), + EXPAND: type('dspace/header/EXPAND'), + TOGGLE: type('dspace/header/TOGGLE') +}; - static EXPAND = 'dspace/header/EXPAND'; - static expand(): Action { - return { - type: HeaderActions.EXPAND - } - } +export class HeaderCollapseAction implements Action { + type = HeaderActionTypes.COLLAPSE; - static TOGGLE = 'dspace/header/TOGGLE'; - static toggle(): Action { - return { - type: HeaderActions.TOGGLE - } - } + constructor() {} } + +export class HeaderExpandAction implements Action { + type = HeaderActionTypes.EXPAND; + + constructor() {} +} + +export class HeaderToggleAction implements Action { + type = HeaderActionTypes.TOGGLE; + + constructor() {} +} + +/** + * Export a type alias of all actions in this action group + * so that reducers can easily compose action types + */ +export type HeaderAction + = HeaderCollapseAction + | HeaderExpandAction + | HeaderToggleAction diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index 69da1aea68..29cac9cadd 100644 --- a/src/app/header/header.component.ts +++ b/src/app/header/header.component.ts @@ -1,9 +1,12 @@ import { Component, OnInit } from "@angular/core"; import { Store } from "@ngrx/store"; import { HeaderState } from "./header.reducer"; -import { HeaderActions } from "./header.actions"; import { Observable } from "rxjs"; -import 'rxjs/add/operator/filter'; +import { + HeaderCollapseAction, + HeaderExpandAction, + HeaderToggleAction +} from "./header.actions"; @Component({ selector: 'ds-header', @@ -25,15 +28,15 @@ export class HeaderComponent implements OnInit { } private collapse(): void { - this.store.dispatch(HeaderActions.collapse()); + this.store.dispatch(new HeaderCollapseAction()); } private expand(): void { - this.store.dispatch(HeaderActions.expand()); + this.store.dispatch(new HeaderExpandAction()); } public toggle(): void { - this.store.dispatch(HeaderActions.toggle()); + this.store.dispatch(new HeaderToggleAction()); } } diff --git a/src/app/header/header.effects.spec.ts b/src/app/header/header.effects.spec.ts new file mode 100644 index 0000000000..7c5f40228d --- /dev/null +++ b/src/app/header/header.effects.spec.ts @@ -0,0 +1,53 @@ +import { TestBed, inject } from "@angular/core/testing"; +import { EffectsTestingModule, EffectsRunner } from '@ngrx/effects/testing'; +import { HeaderEffects } from "./header.effects"; +import { HeaderCollapseAction } from "./header.actions"; +import { HostWindowResizeAction } from "../shared/host-window.actions"; +import { routerActions } from "@ngrx/router-store"; + +describe('HeaderEffects', () => { + beforeEach(() => TestBed.configureTestingModule({ + imports: [ + EffectsTestingModule + ], + providers: [ + HeaderEffects + ] + })); + + let runner: EffectsRunner; + let headerEffects: HeaderEffects; + + beforeEach(inject([ + EffectsRunner, HeaderEffects + ], + (_runner, _headerEffects) => { + runner = _runner; + headerEffects = _headerEffects; + } + )); + + describe('resize$', () => { + + it('should return a COLLAPSE action in response to a RESIZE action', () => { + runner.queue(new HostWindowResizeAction(800,600)); + + headerEffects.resize$.subscribe(result => { + expect(result).toEqual(new HeaderCollapseAction()); + }); + }); + + }); + + describe('routeChange$', () => { + + it('should return a COLLAPSE action in response to an UPDATE_LOCATION action', () => { + runner.queue({ type: routerActions.UPDATE_LOCATION }); + + headerEffects.resize$.subscribe(result => { + expect(result).toEqual(new HeaderCollapseAction()); + }); + }); + + }); +}); diff --git a/src/app/header/header.effects.ts b/src/app/header/header.effects.ts index d9ea53adda..33888e074d 100644 --- a/src/app/header/header.effects.ts +++ b/src/app/header/header.effects.ts @@ -1,8 +1,8 @@ import { Injectable } from "@angular/core"; import { Effect, Actions } from '@ngrx/effects' -import { HeaderActions } from "./header.actions"; -import { HostWindowActions } from "../shared/host-window.actions"; +import { HostWindowActionTypes } from "../shared/host-window.actions"; import { routerActions } from "@ngrx/router-store"; +import { HeaderCollapseAction } from "./header.actions"; @Injectable() export class HeaderEffects { @@ -12,10 +12,10 @@ export class HeaderEffects { ) { } @Effect() resize$ = this.actions$ - .ofType(HostWindowActions.RESIZE) - .map(() => HeaderActions.collapse()); + .ofType(HostWindowActionTypes.RESIZE) + .map(() => new HeaderCollapseAction()); @Effect() routeChange$ = this.actions$ .ofType(routerActions.UPDATE_LOCATION) - .map(() => HeaderActions.collapse()); + .map(() => new HeaderCollapseAction()); } diff --git a/src/app/header/header.reducer.spec.ts b/src/app/header/header.reducer.spec.ts index 03efcf1359..a3f9f50021 100644 --- a/src/app/header/header.reducer.spec.ts +++ b/src/app/header/header.reducer.spec.ts @@ -1,19 +1,25 @@ import * as deepFreeze from "deep-freeze"; import { headerReducer } from "./header.reducer"; -import { HeaderActions } from "./header.actions"; +import { + HeaderCollapseAction, + HeaderExpandAction, + HeaderToggleAction +} from "./header.actions"; describe("headerReducer", () => { + let nullAction = new HeaderCollapseAction(); + nullAction.type = null; it("should return the current state when no valid actions have been made", () => { const state = { navCollapsed: false }; - const newState = headerReducer(state, {type: 'undefined-action'}); + const newState = headerReducer(state, nullAction); expect(newState).toEqual(state); }); it("should start with navCollapsed = true", () => { - const initialState = headerReducer(undefined, {type: 'undefined-action'}); + const initialState = headerReducer(undefined, nullAction); // The navigation starts collapsed expect(initialState.navCollapsed).toEqual(true); @@ -21,7 +27,7 @@ describe("headerReducer", () => { it("should set navCollapsed to true in response to the COLLAPSE action", () => { const state = { navCollapsed: false }; - const action = HeaderActions.collapse(); + const action = new HeaderCollapseAction(); const newState = headerReducer(state, action); expect(newState.navCollapsed).toEqual(true); @@ -31,7 +37,7 @@ describe("headerReducer", () => { const state = { navCollapsed: false }; deepFreeze(state); - const action = HeaderActions.collapse(); + const action = new HeaderCollapseAction(); headerReducer(state, action); //no expect required, deepFreeze will ensure an exception is thrown if the state @@ -40,7 +46,7 @@ describe("headerReducer", () => { it("should set navCollapsed to false in response to the EXPAND action", () => { const state = { navCollapsed: true }; - const action = HeaderActions.expand(); + const action = new HeaderExpandAction(); const newState = headerReducer(state, action); expect(newState.navCollapsed).toEqual(false); @@ -50,13 +56,13 @@ describe("headerReducer", () => { const state = { navCollapsed: true }; deepFreeze(state); - const action = HeaderActions.expand(); + const action = new HeaderExpandAction(); headerReducer(state, action); }); it("should flip the value of navCollapsed in response to the TOGGLE action", () => { const state1 = { navCollapsed: true }; - const action = HeaderActions.toggle(); + const action = new HeaderToggleAction(); const state2 = headerReducer(state1, action); const state3 = headerReducer(state2, action); @@ -69,7 +75,7 @@ describe("headerReducer", () => { const state = { navCollapsed: true }; deepFreeze(state); - const action = HeaderActions.toggle(); + const action = new HeaderToggleAction(); headerReducer(state, action); }); diff --git a/src/app/header/header.reducer.ts b/src/app/header/header.reducer.ts index af153fba24..c1d0fef7ea 100644 --- a/src/app/header/header.reducer.ts +++ b/src/app/header/header.reducer.ts @@ -1,5 +1,4 @@ -import { Action } from "@ngrx/store"; -import { HeaderActions } from "./header.actions"; +import { HeaderAction, HeaderActionTypes } from "./header.actions"; export interface HeaderState { navCollapsed: boolean; @@ -9,23 +8,23 @@ const initialState: HeaderState = { navCollapsed: true }; -export const headerReducer = (state = initialState, action: Action): HeaderState => { +export const headerReducer = (state = initialState, action: HeaderAction): HeaderState => { switch (action.type) { - case HeaderActions.COLLAPSE: { + case HeaderActionTypes.COLLAPSE: { return Object.assign({}, state, { navCollapsed: true }); } - case HeaderActions.EXPAND: { + case HeaderActionTypes.EXPAND: { return Object.assign({}, state, { navCollapsed: false }); } - case HeaderActions.TOGGLE: { + case HeaderActionTypes.TOGGLE: { return Object.assign({}, state, { navCollapsed: !state.navCollapsed }); diff --git a/src/app/shared/host-window.actions.ts b/src/app/shared/host-window.actions.ts index de41c69564..99be01cdc2 100644 --- a/src/app/shared/host-window.actions.ts +++ b/src/app/shared/host-window.actions.ts @@ -1,14 +1,21 @@ import { Action } from "@ngrx/store"; +import { type } from "./ngrx/type"; -export class HostWindowActions { - static RESIZE = 'dspace/host-window/RESIZE'; - static resize(newWidth: number, newHeight: number): Action { - return { - type: HostWindowActions.RESIZE, - payload: { - width: newWidth, - height: newHeight - } - } +export const HostWindowActionTypes = { + RESIZE: type('dspace/host-window/RESIZE') +}; + +export class HostWindowResizeAction implements Action { + type = HostWindowActionTypes.RESIZE; + payload: { + width: number; + height: number; + }; + + constructor(width: number, height: number) { + this.payload = { width, height } } } + +export type HostWindowAction + = HostWindowResizeAction; diff --git a/src/app/shared/host-window.reducer.spec.ts b/src/app/shared/host-window.reducer.spec.ts new file mode 100644 index 0000000000..d0c2e697c0 --- /dev/null +++ b/src/app/shared/host-window.reducer.spec.ts @@ -0,0 +1,40 @@ +import * as deepFreeze from "deep-freeze"; +import { hostWindowReducer } from "./host-window.reducer"; +import { HostWindowResizeAction } from "./host-window.actions"; + +describe('hostWindowReducer', () => { + let nullAction = new HostWindowResizeAction(0, 0); + nullAction.type = null; + + it("should return the current state when no valid actions have been made", () => { + const state = { width: 800, height: 600 }; + const newState = hostWindowReducer(state, nullAction); + + expect(newState).toEqual(state); + }); + + it("should start with width = null and height = null", () => { + const initialState = hostWindowReducer(undefined, nullAction); + + expect(initialState.width).toEqual(null); + expect(initialState.height).toEqual(null); + }); + + it("should update the width and height in the state in response to a RESIZE action", () => { + const state = { width: 800, height: 600 }; + const action = new HostWindowResizeAction(1024, 768); + const newState = hostWindowReducer(state, action); + + expect(newState.width).toEqual(1024); + expect(newState.height).toEqual(768); + }); + + it("should perform the RESIZE action without mutating the previous state", () => { + const state = { width: 800, height: 600 }; + deepFreeze(state); + + const action = new HostWindowResizeAction(1024, 768); + hostWindowReducer(state, action); + }); + +}); diff --git a/src/app/shared/host-window.reducer.ts b/src/app/shared/host-window.reducer.ts index 4b8e1d3cb9..03349b3a91 100644 --- a/src/app/shared/host-window.reducer.ts +++ b/src/app/shared/host-window.reducer.ts @@ -1,5 +1,4 @@ -import { Action } from "@ngrx/store"; -import { HostWindowActions } from "./host-window.actions"; +import { HostWindowAction, HostWindowActionTypes } from "./host-window.actions"; export interface HostWindowState { width: number; @@ -11,10 +10,10 @@ const initialState: HostWindowState = { height: null }; -export const hostWindowReducer = (state = initialState, action: Action): HostWindowState => { +export const hostWindowReducer = (state = initialState, action: HostWindowAction): HostWindowState => { switch (action.type) { - case HostWindowActions.RESIZE: { + case HostWindowActionTypes.RESIZE: { return Object.assign({}, state, action.payload); } diff --git a/src/app/shared/ngrx/type.ts b/src/app/shared/ngrx/type.ts new file mode 100644 index 0000000000..9b50c1d6d0 --- /dev/null +++ b/src/app/shared/ngrx/type.ts @@ -0,0 +1,24 @@ + +/** + * Based on + * https://github.com/ngrx/example-app/blob/master/src/app/util.ts + * + * This function coerces a string into a string literal type. + * Using tagged union types in TypeScript 2.0, this enables + * powerful typechecking of our reducers. + * + * Since every action label passes through this function it + * is a good place to ensure all of our action labels + * are unique. + */ + +let typeCache: { [label: string]: boolean } = {}; +export function type(label: T | ''): T { + if (typeCache[label]) { + throw new Error(`Action type "${label}" is not unique"`); + } + + typeCache[label] = true; + + return label; +} From 28fd92b9f7fdf8fd0ae6f937a979344960896a13 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 13 Jan 2017 18:37:35 +0100 Subject: [PATCH 25/33] test issue --- src/app/app.component.spec.ts | 19 +++++-- src/test-issue.spec.ts | 97 +++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 src/test-issue.spec.ts diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 4f53b0ba93..64e45e9bfb 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -9,6 +9,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from "@angular/core"; +import { By } from '@angular/platform-browser'; import { TranslateModule } from "ng2-translate"; import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; import { Store } from "@ngrx/store"; @@ -28,7 +29,7 @@ let el: HTMLElement; describe('App component', () => { - beforeEach(() => { + beforeEach(async(() => { return TestBed.configureTestingModule({ imports: [ CommonModule, TranslateModule.forRoot(), NgbCollapseModule.forRoot()], declarations: [ AppComponent, HeaderComponent ], // declare the test component @@ -40,10 +41,18 @@ describe('App component', () => { } ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ] - }).compileComponents().then(() => { - fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - }); + }) + })); + + // synchronous beforeEach + beforeEach(() => { + fixture = TestBed.createComponent(AppComponent); + + comp = fixture.componentInstance; // BannerComponent test instance + + // query for the title

by CSS element selector + de = fixture.debugElement.query(By.css('p')); + el = de.nativeElement; }); it('should create component', inject([AppComponent], (app: AppComponent) => { diff --git a/src/test-issue.spec.ts b/src/test-issue.spec.ts new file mode 100644 index 0000000000..434b928e29 --- /dev/null +++ b/src/test-issue.spec.ts @@ -0,0 +1,97 @@ +import { + async, + ComponentFixture, + inject, + TestBed +} from '@angular/core/testing'; + +describe('test issue', () => { + it('should test 1', () => { + expect(true).toBe(true); + }); + + it('should test 2', () => { + expect(true).toBe(true); + }); + + it('should test 3', () => { + expect(true).toBe(true); + }); + + it('should test 4', () => { + expect(true).toBe(true); + }); + + it('should test 5', () => { + expect(true).toBe(true); + }); + + it('should test 6', () => { + expect(true).toBe(true); + }); + + it('should test 7', () => { + expect(true).toBe(true); + }); + + it('should test 8', () => { + expect(true).toBe(true); + }); + + it('should test 9', () => { + expect(true).toBe(true); + }); + + it('should test 10', () => { + expect(true).toBe(true); + }); + + it('should test 11', () => { + expect(true).toBe(true); + }); + + it('should test 12', () => { + expect(true).toBe(true); + }); + + it('should test 13', () => { + expect(true).toBe(true); + }); + + it('should test 14', () => { + expect(true).toBe(true); + }); + + it('should test 15', () => { + expect(true).toBe(true); + }); + + it('should test 16', () => { + expect(true).toBe(true); + }); + + it('should test 17', () => { + expect(true).toBe(true); + }); + + it('should test 18', () => { + expect(true).toBe(true); + }); + + it('should test 19', () => { + expect(true).toBe(true); + }); + + it('should test 20', () => { + expect(true).toBe(true); + }); + + it('should test 21', () => { + expect(true).toBe(true); + }); + + it('should test 22', () => { + expect(true).toBe(true); + }); + +}); From 3766a4ba85a798f97bc2aa5bfbc74c1732199e90 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 13 Jan 2017 18:39:24 +0100 Subject: [PATCH 26/33] test issue --- src/app/app.component.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 64e45e9bfb..f457d141e5 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -14,7 +14,6 @@ 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'; @@ -26,9 +25,9 @@ let fixture: ComponentFixture; let de: DebugElement; let el: HTMLElement; - describe('App component', () => { + // async beforeEach beforeEach(async(() => { return TestBed.configureTestingModule({ imports: [ CommonModule, TranslateModule.forRoot(), NgbCollapseModule.forRoot()], From bd29e4ad6516369832ed50a0989db9365a6a4246 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Mon, 16 Jan 2017 17:13:45 +0100 Subject: [PATCH 27/33] Delete test-issue.spec.ts --- src/test-issue.spec.ts | 97 ------------------------------------------ 1 file changed, 97 deletions(-) delete mode 100644 src/test-issue.spec.ts diff --git a/src/test-issue.spec.ts b/src/test-issue.spec.ts deleted file mode 100644 index 434b928e29..0000000000 --- a/src/test-issue.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - async, - ComponentFixture, - inject, - TestBed -} from '@angular/core/testing'; - -describe('test issue', () => { - it('should test 1', () => { - expect(true).toBe(true); - }); - - it('should test 2', () => { - expect(true).toBe(true); - }); - - it('should test 3', () => { - expect(true).toBe(true); - }); - - it('should test 4', () => { - expect(true).toBe(true); - }); - - it('should test 5', () => { - expect(true).toBe(true); - }); - - it('should test 6', () => { - expect(true).toBe(true); - }); - - it('should test 7', () => { - expect(true).toBe(true); - }); - - it('should test 8', () => { - expect(true).toBe(true); - }); - - it('should test 9', () => { - expect(true).toBe(true); - }); - - it('should test 10', () => { - expect(true).toBe(true); - }); - - it('should test 11', () => { - expect(true).toBe(true); - }); - - it('should test 12', () => { - expect(true).toBe(true); - }); - - it('should test 13', () => { - expect(true).toBe(true); - }); - - it('should test 14', () => { - expect(true).toBe(true); - }); - - it('should test 15', () => { - expect(true).toBe(true); - }); - - it('should test 16', () => { - expect(true).toBe(true); - }); - - it('should test 17', () => { - expect(true).toBe(true); - }); - - it('should test 18', () => { - expect(true).toBe(true); - }); - - it('should test 19', () => { - expect(true).toBe(true); - }); - - it('should test 20', () => { - expect(true).toBe(true); - }); - - it('should test 21', () => { - expect(true).toBe(true); - }); - - it('should test 22', () => { - expect(true).toBe(true); - }); - -}); From 37c9b106f2a906e3baeb3b6c0d39bb3920c00cad Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Tue, 17 Jan 2017 11:01:21 +0100 Subject: [PATCH 28/33] removed global dependency on postcss-cli --- package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3643ba7fc2..5e7e4d4c4a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "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:coverage && npm run clean:node", "sass": "node-sass src -o src --include-path node_modules --output-style compressed -q", - "postcss": "postcss -c postcss.config.json", + "postcss": "node_modules/postcss-cli/bin/postcss -c postcss.config.json", "style": "npm run sass && npm run postcss", "style:watch": "nodemon -e scss -w src -x \"npm run style\"", "rollup": "rollup -c rollup-server.js && rollup -c rollup-client.js", @@ -52,7 +52,7 @@ "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 postcss-cli", + "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", @@ -116,10 +116,10 @@ "@types/node": "6.0.52", "@types/serve-static": "1.7.31", "@types/webfontloader": "1.6.27", - "angular2-template-loader": "0.6.0", - "autoprefixer": "6.5.4", "ajv": "4.2.0", "ajv-keywords": "1.1.1", + "angular2-template-loader": "0.6.0", + "autoprefixer": "6.5.4", "awesome-typescript-loader": "2.2.4", "codelyzer": "2.0.0-beta.3", "concurrently": "3.1.0", @@ -145,6 +145,7 @@ "karma-webpack": "1.8.0", "node-sass": "4.0.0", "nodemon": "1.11.0", + "postcss-cli": "^2.6.0", "protractor": "~4.0.14", "protractor-istanbul-plugin": "~2.0.0", "raw-loader": "0.5.1", From 562f09a36656ad69e5e913309d995ea5ac02b4cc Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Tue, 17 Jan 2017 12:06:32 +0100 Subject: [PATCH 29/33] turned null actions in to classes --- src/app/header/header.reducer.spec.ts | 23 ++++++++++++++-------- src/app/shared/host-window.reducer.spec.ts | 18 ++++++++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/app/header/header.reducer.spec.ts b/src/app/header/header.reducer.spec.ts index a3f9f50021..2b8c26f523 100644 --- a/src/app/header/header.reducer.spec.ts +++ b/src/app/header/header.reducer.spec.ts @@ -7,19 +7,26 @@ import { HeaderToggleAction } from "./header.actions"; -describe("headerReducer", () => { - let nullAction = new HeaderCollapseAction(); - nullAction.type = null; +class NullAction extends HeaderCollapseAction { + type = null; + constructor() { + super(); + } +} + +describe("headerReducer", () => { it("should return the current state when no valid actions have been made", () => { const state = { navCollapsed: false }; - const newState = headerReducer(state, nullAction); + const action = new NullAction(); + const newState = headerReducer(state, action); expect(newState).toEqual(state); }); it("should start with navCollapsed = true", () => { - const initialState = headerReducer(undefined, nullAction); + const action = new NullAction(); + const initialState = headerReducer(undefined, action); // The navigation starts collapsed expect(initialState.navCollapsed).toEqual(true); @@ -33,7 +40,7 @@ describe("headerReducer", () => { expect(newState.navCollapsed).toEqual(true); }); - it("should perform the COLLAPSE action without mutating the previous state", () => { + it("should perform the COLLAPSE action without affecting the previous state", () => { const state = { navCollapsed: false }; deepFreeze(state); @@ -52,7 +59,7 @@ describe("headerReducer", () => { expect(newState.navCollapsed).toEqual(false); }); - it("should perform the EXPAND action without mutating the previous state", () => { + it("should perform the EXPAND action without affecting the previous state", () => { const state = { navCollapsed: true }; deepFreeze(state); @@ -71,7 +78,7 @@ describe("headerReducer", () => { expect(state3.navCollapsed).toEqual(true); }); - it("should perform the TOGGLE action without mutating the previous state", () => { + it("should perform the TOGGLE action without affecting the previous state", () => { const state = { navCollapsed: true }; deepFreeze(state); diff --git a/src/app/shared/host-window.reducer.spec.ts b/src/app/shared/host-window.reducer.spec.ts index d0c2e697c0..19d4f67697 100644 --- a/src/app/shared/host-window.reducer.spec.ts +++ b/src/app/shared/host-window.reducer.spec.ts @@ -2,19 +2,27 @@ import * as deepFreeze from "deep-freeze"; import { hostWindowReducer } from "./host-window.reducer"; import { HostWindowResizeAction } from "./host-window.actions"; +class NullAction extends HostWindowResizeAction { + type = null; + + constructor() { + super(0,0); + } +} + describe('hostWindowReducer', () => { - let nullAction = new HostWindowResizeAction(0, 0); - nullAction.type = null; it("should return the current state when no valid actions have been made", () => { const state = { width: 800, height: 600 }; - const newState = hostWindowReducer(state, nullAction); + const action = new NullAction(); + const newState = hostWindowReducer(state, action); expect(newState).toEqual(state); }); it("should start with width = null and height = null", () => { - const initialState = hostWindowReducer(undefined, nullAction); + const action = new NullAction(); + const initialState = hostWindowReducer(undefined, action); expect(initialState.width).toEqual(null); expect(initialState.height).toEqual(null); @@ -29,7 +37,7 @@ describe('hostWindowReducer', () => { expect(newState.height).toEqual(768); }); - it("should perform the RESIZE action without mutating the previous state", () => { + it("should perform the RESIZE action without affecting the previous state", () => { const state = { width: 800, height: 600 }; deepFreeze(state); From 7947451dd400f9e7d59136a38d6387c19c49285c Mon Sep 17 00:00:00 2001 From: William Welling Date: Tue, 17 Jan 2017 07:58:26 -0600 Subject: [PATCH 30/33] Corrected typo for test command --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2d3d1b602e..8ff0bdfd6e 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ 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` +`npm 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: @@ -192,7 +192,7 @@ dspace-angular ## 3rd Party Library Installation -Install your library via `npm install lib-name --save` and import it in your code. `--save` will add it to `package.json`. +Install your library via `npm install lib-name --save` and import it in your code. `--save` will add it to `package.json`. If the library does not include typings, you can install them using npm: @@ -228,7 +228,7 @@ import * as _ from 'lodash'; ## Frequently asked questions * Why is my service, aka provider, is not injecting a parameter correctly? - * Please use `@Injectable()` for your service for typescript to correctly attach the metadata + * Please use `@Injectable()` for your service for typescript to correctly attach the metadata * Where do I write my tests? * You can write your tests next to your component files. e.g. for `src/app/home/home.component.ts` call it `src/app/home/home.component.spec.ts` * How do I start the app when I get `EACCES` and `EADDRINUSE` errors? From e1d69e0efdfa4b3b4fd20edc479f3ee9e98e5c10 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Tue, 17 Jan 2017 18:50:07 +0100 Subject: [PATCH 31/33] header component tests --- src/app/app.component.ts | 2 +- src/app/header/header.component.spec.ts | 82 +++++++++++++++++++++++++ src/app/header/header.component.ts | 14 +---- 3 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 src/app/header/header.component.spec.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0b861bb75c..be9d1eb76c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -52,7 +52,7 @@ export class AppComponent implements OnDestroy, OnInit { @HostListener('window:resize', ['$event']) private onResize(event): void { this.store.dispatch( - new HostWindowResizeAction(event.target.innerWidth, event.target.innerHeight) + new HostWindowResizeAction(event.target.target.innerWidth, event.target.innerHeight) ); } diff --git a/src/app/header/header.component.spec.ts b/src/app/header/header.component.spec.ts new file mode 100644 index 0000000000..f0edf5e956 --- /dev/null +++ b/src/app/header/header.component.spec.ts @@ -0,0 +1,82 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; +import { HeaderComponent } from "./header.component"; +import { Store, StoreModule } from "@ngrx/store"; +import { HeaderState } from "./header.reducer"; +import Spy = jasmine.Spy; +import { HeaderToggleAction } from "./header.actions"; +import { TranslateModule } from "ng2-translate"; +import { NgbCollapseModule } from "@ng-bootstrap/ng-bootstrap"; +import { Observable } from "rxjs"; + +let comp: HeaderComponent; +let fixture: ComponentFixture; +let store: Store; + +describe('HeaderComponent', () => { + + // async beforeEach + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ StoreModule.provideStore({}), TranslateModule.forRoot(), NgbCollapseModule.forRoot() ], + declarations: [ HeaderComponent ] + }) + .compileComponents(); // compile template and css + })); + + // synchronous beforeEach + beforeEach(() => { + fixture = TestBed.createComponent(HeaderComponent); + + comp = fixture.componentInstance; + + + store = fixture.debugElement.injector.get(Store); + spyOn(store, 'dispatch'); + }); + + describe('when the toggle button is clicked', () => { + + beforeEach(() => { + let navbarToggler = fixture.debugElement.query(By.css('.navbar-toggler')); + navbarToggler.triggerEventHandler('click', null); + }); + + it("should dispatch a HeaderToggleAction", () => { + expect(store.dispatch).toHaveBeenCalledWith(new HeaderToggleAction()); + }); + + }); + + describe("when navCollapsed in the store is true", () => { + let menu: HTMLElement; + + beforeEach(() => { + menu = fixture.debugElement.query(By.css('#collapsingNav')).nativeElement; + spyOn(store, 'select').and.returnValue(Observable.of({ navCollapsed: true })); + fixture.detectChanges(); + }); + + it("should close the menu", () => { + expect(menu.classList).not.toContain('in'); + }); + + }); + + describe("when navCollapsed in the store is false", () => { + let menu: HTMLElement; + + beforeEach(() => { + menu = fixture.debugElement.query(By.css('#collapsingNav')).nativeElement; + spyOn(store, 'select').and.returnValue(Observable.of({ navCollapsed: false })); + fixture.detectChanges(); + }); + + it("should open the menu", () => { + expect(menu.classList).toContain('in'); + }); + + }); + +}); diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index 29cac9cadd..76a9cbe05b 100644 --- a/src/app/header/header.component.ts +++ b/src/app/header/header.component.ts @@ -2,11 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { Store } from "@ngrx/store"; import { HeaderState } from "./header.reducer"; import { Observable } from "rxjs"; -import { - HeaderCollapseAction, - HeaderExpandAction, - HeaderToggleAction -} from "./header.actions"; +import { HeaderToggleAction } from "./header.actions"; @Component({ selector: 'ds-header', @@ -27,14 +23,6 @@ export class HeaderComponent implements OnInit { .map(({ navCollapsed }: HeaderState) => navCollapsed); } - private collapse(): void { - this.store.dispatch(new HeaderCollapseAction()); - } - - private expand(): void { - this.store.dispatch(new HeaderExpandAction()); - } - public toggle(): void { this.store.dispatch(new HeaderToggleAction()); } From 58b4b381e71a7f3d6fbd42ded597faf83d65204f Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 18 Jan 2017 11:27:39 +0100 Subject: [PATCH 32/33] added test for window resize to app.component.spec.ts --- src/app/app.component.spec.ts | 38 ++++++++++++++++++------- src/app/app.component.ts | 2 +- src/app/header/header.component.spec.ts | 1 - 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index f457d141e5..9db1e49c47 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -11,14 +11,14 @@ import { } from "@angular/core"; import { By } from '@angular/platform-browser'; import { TranslateModule } from "ng2-translate"; -import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; -import { Store } from "@ngrx/store"; +import { Store, StoreModule } 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'; +import { HostWindowState } from "./shared/host-window.reducer"; +import { HostWindowResizeAction } from "./shared/host-window.actions"; let comp: AppComponent; let fixture: ComponentFixture; @@ -30,14 +30,10 @@ describe('App component', () => { // async beforeEach beforeEach(async(() => { return TestBed.configureTestingModule({ - imports: [ CommonModule, TranslateModule.forRoot(), NgbCollapseModule.forRoot()], - declarations: [ AppComponent, HeaderComponent ], // declare the test component + imports: [ CommonModule, StoreModule.provideStore({}), TranslateModule.forRoot() ], + declarations: [ AppComponent ], // declare the test component providers: [ - AppComponent, - { - provide: Store, - useClass: class { dispatch = jasmine.createSpy('dispatch') } - } + AppComponent ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }) @@ -47,7 +43,7 @@ describe('App component', () => { beforeEach(() => { fixture = TestBed.createComponent(AppComponent); - comp = fixture.componentInstance; // BannerComponent test instance + comp = fixture.componentInstance; // component test instance // query for the title

by CSS element selector de = fixture.debugElement.query(By.css('p')); @@ -58,4 +54,24 @@ describe('App component', () => { // Perform test using fixture and service expect(app).toBeTruthy(); })); + + describe("when the window is resized", () => { + let width: number; + let height: number; + let store: Store; + + beforeEach(() => { + store = fixture.debugElement.injector.get(Store); + spyOn(store, 'dispatch'); + + window.dispatchEvent(new Event('resize')); + width = window.innerWidth; + height = window.innerHeight; + }); + + it("should dispatch a HostWindowResizeAction with the width and height of the window as its payload", () => { + expect(store.dispatch).toHaveBeenCalledWith(new HostWindowResizeAction(width, height)); + }); + + }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index be9d1eb76c..0b861bb75c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -52,7 +52,7 @@ export class AppComponent implements OnDestroy, OnInit { @HostListener('window:resize', ['$event']) private onResize(event): void { this.store.dispatch( - new HostWindowResizeAction(event.target.target.innerWidth, event.target.innerHeight) + new HostWindowResizeAction(event.target.innerWidth, event.target.innerHeight) ); } diff --git a/src/app/header/header.component.spec.ts b/src/app/header/header.component.spec.ts index f0edf5e956..ab0e591bc9 100644 --- a/src/app/header/header.component.spec.ts +++ b/src/app/header/header.component.spec.ts @@ -1,6 +1,5 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; import { HeaderComponent } from "./header.component"; import { Store, StoreModule } from "@ngrx/store"; import { HeaderState } from "./header.reducer"; From 8fd1c6de5c75e95077625b7ce65f43f3b285da0c Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 18 Jan 2017 12:53:09 +0100 Subject: [PATCH 33/33] added a MockTranslateLoader to fix 404 with ng2-translate during testing --- src/app/app.component.spec.ts | 18 +++++++++++------- .../shared/testing/mock-translate-loader.ts | 8 ++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 src/app/shared/testing/mock-translate-loader.ts diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 9db1e49c47..2664b5f27b 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -10,7 +10,7 @@ import { DebugElement } from "@angular/core"; import { By } from '@angular/platform-browser'; -import { TranslateModule } from "ng2-translate"; +import { TranslateModule, TranslateLoader } from "ng2-translate"; import { Store, StoreModule } from "@ngrx/store"; // Load the implementations that should be tested @@ -19,23 +19,27 @@ import { AppComponent } from './app.component'; import { CommonModule } from '@angular/common'; import { HostWindowState } from "./shared/host-window.reducer"; import { HostWindowResizeAction } from "./shared/host-window.actions"; +import { MockTranslateLoader } from "./shared/testing/mock-translate-loader"; -let comp: AppComponent; +let comp: AppComponent; let fixture: ComponentFixture; -let de: DebugElement; -let el: HTMLElement; +let de: DebugElement; +let el: HTMLElement; describe('App component', () => { // async beforeEach beforeEach(async(() => { return TestBed.configureTestingModule({ - imports: [ CommonModule, StoreModule.provideStore({}), TranslateModule.forRoot() ], - declarations: [ AppComponent ], // declare the test component + imports: [CommonModule, StoreModule.provideStore({}), TranslateModule.forRoot({ + provide: TranslateLoader, + useClass: MockTranslateLoader + })], + declarations: [AppComponent], // declare the test component providers: [ AppComponent ], - schemas: [ CUSTOM_ELEMENTS_SCHEMA ] + schemas: [CUSTOM_ELEMENTS_SCHEMA] }) })); diff --git a/src/app/shared/testing/mock-translate-loader.ts b/src/app/shared/testing/mock-translate-loader.ts new file mode 100644 index 0000000000..a780766b25 --- /dev/null +++ b/src/app/shared/testing/mock-translate-loader.ts @@ -0,0 +1,8 @@ +import { TranslateLoader } from "ng2-translate"; +import { Observable } from "rxjs"; + +export class MockTranslateLoader implements TranslateLoader { + getTranslation(lang: string): Observable { + return Observable.of({}); + } +}