Merge "RolesApprovalSystemController up"
authorSunder Tattavarada <statta@research.att.com>
Wed, 18 Mar 2020 01:51:24 +0000 (01:51 +0000)
committerGerrit Code Review <gerrit@onap.org>
Wed, 18 Mar 2020 01:51:24 +0000 (01:51 +0000)
13 files changed:
ecomp-portal-BE-common/src/main/java/org/onap/portalapp/portal/scheduler/client/HttpsBasicClient.java
ecomp-portal-BE-common/src/main/java/org/onap/portalapp/portal/service/ApplicationsRestClientServiceImpl.java
ecomp-portal-BE-common/src/main/java/org/onap/portalapp/portal/service/MicroserviceServiceImpl.java
ecomp-portal-BE-os/pom.xml
ecomp-portal-BE-os/src/main/webapp/WEB-INF/jsp/login.jsp
pom.xml
portal-FE-common/src/app/layout/components/footer/footer.component.html
portal-FE-common/src/app/layout/components/footer/footer.component.ts
portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.spec.ts
portal-FE-common/src/app/shared/model/widget-onboarding/widget.ts
portal-FE-os/package.json
portal-FE-os/pom.xml
portal-FE-os/src/karma.conf.js

index d618a6e..c79d6c0 100644 (file)
@@ -77,8 +77,7 @@ public class HttpsBasicClient{
        public static Client getClient() throws Exception {
                String methodName = "getClient";
                ClientConfig config = new ClientConfig();
-               //config.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
-               //config.getClasses().add(org.onap.aai.util.CustomJacksonJaxBJsonProvider.class);
+
        
                SSLContext ctx = null;
                
@@ -87,17 +86,17 @@ public class HttpsBasicClient{
                        SimpleDateFormat dateFormat = DateUtil.getDateFormat();
                        config.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
                        
-                       String truststore_path = SchedulerProperties.getProperty(SchedulerProperties.VID_TRUSTSTORE_FILENAME);
+                       String truststorePath = SchedulerProperties.getProperty(SchedulerProperties.VID_TRUSTSTORE_FILENAME);
                        logger.debug(EELFLoggerDelegate.debugLogger, dateFormat.format(new Date()) + " " + methodName + " "
                                + "truststore_path=" +
-                               truststore_path);
-                       String truststore_password = SchedulerProperties.getProperty(SchedulerProperties.VID_TRUSTSTORE_PASSWD_X);
+                               truststorePath);
+                       String truststorePassword = SchedulerProperties.getProperty(SchedulerProperties.VID_TRUSTSTORE_PASSWD_X);
                        
                        
-                       String decrypted_truststore_password = Password.deobfuscate(truststore_password);
+                       String decryptedTruststorePassword = Password.deobfuscate(truststorePassword);
                        //logger.debug(dateFormat.format(new Date()) + " " + methodName + " decrypted_truststore_password=" + decrypted_truststore_password);
                        
-                       File tr = new File (truststore_path);
+                       File tr = new File (truststorePath);
                        logger.debug(EELFLoggerDelegate.debugLogger, dateFormat.format(new Date()) + " " + methodName + " absolute "
                                + "truststore path=" + tr.getAbsolutePath());
                        
@@ -105,8 +104,8 @@ public class HttpsBasicClient{
                        //String keystore_password = SystemProperties.getProperty(AAIProperties.AAI_KEYSTORE_PASSWD_X);
                        //String decrypted_keystore_password = EncryptedPropValue.decryptTriple(keystore_password);
                        
-                   System.setProperty("javax.net.ssl.trustStore", truststore_path);
-                   System.setProperty("javax.net.ssl.trustStorePassword", decrypted_truststore_password);
+                   System.setProperty("javax.net.ssl.trustStore", truststorePath);
+                   System.setProperty("javax.net.ssl.trustStorePassword", decryptedTruststorePassword);
                        HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
                            public boolean verify(String string,SSLSession ssls) {
                                return true;
@@ -134,9 +133,7 @@ public class HttpsBasicClient{
                        ctx.init(kmf.getKeyManagers(), null, null);
                        */
                        ctx.init(null, null, null);
-                       //config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, 
-                       //                                                      new HTTPSProperties( , ctx));
-                       
+
                        return ClientBuilder.newBuilder()
                                .sslContext(ctx)
                                .hostnameVerifier(new HostnameVerifier() {
@@ -148,17 +145,9 @@ public class HttpsBasicClient{
                                .build()
                                .register(CustomJacksonJaxBJsonProvider.class);
                        
-               } catch (Exception e) {
-                       logger.debug(EELFLoggerDelegate.debugLogger, "Error setting up config: exiting");
-                       //System.out.println("Error setting up config: exiting");
-                       e.printStackTrace();
-                       return null;
-               }
-                       
-               //Client client = ClientBuilder.newClient(config);
-               // uncomment this line to get more logging for the request/response
-               // client.addFilter(new LoggingFilter(System.out));
-               
-               //return client;
-       }
-}  
+        } catch (Exception e) {
+            logger.debug(EELFLoggerDelegate.debugLogger, "Error setting up config: exiting", e);
+            return null;
+        }
+    }
+}
index 18dabfb..09d7804 100644 (file)
@@ -133,7 +133,7 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                logger.debug(EELFLoggerDelegate.debugLogger, "http response status=" + status);
                MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE, Integer.toString(status));
                if (!isHttpSuccess(status)) {
-                       String errMsg = "Failed. Status=" + status + restPath +"; [" + ((ResponseImpl)response).getStatusInfo().getReasonPhrase().toString()
+                       String errMsg = "Failed. Status=" + status + restPath +"; [" + ((ResponseImpl)response).getStatusInfo().getReasonPhrase()
                                        + "]";
                        URL url = null;
                        try {
@@ -255,7 +255,6 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                Response response = getResponse(appId, restPath);
 
                if (response != null) {
-                       //verifyResponse(response);
                        verifyResponse(response,restPath);
                        /* It is not recommendable to use the implementation class org.apache.cxf.jaxrs.impl.ResponseImpl in the code, 
                        but had to force this in-order to prevent conflict with the ResponseImpl class of Jersey Client which 
@@ -278,13 +277,11 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                Response response = getResponse(appId, restPath);
 
                if (response != null) {
-                       //verifyResponse(response);
                        verifyResponse(response,restPath);
                        /* It is not recommendable to use the implementation class org.apache.cxf.jaxrs.impl.ResponseImpl in the code, 
                        but had to force this in-order to prevent conflict with the ResponseImpl class of Jersey Client which 
                        doesn't work as expected. Created Portal-253 for tracking  */
-                       String incomingJson = ((ResponseImpl)response).readEntity(String.class);
-                       return incomingJson;
+                       return ((ResponseImpl)response).readEntity(String.class);
                }
                
                return "";
@@ -308,7 +305,6 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                Response response = getResponse(appId, restPath);
 
                if (response != null) {
-                       //verifyResponse(response);
                        verifyResponse(response,restPath);
                        String str = ((ResponseImpl)response).readEntity(String.class);
                        EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
@@ -316,7 +312,6 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                        try {
                                t = mapper.readValue(str, clazz);
                        } catch (Exception e) {
-                               e.printStackTrace();
                                EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
                        }
                }
@@ -373,16 +368,12 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                }
 
                if (response != null) {
-                       //verifyResponse(response);
                        verifyResponse(response,restPath);
-                       // String contentType = response.getHeaderString("Content-Type");
                        if (clazz != null) {
                                String str = ((ResponseImpl)response).readEntity(String.class);
                                EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST result =", str);
                                try {
                                        t = (T) gson.fromJson(str, clazz);
-
-                                       //t = gson.fromJson(str, clazz);
                                } catch (Exception e) {
                                        EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
                                }
@@ -430,7 +421,6 @@ public class ApplicationsRestClientServiceImpl implements ApplicationsRestClient
                }
 
                if (response != null) {
-                       //verifyResponse(response);
                        verifyResponse(response,restPath);
                        String str = ((ResponseImpl)response).readEntity(String.class);
                        EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT result =", str);
index b41d898..451500d 100644 (file)
@@ -136,7 +136,6 @@ public class MicroserviceServiceImpl implements MicroserviceService {
                        dataAccessService.executeNamedQuery("deleteMicroservice", params, null);
 
                } catch (Exception e) {
-                       e.printStackTrace();
                        logger.error(EELFLoggerDelegate.errorLogger, "deleteMicroservice failed", e);
                        throw e;
                }
index e8c8d5b..7ab6cc4 100644 (file)
                        <artifactId>spring-tx</artifactId>
                        <version>${springframework.version}</version>
                </dependency>
+               <dependency> 
+                       <groupId>org.springframework</groupId> 
+                       <artifactId>spring-expression</artifactId> 
+                       <version>${springframework.version}</version> 
+               </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-context-support</artifactId>
index 99c5af4..2fc9ed3 100644 (file)
@@ -45,7 +45,7 @@
        value="<%=(SystemProperties.getProperty(SystemProperties.MOBILE_ENABLE)!= null && SystemProperties.getProperty(SystemProperties.MOBILE_ENABLE).trim().equals(\"true\"))%>" />
 
 <!DOCTYPE html>
-<html ng-app="abs">
+<html>
        <head>
                <link rel="shortcut icon" href="assets/images/1cc621d2.ecomp_logo.png">
            <title>
                <meta charset="utf-8">
                <meta http-equiv="X-UA-Compatible" content="IE=edge">
                <meta name="viewport" content="width=device-width, initial-scale=1"> 
-       <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
+               <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
                <script src="static/js/jquery-1.10.2.js" type="text/javascript"></script>
-               <script src= "static/ebz/angular_js/angular.js"></script> 
-               <script src= "static/ebz/angular_js/angular-sanitize.js"></script>
-               <script src= "static/ebz/angular_js/gestures.js"></script>
                <style>
                        .terms {
                                font-family: Verdana,Arial,Helvetica, sans-serif;
        <% 
        String frontUrl = SystemProperties.getProperty(EPSystemProperties.FE_URL);
     %>
-       <div ng-controller="externalLoginController">
+       <div>
                <div class="centered style="-webkit-transform: translateZ(0);background:white, z-index:0;">
                        <div align="center" id="errorInfo" style="display:none; float:left; font-family: Arial; font-size:12px; margin-left:5px">
                                <span style="color:red">Invalid username or password. Please try again.</span>
                                                                <label class="login-txt">Login ID:</label>
                                                        </td>
                                                        <td>
-                                                               <input type="text" class="login-input-text" ng-model="loginId" maxlength="30" />
+                                                               <input type="text" class="login-input-text" id="loginId" maxlength="30" />
                                                        </td>
                                                </tr>
                                                <tr>
                                                                <label class="login-txt">Password:</label>
                                                        </td>
                                                        <td>
-                                                               <input type="password" class="login-input-text" ng-model="password" maxlength="30" 
+                                                               <input type="password" class="login-input-text" id="password" maxlength="30" 
                                                                        onkeydown="if (event.keyCode == 13) document.getElementById('loginBtn').click()"/>
                                                        </td>
                                                </tr>
                                        </table> 
                                        <br />
-                                       <a class="login-btn" id="loginBtn" ng-click="loginExternal();">LOGIN</a>
+                                       <a class="login-btn" id="loginBtn">LOGIN</a>
                                </div>
                                <br>
                        </div>
                <br/><br/><br/><br/><br/><br/><br/>
     </div>
     </body>
-<script>
-var app=angular.module("abs", []);
-app.controller("externalLoginController", function ($scope) { 
-       // Table Data
-       
-       $scope.viewPerPage = 200;
-       $scope.currentPage = 2;
-       $scope.totalPage;
-       $scope.searchCategory = "";
-       $scope.searchString = "";
-       $scope.loginId="";
-       $scope.password="";
-       $scope.loginError=true;
-       $scope.viewPerPage = 200;
-       $scope.currentPage = 2;
-       $scope.totalPage;
-       $scope.searchCategory = "";
-       $scope.searchString = "";
-       $scope.loginId="";
-       $scope.password="";
-       $scope.loginUrl = "";
-       
-       $scope.loginExternal = function() {
-               var postData={loginId:$scope.loginId,password:$scope.password};
-               $.ajax({
-                   url: "open_source/login?",
-                type : "POST",
-                                dataType: 'json',
-                                contentType: 'application/json',
-                                data: JSON.stringify(postData),                
-                success:function (response){
-                  if(response.success=="success"){
-                    //window.location.href = 'applicationsHome';
-                    window.location.href= "<%=frontUrl%>",
-                    sessionStorage.setItem('userId',$scope.loginId)
-                  }else{
-                       $("#errorInfo span").text(response);
-                       //$("#errorInfo").text = response;
-                       $("#errorInfo").show();
-                  }
-                },
-                error:function( jqXHR, status,error ){
-                       $("#errorInfo").show();
-                }
-                
-        });
-
-    };
-});
-</script>
        
+       <script>
+               $( document ).ready(function() {
+                       $(".login-btn").click(function(){
+                               var loginIdVal = $("#loginId").val();
+                               var passwordVal = $("#password").val();
+                               var postData={loginId:loginIdVal,password:passwordVal};
+                               $.ajax({
+                                       url: "open_source/login?",
+                                       type : "POST",
+                                       dataType: 'json',
+                                       contentType: 'application/json',
+                                       data: JSON.stringify(postData),                
+                                       success:function (response){
+                                         if(response.success=="success"){
+                                               //window.location.href = 'applicationsHome';
+                                               window.location.href= "<%=frontUrl%>",
+                                               sessionStorage.setItem('userId',loginIdVal)
+                                         }else{
+                                               $("#errorInfo span").text(response);
+                                               //$("#errorInfo").text = response;
+                                               $("#errorInfo").show();
+                                         }
+                                       },
+                                       error:function( jqXHR, status,error ){
+                                               $("#errorInfo").show();
+                                       }
+                                               
+                               });
+                       });
+               });
+       </script>
 </html>
diff --git a/pom.xml b/pom.xml
index 3fe2b71..e26a406 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,7 @@
                <!-- <sonar.exclusions>**/scripts/**/*,**.js</sonar.exclusions>  -->
                <sonar.test.exclusions>**/test/**/*,**/tests/**/*</sonar.test.exclusions>
                <enforcer.skip>false</enforcer.skip>
+               <sonar.scm.exclusions.disabled>true</sonar.scm.exclusions.disabled>
        </properties>
 
        <!-- Specify the repositories here to avoid coordination of ~/.m2/settings.xml 
index 6caf2dd..47a53cd 100644 (file)
@@ -41,6 +41,8 @@
             <a class="footer-link" href="{{footerLink}}" target="_blank">
             {{footerLinkText}}</a> {{footerMessage}}
             {{brandName}} Version: {{buildVersion}}
-      <h2 style="color:white; text-align: center;" class="logo-title"> <img src="{{footerLogoImagePath}}"> {{footerLogoText}}</h2>
+      <h2 style="color:white; text-align: center;" class="logo-title"> 
+        <img *ngIf="(footerLogoImagePath !='')" src="{{footerLogoImagePath}}"> {{footerLogoText}}
+      </h2>
       </div>   
 </footer>
\ No newline at end of file
index 9d7559e..422a673 100644 (file)
@@ -69,7 +69,6 @@ export class FooterComponent implements OnInit {
     this.footerLink = this.api.footerLink;
     this.footerLinkText = this.api.footerLinkText;
     this.footerMessage= this.api.footerMessage;
-    this.footerLogoImagePath = "assets/images/global.logo"
     if(this.api.footerLogoImagePath !=''){
       this.footerLogoImagePath= this.api.footerLogoImagePath;
     }
index e0df154..1ecba2c 100644 (file)
@@ -42,17 +42,59 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { FormsModule } from '@angular/forms';
 import { NgMaterialModule } from 'src/app/ng-material-module';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { WidgetOnboardingService } from 'src/app/shared/services/widget-onboarding/widget-onboarding.service';
+import { Observable } from 'rxjs';
+import { HttpClientModule } from '@angular/common/http';
 
 describe('WidgetOnboardingComponent', () => {
   let component: WidgetOnboardingComponent;
   let fixture: ComponentFixture<WidgetOnboardingComponent>;
+  let widgetList = [{"id" :"1",
+    "name":"ONAP-A",
+    "desc" :"desc",
+    "fileLocation" : "fileLocation",
+    "allowAllUser" : "allowAllUser",
+    "serviceId" : "serviceId",
+    "serviceURL" : "serviceURL",
+    "sortOrder" : "sortOrder",
+    "statusCode" : "statusCode",
+    "widgetRoles": "widgetRoles",
+    "appContent" : "appContent",
+    "appName" : "appName",
+    "file"  : "file",
+    "allUser": false,
+    "saving": "saving"},{"id" :"1",
+    "name":"ONAP-B",
+    "desc" :"desc",
+    "fileLocation" : "fileLocation",
+    "allowAllUser" : "allowAllUser",
+    "serviceId" : "serviceId",
+    "serviceURL" : "serviceURL",
+    "sortOrder" : "sortOrder",
+    "statusCode" : "statusCode",
+    "widgetRoles": "widgetRoles",
+    "appContent" : "appContent",
+    "appName" : "appName",
+    "file"  : "file",
+    "allUser": false,
+    "saving": "saving"}]
+
 
   beforeEach(async(() => {
+    let widgetOnboardingService: WidgetOnboardingService;
+    
+   // widgetOnboardingService = jasmine.createSpyObj('WidgetOnboardingService', ['getManagedWidgets']);
+    //widgetOnboardingService.getManagedWidgets.and.returnValue(Observable.of(widgetList));
     TestBed.configureTestingModule({
       declarations: [ WidgetOnboardingComponent ],
-      imports:[HttpClientTestingModule,FormsModule,NgMaterialModule,BrowserAnimationsModule],
+      imports:[HttpClientModule,FormsModule,NgMaterialModule,BrowserAnimationsModule],
+      providers:[WidgetOnboardingService]
     })
     .compileComponents();
+
+
+    widgetOnboardingService = TestBed.get(WidgetOnboardingService);
+    spyOn(widgetOnboardingService, 'getManagedWidgets').and.returnValue(Observable.of(widgetList));
   }));
 
   beforeEach(() => {
@@ -61,7 +103,14 @@ describe('WidgetOnboardingComponent', () => {
     fixture.detectChanges();
   });
 
+  
+
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+  it('getOnboardingWidgets should return stubbed value', () => {
+    spyOn(component, 'getOnboardingWidgets').and.callThrough();
+    component.getOnboardingWidgets();
+    expect(component.getOnboardingWidgets).toHaveBeenCalledWith();
+  });
 });
index ba1842f..930d598 100644 (file)
@@ -5,29 +5,29 @@
  * Copyright © 2019 AT&T Intellectual Property. All rights reserved.
  * ===================================================================
  *
- * Unless otherwise specified?: any; all software contained herein is licensed
- * under the Apache License?: any; Version 2.0 (the "License");
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
  * you may not use this software except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *             http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing?: any; software
- * distributed under the License is distributed on an "AS IS" BASIS?: any;
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND?: any; either express or implied.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- * Unless otherwise specified?: any; all documentation contained herein is licensed
- * under the Creative Commons License?: any; Attribution 4.0 Intl. (the "License");
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
  * you may not use this documentation except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *             https://creativecommons.org/licenses/by/4.0/
  *
- * Unless required by applicable law or agreed to in writing?: any; documentation
- * distributed under the License is distributed on an "AS IS" BASIS?: any;
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND?: any; either express or implied.
+ * Unless required by applicable law or agreed to in writing, documentation
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
@@ -51,4 +51,4 @@ export interface IWidget {
     file  ?: any;
     allUser ?: boolean;
     saving ?: any
-}
\ No newline at end of file
+}
index 77cef69..4371bc4 100644 (file)
     "jasmine-core": "~2.99.1",
     "jasmine-spec-reporter": "~4.2.1",
     "karma": "~3.0.0",
-    "karma-chrome-launcher": "~2.2.0",
+    "karma-chrome-launcher": "^2.2.0",
     "karma-coverage-istanbul-reporter": "~2.0.1",
     "karma-jasmine": "~1.1.2",
     "karma-jasmine-html-reporter": "^0.2.2",
+    "karma-phantomjs-launcher": "^1.0.4",
     "protractor": "~5.4.0",
+    "puppeteer": "^2.1.1",
     "sonar-scanner": "^3.1.0",
     "ts-node": "~7.0.0",
     "tslint": "~5.11.0",
index 21bdd50..fd497e1 100644 (file)
@@ -4,7 +4,7 @@
 
        <groupId>org.onap.portal</groupId>
        <artifactId>portal-FE-os</artifactId>
-       <version>3.1.0</version>
+       <version>3.2.0</version>
 
        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -18,6 +18,7 @@
                <sonar.test.inclusions>**/*.spec.ts</sonar.test.inclusions>
                <sonar.tests>src</sonar.tests>
                <sonar.sourceEncoding>UTF-8</sonar.sourceEncoding>
+               <sonar.nodejs.executable>${project.basedir}\node\</sonar.nodejs.executable>
        </properties>
 
        <build>
index b6e0042..154ad58 100644 (file)
@@ -1,6 +1,7 @@
 // Karma configuration file, see link for more information
 // https://karma-runner.github.io/1.0/config/configuration-file.html
 
+process.env.CHROME_BIN = require('puppeteer').executablePath()
 module.exports = function (config) {
   config.set({
     basePath: '',
@@ -10,6 +11,7 @@ module.exports = function (config) {
       require('karma-chrome-launcher'),
       require('karma-jasmine-html-reporter'),
       require('karma-coverage-istanbul-reporter'),
+      require('karma-phantomjs-launcher'),
       require('@angular-devkit/build-angular/plugins/karma')
     ],
     client: {
@@ -25,7 +27,7 @@ module.exports = function (config) {
     colors: true,
     logLevel: config.LOG_INFO,
     autoWatch: true,
-    browsers: ['Chrome'],
+    browsers: ['ChromeHeadless'],
     singleRun: false
   });
 };
\ No newline at end of file