├── .DS_Store ├── LICENSE ├── README.md ├── RestAssured ├── pom.xml ├── src │ ├── main │ │ └── java │ │ │ └── massa │ │ │ └── Massa.java │ └── test │ │ ├── java │ │ ├── runner │ │ │ └── Runner.java │ │ └── stepDefinitions │ │ │ └── Step.java │ │ └── resources │ │ └── testesFuncionais │ │ └── Teste.feature └── target │ ├── classes │ └── massa │ │ └── Massa.class │ ├── report-html │ ├── formatter.js │ ├── index.html │ ├── jquery-3.4.1.min.js │ ├── report.js │ └── style.css │ └── test-classes │ ├── runner │ └── Runner.class │ ├── stepDefinitions │ └── Step.class │ └── testesFuncionais │ └── Teste.feature ├── appium-java ├── .gitignore └── appium-maven │ ├── .gitignore │ ├── README.md │ ├── apps │ └── Appium.apk │ ├── capabilities │ ├── android-fisico.json │ ├── android-oreo-dev.json │ ├── iphone-8-dev.json │ └── iphone-fisico.json │ ├── massa │ └── data │ │ └── teste.json │ ├── pom.xml │ ├── resources │ └── features │ │ └── teste.feature │ └── src │ └── test │ └── java │ └── br │ └── com │ └── appium │ └── teste │ ├── cucumber │ └── runner │ │ └── CucumberRunnerTest.java │ ├── screens │ ├── base │ │ └── BaseScreen.java │ └── login │ │ └── InitialScreen.java │ ├── steps │ └── definitions │ │ └── TesteSteps.java │ └── test │ ├── constants │ └── Constants.java │ ├── devices │ └── capabilities │ │ ├── AndroidDevicesCapabilities.java │ │ └── IOSDevicesCapabilities.java │ └── utils │ ├── Commons.java │ ├── DriverFactoryManager.java │ ├── Print.java │ └── Utils.java ├── appium-ruby ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── android_appium.txt ├── build │ ├── .DS_Store │ ├── apk │ │ └── app-debug.apk │ └── ipa │ │ ├── .DS_Store │ │ └── WebViewApp.app │ │ ├── Default-568h@2x.png │ │ ├── Default.png │ │ ├── Default@2x.png │ │ ├── Info.plist │ │ ├── PkgInfo │ │ ├── WebViewApp │ │ ├── cybervillainsCA.cer │ │ └── en.lproj │ │ ├── InfoPlist.strings │ │ ├── MainStoryboard_iPad.storyboardc │ │ ├── Info.plist │ │ ├── UIViewController-qCV-AS-rCm.nib │ │ └── qCV-AS-rCm-view-Thv-qS-DhF.nib │ │ └── MainStoryboard_iPhone.storyboardc │ │ ├── 2-view-3.nib │ │ ├── Info.plist │ │ └── UIViewController-2.nib ├── caps_android │ ├── mars.txt │ ├── nougat.txt │ └── oreo.txt ├── comandos.md ├── config │ ├── .DS_Store │ ├── cucumber.yml │ └── ios │ │ ├── build_app.rb │ │ └── build_app.yml ├── features │ ├── .DS_Store │ ├── android │ │ ├── .DS_Store │ │ ├── android_screen_base.rb │ │ ├── features │ │ │ └── .DS_Store │ │ ├── screens │ │ │ ├── .DS_Store │ │ │ └── lista_filmes_screen.rb │ │ └── support │ │ │ └── hooks.rb │ ├── ios │ │ ├── .DS_Store │ │ ├── features │ │ │ └── acessar_site.feature │ │ ├── ios_screen_base.rb │ │ ├── screens │ │ │ ├── .DS_Store │ │ │ └── acessar_site_screen.rb │ │ ├── step_definitions │ │ │ └── acessar_site_steps.rb │ │ └── support │ │ │ └── hooks.rb │ ├── lista_filme.feature │ ├── step_definitions │ │ ├── .DS_Store │ │ └── lista_filme_step.rb │ └── support │ │ ├── credentials.rb │ │ ├── env.rb │ │ ├── hooks.rb │ │ └── parallel_test.rb └── ios_appium.txt ├── backstop.js └── .gitignore ├── httparty-ruby ├── Gemfile ├── Gemfile.lock ├── Readme.md ├── endpoints.json └── features │ ├── helper │ └── helper.rb │ ├── step_definitions │ ├── delete.rb │ ├── get.rb │ ├── post.rb │ └── put.rb │ ├── support │ └── env.rb │ ├── verbo_delete.feature │ ├── verbo_get.feature │ ├── verbo_post.feature │ └── verbo_put.feature ├── jest ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src │ ├── actions │ ├── balance.js │ ├── balance.test.js │ ├── bitcoin.js │ ├── bitcoin.test.js │ └── constants.js │ ├── assets │ ├── bitcoin.jpg │ └── bitcoin.mp4 │ ├── components │ ├── App.js │ ├── App.test.js │ ├── Loot.js │ ├── Loot.test.js │ ├── Wallet.js │ └── Wallet.test.js │ ├── index.css │ ├── index.js │ ├── reducers │ ├── balance.js │ ├── balance.test.js │ ├── bitcoin.js │ ├── bitcoin.test.js │ ├── index.js │ └── index.test.js │ └── setupTest.js ├── nightwatch └── .gitignore ├── pact └── .gitignore ├── protractor ├── .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 ├── selenium-java ├── .gitignore ├── README.md ├── drivers │ ├── linux │ │ ├── chromedriver │ │ └── geckodriver │ ├── mac │ │ ├── chromedriver │ │ └── geckodriver │ └── windows │ │ ├── IEDriverServer.exe │ │ ├── MicrosoftWebDriver.exe │ │ ├── chromedriver.exe │ │ └── geckodriver.exe ├── pom.xml └── src │ ├── resources │ ├── config.properties │ └── features │ │ └── example.feature │ └── test │ └── java │ └── br │ └── com │ └── selenium │ └── java_project │ ├── enums │ ├── Browsers.java │ └── OperationSystems.java │ ├── pages │ ├── ConcretePage.java │ └── ElementBy.java │ ├── runner │ └── CucumberRunnerTest.java │ ├── test │ └── steps │ │ └── definitions │ │ ├── Hooks.java │ │ └── exampleSteps.java │ └── utils │ ├── AllureHelper.java │ ├── DriverFactory.java │ ├── HandleProperties.java │ └── Page.java ├── splinter └── .gitignore ├── supertestApi ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── response_schemes │ └── reponseCapitalData.js ├── searchByCapital │ └── returnListCapitalDataTest.js └── utils.js └── wedbriver.io └── .gitignore /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Concrete 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qa-automation-samples 2 | Repository with examples of automation tools used by Concrete QAs 3 | -------------------------------------------------------------------------------- /RestAssured/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | TESTE.API.CONCRETE.ESTUDO 7 | TESTE.API.CONCRETE.ESTUDO 8 | 0.0.1-SNAPSHOT 9 | 10 | 11 | 12 | 13 | com.fasterxml.jackson.core 14 | jackson-databind 15 | 2.9.5 16 | 17 | 18 | 19 | junit 20 | junit 21 | 4.13 22 | test 23 | 24 | 25 | 26 | io.rest-assured 27 | rest-assured 28 | 4.0.0 29 | test 30 | 31 | 32 | 33 | org.hamcrest 34 | hamcrest-library 35 | 1.3 36 | test 37 | 38 | 39 | 40 | io.cucumber 41 | cucumber-java 42 | 5.2.0 43 | 44 | 45 | 46 | io.cucumber 47 | cucumber-jvm-deps 48 | 1.0.6 49 | provided 50 | 51 | 52 | 53 | io.cucumber 54 | cucumber-junit 55 | 5.2.0 56 | test 57 | 58 | 59 | com.fasterxml.jackson 60 | jackson-bom 61 | 2.10.2 62 | pom 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-compiler-plugin 71 | 3.7.0 72 | 73 | 1.8 74 | 1.8 75 | UTF-8 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /RestAssured/src/main/java/massa/Massa.java: -------------------------------------------------------------------------------- 1 | package massa; 2 | 3 | 4 | 5 | public class Massa { 6 | 7 | 8 | private String name; 9 | private String job; 10 | 11 | 12 | 13 | public Massa(String name, String job) { 14 | super(); 15 | this.name = name; 16 | this.job = job; 17 | } 18 | 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | 30 | public String getJob() { 31 | return job; 32 | } 33 | 34 | 35 | public void setJob(String job) { 36 | this.job = job; 37 | } 38 | } -------------------------------------------------------------------------------- /RestAssured/src/test/java/runner/Runner.java: -------------------------------------------------------------------------------- 1 | package runner; 2 | 3 | 4 | import io.cucumber.junit.Cucumber; 5 | import io.cucumber.junit.CucumberOptions; 6 | import io.cucumber.junit.CucumberOptions.SnippetType; 7 | 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(Cucumber.class) 11 | @CucumberOptions( 12 | features = "src/test/resources/testesFuncionais/", 13 | plugin = {"pretty", "html:target/report-html"}, 14 | monochrome = true, 15 | glue = {"stepDefinitions"}, 16 | snippets = SnippetType.CAMELCASE, 17 | strict = false, 18 | dryRun= false 19 | ) 20 | 21 | public class Runner { 22 | 23 | } -------------------------------------------------------------------------------- /RestAssured/src/test/java/stepDefinitions/Step.java: -------------------------------------------------------------------------------- 1 | package stepDefinitions; 2 | 3 | import massa.Massa; 4 | 5 | import io.cucumber.java.es.Dado; 6 | import io.cucumber.java.it.Quando; 7 | import io.cucumber.java.pt.Entao; 8 | import io.restassured.response.Response; 9 | import io.restassured.RestAssured; 10 | import io.restassured.http.ContentType; 11 | import io.restassured.response.ValidatableResponse; 12 | import io.restassured.specification.RequestSpecification; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import org.hamcrest.Matchers; 17 | import org.junit.BeforeClass; 18 | import org.junit.Test; 19 | 20 | public class Step { 21 | 22 | 23 | private static final String BASE_URL = "https://reqres.in"; 24 | private static Response response; 25 | private ValidatableResponse json; 26 | 27 | Map jsonBodyUsingMap = new HashMap(); 28 | 29 | 30 | 31 | @Quando("fazer uma solicitacao") 32 | public void fazerUmaRequisicao() { 33 | RestAssured.baseURI = BASE_URL; 34 | RequestSpecification request = (RequestSpecification) RestAssured.when(); 35 | response = request.get("/api/users/"+2); 36 | } 37 | 38 | @Entao("devo visualizar os dados do usuario") 39 | public void devoVisualizarOsDados() { 40 | json = response.then().statusCode(200) 41 | .body("data.id", Matchers.is(2)) 42 | .body("data.email", Matchers.is("janet.weaver@reqres.in")) 43 | .body("data.first_name", Matchers.is("Janet")) 44 | .body("data.last_name", Matchers.is("Weaver")); 45 | } 46 | 47 | 48 | 49 | 50 | 51 | @Dado("que quero adicionar um novo usuario") 52 | public void ajdQueroAdicionarUmNovoUsuario() { 53 | jsonBodyUsingMap.put("name","Ériton"); 54 | jsonBodyUsingMap.put("job","QA"); 55 | 56 | } 57 | 58 | @Quando("fazer um post") 59 | public void fazerUmPost() { 60 | RestAssured.baseURI = BASE_URL; 61 | RequestSpecification request = (RequestSpecification) RestAssured.when(); 62 | request.header("Content-Type","application/json") ; 63 | response = request.body(jsonBodyUsingMap) 64 | .post("/api/users"); 65 | 66 | } 67 | 68 | @Entao("devo realizar cadastro com sucesso") 69 | public void devoReceberCadastroComSucesso() { 70 | 71 | json = response.then().statusCode(201) 72 | .body("name", Matchers.is("Ériton")) 73 | .body("job", Matchers.is("QA")) 74 | .body("id", Matchers.notNullValue()) 75 | .body("createdAt", Matchers.notNullValue()); 76 | 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /RestAssured/src/test/resources/testesFuncionais/Teste.feature: -------------------------------------------------------------------------------- 1 | # language: pt 2 | 3 | Funcionalidade: Teste seu front-end em uma API real 4 | 5 | Como desenvolvedor, 6 | Eu quero realizar uma consulta de usuario, 7 | para que eu possa visualizar, email, primeiro nome e sobrenome. 8 | 9 | 10 | Como desenvolvedor, 11 | Eu inserir novo usuario, 12 | para que eu possa visualizar o cadstro com sucesso. 13 | 14 | 15 | url da aplicacao https://reqres.in/ 16 | 17 | 18 | 19 | Cenário: Consultar os dados de um usuário; 20 | Quando fazer uma solicitacao 21 | Entao devo visualizar os dados do usuario 22 | 23 | 24 | Cenário: Adicionar um novo usuário 25 | Dado que quero adicionar um novo usuario 26 | Quando fazer um post 27 | Entao devo realizar cadastro com sucesso 28 | -------------------------------------------------------------------------------- /RestAssured/target/classes/massa/Massa.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/RestAssured/target/classes/massa/Massa.class -------------------------------------------------------------------------------- /RestAssured/target/report-html/formatter.js: -------------------------------------------------------------------------------- 1 | var CucumberHTML = {}; 2 | 3 | CucumberHTML.DOMFormatter = function(rootNode) { 4 | var currentUri; 5 | var currentFeature; 6 | var currentElement; 7 | var currentSteps; 8 | 9 | var currentStepIndex; 10 | var currentStep; 11 | var $templates = $(CucumberHTML.templates); 12 | 13 | this.uri = function(uri) { 14 | currentUri = uri; 15 | }; 16 | 17 | this.feature = function(feature) { 18 | currentFeature = blockElement(rootNode, feature, 'feature'); 19 | }; 20 | 21 | this.background = function(background) { 22 | currentElement = featureElement(background, 'background'); 23 | currentStepIndex = 1; 24 | }; 25 | 26 | this.scenario = function(scenario) { 27 | currentElement = featureElement(scenario, 'scenario'); 28 | currentStepIndex = 1; 29 | }; 30 | 31 | this.scenarioOutline = function(scenarioOutline) { 32 | currentElement = featureElement(scenarioOutline, 'scenario_outline'); 33 | currentStepIndex = 1; 34 | }; 35 | 36 | this.step = function(step) { 37 | var stepElement = $('.step', $templates).clone(); 38 | stepElement.appendTo(currentSteps); 39 | populate(stepElement, step, 'step'); 40 | 41 | if (step.doc_string) { 42 | docString = $('.doc_string', $templates).clone(); 43 | docString.appendTo(stepElement); 44 | // TODO: use a syntax highlighter based on the content_type 45 | docString.text(step.doc_string.value); 46 | } 47 | if (step.rows) { 48 | dataTable = $('.data_table', $templates).clone(); 49 | dataTable.appendTo(stepElement); 50 | var tBody = dataTable.find('tbody'); 51 | $.each(step.rows, function(index, row) { 52 | var tr = $('').appendTo(tBody); 53 | $.each(row.cells, function(index, cell) { 54 | var td = $('' + cell + '').appendTo(tBody); 55 | }); 56 | }); 57 | } 58 | }; 59 | 60 | this.examples = function(examples) { 61 | var examplesElement = blockElement(currentElement.children('details'), examples, 'examples'); 62 | var examplesTable = $('.examples_table', $templates).clone(); 63 | examplesTable.appendTo(examplesElement.children('details')); 64 | 65 | $.each(examples.rows, function(index, row) { 66 | var parent = index == 0 ? examplesTable.find('thead') : examplesTable.find('tbody'); 67 | var tr = $('').appendTo(parent); 68 | $.each(row.cells, function(index, cell) { 69 | var td = $('' + cell + '').appendTo(tr); 70 | }); 71 | }); 72 | }; 73 | 74 | this.match = function(match) { 75 | currentStep = currentSteps.find('li:nth-child(' + currentStepIndex + ')'); 76 | currentStepIndex++; 77 | }; 78 | 79 | this.result = function(result) { 80 | currentStep.addClass(result.status); 81 | if (result.error_message != '') { 82 | populateStepError(currentStep, result.error_message); 83 | } 84 | currentElement.addClass(result.status); 85 | var isLastStep = currentSteps.find('li:nth-child(' + currentStepIndex + ')').length == 0; 86 | if (isLastStep) { 87 | if (currentSteps.find('.failed').length == 0) { 88 | // No failed steps. Collapse it. 89 | currentElement.find('details').prop('open', false); 90 | } else { 91 | currentElement.find('details').attr('open', 'open'); 92 | } 93 | } 94 | }; 95 | 96 | this.embedding = function(mediaType, data, name) { 97 | var nameHtml; 98 | if (!name) { 99 | nameHtml = ""; 100 | } else { 101 | nameHtml = "

" + name + "

"; 102 | } 103 | if (currentStepIndex == 1) { 104 | this.dummyStep(); 105 | } 106 | if (mediaType.match(/^image\//)) 107 | { 108 | currentStep.append(nameHtml + ''); 109 | } 110 | else if (mediaType.match(/^video\//)) 111 | { 112 | currentStep.append(nameHtml + ''); 113 | } 114 | else if (mediaType.match(/^text\//)) 115 | { 116 | this.write(nameHtml + data); 117 | } 118 | }; 119 | 120 | this.write = function(text) { 121 | if (currentStepIndex == 1) { 122 | this.dummyStep(); 123 | } 124 | currentStep.append('
' + text + '
'); 125 | }; 126 | 127 | this.before = function(before) { 128 | this.handleHookResult(before); 129 | }; 130 | 131 | this.after = function(after) { 132 | this.handleHookResult(after); 133 | }; 134 | 135 | this.beforestep = function(beforestep) { 136 | this.handleHookResult(beforestep); 137 | }; 138 | 139 | this.afterstep = function(afterstep) { 140 | this.handleHookResult(afterstep); 141 | }; 142 | 143 | this.handleHookResult = function(hook) { 144 | if (hook.status != 'passed' && hook.error_message != '') { 145 | this.dummyStep(); 146 | currentStep.addClass(hook.status); 147 | currentElement.addClass(hook.status); 148 | populateStepError(currentStep, hook.error_message); 149 | } 150 | }; 151 | 152 | this.dummyStep = function() { 153 | var stepElement = $('.step', $templates).clone(); 154 | stepElement.appendTo(currentSteps); 155 | populate(stepElement, {keyword: '', name: ''}, 'step'); 156 | currentStep = currentSteps.find('li:nth-child(' + currentStepIndex + ')'); 157 | currentStepIndex++; 158 | }; 159 | 160 | function featureElement(statement, itemtype) { 161 | var e = blockElement(currentFeature.children('details'), statement, itemtype); 162 | 163 | currentSteps = $('.steps', $templates).clone(); 164 | currentSteps.appendTo(e.children('details')); 165 | 166 | return e; 167 | } 168 | 169 | function blockElement(parent, statement, itemtype) { 170 | var e = $('.blockelement', $templates).clone(); 171 | e.appendTo(parent); 172 | return populate(e, statement, itemtype); 173 | } 174 | 175 | function populate(e, statement, itemtype) { 176 | populateTags(e, statement.tags); 177 | populateComments(e, statement.comments); 178 | e.find('.keyword').text(statement.keyword); 179 | e.find('.name').text(statement.name); 180 | e.find('.description').text(statement.description); 181 | e.attr('itemtype', 'http://cukes.info/microformat/' + itemtype); 182 | e.addClass(itemtype); 183 | return e; 184 | } 185 | 186 | function populateComments(e, comments) { 187 | if (comments !== undefined) { 188 | var commentsNode = $('.comments', $templates).clone().prependTo(e.find('.header')); 189 | $.each(comments, function(index, comment) { 190 | var commentNode = $('.comment', $templates).clone().appendTo(commentsNode); 191 | commentNode.text(comment.value); 192 | }); 193 | } 194 | } 195 | 196 | function populateTags(e, tags) { 197 | if (tags !== undefined) { 198 | var tagsNode = $('.tags', $templates).clone().prependTo(e.find('.header')); 199 | $.each(tags, function(index, tag) { 200 | var tagNode = $('.tag', $templates).clone().appendTo(tagsNode); 201 | tagNode.text(tag.name); 202 | }); 203 | } 204 | } 205 | 206 | function populateStepError(e, error) { 207 | if (error !== undefined) { 208 | errorNode = $('.error', $templates).clone().appendTo(e); 209 | errorNode.text(error); 210 | } 211 | } 212 | }; 213 | 214 | CucumberHTML.templates = '
\ 215 |
\ 216 |
\ 217 | \ 218 | Keyword: This is the block name\ 219 | \ 220 |
The description goes here
\ 221 |
\ 222 |
\ 223 | \ 224 |
    \ 225 | \ 226 |
      \ 227 |
    1. KeywordName
    2. \ 228 |
    \ 229 | \ 230 |
    \
    231 | \
    232 |   
    \
    233 | \
    234 |   \
    235 |     \
    236 |     \
    237 |   
    \ 238 | \ 239 | \ 240 | \ 241 | \ 242 |
    \ 243 | \ 244 |
    \ 245 | \ 246 |
    \ 247 |
    \ 248 | \ 249 |
    \ 250 |
    \ 251 |
    '; 252 | 253 | if (typeof module !== 'undefined') { 254 | module.exports = CucumberHTML; 255 | } else if (typeof define !== 'undefined') { 256 | define([], function() { return CucumberHTML; }); 257 | } 258 | -------------------------------------------------------------------------------- /RestAssured/target/report-html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Cucumber Features 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | 15 | -------------------------------------------------------------------------------- /RestAssured/target/report-html/report.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() {var formatter = new CucumberHTML.DOMFormatter($('.cucumber-report'));formatter.uri("file:src/test/resources/testesFuncionais/Teste.feature"); 2 | formatter.feature({ 3 | "name": "exemplo de teste de API com Cumcumber", 4 | "description": "Este projeto é um exemplo de testes de API com Cucumber", 5 | "keyword": "Funcionalidade" 6 | }); 7 | formatter.scenario({ 8 | "name": "Consultar os dados de um usuário;", 9 | "description": "", 10 | "keyword": "Cenário" 11 | }); 12 | formatter.step({ 13 | "name": "fazer uma requisicao", 14 | "keyword": "Quando " 15 | }); 16 | formatter.match({ 17 | "location": "stepDefinitions.Step.fazerUmaRequisicao()" 18 | }); 19 | formatter.result({ 20 | "status": "passed" 21 | }); 22 | formatter.step({ 23 | "name": "devo visualizar os dados", 24 | "keyword": "Entao " 25 | }); 26 | formatter.match({ 27 | "location": "stepDefinitions.Step.devoVisualizarOsDados()" 28 | }); 29 | formatter.result({ 30 | "status": "passed" 31 | }); 32 | formatter.scenario({ 33 | "name": "Adicionar um novo usuário", 34 | "description": "", 35 | "keyword": "Cenário" 36 | }); 37 | formatter.step({ 38 | "name": "que quero adicionar um novo usuario", 39 | "keyword": "Dado " 40 | }); 41 | formatter.match({ 42 | "location": "stepDefinitions.Step.ajdQueroAdicionarUmNovoUsuario()" 43 | }); 44 | formatter.result({ 45 | "status": "passed" 46 | }); 47 | formatter.step({ 48 | "name": "fazer um post", 49 | "keyword": "Quando " 50 | }); 51 | formatter.match({ 52 | "location": "stepDefinitions.Step.fazerUmPost()" 53 | }); 54 | formatter.result({ 55 | "status": "passed" 56 | }); 57 | formatter.step({ 58 | "name": "devo receber cadastro com sucesso", 59 | "keyword": "Entao " 60 | }); 61 | formatter.match({ 62 | "location": "stepDefinitions.Step.devoReceberCadastroComSucesso()" 63 | }); 64 | formatter.result({ 65 | "status": "passed" 66 | }); 67 | }); -------------------------------------------------------------------------------- /RestAssured/target/report-html/style.css: -------------------------------------------------------------------------------- 1 | .cucumber-report .body { 2 | font-family: Helvetica,Arial,sans-serif; 3 | } 4 | 5 | .cucumber-report .keyword { 6 | font-weight: bold; 7 | } 8 | 9 | .cucumber-report .description { 10 | font-style: italic; 11 | margin-left: 20px; 12 | white-space: pre; 13 | } 14 | 15 | .cucumber-report details > section { 16 | margin-left: 20px; 17 | } 18 | 19 | .cucumber-report ol.steps { 20 | list-style-type: none; 21 | margin-top: 0; 22 | margin-bottom: 0; 23 | } 24 | 25 | .cucumber-report .step .embedded-text { 26 | background: #dddddd; 27 | } 28 | 29 | .cucumber-report .doc_string { 30 | margin: 0 0 0 20px; 31 | } 32 | 33 | .cucumber-report table { 34 | border-collapse: collapse; 35 | border: 1px; 36 | border-style: solid; 37 | } 38 | 39 | .cucumber-report td, .cucumber-report th { 40 | border: 1px; 41 | border-style: solid; 42 | padding-left: 4px; 43 | padding-right: 4px; 44 | } 45 | 46 | .cucumber-report table { 47 | margin-left: 20px; 48 | } 49 | 50 | .cucumber-report thead { 51 | background-color: #C0C0C0; 52 | } 53 | 54 | .cucumber-report .passed { 55 | background-color: #C5D88A; 56 | } 57 | 58 | .cucumber-report .undefined, .cucumber-report .pending { 59 | background-color: #EAEC2D; 60 | } 61 | 62 | .cucumber-report .skipped { 63 | background-color: #2DEAEC; 64 | } 65 | 66 | .cucumber-report .failed { 67 | background-color: #D88A8A; 68 | } 69 | 70 | .cucumber-report .tags { 71 | display: inline; 72 | } 73 | 74 | .cucumber-report .tag { 75 | margin-right: 0.25em; 76 | color: #246ac1; 77 | } 78 | 79 | .cucumber-report .comments { 80 | display: inline; 81 | } 82 | 83 | .cucumber-report .comment { 84 | margin: 0; 85 | padding: 0; 86 | } 87 | 88 | .cucumber-report .error { 89 | margin: .2em .75em; 90 | padding: .2em; 91 | border: 1px solid #900; 92 | background-color: #EDBBBB; 93 | } 94 | 95 | #cucumber-templates { 96 | display: none; 97 | } 98 | -------------------------------------------------------------------------------- /RestAssured/target/test-classes/runner/Runner.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/RestAssured/target/test-classes/runner/Runner.class -------------------------------------------------------------------------------- /RestAssured/target/test-classes/stepDefinitions/Step.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/RestAssured/target/test-classes/stepDefinitions/Step.class -------------------------------------------------------------------------------- /RestAssured/target/test-classes/testesFuncionais/Teste.feature: -------------------------------------------------------------------------------- 1 | # language: pt 2 | 3 | Funcionalidade: Teste seu front-end em uma API real 4 | 5 | Como desenvolvedor, 6 | Eu quero realizar uma consulta de usuario, 7 | para que eu possa visualizar, email, primeiro nome e sobrenome. 8 | 9 | 10 | Como desenvolvedor, 11 | Eu inserir novo usuario, 12 | para que eu possa visualizar o cadstro com sucesso. 13 | 14 | 15 | url da aplicacao https://reqres.in/ 16 | 17 | 18 | 19 | Cenário: Consultar os dados de um usuário; 20 | Quando fazer uma solicitacao 21 | Entao devo visualizar os dados do usuario 22 | 23 | 24 | Cenário: Adicionar um novo usuário 25 | Dado que quero adicionar um novo usuario 26 | Quando fazer um post 27 | Entao devo realizar cadastro com sucesso 28 | -------------------------------------------------------------------------------- /appium-java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-java/.gitignore -------------------------------------------------------------------------------- /appium-java/appium-maven/.gitignore: -------------------------------------------------------------------------------- 1 | ### Eclipse ### 2 | 3 | .metadata 4 | bin/ 5 | tmp/ 6 | *.tmp 7 | *.bak 8 | *.swp 9 | *~.nib 10 | local.properties 11 | .settings/ 12 | .loadpath 13 | .recommenders 14 | 15 | # External tool builders 16 | .externalToolBuilders/ 17 | 18 | # Locally stored "Eclipse launch configurations" 19 | *.launch 20 | 21 | # PyDev specific (Python IDE for Eclipse) 22 | *.pydevproject 23 | 24 | # CDT-specific (C/C++ Development Tooling) 25 | .cproject 26 | 27 | # CDT- autotools 28 | .autotools 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Annotation Processing 52 | .apt_generated/ 53 | 54 | # Scala IDE specific (Scala & Java development for Eclipse) 55 | .cache-main 56 | .scala_dependencies 57 | .worksheet 58 | 59 | ### Eclipse Patch ### 60 | # Eclipse Core 61 | .project 62 | 63 | # JDT-specific (Eclipse Java Development Tools) 64 | .classpath 65 | 66 | # Annotation Processing 67 | .apt_generated 68 | 69 | .sts4-cache/ 70 | 71 | ### Intellij ### 72 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 73 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 74 | 75 | # User-specific stuff 76 | .idea/**/workspace.xml 77 | .idea/**/tasks.xml 78 | .idea/**/usage.statistics.xml 79 | .idea/**/dictionaries 80 | .idea/**/shelf 81 | 82 | # Generated files 83 | .idea/**/contentModel.xml 84 | 85 | # Sensitive or high-churn files 86 | .idea/**/dataSources/ 87 | .idea/**/dataSources.ids 88 | .idea/**/dataSources.local.xml 89 | .idea/**/sqlDataSources.xml 90 | .idea/**/dynamic.xml 91 | .idea/**/uiDesigner.xml 92 | .idea/**/dbnavigator.xml 93 | 94 | # Gradle 95 | .idea/**/gradle.xml 96 | .idea/**/libraries 97 | 98 | # Gradle and Maven with auto-import 99 | # When using Gradle or Maven with auto-import, you should exclude module files, 100 | # since they will be recreated, and may cause churn. Uncomment if using 101 | # auto-import. 102 | # .idea/modules.xml 103 | # .idea/*.iml 104 | # .idea/modules 105 | 106 | # CMake 107 | cmake-build-*/ 108 | 109 | # Mongo Explorer plugin 110 | .idea/**/mongoSettings.xml 111 | 112 | # File-based project format 113 | *.iws 114 | 115 | # IntelliJ 116 | out/ 117 | 118 | # mpeltonen/sbt-idea plugin 119 | .idea_modules/ 120 | 121 | # JIRA plugin 122 | atlassian-ide-plugin.xml 123 | 124 | # Cursive Clojure plugin 125 | .idea/replstate.xml 126 | 127 | # Crashlytics plugin (for Android Studio and IntelliJ) 128 | com_crashlytics_export_strings.xml 129 | crashlytics.properties 130 | crashlytics-build.properties 131 | fabric.properties 132 | 133 | # Editor-based Rest Client 134 | .idea/httpRequests 135 | 136 | # Android studio 3.1+ serialized cache file 137 | .idea/caches/build_file_checksums.ser 138 | 139 | ### Intellij Patch ### 140 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 141 | 142 | # *.iml 143 | # modules.xml 144 | # .idea/misc.xml 145 | # *.ipr 146 | 147 | # Sonarlint plugin 148 | .idea/sonarlint 149 | 150 | ### Java ### 151 | # Compiled class file 152 | *.class 153 | 154 | # Log file 155 | *.log 156 | 157 | # BlueJ files 158 | *.ctxt 159 | 160 | # Mobile Tools for Java (J2ME) 161 | .mtj.tmp/ 162 | 163 | # Package Files # 164 | *.jar 165 | *.war 166 | *.nar 167 | *.ear 168 | *.zip 169 | *.tar.gz 170 | *.rar 171 | 172 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 173 | hs_err_pid* 174 | 175 | ### Linux ### 176 | *~ 177 | 178 | # temporary files which can be created if a process still has a handle open of a deleted file 179 | .fuse_hidden* 180 | 181 | # KDE directory preferences 182 | .directory 183 | 184 | # Linux trash folder which might appear on any partition or disk 185 | .Trash-* 186 | 187 | # .nfs files are created when an open file is removed but is still being accessed 188 | .nfs* 189 | 190 | ### macOS ### 191 | # General 192 | .DS_Store 193 | .AppleDouble 194 | .LSOverride 195 | 196 | # Icon must end with two \r 197 | Icon 198 | 199 | # Thumbnails 200 | ._* 201 | 202 | # Files that might appear in the root of a volume 203 | .DocumentRevisions-V100 204 | .fseventsd 205 | .Spotlight-V100 206 | .TemporaryItems 207 | .Trashes 208 | .VolumeIcon.icns 209 | .com.apple.timemachine.donotpresent 210 | 211 | # Directories potentially created on remote AFP share 212 | .AppleDB 213 | .AppleDesktop 214 | Network Trash Folder 215 | Temporary Items 216 | .apdisk 217 | 218 | ### Windows ### 219 | # Windows thumbnail cache files 220 | Thumbs.db 221 | ehthumbs.db 222 | ehthumbs_vista.db 223 | 224 | # Dump file 225 | *.stackdump 226 | 227 | # Folder config file 228 | [Dd]esktop.ini 229 | 230 | # Recycle Bin used on file shares 231 | $RECYCLE.BIN/ 232 | 233 | # Windows Installer files 234 | *.cab 235 | *.msi 236 | *.msix 237 | *.msm 238 | *.msp 239 | 240 | # Windows shortcuts 241 | *.lnk 242 | -------------------------------------------------------------------------------- /appium-java/appium-maven/README.md: -------------------------------------------------------------------------------- 1 | #QA Mobile 2 | 3 | QA Mobile is made with Appium. 4 | 5 | ## Components 6 | 7 | * Java 8 8 | * Appium 1.8.1 9 | * Maven 10 | * Android and Ios Simulators or Devices 11 | 12 | ## Running Tests 13 | 14 | 1. Start appium server: `$ appium` ( Use method appiumServerUp to start appium server automatically, and appiumServerDown to close) 15 | 16 | 2. Run implemented android tests: `$ mvn clean test -Dcucumber.options="--tags @implementedForAndroid" -Denv.PLATAFORM=ANDROID_OREO_DEV` 17 | 18 | 3. Run implemented ios tests: `$ mvn clean test -Dcucumber.options="--tags @implementedForIOS" -Denv.PLATAFORM=IPHONE_8_DEV` 19 | 20 | ## IMPORTANT 21 | 22 | * Before run the tests you need to start android device or emulator and appium server. 23 | 24 | 25 | ## OPERATIONAL SYSTEMS FOR TESTS 26 | 27 | ###ANDROID 28 | 29 | * ANDROID_OREO_DEV (Simulator) 30 | 31 | ###IOS 32 | 33 | * IPHONE_6S_DEV (Simulator) 34 | 35 | ## Documentation 36 | 37 | * **[Appium Docs](http://appium.io/)** 38 | * **[Selenium Docs](https://www.seleniumhq.org/docs/)** 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /appium-java/appium-maven/apps/Appium.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-java/appium-maven/apps/Appium.apk -------------------------------------------------------------------------------- /appium-java/appium-maven/capabilities/android-fisico.json: -------------------------------------------------------------------------------- 1 | { 2 | "platformName": "Android", 3 | "deviceName": "Android", 4 | "platformVersion": "7.0", 5 | "automationName": "UiAutomator2", 6 | "udid": "", 7 | "noReset": true, 8 | "appPackage": "", 9 | "appActivity": "", 10 | "newCommandTimeout": 10 11 | } 12 | 13 | -------------------------------------------------------------------------------- /appium-java/appium-maven/capabilities/android-oreo-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "platformName": "Android", 3 | "deviceName": "Device", 4 | "platformVersion": "7.0", 5 | "automationName": "UiAutomator2", 6 | "udid": "emulator-5554", 7 | "avd": "OREO_API_26", 8 | "fullReset": true, 9 | "newCommandTimeout": 5 10 | } 11 | 12 | -------------------------------------------------------------------------------- /appium-java/appium-maven/capabilities/iphone-8-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "platformName": "iOS", 3 | "platformVersion": "12.0", 4 | "deviceName": "iPhone 8", 5 | "automationName": "XCUITest", 6 | "newCommandTimeout": 5, 7 | "connectHardwareKeyboard": true 8 | } 9 | 10 | -------------------------------------------------------------------------------- /appium-java/appium-maven/capabilities/iphone-fisico.json: -------------------------------------------------------------------------------- 1 | { 2 | "udid": "", 3 | "bundleId": "", 4 | "deviceName": "iPhone 6s Plus", 5 | "automationName": "XCUITest", 6 | "noReset": true, 7 | "AutoAcceptAlerts": true, 8 | "newCommandTimeout": 10 9 | } -------------------------------------------------------------------------------- /appium-java/appium-maven/massa/data/teste.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "José ", 3 | "password": "123456", 4 | "cpf": "00000000011", 5 | "cards": [ 6 | "0011" 7 | ] 8 | } -------------------------------------------------------------------------------- /appium-java/appium-maven/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | br.com.appium 9 | appium-maven 10 | 0.0.1-SNAPSHOT 11 | jar 12 | 13 | appium-maven 14 | http://maven.apache.org 15 | 16 | 17 | 18 | UTF-8 19 | 1.8.11 20 | 1.8 21 | 1.8 22 | 23 | 24 | 25 | 26 | junit 27 | junit 28 | 4.12 29 | test 30 | 31 | 32 | 33 | io.appium 34 | java-client 35 | 4.1.2 36 | 37 | 38 | 39 | com.google.code.gson 40 | gson 41 | 2.8.2 42 | 43 | 44 | 45 | io.qameta.allure 46 | allure-cucumber-jvm 47 | 2.0-BETA6 48 | 49 | 50 | 51 | io.cucumber 52 | cucumber-jvm 53 | 3.0.2 54 | pom 55 | 56 | 57 | info.cukes 58 | cucumber-java 59 | 1.2.5 60 | test 61 | 62 | 63 | info.cukes 64 | cucumber-junit 65 | 1.2.5 66 | test 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-surefire-plugin 75 | 2.20 76 | 77 | 1.8 78 | 1.8 79 | 80 | ${env.PLATAFORM} 81 | 82 | 83 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" 84 | 85 | 86 | 87 | 88 | allure.results.directory 89 | ${project.build.directory}/allure-results 90 | 91 | 92 | allure.link.issue.pattern 93 | https://alm.accenture.com/jira/browse/{} 94 | 95 | 96 | 97 | 98 | 99 | org.aspectj 100 | aspectjweaver 101 | ${aspectj.version} 102 | 103 | 104 | 105 | 106 | io.qameta.allure 107 | allure-maven 108 | 2.9 109 | 110 | 2.5.0 111 | ${soapui.results.directory} 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /appium-java/appium-maven/resources/features/teste.feature: -------------------------------------------------------------------------------- 1 | # language: pt 2 | 3 | @teste 4 | Funcionalidade: Teste appium 5 | 6 | @teste01 7 | Cenário: Portador com apenas um cartão para aviso de viagem 8 | Dado que tenha aberto o app 9 | Quando clicar no formulário 10 | E e colocar o meu nome "Fulado" 11 | E salvar a alteração 12 | Então irei visualizar o meu nome na tela 13 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/cucumber/runner/CucumberRunnerTest.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.cucumber.runner; 2 | 3 | import br.com.appium.teste.test.utils.DriverFactoryManager; 4 | import cucumber.api.SnippetType; 5 | import org.junit.AfterClass; 6 | import org.junit.BeforeClass; 7 | import org.junit.runner.RunWith; 8 | import cucumber.api.CucumberOptions; 9 | import cucumber.api.junit.Cucumber; 10 | 11 | @RunWith(Cucumber.class) 12 | @CucumberOptions(monochrome = true, snippets = SnippetType.CAMELCASE, 13 | features = "resources/features", 14 | glue = "br/com/appium/teste/steps/definitions", 15 | tags = {"@teste01","~@unit", "~@notIntegrated"}, 16 | plugin = {"io.qameta.allure.cucumberjvm.AllureCucumberJvm", "pretty"}) 17 | 18 | public class CucumberRunnerTest { 19 | 20 | @BeforeClass 21 | public static void tearUp() { 22 | DriverFactoryManager.appiumServerUp(); 23 | DriverFactoryManager.startDriverByMavenParameter(System.getProperty("environment")); 24 | } 25 | 26 | @AfterClass 27 | public static void tearDown() { 28 | DriverFactoryManager.appiumServerDown(); 29 | DriverFactoryManager.quitDriver(); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/screens/base/BaseScreen.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.screens.base; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.PageFactory; 6 | import br.com.appium.teste.test.utils.DriverFactoryManager; 7 | import io.appium.java_client.pagefactory.AppiumFieldDecorator; 8 | import org.openqa.selenium.support.ui.ExpectedConditions; 9 | import org.openqa.selenium.support.ui.WebDriverWait; 10 | 11 | 12 | public abstract class BaseScreen extends MobileElement { 13 | 14 | public BaseScreen() { 15 | PageFactory.initElements(new AppiumFieldDecorator(DriverFactoryManager.getDriver()), this); 16 | } 17 | 18 | protected void waitForInsvisibilityOfElement(By locator) { 19 | new WebDriverWait(DriverFactoryManager.getDriver(), 5) 20 | .until(ExpectedConditions.invisibilityOfElementLocated(locator)); 21 | } 22 | 23 | protected void waitForVisibilityOfElement(By locator) { 24 | 25 | new WebDriverWait(DriverFactoryManager.getDriver(), 5) 26 | .until(ExpectedConditions.visibilityOfElementLocated(locator)); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/screens/login/InitialScreen.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.screens.login; 2 | 3 | import br.com.appium.teste.screens.base.BaseScreen; 4 | import io.appium.java_client.pagefactory.WithTimeout; 5 | import io.appium.java_client.MobileElement; 6 | import io.appium.java_client.pagefactory.AndroidFindBy; 7 | import io.appium.java_client.pagefactory.iOSFindBy; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | 11 | public class InitialScreen extends BaseScreen { 12 | 13 | @WithTimeout(time = 5000, unit = TimeUnit.SECONDS) 14 | @AndroidFindBy(xpath = "//android.widget.TextView[@text='Formulário']") 15 | private MobileElement clickFormulario; 16 | 17 | @AndroidFindBy(accessibility = "nome") 18 | private MobileElement inputNome; 19 | 20 | @AndroidFindBy(xpath = "//android.widget.Button[@content-desc='save']/android.widget.TextView") 21 | private MobileElement save; 22 | 23 | @AndroidFindBy(xpath = "//android.widget.TextView[starts-with(@text,'Nome')]") 24 | private MobileElement assertName; 25 | 26 | public void clickFormulario() { 27 | this.clickFormulario.click(); 28 | } 29 | 30 | public void inputNome(String nome) { 31 | 32 | this.inputNome.sendKeys(nome); 33 | } 34 | 35 | public void saveClick() { 36 | 37 | this.save.click(); 38 | } 39 | 40 | public boolean assertNome(String nome) { 41 | return this.assertName.getText().contains(nome); 42 | 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/steps/definitions/TesteSteps.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.steps.definitions; 2 | 3 | import br.com.appium.teste.screens.login.InitialScreen; 4 | import cucumber.api.java.pt.Dado; 5 | import cucumber.api.java.pt.Entao; 6 | import cucumber.api.java.pt.Quando; 7 | 8 | public class TesteSteps { 9 | 10 | InitialScreen initialScreen; 11 | 12 | public TesteSteps() { 13 | 14 | initialScreen = new InitialScreen(); 15 | } 16 | 17 | 18 | @Dado("^que tenha aberto o app$") 19 | public void que_tenha_aberto_o_app() { 20 | } 21 | 22 | @Quando("^clicar no formulário$") 23 | public void clicar_no_formulário() { 24 | this.initialScreen.clickFormulario(); 25 | } 26 | 27 | @Quando("^e colocar o meu nome \"([^\"]*)\"$") 28 | public void e_colocar_o_meu_nome(String nome) { 29 | this.initialScreen.inputNome(nome); 30 | 31 | } 32 | 33 | @Quando("^salvar a alteração$") 34 | public void salvar_a_alteração() { 35 | this.initialScreen.saveClick(); 36 | 37 | } 38 | 39 | @Entao("^irei visualizar o meu nome na tela$") 40 | public void irei_visualizar_o_meu_nome_na_tela() { 41 | this.initialScreen.assertNome("Fulano"); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/constants/Constants.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.constants; 2 | 3 | public class Constants { 4 | public static final String APPIUM_URL_DEV = "http://localhost:4723/wd/hub"; 5 | 6 | } 7 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/devices/capabilities/AndroidDevicesCapabilities.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.devices.capabilities; 2 | 3 | import org.openqa.selenium.remote.DesiredCapabilities; 4 | import br.com.appium.teste.test.utils.Utils; 5 | 6 | import java.io.File; 7 | 8 | public enum AndroidDevicesCapabilities { 9 | 10 | 11 | ANDROID_OREO_DEV("capabilities/android-oreo-dev.json"), 12 | ANDROID_FISICO("capabilities/android-fisico.json"); 13 | 14 | 15 | private String path; 16 | 17 | AndroidDevicesCapabilities(String path) { 18 | this.path = path; 19 | } 20 | 21 | public DesiredCapabilities getAndroidCapabilitiesFromPlataform() { 22 | DesiredCapabilities androidCapabilities = Utils.pathToDesiredCapabilitites(this.path); 23 | androidCapabilities.setCapability("app", new File("apps/Appium.apk").getAbsolutePath()); 24 | return androidCapabilities; 25 | } 26 | 27 | public static void showAvaliableAndroidDevices() { 28 | System.out.println("======= ANDROID DEVICES ====== "); 29 | for (AndroidDevicesCapabilities androidDevicesCapabilities : AndroidDevicesCapabilities.values()) { 30 | System.out.println(androidDevicesCapabilities.name()); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/devices/capabilities/IOSDevicesCapabilities.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.devices.capabilities; 2 | 3 | import org.openqa.selenium.remote.DesiredCapabilities; 4 | import br.com.appium.teste.test.utils.Utils; 5 | 6 | import java.io.File; 7 | 8 | public enum IOSDevicesCapabilities { 9 | 10 | IPHONE_8_DEV("capabilities/iphone-8-dev.json"), 11 | IPHONE_FISICO("capabilities/iphone-fisico.json"); 12 | 13 | private String path; 14 | 15 | IOSDevicesCapabilities(String path) { 16 | this.path = path; 17 | } 18 | 19 | public DesiredCapabilities getIOSCapabilitiesFromPlataform() { 20 | DesiredCapabilities iosCapabilities = Utils.pathToDesiredCapabilitites(this.path); 21 | iosCapabilities.setCapability("app", new File("apps/Appium.app").getAbsolutePath()); 22 | return iosCapabilities; 23 | } 24 | 25 | public static void showAvaliableIphoneDevices() { 26 | System.out.println("======= IOS DEVICES ====== "); 27 | for (IOSDevicesCapabilities iosDevicesCapabilities : IOSDevicesCapabilities.values()) { 28 | System.out.println(iosDevicesCapabilities.name()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/utils/Commons.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.utils; 2 | 3 | import br.com.appium.teste.screens.base.BaseScreen; 4 | import io.appium.java_client.MobileElement; 5 | import io.appium.java_client.TouchAction; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.remote.RemoteWebElement; 8 | 9 | import java.util.HashMap; 10 | 11 | public class Commons extends BaseScreen { 12 | 13 | public static void scroll(int startX, int startY, int endX, int endY) { 14 | new TouchAction(DriverFactoryManager.getDriver()).press(startX, startY).waitAction().moveTo(endX, endY).release().waitAction().perform(); 15 | } 16 | 17 | public static void holdElement(MobileElement mobileElement) { 18 | new TouchAction(DriverFactoryManager.getDriver()).longPress(mobileElement).perform(); 19 | } 20 | 21 | public static void holdElementiOS(MobileElement element) { 22 | JavascriptExecutor js = (JavascriptExecutor) DriverFactoryManager.getDriver(); 23 | HashMap tapObject = new HashMap(); 24 | tapObject.put("element", ((RemoteWebElement) element).getId()); 25 | tapObject.put("duration", "2"); 26 | js.executeScript("mobile: touchAndHold", tapObject); 27 | } 28 | 29 | public static void swipeiOS() { 30 | JavascriptExecutor js = (JavascriptExecutor) DriverFactoryManager.getDriver(); 31 | HashMap scrollObject = new HashMap(); 32 | scrollObject.put("direction", "up"); 33 | js.executeScript("mobile: swipe", scrollObject); 34 | } 35 | 36 | public static void swipeInvertiOS() { 37 | JavascriptExecutor js = (JavascriptExecutor) DriverFactoryManager.getDriver(); 38 | HashMap scrollObject = new HashMap(); 39 | scrollObject.put("direction", "down"); 40 | js.executeScript("mobile: swipe", scrollObject); 41 | } 42 | 43 | public static void dataPicker(MobileElement element) { 44 | JavascriptExecutor js = (JavascriptExecutor) DriverFactoryManager.getDriver(); 45 | HashMap picker = new HashMap(); 46 | picker.put("order", "next"); 47 | picker.put("offset", "0.15"); 48 | picker.put("element", ((RemoteWebElement) element).getId()); 49 | js.executeScript("mobile: selectPickerWheelValue", picker); 50 | } 51 | 52 | public static void swipe() { 53 | new TouchAction(DriverFactoryManager.getDriver()).press(300, 1000).waitAction().moveTo(300, 50).release().perform(); 54 | } 55 | 56 | public static void swipeInvert() { 57 | new TouchAction(DriverFactoryManager.getDriver()).press(300, 50).waitAction().moveTo(300, 1000).release().perform(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/utils/DriverFactoryManager.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.utils; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | import br.com.appium.teste.test.constants.Constants; 7 | import br.com.appium.teste.test.devices.capabilities.AndroidDevicesCapabilities; 8 | import br.com.appium.teste.test.devices.capabilities.IOSDevicesCapabilities; 9 | import io.appium.java_client.AppiumDriver; 10 | import io.appium.java_client.android.AndroidDriver; 11 | import io.appium.java_client.ios.IOSDriver; 12 | import io.appium.java_client.service.local.AppiumDriverLocalService; 13 | import org.openqa.selenium.remote.UnreachableBrowserException; 14 | 15 | public class DriverFactoryManager { 16 | 17 | private static AppiumDriver appiumDriver; 18 | private static AppiumDriverLocalService service; 19 | 20 | 21 | public static AppiumDriver startDriverByMavenParameter(String mavenEnvironment) { 22 | 23 | if (appiumDriver == null) { 24 | 25 | try { 26 | 27 | if (mavenEnvironment.contains("ANDROID")) { 28 | appiumDriver = new AndroidDriver<>(new URL(Constants.APPIUM_URL_DEV), AndroidDevicesCapabilities.valueOf(mavenEnvironment).getAndroidCapabilitiesFromPlataform()); 29 | } else if (mavenEnvironment.contains("IPHONE")) { 30 | appiumDriver = new IOSDriver<>(new URL(Constants.APPIUM_URL_DEV), IOSDevicesCapabilities.valueOf(mavenEnvironment).getIOSCapabilitiesFromPlataform()); 31 | } 32 | 33 | } catch (IllegalArgumentException e) { 34 | System.out.println(" ==== AVISO : Por favor selecionar um dos devices abaixo para executar os testes ==== "); 35 | AndroidDevicesCapabilities.showAvaliableAndroidDevices(); 36 | IOSDevicesCapabilities.showAvaliableIphoneDevices(); 37 | System.exit(1); 38 | } catch (UnreachableBrowserException e) { 39 | System.out.println(" ==== AVISO : Por favor verifique se foi passado uma url válida para executar os testes ou se já inicializou o Appium. ===="); 40 | System.exit(1); 41 | } catch (MalformedURLException e) { 42 | System.out.println(" ==== AVISO : Por favor verifique a url que foi informada para executar os testes. ===="); 43 | System.exit(1); 44 | } 45 | } 46 | 47 | return appiumDriver; 48 | } 49 | 50 | public static AppiumDriver getDriver() { 51 | return appiumDriver; 52 | } 53 | 54 | public static void reLaunchApp() { 55 | if (appiumDriver != null) { 56 | appiumDriver.launchApp(); 57 | } 58 | } 59 | 60 | public static void quitDriver() { 61 | if (appiumDriver != null) { 62 | appiumDriver.quit(); 63 | } 64 | } 65 | 66 | public static String getPageHierarchy() { 67 | return appiumDriver.getPageSource(); 68 | } 69 | 70 | public static void appiumServerUp() { 71 | service = AppiumDriverLocalService.buildDefaultService(); 72 | service.start(); 73 | } 74 | 75 | 76 | public static void appiumServerDown() { 77 | service = AppiumDriverLocalService.buildDefaultService(); 78 | service.stop(); 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/utils/Print.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.utils; 2 | 3 | import cucumber.api.Scenario; 4 | import org.apache.commons.io.FileUtils; 5 | import org.openqa.selenium.OutputType; 6 | import org.openqa.selenium.TakesScreenshot; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | public class Print { 12 | 13 | public static void takeScreenShot(Scenario scenario) { 14 | 15 | File scrFile = ((TakesScreenshot) DriverFactoryManager.getDriver()).getScreenshotAs(OutputType.FILE); 16 | 17 | try { 18 | FileUtils.copyFile(scrFile, (new File("./evidence", scenario.getName() + " - " + scenario.getStatus().toUpperCase() + ".png"))); 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /appium-java/appium-maven/src/test/java/br/com/appium/teste/test/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package br.com.appium.teste.test.utils; 2 | 3 | import java.io.FileReader; 4 | import java.lang.reflect.Type; 5 | import java.util.Map; 6 | 7 | import org.openqa.selenium.remote.DesiredCapabilities; 8 | import com.google.gson.Gson; 9 | import com.google.gson.reflect.TypeToken; 10 | 11 | public class Utils { 12 | 13 | public static DesiredCapabilities pathToDesiredCapabilitites(String path) { 14 | try { 15 | Gson gson = new Gson(); 16 | Type type = new TypeToken>(){}.getType(); 17 | Map map = gson.fromJson(new FileReader(path), type); 18 | return new DesiredCapabilities(map); 19 | } catch (Exception e) { 20 | System.out.println(e); 21 | } 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /appium-ruby/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/.gitignore -------------------------------------------------------------------------------- /appium-ruby/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'appium_console' 6 | gem 'appium_lib' 7 | gem 'cucumber' 8 | gem 'pry' 9 | gem 'rspec' 10 | -------------------------------------------------------------------------------- /appium-ruby/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | appium_console (2.9.0) 5 | appium_lib (~> 9.15.0) 6 | awesome_print (~> 1.7) 7 | bond (~> 0.5) 8 | pry (~> 0.11.0) 9 | spec (~> 5.3, >= 5.3.1) 10 | thor (~> 0.19) 11 | appium_lib (9.15.1) 12 | appium_lib_core (~> 2.0.0) 13 | nokogiri (~> 1.8, >= 1.8.1) 14 | tomlrb (~> 1.1) 15 | appium_lib_core (2.0.1) 16 | faye-websocket (~> 0.10.0) 17 | selenium-webdriver (~> 3.14) 18 | awesome_print (1.8.0) 19 | backports (3.11.4) 20 | bond (0.5.1) 21 | builder (3.2.3) 22 | childprocess (0.9.0) 23 | ffi (~> 1.0, >= 1.0.11) 24 | chronic_duration (0.10.6) 25 | numerizer (~> 0.1.1) 26 | coderay (1.1.2) 27 | cucumber (3.1.2) 28 | builder (>= 2.1.2) 29 | cucumber-core (~> 3.2.0) 30 | cucumber-expressions (~> 6.0.1) 31 | cucumber-wire (~> 0.0.1) 32 | diff-lcs (~> 1.3) 33 | gherkin (~> 5.1.0) 34 | multi_json (>= 1.7.5, < 2.0) 35 | multi_test (>= 0.1.2) 36 | cucumber-core (3.2.0) 37 | backports (>= 3.8.0) 38 | cucumber-tag_expressions (~> 1.1.0) 39 | gherkin (>= 5.0.0) 40 | cucumber-expressions (6.0.1) 41 | cucumber-tag_expressions (1.1.1) 42 | cucumber-wire (0.0.1) 43 | diff-lcs (1.3) 44 | eventmachine (1.2.7) 45 | faye-websocket (0.10.7) 46 | eventmachine (>= 0.12.0) 47 | websocket-driver (>= 0.5.1) 48 | ffi (1.9.25) 49 | gherkin (5.1.0) 50 | method_source (0.9.0) 51 | mini_portile2 (2.3.0) 52 | multi_json (1.13.1) 53 | multi_test (0.1.2) 54 | nokogiri (1.8.4) 55 | mini_portile2 (~> 2.3.0) 56 | numerizer (0.1.1) 57 | pry (0.11.3) 58 | coderay (~> 1.1.0) 59 | method_source (~> 0.9.0) 60 | rspec (3.8.0) 61 | rspec-core (~> 3.8.0) 62 | rspec-expectations (~> 3.8.0) 63 | rspec-mocks (~> 3.8.0) 64 | rspec-core (3.8.0) 65 | rspec-support (~> 3.8.0) 66 | rspec-expectations (3.8.1) 67 | diff-lcs (>= 1.2.0, < 2.0) 68 | rspec-support (~> 3.8.0) 69 | rspec-mocks (3.8.0) 70 | diff-lcs (>= 1.2.0, < 2.0) 71 | rspec-support (~> 3.8.0) 72 | rspec-support (3.8.0) 73 | rubyzip (1.2.2) 74 | selenium-webdriver (3.14.0) 75 | childprocess (~> 0.5) 76 | rubyzip (~> 1.2) 77 | spec (5.3.4) 78 | chronic_duration (~> 0.10.2) 79 | thor (0.20.0) 80 | tomlrb (1.2.7) 81 | websocket-driver (0.7.0) 82 | websocket-extensions (>= 0.1.0) 83 | websocket-extensions (0.1.3) 84 | 85 | PLATFORMS 86 | ruby 87 | 88 | DEPENDENCIES 89 | appium_console 90 | appium_lib 91 | cucumber 92 | pry 93 | rspec 94 | 95 | BUNDLED WITH 96 | 1.16.3 97 | -------------------------------------------------------------------------------- /appium-ruby/README.md: -------------------------------------------------------------------------------- 1 | # Estudo do appium_ruby 2 | 3 | [![Code Climate](https://codeclimate.com/github/codeclimate/codeclimate/badges/gpa.svg)](https://codeclimate.com/github/danilopolicarpos/Appium/) 4 | 5 | ## O que é o APPIUM ? 6 | 7 | Appium é uma ferramenta Open Source e multi-plataforma para automação de aplicações nativas, híbridas e sites mobile para os principais sistemas operacionais do mercado: Android, iOS (e agora para FirefoxOS). 8 | 9 | É melhor instalar o Appium através da linha de comando, em vez de baixar o appium, uma vez que o aplicativo GUI do Appium é mais frágil. 10 | 11 | > **Atenção**: Não instale o Node ou o Appium utilizando `sudo`, vai te causar problemas. 12 | 13 | ## Pré-requisitos 14 | 15 | ### > Xcode 16 | 17 | É um ambiente de desenvolvimento integrado e software livre da Apple Inc. 18 | Também precisamos autorizar o uso do iOS Simulator: 19 | ``` 20 | sudo authorize_ios 21 | ``` 22 | ### > Android studio 23 | 24 | É a IDE oficial para criação de aplicativos em todos os tipos de dispositivos android 25 | Para baixar o android segue o link: 26 | > https://developer.android.com/studio/index.html?hl=pt-br 27 | 28 | ### > Java 29 | 30 | Para baixar o jdk8 segue o link: 31 | > http://www.oracle.com/technetwork/pt/java/javase/downloads/jdk8-downloads-2133151.html 32 | 33 | Após a instalação é necessário setar as variáveis de ambiente `JAVA_HOME` e `ANDROID_HOME` no seu bash_profile. 34 | 35 | Abra o terminal e digite: 36 | ```bash 37 | open ~/.bash_profile # abre o arquivo bash_profile 38 | ``` 39 | E cole o código abaixo 40 | ```bash 41 | export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) # encontra a Home do Java 8 (1.8) 42 | export ANDROID_HOME=~/Library/Android/sdk 43 | 44 | PATH=$PATH:$ANDROID_HOME/platform-tools 45 | PATH=$PATH:$ANDROID_HOME/tools 46 | PATH=$PATH:$ANDROID_HOME/tools/bin 47 | PATH=$PATH:$ANDROID_HOME/tools/lib 48 | PATH=$PATH:$JAVA_HOME/bin 49 | ``` 50 | Logo após a **última** variável de ambiente do seu **bash_profile** exporte o PATH 51 | ```bash 52 | export PATH 53 | ``` 54 | 55 | ### > Homebrew 56 | 57 | O [Homebrew](https://brew.sh/) instala os pacotes que não vem por padrão no sistema da Apple. 58 | Para instalá-lo, execute o código abaixo no seu terminal: 59 | ``` 60 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 61 | ``` 62 | 63 | ### > Node JS 64 | 65 | O Appium é um servidor HTTP escrito em node.js que cria e manipula várias sessões do WebDriver para diferentes plataformas, como iOS e Android. 66 | A automação de aplicativos móveis híbridos e nativos para Android e iOS é uma função chave administrada pelo Appium, um servidor node.js. A interação entre o servidor node.js e as bibliotecas de client do Selenium é o que, em última análise, funciona em conjunto com a aplicação móvel. 67 | Para instalar, basta colar no terminal: 68 | ``` 69 | brew install npm # instalar o appium via (source) npm (Node JS Package Manager) 70 | npm --version # versão atual do npm 71 | brew install node # instalar o node 72 | node --version # versão atual do node 73 | ``` 74 | 75 | ### > Appium-doctor 76 | Verifica se todas as dependências do Appium são atendidas e se todas as dependências estão configuradas corretamente. 77 | Para instalar o appium-doctor basta colar no seu terminal: 78 | ``` 79 | npm install -g appium-doctor # instalar o appium-doctor 80 | ``` 81 | 82 | Uma vez que o **node.js**, **npm** e o **appium-doctor** estão instalados, você pode usar o comando abaixo para verificar se todas as dependências do appium são atendidas: 83 | ``` 84 | appium-doctor # verificar todas as dependencias necessarias para usar o appium 85 | appium-doctor --android # verificar as dependencias somente para android 86 | appium-doctor --ios # verificar as dependencias somente para ios 87 | ``` 88 | 89 | ## Instalando o Appium 90 | 91 | ### Appium Server 92 | 93 | Execute o comando abaixo para instalar o Appium: 94 | ```bash 95 | npm install -g appium 96 | ``` 97 | 98 | Após o término, inicie o servidor do Appium pelo seguinte comando: 99 | ```bash 100 | appium 101 | ``` 102 | 103 | > Para atualizar o Appium, você precisará executar `npm install -g appium` novamente. 104 | 105 | ### Appium Client 106 | 107 | São as linguagens de programação suportadas pelo Appium. 108 | 109 | - [Ruby](https://github.com/appium/ruby_lib) 110 | - [Python](https://github.com/appium/python-client) 111 | - [Java](https://github.com/appium/java-client) 112 | - [JavaScript (Node.js)](https://github.com/admc/wd) 113 | - [Objective C](https://github.com/appium/selenium-objective-c) 114 | - [PHP](https://github.com/appium/php-client) 115 | - [C# (.NET)](https://github.com/appium/appium-dotnet-driver) 116 | - [RobotFramework](https://github.com/jollychang/robotframework-appiumlibrary) 117 | 118 | 119 | Execute o comando abaixo para instalar o Appium Client: 120 | ```bash 121 | npm install wd # cliente do appium 122 | ``` 123 | 124 | ## Desired Capabilities 125 | 126 | São um conjunto de chave/valor que são enviados ao Appium Server para informar qual tipo de sessão desejamos iniciar. 127 | É através do Desired Capabilities que informamos em qual dispositivo queremos executar e quais as configurações iniciais. 128 | Exemplos: 129 | 130 | ### Capabilities para Android 131 | ```bash 132 | [caps] 133 | platformName = "Android" 134 | deviceName = 'Nexus_5_API_23_mars' 135 | app = '~/dev/android/app/build/outputs/apk/nome.apk' 136 | ``` 137 | 138 | ### Capabilities para iOS 139 | ```bash 140 | [caps] 141 | platformName = "iOS" 142 | platformVersion = "10.3" 143 | deviceName = "iPhone 6 Plus" 144 | 145 | app = "~/dev/appium/build/mock/simulator/nome.app" 146 | ``` 147 | 148 | ## Sessão 149 | 150 | Como o Appium é um servidor, toda a comunicação com o dispositivo é realizada através de uma sessão. O cliente inicializa uma sessão com o servidor via `POST /session` com um objeto JSON chamado **Desired Capabilities**. 151 | Quando a sessão é criada um ID é atribuido a ela; E este ID é utilizado para realizar o envio dos comandos para o dispositivo apropriado. 152 | 153 | 154 | ## Criando um projeto Appium_Android 155 | 156 | Para criar um projeto Appium Android [clique aqui](https://github.com/danilopolicarpos/Appium-android) 157 | 158 | ## Criando um projeto Appium_iOS 159 | 160 | Para criar um projeto Appium iOS 161 | Abra o terminal e execute os comandos abaixo: 162 | ``` 163 | cucumber --init # criando estrutura do projeto 164 | 165 | create features 166 | create features/step_definitions 167 | create features/support 168 | create features/support/env.rb 169 | ``` 170 | ``` 171 | Arc setup ios # cria um txt. para ios (Capabilities para iOS) 172 | ``` 173 | Abra o Capabilities para iOS e preencha o arquivo conforme exemplo: 174 | ```bash 175 | [caps] 176 | platformName = "ios" # Plataforma 177 | platformVersion = "10.3" # OS 178 | deviceName = "iPhone 5" # nome do dispositivo 179 | app = '/Users/estudo_appium.apk' # caminho do apk 180 | 181 | ``` 182 | - Inspecionando elemento 183 | 184 | Para inspecionar os elementos na plataforma android podemos usar essas opções: 185 | 186 | - Console (Arc) 187 | 188 | Inicie o servidor do Appium pelo seguinte comando: 189 | ``` 190 | appium # inicia o servidor do appium 191 | ``` 192 | Abre uma nova aba e digite o comando 193 | ``` 194 | Arc # inicia o modo console 195 | page # inspeciona os elementos da tela 196 | source # inspeciona os elementos da tela em HTML 197 | exit # sair do console 198 | ``` 199 | 200 | 201 | - Macaca Js 202 | 203 | Para inspecionar os elemento na tela usando Macaca acesse: 204 | - https://macacajs.github.io/ 205 | - [Deyvirson Mendonça: Inspecionando Elementos no app iOS com MacacaJs](https://medium.com/@deyvirsonmendona/inspecionando-elementos-no-app-ios-com-macacajs-cad962719ce2) 206 | 207 | 208 | - Executando seus testes 209 | 210 | Para rodar os testes execute os comandos no terminal: 211 | ``` 212 | cucumber # rodar todos seus testes 213 | cucumber feature/ # executa todos os cenários de uma feature especifica. 214 | ``` 215 | > Atenção: Antes de rodar seus testes inicie o servidor do Appium 216 | 217 | - Gerando relatório de teste 218 | 219 | Para gerar o relatório no final dos testes, basta colocar o comando: 220 | ``` 221 | <--format html --out reports.html> 222 | ``` 223 | **Exemplo:** `cucumber feature/ --format html --out reports.html` 224 | 225 | 226 | ## Dúvidas 227 | 228 | ### > Links úteis 229 | - [Documentação do Appium](http://appium.io/slate/en/master/?ruby#) 230 | - [Github do Appium](https://github.com/appium/appium) 231 | - [Configuração do JAVA_HOME](https://www.mkyong.com/java/how-to-set-java_home-environment-variable-on-mac-os-x/) 232 | - [Opções de instalação (Appium Doctor)](http://hy1984427.github.io/appium/environment_setup/use_appium-doctor_to_verify_settings.html) 233 | 234 | ### > Problema na instalação do Appium 235 | 236 | Erro: EACCES: permissão negada, mkdir '/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver 237 | 238 | acesse o link https://github.com/appium/appium/issues/10020 ou 239 | 240 | Abra o terminal e execute o comando abaixo : 241 | 242 | sudo npm install -g appium --unsafe-perm=true --allow-root 243 | 244 | ### > Verificar o deviceName instalado na máquina 245 | 246 | Abra o terminal e execute os comandos abaixo : 247 | 248 | emulator -list-avds # verifica os emuladores existentes 249 | 250 | ### > Xcode Command Line Tools are NOT installed! 251 | 252 | Abra o terminal e execute os comandos abaixo : 253 | 254 | xcode-select --install # instala Xcode Command Line Tools 255 | 256 | ### > Could not get Xcode version. /Library/Developer/Info.plist 257 | 258 | Abra o terminal e execute os comandos abaixo : 259 | 260 | sudo xcode-select --reset 261 | sudo xcode-select --switch /Applications/Xcode.app 262 | 263 | 264 | ### > Removendo DEPRECATION 265 | 266 | [DEPRECATION] Appium::Driver.new(opts) will not generate global driver by default.If you would like to generate the global driver dy default, please initialise driver with Appium::Driver.new(opts, true) 267 | 268 | Abra o terminal e execute os comandos abaixo : 269 | 270 | gem list appium_console #verifica as versões instaladas 271 | gem list appium_lib 272 | 273 | Excluir todas as versões: 274 | gem uninstall appium_console #Remove versão instalada 275 | gem uninstall appium_lib 276 | 277 | Updade na versão: 278 | gem update appium_console #Atualiza a versão instalada 279 | gem update appium_lib 280 | 281 | #Atenção: Devo somente ter uma versão da gem instalada, sendo a mais recente 282 | 283 | 284 | ## > Deixando a execução do script limpa no terminal 285 | 286 | WARN: Unresolved specs during Gem::Specification.reset: 287 | childprocess (~> 0.5) 288 | awesome_print (~> 1.7) 289 | json (>= 1.8) 290 | nokogiri (>= 1.6.6, ~> 1.6) 291 | 292 | Abra o terminal e execute os comandos abaixo : 293 | 294 | Visualiza versão gem: 295 | gem list [NomeGem] #verifica as versões instaladas 296 | 297 | Excluir todas as versões: 298 | gem uninstall [NomeGem] #Remove versão instalada 299 | 300 | Updade na versão: 301 | gem update [NomeGem] #Atualiza a versão instalada 302 | 303 | 304 | #Atenção: Devo somente ter uma versão da gem instalada, sendo a mais recente. 305 | Para as gem nokogiri deixar instalada a versão maior, exemplo:"nokogiri (1.6.8.1)". 306 | 307 | Para a versão json deixar instalada a versão default, exemplo: "json (default: 1.8.3)". 308 | 309 | 310 | -------------------------------------------------------------------------------- /appium-ruby/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rubygems' 4 | require 'cucumber' 5 | require 'cucumber/rake/task' 6 | require 'appium_lib' 7 | 8 | desc 'Start server Appium' 9 | task :appium_server do 10 | puts 'iniciando server do appium' 11 | system 'nohup appium &' 12 | end 13 | 14 | desc 'Close server Appium' 15 | task :close_appium_server do 16 | puts 'fechando conexão do server do appium' 17 | system "ps -ef | grep -v grep | grep appium | awk '{print $2}' | 18 | xargs kill -9" 19 | end 20 | 21 | desc 'Run test in Android' 22 | task :android do 23 | sh 'bundle exec cucumber -p android' 24 | end 25 | 26 | desc 'Run test in iOS' 27 | task :ios do 28 | sh 'bundle exec cucumber -p ios' 29 | end 30 | 31 | desc 'Run both Android e iOS' 32 | task :android_ios do 33 | sh 'bundle exec cucumber -p ios & bundle exec cucumber -p android' 34 | end 35 | 36 | desc 'Open mode android console' 37 | task :android_console do 38 | puts 'Iniciando modo console no android' 39 | sh 'bundle exec arc toml android_appium.txt' 40 | end 41 | 42 | desc 'Open mode ios console' 43 | task :ios_console do 44 | puts 'Iniciando modo console no ios' 45 | sh 'bundle exec arc toml ios_appium.txt' 46 | end 47 | 48 | desc 'start wiremock server' 49 | task :wiremock do 50 | puts 'Iniciando o wiremock' 51 | system 'nohup ./wiremock proxy playback &' 52 | end 53 | 54 | 55 | 56 | 57 | desc 'Run test in parallell' 58 | task :paralelo do 59 | sh 'cucumber -p nougat & cucumber -p oreo' 60 | end 61 | 62 | desc 'start server in parallell' 63 | task :server do 64 | system 'nohup appium -p 4530 & nohup appium -p 4527' 65 | end 66 | -------------------------------------------------------------------------------- /appium-ruby/android_appium.txt: -------------------------------------------------------------------------------- 1 | [caps] 2 | platformName = "Android" 3 | automationName = "UiAutomator2" 4 | deviceName = 'orio_27' 5 | app = "/Users/Danilo.Policarpo/dev/appium/build/apk/app-debug.apk" 6 | udid = "emulator-5554" 7 | 8 | [appium_lib] 9 | port = "4527" -------------------------------------------------------------------------------- /appium-ruby/build/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/build/apk/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/apk/app-debug.apk -------------------------------------------------------------------------------- /appium-ruby/build/ipa/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/Default-568h@2x.png -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/Default.png -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/Default@2x.png -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/Info.plist -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/WebViewApp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/WebViewApp -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/cybervillainsCA.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/cybervillainsCA.cer -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPad.storyboardc/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPad.storyboardc/Info.plist -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPad.storyboardc/UIViewController-qCV-AS-rCm.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPad.storyboardc/UIViewController-qCV-AS-rCm.nib -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPad.storyboardc/qCV-AS-rCm-view-Thv-qS-DhF.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPad.storyboardc/qCV-AS-rCm-view-Thv-qS-DhF.nib -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPhone.storyboardc/2-view-3.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPhone.storyboardc/2-view-3.nib -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPhone.storyboardc/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPhone.storyboardc/Info.plist -------------------------------------------------------------------------------- /appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPhone.storyboardc/UIViewController-2.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/build/ipa/WebViewApp.app/en.lproj/MainStoryboard_iPhone.storyboardc/UIViewController-2.nib -------------------------------------------------------------------------------- /appium-ruby/caps_android/mars.txt: -------------------------------------------------------------------------------- 1 | [caps] 2 | platformName = "Android" 3 | deviceName = 'mars' 4 | app = "/Users/Danilo.Policarpo/dev/appium/build/apk/app-debug.apk" 5 | platformVersion= "6.0" 6 | systemPort = 8203 7 | 8 | 9 | [appium_lib] 10 | port = "4528" -------------------------------------------------------------------------------- /appium-ruby/caps_android/nougat.txt: -------------------------------------------------------------------------------- 1 | [caps] 2 | platformName = "Android" 3 | automationName = "UiAutomator2" 4 | deviceName = 'nougat_25' 5 | app = "/Users/Danilo.Policarpo/dev/appium/build/apk/app-debug.apk" 6 | platformVersion= "7.1" 7 | systemPort = 8201 8 | 9 | 10 | [appium_lib] 11 | port = "4527" 12 | 13 | -------------------------------------------------------------------------------- /appium-ruby/caps_android/oreo.txt: -------------------------------------------------------------------------------- 1 | [caps] 2 | platformName = "Android" 3 | automationName = "UiAutomator2" 4 | deviceName = 'orio_27' 5 | app = "/Users/Danilo.Policarpo/dev/appium/build/apk/app-debug.apk" 6 | platformVersion = "8.1" 7 | systemPort = 8202 8 | [appium_lib] 9 | port = "4530" -------------------------------------------------------------------------------- /appium-ruby/comandos.md: -------------------------------------------------------------------------------- 1 | ## Exemplos de Métodos usados no Appium 2 | 3 | - driver.rotate :landscape 4 | 5 | - driver.rotate :portrait 6 | 7 | - find_element(id:'title').text = retorna o texto do elemento 8 | 9 | - find_element(id:'title').name = retorna o texto do elemento 10 | 11 | - find_element(id:'title') = busca o elemento 12 | 13 | - find_element(id:'showInvisible').click = encontra o elemento e toca nele 14 | 15 | - find_element(id:'showInvisible').clear = limpa o campo 16 | 17 | - find_element(id:'showInvisible').tag_name = verifica a class do elemento 18 | 19 | - find_element(id:'showInvisible').displayed? = retorna true ou falso 20 | 21 | - find_element(id:'showInvisible').attribute('checked') = retorna true ou falso para o um checkbox 22 | 23 | - driver.hide_keyboard = somente android por enquanto 24 | 25 | - find_element(name: 'Go').location = valores de x e y 26 | 27 | - find_element(name: 'Go').rect = valores de x,y, height e width 28 | 29 | - start_driver = reinicia o driver 30 | 31 | - find_elements(id:'wandimito')[1] 32 | 33 | - scroll_to("Batman & Robin") 34 | 35 | - scroll_to("direction:'up'") 36 | 37 | - driver.press_keycode(4) 38 | 39 | - driver.navigate 40 | 41 | - driver.back 42 | 43 | - appium.device 44 | 45 | - find_element(:accessibility_id, 'SomeAccessibilityID').attribute("content-desc") 46 | 47 | - find_element(:accessibility_id, "SomeAccessibilityID").enabled? 48 | 49 | - find_element(:accessibility_id, "SomeAccessibilityID").selected? 50 | 51 | - find_element(:accessibility_id, "SomeAccessibilityID").send_keys("Hello World!") 52 | 53 | - Appium::TouchAction.new.tap( x: 539, y:1700, count: 1).release.perform = tocar no elemento por posição com duração default 1000 54 | 55 | - Appium::TouchAction.new.long_press( x: 768, y:456, count: 1, duration: 2000).release.perform = tocar no elemento por posição passando duração 56 | 57 | - teste = find_element(id: 'search') 58 | Appium::TouchAction.new.long_press(element: teste, duration: 2000).release.perform = tocar por elemento 59 | 60 | - def scroll_pra_baixo vezes = 1 61 | swipe(start_y:600, offset_y:200, duration:1000) 62 | end 63 | 2.times do 64 | scroll_pra_baixo 65 | end 66 | = Método de scroll para ios 67 | 68 | - value = ""; 8.times{value << (65 + rand(25)).chr} 69 | value << "@gmail.com" 70 | wait{find_element(id: "showInvisible").send_keys(value)} 71 | find_element(id: "showInvisible").click 72 | = Método para a criação de emails aleatórios 73 | 74 | driver.execute_script 'mobile: scroll', :direction => "down" -------------------------------------------------------------------------------- /appium-ruby/config/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/config/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/config/cucumber.yml: -------------------------------------------------------------------------------- 1 | # config/cucumber.yml 2 | ##YAML Template 3 | --- 4 | android: PLATFORM=android -r features/support -r features/android -r features/step_definitions --exclude features/ios 5 | ios: PLATFORM=ios -r features/support -r features/ios -r features/step_definitions --exclude features/android 6 | 7 | #Sugestão de tags 8 | #--tags ~@manual --tags ~@nok --tags ~@negocio --tags ~@novo --tags ~@ios --tags ~@iOS --tags ~@integrado 9 | 10 | nougat: DEVICE=nougat --exclude features/ios 11 | oreo: DEVICE=oreo --exclude features/ios 12 | mars: DEVICE=mars --exclude features/ios -------------------------------------------------------------------------------- /appium-ruby/config/ios/build_app.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # coding: utf-8 3 | # ---------------------------------------------------------------------------- 4 | # 5 | # $1 -> configuration environment (dev or jenkins) 6 | # $2 -> device type. Builds for 'simulator' or 'device' 7 | # 8 | # 9 | # REMEMBER to fill the configuration file build_app.yml 10 | 11 | require 'fileutils' 12 | require 'yaml' 13 | 14 | # When running on CI 15 | # It is a good pratice rb_sysopento run pod install when executing this script 16 | # on the CI to avoid building problems 17 | # %x(pod install) 18 | 19 | # Parsing the yaml configuration file 20 | config = YAML.load_file(File.join(File.dirname(__FILE__), 'build_app.yml')) 21 | 22 | if ARGV.length < 2 23 | puts 'Error: Wrong number of arguments!' 24 | puts 'Usage: build_app.rb environment device_type' 25 | puts "Available Environments: #{config.keys.join(', ')}" 26 | puts "Device type: 'simulator' or 'device'" 27 | exit 1 28 | end 29 | 30 | puts "Starting at #{Time.now.strftime('%H:%M:%S')}" 31 | 32 | if config[ARGV[0]].nil? 33 | puts 'Error: Wrong configuration environment!' 34 | puts "Available Environments: #{config.keys}" 35 | exit 1 36 | else 37 | config = config[ARGV[0]] 38 | end 39 | 40 | export_path = File.join(config['export_path'], ARGV[1]) 41 | 42 | # Creating the folder where the .app will be stored 43 | puts export_path 44 | FileUtils.mkdir_p export_path 45 | 46 | puts 'Building project' 47 | 48 | system < 5) 4 | def wait_for_element(atributos) 5 | begin 6 | wait = Selenium::WebDriver::Wait.new 7 | wait.until { find_element(atributos).displayed? } 8 | rescue Selenium::WebDriver::Error::TimeOutError => e 9 | raise "Não encontrou resultado da busca \n #{e.message}" 10 | end 11 | end 12 | 13 | # wait_for_click(:id 'xpto') 14 | def wait_for_click(atributos) 15 | begin 16 | wait = Selenium::WebDriver::Wait.new 17 | wait { find_element(atributos).click } 18 | rescue Selenium::WebDriver::Error::TimeOutError => e 19 | raise "Não consegui efetuar a ação \n #{e.message}" 20 | end 21 | end 22 | 23 | def reinstall_apps 24 | @driver.reset 25 | end 26 | 27 | # element_exist(id: @contato,:timeout => 5) 28 | def element_exist(attribute) 29 | begin 30 | wait = Selenium::WebDriver::Wait.new 31 | wait.until { find_element(attribute).displayed? } 32 | rescue 33 | return false 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /appium-ruby/features/android/features/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/android/features/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/features/android/screens/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/android/screens/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/features/android/screens/lista_filmes_screen.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Lista_filme_Screen 4 | def initialize 5 | @layout_name = 'home_omdb' 6 | @buscar_filme = 'search_title' 7 | @btn_buscar = 'search' 8 | @title = 'title' 9 | @btn_favoritos = 'favorite' 10 | end 11 | 12 | def home 13 | wait_for_element(id: @layout_name, timeout: 5) 14 | end 15 | 16 | def buscar_filmes 17 | @filmes = 'batman forever' 18 | find_element(id: @buscar_filme).send_keys(@filmes) 19 | find_element(id: @btn_buscar).click 20 | end 21 | 22 | def titulo_filme 23 | wait_for_element(id: @title, timeout: 5) 24 | end 25 | 26 | def tocar_favoritos 27 | find_element(id: @btn_favoritos).click 28 | find_elements(class: 'android.widget.TextView').text('Favoritos').click 29 | end 30 | 31 | def vejo_favorito 32 | wait_for_element(id: @title, timeout: 5) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /appium-ruby/features/android/support/hooks.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/android/support/hooks.rb -------------------------------------------------------------------------------- /appium-ruby/features/ios/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/ios/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/features/ios/features/acessar_site.feature: -------------------------------------------------------------------------------- 1 | # language: pt 2 | Funcionalidade: Acessar o Site Globo.com 3 | Eu como usuário desejo acessar a tela de login 4 | 5 | Cenário: Acessar a tela de login 6 | Dado que estou na webview 7 | Quando acesso o "site" 8 | Entao vejo a tela de login 9 | 10 | -------------------------------------------------------------------------------- /appium-ruby/features/ios/ios_screen_base.rb: -------------------------------------------------------------------------------- 1 | require 'appium_lib' 2 | 3 | def wait_for_element(atributos) 4 | begin 5 | wait = Selenium::WebDriver::Wait.new :timeout => 5 6 | wait.until { find_element(atributos).displayed? } 7 | rescue Selenium::WebDriver::Error::TimeOutError => e 8 | raise "Não encontrou resultado da busca \n #{e.message}" 9 | end 10 | end 11 | 12 | # wait_for_click(:id 'xpto') 13 | def wait_for_click(atributos) 14 | begin 15 | wait = Selenium::WebDriver::Wait.new :timeout => 5 16 | wait { find_element(atributos).click } 17 | rescue Selenium::WebDriver::Error::TimeOutError => e 18 | raise "Não consegui efetuar a ação \n #{e.message}" 19 | end 20 | end 21 | 22 | 23 | def scroll(direction:, element: nil) 24 | return 'Set "up", "down", "left" or "right" for :direction' unless %w(up down left right).include?(direction) 25 | args = { :direction => direction } 26 | @driver.execute_script 'mobile: scroll', args 27 | end 28 | 29 | def reinstall_apps 30 | @caps = Appium.load_appium_txt file: File.join(Dir.pwd, 'ios_appium.txt') 31 | @caps[:caps].delete :noReset 32 | @caps[:caps].delete :fullReset 33 | Appium::Driver.new(@caps, true) 34 | Appium.promote_appium_methods Object 35 | $driver.start_driver 36 | end 37 | -------------------------------------------------------------------------------- /appium-ruby/features/ios/screens/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/ios/screens/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/features/ios/screens/acessar_site_screen.rb: -------------------------------------------------------------------------------- 1 | class AcessarSiteScreen 2 | def initialize 3 | @layout_name = 'XCUIElementTypeButton' 4 | @url = 'XCUIElementTypeTextField' 5 | @enter = 'XCUIElementTypeButton' 6 | @home_site = 'XCUIElementTypeLink' 7 | end 8 | 9 | def acessar_homePage 10 | find_element(class: @layout_name).text 11 | end 12 | 13 | def acessar_site(site) 14 | @site = CREDENTIALS[site.tr(' ', '_').to_sym][:url] 15 | find_element(class: @url).send_keys @site 16 | find_element(class: @enter).click 17 | end 18 | 19 | def visualizar_home_site 20 | wait_for_element(class: @home_site) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /appium-ruby/features/ios/step_definitions/acessar_site_steps.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Dado(/^que estou na webview$/) do 4 | @site = AcessarSiteScreen.new 5 | @site.acessar_homePage 6 | end 7 | 8 | Quando(/^acesso o "([^"]*)"$/) do |url| 9 | @site.acessar_site url 10 | end 11 | 12 | Entao(/^vejo a tela de login$/) do 13 | @site.visualizar_home_site 14 | end 15 | -------------------------------------------------------------------------------- /appium-ruby/features/ios/support/hooks.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/ios/support/hooks.rb -------------------------------------------------------------------------------- /appium-ruby/features/lista_filme.feature: -------------------------------------------------------------------------------- 1 | # language: pt 2 | 3 | Funcionalidade: Lista de filmes 4 | Eu como usuário 5 | desejo realizar uma busca de filmes por titulo 6 | para poder adicionar na minha lista de favoritos 7 | 8 | Cenário: Realizar uma busca por titulo do filme 9 | Dado que estou na lista de filmes 10 | Quando realizar uma busca por titulo 11 | Então vejo o resultado da busca 12 | 13 | # Cenario: Adicionar filme na lista de favoritos 14 | # Dado que estou na lista de filmes 15 | # E realizar uma busca por titulo 16 | # Quando favoritar o filme desejado 17 | # Então vejo o filme favoritado na aba favoritos 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /appium-ruby/features/step_definitions/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/appium-ruby/features/step_definitions/.DS_Store -------------------------------------------------------------------------------- /appium-ruby/features/step_definitions/lista_filme_step.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Dado('que estou na lista de filmes') do 4 | @lista = Lista_filme_Screen.new 5 | @lista.home 6 | end 7 | 8 | Quando('realizar uma busca por titulo') do 9 | @lista.buscar_filmes 10 | end 11 | 12 | Então('vejo o resultado da busca') do 13 | @lista.titulo_filme 14 | end 15 | 16 | Quando('favoritar o filme desejado') do 17 | @lista.tocar_favoritos 18 | end 19 | 20 | Então('vejo o filme favoritado na aba favoritos') do 21 | @lista.vejo_favorito 22 | end 23 | -------------------------------------------------------------------------------- /appium-ruby/features/support/credentials.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | CREDENTIALS = { 3 | site: { 4 | url: 'www.globo.com' 5 | } 6 | } -------------------------------------------------------------------------------- /appium-ruby/features/support/env.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rspec/expectations' 4 | require 'appium_lib' 5 | require 'pry' 6 | require 'parallel' 7 | 8 | if ENV['PLATFORM'] == 'ios' 9 | caps = Appium.load_appium_txt file: File.join('./ios_appium.txt') 10 | elsif ENV['PLATFORM'] == 'android' 11 | caps = Appium.load_settings file: File.join('./caps_android', 'oreo.txt'), verbose: true 12 | end 13 | 14 | case ENV['DEVICE'] 15 | when 'nougat' 16 | caps = Appium.load_settings file: File.join('./caps_android', 'nougat.txt') 17 | when 'oreo' 18 | caps = Appium.load_settings file: File.join('./caps_android', 'oreo.txt') 19 | when 'mars' 20 | caps = Appium.load_settings file: File.join('./caps_android', 'mars.txt') 21 | end 22 | 23 | 24 | Appium::Driver.new(caps, true) 25 | Appium.promote_appium_methods Object 26 | -------------------------------------------------------------------------------- /appium-ruby/features/support/hooks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Before do 4 | driver.start_driver 5 | end 6 | 7 | After do 8 | driver.driver_quit 9 | end 10 | 11 | Before('@reinstall') do 12 | reinstall_apps 13 | end 14 | 15 | After('@reinstall') do 16 | @caps = Appium.load_appium_txt file: File.join(Dir.pwd, 'ios_caps.txt') 17 | Appium::Driver.new(@caps, true) 18 | Appium.promote_appium_methods Object 19 | end 20 | -------------------------------------------------------------------------------- /appium-ruby/features/support/parallel_test.rb: -------------------------------------------------------------------------------- 1 | 2 | # require_relative '../../lib/appium_lib' 3 | 4 | 5 | # class TestParallelRunThread 6 | # def initialize(capability) 7 | # @capability = capability 8 | # end 9 | 10 | # def setup 11 | # @appium = Appium::Driver.new({ caps: @capability}, false) 12 | # @appium.start_driver 13 | # end 14 | 15 | # def teardown 16 | # @appium.quit_driver 17 | # puts "finish: #{@capability}" 18 | # end 19 | 20 | # def test_run 21 | # setup 22 | 23 | # # tap alert 24 | # @appium.find_element(:name, 'Alerts').click 25 | # @appium.wait_true do 26 | # @appium.find_element(:name, 'Show OK-Cancel').click 27 | # @appium.find_element(:name, 'UIActionSheet ').displayed? 28 | # end 29 | # @appium.alert action: 'accept' 30 | # @appium.back 31 | 32 | # sleep 5 33 | 34 | # # TouchAction 35 | # text_elem = @appium.text(@appium.app_strings['ButtonsExplain']) 36 | # @appium.tap x: 0, y: 0, element: text_elem 37 | # @appium.back 38 | 39 | # teardown 40 | # end 41 | # end 42 | 43 | # class TestParallelRunProcess 44 | # def initialize(capability) 45 | # @capability = capability 46 | # end 47 | 48 | # def setup 49 | # @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false) 50 | # Appium.promote_appium_methods TestParallelRunProcess, @appium 51 | # start_driver 52 | # end 53 | 54 | # def teardown 55 | # quit_driver 56 | # puts "finish: #{@capability}" 57 | # end 58 | 59 | # def test_run 60 | # setup 61 | 62 | # # tap alert 63 | # find_element(:name, 'Alerts').click 64 | # wait_true do 65 | # find_element(:name, 'Show OK-Cancel').click 66 | # find_element(:name, 'UIActionSheet <title>').displayed? 67 | # end 68 | # alert action: 'accept' 69 | # back 70 | 71 | # sleep 5 72 | 73 | # # TouchAction 74 | # text_elem = text(app_strings['ButtonsExplain']) 75 | # tap x: 0, y: 0, element: text_elem 76 | # back 77 | 78 | # teardown 79 | # end 80 | # end 81 | 82 | # # Rakefile 83 | 84 | # class Device 85 | # def self.one 86 | # { 87 | # automationName: 'xcuitest', 88 | # platformName: 'ios', 89 | # platformVersion: '11.0', 90 | # deviceName: 'iPhone 6', 91 | # app: "#{Dir.pwd}/../test_apps/UICatalog.app", 92 | # wdaLocalPort: 8100, 93 | # isCommandsQueueEnabled: false 94 | # } 95 | # end 96 | 97 | # def self.two 98 | # { 99 | # automationName: 'xcuitest', 100 | # platformName: 'ios', 101 | # platformVersion: '11.0', 102 | # deviceName: 'iPhone 6s', 103 | # app: "#{Dir.pwd}/../test_apps/UICatalog.app", 104 | # wdaLocalPort: 8200, 105 | # isCommandsQueueEnabled: false 106 | # } 107 | # end 108 | # end 109 | 110 | # desc 'Run tests with parallel thread' 111 | # task :run_parallel_t do 112 | # require 'thread' 113 | # require_relative 'parallel/test' 114 | 115 | # threads = [] 116 | # [Device.one, Device.two].each do |capability| 117 | # threads << Thread.new do 118 | # TestParallelRunThread.new(capability).test_run 119 | # end 120 | # end 121 | 122 | # threads.each(&:join) 123 | # end 124 | 125 | # desc 'Run tests with parallel processes' 126 | # task :run_parallel_p do 127 | # require_relative 'parallel/test' 128 | 129 | # [Device.one, Device.two].each do |capability| 130 | # fork do 131 | # TestParallelRunProcess.new(capability).test_run 132 | # end 133 | # end 134 | 135 | # Process.waitall 136 | # end -------------------------------------------------------------------------------- /appium-ruby/ios_appium.txt: -------------------------------------------------------------------------------- 1 | [caps] 2 | platformName = "iOS" 3 | platformVersion = "11.4" 4 | deviceName = "iPhone 8" 5 | noReset= "false" 6 | fullReset= "false" 7 | app = "/Users/Danilo.Policarpo/dev/appium/build/ipa/WebViewApp.app" 8 | -------------------------------------------------------------------------------- /backstop.js/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/backstop.js/.gitignore -------------------------------------------------------------------------------- /httparty-ruby/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'httparty' 6 | gem 'rspec' 7 | gem 'pry' 8 | -------------------------------------------------------------------------------- /httparty-ruby/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | coderay (1.1.2) 5 | diff-lcs (1.3) 6 | httparty (0.14.0) 7 | multi_xml (>= 0.5.2) 8 | method_source (0.9.0) 9 | multi_xml (0.6.0) 10 | pry (0.11.2) 11 | coderay (~> 1.1.0) 12 | method_source (~> 0.9.0) 13 | rspec (3.7.0) 14 | rspec-core (~> 3.7.0) 15 | rspec-expectations (~> 3.7.0) 16 | rspec-mocks (~> 3.7.0) 17 | rspec-core (3.7.0) 18 | rspec-support (~> 3.7.0) 19 | rspec-expectations (3.7.0) 20 | diff-lcs (>= 1.2.0, < 2.0) 21 | rspec-support (~> 3.7.0) 22 | rspec-mocks (3.7.0) 23 | diff-lcs (>= 1.2.0, < 2.0) 24 | rspec-support (~> 3.7.0) 25 | rspec-support (3.7.0) 26 | 27 | PLATFORMS 28 | ruby 29 | 30 | DEPENDENCIES 31 | httparty 32 | pry 33 | rspec 34 | 35 | BUNDLED WITH 36 | 1.14.6 37 | -------------------------------------------------------------------------------- /httparty-ruby/Readme.md: -------------------------------------------------------------------------------- 1 | Projeto usado para apresentação do Coders on Beers de QA da Concrete no dia 21/11 2 | Foco em passagem de conhecimento em como realizar testes de serviço 3 | 4 | ## Passo a Passo 5 | 6 | Abra o terminal e execute o comando abaixo : 7 | ``` 8 | bundle install 9 | ``` 10 | 11 | Vamos instalar o servidor Json-server: 12 | ``` 13 | npm install -g json-server 14 | ``` 15 | Agora vamos rodar o servidor Json-Server: 16 | 17 | ``` 18 | json-server --watch endpoints.json 19 | ```` 20 | 21 | O resultado será esse: 22 | ``` 23 | \{^_^}/ hi! 24 | 25 | Loading db.json 26 | Done 27 | 28 | Resources 29 | http://localhost:3000/clientes 30 | 31 | Home 32 | http://localhost:3000 33 | 34 | Type s + enter at any time to create a snapshot of the database 35 | Watching... 36 | 37 | ``` 38 | 39 | ## Executando os testes 40 | 41 | Abra uma nova aba e digite o comando abaixo: 42 | 43 | ``` 44 | cucumber 45 | ``` 46 | 47 | ## Referências 48 | Acesso o github do <a href="https://github.com/danilopolicarpos/Httparty 49 | l">danilopolicarpos/Httparty</a> -------------------------------------------------------------------------------- /httparty-ruby/endpoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "clientes": [ 3 | { 4 | "id": 2, 5 | "nome": "carlos", 6 | "cpf": "123.456.789-00", 7 | "sexo": "Feminino", 8 | "altura": 1.75 9 | }, 10 | { 11 | "id": 1, 12 | "nome": "Maria", 13 | "cpf": "XXXXXXXX", 14 | "sexo": "Feminino", 15 | "altura": 1.75 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /httparty-ruby/features/helper/helper.rb: -------------------------------------------------------------------------------- 1 | 2 | class Helper 3 | def validation_of_type (element , type, element_name) 4 | fail "parametro " + element_name + " invalido" if element.is_a?(type) == false 5 | puts "atributo " + element_name + " valido !" 6 | end 7 | end -------------------------------------------------------------------------------- /httparty-ruby/features/step_definitions/delete.rb: -------------------------------------------------------------------------------- 1 | Dado(/^que envie as informações para deletar$/) do 2 | @contatos_delete = { 3 | "id": 1 4 | }.to_json 5 | end 6 | 7 | Quando(/^realizar uma requisição DELETE para o endpoint "([^"]*)"$/) do |endpoint| 8 | @response = HTTParty.delete 'http://localhost:3000/clientes/1', 9 | :body => @contatos_delete, 10 | :headers => { 11 | "Content-Type" => 'application/json' 12 | } 13 | end 14 | 15 | Entao("retorna a lista de clientes") do 16 | expect(@response.code).to eq 404 17 | expect(@response.size).to eq 0 18 | end -------------------------------------------------------------------------------- /httparty-ruby/features/step_definitions/get.rb: -------------------------------------------------------------------------------- 1 | Dado(/^que tenho um endpoint clientes$/) do 2 | # lista para o endpoint clientes em endpoints.json 3 | end 4 | 5 | Quando(/^realizar uma requisição GET para o endpoint "([^"]*)"$/) do |endpoint| 6 | @response = HTTParty.get 'http://localhost:3000/' + endpoint 7 | end 8 | 9 | Entao(/^retorna a lista com as informacoes dos clientes$/) do 10 | @validator=Helper.new 11 | @validator.validation_of_type @response [0] ["id"], Fixnum , "id" 12 | @validator.validation_of_type @response [0] ["nome"], String , "nome" 13 | @validator.validation_of_type @response [0] ["cpf"], String , "cpf" 14 | @validator.validation_of_type @response [0] ["sexo"], String , "sexo" 15 | @validator.validation_of_type @response [0] ["altura"], Float , "altura" 16 | 17 | end 18 | 19 | E(/^o status code '(\d+)'$/) do |status_code| 20 | status_code = status_code.to_i 21 | expect(@response.code).to eq status_code 22 | end 23 | -------------------------------------------------------------------------------- /httparty-ruby/features/step_definitions/post.rb: -------------------------------------------------------------------------------- 1 | Dado(/^que envie as informações para o endpoint clientes$/) do 2 | @contatos = { 3 | "id": 1, 4 | "nome": "Maria", 5 | "cpf": "XXXXXXXX", 6 | "sexo": "Feminino", 7 | "altura": 1.75 8 | }.to_json 9 | 10 | end 11 | 12 | Quando(/^realizar uma requisição POST para o endpoint "([^"]*)"$/) do |endpoint| 13 | @response = HTTParty.post 'http://localhost:3000/clientes', 14 | :body => @contatos, 15 | :headers => { 16 | "Content-Type" => 'application/json' 17 | } 18 | end 19 | -------------------------------------------------------------------------------- /httparty-ruby/features/step_definitions/put.rb: -------------------------------------------------------------------------------- 1 | Dado(/^que altero as informações do endpoint clientes$/) do 2 | @contatos = { 3 | "id": 1, 4 | "nome": "joao", 5 | "cpf": "123.456.789-00", 6 | "sexo": "Feminino", 7 | "altura": 1.75 8 | }.to_json 9 | end 10 | 11 | Quando(/^realizar uma requisição PUT para o endpoint "([^"]*)"$/) do |endpoint| 12 | @response = HTTParty.put 'http://localhost:3000/clientes/1', 13 | :body => @contatos, 14 | :headers => { 15 | "Content-Type" => 'application/json' 16 | } 17 | end 18 | -------------------------------------------------------------------------------- /httparty-ruby/features/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'httparty' 2 | require 'rspec' 3 | require 'pry' 4 | 5 | -------------------------------------------------------------------------------- /httparty-ruby/features/verbo_delete.feature: -------------------------------------------------------------------------------- 1 | #language: pt 2 | 3 | Funcionalidade: Utilizar o verbo DELETE 4 | 5 | @delete1 6 | Cenario: Realizar uma requisição DELETE com sucesso 7 | Dado que envie as informações para deletar 8 | Quando realizar uma requisição DELETE para o endpoint "clientes" 9 | E o status code '200' 10 | 11 | @delete2 12 | Cenario: Realizar uma requisição DELETE com sucesso 13 | Dado que envie as informações para deletar 14 | Quando realizar uma requisição DELETE para o endpoint "clientes" 15 | E o status code '404' -------------------------------------------------------------------------------- /httparty-ruby/features/verbo_get.feature: -------------------------------------------------------------------------------- 1 | #language: pt 2 | 3 | Funcionalidade: Utilizar o verbo GET 4 | 5 | @get 6 | Cenario: Realizar uma requisição GET com sucesso 7 | Dado que tenho um endpoint clientes 8 | Quando realizar uma requisição GET para o endpoint "clientes" 9 | E retorna a lista com as informacoes dos clientes 10 | Então o status code '200' 11 | -------------------------------------------------------------------------------- /httparty-ruby/features/verbo_post.feature: -------------------------------------------------------------------------------- 1 | #language: pt 2 | 3 | Funcionalidade: Utilizar o verbo POST 4 | 5 | @post 6 | Cenario: Realizar uma requisição POST com sucesso 7 | Dado que envie as informações para o endpoint clientes 8 | Quando realizar uma requisição POST para o endpoint "clientes" 9 | Então o status code '201' 10 | -------------------------------------------------------------------------------- /httparty-ruby/features/verbo_put.feature: -------------------------------------------------------------------------------- 1 | #language: pt 2 | 3 | Funcionalidade: Utilizar o verbo PUT 4 | 5 | @put 6 | Cenario: Realizar uma requisição PUT com sucesso 7 | Dado que altero as informações do endpoint clientes 8 | Quando realizar uma requisição PUT para o endpoint "clientes" 9 | Então o status code '200' -------------------------------------------------------------------------------- /jest/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | #__snapshots__ 24 | /src/components/__snapshots__ -------------------------------------------------------------------------------- /jest/README.md: -------------------------------------------------------------------------------- 1 | # qa-automation-sample: JEST 2 | > Repository with examples of unit tests using Jest. 3 | > Jest is a library for testing javascript code. Jest is an open source project maintained by facebook. 4 | 5 | --- 6 | ## Table of Contents 7 | > Índice `README`. 8 | - [Clone](#clone) 9 | - [Prerequisite](#prerequisite) 10 | - [Installation](#installation) 11 | - [Support](#support) 12 | - [License](#license) 13 | --- 14 | ### Clone 15 | - Clone this repo to your local machine using `https://github.com/concretesolutions/qa-automation-samples` 16 | 17 | --- 18 | ## Prerequisite 19 | - [Node install](https://nodejs.org/en/download/) 20 | - [Npm install](https://www.npmjs.com/get-npm) 21 | - [jest install](https://www.npmjs.com/package/jest) 22 | 23 | --- 24 | ## Installation 25 | - Install all dependencies (package.json) 26 | $npm i 27 | ![Install example](http://g.recordit.co/OwakU85ifp.gif) 28 | > Tips 29 | - Use scripts (package.json) for shortcut 30 | 31 | --- 32 | ### Run test 33 | - Execute your tests scripts: 34 | 35 | > run jest test watch mode 36 | ```shell 37 | $ npm run test 38 | ``` 39 | 40 | > run jest test coverage mode 41 | ```shell 42 | $ npm run test:coverage 43 | ``` 44 | 45 | --- 46 | ## Support 47 | - Website at <a href="https://concrete.com.br" target="_blank">`Concrete`</a> 48 | - Twitter at <a href="https://twitter.com/ConcreteS" target="_blank">`@ConcreteS`</a> 49 | - Facebook at <a href="https://www.facebook.com/ConcreteS" target="_blank">`FB - Concrete`</a> 50 | - Instagram at <a href="https://www.instagram.com/concretebr" target="_blank">`IG - Concrete`</a> 51 | - E-mail: `contato@concrete.com.br` 52 | 53 | --- 54 | ## License 55 | [![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](http://badges.mit-license.org) 56 | - **[MIT license](http://opensource.org/licenses/mit-license.php)** 57 | - Copyright 2018 © <a href="http://concrete.com.br" target="_blank">Concrete</a> 58 | 59 | --- -------------------------------------------------------------------------------- /jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-jest", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "lodash": "^4.17.10", 7 | "react-redux": "^5.0.7", 8 | "react-scripts": "1.1.4", 9 | "redux": "^4.0.0", 10 | "redux-thunk": "^2.3.0", 11 | "sfcookies": "^1.0.2" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "test:coverage": "react-scripts test --env=jsdom --coverage", 18 | "eject": "react-scripts eject" 19 | }, 20 | "devDependencies": { 21 | "enzyme": "^3.3.0", 22 | "enzyme-adapter-react-16": "^1.1.1", 23 | "fetch-mock": "^6.5.0", 24 | "jest-cli": "^20.0.4", 25 | "react": "^16.4.1", 26 | "react-dom": "^16.4.1", 27 | "react-test-render": "^1.1.1", 28 | "redux-mock-store": "^1.5.3" 29 | }, 30 | "jest": { 31 | "collectCoverageFrom": [ 32 | "src/**/*.js", 33 | "!src/index.js" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jest/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/jest/public/favicon.ico -------------------------------------------------------------------------------- /jest/public/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 6 | <meta name="theme-color" content="#000000"> 7 | <!-- 8 | manifest.json provides metadata used when your web app is added to the 9 | homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ 10 | --> 11 | <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> 12 | <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> 13 | <!-- 14 | Notice the use of %PUBLIC_URL% in the tags above. 15 | It will be replaced with the URL of the `public` folder during the build. 16 | Only files inside the `public` folder can be referenced from the HTML. 17 | 18 | Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will 19 | work correctly both with client-side routing and a non-root public URL. 20 | Learn how to configure a non-root public URL by running `npm run build`. 21 | --> 22 | <title>React App 23 | 24 | 25 | 28 |
    29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /jest/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /jest/src/actions/balance.js: -------------------------------------------------------------------------------- 1 | import * as constants from './constants'; 2 | 3 | export const setBalance = balance => { 4 | return { 5 | type: constants.SET_BALANCE, 6 | balance 7 | } 8 | } 9 | 10 | export const deposit = deposit => { 11 | return { 12 | type: constants.DEPOSIT, 13 | deposit 14 | } 15 | } 16 | 17 | export const withdraw = withdraw => { 18 | return { 19 | type: constants.WITHDRAW, 20 | withdraw 21 | } 22 | } -------------------------------------------------------------------------------- /jest/src/actions/balance.test.js: -------------------------------------------------------------------------------- 1 | import * as constants from './constants'; 2 | import * as actions from './balance'; 3 | 4 | it('creates an action to set the balance',() => { 5 | const balance = 0; 6 | 7 | const expectedAction = { type: constants.SET_BALANCE, balance }; 8 | 9 | expect(actions.setBalance(balance)).toEqual(expectedAction); 10 | 11 | }); 12 | 13 | 14 | it('creates an action to deposit into the balance', () => { 15 | const deposit = 10; 16 | 17 | const expectedAction = { type: constants.DEPOSIT, deposit }; 18 | 19 | expect(actions.deposit(deposit)).toEqual(expectedAction); 20 | }); 21 | 22 | it('creates an action to withdraw from the balance', () => { 23 | const withdraw = 10; 24 | 25 | const expectedAction = { type: constants.WITHDRAW, withdraw }; 26 | 27 | expect(actions.withdraw(withdraw)).toEqual(expectedAction); 28 | }); -------------------------------------------------------------------------------- /jest/src/actions/bitcoin.js: -------------------------------------------------------------------------------- 1 | import { FETCH_BITCOIN } from './constants'; 2 | 3 | export const fetchBitcoin = () => { 4 | return dispatch => { 5 | return fetch('https://api.coindesk.com/v1/bpi/currentprice.json') 6 | .then(response => response.json()) 7 | .then(json => dispatch({ type: FETCH_BITCOIN, bitcoin: json})) 8 | } 9 | }; -------------------------------------------------------------------------------- /jest/src/actions/bitcoin.test.js: -------------------------------------------------------------------------------- 1 | 2 | // https://api.coindesk.com/v1/bpi/currentprice.json 3 | import configureMockStore from 'redux-mock-store'; 4 | import thunk from 'redux-thunk'; 5 | import fetchMock from 'fetch-mock'; 6 | import { FETCH_BITCOIN } from './constants'; 7 | import { fetchBitcoin } from './bitcoin'; 8 | 9 | const createMockStore = configureMockStore([thunk]); 10 | const store = createMockStore({ bitcoin: {} }); 11 | 12 | const mockResponse = { body: { bpi: 'bitcoin price index' }}; 13 | 14 | fetchMock.get('https://api.coindesk.com/v1/bpi/currentprice.json', mockResponse); 15 | 16 | it('creates an async action to fetch the bitcoin value', () => { 17 | const expectedActions = [{ bitcoin: mockResponse.body, type: FETCH_BITCOIN}]; 18 | 19 | return store.dispatch(fetchBitcoin()).then(() => { 20 | expect(store.getActions()).toEqual(expectedActions); 21 | }); 22 | }); -------------------------------------------------------------------------------- /jest/src/actions/constants.js: -------------------------------------------------------------------------------- 1 | export const SET_BALANCE = 'SET_BALANCE'; 2 | export const DEPOSIT = 'DEPOSIT'; 3 | export const WITHDRAW = 'WITHDRAW'; 4 | export const FETCH_BITCOIN = 'FETCH_BITCOIN'; -------------------------------------------------------------------------------- /jest/src/assets/bitcoin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/jest/src/assets/bitcoin.jpg -------------------------------------------------------------------------------- /jest/src/assets/bitcoin.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/jest/src/assets/bitcoin.mp4 -------------------------------------------------------------------------------- /jest/src/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Wallet from './Wallet'; 3 | import Loot from './Loot'; 4 | 5 | const App = () => { 6 | return ( 7 |
    8 |

    Wallet Bitcoin

    9 |
    10 | 11 |
    12 | 13 |
    Powered by Coindesk :)
    14 |
    15 | ) 16 | } 17 | 18 | export default App; -------------------------------------------------------------------------------- /jest/src/components/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import App from './App'; 4 | import setupTests from './../setupTest'; 5 | 6 | describe('App', () => { 7 | const app = shallow(); 8 | 9 | it('renders properly', () => { 10 | expect(app).toMatchSnapshot(); 11 | }); 12 | 13 | it('contains a connected Wallet component', () => { 14 | expect(app.find('Connect(Wallet)').exists()).toBe(true); 15 | }); 16 | 17 | it('constains a connected loot component', () => { 18 | expect(app.find('Connect(Loot)').exists()).toBe(true); 19 | }); 20 | 21 | it('contains a link to the coindesk price page', () => { 22 | expect(app.find('a').props().href).toBe('http://www.coindesk.com/price'); 23 | }); 24 | }); -------------------------------------------------------------------------------- /jest/src/components/Loot.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { fetchBitcoin } from '../actions/bitcoin'; 4 | 5 | export class Loot extends Component { 6 | componentDidMount() { 7 | this.props.fetchBitcoin(); 8 | 9 | } 10 | computeBitcoin() { 11 | const { bitcoin } = this.props; 12 | 13 | if(Object.keys(bitcoin).length === 0) return ''; 14 | 15 | return this.props.balance / parseInt(bitcoin.bpi.USD.rate.replace(',', ''), 10); 16 | } 17 | render(){ 18 | return( 19 |

    Bitcoin balance: {this.computeBitcoin()}

    20 | ) 21 | } 22 | } 23 | 24 | export default connect(state => state, { fetchBitcoin })(Loot); -------------------------------------------------------------------------------- /jest/src/components/Loot.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount, shallow } from 'enzyme'; 3 | import { Loot } from './Loot'; 4 | import setupTests from './../setupTest'; 5 | 6 | describe('Loot', () => { 7 | let props = { balance: 10, bitcoin: {} }; 8 | let loot = shallow(); 9 | 10 | it('renders properly', () => { 11 | expect(loot).toMatchSnapshot(); 12 | }); 13 | 14 | describe('when mounted', () => { 15 | const mockFetchbitcoin = jest.fn(); 16 | 17 | beforeEach(() => { 18 | props.fetchBitcoin = mockFetchbitcoin; 19 | loot = mount(); 20 | }); 21 | 22 | it('dispatches the `fetchBitcoin()` method it receives from props', () => { 23 | expect(mockFetchbitcoin).toHaveBeenCalled(); 24 | }); 25 | 26 | describe('when there are valid bitcoin props', () => { 27 | beforeEach(() => { 28 | props = { balance: 10, bitcoin: {bpi: { USD: { rate: '1,000' } } } }; 29 | loot = shallow(); 30 | }); 31 | it('display the correct bitcoin value',() => { 32 | expect(loot.find('h3').text()).toEqual('Bitcoin balance: 0.01'); 33 | }); 34 | }); 35 | }); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /jest/src/components/Wallet.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { deposit, withdraw } from '../actions/balance'; 4 | 5 | export class Wallet extends Component{ 6 | constructor() { 7 | super(); 8 | 9 | this.state = { balance: undefined }; 10 | } 11 | 12 | updateBalance = event => this.setState({ balance: parseInt(event.target.value, 10) }) 13 | 14 | deposit = () => this.props.deposit(this.state.balance) 15 | 16 | withdraw = () => this.props.withdraw(this.state.balance) 17 | 18 | render() { 19 | return( 20 |
    21 |

    Wallet Balance: {this.props.balance}

    22 |
    23 | 24 |
    25 | 26 | 27 |
    28 | ) 29 | } 30 | } 31 | 32 | export default connect(state => { return { balance : state.balance } }, { deposit, withdraw })(Wallet); -------------------------------------------------------------------------------- /jest/src/components/Wallet.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { Wallet } from './Wallet'; 4 | import setupTests from './../setupTest'; 5 | 6 | describe('Wallet', () => { 7 | const mockDeposit = jest.fn(); 8 | const mockWithdraw = jest.fn(); 9 | const props = { balance: 20, deposit: mockDeposit, withdraw: mockWithdraw}; 10 | const wallet = shallow(); 11 | 12 | it('snapshot', () => { 13 | expect(wallet).toMatchSnapshot(); 14 | }) 15 | it ('display the balance from props', () => { 16 | expect(wallet.find('.balance').text()).toEqual('Wallet Balance: 20'); 17 | }); 18 | 19 | it('creates an input to deposit into or withdraw from balance', () => { 20 | expect(wallet.find('.input-wallet').exists()).toBe(true); 21 | }); 22 | 23 | describe('when the user types into the wallet input', () => { 24 | const userBalance = '25'; 25 | 26 | beforeEach(() => { 27 | wallet.find('.input-wallet') 28 | .simulate('change', { target: { value: userBalance}}); 29 | 30 | }); 31 | 32 | it('updates the local wallet balance in `state` and converts it to a number', () => { 33 | expect(wallet.state().balance).toEqual(parseInt(userBalance, 10)); 34 | }); 35 | 36 | describe('and the user wants to make a deposit', () => { 37 | beforeEach(() => wallet.find('.btn-deposit').simulate('click')); 38 | 39 | it('dispatches the `deposit()` it receives from props with the local balance', () => { 40 | expect(mockDeposit).toHaveBeenCalledWith(parseInt(userBalance, 10)); 41 | }); 42 | }); 43 | 44 | describe('and the user wants to make a withdraw', () => { 45 | beforeEach(() => wallet.find('.btn-withdraw').simulate('click')); 46 | 47 | it('dispatches the `withdraw()` it receives from props with the local balance', () => { 48 | expect(mockWithdraw).toHaveBeenCalledWith(parseInt(userBalance, 10)); 49 | }); 50 | }); 51 | }); 52 | }); -------------------------------------------------------------------------------- /jest/src/index.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-image: url('./assets/bitcoin.jpg'); 3 | text-align: center; 4 | } 5 | h2, h3{ 6 | text-align: center; 7 | text-shadow: 1px 1px gray; 8 | padding: 5%; 9 | font-size: 28px; 10 | color: white; 11 | } 12 | button{ 13 | margin-left: 5px; 14 | } 15 | 16 | 17 | button, input{ 18 | text-align: center; 19 | width: 200px; 20 | height: 30px; 21 | border: 2px solid gray; 22 | border-radius: 30px; 23 | background-color: white; 24 | text-align: center; 25 | font-size: 20px; 26 | } -------------------------------------------------------------------------------- /jest/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { createStore, applyMiddleware } from 'redux'; 4 | import thunk from 'redux-thunk'; 5 | import rootReduccer from './reducers'; 6 | import { Provider } from 'react-redux'; 7 | import App from './components/App'; 8 | import './index.css'; 9 | 10 | render ( 11 | 12 | 13 | , 14 | document.getElementById('root') 15 | ); 16 | -------------------------------------------------------------------------------- /jest/src/reducers/balance.js: -------------------------------------------------------------------------------- 1 | import * as constants from '../actions/constants'; 2 | import { read_cookie , bake_cookie } from 'sfcookies'; 3 | 4 | const BALANCE_COOKIE = 'BALANCE_COOKIE'; 5 | 6 | const balance = (state = 0, action) => { 7 | let balance; 8 | 9 | switch (action.type) { 10 | case constants.SET_BALANCE: 11 | balance = action.balance; 12 | break; 13 | 14 | case constants.DEPOSIT: 15 | balance = state + action.deposit; 16 | break; 17 | 18 | case constants.WITHDRAW: 19 | balance = state - action.withdraw; 20 | break; 21 | default: 22 | balance = read_cookie(BALANCE_COOKIE), 10 || state; 23 | break; 24 | } 25 | bake_cookie(BALANCE_COOKIE, balance); 26 | return balance; 27 | } 28 | 29 | export default balance; -------------------------------------------------------------------------------- /jest/src/reducers/balance.test.js: -------------------------------------------------------------------------------- 1 | import balanceReducer from './balance'; 2 | import balanceReducer2 from './balance'; 3 | import * as constants from '../actions/constants'; 4 | import { withdraw } from '../actions/balance'; 5 | 6 | describe('balanceReducer', () => { 7 | 8 | describe('when initializing', () => { 9 | const balance = 10; 10 | 11 | it('sets a balance', () => { 12 | expect(balanceReducer(undefined, { type: constants.SET_BALANCE, balance})) 13 | .toEqual(balance); 14 | }); 15 | 16 | describe('then re-initalizing', () => { 17 | it('read the balance from cookies', () => { 18 | expect(balanceReducer2(undefined, {})).toEqual(balance); 19 | }); 20 | }); 21 | }); 22 | 23 | 24 | it('deposits into the balance', () => { 25 | const deposit = 10; 26 | const initialState = 5; 27 | 28 | expect(balanceReducer(initialState, { type: constants.DEPOSIT, deposit })) 29 | .toEqual(initialState + deposit); 30 | }); 31 | 32 | it('whithdraws from the balance', () => { 33 | const whithdraw = 10; 34 | const initialState = 20; 35 | 36 | expect(balanceReducer(initialState, {type: constants.WITHDRAW, whithdraw })) 37 | .toEqual(initialState - withdraw); 38 | }); 39 | }); -------------------------------------------------------------------------------- /jest/src/reducers/bitcoin.js: -------------------------------------------------------------------------------- 1 | import { FETCH_BITCOIN } from '../actions/constants' 2 | 3 | const bitcoin = (state = {}, action) => { 4 | switch(action.type){ 5 | case FETCH_BITCOIN: 6 | return action.bitcoin; 7 | default: 8 | return state; 9 | } 10 | }; 11 | 12 | export default bitcoin; -------------------------------------------------------------------------------- /jest/src/reducers/bitcoin.test.js: -------------------------------------------------------------------------------- 1 | import bitcoinReducer from './bitcoin'; 2 | import { FETCH_BITCOIN } from '../actions/constants' 3 | 4 | describe('bitcoinReducer', () => { 5 | const bitcoinData = { bpi: 'bitcoin price index' }; 6 | 7 | it('fetches and sets the bitcoin data', () => { 8 | expect(bitcoinReducer({}, { type: FETCH_BITCOIN, bitcoin: bitcoinData })) 9 | .toEqual(bitcoinData); 10 | }); 11 | 12 | }); 13 | -------------------------------------------------------------------------------- /jest/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import balance from './balance'; 3 | import bitcoin from './bitcoin'; 4 | 5 | export default combineReducers({ balance, bitcoin }); -------------------------------------------------------------------------------- /jest/src/reducers/index.test.js: -------------------------------------------------------------------------------- 1 | import rootReducer from './index'; 2 | 3 | describe('rootReducer', () => { 4 | it('initalizes the default state', () => { 5 | expect(rootReducer({}, {})).toEqual({ balance: [], bitcoin: {} }); 6 | }); 7 | }); -------------------------------------------------------------------------------- /jest/src/setupTest.js: -------------------------------------------------------------------------------- 1 | 2 | import { configure } from 'enzyme'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | 5 | configure({ adapter: new Adapter(), disableLifecycleMethods: true }); -------------------------------------------------------------------------------- /nightwatch/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/nightwatch/.gitignore -------------------------------------------------------------------------------- /pact/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/pact/.gitignore -------------------------------------------------------------------------------- /protractor/.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/ -------------------------------------------------------------------------------- /protractor/README.md: -------------------------------------------------------------------------------- 1 | # qa-automation-sample: PROTRACTOR 2 | 3 | > Repository with examples of automation using Protractor 4 | 5 | > Protractor is an end-to-end test framework for Angular and AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would. 6 | 7 | --- 8 | 9 | ## Table of Contents 10 | 11 | > Índice `README`. 12 | 13 | - [Prerequisites](#prerequisites) 14 | - [Installation](#installation) 15 | - [Features](#features) 16 | - [Support](#support) 17 | - [License](#license) 18 | 19 | --- 20 | 21 | ## Prerequisites 22 | 23 | - [Node install](https://nodejs.org/en/download/) 24 | - [Npm install](https://www.npmjs.com/get-npm) 25 | - [Protractor install](https://www.npmjs.com/package/protractor) 26 | 27 | ## Installation 28 | 29 | - Install all dependencies (package.json: `./protractor` and folder: `/shared_libs`) 30 | 31 | ![Install example](http://g.recordit.co/0xODbJSVZ1.gif) 32 | 33 | > Tips 34 | 35 | - Use scripts (package.json) for shortcut 36 | 37 | ### Clone 38 | 39 | - Clone this repo to your local machine using `https://github.com/concretesolutions/qa-automation-samples` 40 | 41 | ### Run test 42 | 43 | - Run selenium server and then execute your tests scripts: 44 | 45 | > run server and tests 46 | 47 | ```shell 48 | $ npm run start_update_webdriver 49 | $ npm run test 50 | ``` 51 | 52 | > stop server 53 | 54 | ```shell 55 | $ npm run_stop_webdriver 56 | ``` 57 | 58 | --- 59 | 60 | ## Features 61 | - file example `.feature` 62 | 63 | ```gherkin 64 | Feature: Learning to use Protractor 65 | As a QA 66 | I want to learn how to use Protractor 67 | To be able to automate angular applications 68 | 69 | Scenario Outline: Validate texts in angular.org website 70 | Given Im on the page 71 | When I fill in the text field with "" 72 | Then I checked if the text "Hello " was successfully validated 73 | 74 | Examples: 75 | | name | 76 | | Concrete | 77 | | QA Analyst | 78 | | Any Name | 79 | ``` 80 | 81 | --- 82 | 83 | ## Support 84 | 85 | - Website at `Concrete` 86 | - Twitter at `@ConcreteS` 87 | - Facebook at `FB - Concrete` 88 | - Instagram at `IG - Concrete` 89 | 90 | - E-mail: `contato@concrete.com.br` 91 | 92 | --- 93 | 94 | ## License 95 | 96 | [![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](http://badges.mit-license.org) 97 | 98 | - **[MIT license](http://opensource.org/licenses/mit-license.php)** 99 | - Copyright 2018 © Concrete. -------------------------------------------------------------------------------- /protractor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qa-automation-samples", 3 | "version": "1.0.0", 4 | "description": "Project tests", 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 && 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 | -------------------------------------------------------------------------------- /protractor/quality_assurance/conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Data = require('./environments_parameters.json') 4 | 5 | const TEST_ENV = process.env.TEST_ENV || 'local' 6 | let environmentParameters 7 | 8 | switch (TEST_ENV) { 9 | case 'local': 10 | environmentParameters = Data[0].local 11 | break 12 | } 13 | 14 | exports.config = { 15 | seleniumAddress: environmentParameters.seleniumAddress, 16 | ignoreUncaughtExceptions: true, 17 | framework: 'custom', 18 | frameworkPath: require.resolve('protractor-cucumber-framework'), 19 | restartBrowserBetweenTests: false, 20 | getPageTimeout: 50000, 21 | allScriptsTimeout: 30000, 22 | rootElement: '*[ng-app]', 23 | baseUrl: environmentParameters.baseUrl, 24 | params: { 25 | 26 | }, 27 | 28 | specs: [ 29 | 'features/*.feature' 30 | ], 31 | 32 | exclude: [ 33 | ], 34 | 35 | capabilities: { 36 | 'browserName': 'chrome', 37 | chromeOptions: { 38 | args: [ 39 | '--disable-gpu' 40 | ] 41 | } 42 | }, 43 | 44 | cucumberOpts: { 45 | require: '../features/step_definitions/*.js', 46 | tags: ['~@notImplemented'], 47 | format: ['json:results.json'], 48 | profile: false, 49 | 'no-source': true 50 | }, 51 | 52 | beforeLaunch: function () { 53 | setTimeout(function () { 54 | browser.driver.executeScript(function () { 55 | return { 56 | width: window.screen.availWidth, 57 | height: window.screen.availHeight 58 | } 59 | }).then(function (result) { 60 | browser.driver.manage().window().setSize(result.width, result.height) 61 | }) 62 | }) 63 | }, 64 | 65 | onPrepare: function () { 66 | // Use only for angular applications 67 | // False: app Angular 68 | // True: app not Angular 69 | browser.ignoreSynchronization = false 70 | }, 71 | 72 | afterLaunch: function () { 73 | var reporter = require('cucumber-html-reporter') 74 | 75 | var options = { 76 | theme: 'bootstrap', 77 | jsonFile: 'results.json', 78 | output: 'report/cucumber_report.html', 79 | reportSuiteAsScenarios: true, 80 | launchReport: true, 81 | storeScreenshots: false, 82 | metadata: { 83 | 'App Version': '0.0.1', 84 | 'Test Environment': 'STAGING', 85 | 'Browser': 'Chrome 69.0.3497.100', 86 | 'Platform': 'OSX', 87 | 'Parallel': 'Scenarios', 88 | 'Executed': 'Remote' 89 | } 90 | } 91 | reporter.generate(options) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /protractor/quality_assurance/environments_parameters.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "local": { 3 | "seleniumAddress": "http://localhost:4444/wd/hub", 4 | "baseUrl": "https://angularjs.org" 5 | } 6 | }] -------------------------------------------------------------------------------- /protractor/quality_assurance/features/hooks/hooks.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const wait_sec = 1000; 4 | const { BeforeAll, After, Status } = require("cucumber"); 5 | 6 | BeforeAll({ timeout: 60 * wait_sec }, async function () { 7 | console.log("\nStart executing tests ....") 8 | }); 9 | 10 | After(async function (scenario) { 11 | let world = this; 12 | if (scenario.result.status === Status.FAILED) { 13 | return await browser.takeScreenshot().then(function (buffer) { 14 | return world.attach(buffer, "image/png"); 15 | }); 16 | } 17 | }); -------------------------------------------------------------------------------- /protractor/quality_assurance/features/page_objects/angular_po.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const Helper = require('../shared_libs/helper.js') 3 | 4 | class AngularPage { 5 | constructor () { 6 | this.helper = new Helper() 7 | this.inputName = $('input[ng-model="yourName"]') 8 | this.inputSearch = $('input[id="projects_search"]') 9 | this.resultText = $('h1[class="ng-binding"]') 10 | } 11 | 12 | open (link) { 13 | return browser.get(link) 14 | } 15 | 16 | fillText (text) { 17 | this.helper.elementIsPresenceDom(this.inputName) 18 | return this.inputName.sendKeys(text) 19 | } 20 | } 21 | 22 | module.exports = AngularPage 23 | -------------------------------------------------------------------------------- /protractor/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 if the text "Hello !" was successfully validated 13 | 14 | Examples: 15 | | name | 16 | | Concrete | 17 | | QA Analyst | 18 | | Any Name | -------------------------------------------------------------------------------- /protractor/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 59 | Helper.prototype.getScreenshot = function (name) { 60 | function writeScreenShot (data, filename) { 61 | var stream = fs.createWriteStream(filename) 62 | stream.write(Buffer.from(data, 'base64').toString()); 63 | stream.end() 64 | } 65 | return browser.takeScreenshot().then((png) => { 66 | writeScreenShot(png, 'report/screenshots/' + name + '.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 | -------------------------------------------------------------------------------- /protractor/quality_assurance/features/shared_libs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shared_libs", 3 | "version": "1.0.0", 4 | "description": "folder with files to be shared between the project", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "Lucas Fraga", 9 | "license": "MIT", 10 | "dependencies": { 11 | "fs": "0.0.1-security", 12 | "safe-buffer": "^5.1.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /protractor/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 if the text {string} was successfully validated', async function (text) { 16 | await expect(page.resultText.getText()) 17 | .to.eventually.equal(text) 18 | }) -------------------------------------------------------------------------------- /selenium-java/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | test/* 4 | allure* 5 | !/src/test/resources/allure.properties 6 | !AllureHelper.java 7 | build 8 | errorShots 9 | package-lock.json 10 | mochawesome-report 11 | .DS_Store 12 | test_result.json 13 | /target/ 14 | .idea/ 15 | .scripts/ 16 | /evidence/ 17 | 18 | # Created by https://www.gitignore.io/api/visualstudiocode 19 | 20 | ### VisualStudioCode ### 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | .history 27 | 28 | 29 | # End of https://www.gitignore.io/api/visualstudiocode 30 | 31 | #.gitignore for Java projects (using eclipse) 32 | 33 | # Linux 34 | # backup files 35 | *~ 36 | 37 | # Windows 38 | # thumbnails 39 | Thumbs.db 40 | 41 | # Mac OS X 42 | # metadata 43 | .DS_Store 44 | # thumbnails 45 | ._* 46 | 47 | # GIT 48 | .git/ 49 | 50 | # Java 51 | *.class 52 | # packages 53 | *.jar 54 | *.war 55 | *.ear 56 | 57 | # Eclipse 58 | .settings/ 59 | .buildpath 60 | .classpath 61 | .project 62 | 63 | # Logging 64 | *.log 65 | 66 | # jME (binaries) 67 | *.so -------------------------------------------------------------------------------- /selenium-java/README.md: -------------------------------------------------------------------------------- 1 | # qa-automation-sample: SELENIUM-JAVA 2 | 3 | > Repository with examples of automation using selenium + java 4 | 5 | > Selenium is a portable software-testing framework for web applications. Selenium provides a playback tool for authoring tests without the need to learn a test scripting language. 6 | 7 | --- 8 | 9 | ## Table of Contents 10 | 11 | > Índice `README`. 12 | 13 | - [Prerequisites](#prerequisites) 14 | - [Configuration](#configuration) 15 | - [Installation](#installation) 16 | - [Features](#features) 17 | - [Report](#report) 18 | - [Support](#support) 19 | - [License](#license) 20 | 21 | --- 22 | 23 | ## Prerequisites 24 | 25 | - [JDK install +8](https://www.oracle.com/technetwork/java/javase/downloads/index.html) 26 | - [Eclipse IDE install](http://www.eclipse.org/downloads/) 27 | - [Maven install](https://maven.apache.org/install.html) 28 | - [Cucumber plugin install](http://toolsqa.com/cucumber/install-cucumber-eclipse-plugin/) 29 | 30 | 31 | ## Configuration 32 | > environment variables and bash_profile 33 | 34 | ###Java 35 | - Mac: 36 | `export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home` 37 | 38 | - Windows: 39 | https://confluence.atlassian.com/doc/setting-the-java_home-variable-in-windows-8895.html 40 | 41 | ###Maven 42 | - Mac: 43 | `export PATH=/opt/apache-maven-3.5.3/bin:$PATH` 44 | 45 | - Windows: 46 | https://www.mkyong.com/maven/how-to-install-maven-in-windows/ 47 | 48 | ## Installation 49 | 50 | - Install all dependencies (pom.xml) 51 | `mvn install` 52 | 53 | ![Maven install example](http://g.recordit.co/AC3WJT4g4D.gif) 54 | 55 | > Tips 56 | 57 | - Use pom.xml to install the project dependencies 58 | 59 | ### Clone 60 | 61 | - Clone this repo to your local machine using `https://github.com/concretesolutions/qa-automation-samples` 62 | 63 | ### Run test 64 | 65 | > run test Maven 66 | 67 | ```shell 68 | $ mvn clean test 69 | ``` 70 | 71 | > run test Cucumber 72 | 73 | ```shell 74 | $ mvn clean -Dtest=CucumberRunnerTest test 75 | ``` 76 | 77 | > run test Eclipse 78 | 79 | Right click on class CucumberRunnerTest.java> Run as> JUnit Test 80 | 81 | 82 | --- 83 | 84 | ## Features 85 | - file example `.feature` 86 | 87 | ```gherkin 88 | Feature: Learning to use selenium with java 89 | As a QA 90 | I want to learn how to use selenium 91 | To be able to automate applications 92 | 93 | Scenario Outline: Validate texts in concrete.com.br website 94 | Given Im on the page 95 | When I fill in the text field with "" 96 | Then I checked if the text "" was successfully validated 97 | 98 | Examples: 99 | | name | expected | 100 | | Concrete | A Concrete no QCon SP 2011 – parte 1 | 101 | | Lucas Fraga | Utilizando async/await com Protractor | 102 | ``` 103 | 104 | ## Report 105 | 106 | > run allure report 107 | 108 | ```shell 109 | $ mvn allure:serve 110 | ``` 111 | 112 | --- 113 | 114 | ## Support 115 | 116 | - Website at `Concrete` 117 | - Twitter at `@ConcreteS` 118 | - Facebook at `FB - Concrete` 119 | - Instagram at `IG - Concrete` 120 | 121 | - E-mail: `contato@concrete.com.br` 122 | 123 | --- 124 | 125 | ## License 126 | 127 | [![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](http://badges.mit-license.org) 128 | 129 | - **[MIT license](http://opensource.org/licenses/mit-license.php)** 130 | - Copyright 2018 © Concrete. -------------------------------------------------------------------------------- /selenium-java/drivers/linux/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/linux/chromedriver -------------------------------------------------------------------------------- /selenium-java/drivers/linux/geckodriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/linux/geckodriver -------------------------------------------------------------------------------- /selenium-java/drivers/mac/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/mac/chromedriver -------------------------------------------------------------------------------- /selenium-java/drivers/mac/geckodriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/mac/geckodriver -------------------------------------------------------------------------------- /selenium-java/drivers/windows/IEDriverServer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/windows/IEDriverServer.exe -------------------------------------------------------------------------------- /selenium-java/drivers/windows/MicrosoftWebDriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/windows/MicrosoftWebDriver.exe -------------------------------------------------------------------------------- /selenium-java/drivers/windows/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/windows/chromedriver.exe -------------------------------------------------------------------------------- /selenium-java/drivers/windows/geckodriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/selenium-java/drivers/windows/geckodriver.exe -------------------------------------------------------------------------------- /selenium-java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | br.com.selenium 6 | java-project 7 | 0.0.1-SNAPSHOT 8 | 9 | 10 | 1.8.11 11 | UTF-8 12 | 1.8 13 | 1.8 14 | 15 | 16 | 17 | 18 | junit 19 | junit 20 | 4.12 21 | test 22 | 23 | 24 | 25 | org.seleniumhq.selenium 26 | selenium-java 27 | 3.14.0 28 | 29 | 30 | 31 | io.qameta.allure 32 | allure-cucumber-jvm 33 | 2.7.0 34 | test 35 | 36 | 37 | 38 | io.cucumber 39 | cucumber-jvm 40 | 4.2.0 41 | pom 42 | 43 | 44 | 45 | com.google.code.gson 46 | gson 47 | 2.8.5 48 | 49 | 50 | 51 | com.squareup.okhttp3 52 | okhttp 53 | 3.11.0 54 | 55 | 56 | 57 | commons-io 58 | commons-io 59 | 2.6 60 | 61 | 62 | 63 | org.aspectj 64 | aspectjweaver 65 | ${aspectj.version} 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-surefire-plugin 74 | 2.22.1 75 | 76 | 1.8 77 | 1.8 78 | 79 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" 80 | 81 | 82 | 83 | 84 | 85 | allure.results.directory 86 | ${project.build.directory}/allure-results 87 | 88 | 89 | 90 | ${browser} 91 | ${urlConcrete} 92 | 93 | 94 | 95 | 96 | io.qameta.allure 97 | allure-maven 98 | 2.9 99 | 100 | 2.5.0 101 | ${soapui.results.directory} 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /selenium-java/src/resources/config.properties: -------------------------------------------------------------------------------- 1 | url_concrete : https://concrete.com.br/ -------------------------------------------------------------------------------- /selenium-java/src/resources/features/example.feature: -------------------------------------------------------------------------------- 1 | #language: en 2 | 3 | @example 4 | Feature: Learning to use selenium with java 5 | As a QA 6 | I want to learn how to use selenium 7 | To be able to automate applications 8 | 9 | Scenario Outline: Validate texts in concrete.com.br website 10 | Given Im on the page 11 | When I fill in the text field with "" 12 | Then I checked if the text "" was successfully validated 13 | 14 | Examples: 15 | | name | expected | 16 | | Concrete | A Concrete no QCon SP 2011 – parte 1 | 17 | | Lucas Fraga | Utilizando async/await com Protractor | -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/enums/Browsers.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.enums; 2 | 3 | import java.net.URL; 4 | import org.openqa.selenium.WebDriver; 5 | import java.net.MalformedURLException; 6 | import org.openqa.selenium.edge.EdgeDriver; 7 | import org.openqa.selenium.chrome.ChromeDriver; 8 | import org.openqa.selenium.chrome.ChromeOptions; 9 | import org.openqa.selenium.firefox.FirefoxDriver; 10 | import org.openqa.selenium.remote.RemoteWebDriver; 11 | import org.openqa.selenium.ie.InternetExplorerDriver; 12 | import br.com.selenium.java_project.utils.DriverFactory; 13 | import br.com.selenium.java_project.utils.HandleProperties; 14 | 15 | public enum Browsers { 16 | 17 | IE_WINDOWS("webdriver.ie.driver", "\\IEDriverServer.exe"), 18 | MOZILLA_WINDOWS("webdriver.gecko.driver", "\\geckodriver.exe"), 19 | CHROME_WINDOWS("webdriver.chrome.driver", "\\chromedriver.exe"), 20 | EDGE_WINDOWS("webdriver.edge.driver", "\\MicrosoftWebDriver.exe"), 21 | CHROME_MAC("webdriver.chrome.driver", "/chromedriver"); 22 | 23 | public static WebDriver webDriver; 24 | private String browserType; 25 | private String executable; 26 | 27 | Browsers(String browserType , String executable){ 28 | this.browserType = browserType; 29 | this.executable = executable; 30 | } 31 | 32 | public String getBrowserType(){ 33 | return browserType; 34 | } 35 | 36 | public String getExecutable(){ 37 | return executable; 38 | } 39 | 40 | public static void showAvaliableBrowsersOptions(){ 41 | for (Browsers browsers : Browsers.values()) { 42 | System.out.println("======= " . concat(browsers.name())); 43 | } 44 | } 45 | 46 | public WebDriver createDriverInstance() { 47 | switch (browserType) { 48 | case "webdriver.ie.driver": 49 | return new InternetExplorerDriver(); 50 | case "webdriver.gecko.driver": 51 | return new FirefoxDriver(); 52 | case "webdriver.chrome.driver": 53 | return new ChromeDriver(); 54 | case "webdriver.edge.driver": 55 | return new EdgeDriver(); 56 | default: 57 | return null; 58 | } 59 | } 60 | 61 | public static void setWebDriver() { 62 | if (Boolean.parseBoolean(System.getProperty("url_concrete"))) { 63 | try { 64 | String urlConcrete = System.getProperty("urlConcrete") != null ? System.getProperty("urlConcrete") 65 | : HandleProperties.getValue("url_concrete"); 66 | webDriver = new RemoteWebDriver(new URL(urlConcrete), new ChromeOptions()); 67 | } catch (MalformedURLException e) { 68 | e.printStackTrace(); 69 | } 70 | } else { 71 | webDriver = DriverFactory.createDriver(System.getProperty("browser")); 72 | } 73 | } 74 | 75 | public static void quitDriver() { 76 | webDriver.quit(); 77 | webDriver = null; 78 | } 79 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/enums/OperationSystems.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.enums; 2 | 3 | import java.io.File; 4 | 5 | public enum OperationSystems { 6 | 7 | MAC_OS_X("drivers/mac/"), 8 | WINDOWS_7("drivers/windows/"), 9 | WINDOWS_10("drivers/windows/"), 10 | LINUX("drivers/linux/"); 11 | 12 | private String driverPath; 13 | 14 | OperationSystems(String driverPath){ 15 | this.driverPath = driverPath; 16 | } 17 | 18 | public String getDriversPath() { 19 | return new File(driverPath).getAbsolutePath(); 20 | } 21 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/pages/ConcretePage.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.pages; 2 | 3 | import org.openqa.selenium.By; 4 | import br.com.selenium.java_project.utils.HandleProperties; 5 | import br.com.selenium.java_project.utils.Page; 6 | 7 | public class ConcretePage extends Page { 8 | 9 | private static final By INPUT_SEARCH = By.cssSelector("input[placeholder='faça sua busca...']"); 10 | private static final By BUTTON_SEARCH = By.cssSelector("span[class='icon-search']"); 11 | 12 | public void visit(String url) { 13 | String urlConcrete = System.getProperty("urlConcrete") != null ? System.getProperty("urlConcrete") 14 | : HandleProperties.getValue("url_concrete"); 15 | openUrl(urlConcrete); 16 | isUrlContainsValue(url); 17 | } 18 | 19 | public void fillIn(String text) { 20 | isElementAttachedToHtml(INPUT_SEARCH); 21 | fillInput(text, INPUT_SEARCH); 22 | click(BUTTON_SEARCH); 23 | } 24 | 25 | public boolean verifySearch(String message) { 26 | By MESSAGE = By.xpath("//div[@class='_byCx']//h3//div[contains(.,'" + message + "')]"); 27 | isElementAttachedToHtml(MESSAGE); 28 | return getTextFromLabel(MESSAGE).equals(message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/pages/ElementBy.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.pages; 2 | 3 | import org.openqa.selenium.By; 4 | 5 | public abstract class ElementBy extends By { 6 | 7 | public static By dataAttribute(String data) { 8 | return By.cssSelector("[data-test='" + data + "']"); 9 | } 10 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/runner/CucumberRunnerTest.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.runner; 2 | 3 | import org.junit.BeforeClass; 4 | import org.junit.runner.RunWith; 5 | import cucumber.api.junit.Cucumber; 6 | import cucumber.api.CucumberOptions; 7 | import br.com.selenium.java_project.enums.Browsers; 8 | 9 | @RunWith(Cucumber.class) 10 | @CucumberOptions(features="src/resources/", 11 | plugin= {"io.qameta.allure.cucumberjvm.AllureCucumberJvm"}, 12 | glue = "br/com/selenium/java_project/test/steps/definitions", 13 | tags= {"~@notImplemented"}) 14 | 15 | public class CucumberRunnerTest { 16 | 17 | @BeforeClass 18 | public static void tearUp() { 19 | Browsers.setWebDriver(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/test/steps/definitions/Hooks.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.test.steps.definitions; 2 | 3 | import cucumber.api.Scenario; 4 | import cucumber.api.java.After; 5 | import br.com.selenium.java_project.enums.Browsers; 6 | import br.com.selenium.java_project.utils.AllureHelper; 7 | 8 | public class Hooks { 9 | 10 | @After 11 | public void afterEachScenario(Scenario scenario) { 12 | AllureHelper.saveScreenshootOfScenario(scenario); 13 | Browsers.quitDriver(); 14 | } 15 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/test/steps/definitions/exampleSteps.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.test.steps.definitions; 2 | 3 | import cucumber.api.java.Before; 4 | import cucumber.api.java.en.Then; 5 | import cucumber.api.java.en.When; 6 | import cucumber.api.java.en.Given; 7 | import static org.junit.Assert.assertTrue; 8 | import br.com.selenium.java_project.pages.ConcretePage; 9 | 10 | public class exampleSteps { 11 | 12 | private static ConcretePage concrete; 13 | 14 | @Before 15 | public static void setup() { 16 | concrete = new ConcretePage(); 17 | } 18 | 19 | //-----------------------------------DADO---------------------------------------------------------- 20 | @Given("^Im on the page$") 21 | public void im_on_the_page() { 22 | concrete.visit("Concrete"); 23 | } 24 | 25 | //-----------------------------------QUANDO--------------------------------------------------------- 26 | @When("^I fill in the text field with \"([^\"]*)\"$") 27 | public void i_fill_in_the_text_field_with(String name) { 28 | concrete.fillIn(name); 29 | } 30 | 31 | //-----------------------------------ENTÃO---------------------------------------------------------- 32 | @Then("^I checked if the text \"([^\"]*)\" was successfully validated$") 33 | public void i_checked_if_the_text_was_successfully_validated(String expected) { 34 | assertTrue(concrete.verifySearch(expected)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/utils/AllureHelper.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.utils; 2 | 3 | import java.io.InputStream; 4 | import cucumber.api.Scenario; 5 | import io.qameta.allure.Allure; 6 | import java.io.ByteArrayInputStream; 7 | import org.openqa.selenium.OutputType; 8 | import org.openqa.selenium.TakesScreenshot; 9 | 10 | public class AllureHelper { 11 | 12 | private static void screenShot(String status, Scenario scenario) { 13 | byte[] screenshootBytes = ((TakesScreenshot) Page.getDriver()).getScreenshotAs(OutputType.BYTES); 14 | InputStream screenshootStream = new ByteArrayInputStream(screenshootBytes); 15 | Allure.addAttachment(scenario.getName() +" - "+ status, screenshootStream); 16 | } 17 | 18 | public static void saveScreenshootOfScenario(Scenario scenario) { 19 | if (!scenario.isFailed()) { 20 | screenShot("PASSED", scenario); 21 | 22 | } else { 23 | screenShot("FAILED", scenario); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/utils/DriverFactory.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.utils; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.chrome.ChromeDriver; 5 | import org.openqa.selenium.chrome.ChromeOptions; 6 | import br.com.selenium.java_project.enums.Browsers; 7 | import br.com.selenium.java_project.enums.OperationSystems; 8 | 9 | public class DriverFactory { 10 | 11 | public static WebDriver createDriver(String mvnParameter){ 12 | if (mvnParameter == null){ 13 | System.setProperty(Browsers.CHROME_MAC.getBrowserType(), 14 | OperationSystems.MAC_OS_X.getDriversPath().concat(Browsers.CHROME_MAC.getExecutable())); 15 | ChromeOptions options = new ChromeOptions(); 16 | options.addArguments("--start-fullscreen", "--disable-gpu"); 17 | return new ChromeDriver(options); 18 | } 19 | 20 | try { 21 | String soName = getSoName(); 22 | String browserType = getBrowserTypeFromParameter(mvnParameter); 23 | System.setProperty(browserType, getDriversPath(soName).concat(getFullExecutableNameFromParameter(mvnParameter))); 24 | }catch (Exception e){ 25 | System.out.println("ERROR: Please select one of the valid browsers for the test."); 26 | Browsers.showAvaliableBrowsersOptions(); 27 | System.exit(1); 28 | } 29 | 30 | return Browsers.valueOf(mvnParameter).createDriverInstance(); 31 | } 32 | 33 | private static String formatSoName(String soName){ 34 | return soName.replace(" ", "_").toUpperCase(); 35 | } 36 | 37 | private static String getBrowserTypeFromParameter(String mvnParameter ){ 38 | return Browsers.valueOf(mvnParameter).getBrowserType(); 39 | } 40 | 41 | private static String getDriversPath(String osName){ 42 | return OperationSystems.valueOf(formatSoName(osName)).getDriversPath(); 43 | } 44 | 45 | private static String getSoName(){ 46 | return System.getProperty("os.name"); 47 | } 48 | 49 | private static String getFullExecutableNameFromParameter (String mvnParameter){ 50 | return Browsers.valueOf(mvnParameter).getExecutable(); 51 | } 52 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/utils/HandleProperties.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.utils; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | import java.io.FileInputStream; 6 | 7 | public class HandleProperties { 8 | 9 | private static final String PROPERTIES = "./src/resources/config.properties"; 10 | 11 | private static Properties properties; 12 | 13 | public static String getValue(String value) { 14 | try { 15 | if(properties == null) { 16 | HandleProperties.properties = new Properties(); 17 | HandleProperties.properties.load( new FileInputStream(PROPERTIES)); 18 | } 19 | 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | } 23 | 24 | return HandleProperties.properties.getProperty(value); 25 | } 26 | } -------------------------------------------------------------------------------- /selenium-java/src/test/java/br/com/selenium/java_project/utils/Page.java: -------------------------------------------------------------------------------- 1 | package br.com.selenium.java_project.utils; 2 | 3 | import java.util.List; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.Keys; 6 | import org.openqa.selenium.WebDriver; 7 | import org.openqa.selenium.WebElement; 8 | import org.openqa.selenium.interactions.Actions; 9 | import br.com.selenium.java_project.enums.Browsers; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | import org.openqa.selenium.support.ui.ExpectedConditions; 12 | 13 | public class Page { 14 | 15 | private static final long DEFAULT_TIME_WAIT = 10; 16 | 17 | public Page() { 18 | if (Browsers.webDriver == null) { 19 | Browsers.setWebDriver(); 20 | } 21 | } 22 | 23 | public static WebDriver getDriver() { 24 | return Browsers.webDriver; 25 | } 26 | 27 | protected void openUrl(String url) { 28 | getDriver().get(url); 29 | } 30 | 31 | protected String getUrl() { 32 | return getDriver().getCurrentUrl(); 33 | } 34 | 35 | protected boolean isUrlContainsValue(String text) { 36 | return getUrl().contains(text); 37 | } 38 | 39 | protected WebElement waitElement(By locator) { 40 | return new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 41 | .until(ExpectedConditions.presenceOfElementLocated(locator)); 42 | } 43 | 44 | protected List waitElements(By locator) { 45 | return new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 46 | .until(ExpectedConditions.presenceOfAllElementsLocatedBy(locator)); 47 | } 48 | 49 | protected boolean isVisible(By locator) { 50 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 51 | .until(ExpectedConditions.visibilityOf(getElement(locator))); 52 | return getElement(locator).isDisplayed(); 53 | } 54 | 55 | protected void isNotVisible(By locator) { 56 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 57 | .until(ExpectedConditions.invisibilityOf(getElement(locator))); 58 | } 59 | 60 | protected boolean isClickable(By locator) { 61 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 62 | .until(ExpectedConditions.elementToBeClickable(getElement(locator))); 63 | return getElement(locator).isDisplayed() && getElement(locator).isEnabled(); 64 | } 65 | 66 | protected void waitForTextInElement(By locator, String textToBeWait) { 67 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 68 | .until(ExpectedConditions.textToBe(locator, textToBeWait)); 69 | } 70 | 71 | protected void waitForTextPresentInElement(By locator, String textToBeWait) { 72 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 73 | .until(ExpectedConditions.textToBePresentInElement(getElement(locator), textToBeWait)); 74 | } 75 | 76 | protected void waitForElementToBeSelected(By locator) { 77 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 78 | .until(ExpectedConditions.elementToBeSelected(getElement(locator))); 79 | } 80 | 81 | protected void waitElementInvisible(By locator) { 82 | new WebDriverWait(getDriver(), DEFAULT_TIME_WAIT) 83 | .until(ExpectedConditions.invisibilityOfElementLocated((locator))); 84 | } 85 | 86 | protected WebElement getElement(By locator) { 87 | return waitElement(locator); 88 | } 89 | 90 | protected List getElements(By locator) { 91 | return waitElements(locator); 92 | } 93 | 94 | protected void clickOn(By locator) { 95 | isVisible(locator); 96 | new Actions(getDriver()).moveToElement(getElement(locator)).perform(); 97 | getElement(locator).click(); 98 | } 99 | 100 | protected void fillInput(String dados, By locator) { 101 | isVisible(locator); 102 | getElement(locator).clear(); 103 | this.waitForTextInElement(locator, ""); 104 | getElement(locator).sendKeys(dados); 105 | } 106 | 107 | protected void click(By locator) { 108 | isClickable(locator); 109 | getElement(locator).click(); 110 | } 111 | 112 | protected void check(By locator) { 113 | if (!getElement(locator).isSelected()) { 114 | click(locator); 115 | waitForChecked(locator); 116 | } 117 | } 118 | 119 | protected void unCheck(By locator) { 120 | if (getElement(locator).isSelected()) { 121 | click(locator); 122 | waitForNotChecked(locator); 123 | } 124 | } 125 | 126 | protected boolean waitForChecked(By locator) { 127 | return getElement(locator).isSelected(); 128 | } 129 | 130 | protected boolean waitForNotChecked(By locator) { 131 | return !getElement(locator).isSelected(); 132 | } 133 | 134 | protected boolean isVisibleOnMouse(By locator) { 135 | isVisible(locator); 136 | new Actions(getDriver()).moveToElement(getElement(locator)).perform(); 137 | return getElement(locator).isDisplayed(); 138 | } 139 | 140 | protected String getTextFromLabel(By locator) { 141 | return getElement(locator).getText().trim(); 142 | } 143 | 144 | protected String getTextOfVisibleElement(WebElement element) { 145 | String text = null; 146 | try { 147 | text = element.getText().trim(); 148 | } catch (Exception e) { 149 | System.out.println(element + " : " + e); 150 | } 151 | return text; 152 | } 153 | 154 | protected boolean isElementAttachedToHtml(By locator) { 155 | try { 156 | waitElement(locator); 157 | return true; 158 | } catch (Exception e) { 159 | return false; 160 | } 161 | } 162 | 163 | protected void pressTab(By locator) { 164 | isVisible(locator); 165 | getElement(locator).sendKeys(Keys.TAB); 166 | } 167 | 168 | protected void pressEnter(By locator) { 169 | isVisible(locator); 170 | getElement(locator).sendKeys(Keys.ENTER); 171 | } 172 | } -------------------------------------------------------------------------------- /splinter/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/splinter/.gitignore -------------------------------------------------------------------------------- /supertestApi/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # Mac OS files 64 | *.DS_Store -------------------------------------------------------------------------------- /supertestApi/README.md: -------------------------------------------------------------------------------- 1 | 2 | Small project for show an api test structure using Supertest, Mocha, Chai and Joi 3 | 4 | ================================================================================= 5 | 6 | #### Requirements: 7 | 8 | * Node.js (JavaScript runtime built on Chrome`s V8 JavaScript engine). Donwload [here](https://nodejs.org/en/) 9 | 10 | #### Dependencies: 11 | 12 | * Mocha (mocha is a feature-rich JavaScript test framework running on Node.js and in the browser) 13 | * SuperTest (module is to provide a high-level abstraction for testing HTTP, while still allowing you to drop down to the lower-level API provided by superagent) 14 | * Chai (Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework) 15 | * Joi (Object schema description language and validator for JavaScript objects) 16 | 17 | #### Setup dependencies: 18 | 19 | * npm install (in root directory) 20 | 21 | #### Run: 22 | 23 | * npm run test_api (in root directory) 24 | * mocha -R spec file path (in root directory for run a specific spec) 25 | 26 | #### Checking javaScript lint errors: 27 | 28 | * npm run static_test (in root directory) 29 | * npm run static_fix (in root directory / to fix errors) 30 | 31 | #### Project Structure: 32 | 33 | * Directory (./response_schemes) 34 | * Response schemes expected 35 | 36 | * Directory (./searchByCapital) 37 | * Test Cases 38 | 39 | 40 | -------------------------------------------------------------------------------- /supertestApi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evj_supertest_api", 3 | "version": "1.0.0", 4 | "description": "This is small project for showing an api test automation structure using Supertest, Mocha and Chai", 5 | "main": "index.js", 6 | "scripts": { 7 | "test_api": "node_modules/mocha/bin/_mocha --recursive **/**Test.js && standard", 8 | "static_test": "standard", 9 | "static_fix": "standard --fix" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/Eloyvj/evjSupertestApi.git" 14 | }, 15 | "author": "Eloy Vitorio", 16 | "license": "Free", 17 | "homepage": "http://github.com", 18 | "devDependencies": { 19 | "chai": "^1.10.0", 20 | "chai-sorted": "^0.1.0", 21 | "eslint": "^3.18.0", 22 | "mocha": "^5.2.0", 23 | "standard": "10.0.3", 24 | "supertest": "^3.3.0", 25 | "supertest-as-promised": "^4.0.2" 26 | }, 27 | "dependencies": { 28 | "bluebird": "^3.5.0", 29 | "joi": "^10.6.0" 30 | }, 31 | "standard": { 32 | "globals": [ 33 | "describe", 34 | "it", 35 | "before", 36 | "afterEach", 37 | "beforeEach", 38 | "after" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /supertestApi/response_schemes/reponseCapitalData.js: -------------------------------------------------------------------------------- 1 | const Joi = require('joi') 2 | 3 | function getSchema () { 4 | const schema = Joi.object().keys({ 5 | currencies: Joi.array().min(1).items(Joi.object().keys({ 6 | code: Joi.string().required(), 7 | name: Joi.string().required(), 8 | symbol: Joi.string().required() 9 | })), 10 | name: Joi.string().required(), 11 | capital: Joi.string().required() 12 | }) 13 | return schema 14 | } 15 | 16 | module.exports = { 17 | getSchema 18 | } 19 | -------------------------------------------------------------------------------- /supertestApi/searchByCapital/returnListCapitalDataTest.js: -------------------------------------------------------------------------------- 1 | const request = require('supertest') 2 | const utils = require('../utils.js') 3 | const chai = require('chai') 4 | const expect = require('chai').expect 5 | const Joi = require('joi') 6 | const url = utils.getUrl() 7 | const schema = require('../response_schemes/reponseCapitalData.js') 8 | 9 | chai.use(require('chai-sorted')) 10 | 11 | describe('GET on /capital/:capital', () => { 12 | const path = `/capital` 13 | it('should be return currencies, name, capital', done => { 14 | const capitalName = 'brasilia' 15 | request(url) 16 | .get(`${path}/${capitalName}`) 17 | .query({ 18 | fields: 'name;capital;currencies' 19 | }) 20 | .end((err, res) => { 21 | expect(res.status).to.be.eql(200) 22 | // Print data for debug 23 | console.log('Retorno: ' + res.status) 24 | console.log('Código da moeda: ' + res.body[0].currencies[0].code) 25 | console.log('Nome da moeda: ' + res.body[0].currencies[0].name) 26 | console.log('Simbolo da moeda: ' + res.body[0].currencies[0].symbol) 27 | console.log('País: ' + res.body[0].name) 28 | console.log('Capital: ' + res.body[0].capital) 29 | // End print 30 | if (err) return done(err) 31 | const actual = res.body[0] 32 | err = Joi.validate(actual, schema.getSchema()).error 33 | if (err) return done(err) 34 | done() 35 | }) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /supertestApi/utils.js: -------------------------------------------------------------------------------- 1 | // utils.js - add commons methods here 2 | function getUrl () { 3 | return process.env.BACKEND_URL || 'https://restcountries.eu/rest/v2' 4 | } 5 | 6 | module.exports = { 7 | getUrl 8 | } 9 | -------------------------------------------------------------------------------- /wedbriver.io/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/concretesolutions/qa-automation-samples/c8fb94594303445ae792a4b24d7adf9f981e4ba9/wedbriver.io/.gitignore --------------------------------------------------------------------------------