DevSecOps

29 ago, 2018

Continuous Integration – Integrando seu front-end Angular no Visual Studio Team Services

Publicidade

Fala, galera!

Neste artigo mostrarei como podemos integrar nosso Front-end dentro do Visual Studio Team Services (VSTS), não somente integrar mas também como podemos ter um processo de Continuous Integration com execução de testes de unidade usando Jasmine, minificação de arquivos JavaScript com Gulp.

O que é Visual Studio Team Services

É uma solução baseada na nuvem para desenvolvedores que serve para controlar o Life Cycle de uma aplicação (ALM) que vai desde repositórios de códigos hospedado a acompanhamento de problemas de carga e compilações automatizadas (Builds). Como VSTS é uma solução na nuvem, pode ser acessado em qualquer lugar. Para usar, basta criar uma conta gratuitamente e nesta conta você pode incluir até cinco usuários. Crie sua conta grátis clicando aqui.

Neste exemplo vamos integrar nossa aplicação Front-end ao Visual Studio Team Services. Nesta integração vamos configurar o Continuos Integration da nossa aplicação e executar testes de unidade usando Jasmine e Karma JS para executar tarefas automatizadas no Gulp para minificação dos arquivos JavaScript.

Neste exemplo estou usando uma aplicação AngularJS na sua versão 1.6.x. Essa aplicação consome a API do GitHub; seu código fonte pode se encontrado no meu GitHub através deste link. Para testar a aplicação basta abrir um terminal de comando e digitar o seguinte comando:

npm install
npm run start-server

Configurando o Gulp para execução de tarefas

Vamos configurar o Gulp para automatizar o processo de minificação dos arquivos JavaScript. Abra o arquivo package.json e coloque a importação do Gulp como dependência do nosso projeto. Além do Gulp, também colocaremos os pacotes necessários para a minificação dos arquivos JavaScript conforme o exemplo abaixo:

"dependencies": {
    "jquery": "3.2.1",
    "bootstrap": "^3.3.7",
    "angular": "^1.6.6",
    "angular-resource": "^1.6.6",
    "angular-ui-router": "^1.0.3",
    "angular-mocks": "^1.6.10",
    "lite-server": "^2.3.0",
    "gulp": "3.9.1",
    "gulp-util": "3.0.8",
    "gulp-uglify": "3.0.0",
    "gulp-concat": "2.6.1",
    "gulp-rename": "1.2.2",
    "gulp-sourcemaps": "2.6.4",
    "gulp-plumber": "1.2.0",
    "run-sequence": "2.2.1"
}

Após fazer a alteração, abra o terminal e execute o comando npm install, assim vamos instalar localmente o Gulp e suas dependências para conseguirmos executar a tarefa de minificação. Feito isso, vamos criar um arquivo novo chamado gulpfile.js e colocar a tarefa de minificação dos nosso arquivos Javascript conforme exemplo de código abaixo:

var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
var plumber = require('gulp-plumber');
var runSequence = require('run-sequence');
gulp.task('minificar-scripts', function () {
    return gulp.src([
                      'app/**/*-module.js',
                      '!app/tests/**/*.js',
                      'app/**/*.js',
                    ])
               .pipe(plumber())      
               .pipe(sourcemaps.init())      
               .pipe(concat('app-github.js'))
               .pipe(gulp.dest('dist/app'))
               .pipe(uglify())
               .pipe(rename({ extname: ".min.js"}))
               .pipe(sourcemaps.write('.'))
               .pipe(gulp.dest('dist/app'));
});
gulp.task('watch', function(){
   var watcher = gulp.watch('app/**/*.js',['minificar-scripts']);
   watcher.on( 'change', function( event ) {
        console.log( 'File ' + event.path + ' was ' + event.type );
    });
});
gulp.task('default', ['minificar-scripts']);

Configurando o Jasmine e Karma Runner para execução de Testes de Unidade

Neste ponto, estamos com o automatizador de tarefas Gulp configurado. Temos que configurar o Jasmine e o Karma Runner para executar teste de unidade no nosso projeto. O Jasmine é um Framework de teste de unidade para JavaScript e o Karma Runner é a biblioteca de execução de teste de unidade.

Primeiro devemos abrir o package.json e adicionar as dependências para rodar o Jasmine e o Karma. Adicione as dependências conforme código abaixo:

"dependencies": {
    "jquery": "3.2.1",
    "bootstrap": "^3.3.7",
    "angular": "^1.6.6",
    "angular-resource": "^1.6.6",
    "angular-ui-router": "^1.0.3",
    "angular-mocks": "^1.6.10",
    "lite-server": "^2.3.0",
    "gulp": "3.9.1",
    "gulp-util": "3.0.8",
    "gulp-uglify": "3.0.0",
    "gulp-concat": "2.6.1",
    "gulp-rename": "1.2.2",
    "gulp-sourcemaps": "2.6.4",
    "gulp-plumber": "1.2.0",
    "run-sequence": "2.2.1",
    "jasmine-core": "2.6.4",
    "karma": "1.7.1",
    "karma-jasmine": "1.1.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-jasmine-html-reporter": "0.2.2",
    "karma-junit-reporter": "1.2.0",
    "karma-phantomjs-launcher": "1.0.4",
    "phantom": "4.0.5"
}

