diff --git a/package.json b/package.json index 570285e8fb85..47cb62040134 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "karma": "^1.5.0", "karma-browserstack-launcher": "^1.2.0", "karma-chrome-launcher": "^2.0.0", + "karma-coverage": "^1.1.1", "karma-firefox-launcher": "^1.0.1", "karma-jasmine": "^1.1.0", "karma-sauce-launcher": "^1.1.0", diff --git a/scripts/ci/build-and-test.sh b/scripts/ci/build-and-test.sh index 86f60c7d302e..820bb1fe560f 100755 --- a/scripts/ci/build-and-test.sh +++ b/scripts/ci/build-and-test.sh @@ -11,8 +11,8 @@ source scripts/ci/sources/mode.sh source scripts/ci/sources/tunnel.sh start_tunnel - wait_for_tunnel + if is_lint; then $(npm bin)/gulp ci:lint elif is_e2e; then @@ -24,4 +24,10 @@ elif is_payload; then else $(npm bin)/gulp ci:test fi + +# Don't upload coverage for both test modes (browserstack and saucelabs) and inside of PRs. +if [[ "$MODE" == "saucelabs_required" ]] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then + $(npm bin)/gulp ci:coverage +fi + teardown_tunnel diff --git a/test/karma.conf.js b/test/karma.conf.js index 362ffeae2e77..49c1f7038ac0 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -12,7 +12,8 @@ module.exports = (config) => { require('karma-sauce-launcher'), require('karma-chrome-launcher'), require('karma-firefox-launcher'), - require('karma-sourcemap-loader') + require('karma-sourcemap-loader'), + require('karma-coverage') ], files: [ {pattern: 'dist/vendor/core-js/client/core.js', included: true, watched: false}, @@ -50,16 +51,23 @@ module.exports = (config) => { customLaunchers: customLaunchers, - exclude: [], preprocessors: { - '**/*.js': ['sourcemap'] + 'dist/@angular/material/**/*.js': ['sourcemap'] }, + reporters: ['dots'], + port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: false, + coverageReporter: { + type : 'json-summary', + dir : 'dist/coverage/', + subdir: '.' + }, + sauceLabs: { testName: 'material2', startConnect: false, @@ -92,6 +100,11 @@ module.exports = (config) => { if (process.env['TRAVIS']) { let buildId = `TRAVIS #${process.env.TRAVIS_BUILD_NUMBER} (${process.env.TRAVIS_BUILD_ID})`; + if (process.env['TRAVIS_PULL_REQUEST'] === 'false') { + config.preprocessors['dist/@angular/material/**/!(*+(.|-)spec).js'] = ['coverage']; + config.reporters.push('coverage'); + } + // The MODE variable is the indicator of what row in the test matrix we're running. // It will look like _, where platform is one of 'saucelabs' or 'browserstack', // and alias is one of the keys in the CI configuration variable declared in diff --git a/tools/gulp/constants.ts b/tools/gulp/constants.ts index b2811415da31..5aaceed5edf3 100644 --- a/tools/gulp/constants.ts +++ b/tools/gulp/constants.ts @@ -8,6 +8,8 @@ export const SOURCE_ROOT = join(PROJECT_ROOT, 'src'); export const DIST_ROOT = join(PROJECT_ROOT, 'dist'); export const DIST_COMPONENTS_ROOT = join(DIST_ROOT, '@angular/material'); +export const COVERAGE_RESULT_FILE = join(DIST_ROOT, 'coverage', 'coverage-summary.json'); + export const SASS_AUTOPREFIXER_OPTIONS = { browsers: [ 'last 2 versions', diff --git a/tools/gulp/gulpfile.ts b/tools/gulp/gulpfile.ts index 540c73aacfcf..7ed02af2f2d6 100644 --- a/tools/gulp/gulpfile.ts +++ b/tools/gulp/gulpfile.ts @@ -13,3 +13,4 @@ import './tasks/unit-test'; import './tasks/docs'; import './tasks/aot'; import './tasks/payload'; +import './tasks/coverage'; diff --git a/tools/gulp/tasks/ci.ts b/tools/gulp/tasks/ci.ts index f1d3f5d26eed..51fc8e7204b7 100644 --- a/tools/gulp/tasks/ci.ts +++ b/tools/gulp/tasks/ci.ts @@ -17,3 +17,6 @@ task('ci:aot', ['aot:build']); /** Task which reports the size of the library and stores it in a database. */ task('ci:payload', ['payload']); + +/** Task that uploads the coverage results to a firebase database. */ +task('ci:coverage', ['coverage:upload']); diff --git a/tools/gulp/tasks/coverage.ts b/tools/gulp/tasks/coverage.ts new file mode 100644 index 000000000000..ea12470bf172 --- /dev/null +++ b/tools/gulp/tasks/coverage.ts @@ -0,0 +1,34 @@ +import {task} from 'gulp'; +import {existsSync} from 'fs-extra'; +import {COVERAGE_RESULT_FILE} from '../constants'; +import {spawnSync} from 'child_process'; +import {isTravisPushBuild, openFirebaseDashboardDatabase} from '../task_helpers'; + +task('coverage:upload', () => { + if (!existsSync(COVERAGE_RESULT_FILE)) { + throw new Error('No coverage file has been found!'); + } + + if (!isTravisPushBuild()) { + throw new Error('Coverage results will be only uploaded inside of Travis Push builds.'); + } + + let results = require(COVERAGE_RESULT_FILE)['total']; + + // To reduce database payload, the covered lines won't be pushed to the Firebase database. + delete results['linesCovered']; + + return uploadResults(results); +}); + +/** Uploads the coverage results to the firebase database. */ +function uploadResults(results: any): Promise { + let latestSha = spawnSync('git', ['rev-parse', 'HEAD']).stdout.toString().trim(); + let database = openFirebaseDashboardDatabase(); + + return database.ref('coverage-reports').child(latestSha).set(results) + .then(() => database.goOffline(), () => database.goOffline()); +} + +// TODO(devversion): In the future we might have a big database where we can store full summaries. +// TODO(devversion): We could also move the coverage to a bot and reply with the results on PRs.