diff options
-rwxr-xr-x[-rw-r--r--] | server/sonar-web/src/main/js/libs/third-party/jquery.mockjax.js | 451 | ||||
-rw-r--r-- | server/sonar-web/test/helpers/test-page.js | 20 | ||||
-rw-r--r-- | server/sonar-web/test/intern.js | 3 | ||||
-rw-r--r-- | server/sonar-web/test/medium/base.html | 2 | ||||
-rw-r--r-- | server/sonar-web/test/medium/coding-rules.spec.js | 924 | ||||
-rw-r--r-- | server/sonar-web/test/medium/computation.spec.js | 2 | ||||
-rwxr-xr-x | travis.sh | 2 |
7 files changed, 1263 insertions, 141 deletions
diff --git a/server/sonar-web/src/main/js/libs/third-party/jquery.mockjax.js b/server/sonar-web/src/main/js/libs/third-party/jquery.mockjax.js index fc6327fd1c1..b935290ff58 100644..100755 --- a/server/sonar-web/src/main/js/libs/third-party/jquery.mockjax.js +++ b/server/sonar-web/src/main/js/libs/third-party/jquery.mockjax.js @@ -1,15 +1,51 @@ -(function($) { +/*! jQuery Mockjax + * A Plugin providing simple and flexible mocking of ajax requests and responses + * + * Version: 2.0.1 + * Home: https://github.com/jakerella/jquery-mockjax + * Copyright (c) 2015 Jordan Kasper, formerly appendTo; + * NOTE: This repository was taken over by Jordan Kasper (@jakerella) October, 2014 + * + * Dual licensed under the MIT or GPL licenses. + * http://opensource.org/licenses/MIT OR http://www.gnu.org/licenses/gpl-2.0.html + */ +(function(root, factory) { + 'use strict'; + + // AMDJS module definition + if ( typeof define === 'function' && define.amd && define.amd.jQuery ) { + define(['jquery'], function($) { + return factory($, root); + }); + + // CommonJS module definition + } else if ( typeof exports === 'object') { + + // NOTE: To use Mockjax as a Node module you MUST provide the factory with + // a valid version of jQuery and a window object (the global scope): + // var mockjax = require('jquery.mockjax')(jQuery, window); + + module.exports = factory; + + // Global jQuery in web browsers + } else { + return factory(root.jQuery || root.$, root); + } +}(this, function($, window) { + 'use strict'; + var _ajax = $.ajax, mockHandlers = [], mockedAjaxCalls = [], + unmockedAjaxCalls = [], CALLBACK_REGEX = /=\?(&|$)/, jsc = (new Date()).getTime(); // Parse the given XML string. function parseXML(xml) { - if ( window.DOMParser == undefined && window.ActiveXObject ) { - DOMParser = function() { }; + if ( window.DOMParser === undefined && window.ActiveXObject ) { + window.DOMParser = function() { }; DOMParser.prototype.parseFromString = function( xmlString ) { var doc = new ActiveXObject('Microsoft.XMLDOM'); doc.async = 'false'; @@ -22,25 +58,20 @@ var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' ); if ( $.isXMLDoc( xmlDoc ) ) { var err = $('parsererror', xmlDoc); - if ( err.length == 1 ) { - throw('Error: ' + $(xmlDoc).text() ); + if ( err.length === 1 ) { + throw new Error('Error: ' + $(xmlDoc).text() ); } } else { - throw('Unable to parse XML'); + throw new Error('Unable to parse XML'); } return xmlDoc; } catch( e ) { - var msg = ( e.name == undefined ? e : e.name + ': ' + e.message ); + var msg = ( e.name === undefined ? e : e.name + ': ' + e.message ); $(document).trigger('xmlParseError', [ msg ]); return undefined; } } - // Trigger a jQuery event - function trigger(s, type, args) { - (s.context ? $(s.context) : $.event).trigger(type, args); - } - // Check if the data field on the mock handler and the request match. This // can be used to restrict a mock handler to being used only when a certain // set of data is passed to it. @@ -49,21 +80,23 @@ // Test for situations where the data is a querystring (not an object) if (typeof live === 'string') { // Querystring may be a regex - return $.isFunction( mock.test ) ? mock.test(live) : mock == live; + return $.isFunction( mock.test ) ? mock.test(live) : mock === live; } $.each(mock, function(k) { if ( live[k] === undefined ) { identical = false; return identical; } else { - // This will allow to compare Arrays if ( typeof live[k] === 'object' && live[k] !== null ) { + if ( identical && $.isArray( live[k] ) ) { + identical = $.isArray( mock[k] ) && live[k].length === mock[k].length; + } identical = identical && isMockDataEqual(mock[k], live[k]); } else { if ( mock[k] && $.isFunction( mock[k].test ) ) { identical = identical && mock[k].test(live[k]); } else { - identical = identical && ( mock[k] == live[k] ); + identical = identical && ( mock[k] === live[k] ); } } } @@ -72,10 +105,10 @@ return identical; } - // See if a mock handler property matches the default settings - function isDefaultSetting(handler, property) { - return handler[property] === $.mockjaxSettings[property]; - } + // See if a mock handler property matches the default settings + function isDefaultSetting(handler, property) { + return handler[property] === $.mockjaxSettings[property]; + } // Check the given handler should mock the given request function getMockForRequest( handler, requestSettings ) { @@ -96,21 +129,42 @@ // Look for a simple wildcard '*' or a direct URL match var star = handler.url.indexOf('*'); if (handler.url !== requestSettings.url && star === -1 || - !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace(/\*/g, '.+')).test(requestSettings.url)) { + !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&').replace(/\*/g, '.+')).test(requestSettings.url)) { return null; } } + // Inspect the request headers submitted + if ( handler.requestHeaders ) { + //No expectation for headers, do not mock this request + if (requestSettings.headers === undefined) { + return null; + } else { + var headersMismatch = false; + $.each(handler.requestHeaders, function(key, value) { + var v = requestSettings.headers[key]; + if(v !== value) { + headersMismatch = true; + return false; + } + }); + //Headers do not match, do not mock this request + if (headersMismatch) { + return null; + } + } + } + // Inspect the data submitted in the request (either POST body or GET query string) - if ( handler.data && requestSettings.data ) { - if ( !isMockDataEqual(handler.data, requestSettings.data) ) { + if ( handler.data ) { + if ( ! requestSettings.data || !isMockDataEqual(handler.data, requestSettings.data) ) { // They're not identical, do not mock this request return null; } } // Inspect the request type if ( handler && handler.type && - handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) { + handler.type.toLowerCase() !== requestSettings.type.toLowerCase() ) { // The request type doesn't match (GET vs. POST) return null; } @@ -118,6 +172,23 @@ return handler; } + function isPosNum(value) { + return typeof value === 'number' && value >= 0; + } + + function parseResponseTimeOpt(responseTime) { + if ($.isArray(responseTime) && responseTime.length === 2) { + var min = responseTime[0]; + var max = responseTime[1]; + if(isPosNum(min) && isPosNum(max)) { + return Math.floor(Math.random() * (max - min)) + min; + } + } else if(isPosNum(responseTime)) { + return responseTime; + } + return DEFAULT_RESPONSE_TIME; + } + // Process the xhr objects send operation function _xhrSend(mockHandler, requestSettings, origSettings) { @@ -125,52 +196,70 @@ var process = (function(that) { return function() { return (function() { - var onReady; - // The request has returned - this.status = mockHandler.status; + this.status = mockHandler.status; this.statusText = mockHandler.statusText; - this.readyState = 4; + this.readyState = 1; + + var finishRequest = function () { + this.readyState = 4; + + var onReady; + // Copy over our mock to our xhr object before passing control back to + // jQuery's onreadystatechange callback + if ( requestSettings.dataType === 'json' && ( typeof mockHandler.responseText === 'object' ) ) { + this.responseText = JSON.stringify(mockHandler.responseText); + } else if ( requestSettings.dataType === 'xml' ) { + if ( typeof mockHandler.responseXML === 'string' ) { + this.responseXML = parseXML(mockHandler.responseXML); + //in jQuery 1.9.1+, responseXML is processed differently and relies on responseText + this.responseText = mockHandler.responseXML; + } else { + this.responseXML = mockHandler.responseXML; + } + } else if (typeof mockHandler.responseText === 'object' && mockHandler.responseText !== null) { + // since jQuery 1.9 responseText type has to match contentType + mockHandler.contentType = 'application/json'; + this.responseText = JSON.stringify(mockHandler.responseText); + } else { + this.responseText = mockHandler.responseText; + } + if( typeof mockHandler.status === 'number' || typeof mockHandler.status === 'string' ) { + this.status = mockHandler.status; + } + if( typeof mockHandler.statusText === 'string') { + this.statusText = mockHandler.statusText; + } + // jQuery 2.0 renamed onreadystatechange to onload + onReady = this.onreadystatechange || this.onload; + + // jQuery < 1.4 doesn't have onreadystate change for xhr + if ( $.isFunction( onReady ) ) { + if( mockHandler.isTimeout) { + this.status = -1; + } + onReady.call( this, mockHandler.isTimeout ? 'timeout' : undefined ); + } else if ( mockHandler.isTimeout ) { + // Fix for 1.3.2 timeout to keep success from firing. + this.status = -1; + } + }; // We have an executable function, call it to give // the mock handler a chance to update it's data if ( $.isFunction(mockHandler.response) ) { - mockHandler.response(origSettings); - } - // Copy over our mock to our xhr object before passing control back to - // jQuery's onreadystatechange callback - if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) { - this.responseText = JSON.stringify(mockHandler.responseText); - } else if ( requestSettings.dataType == 'xml' ) { - if ( typeof mockHandler.responseXML == 'string' ) { - this.responseXML = parseXML(mockHandler.responseXML); - //in jQuery 1.9.1+, responseXML is processed differently and relies on responseText - this.responseText = mockHandler.responseXML; + // Wait for it to finish + if ( mockHandler.response.length === 2 ) { + mockHandler.response(origSettings, function () { + finishRequest.call(that); + }); + return; } else { - this.responseXML = mockHandler.responseXML; + mockHandler.response(origSettings); } - } else { - this.responseText = mockHandler.responseText; - } - if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) { - this.status = mockHandler.status; - } - if( typeof mockHandler.statusText === "string") { - this.statusText = mockHandler.statusText; } - // jQuery 2.0 renamed onreadystatechange to onload - onReady = this.onreadystatechange || this.onload; - // jQuery < 1.4 doesn't have onreadystate change for xhr - if ( $.isFunction( onReady ) ) { - if( mockHandler.isTimeout) { - this.status = -1; - } - onReady.call( this, mockHandler.isTimeout ? 'timeout' : undefined ); - } else if ( mockHandler.isTimeout ) { - // Fix for 1.3.2 timeout to keep success from firing. - this.status = -1; - } + finishRequest.call(that); }).apply(that); }; })(this); @@ -182,28 +271,27 @@ url: mockHandler.proxy, type: mockHandler.proxyType, data: mockHandler.data, - dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType, + dataType: requestSettings.dataType === 'script' ? 'text/plain' : requestSettings.dataType, complete: function(xhr) { mockHandler.responseXML = xhr.responseXML; mockHandler.responseText = xhr.responseText; - // Don't override the handler status/statusText if it's specified by the config - if (isDefaultSetting(mockHandler, 'status')) { - mockHandler.status = xhr.status; - } - if (isDefaultSetting(mockHandler, 'statusText')) { - mockHandler.statusText = xhr.statusText; - } - - this.responseTimer = setTimeout(process, mockHandler.responseTime || 0); + // Don't override the handler status/statusText if it's specified by the config + if (isDefaultSetting(mockHandler, 'status')) { + mockHandler.status = xhr.status; + } + if (isDefaultSetting(mockHandler, 'statusText')) { + mockHandler.statusText = xhr.statusText; + } + this.responseTimer = setTimeout(process, parseResponseTimeOpt(mockHandler.responseTime)); } }); } else { - // type == 'POST' || 'GET' || 'DELETE' + // type === 'POST' || 'GET' || 'DELETE' if ( requestSettings.async === false ) { // TODO: Blocking delay process(); } else { - this.responseTimer = setTimeout(process, mockHandler.responseTime || 50); + this.responseTimer = setTimeout(process, parseResponseTimeOpt(mockHandler.responseTime)); } } } @@ -216,6 +304,9 @@ if (typeof mockHandler.headers === 'undefined') { mockHandler.headers = {}; } + if (typeof requestSettings.headers === 'undefined') { + requestSettings.headers = {}; + } if ( mockHandler.contentType ) { mockHandler.headers['content-type'] = mockHandler.contentType; } @@ -233,25 +324,29 @@ clearTimeout(this.responseTimer); }, setRequestHeader: function(header, value) { - mockHandler.headers[header] = value; + requestSettings.headers[header] = value; }, getResponseHeader: function(header) { // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery if ( mockHandler.headers && mockHandler.headers[header] ) { // Return arbitrary headers return mockHandler.headers[header]; - } else if ( header.toLowerCase() == 'last-modified' ) { + } else if ( header.toLowerCase() === 'last-modified' ) { return mockHandler.lastModified || (new Date()).toString(); - } else if ( header.toLowerCase() == 'etag' ) { + } else if ( header.toLowerCase() === 'etag' ) { return mockHandler.etag || ''; - } else if ( header.toLowerCase() == 'content-type' ) { + } else if ( header.toLowerCase() === 'content-type' ) { return mockHandler.contentType || 'text/plain'; } }, getAllResponseHeaders: function() { var headers = ''; + // since jQuery 1.9 responseText type has to match contentType + if (mockHandler.contentType) { + mockHandler.headers['Content-Type'] = mockHandler.contentType; + } $.each(mockHandler.headers, function(k, v) { - headers += k + ': ' + v + "\n"; + headers += k + ': ' + v + '\n'; }); return headers; } @@ -265,7 +360,7 @@ processJsonpUrl( requestSettings ); - requestSettings.dataType = "json"; + requestSettings.dataType = 'json'; if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) { createJsonpCallback(requestSettings, mockHandler, origSettings); @@ -276,8 +371,8 @@ parts = rurl.exec( requestSettings.url ), remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host); - requestSettings.dataType = "script"; - if(requestSettings.type.toUpperCase() === "GET" && remote ) { + requestSettings.dataType = 'script'; + if(requestSettings.type.toUpperCase() === 'GET' && remote ) { var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings ); // Check if we are supposed to return a Deferred back to the mock call, or just @@ -294,13 +389,13 @@ // Append the required callback parameter to the end of the request URL, for a JSONP request function processJsonpUrl( requestSettings ) { - if ( requestSettings.type.toUpperCase() === "GET" ) { + if ( requestSettings.type.toUpperCase() === 'GET' ) { if ( !CALLBACK_REGEX.test( requestSettings.url ) ) { - requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") + - (requestSettings.jsonp || "callback") + "=?"; + requestSettings.url += (/\?/.test( requestSettings.url ) ? '&' : '?') + + (requestSettings.jsonp || 'callback') + '=?'; } } else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) { - requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?"; + requestSettings.data = (requestSettings.data ? requestSettings.data + '&' : '') + (requestSettings.jsonp || 'callback') + '=?'; } } @@ -308,58 +403,82 @@ function processJsonpRequest( requestSettings, mockHandler, origSettings ) { // Synthesize the mock request for adding a script tag var callbackContext = origSettings && origSettings.context || requestSettings, - newMock = null; - + // If we are running under jQuery 1.5+, return a deferred object + newMock = ($.Deferred) ? (new $.Deferred()) : null; // If the response handler on the moock is a function, call it if ( mockHandler.response && $.isFunction(mockHandler.response) ) { + mockHandler.response(origSettings); - } else { - + + + } else if ( typeof mockHandler.responseText === 'object' ) { // Evaluate the responseText javascript in a global context - if( typeof mockHandler.responseText === 'object' ) { - $.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')'); - } else { - $.globalEval( '(' + mockHandler.responseText + ')'); - } + $.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')'); + + } else if (mockHandler.proxy) { + + // This handles the unique case where we have a remote URL, but want to proxy the JSONP + // response to another file (not the same URL as the mock matching) + _ajax({ + global: false, + url: mockHandler.proxy, + type: mockHandler.proxyType, + data: mockHandler.data, + dataType: requestSettings.dataType === 'script' ? 'text/plain' : requestSettings.dataType, + complete: function(xhr) { + $.globalEval( '(' + xhr.responseText + ')'); + completeJsonpCall( requestSettings, mockHandler, callbackContext, newMock ); + } + }); + + return newMock; + + } else { + $.globalEval( '(' + mockHandler.responseText + ')'); } + completeJsonpCall( requestSettings, mockHandler, callbackContext, newMock ); + + return newMock; + } + + function completeJsonpCall( requestSettings, mockHandler, callbackContext, newMock ) { + var json; + // Successful response - jsonpSuccess( requestSettings, callbackContext, mockHandler ); - jsonpComplete( requestSettings, callbackContext, mockHandler ); - - // If we are running under jQuery 1.5+, return a deferred object - if($.Deferred){ - newMock = new $.Deferred(); - if(typeof mockHandler.responseText == "object"){ - newMock.resolveWith( callbackContext, [mockHandler.responseText] ); - } - else{ - newMock.resolveWith( callbackContext, [$.parseJSON( mockHandler.responseText )] ); - } + setTimeout(function() { + jsonpSuccess( requestSettings, callbackContext, mockHandler ); + jsonpComplete( requestSettings, callbackContext ); + }, parseResponseTimeOpt( mockHandler.responseTime )); + + if ( newMock ) { + try { + json = $.parseJSON( mockHandler.responseText ); + } catch (err) { /* just checking... */ } + + newMock.resolveWith( callbackContext, [json || mockHandler.responseText] ); } - return newMock; } // Create the required JSONP callback function for the request function createJsonpCallback( requestSettings, mockHandler, origSettings ) { var callbackContext = origSettings && origSettings.context || requestSettings; - var jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++); + var jsonp = requestSettings.jsonpCallback || ('jsonp' + jsc++); // Replace the =? sequence both in the query string and the data if ( requestSettings.data ) { - requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1"); + requestSettings.data = (requestSettings.data + '').replace(CALLBACK_REGEX, '=' + jsonp + '$1'); } - requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1"); + requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, '=' + jsonp + '$1'); // Handle JSONP-style loading - window[ jsonp ] = window[ jsonp ] || function( tmp ) { - data = tmp; + window[ jsonp ] = window[ jsonp ] || function() { jsonpSuccess( requestSettings, callbackContext, mockHandler ); - jsonpComplete( requestSettings, callbackContext, mockHandler ); + jsonpComplete( requestSettings, callbackContext ); // Garbage collect window[ jsonp ] = undefined; @@ -367,9 +486,6 @@ delete window[ jsonp ]; } catch(e) {} - if ( head ) { - head.removeChild( script ); - } }; } @@ -377,49 +493,65 @@ function jsonpSuccess(requestSettings, callbackContext, mockHandler) { // If a local callback was specified, fire it and pass it the data if ( requestSettings.success ) { - requestSettings.success.call( callbackContext, mockHandler.responseText || "", status, {} ); + requestSettings.success.call( callbackContext, mockHandler.responseText || '', 'success', {} ); } // Fire the global callback if ( requestSettings.global ) { - trigger(requestSettings, "ajaxSuccess", [{}, requestSettings] ); + (requestSettings.context ? $(requestSettings.context) : $.event).trigger('ajaxSuccess', [{}, requestSettings]); } } // The JSONP request was completed function jsonpComplete(requestSettings, callbackContext) { - // Process result if ( requestSettings.complete ) { - requestSettings.complete.call( callbackContext, {} , status ); + requestSettings.complete.call( callbackContext, { + statusText: 'success', + status: 200 + } , 'success' ); } // The request was completed if ( requestSettings.global ) { - trigger( "ajaxComplete", [{}, requestSettings] ); + (requestSettings.context ? $(requestSettings.context) : $.event).trigger('ajaxComplete', [{}, requestSettings]); } // Handle the global AJAX counter if ( requestSettings.global && ! --$.active ) { - $.event.trigger( "ajaxStop" ); + $.event.trigger( 'ajaxStop' ); } } // The core $.ajax replacement. function handleAjax( url, origSettings ) { - var mockRequest, requestSettings, mockHandler; + var mockRequest, requestSettings, mockHandler, overrideCallback; // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { + if ( typeof url === 'object' ) { origSettings = url; url = undefined; } else { // work around to support 1.5 signature + origSettings = origSettings || {}; origSettings.url = url; } // Extend the original settings for the request - requestSettings = $.extend(true, {}, $.ajaxSettings, origSettings); + requestSettings = $.ajaxSetup({}, origSettings); + requestSettings.type = requestSettings.method = requestSettings.method || requestSettings.type; + + // Generic function to override callback methods for use with + // callback options (onAfterSuccess, onAfterError, onAfterComplete) + overrideCallback = function(action, mockHandler) { + var origHandler = origSettings[action.toLowerCase()]; + return function() { + if ( $.isFunction(origHandler) ) { + origHandler.apply(this, [].slice.call(arguments)); + } + mockHandler['onAfter' + action](); + }; + }; // Iterate over our mock handlers (in registration order) until we find // one that is willing to intercept the request @@ -440,7 +572,7 @@ $.mockjaxSettings.log( mockHandler, requestSettings ); - if ( requestSettings.dataType === "jsonp" ) { + if ( requestSettings.dataType && requestSettings.dataType.toUpperCase() === 'JSONP' ) { if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) { // This mock will handle the JSONP request return mockRequest; @@ -455,21 +587,48 @@ mockHandler.timeout = requestSettings.timeout; mockHandler.global = requestSettings.global; + // In the case of a timeout, we just need to ensure + // an actual jQuery timeout (That is, our reponse won't) + // return faster than the timeout setting. + if ( mockHandler.isTimeout ) { + if ( mockHandler.responseTime > 1 ) { + origSettings.timeout = mockHandler.responseTime - 1; + } else { + mockHandler.responseTime = 2; + origSettings.timeout = 1; + } + } + + // Set up onAfter[X] callback functions + if ( $.isFunction( mockHandler.onAfterSuccess ) ) { + origSettings.success = overrideCallback('Success', mockHandler); + } + if ( $.isFunction( mockHandler.onAfterError ) ) { + origSettings.error = overrideCallback('Error', mockHandler); + } + if ( $.isFunction( mockHandler.onAfterComplete ) ) { + origSettings.complete = overrideCallback('Complete', mockHandler); + } + copyUrlParameters(mockHandler, origSettings); + /* jshint loopfunc:true */ (function(mockHandler, requestSettings, origSettings, origHandler) { + mockRequest = _ajax.call($, $.extend(true, {}, origSettings, { // Mock the XHR object xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ); } })); })(mockHandler, requestSettings, origSettings, mockHandlers[k]); + /* jshint loopfunc:true */ return mockRequest; } // We don't have a mock request + unmockedAjaxCalls.push(origSettings); if($.mockjaxSettings.throwUnmocked === true) { - throw('AJAX not mocked: ' + origSettings.url); + throw new Error('AJAX not mocked: ' + origSettings.url); } else { // trigger a normal request return _ajax.apply($, [origSettings]); @@ -517,20 +676,23 @@ ajax: handleAjax }); + var DEFAULT_RESPONSE_TIME = 500; + + $.mockjaxSettings = { - //url: null, - //type: 'GET', - log: function( mockHandler, requestSettings ) { + //url: null, + //type: 'GET', + log: function( mockHandler, requestSettings ) { if ( mockHandler.logging === false || ( typeof mockHandler.logging === 'undefined' && $.mockjaxSettings.logging === false ) ) { return; } if ( window.console && console.log ) { var message = 'MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url; - var request = $.extend({}, requestSettings); + var request = $.ajaxSetup({}, requestSettings); if (typeof console.log === 'function') { - console.log(message, JSON.stringify(request.data)); + console.log(message, request); } else { try { console.log( message + ' ' + JSON.stringify(request) ); @@ -542,8 +704,8 @@ }, logging: true, status: 200, - statusText: "OK", - responseTime: 500, + statusText: 'OK', + responseTime: DEFAULT_RESPONSE_TIME, isTimeout: false, throwUnmocked: false, contentType: 'text/plain', @@ -566,20 +728,37 @@ mockHandlers[i] = settings; return i; }; - $.mockjaxClear = function(i) { - if ( arguments.length == 1 ) { + $.mockjax.clear = function(i) { + if ( i || i === 0 ) { mockHandlers[i] = null; } else { mockHandlers = []; } mockedAjaxCalls = []; + unmockedAjaxCalls = []; }; $.mockjax.handler = function(i) { - if ( arguments.length == 1 ) { + if ( arguments.length === 1 ) { return mockHandlers[i]; } }; $.mockjax.mockedAjaxCalls = function() { return mockedAjaxCalls; }; -})(jQuery); + $.mockjax.unfiredHandlers = function() { + var results = []; + for (var i=0, len=mockHandlers.length; i<len; i++) { + var handler = mockHandlers[i]; + if (handler !== null && !handler.fired) { + results.push(handler); + } + } + return results; + }; + $.mockjax.unmockedAjaxCalls = function() { + return unmockedAjaxCalls; + }; + + return $.mockjax; + +})); diff --git a/server/sonar-web/test/helpers/test-page.js b/server/sonar-web/test/helpers/test-page.js index b07a0b91a0b..8e370300d71 100644 --- a/server/sonar-web/test/helpers/test-page.js +++ b/server/sonar-web/test/helpers/test-page.js @@ -109,6 +109,15 @@ define(function (require) { }); }; + Command.prototype.submitForm = function (selector) { + return new this.constructor(this, function () { + return this.parent + .execute(function (selector) { + jQuery(selector).submit(); + }, [selector]); + }); + }; + Command.prototype.mockFromFile = function (url, file, options) { var response = fs.readFileSync('src/test/json/' + file, 'utf-8'); return new this.constructor(this, function () { @@ -132,7 +141,7 @@ define(function (require) { return new this.constructor(this, function () { return this.parent .execute(function () { - jQuery.mockjaxClear(); + jQuery.mockjax.clear(); }); }); }; @@ -162,4 +171,13 @@ define(function (require) { }); }; + Command.prototype.forceJSON = function () { + return new this.constructor(this, function () { + return this.parent + .execute(function () { + jQuery.ajaxSetup({ dataType: 'json' }); + }); + }); + }; + }); diff --git a/server/sonar-web/test/intern.js b/server/sonar-web/test/intern.js index 1de94e101e3..6e846af1423 100644 --- a/server/sonar-web/test/intern.js +++ b/server/sonar-web/test/intern.js @@ -23,7 +23,8 @@ define(['intern'], function (intern) { 'test/medium/users.spec', 'test/medium/issues.spec', 'test/medium/update-center.spec', - 'test/medium/computation.spec' + 'test/medium/computation.spec', + 'test/medium/coding-rules.spec' ], tunnel: tunnel, diff --git a/server/sonar-web/test/medium/base.html b/server/sonar-web/test/medium/base.html index 09060d02b4a..4a241acad60 100644 --- a/server/sonar-web/test/medium/base.html +++ b/server/sonar-web/test/medium/base.html @@ -43,8 +43,8 @@ <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 src="../../build/js/libs/third-party/require.js"></script> <script>var baseUrl = ''; var $j = jQuery.noConflict(); window.suppressTranslationWarnings = true; diff --git a/server/sonar-web/test/medium/coding-rules.spec.js b/server/sonar-web/test/medium/coding-rules.spec.js new file mode 100644 index 00000000000..cf50688cd96 --- /dev/null +++ b/server/sonar-web/test/medium/coding-rules.spec.js @@ -0,0 +1,924 @@ +define(function (require) { + var bdd = require('intern!bdd'); + require('../helpers/test-page'); + + bdd.describe('Coding Rules Page', function () { + + bdd.it('should show alert when there is no available profiles for activation', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app-no-available-profiles.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-no-available-profiles.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-no-available-profiles.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-detail-header') + .checkElementExist('#coding-rules-quality-profile-activate') + .clickElement('#coding-rules-quality-profile-activate') + .checkElementExist('.modal') + .checkElementExist('.modal .alert'); + }); + + bdd.it('should show profile facet', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-profile-facet.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', '609') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clearMocks() + .mockFromFile('/api/rules/search', + 'coding-rules-spec/search-profile-facet-qprofile-active.json', + { data: { activation: true } }) + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .checkElementInclude('#coding-rules-total', '407') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"] .js-active.facet-toggle-active') + .clearMocks() + .mockFromFile('/api/rules/search', + 'coding-rules-spec/search-profile-facet-qprofile-inactive.json', + { data: { activation: 'false' } }) + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"] .js-inactive') + .checkElementInclude('#coding-rules-total', '408') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"] .js-inactive.facet-toggle-active') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-profile-facet.json') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', '609'); + }); + + bdd.it('should show query facet', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', '609') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-query.json', { data: { q: 'query' } }) + .fillElement('[data-property="q"] input', 'query') + .submitForm('[data-property="q"] form') + .checkElementInclude('#coding-rules-total', '4') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .fillElement('[data-property="q"] input', '') + .submitForm('[data-property="q"] form') + .checkElementInclude('#coding-rules-total', '609'); + }); + + bdd.it('should show rule permalink', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-detail-header') + .checkElementExist('a[href="/coding_rules#rule_key=squid%3AS2204"]'); + }); + + bdd.it('should activate profile', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-activate-profile.json') + .mockFromString('/api/qualityprofiles/activate_rule', '{}') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-detail-header') + .checkElementNotExist('.coding-rules-detail-quality-profile-name') + .checkElementExist('#coding-rules-quality-profile-activate') + .clickElement('#coding-rules-quality-profile-activate') + .checkElementExist('.modal') + .clearMocks() + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-activate-profile-with-profile.json') + .mockFromString('/api/qualityprofiles/activate_rule', '{}') + .mockFromString('/api/issues/search', '{}') + .clickElement('#coding-rules-quality-profile-activation-activate') + .checkElementExist('.coding-rules-detail-quality-profile-name') + .checkElementExist('.coding-rules-detail-quality-profile-name') + .checkElementExist('.coding-rules-detail-quality-profile-severity') + .checkElementExist('.coding-rules-detail-quality-profile-deactivate'); + }); + + bdd.it('should create custom rule', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-create-custom-rules.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clearMocks() + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-custom-rules.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-custom-rules.json', + { data: { template_key: 'squid:ArchitecturalConstraint' } }) + .mockFromString('/api/rules/create', '{}') + .mockFromString('/api/issues/search', '{}') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('#coding-rules-detail-custom-rules .coding-rules-detail-list-name') + .clearMocks() + .mockFromString('/api/rules/create', '{}') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-custom-rules.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-custom-rules2.json') + .checkElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 1) + .clickElement('.js-create-custom-rule') + .fillElement('.modal form [name="name"]', 'test') + .fillElement('.modal form [name="markdown_description"]', 'test') + .clickElement('#coding-rules-custom-rule-creation-create') + .checkElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2); + }); + + bdd.it('should reactivate custom rule', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-create-custom-rules.json') + .startApp('coding-rules') + .forceJSON() + .checkElementExist('.coding-rule.selected') + .clearMocks() + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-custom-rules.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-custom-rules.json', + { data: { template_key: 'squid:ArchitecturalConstraint' } }) + .mockFromFile('/api/rules/create', 'coding-rules-spec/create-create-custom-rules.json', { status: 409 }) + .mockFromString('/api/issues/search', '{}') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.js-create-custom-rule') + .clickElement('.js-create-custom-rule') + .checkElementExist('.modal') + .fillElement('.modal form [name="name"]', 'My Custom Rule') + .fillElement('.modal form [name="markdown_description"]', 'My Description') + .clickElement('#coding-rules-custom-rule-creation-create') + .checkElementExist('.modal .alert-warning') + .clearMocks() + .mockFromFile('/api/rules/create', 'coding-rules-spec/create-create-custom-rules.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-custom-rules2.json', + { data: { template_key: 'squid:ArchitecturalConstraint' } }) + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-create-custom-rules.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-custom-rules.json') + .clickElement('.modal #coding-rules-custom-rule-creation-reactivate') + .checkElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2); + }); + + bdd.it('should create manual rule', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-create-manual-rule.json') + .mockFromFile('/api/rules/create', 'coding-rules-spec/show-create-manual-rule.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-manual-rule.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .forceJSON() + .checkElementExist('.js-create-manual-rule') + .clickElement('.js-create-manual-rule') + .checkElementExist('.modal') + .fillElement('.modal [name="name"]', 'Manual Rule') + .fillElement('.modal [name="markdown_description"]', 'Manual Rule Description') + .clickElement('.modal #coding-rules-manual-rule-creation-create') + .checkElementExist('.coding-rules-detail-header') + .checkElementInclude('.coding-rules-detail-header', 'Manual Rule') + .checkElementInclude('.coding-rule-details', 'manual:Manual_Rule') + .checkElementInclude('.coding-rules-detail-description', 'Manual Rule Description'); + }); + + bdd.it('should reactivate manual rule', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-create-manual-rule.json') + .mockFromFile('/api/rules/create', 'coding-rules-spec/show-create-manual-rule.json', { status: 409 }) + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-manual-rule.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .forceJSON() + .checkElementExist('.js-create-manual-rule') + .clickElement('.js-create-manual-rule') + .checkElementExist('.modal') + .checkElementExist('.modal #coding-rules-manual-rule-creation-create') + .fillElement('.modal [name="name"]', 'Manual Rule') + .fillElement('.modal [name="markdown_description"]', 'Manual Rule Description') + .clickElement('.modal #coding-rules-manual-rule-creation-create') + .checkElementExist('.modal .alert-warning') + .clearMocks() + .mockFromFile('/api/rules/create', 'coding-rules-spec/show.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-create-manual-rule.json') + .clickElement('.modal #coding-rules-manual-rule-creation-reactivate') + .checkElementExist('.coding-rules-detail-header') + .checkElementInclude('.coding-rules-detail-header', 'Manual Rule') + .checkElementInclude('.coding-rule-details', 'manual:Manual_Rule') + .checkElementInclude('.coding-rules-detail-description', 'Manual Rule Description'); + }); + + bdd.it('should delete custom rules', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-delete-custom-rule-custom-rules.json', + { data: { template_key: 'squid:ArchitecturalConstraint' } }) + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-delete-custom-rule.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-delete-custom-rule.json') + .mockFromString('/api/rules/delete', '{}') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('#coding-rules-detail-custom-rules .coding-rules-detail-list-name') + .checkElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2) + .clickElement('.js-delete-custom-rule') + .clickElement('[data-confirm="yes"]') + .checkElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 1); + }); + + bdd.it('should delete manual rules', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-delete-manual-rule-before.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-delete-manual-rule.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .forceJSON() + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.js-delete') + .clickElement('.js-delete') + .checkElementExist('[data-confirm="yes"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-delete-manual-rule-after.json') + .mockFromString('/api/rules/delete', '{}') + .clickElement('[data-confirm="yes"]') + .checkElementInclude('#coding-rules-total', 0); + }); + + bdd.it('should show custom rules', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-show-cutsom-rule-custom-rules.json', + { data: { template_key: 'squid:ArchitecturalConstraint' } }) + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-show-cutsom-rule.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-show-cutsom-rule.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('#coding-rules-detail-custom-rules .coding-rules-detail-list-name') + .checkElementExist('#coding-rules-detail-custom-rules') + .checkElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2) + .checkElementInclude('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', + 'Do not use org.h2.util.StringUtils'); + }); + + bdd.it('should show deprecated label', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-deprecated.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .checkElementInclude('.coding-rule.selected', 'DEPRECATED'); + }); + + bdd.it('should show rule details', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-show-details.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show-show-details.json') + .mockFromString('/api/issues/search', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-detail-header') + .checkElementInclude('.search-navigator-workspace-details', + 'Throwable and Error classes should not be caught') + .checkElementInclude('.search-navigator-workspace-details', 'squid:S1181') + .checkElementExist('.coding-rules-detail-properties .icon-severity-blocker') + .checkElementInclude('.coding-rules-detail-properties', 'error-handling') + .checkElementInclude('.coding-rules-detail-properties', '2013') + .checkElementInclude('.coding-rules-detail-properties', 'SonarQube (Java)') + .checkElementInclude('.coding-rules-detail-properties', 'Reliability > Exception handling') + .checkElementInclude('.coding-rules-detail-properties', 'LINEAR') + .checkElementInclude('.coding-rules-detail-properties', '20min') + + .checkElementInclude('.coding-rules-detail-description', 'is the superclass of all errors and') + .checkElementInclude('.coding-rules-detail-description', 'its subclasses should be caught.') + .checkElementInclude('.coding-rules-detail-description', 'Noncompliant Code Example') + .checkElementInclude('.coding-rules-detail-description', 'Compliant Solution') + + .checkElementInclude('.coding-rules-detail-parameters', 'max') + .checkElementInclude('.coding-rules-detail-parameters', 'Maximum authorized number of parameters') + .checkElementInclude('.coding-rules-detail-parameters', '7') + + .checkElementCount('.coding-rules-detail-quality-profile-name', 6) + .checkElementInclude('.coding-rules-detail-quality-profile-name', 'Default - Top') + .checkElementCount('.coding-rules-detail-quality-profile-inheritance', 4) + .checkElementInclude('.coding-rules-detail-quality-profile-inheritance', 'Default - Top'); + }); + + bdd.it('should show empty list', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-empty.json') + .startApp('coding-rules') + .checkElementExist('.search-navigator-facet-box') + .checkElementNotExist('.coding-rule') + .checkElementInclude('#coding-rules-total', 0) + .checkElementExist('.search-navigator-no-results'); + }); + + bdd.it('should show facets', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.search-navigator-facet-box') + .checkElementCount('.search-navigator-facet-box', 13); + }); + + bdd.it('should show rule', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .checkElementInclude('.coding-rule.selected', 'Values passed to SQL commands should be sanitized') + .checkElementInclude('.coding-rule.selected', 'Java') + .checkElementInclude('.coding-rule.selected', 'cwe') + .checkElementInclude('.coding-rule.selected', 'owasp-top10') + .checkElementInclude('.coding-rule.selected', 'security') + .checkElementInclude('.coding-rule.selected', 'sql') + .checkElementInclude('.coding-rule.selected', 'custom-tag'); + }); + + bdd.it('should show rule issues', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show.json') + .mockFromFile('/api/issues/search', 'coding-rules-spec/issues-search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-most-violated-projects') + .checkElementInclude('.js-rule-issues', '7') + .checkElementInclude('.coding-rules-most-violated-projects', 'SonarQube') + .checkElementInclude('.coding-rules-most-violated-projects', '2') + .checkElementInclude('.coding-rules-most-violated-projects', 'SonarQube Runner') + .checkElementInclude('.coding-rules-most-violated-projects', '1'); + }); + + bdd.it('should show rules', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementCount('.coding-rule', 25) + .checkElementInclude('.coding-rule', 'Values passed to SQL commands should be sanitized') + .checkElementInclude('.coding-rule', 'An open curly brace should be located at the beginning of a line') + .checkElementInclude('#coding-rules-total', '609'); + }); + + bdd.it('should move between rules from detailed view', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-detail-header') + .checkElementInclude('.coding-rules-detail-header', + '".equals()" should not be used to test the values') + .clearMocks() + .mockFromFile('/api/rules/show', 'coding-rules-spec/show2.json') + .clickElement('.js-next') + .checkElementInclude('.coding-rules-detail-header', '"@Override" annotation should be used on any') + .clearMocks() + .mockFromFile('/api/rules/show', 'coding-rules-spec/show.json') + .clickElement('.js-prev') + .checkElementInclude('.coding-rules-detail-header', '".equals()" should not be used to test the values'); + }); + + bdd.it('should filter similar rules', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected .js-rule-filter') + .checkElementInclude('#coding-rules-total', '609') + .clickElement('.js-rule-filter') + .checkElementExist('.bubble-popup') + .checkElementExist('.bubble-popup [data-property="languages"][data-value="java"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-sql-tag.json', { data: { tags: 'sql' } }) + .clickElement('.bubble-popup [data-property="tags"][data-value="sql"]') + .checkElementInclude('#coding-rules-total', '2'); + }); + + bdd.it('should show active severity facet', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', '609') + .checkElementExist('.search-navigator-facet-box-forbidden[data-property="active_severities"]') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-qprofile.json', + { data: { qprofile: 'java-default-with-mojo-conventions-49307' } }) + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .checkElementInclude('#coding-rules-total', '407') + .checkElementNotExist('.search-navigator-facet-box-forbidden[data-property="active_severities"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/active-severities-facet.json', + { data: { facets: 'active_severities', ps: 1 } }) + .clickElement('[data-property="active_severities"] .js-facet-toggle') + .checkElementExist('[data-property="active_severities"] [data-value="BLOCKER"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-BLOCKER.json', + { data: { active_severities: 'BLOCKER' } }) + .clickElement('[data-property="active_severities"] [data-value="BLOCKER"]') + .checkElementInclude('#coding-rules-total', '4') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', '609') + .checkElementExist('.search-navigator-facet-box-forbidden[data-property="active_severities"]'); + }); + + bdd.it('should show available since facet', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', '609') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-limited.json', + { data: { available_since: '2014-12-01' } }) + .clickElement('[data-property="available_since"] .js-facet-toggle') + .fillElement('[data-property="available_since"] input', '2014-12-01') + .execute(function () { + // TODO do not use jQuery + jQuery('[data-property="available_since"] input').change(); + }) + .checkElementInclude('#coding-rules-total', '101'); + }); + + bdd.it('should bulk activate', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromString('/api/qualityprofiles/activate_rules', '{ "succeeded": 225 }') + .startApp('coding-rules') + .forceJSON() + .checkElementExist('.coding-rule') + .checkElementExist('.js-bulk-change') + .clickElement('.js-bulk-change') + .checkElementExist('.bubble-popup') + .checkElementExist('.bubble-popup .js-bulk-change[data-action="activate"]') + .clickElement('.js-bulk-change[data-action="activate"]') + .checkElementExist('.modal') + .checkElementExist('.modal #coding-rules-bulk-change-profile') + .checkElementExist('.modal #coding-rules-submit-bulk-change') + .fillElement('#coding-rules-bulk-change-profile', 'java-default-with-mojo-conventions-49307') + .clickElement('.modal #coding-rules-submit-bulk-change') + .checkElementExist('.modal .alert-success') + .checkElementInclude('.modal', 'Default - Maven Conventions') + .checkElementInclude('.modal', 'Java') + .checkElementInclude('.modal', '225'); + }); + + bdd.it('should fail to bulk activate', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromString('/api/qualityprofiles/activate_rules', '{ "succeeded": 225, "failed": 395 }') + .startApp('coding-rules') + .forceJSON() + .checkElementExist('.coding-rule') + .checkElementExist('.js-bulk-change') + .clickElement('.js-bulk-change') + .checkElementExist('.bubble-popup') + .checkElementExist('.bubble-popup .js-bulk-change[data-action="activate"]') + .clickElement('.js-bulk-change[data-action="activate"]') + .checkElementExist('.modal') + .checkElementExist('.modal #coding-rules-bulk-change-profile') + .checkElementExist('.modal #coding-rules-submit-bulk-change') + .fillElement('#coding-rules-bulk-change-profile', 'java-default-with-mojo-conventions-49307') + .clickElement('.modal #coding-rules-submit-bulk-change') + .checkElementExist('.modal .alert-warning') + .checkElementInclude('.modal', '225') + .checkElementInclude('.modal', '395'); + }); + + bdd.it('should filter profiles by language during bulk change', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .clickElement('.js-facet[data-value="java"]') + .checkElementExist('.js-bulk-change') + .clickElement('.js-bulk-change') + .checkElementExist('.bubble-popup') + .checkElementExist('.bubble-popup .js-bulk-change[data-action="activate"]') + .clickElement('.js-bulk-change[data-action="activate"]') + .checkElementExist('.modal') + .checkElementExist('.modal #coding-rules-bulk-change-profile') + .checkElementCount('.modal #coding-rules-bulk-change-profile option', 8); + }); + + bdd.it('should change selected profile during bulk change', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-qprofile-active.json', + { data: { activation: true } }) + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromString('/api/qualityprofiles/deactivate_rules', '{ "succeeded": 7 }') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .checkElementExist('.js-bulk-change') + .clickElement('.js-bulk-change') + .checkElementExist('.bubble-popup') + .checkElementExist('.bubble-popup .js-bulk-change[data-param="java-default-with-mojo-conventions-49307"]') + .clickElement('.js-bulk-change[data-param="java-default-with-mojo-conventions-49307"]') + .checkElementExist('.modal') + .checkElementNotExist('.modal #coding-rules-bulk-change-profile') + .clickElement('.modal #coding-rules-submit-bulk-change') + .checkElementExist('.modal .alert-success') + .checkElementInclude('.modal', '7'); + }); + + bdd.it('should show characteristic facet', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementExist('.search-navigator-facet-box-collapsed[data-property="debt_characteristics"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-characteristic.json', + { data: { facets: 'debt_characteristics' } }) + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="PORTABILITY"]') + .checkElementCount('[data-property="debt_characteristics"] .js-facet', 32) + .checkElementCount('[data-property="debt_characteristics"] .js-facet.search-navigator-facet-indent', 24) + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-with-portability-characteristic.json', + { data: { debt_characteristics: 'PORTABILITY' } }) + .clickElement('.js-facet[data-value="PORTABILITY"]') + .checkElementInclude('#coding-rules-total', 21) + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-without-characteristic.json', + { data: { has_debt_characteristic: 'false' } }) + .clickElement('.js-facet[data-empty-characteristic]') + .checkElementInclude('#coding-rules-total', 208) + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-with-memory-efficiency-characteristic.json', + { data: { debt_characteristics: 'MEMORY_EFFICIENCY' } }) + .clickElement('.js-facet[data-value="MEMORY_EFFICIENCY"]') + .checkElementInclude('#coding-rules-total', 3); + }); + + bdd.it('should disable characteristic facet', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-characteristic.json', + { data: { facets: 'debt_characteristics' } }) + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="PORTABILITY"]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-with-portability-characteristic.json', + { data: { debt_characteristics: 'PORTABILITY' } }) + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('.js-facet[data-value="PORTABILITY"]') + .checkElementInclude('#coding-rules-total', 21) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', 609) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-characteristic.json', + { data: { facets: 'debt_characteristics' } }) + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="MEMORY_EFFICIENCY"]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-with-memory-efficiency-characteristic.json', + { data: { debt_characteristics: 'MEMORY_EFFICIENCY' } }) + .clickElement('.js-facet[data-value="MEMORY_EFFICIENCY"]') + .checkElementInclude('#coding-rules-total', 3) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', 609) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-characteristic.json', + { data: { facets: 'debt_characteristics' } }) + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementExist('.js-facet[data-empty-characteristic]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-without-characteristic.json', + { data: { has_debt_characteristic: 'false' } }) + .clickElement('.js-facet[data-empty-characteristic]') + .checkElementInclude('#coding-rules-total', 208) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('[data-property="debt_characteristics"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', 609); + }); + + bdd.it('should show template facet', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementExist('.search-navigator-facet-box-collapsed[data-property="is_template"]') + + .clickElement('[data-property="is_template"] .js-facet-toggle') + .checkElementExist('[data-property="is_template"] .js-facet[data-value="true"]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-only-templates.json', + { data: { 'is_template': 'true' } }) + .clickElement('[data-property="is_template"] .js-facet[data-value="true"]') + .checkElementInclude('#coding-rules-total', 8) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-hide-templates.json', + { data: { 'is_template': 'false' } }) + .clickElement('[data-property="is_template"] .js-facet[data-value="false"]') + .checkElementInclude('#coding-rules-total', 7) + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('[data-property="is_template"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', 609); + }); + + bdd.it('should show language facet', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromString('/api/languages/list', '{"languages":[{"key":"custom","name":"Custom"}]}', + { data: { q: 'custom' } }) + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .clickElement('[data-property="languages"] .select2-choice') + .checkElementExist('.select2-search') + .fillElement('.select2-input', 'custom') + .execute(function () { + // TODO remove jQuery usage + jQuery('.select2-input').trigger('keyup-change'); + }) + .checkElementExist('.select2-result') + .checkElementInclude('.select2-result', 'Custom') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-with-custom-language.json', + { data: { languages: 'custom' } }) + .execute(function () { + // TODO remove jQuery usage + jQuery('.select2-result').mouseup(); + }) + .checkElementInclude('#coding-rules-total', 13) + .checkElementExist('[data-property="languages"] .js-facet.active') + .checkElementInclude('[data-property="languages"] .js-facet.active', 'custom') + .checkElementInclude('[data-property="languages"] .js-facet.active', '13'); + }); + + bdd.it('should reload results', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', 609) + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search2.json') + .clickElement('.js-reload') + .checkElementInclude('#coding-rules-total', 413); + }); + + bdd.it('should do a new search', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', 609) + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search2.json', { data: { languages: 'java' } }) + .clickElement('.js-facet[data-value="java"]') + .checkElementInclude('#coding-rules-total', 413) + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('.js-new-search') + .checkElementInclude('#coding-rules-total', 609); + }); + + bdd.it('should go back', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromFile('/api/rules/show', 'coding-rules-spec/show.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule.selected') + .clickElement('.coding-rule.selected .js-rule') + .checkElementExist('.coding-rules-detail-header') + .clickElement('.js-back') + .checkElementNotExist('.js-back') + .checkElementNotExist('.coding-rules-detail-header'); + }); + + bdd.it('should show inheritance facet', function () { + return this.remote + .open() + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementInclude('#coding-rules-total', '609') + .checkElementExist('.search-navigator-facet-box-forbidden[data-property="inheritance"]') + + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-qprofile.json', + { data: { qprofile: 'java-default-with-mojo-conventions-49307' } }) + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .checkElementInclude('#coding-rules-total', '407') + .checkElementNotExist('.search-navigator-facet-box-forbidden[data-property="inheritance"]') + + .clickElement('[data-property="inheritance"] .js-facet-toggle') + .checkElementExist('[data-property="inheritance"] [data-value="NONE"]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-not-inherited.json', + { data: { inheritance: 'NONE' } }) + .clickElement('[data-property="inheritance"] [data-value="NONE"]') + .checkElementInclude('#coding-rules-total', '103') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-inherited.json', + { data: { inheritance: 'INHERITED' } }) + .clickElement('[data-property="inheritance"] [data-value="INHERITED"]') + .checkElementInclude('#coding-rules-total', '101') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-overriden.json', + { data: { inheritance: 'OVERRIDES' } }) + .clickElement('[data-property="inheritance"] [data-value="OVERRIDES"]') + .checkElementInclude('#coding-rules-total', '102') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-qprofile2.json', + { data: { qprofile: 'java-top-profile-without-formatting-conventions-50037' } }) + .clickElement('.js-facet[data-value="java-top-profile-without-formatting-conventions-50037"]') + .checkElementInclude('#coding-rules-total', '408') + .checkElementExist('.search-navigator-facet-box-forbidden[data-property="inheritance"]') + + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementInclude('#coding-rules-total', '609') + .checkElementExist('.search-navigator-facet-box-forbidden[data-property="inheritance"]'); + }); + + bdd.it('should show activation details', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementNotExist('.coding-rule-activation') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clearMocks() + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-actives.json', { data: { activation: true } }) + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .checkElementCount('.coding-rule-activation', 2) + .checkElementCount('.coding-rule-activation .icon-severity-major', 2) + .checkElementCount('.coding-rule-activation .icon-inheritance', 1) + .checkElementNotExist('.coding-rules-detail-quality-profile-activate'); + }); + + bdd.it('should activate rule', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-inactive.json', + { data: { activation: 'false' } }) + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .mockFromString('/api/qualityprofiles/activate_rule', '{}') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementNotExist('.coding-rule-activation') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"] .js-inactive') + .checkElementNotExist('.coding-rule-activation .icon-severity-major') + .checkElementExist('.coding-rules-detail-quality-profile-activate') + .clickElement('.coding-rules-detail-quality-profile-activate') + .checkElementExist('.modal') + .checkElementExist('#coding-rules-quality-profile-activation-select') + .checkElementCount('#coding-rules-quality-profile-activation-select option', 1) + .checkElementExist('#coding-rules-quality-profile-activation-severity') + .clickElement('#coding-rules-quality-profile-activation-activate') + .checkElementExist('.coding-rule-activation .icon-severity-major') + .checkElementExist('.coding-rule-activation .icon-severity-major') + .checkElementNotExist('.coding-rules-detail-quality-profile-activate') + .checkElementExist('.coding-rules-detail-quality-profile-deactivate'); + }); + + bdd.it('should deactivate rule', function () { + return this.remote + .open() + .mockFromString('/api/l10n/index', '{}') + .mockFromFile('/api/rules/app', 'coding-rules-spec/app.json') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search.json') + .startApp('coding-rules') + .checkElementExist('.coding-rule') + .checkElementNotExist('.coding-rule-activation') + .clickElement('[data-property="qprofile"] .js-facet-toggle') + .checkElementExist('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .clearMocks() + .mockFromString('/api/qualityprofiles/deactivate_rule', '{}') + .mockFromFile('/api/rules/search', 'coding-rules-spec/search-active.json', { data: { activation: true } }) + .clickElement('.js-facet[data-value="java-default-with-mojo-conventions-49307"]') + .checkElementExist('.coding-rule-activation .icon-severity-major') + .checkElementNotExist('.coding-rules-detail-quality-profile-activate') + .clickElement('.coding-rules-detail-quality-profile-deactivate') + .checkElementExist('button[data-confirm="yes"]') + .clickElement('button[data-confirm="yes"]') + .checkElementNotExist('.coding-rule-activation .icon-severity-major') + .checkElementNotExist('.coding-rule-activation .icon-severity-major') + .checkElementExist('.coding-rules-detail-quality-profile-activate') + .checkElementNotExist('.coding-rules-detail-quality-profile-deactivate'); + }); + }); +}); diff --git a/server/sonar-web/test/medium/computation.spec.js b/server/sonar-web/test/medium/computation.spec.js index f6af86f4654..4884204fbf1 100644 --- a/server/sonar-web/test/medium/computation.spec.js +++ b/server/sonar-web/test/medium/computation.spec.js @@ -30,7 +30,7 @@ define(function (require) { .startApp('computation', { urlRoot: '/test/medium/base.html' }) .checkElementCount('#computation-list li[data-id]', 2) .clearMocks() - .mockFromFile('/api/computation/history', 'computation-spec/history-big-2.json', { data: { p: '2' } }) + .mockFromFile('/api/computation/history', 'computation-spec/history-big-2.json', { data: { p: 2 } }) .clickElement('#computation-fetch-more') .checkElementCount('#computation-list li[data-id]', 3); }); diff --git a/travis.sh b/travis.sh index f616c39006f..58de4bc9953 100755 --- a/travis.sh +++ b/travis.sh @@ -33,7 +33,7 @@ MYSQL) WEB) export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start + /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 wget http://selenium-release.storage.googleapis.com/2.46/selenium-server-standalone-2.46.0.jar nohup java -jar selenium-server-standalone-2.46.0.jar & sleep 3 |