Vamos configurar o Karma Runner. Para isso, crie um novo arquivo chamado karma.config.js e adicione o código abaixo:

module.exports = function (config) {
  config.set({
        basePath: '',
        frameworks: ['jasmine'],
         files: [
           'node_modules/jquery/dist/jquery.min.js',
           'node_modules/angular/angular.min.js',
           'node_modules/angular-mocks/angular-mocks.js',
           'node_modules/angular-resource/angular-resource.min.js',
           'app/app-module.js',
           'app/factory/github-resource.js',
           'app/user-controller.js',
           'app/user-repository-controller.js',
           'app/tests/**/*.js'
        ],
        exclude: [
        ],
        preprocessors: {
        },
        reporters: ['progress', 'dots', 'kjhtml', 'junit'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_DISABLE,
        autoWatch: true,
        browsers: ['Chrome', 'PhantomJS'],
        singleRun: false,
        concurrency: 0,
        plugins: [
            'karma-jasmine',
            'karma-chrome-launcher',
            'karma-jasmine-html-reporter',
            'karma-phantomjs-launcher',
            'karma-junit-reporter',
        ],
        client: {
            captureConsole: false
        },
        junitReporter: {
            outputDir: 'testresults',
            outputFile: 'testResult.xml'
        }
    });
};

Com o nosso arquivo karma.config.js configurado, abra o packages.config e adicione o comando no qual faremos o Karma Runner ser executado.

Adicione o comando conforme o código abaixo:

"scripts": {
  "karma-test": "karma start karma.config.js --browsers Chrome --reporters kjhtml,dots",
"tfs-karma-test": "karma start karma.config.js --browsers PhantomJS --auto-watch=false  --single-run=true --reporters=progress,dots,junit"
},

Para testar o Karma Runner, abra um terminal e digite:

npm install
npm run karma-test

Configurando o Jasmine, o framework de Testes de Unidade

Agora vamos configurar o Jasmine. Para isso criaremos testes de unidade para os nossos arquivos JavaScript. Neste exemplo testaremos o Controller de busca de usuário de GitHub.

Configuramos o Karma para executar todos os testes contidos na pasta app/tests; dessa forma, basta criarmos nossos testes de unidade dentro desta pasta. Para isso criaremos um arquivo chamado user-controller-specs.js e adicionaremos o código abaixo:

describe('Teste de Unidade de Busca de Usuário', function () {
    var $controller;
    var $scope;
    var resource;
    var $rootScope;
    var $q;
    function construirController() {
        var controller = $controller('userController', {
            $scope: $scope,
            githubResource: resource,
        });
        return controller;
    }
    beforeEach(function () {
        angular.mock.module('githubapp');
        angular.mock.inject(function (_$controller_, _$rootScope_, _githubResource_, _$q_) {
            resource = _githubResource_;
            $controller = _$controller_;
            $rootScope = _$rootScope_;
            $scope = _$rootScope_.$new();
            $q = _$q_;
        });
    });
    it('Deverá incicializar corretamente a controller', function () {
        $controller = construirController();
        expect($controller).not.toBe(null);
    });
    it ('Devera buscar usuário do github', function(){
        $controller = construirController();
        $scope.vm = {
            username: "rafaelcruz_net"
        };
        spyOn(resource.User, 'search').and.callFake(function(args){
            var response = {};
            response.items = [
                {
                    login: "rafaelcruz_net"
                }
            ];
            var deferred = $q.defer();
            deferred.resolve(response);
            return { $promise: deferred.promise };
   
        });
        $scope.buscarUsuario();
        expect($scope.vm).toBeDefined();
    });
});

Para testar nossos testes, execute em um terminal o seguinte comando:

npm run karma-test

Se tudo ocorrer bem, devemos ver uma tela conforme abaixo:

Configurando o Visual Studio Team Services

Após todas as configurações locais funcionando, vamos configurar nosso Build (CI) para executar as tarefas. Para isso, clique no menu Build and Release e clique no botão “New Definition“, conforme a imagem abaixo:

Vamos criar nossas tarefas para fazer o nosso CI do front-end

Neste caso, estou usando o próprio Git do Visual Studio Team Services, mas como podemos ver, temos diversas opções de integração: desde o GitHub até uma fonte externa do Git.

Na próxima tela, escolha a opção “Empty Process“. Vamos adicionar a primeira tarefa que seria a instalação dos pacotes do NPM, conforme a imagem abaixo:

Vamos colocar a segunda tarefa que é a execução dos testes de unidade conforme imagem abaixo:

A terceira tarefa é a minificação dos nosso arquivos. Vamos adicionar uma tarefa de Gulp conforme a imagem abaixo:

Por último, vamos publicar o resultado dos nossos testes:

Clique em “Save & Queue“; com isso nosso build irá disparar uma execução. Ao final da execução devemos ter o resultado dos testes conforme a imagem abaixo:

Quando executamos um teste que falha, o nosso Build sinaliza o teste que falhou conforme imagem abaixo:

Como podemos ver, nosso front-end Angular está todo integrado ao Visual Studio Team Services. Agora a cada push que fizermos no Git, ele vai disparar um novo Build e executar essas tarefas.

Abraços e até a próxima!