├── .gitignore ├── README.md ├── package.json └── quality_assurance ├── conf.js ├── environments_parameters.json └── features ├── hooks └── hooks.js ├── page_objects └── angular_po.js ├── protractor_example.feature ├── shared_libs ├── helper.js └── package.json └── step_definitions └── angular_steps.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Shared between .npmignore and .gitignore 2 | 3 | yarn.lock 4 | chromedriver.log 5 | libpeerconnection.log 6 | xmloutput* 7 | npm-debug.log 8 | .idea/ 9 | .vscode/ 10 | *.DS_Store 11 | *.swp 12 | selenium/ 13 | 14 | # Build artifacts 15 | 16 | built/ 17 | spec/built/ 18 | node_modules/ 19 | website/bower_components/ 20 | website/build/ 21 | website/docgen/build/ 22 | screenshots/ 23 | results.json/ 24 | cucumber_report.html/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PROTRACTOR-FOR-STUDIES 2 | 3 | Repositório destinado para aprendermos a usar testes automatizados com o Protractor e o CucumberJS 4 | 5 | ## Pré-requisitos para rodar localmente 6 | * [Intalação do node](https://nodejs.org/en/download/) 7 | * [Intalação do npm](https://www.npmjs.com/get-npm) 8 | * [Intalação do protractor](https://www.npmjs.com/package/protractor) 9 | 10 | #### Atenção: É necessário que a máquina esteja com todas as dependencias instaladas: 11 | * Usar o comando abaixo onde existam os arquivos `package.json` 12 | 13 | ```npm install``` ou ```npm run simple_build``` 14 | 15 | (raíz: `/protractor_for_studies` e na pasta: `/shared_libs`) 16 | 17 | ## Iniciando os passos para rodar os testes 18 | * Entrar pelo terminal na raíz do projeto 19 | * Usar o comando ```npm run start_update_webdriver``` 20 | 21 | #### Atenção 2: Será necessário abrir outra aba do terminal para que o servidor consiga trabalhar na aba antiga. 22 | 23 | ## Rodando os testes de regressão 24 | 25 | * Entrar na raíz do projeto `/protractor_for_studies` 26 | * Usar o comando ```npm run test``` 27 | 28 | Ou podemos seguir esse caminho abaixo. 29 | * Entrar na a pasta `/quality_assurance` 30 | * Usar o comando ```protractor conf.js``` 31 | 32 | 33 | #### Atenção 3: Vale lembrar que o arquivo `conf.js` encontra-se com um campo chamado *tag* onde é possível escolher um determinado cenário apenas. Nesse script ele está ativo para rodar toda a funcionalidade @learning 34 | 35 | ## Resumindo o projeto 36 | * A pasta principal é a `quality_assurance` e dentro dela temos a `features` 37 | * `protractor_example.feature` são nossos cenários de exemplo 38 | * `page_objetcs` ficam nossos elementos e métodos da página 39 | * `step_definitions` são nossos steps gerados pelo cucumber 40 | * `report` será uma a pasta onde o cucumber colocará o report.html (caso não exista, ele criará ao final dos testes) 41 | * `shared_libs` são métodos auxiliáres que podemos usar dentro de todo o projeto 42 | * `conf.js` nosso arquivo de configuração 43 | * `environments_parameters.json` são nossas urls e ambientes 44 | * `package.json` arquivo com nossas dependências e os scripts 45 | 46 | ------------------------------------- 47 | #### Dúvidas: lucass.fragaa@gmail.com 48 | 49 | ###### Skype: live:lucass.fragaa 50 | 51 | ------------------------------------- 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quality_assurance_protractor", 3 | "version": "1.0.0", 4 | "description": "Projeto de testes", 5 | "devDependencies": { 6 | "chai": "^4.2.0", 7 | "chai-as-promised": "^7.1.1", 8 | "cucumber": "^5.0.2", 9 | "cucumber-html-reporter": "^4.0.4", 10 | "protractor": "^5.4.1", 11 | "protractor-cucumber-framework": "^6.1.1", 12 | "protractor-cucumber-steps": "^1.3.2", 13 | "standard": "^12.0.1" 14 | }, 15 | "main": "protractor conf.js", 16 | "scripts": { 17 | "test": "cd ./quality_assurance && protractor conf.js", 18 | "static_fix": "standard --fix", 19 | "start_update_webdriver": "webdriver-manager update && webdriver-manager start --detach --seleniumPort=4444", 20 | "simple_build": "cd ../protractor_basic && npm install", 21 | "run_local_test": "npm run simple_build && export TEST_ENV=local && npm run test", 22 | "run_stop_webdriver": "kill -9 $(lsof -ti tcp:4444)" 23 | }, 24 | "standard": { 25 | "globals": [] 26 | }, 27 | "author": "Lucas Fraga", 28 | "license": "MIT", 29 | "dependencies": { 30 | "chromedriver": "^2.43", 31 | "yarn": "^1.10.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /quality_assurance/conf.js: -------------------------------------------------------------------------------- 1 | const Data = require('./environments_parameters.json') 2 | 3 | const TEST_ENV = process.env.TEST_ENV || 'local' 4 | let environmentParameters 5 | 6 | switch (TEST_ENV) { 7 | case 'local': 8 | environmentParameters = Data[0].local 9 | break 10 | } 11 | 12 | exports.config = { 13 | seleniumAddress: environmentParameters.seleniumAddress, 14 | ignoreUncaughtExceptions: true, 15 | framework: 'custom', 16 | frameworkPath: require.resolve('protractor-cucumber-framework'), 17 | restartBrowserBetweenTests: false, 18 | getPageTimeout: 50000, 19 | allScriptsTimeout: 30000, 20 | rootElement: '*[ng-app]', 21 | baseUrl: environmentParameters.baseUrl, 22 | params: { 23 | 24 | }, 25 | 26 | specs: [ 27 | 'features/*.feature' 28 | ], 29 | 30 | exclude: [ 31 | ], 32 | 33 | capabilities: { 34 | 'browserName': 'chrome', 35 | chromeOptions: { 36 | args: [ 37 | '--disable-gpu' 38 | ] 39 | } 40 | }, 41 | 42 | cucumberOpts: { 43 | require: '../features/step_definitions/*.js', 44 | tags: ['~@notImplemented'], 45 | format: ['json:results.json'], 46 | profile: false, 47 | 'no-source': true 48 | }, 49 | 50 | beforeLaunch: function () { 51 | setTimeout(function () { 52 | browser.driver.executeScript(function () { 53 | return { 54 | width: window.screen.availWidth, 55 | height: window.screen.availHeight 56 | } 57 | }).then(function (result) { 58 | browser.driver.manage().window().setSize(result.width, result.height) 59 | }) 60 | }) 61 | }, 62 | 63 | onPrepare: function () { 64 | // Use only for angular applications 65 | // False: app Angular 66 | // True: app not Angular 67 | browser.ignoreSynchronization = false 68 | }, 69 | 70 | afterLaunch: function () { 71 | var reporter = require('cucumber-html-reporter') 72 | 73 | var options = { 74 | theme: 'bootstrap', 75 | jsonFile: 'results.json', 76 | output: 'report/cucumber_report.html', 77 | reportSuiteAsScenarios: true, 78 | launchReport: true, 79 | storeScreenshots: false, 80 | metadata: { 81 | 'App Version': '0.0.1', 82 | 'Test Environment': 'STAGING', 83 | 'Browser': 'Chrome 69.0.3497.100', 84 | 'Platform': 'OSX', 85 | 'Parallel': 'Scenarios', 86 | 'Executed': 'Remote' 87 | } 88 | } 89 | reporter.generate(options) 90 | } 91 | } -------------------------------------------------------------------------------- /quality_assurance/environments_parameters.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "local": { 3 | "seleniumAddress": "http://localhost:4444/wd/hub", 4 | "baseUrl": "https://angularjs.org" 5 | } 6 | }] 7 | -------------------------------------------------------------------------------- /quality_assurance/features/hooks/hooks.js: -------------------------------------------------------------------------------- 1 | const wait_sec = 1000; 2 | const { BeforeAll, After, Status } = require("cucumber"); 3 | 4 | BeforeAll({ timeout: 60 * wait_sec }, async function () { 5 | console.log("\nStart executing tests ....") 6 | }); 7 | 8 | After(async function (scenario) { 9 | let world = this; 10 | if (scenario.result.status === Status.FAILED) { 11 | return await browser.takeScreenshot().then(function (buffer) { 12 | return world.attach(buffer, "image/png"); 13 | }); 14 | } 15 | }); -------------------------------------------------------------------------------- /quality_assurance/features/page_objects/angular_po.js: -------------------------------------------------------------------------------- 1 | const Helper = require('../shared_libs/helper.js') 2 | 3 | class AngularPage { 4 | constructor () { 5 | this.helper = new Helper() 6 | this.inputName = $('input[ng-model="yourName"]') 7 | this.inputSearch = $('input[id="projects_search"]') 8 | this.resultText = $('h1[class="ng-binding"]') 9 | } 10 | 11 | open (link) { 12 | return browser.get(link) 13 | } 14 | 15 | fillText (text) { 16 | this.helper.elementIsPresenceDom(this.inputName) 17 | return this.inputName.sendKeys(text) 18 | } 19 | } 20 | 21 | module.exports = AngularPage -------------------------------------------------------------------------------- /quality_assurance/features/protractor_example.feature: -------------------------------------------------------------------------------- 1 | #language: en 2 | 3 | @example 4 | Feature: Learning to use Protractor 5 | As a QA 6 | I want to learn how to use Protractor 7 | To be able to automate angular applications 8 | 9 | Scenario Outline: Validate texts in angular.org website 10 | Given Im on the page 11 | When I fill in the text field with "" 12 | Then I checked that the text "Hello !" was successfully validated 13 | 14 | Examples: 15 | | name | 16 | | Concrete | 17 | | QA Analyst | 18 | | Any Name | -------------------------------------------------------------------------------- /quality_assurance/features/shared_libs/helper.js: -------------------------------------------------------------------------------- 1 | var until = protractor.ExpectedConditions 2 | var fs = require('fs') 3 | var Buffer = require('safe-buffer').Buffer 4 | const {setDefaultTimeout} = require('cucumber') 5 | setDefaultTimeout(60 * 1000) 6 | 7 | var Helper = function () {} 8 | 9 | // Wait to see if element is on DOM 10 | Helper.prototype.elementIsPresenceDom = function (element) { 11 | browser.wait(until.presenceOf(element), 25000, 'Element ' + element.getText() + ' taking too long to appear in the DOM') 12 | browser.executeScript('arguments[0].scrollIntoView();', element.getWebElement()) 13 | } 14 | 15 | // Wait to see if element is clickable 16 | Helper.prototype.elementIsClickable = function (element) { 17 | browser.wait(until.elementToBeClickable(element), 50000, 'Element taking too long to appear in the DOM and stay clickable') 18 | } 19 | 20 | // Wait to see if element is visible 21 | Helper.prototype.elementIsVisible = function (element) { 22 | browser.wait(until.visibilityOf(element), 10000, 'Element taking too long to appear in the DOM and stay visible') 23 | } 24 | 25 | // Wait to see if element is not attache to the DOM 26 | Helper.prototype.elementIsNotAttachedOnDom = function (element) { 27 | browser.wait(until.stalenessOf(element), 10000, 'Element appeared in DOM') 28 | } 29 | 30 | // Wait to see if element is not present of DOM 31 | Helper.prototype.elementIsNotPresentOfDom = function (element) { 32 | return browser.wait(until.not(until.presenceOf(element))) 33 | } 34 | 35 | // Force the browser to stop 36 | Helper.prototype.stopBrowser = function (time) { 37 | browser.sleep(time) 38 | } 39 | 40 | // Wait for dropdown list elements load 41 | Helper.prototype.waitForCount = function (elementArrayFinder, expectedCount) { 42 | return function () { 43 | return elementArrayFinder.count().then(function (actualCount) { 44 | return expectedCount === actualCount // or <= instead of ===, depending on the use case 45 | }) 46 | } 47 | } 48 | 49 | // Wait for all elements the array of webelements 50 | Helper.prototype.presenceOfAll = function (elementArrayFinder) { 51 | return function () { 52 | return elementArrayFinder.count(function (count) { 53 | return count > 0 54 | }) 55 | } 56 | } 57 | 58 | // This function take a screenshot and save in directory screenshots_atual 59 | Helper.prototype.getScreenshot = function (nomeArquivo) { 60 | function writeScreenShot (data, filename) { 61 | var stream = fs.createWriteStream(filename) 62 | stream.write(Buffer.from(data, 'base64')) 63 | stream.end() 64 | } 65 | return browser.takeScreenshot().then((png) => { 66 | writeScreenShot(png, './features/screenshots_atual/' + nomeArquivo + '.png') 67 | }) 68 | } 69 | 70 | // This function make scrool to down on page 71 | Helper.prototype.scrollPageDown = function (valuePixels) { 72 | browser.executeScript('window.scrollBy(0,' + valuePixels + ');') 73 | } 74 | 75 | // Check if an array is ascending ordered - V2 76 | Helper.prototype.stringArrayIsAscendingOrdered = function (data) { 77 | for (let i = 0; i < data.length - 1; i++) { 78 | if (data[i].localeCompare(data[i + 1]) > 0) { 79 | return false 80 | } 81 | } 82 | return true 83 | } 84 | 85 | // Check if an array is descending ordered - V2 86 | Helper.prototype.stringArrayIsDescendingOrdered = function (data) { 87 | for (let i = 0; i < data.length - 1; i++) { 88 | if (data[i].localeCompare(data[i + 1]) < 0) { 89 | return false 90 | } 91 | } 92 | return true 93 | } 94 | 95 | Helper.prototype.numberArrayIsOrdered = function (a, b) { 96 | 'use strict' // optional. 97 | // -------------------------------------------- 98 | // a is the array input to be tested. 99 | // -------------------------------------------- 100 | // b is optional. 101 | // Undefined b (or other value besides 1) for ascending sequence. 102 | // b === 1 for descending sequence test. 103 | // -------------------------------------------- 104 | var m = 0 // counter for loop. 105 | var currentNum 106 | var nextNum 107 | var result = a 108 | var test 109 | 110 | if (a !== undefined) { 111 | if (a.constructor === Array) { // check if input a is array object. 112 | result = true 113 | while (m < a.length) { // loop through array elements. 114 | currentNum = a[m] 115 | nextNum = a[m + 1] 116 | if (typeof currentNum === 'number' && 117 | typeof nextNum === 'number') { 118 | if (b === 1) { 119 | test = currentNum <= nextNum // descending. 120 | } else { 121 | test = currentNum >= nextNum // ascending. 122 | } 123 | if (test) { // found unordered/same elements. 124 | result = false 125 | break 126 | } 127 | } 128 | m += 1 129 | } 130 | } 131 | } 132 | return result 133 | } 134 | 135 | module.exports = Helper 136 | -------------------------------------------------------------------------------- /quality_assurance/features/shared_libs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shared_libs", 3 | "version": "1.0.0", 4 | "description": "pasta com arquivos para serem compartilhados entre projetos", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "Lucas Fraga", 9 | "license": "ISC", 10 | "dependencies": { 11 | "fs": "0.0.1-security", 12 | "safe-buffer": "^5.1.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /quality_assurance/features/step_definitions/angular_steps.js: -------------------------------------------------------------------------------- 1 | const { Given, When, Then } = require('cucumber') 2 | const expect = require('chai').use(require('chai-as-promised')).expect 3 | 4 | const AngularPage = require('../page_objects/angular_po') 5 | const page = new AngularPage() 6 | 7 | Given('Im on the page', async function () { 8 | await page.open('/') 9 | }) 10 | 11 | When('I fill in the text field with {string}', async function (name) { 12 | await page.fillText(name) 13 | }) 14 | 15 | Then('I checked that the text {string} was successfully validated', async function (text) { 16 | await expect(page.resultText.getText()) 17 | .to.eventually.equal(text) 18 | }) --------------------------------------------------------------------------------