diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | pom.xml | 7 | ||||
-rw-r--r-- | server/sonar-web/Gruntfile.coffee | 175 | ||||
-rw-r--r-- | server/sonar-web/package.json | 14 | ||||
-rw-r--r-- | server/sonar-web/pom.xml | 21 | ||||
-rw-r--r-- | server/sonar-web/test/intern.js | 30 | ||||
-rw-r--r-- | server/sonar-web/test/medium/base.html | 72 | ||||
-rw-r--r-- | server/sonar-web/test/medium/users.spec.js | 104 | ||||
-rw-r--r-- | server/sonar-web/test/unit/application.spec.js | 53 | ||||
-rwxr-xr-x | travis.sh | 15 |
10 files changed, 298 insertions, 194 deletions
diff --git a/.travis.yml b/.travis.yml index c87e65797c9..18c2d3d190e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ env: - JOB=H2 - JOB=POSTGRES - JOB=MYSQL + - JOB=WEB - JOB=PRANALYSIS script: @@ -77,8 +77,6 @@ <skipBatchTests>false</skipBatchTests> <skipServerTests>false</skipServerTests> - <skipWebTests>false</skipWebTests> - <jsCoverage>nocoverage</jsCoverage> <version.maven-license.plugin>1.9.0</version.maven-license.plugin> <skipSanityChecks>false</skipSanityChecks> @@ -1507,7 +1505,6 @@ </property> </activation> <properties> - <skipWebTests>true</skipWebTests> <skipBatchTests>true</skipBatchTests> <skipServerTests>true</skipServerTests> </properties> @@ -1517,7 +1514,6 @@ <id>batch</id> <properties> <skipServerTests>true</skipServerTests> - <skipWebTests>true</skipWebTests> </properties> </profile> @@ -1525,7 +1521,6 @@ <id>server</id> <properties> <skipBatchTests>true</skipBatchTests> - <skipWebTests>true</skipWebTests> </properties> </profile> @@ -1548,7 +1543,6 @@ </property> </activation> <properties> - <skipWebTests>true</skipWebTests> <junitGroups>org.sonar.test.DbTests</junitGroups> </properties> <dependencies> @@ -1609,7 +1603,6 @@ <profile> <id>analysis</id> <properties> - <jsCoverage>coverage</jsCoverage> <coveragePerTest>true</coveragePerTest> </properties> </profile> diff --git a/server/sonar-web/Gruntfile.coffee b/server/sonar-web/Gruntfile.coffee index a8cf7b6767f..18a37e1349b 100644 --- a/server/sonar-web/Gruntfile.coffee +++ b/server/sonar-web/Gruntfile.coffee @@ -1,12 +1,13 @@ module.exports = (grunt) -> require('jit-grunt')(grunt, { - express: 'grunt-express-server' unzip: 'grunt-zip' replace: 'grunt-text-replace' }); require('time-grunt')(grunt); + useBrowserStack = !!process.env['BROWSERSTACK_USERNAME'] && !!process.env['BROWSERSTACK_ACCESS_KEY'] expressPort = '<%= grunt.option("port") || 3000 %>' + internPort = '<%= grunt.option("internPort") || 9100 %>' grunt.initConfig pkg: grunt.file.readJSON('package.json') @@ -143,32 +144,6 @@ module.exports = (grunt) -> 'requirejs:issuesContext' 'requirejs:selectList' ] - casper: - tasks: [ - 'casper:apiDocumentation' - 'casper:application' - 'casper:codingRules' - 'casper:issueFilterWidget' - 'casper:handlebarsHelpers' - 'casper:issues' - 'casper:markdown' - 'casper:nav' - 'casper:process' - 'casper:qualityGates' - 'casper:qualityProfiles' - 'casper:sourceViewer' - 'casper:treemap' - 'casper:ui' - 'casper:workspace' - 'casper:users' - 'casper:groups' - 'casper:provisioning' - 'casper:computation' - 'casper:metrics' - 'casper:maintenance' - 'casper:updateCenter' - 'casper:histogram' - ] handlebars: @@ -267,125 +242,37 @@ module.exports = (grunt) -> src: '<%= BUILD_PATH %>/css/sonar.css', dest: '<%= ASSETS_PATH %>/css/sonar.css' - express: - test: - options: - script: 'src/test/server.js' - port: expressPort - testCoverage: - options: - script: 'src/test/server-coverage.js' - port: expressPort - dev: - options: - background: false - script: 'src/test/server.js' - - - casper: - options: - test: true - 'fail-fast': true - concise: true - 'no-colors': true - port: expressPort - testCoverageLight: - options: - concise: false - verbose: true - 'no-colors': false - src: ['src/test/js/**/*<%= grunt.option("spec") %>*.js'] - single: - options: - concise: false - verbose: true - 'no-colors': false - src: ['src/test/js/<%= grunt.option("spec") %>-spec.js'] - testfile: - options: - concise: false - verbose: true - 'no-colors': false - src: ['<%= grunt.option("file") %>'] - - apiDocumentation: - src: ['src/test/js/api-documentation*.js'] - application: - src: ['src/test/js/application*.js'] - codingRules: - src: ['src/test/js/coding-rules*.js'] - issueFilterWidget: - src: ['src/test/js/*issue-filter-widget*.js'] - handlebarsHelpers: - src: ['src/test/js/handlebars-helpers*.js'] - issues: - src: ['src/test/js/issues*.js'] - markdown: - src: ['src/test/js/markdown*.js'] - nav: - src: ['src/test/js/nav*.js'] - process: - src: ['src/test/js/process*.js'] - qualityGates: - src: ['src/test/js/quality-gates*.js'] - qualityProfiles: - src: ['src/test/js/quality-profiles*.js'] - sourceViewer: - src: ['src/test/js/source-viewer*.js'] - treemap: - src: ['src/test/js/treemap*.js'] - ui: - src: ['src/test/js/ui*.js'] - workspace: - src: ['src/test/js/workspace*.js'] - users: - src: ['src/test/js/users*.js'] - provisioning: - src: ['src/test/js/provisioning*.js'] - computation: - src: ['src/test/js/computation*.js'] - groups: - src: ['src/test/js/groups-spec.js'] - metrics: - src: ['src/test/js/metrics-spec.js'] - maintenance: - src: ['src/test/js/maintenance-spec.js'] - updateCenter: - src: ['src/test/js/update-center-spec.js'] - histogram: - src: ['src/test/js/histogram-spec.js'] - uglify: build: src: '<%= ASSETS_PATH %>/js/sonar.js' dest: '<%= ASSETS_PATH %>/js/sonar.js' - curl: - resetCoverage: - src: - url: 'http://localhost:' + expressPort + '/coverage/reset' - method: 'POST' - dest: 'target/reset_coverage.dump' - - downloadCoverage: - src: 'http://localhost:' + expressPort + '/coverage/download' - dest: 'target/coverage.zip' - - - unzip: - 'target/js-coverage': 'target/coverage.zip' - - replace: lcov: - src: 'target/js-coverage/lcov.info' - dest: 'target/js-coverage/lcov.info' + src: 'target/web-tests/lcov.info' + dest: 'target/web-tests/lcov.info' replacements: [ { from: '/build/', to: '/src/main/' } ] + rename: + lcov: + src: 'lcov.info' + dest: 'target/web-tests/lcov.info' + + + intern: + test: + options: + runType: 'runner' + config: 'test/intern' + proxyPort: expressPort + proxyUrl: 'http://localhost:' + expressPort + '/' + useBrowserStack: useBrowserStack + + jshint: dev: src: [ @@ -427,11 +314,10 @@ module.exports = (grunt) -> ['copy:assets-css', 'copy:assets-js', 'concurrent:build'] grunt.registerTask 'test-suffix', - ['express:test', 'concurrent:casper'] + ['intern:test', 'rename:lcov', 'replace:lcov'] grunt.registerTask 'coverage-suffix', - ['express:testCoverage', 'curl:resetCoverage', 'concurrent:casper', 'curl:downloadCoverage', 'unzip', - 'replace:lcov'] + ['test-suffix'] grunt.registerTask 'build-app', (app) -> grunt.option 'app', app @@ -467,24 +353,9 @@ module.exports = (grunt) -> grunt.registerTask 'dw', ['build-fast', 'watch'] - grunt.registerTask 'testCoverageLight', - ['prepare', 'express:testCoverage', 'curl:resetCoverage', 'casper:testCoverageLight', 'curl:downloadCoverage', 'unzip', 'replace:lcov'] - - grunt.registerTask 'single', - ['prepare', 'express:test', 'casper:single'] - - grunt.registerTask 'testfile', - ['prepare', 'express:test', 'casper:testfile'] - # tasks used by Maven build (see pom.xml) grunt.registerTask 'maven-quick-build', ['build-fast'] - grunt.registerTask 'maven-build-skip-tests-true-nocoverage', + grunt.registerTask 'maven-build', ['build'] - - grunt.registerTask 'maven-build-skip-tests-false-nocoverage', - ['build-test'] - - grunt.registerTask 'maven-build-skip-tests-false-coverage', - ['build-coverage'] diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index 3c0531b99ac..f82f544b835 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -2,12 +2,7 @@ "name": "SonarQube", "version": "0.0.1", "devDependencies": { - "body-parser": "1.13.0", - "casperjs": "1.1.0-beta3", - "errorhandler": "1.1.1", - "express": "4.8.0", "grunt": "0.4.5", - "grunt-casper": "0.3.9", "grunt-cli": "0.1.13", "grunt-concurrent": "1.0.0", "grunt-contrib-clean": "0.6.0", @@ -18,15 +13,10 @@ "grunt-contrib-requirejs": "0.4.4", "grunt-contrib-uglify": "0.9.1", "grunt-contrib-watch": "0.6.1", - "grunt-curl": "2.1.0", - "grunt-express-server": "0.4.17", + "grunt-rename": "^0.1.4", "grunt-text-replace": "0.4.0", - "grunt-zip": "0.16.2", - "istanbul": "0.3.5", - "istanbul-middleware": "0.2.0", - "jade": "1.4.2", + "intern": "^3.0.0-rc.1", "jit-grunt": "0.9.1", - "serve-static": "1.5.0", "time-grunt": "1.2.1" }, "scripts": { diff --git a/server/sonar-web/pom.xml b/server/sonar-web/pom.xml index 5203f26cf38..42892b74a81 100644 --- a/server/sonar-web/pom.xml +++ b/server/sonar-web/pom.xml @@ -15,8 +15,7 @@ <!-- self-analysis --> <sonar.sources>src/main/js,src/main/less</sonar.sources> <sonar.exclusions>src/main/js/libs/third-party/**/*,src/main/js/libs/require.js</sonar.exclusions> - <sonar.javascript.lcov.reportPath>target/js-coverage/lcov.info</sonar.javascript.lcov.reportPath> - <grunt.arguments>maven-build-skip-tests-${skipWebTests}-${jsCoverage} --port=${jsTestPort} --no-color</grunt.arguments> + <grunt.arguments>maven-build --no-color</grunt.arguments> </properties> <build> @@ -84,24 +83,6 @@ </executions> </plugin> <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <id>reserve-network-port</id> - <goals> - <goal>reserve-network-port</goal> - </goals> - <phase>initialize</phase> - <configuration> - <portNames> - <portName>jsTestPort</portName> - </portNames> - </configuration> - </execution> - </executions> - </plugin> - <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <executions> diff --git a/server/sonar-web/test/intern.js b/server/sonar-web/test/intern.js new file mode 100644 index 00000000000..984906c4ea9 --- /dev/null +++ b/server/sonar-web/test/intern.js @@ -0,0 +1,30 @@ +/* jshint node:true */ +define(['intern'], function (intern) { + var useBrowserStack = intern.args.useBrowserStack, + tunnel = useBrowserStack ? 'BrowserStackTunnel' : 'NullTunnel'; + + return { + excludeInstrumentation: /(test|third-party|node_modules)\//, + + defaultTimeout: 60 * 1000, + + reporters: [ + { id: 'Runner' }, + { id: 'Lcov' }, + { id: 'LcovHtml', directory: 'target/web-tests' } + ], + + suites: [ + 'test/unit/application.spec' + ], + + functionalSuites: [ + 'test/medium/users.spec' + ], + + tunnel: tunnel, + environments: [ + { browserName: 'firefox' } + ] + }; +}); diff --git a/server/sonar-web/test/medium/base.html b/server/sonar-web/test/medium/base.html new file mode 100644 index 00000000000..09060d02b4a --- /dev/null +++ b/server/sonar-web/test/medium/base.html @@ -0,0 +1,72 @@ +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <link href="../../build/css/sonar.css" rel="stylesheet" media="all"> + <script src="../../build/js/libs/translate.js"></script> + <script src="../../build/js/libs/third-party/jquery.js"></script> + <script src="../../build/js/libs/third-party/jquery-ui.js"></script> + <script src="../../build/js/libs/third-party/d3.js"></script> + <script src="../../build/js/libs/third-party/latinize.js"></script> + <script src="../../build/js/libs/third-party/underscore.js"></script> + <script src="../../build/js/libs/third-party/backbone.js"></script> + <script src="../../build/js/libs/third-party/backbone-super.js"></script> + <script src="../../build/js/libs/third-party/backbone.marionette.js"></script> + <script src="../../build/js/libs/third-party/handlebars.js"></script> + <script src="../../build/js/libs/third-party/select2.js"></script> + <script src="../../build/js/libs/third-party/keymaster.js"></script> + <script src="../../build/js/libs/third-party/moment.js"></script> + <script src="../../build/js/libs/third-party/numeral.js"></script> + <script src="../../build/js/libs/third-party/numeral-languages.js"></script> + <script src="../../build/js/libs/third-party/bootstrap/tooltip.js"></script> + <script src="../../build/js/libs/third-party/bootstrap/dropdown.js"></script> + <script src="../../build/js/libs/third-party/md5.js"></script> + <script src="../../build/js/libs/select2-jquery-ui-fix.js"></script> + <script src="../../build/js/libs/widgets/base.js"></script> + <script src="../../build/js/libs/widgets/widget.js"></script> + <script src="../../build/js/libs/widgets/bubble-chart.js"></script> + <script src="../../build/js/libs/widgets/timeline.js"></script> + <script src="../../build/js/libs/widgets/stack-area.js"></script> + <script src="../../build/js/libs/widgets/pie-chart.js"></script> + <script src="../../build/js/libs/widgets/histogram.js"></script> + <script src="../../build/js/libs/widgets/word-cloud.js"></script> + <script src="../../build/js/libs/widgets/tag-cloud.js"></script> + <script src="../../build/js/libs/widgets/treemap.js"></script> + <script src="../../build/js/libs/graphics/pie-chart.js"></script> + <script src="../../build/js/libs/graphics/barchart.js"></script> + <script src="../../build/js/libs/sortable.js"></script> + <script src="../../build/js/libs/inputs.js"></script> + <script src="../../build/js/components/common/dialogs.js"></script> + <script src="../../build/js/components/common/processes.js"></script> + <script src="../../build/js/components/common/jquery-isolated-scroll.js"></script> + <script src="../../build/js/components/common/handlebars-extensions.js"></script> + <script src="../../build/js/libs/application.js"></script> + <script src="../../build/js/libs/csv.js"></script> + <script src="../../build/js/libs/dashboard.js"></script> + <script src="../../build/js/libs/recent-history.js"></script> + <script src="../../build/js/libs/third-party/require.js"></script> + <script src="../../build/js/libs/third-party/jquery.mockjax.js"></script> + <script>var baseUrl = ''; + var $j = jQuery.noConflict(); + window.suppressTranslationWarnings = true; + jQuery.mockjaxSettings.contentType = 'text/json'; + jQuery.mockjaxSettings.responseTime = 50; + jQuery(document).ready(function () { + $j('.open-modal').modal(); + }); + window.SS = { + hoursInDay: 8, + user: '', + userName: '', + userEmail: '', + lf: { + enableGravatar: false, + gravatarServerUrl: '' + } + }; + </script> + <script>requirejs.config({ baseUrl: baseUrl + '../../build/js' });</script> +</head> +<body> +<div id="content"></div> +</body> +</html> diff --git a/server/sonar-web/test/medium/users.spec.js b/server/sonar-web/test/medium/users.spec.js new file mode 100644 index 00000000000..5337eb3a52d --- /dev/null +++ b/server/sonar-web/test/medium/users.spec.js @@ -0,0 +1,104 @@ +define(function (require) { + var intern = require('intern'); + var bdd = require('intern!bdd'); + var assert = require('intern/chai!assert'); + var fs = require('intern/dojo/node!fs'); + + bdd.describe('Users Page', function () { + + bdd.it('should show list of users', function () { + var searchResponse = fs.readFileSync('src/test/json/users-spec/search.json', 'utf-8'); + + return this.remote + .get(require.toUrl('test/medium/base.html')) + .setFindTimeout(5000) + .findByCssSelector('#content') + .execute(function () { + return jQuery.mockjax(_.extend({ url: '/api/l10n/index', responseText: {} })); + }) + .execute(function (searchResponse) { + return jQuery.mockjax(_.extend({ url: '/api/users/search', responseText: searchResponse })); + }, [searchResponse]) + .execute(function () { + require(['apps/users/app'], function (App) { + App.start({ el: '#content' }); + }); + }) + .findByCssSelector('#users-list ul') + .findAllByCssSelector('#users-list li[data-login]') + .then(function (elements) { + assert.equal(3, elements.length); + }) + .end() + .findAllByCssSelector('#users-list .js-user-login') + .getVisibleText() + .then(function (text) { + assert.include(text, 'smith'); + }) + .end() + .findAllByCssSelector('#users-list .js-user-name') + .getVisibleText() + .then(function (text) { + assert.include(text, 'Bob'); + }) + .end() + .findAllByCssSelector('#users-list .js-user-email') + .getVisibleText() + .then(function (text) { + assert.include(text, 'bob@example.com'); + }) + .end() + .findAllByCssSelector('#users-list .js-user-update') + .then(function (elements) { + assert.equal(3, elements.length); + }) + .end() + .findAllByCssSelector('#users-list .js-user-change-password') + .then(function (elements) { + assert.equal(3, elements.length); + }) + .end() + .findAllByCssSelector('#users-list .js-user-deactivate') + .then(function (elements) { + assert.equal(3, elements.length); + }) + .end() + //.findByCssSelector('#users-list-footer') + //.getVisibleText() + //.then(function (text) { + // assert.include(text, '3/3'); + //}) + //.end() + .findByCssSelector('[data-login="ryan"]') + .getVisibleText() + .then(function (text) { + assert.notInclude(text, 'another@example.com'); + }) + .end() + .findByCssSelector('[data-login="ryan"] .js-user-more-scm') + .click() + .end() + .findByCssSelector('[data-login="ryan"]') + .getVisibleText() + .then(function (text) { + assert.include(text, 'another@example.com'); + }) + .end() + .findByCssSelector('[data-login="ryan"]') + .getVisibleText() + .then(function (text) { + assert.notInclude(text, 'four'); + }) + .end() + .findByCssSelector('[data-login="ryan"] .js-user-more-groups') + .click() + .end() + .findByCssSelector('[data-login="ryan"]') + .getVisibleText() + .then(function (text) { + assert.include(text, 'four'); + }); + }); + + }); +}); diff --git a/server/sonar-web/test/unit/application.spec.js b/server/sonar-web/test/unit/application.spec.js new file mode 100644 index 00000000000..3b04548ca98 --- /dev/null +++ b/server/sonar-web/test/unit/application.spec.js @@ -0,0 +1,53 @@ +define(function (require) { + var bdd = require('intern!bdd'); + var assert = require('intern/chai!assert'); + + //require('intern/order!build/js/libs/translate.js'); + require('intern/order!build/js/libs/third-party/jquery.js'); + //require('intern/order!build/js/libs/third-party/jquery-ui.js'); + //require('intern/order!build/js/libs/third-party/d3.js'); + //require('intern/order!build/js/libs/third-party/latinize.js'); + require('intern/order!build/js/libs/third-party/underscore.js'); + //require('intern/order!build/js/libs/third-party/backbone.js'); + //require('intern/order!build/js/libs/third-party/handlebars.js'); + //require('intern/order!build/js/libs/third-party/select2.js'); + require('intern/order!build/js/libs/third-party/keymaster.js'); + //require('intern/order!build/js/libs/third-party/moment.js'); + //require('intern/order!build/js/libs/third-party/numeral.js'); + //require('intern/order!build/js/libs/third-party/numeral-languages.js'); + //require('intern/order!build/js/libs/third-party/bootstrap/tooltip.js'); + //require('intern/order!build/js/libs/third-party/bootstrap/dropdown.js'); + //require('intern/order!build/js/libs/third-party/md5.js'); + //require('intern/order!build/js/libs/select2-jquery-ui-fix.js'); + require('intern/order!build/js/libs/application.js'); + + bdd.describe('Application', function () { + + bdd.describe('#collapsedDirFromPath', function () { + + bdd.it('should return null when pass null', function () { + assert.isNull(window.collapsedDirFromPath(null)); + }); + + bdd.it('should return "/" when pass "/"', function () { + assert.equal(window.collapsedDirFromPath('/'), '/'); + }); + + bdd.it('should not cut short path', function () { + assert.equal(window.collapsedDirFromPath('src/main/js/components/state.js'), 'src/main/js/components/'); + }); + + bdd.it('should cut long path', function () { + assert.equal(window.collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js'), + 'src/.../js/components/navigator/app/models/'); + }); + + bdd.it('should cut very long path', function () { + assert.equal(window.collapsedDirFromPath('src/main/another/js/components/navigator/app/models/state.js'), + 'src/.../js/components/navigator/app/models/'); + }); + + }); + + }); +}); diff --git a/travis.sh b/travis.sh index ee25f626d7a..cb170cb9d77 100755 --- a/travis.sh +++ b/travis.sh @@ -31,8 +31,17 @@ MYSQL) travis_runDatabaseCI "mysql" "jdbc:mysql://localhost/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance" "sonar" "sonar" ;; +WEB) + export DISPLAY=:99.0 + sh -e /etc/init.d/xvfb start + wget http://selenium-release.storage.googleapis.com/2.46/selenium-server-standalone-2.46.0.jar + java -jar selenium-server-standalone-2.46.0.jar & + sleep 3 + cd server/sonar-web && npm install && npm test + ;; + PRANALYSIS) - if [ -n "$SONAR_GITHUB_OAUTH" ] && [ "${TRAVIS_PULL_REQUEST}" != "false" ] + if [ -n "$SONAR_GITHUB_OAUTH" ] && [ "${TRAVIS_PULL_REQUEST}" != "false" ] then echo "Start pullrequest analysis" mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -B -e -V -Dmaven.test.failure.ignore=true -Dclirr=true \ @@ -43,8 +52,8 @@ PRANALYSIS) -Dsonar.github.oauth=$SONAR_GITHUB_OAUTH \ -Dsonar.host.url=$SONAR_HOST_URL \ -Dsonar.login=$SONAR_LOGIN \ - -Dsonar.password=$SONAR_PASSWD - fi + -Dsonar.password=$SONAR_PASSWD + fi ;; *) |