├── .gitignore ├── .travis.yml ├── CI ├── README.md ├── after_script ├── before_install_docker ├── before_install_setup ├── install ├── run_scenario ├── script └── script_archive ├── Dockerfile ├── Jenkinsfile ├── README.md ├── add-item-to-shopping-cart ├── README.md ├── java-fluentlenium │ ├── README.md │ ├── complete │ │ ├── pom.xml │ │ └── src │ │ │ └── test │ │ │ └── java │ │ │ └── AddItemToShoppingCartTest.java │ └── initial │ │ ├── pom.xml │ │ └── src │ │ └── test │ │ └── java │ │ └── AddItemToShoppingCartTest.java └── js-webdriverio │ ├── README.md │ ├── complete │ ├── package-lock.json │ ├── package.json │ ├── test │ │ └── specs │ │ │ └── addToShoppingCartTest.js │ └── wdio.conf.js │ └── initial │ ├── package-lock.json │ ├── package.json │ ├── test │ └── specs │ │ └── addToShoppingCartTest.js │ └── wdio.conf.js ├── first-test ├── README.md ├── java-testng │ ├── README.md │ ├── pom.xml │ └── src │ │ └── test │ │ └── java │ │ └── FirstWebDriverTestJavaTestNGTest.java └── js-mocha-chai │ ├── .nvmrc │ ├── README.md │ ├── package-lock.json │ ├── package.json │ └── test │ └── first-webdriver-test-js-mocha-chai.js ├── page-objects ├── README.md ├── java-fluentlenium │ ├── README.md │ ├── complete │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── pages │ │ │ │ ├── HomePage.java │ │ │ │ ├── ProductDetailPage.java │ │ │ │ ├── SearchResultsPage.java │ │ │ │ └── ShoppingCartPage.java │ │ │ └── test │ │ │ └── java │ │ │ └── AddItemToShoppingCartTest.java │ └── initial │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ └── java │ │ │ └── pages │ │ │ ├── HomePage.java │ │ │ └── SearchResultsPage.java │ │ └── test │ │ └── java │ │ └── AddItemToShoppingCartTest.java └── js-webdriverio │ ├── complete │ ├── package-lock.json │ ├── package.json │ ├── pageobjects │ │ ├── home.page.js │ │ ├── page.js │ │ ├── productDetail.page.js │ │ ├── searchResults.page.js │ │ └── shoppingCart.page.js │ ├── specs │ │ └── addToShoppingCartTest.js │ └── wdio.conf.js │ └── initial │ ├── package-lock.json │ ├── package.json │ ├── pageobjects │ ├── home.page.js │ ├── page.js │ └── searchResults.page.js │ ├── specs │ └── addToShoppingCartTest.js │ └── wdio.conf.js └── running-in-parallel ├── README.md ├── java-testng ├── README.md ├── complete │ ├── pom.xml │ └── src │ │ └── test │ │ └── java │ │ ├── BaseTest.java │ │ ├── EcommSitesTest.java │ │ └── SearchEnginesTest.java └── initial │ ├── pom.xml │ └── src │ └── test │ └── java │ ├── EcommSitesTest.java │ └── SearchEnginesTest.java └── js-mocha-chai ├── README.md ├── complete ├── .nvmrc ├── Gruntfile.js ├── package.json └── test │ ├── base.js │ ├── ecomm-sites.js │ └── search-engines.js └── initial ├── .nvmrc ├── package.json └── test ├── ecomm-sites.js └── search-engines.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | target 4 | node_modules 5 | npm-debug.log 6 | CI/videos 7 | errorShots 8 | allure-report 9 | allure-results 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | services: 4 | - docker 5 | 6 | language: node_js 7 | node_js: 8 | - "7.4" 9 | 10 | install: 11 | - ./CI/install 12 | 13 | env: 14 | - TEST_NAME="first-test" TEST_LANG="java" TEST_TYPE="basic" 15 | - TEST_NAME="first-test" TEST_LANG="js" TEST_TYPE="basic" 16 | - TEST_NAME="add-item-to-shopping-cart" TEST_LANG="java" TEST_TYPE="advan" 17 | - TEST_NAME="add-item-to-shopping-cart" TEST_LANG="js" TEST_TYPE="advan" 18 | - TEST_NAME="page-objects" TEST_LANG="java" TEST_TYPE="advan" 19 | - TEST_NAME="page-objects" TEST_LANG="js" TEST_TYPE="advan" 20 | - TEST_NAME="running-in-parallel" TEST_LANG="java" TEST_TYPE="advan" 21 | - TEST_NAME="running-in-parallel" TEST_LANG="js" TEST_TYPE="advan" 22 | script: 23 | - ./CI/script 24 | 25 | after_script: 26 | - ./CI/script_archive 27 | - ./CI/after_script 28 | 29 | branches: 30 | only: 31 | - master -------------------------------------------------------------------------------- /CI/README.md: -------------------------------------------------------------------------------- 1 | # Steps to add TravisCI 2 | Here users may find useful to see how TravisCI was added to this project, step by step. 3 | 4 | 1. Enable TravisCI on this project at [your profile page](https://travis-ci.org/profile/diemol). 5 | Note you will need to signup to TravisCI by linking your Github account. 6 | 7 | 1. Check the [repo automatic build](https://travis-ci.org/diemol/frontend_testing) is enabled. 8 | 9 | 1. Sign up for an [open source Sauce Labs account](https://saucelabs.com/opensauce) and grab the `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` value to be used later on. 10 | 11 | 1. Environment variables that are secrets like `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` need to be set [in the travis-ci settings page](https://travis-ci.org/diemol/frontend_testing/settings). **Important** do **NOT** enable the option `Display value in build log` 12 | 13 | 1. Add the image badges in the README repo file. 14 | ```markdown 15 | [![Build Status](https://travis-ci.org/diemol/frontend_testing.svg?branch=master)](https://travis-ci.org/diemol/frontend_testing) 16 | ``` 17 | 18 | 1. Probably already have it but create a `.travis.yml` file at the root of the project declaring the build steps. 19 | Push the changes to trigger a new CI build. 20 | -------------------------------------------------------------------------------- /CI/after_script: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set -e: exit asap if a command exits with a non-zero status 4 | set -e 5 | 6 | # long wait 7 | docker exec grid stop || true 8 | docker stop grid || true 9 | docker rm grid || true 10 | 11 | # fast wait 12 | # docker rm -vf grid || true 13 | -------------------------------------------------------------------------------- /CI/before_install_docker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set -e: exit asap if a command exits with a non-zero status 4 | # set -x: print each command right before it is executed 5 | set -xe 6 | 7 | # cleanup 8 | service docker stop || true 9 | rm -f /etc/apt/sources.list.d/docker.list 10 | apt-get -qqy purge lxc-docker || true 11 | apt-get -qqy purge docker-engine || true 12 | /etc/init.d/apparmor stop || true 13 | rm -rf /var/lib/docker /dev/mapper/docker* /usr/bin/docker /run/docker /etc/docker 14 | rm -rf /etc/apt/sources.list.d/docker* /etc/default/docker /etc/init.d/docker /etc/apparmor.d/cache/docker 15 | rm -rf /etc/apparmor.d/docker /etc/bash_completion.d/docker /var/log/upstart/docker* 16 | rm -rf /var/lib/apt/lists/*docker* /var/lib/dpkg/info/*docker* /dev/disk/by-id/*docker* 17 | rm -rf /var/cache/apt/archives/docker* 18 | 19 | # install 20 | CODE_NAME=$(lsb_release -sc) #e.g. trusty 21 | [ "${CODE_NAME}" == "" ] && CODE_NAME=trusty 22 | echo "deb https://apt.dockerproject.org/repo ubuntu-${CODE_NAME} main" >> /etc/apt/sources.list.d/docker.list 23 | # sed -i.bak '/docker/d' /etc/apt/sources.list.d/docker.list 24 | apt-get -qqy update 25 | apt-get -qqy install apt-transport-https ca-certificates 26 | apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D 27 | apt-cache policy docker-engine || true 28 | apt-get -qqy install linux-image-extra-$(uname -r) 29 | apt-get -qqy install apparmor 30 | /etc/init.d/apparmor start || true 31 | export DEBCONF_NONINTERACTIVE_SEEN=true 32 | apt-get -qqy install docker-engine 33 | service docker start || true 34 | 35 | docker --version 36 | -------------------------------------------------------------------------------- /CI/before_install_setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set -e: exit asap if a command exits with a non-zero status 4 | # set -x: print each command right before it is executed 5 | set -xe 6 | 7 | # sudo apt-get install -qyy tree 8 | 9 | docker --version || echo "INFO: No docker installed yet" 10 | 11 | sudo ./CI/before_install_docker 12 | 13 | docker --version || (echo "FATAL: No docker installed" && exit 1) 14 | -------------------------------------------------------------------------------- /CI/install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set -e: exit asap if a command exits with a non-zero status 4 | # set -x: print each command right before it is executed 5 | set -xe 6 | 7 | curl -sSL https://raw.githubusercontent.com/dosel/t/i/p | bash -s 3 start 8 | -------------------------------------------------------------------------------- /CI/run_scenario: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Runs one of the tests scenarios 3 | 4 | # set -e: exit asap if a command exits with a non-zero status 5 | # set -x: print each command right before it is executed 6 | set -xe 7 | 8 | # echo fn that outputs to stderr http://stackoverflow.com/a/2990533/511069 9 | echoerr() { 10 | cat <<< "$@" 1>&2; 11 | } 12 | 13 | # print error and exit 14 | die () { 15 | echoerr "ERROR: $1" 16 | # if $2 is defined AND NOT EMPTY, use $2; otherwise, set to "3" 17 | errnum=${2-3} 18 | exit $errnum 19 | } 20 | 21 | # Required params 22 | [ -z "${1}" ] && die "Need first argument to be the test name, i.e. scenario directory" 23 | test_name=${1} 24 | [ -z "${2}" ] && die "Need second argument to be the test type (basic/advan)" 25 | test_type=${2} 26 | [ -z "${3}" ] && die "Need third argument test language (java/js)" 27 | test_lang=${3} 28 | 29 | echo "#================================" 30 | echo "# Scenario ${test_name}" 31 | echo "#================================" 32 | 33 | echo "Starting ${test_lang} tests..." 34 | cd ${test_name} 35 | 36 | if [ "${test_lang}" = "java" ]; then 37 | java -version 38 | mvn --version 39 | cd java-* 40 | 41 | if [ "${test_type}" = "basic" ]; then 42 | mvn test 43 | elif [ "${test_type}" = "advan" ]; then 44 | echo "#=========================" 45 | echo "# ${test_name} - Initial" 46 | echo "#=========================" 47 | cd initial 48 | mvn test 49 | 50 | echo "#=========================" 51 | echo "# ${test_name} - Complete" 52 | echo "#=========================" 53 | cd ../complete/ 54 | mvn test 55 | # back to java-testng dir 56 | cd .. 57 | else 58 | die "Fatal, test_type is not either 'basic' nor 'advan'" 59 | fi 60 | elif [ "${test_lang}" = "js" ]; then 61 | node --version 62 | cd js-* 63 | 64 | if [ "${test_type}" = "basic" ]; then 65 | npm install 66 | npm test 67 | elif [ "${test_type}" = "advan" ]; then 68 | cd initial 69 | npm install 70 | npm test 71 | cd ../complete/ 72 | npm install 73 | npm test 74 | # back to js-mocha-chai dir 75 | cd .. 76 | else 77 | die "Fatal, test_type is not either 'basic' nor 'advan'" 78 | fi 79 | fi 80 | 81 | -------------------------------------------------------------------------------- /CI/script: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set -e: exit asap if a command exits with a non-zero status 4 | # set -x: print each command right before it is executed 5 | set -xe 6 | 7 | ./CI/run_scenario ${TEST_NAME} ${TEST_TYPE} ${TEST_LANG} 8 | -------------------------------------------------------------------------------- /CI/script_archive: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set -e: exit asap if a command exits with a non-zero status 4 | set -e 5 | 6 | echo "#==================" 7 | echo "# Archive artifacts" 8 | echo "#==================" 9 | # pending to upload to S3 bucket 10 | ls -la /tmp/videos 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build 2 | # docker build -t fe . 3 | # Use 4 | # curl -sSL https://raw.githubusercontent.com/dosel/t/i/p | bash -s start 5 | # docker run --rm -ti --net container:zalenium fe 6 | # curl -sSL https://raw.githubusercontent.com/dosel/t/i/p | bash -s stop 7 | FROM node:7 8 | 9 | RUN apt-get -qqy update \ 10 | && apt-get -qqy install \ 11 | git-core \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | RUN git clone https://github.com/diemol/frontend_testing.git 15 | 16 | RUN ln -sf /frontend_testing/page-objects/js-webdriverio/complete /js-webdriverio 17 | 18 | WORKDIR /js-webdriverio 19 | RUN npm install 20 | 21 | CMD ["npm", "test"] 22 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | node('kraken') { 2 | try { 3 | stage 'Checkout' 4 | deleteDir() 5 | sh 'rm -rf videos/' 6 | sh 'env' 7 | checkout scm 8 | sh 'pwd' 9 | sh 'ls -lah' 10 | sh 'ls -lah videos || true' 11 | sh 'docker ps -a || true' 12 | sh 'docker volume ls || true' 13 | 14 | stage 'Remove volumes' 15 | sh 'docker volume rm $(docker volume ls -qf dangling=true) || true' 16 | 17 | stage 'Running in Parallel' 18 | try { 19 | sh '/tools/run-with-selenium :maven -- bash -c "cd running-in-parallel/java-testng/complete; mvn clean test -DthreadCountProperty=2"' 20 | currentBuild.result = "SUCCESS" 21 | } catch (e) { 22 | currentBuild.result = "FAILURE" 23 | throw e 24 | } 25 | 26 | } finally { 27 | stage "Status" 28 | emailext ([ 29 | to: "diego.fernando.molina.bocanegra", 30 | subject: "${env.JOB_NAME}#${env.BUILD_NUMBER} - ${currentBuild.result}", 31 | body: "Use triple double-quotes for multiline text", 32 | mimeType: 'text/html', 33 | charset: 'UTF-8', 34 | attachLog: true 35 | ]) 36 | // sh 'cd /; ls -lah **/**' 37 | sh '/tools/run :frontend -v /tmp/videos:/tmp/videos -- ls -la /tmp/videos' 38 | archiveArtifacts allowEmptyArchive: true, artifacts: '**/videos/**, *.log, logs/*, reports/**, videos/*.html, videos/*.css, videos/*.ico' 39 | publishHTML (target: [ 40 | reportName: "Zalenium", 41 | reportDir: 'videos', 42 | reportFiles: 'dashboard.html', 43 | allowMissing: false, 44 | alwaysLinkToLastBuild: true, 45 | keepAll: true 46 | ]) 47 | } 48 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Frontend Testing Workshop - Code Examples 2 | 3 | [![Build Status](https://travis-ci.org/diemol/frontend_testing.svg?branch=master)](https://travis-ci.org/diemol/frontend_testing) 4 | 5 | This repository contains different examples that are used during a basic Frontend Testing workshop. 6 | 7 | The examples are provided in Java with TestNG+Fluentlenium and JavaScript with WebDriverIO+Mocha+Chai. 8 | 9 | ## The code is structured as follows: 10 | * [first-test](https://github.com/diemol/frontend_testing/tree/master/first-test) 11 | 12 | A page is opened, the page title is retrieved, and finally an assertion of a expected value is done. 13 | * [add-item-to-shopping-cart](https://github.com/diemol/frontend_testing/tree/master/add-item-to-shopping-cart) 14 | 15 | This is an example where a guest searches for a brand and puts an item in the shopping cart. 16 | * [running-in-parallel](https://github.com/diemol/frontend_testing/tree/master/running-in-parallel) 17 | 18 | After having tests working, a natural step is to try to execute all of them in less time. Some simple examples where a page is loaded are executed in parallel. 19 | * [page-objects](https://github.com/diemol/frontend_testing/tree/master/page-objects) 20 | 21 | A final round up of the hotel booking example but now using the Page Object model/pattern, which is know as one of the best practices when doing Frontend Testing. 22 | 23 | 24 | ## General Setup to run the examples 25 | 26 | ### Java 27 | _Only if you want to run the Java examples_ 28 | * [Install Maven](https://maven.apache.org/install.html) 29 | * Or Install Maven with [Homebrew](http://brew.sh/) 30 | 31 | ```sh 32 | brew install maven 33 | ``` 34 | 35 | ### JavaScript 36 | _Only if you want to run the JavaScript examples_ 37 | * Install [Node.js](https://nodejs.org/en/) 38 | * Or Install Node.js with [Homebrew](http://brew.sh/) 39 | 40 | ```sh 41 | brew install node 42 | ``` 43 | 44 | ### Docker 45 | [Zalenium](https://github.com/zalando/zalenium) is used to run most of the examples. 46 | This means: 47 | * You need to have [docker](https://www.docker.com/) installed, version >= 1.11.1. Here are the instructions for 48 | most of the supported [platforms](https://www.docker.com/products/docker). 49 | * After installing docker, just run this command to start Zalenium: 50 | 51 | ```sh 52 | curl -sSL https://raw.githubusercontent.com/dosel/t/i/p | bash -s start 53 | ``` 54 | 55 | This will check for the latest images and ask for missing dependencies. 56 | 57 | To stop Zalenium when you are done testing, you can. 58 | 59 | ```sh 60 | curl -sSL https://raw.githubusercontent.com/dosel/t/i/p | bash -s stop 61 | ``` 62 | 63 | * After getting the message `Zalenium in docker started!`, head to [http://localhost:4444/grid/console](http://localhost:4444/grid/console). 64 | 65 | * If you want to see the browsers while the test is running, you can access the container with VNC through 66 | [http://localhost:4444/grid/admin/live](http://localhost:4444/grid/admin/live). 67 | 68 | 69 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/README.md: -------------------------------------------------------------------------------- 1 | ### Add to bag example using WebDriver in Java and JavaScript 2 | 3 | This is an example where a guest searches for a brand and puts an article in the bag. 4 | 5 | Implemented in [Java with Fluentlenium](https://github.com/diemol/frontend_testing/tree/master/add-item-to-shopping-cart/java-fluentlenium) 6 | and [JavaScript with WebDriverIO](https://github.com/diemol/frontend_testing/tree/master/add-item-to-shopping-cart/js-webdriverio). 7 | 8 | On each implementation, you will find two folders: 9 | * Initial: Just contains a folder structure and some files to help you get started and develop the test. 10 | * Complete: Contains a proposed solution for the exercise. 11 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/java-fluentlenium/README.md: -------------------------------------------------------------------------------- 1 | ### Selenium WebDriver example in Java, TestNG and Fluentlenium 2 | 3 | #### Environment Setup: 4 | 5 | Check your [Java](https://github.com/diemol/frontend_testing#java) and [Docker](https://github.com/diemol/frontend_testing#docker) setup. 6 | 7 | #### Steps to run it: 8 | 9 | 1. Clone the repo: 10 | 11 | ```sh 12 | git clone https://github.com/diemol/frontend_testing.git 13 | cd frontend_testing/add-item-to-shopping-cart/java-fluentlenium/ 14 | ``` 15 | 1. Execute the code 16 | 17 | ```sh 18 | mvn test 19 | ``` 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/java-fluentlenium/complete/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | add-to-shopping-cart-example-complete 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 16 | 17 | 18 | maven-compiler-plugin 19 | 3.6.0 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.fluentlenium 32 | fluentlenium-testng 33 | 3.5.2 34 | test 35 | 36 | 37 | 38 | org.fluentlenium 39 | fluentlenium-assertj 40 | 3.5.2 41 | test 42 | 43 | 44 | 45 | org.testng 46 | testng 47 | 6.14.2 48 | test 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/java-fluentlenium/complete/src/test/java/AddItemToShoppingCartTest.java: -------------------------------------------------------------------------------- 1 | import org.fluentlenium.adapter.testng.FluentTestNg; 2 | import org.fluentlenium.core.domain.FluentList; 3 | import org.fluentlenium.core.domain.FluentWebElement; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.Capabilities; 6 | import org.openqa.selenium.Platform; 7 | import org.openqa.selenium.chrome.ChromeOptions; 8 | import org.openqa.selenium.remote.CapabilityType; 9 | import org.openqa.selenium.remote.DesiredCapabilities; 10 | import org.testng.annotations.Test; 11 | 12 | import java.util.concurrent.TimeUnit; 13 | import java.util.logging.Logger; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | public class AddItemToShoppingCartTest extends FluentTestNg { 18 | 19 | private static final Logger LOG = Logger.getLogger(AddItemToShoppingCartTest.class.getName()); 20 | 21 | @Override 22 | public String getRemoteUrl() { 23 | return "http://localhost:4444/wd/hub"; 24 | } 25 | 26 | @Override 27 | public String getWebDriver() { 28 | return "remote"; 29 | } 30 | 31 | @Override 32 | public Capabilities getCapabilities() { 33 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(new ChromeOptions()); 34 | desiredCapabilities.setCapability(CapabilityType.PLATFORM_NAME, Platform.LINUX); 35 | return desiredCapabilities; 36 | } 37 | 38 | /* 39 | Go to Zalando home page, search for "Nike", click on the first product, add it to the basket and 40 | assert that the product name and value is the correct one. 41 | */ 42 | @Test 43 | public void searchProductAndAddItToBag() { 44 | // Go to the homepage 45 | LOG.info("Loading https://www.zalando.de/..."); 46 | window().maximize(); 47 | goTo("https://www.zalando.de/"); 48 | 49 | LOG.info("Type Nike in the search field..."); 50 | find(By.cssSelector(".z-navicat-header_searchInput")).write("Nike").submit(); 51 | 52 | LOG.info("Click on the first item..."); 53 | find(By.cssSelector("z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child")).click(); 54 | 55 | LOG.info("Get product brand and name..."); 56 | String expectedProductBrand = find(By.cssSelector("h2[class*='h-color-black'][class*='detail']")).first().text(); 57 | String expectedProductName = find(By.cssSelector("h1[class*='h-text']")).first().text(); 58 | 59 | LOG.info("Click on the first available size..."); 60 | find(By.cssSelector(".h-container.h-dropdown-placeholder")).click(); 61 | String sizeSelector = "h5[class*='h-color-black'][class*='title-4'][class*='h-all-caps']"; 62 | await().atMost(5, TimeUnit.SECONDS).until(el(sizeSelector)).present(); 63 | find(By.cssSelector(sizeSelector)).click(); 64 | 65 | LOG.info("Add product to shopping cart..."); 66 | find(By.cssSelector("#z-pdp-topSection-addToCartButton")).click(); 67 | 68 | LOG.info("Go to shopping cart..."); 69 | String goToShoppingCartSelector = "a[class='z-navicat-header_navToolItemLink']"; 70 | await().atMost(5, TimeUnit.SECONDS).until(el(goToShoppingCartSelector)).present(); 71 | find(By.cssSelector(goToShoppingCartSelector)).click(); 72 | 73 | LOG.info("Assert product brand and name..."); 74 | FluentList productInfo = find(By.className("z-coast-fjord_link")); 75 | String productBrand = productInfo.get(1).text(); 76 | String productName = productInfo.last().text(); 77 | assertThat(productBrand).containsIgnoringCase(expectedProductBrand); 78 | assertThat(productName).containsIgnoringCase(expectedProductName); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/java-fluentlenium/initial/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | add-to-shopping-cart-example-initial 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 16 | 17 | 18 | maven-compiler-plugin 19 | 3.6.0 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.fluentlenium 32 | fluentlenium-testng 33 | 3.5.2 34 | test 35 | 36 | 37 | 38 | org.fluentlenium 39 | fluentlenium-assertj 40 | 3.5.2 41 | test 42 | 43 | 44 | 45 | org.testng 46 | testng 47 | 6.14.2 48 | test 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/java-fluentlenium/initial/src/test/java/AddItemToShoppingCartTest.java: -------------------------------------------------------------------------------- 1 | import org.fluentlenium.adapter.testng.FluentTestNg; 2 | import org.openqa.selenium.By; 3 | import org.openqa.selenium.Capabilities; 4 | import org.openqa.selenium.Platform; 5 | import org.openqa.selenium.chrome.ChromeOptions; 6 | import org.openqa.selenium.remote.CapabilityType; 7 | import org.openqa.selenium.remote.DesiredCapabilities; 8 | import org.testng.annotations.Test; 9 | 10 | import java.util.logging.Logger; 11 | 12 | public class AddItemToShoppingCartTest extends FluentTestNg { 13 | 14 | private static final Logger LOG = Logger.getLogger(AddItemToShoppingCartTest.class.getName()); 15 | 16 | @Override 17 | public String getRemoteUrl() { 18 | return "http://localhost:4444/wd/hub"; 19 | } 20 | 21 | @Override 22 | public String getWebDriver() { 23 | return "remote"; 24 | } 25 | 26 | @Override 27 | public Capabilities getCapabilities() { 28 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(new ChromeOptions()); 29 | desiredCapabilities.setCapability(CapabilityType.PLATFORM_NAME, Platform.LINUX); 30 | return desiredCapabilities; 31 | } 32 | 33 | /* 34 | Go to Zalando home page, search for "Nike", click on the first article, add it to the basket and 35 | assert that the article name and value is the correct one. 36 | */ 37 | @Test 38 | public void searchArticleAndAddItToBag() { 39 | // Go to the homepage 40 | LOG.info("Loading https://www.zalando.de/..."); 41 | window().maximize(); 42 | goTo("https://www.zalando.de/"); 43 | 44 | LOG.info("Type Nike in the search field..."); 45 | find(By.cssSelector(".z-navicat-header_searchInput")).write("Nike").submit(); 46 | 47 | LOG.info("Click on the first item..."); 48 | find(By.cssSelector("z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child")).click(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/README.md: -------------------------------------------------------------------------------- 1 | ### Selenium WebDriver example in JavaScript with WebDriverIO 2 | 3 | #### Environment Setup 4 | 5 | Check your [JavaScript](https://github.com/diemol/frontend_testing#javascript) and [Docker](https://github.com/diemol/frontend_testing#docker) setup. 6 | 7 | ### Steps to run it: 8 | 9 | 1. Clone the repo and go to the folder to execute the examples: 10 | 11 | ```sh 12 | git clone https://github.com/diemol/frontend_testing 13 | cd frontend_testing/add-item-to-shopping-cart/js-webdriverio/ 14 | ``` 15 | 1. Install Node dependencies: 16 | 17 | ```sh 18 | npm install 19 | ``` 20 | 1. Execute the code 21 | 22 | ```sh 23 | npm test 24 | ``` -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/complete/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-webdriver-complete", 3 | "version": "1.0.0", 4 | "description": "Add article to bad test with WebDriverIO", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/wdio wdio.conf.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing#readme", 19 | "dependencies": { 20 | "chai": "^4.1.2", 21 | "webdriverio": "^4.11.0" 22 | }, 23 | "devDependencies": { 24 | "wdio-allure-reporter": "^0.3.3", 25 | "wdio-mocha-framework": "^0.5.12" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/complete/test/specs/addToShoppingCartTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | let expectedProductBrand; 3 | let expectedProductName 4 | 5 | describe('Add item to Shopping Cart', function() { 6 | 7 | it('Loading https://www.zalando.de/...', function () { 8 | browser.windowHandleMaximize(); 9 | browser.url('https://www.zalando.de'); 10 | }); 11 | 12 | it('Type Nike in the search field...', function () { 13 | const searchFieldSelector = ".z-navicat-header_searchInput"; 14 | const searchField = $(searchFieldSelector); 15 | searchField.setValue('Nike'); 16 | searchField.click(); 17 | browser.keys('Enter'); 18 | }); 19 | 20 | it('Click on the first item..."', function () { 21 | const firstElementSelector = "z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child"; 22 | browser.click(firstElementSelector); 23 | }); 24 | 25 | it('Get product brand and name...', function () { 26 | expectedProductBrand = browser.getText("h2[class*='h-color-black'][class*='detail']"); 27 | expectedProductName = browser.getText("h1[class*='h-text']"); 28 | }); 29 | 30 | it('Click on the first available size...', function () { 31 | const sizeDropDownSelector = ".h-container.h-dropdown-placeholder"; 32 | browser.click(sizeDropDownSelector); 33 | const firstAvailableSizeSelector = "h5[class*='h-color-black'][class*='title-4'][class*='h-all-caps']"; 34 | browser.click(firstAvailableSizeSelector); 35 | }); 36 | 37 | it('Add product to shopping cart...', function () { 38 | const addToShoppingCartSelector = "#z-pdp-topSection-addToCartButton"; 39 | browser.click(addToShoppingCartSelector); 40 | }); 41 | 42 | it('Go to shopping cart...', function () { 43 | const goToShoppingCartSelector = "a[class='z-navicat-header_navToolItemLink']"; 44 | browser.waitForVisible(goToShoppingCartSelector, 10000); 45 | browser.click(goToShoppingCartSelector); 46 | const goToCheckoutButton = "button[data-id='z-coast-fjord_proceedToCheckout-bottom']"; 47 | browser.waitForVisible(goToCheckoutButton); 48 | }); 49 | 50 | it('Get product brand and name...', function () { 51 | const productInfo = browser.elements(".z-coast-fjord_link"); 52 | const productBrand = productInfo.value[1].getText(); 53 | const productName = productInfo.value[2].getText(); 54 | assert.include(productBrand, expectedProductBrand); 55 | assert.include(productName, expectedProductName); 56 | }); 57 | 58 | }); -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/complete/wdio.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | // 4 | // ================== 5 | // Specify Test Files 6 | // ================== 7 | // Define which test specs should run. The pattern is relative to the directory 8 | // from which `wdio` was called. Notice that, if you are calling `wdio` from an 9 | // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working 10 | // directory is where your package.json resides, so `wdio` will be called from there. 11 | // 12 | specs: [ 13 | './test/specs/**/*.js' 14 | ], 15 | // Patterns to exclude. 16 | exclude: [ 17 | // 'path/to/excluded/files' 18 | ], 19 | // 20 | // ============ 21 | // Capabilities 22 | // ============ 23 | // Define your capabilities here. WebdriverIO can run multiple capabilities at the same 24 | // time. Depending on the number of capabilities, WebdriverIO launches several test 25 | // sessions. Within your capabilities you can overwrite the spec and exclude options in 26 | // order to group specific specs to a specific capability. 27 | // 28 | // First, you can define how many instances should be started at the same time. Let's 29 | // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have 30 | // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec 31 | // files and you set maxInstances to 10, all spec files will get tested at the same time 32 | // and 30 processes will get spawned. The property handles how many capabilities 33 | // from the same test should run tests. 34 | // 35 | maxInstances: 10, 36 | // 37 | // If you have trouble getting all important capabilities together, check out the 38 | // Sauce Labs platform configurator - a great tool to configure your capabilities: 39 | // https://docs.saucelabs.com/reference/platforms-configurator 40 | // 41 | capabilities: [{ 42 | // maxInstances can get overwritten per capability. So if you have an in-house Selenium 43 | // grid with only 5 firefox instances available you can make sure that not more than 44 | // 5 instances get started at a time. 45 | maxInstances: 5, 46 | // 47 | browserName: 'chrome' 48 | }], 49 | // 50 | // =================== 51 | // Test Configurations 52 | // =================== 53 | // Define all options that are relevant for the WebdriverIO instance here 54 | // 55 | // By default WebdriverIO commands are executed in a synchronous way using 56 | // the wdio-sync package. If you still want to run your tests in an async way 57 | // e.g. using promises you can set the sync option to false. 58 | sync: true, 59 | // 60 | // Level of logging verbosity: silent | verbose | command | data | result | error 61 | logLevel: 'silent', 62 | // 63 | // Enables colors for log output. 64 | coloredLogs: true, 65 | // 66 | // Warns when a deprecated command is used 67 | deprecationWarnings: true, 68 | // 69 | // If you only want to run your tests until a specific amount of tests have failed use 70 | // bail (default is 0 - don't bail, run all tests). 71 | bail: 0, 72 | // 73 | // Saves a screenshot to a given path if a command fails. 74 | screenshotPath: './errorShots/', 75 | // 76 | // Set a base URL in order to shorten url command calls. If your `url` parameter starts 77 | // with `/`, the base url gets prepended, not including the path portion of your baseUrl. 78 | // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url 79 | // gets prepended directly. 80 | baseUrl: 'http://localhost', 81 | // 82 | // Default timeout for all waitFor* commands. 83 | waitforTimeout: 10000, 84 | // 85 | // Default timeout in milliseconds for request 86 | // if Selenium Grid doesn't send response 87 | connectionRetryTimeout: 90000, 88 | // 89 | // Default request retries count 90 | connectionRetryCount: 3, 91 | // 92 | // Initialize the browser instance with a WebdriverIO plugin. The object should have the 93 | // plugin name as key and the desired plugin options as properties. Make sure you have 94 | // the plugin installed before running any tests. The following plugins are currently 95 | // available: 96 | // WebdriverCSS: https://github.com/webdriverio/webdrivercss 97 | // WebdriverRTC: https://github.com/webdriverio/webdriverrtc 98 | // Browserevent: https://github.com/webdriverio/browserevent 99 | // plugins: { 100 | // webdrivercss: { 101 | // screenshotRoot: 'my-shots', 102 | // failedComparisonsRoot: 'diffs', 103 | // misMatchTolerance: 0.05, 104 | // screenWidth: [320,480,640,1024] 105 | // }, 106 | // webdriverrtc: {}, 107 | // browserevent: {} 108 | // }, 109 | // 110 | // Test runner services 111 | // Services take over a specific job you don't want to take care of. They enhance 112 | // your test setup with almost no effort. Unlike plugins, they don't add new 113 | // commands. Instead, they hook themselves up into the test process. 114 | // services: [],// 115 | // Framework you want to run your specs with. 116 | // The following are supported: Mocha, Jasmine, and Cucumber 117 | // see also: http://webdriver.io/guide/testrunner/frameworks.html 118 | // 119 | // Make sure you have the wdio adapter package for the specific framework installed 120 | // before running any tests. 121 | framework: 'mocha', 122 | // 123 | // Test reporter for stdout. 124 | // The only one supported by default is 'dot' 125 | // see also: http://webdriver.io/guide/reporters/dot.html 126 | reporters: ['allure'], 127 | 128 | // 129 | // Options to be passed to Mocha. 130 | // See the full list at http://mochajs.org/ 131 | mochaOpts: { 132 | ui: 'bdd', 133 | timeout: 60000 134 | }, 135 | // 136 | // ===== 137 | // Hooks 138 | // ===== 139 | // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance 140 | // it and to build services around it. You can either apply a single function or an array of 141 | // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got 142 | // resolved to continue. 143 | /** 144 | * Gets executed once before all workers get launched. 145 | * @param {Object} config wdio configuration object 146 | * @param {Array.} capabilities list of capabilities details 147 | */ 148 | // onPrepare: function (config, capabilities) { 149 | // }, 150 | /** 151 | * Gets executed just before initialising the webdriver session and test framework. It allows you 152 | * to manipulate configurations depending on the capability or spec. 153 | * @param {Object} config wdio configuration object 154 | * @param {Array.} capabilities list of capabilities details 155 | * @param {Array.} specs List of spec file paths that are to be run 156 | */ 157 | // beforeSession: function (config, capabilities, specs) { 158 | // }, 159 | /** 160 | * Gets executed before test execution begins. At this point you can access to all global 161 | * variables like `browser`. It is the perfect place to define custom commands. 162 | * @param {Array.} capabilities list of capabilities details 163 | * @param {Array.} specs List of spec file paths that are to be run 164 | */ 165 | // before: function (capabilities, specs) { 166 | // }, 167 | /** 168 | * Runs before a WebdriverIO command gets executed. 169 | * @param {String} commandName hook command name 170 | * @param {Array} args arguments that command would receive 171 | */ 172 | // beforeCommand: function (commandName, args) { 173 | // }, 174 | 175 | /** 176 | * Hook that gets executed before the suite starts 177 | * @param {Object} suite suite details 178 | */ 179 | // beforeSuite: function (suite) { 180 | // }, 181 | /** 182 | * Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts. 183 | * @param {Object} test test details 184 | */ 185 | // beforeTest: function (test) { 186 | // }, 187 | /** 188 | * Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling 189 | * beforeEach in Mocha) 190 | */ 191 | // beforeHook: function () { 192 | // }, 193 | /** 194 | * Hook that gets executed _after_ a hook within the suite ends (e.g. runs after calling 195 | * afterEach in Mocha) 196 | */ 197 | // afterHook: function () { 198 | // }, 199 | /** 200 | * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) ends. 201 | * @param {Object} test test details 202 | */ 203 | // afterTest: function (test) { 204 | // }, 205 | /** 206 | * Hook that gets executed after the suite has ended 207 | * @param {Object} suite suite details 208 | */ 209 | // afterSuite: function (suite) { 210 | // }, 211 | 212 | /** 213 | * Runs after a WebdriverIO command gets executed 214 | * @param {String} commandName hook command name 215 | * @param {Array} args arguments that command would receive 216 | * @param {Number} result 0 - command success, 1 - command error 217 | * @param {Object} error error object if any 218 | */ 219 | // afterCommand: function (commandName, args, result, error) { 220 | // }, 221 | /** 222 | * Gets executed after all tests are done. You still have access to all global variables from 223 | * the test. 224 | * @param {Number} result 0 - test pass, 1 - test fail 225 | * @param {Array.} capabilities list of capabilities details 226 | * @param {Array.} specs List of spec file paths that ran 227 | */ 228 | // after: function (result, capabilities, specs) { 229 | // }, 230 | /** 231 | * Gets executed right after terminating the webdriver session. 232 | * @param {Object} config wdio configuration object 233 | * @param {Array.} capabilities list of capabilities details 234 | * @param {Array.} specs List of spec file paths that ran 235 | */ 236 | // afterSession: function (config, capabilities, specs) { 237 | // }, 238 | /** 239 | * Gets executed after all workers got shut down and the process is about to exit. 240 | * @param {Object} exitCode 0 - success, 1 - fail 241 | * @param {Object} config wdio configuration object 242 | * @param {Array.} capabilities list of capabilities details 243 | */ 244 | // onComplete: function(exitCode, config, capabilities) { 245 | // } 246 | } 247 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/initial/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-webdriver-initial", 3 | "version": "1.0.0", 4 | "description": "Add article to bad test with WebDriverIO", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/wdio wdio.conf.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing#readme", 19 | "dependencies": { 20 | "webdriverio": "^4.11.0" 21 | }, 22 | "devDependencies": { 23 | "allure-commandline": "^2.5.0", 24 | "wdio-allure-reporter": "^0.3.3", 25 | "wdio-mocha-framework": "^0.5.12" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/initial/test/specs/addToShoppingCartTest.js: -------------------------------------------------------------------------------- 1 | describe('Add item to Shopping Cart', function() { 2 | 3 | it('Visit HomePage', function () { 4 | browser.windowHandleMaximize(); 5 | browser.url('https://www.zalando.de'); 6 | }); 7 | 8 | it('Search for Nike', function () { 9 | const searchFieldSelector = ".z-navicat-header_searchInput"; 10 | const searchField = $(searchFieldSelector); 11 | searchField.setValue('Nike'); 12 | searchField.click(); 13 | browser.keys('Enter'); 14 | }); 15 | 16 | it('Click on first Item', function () { 17 | const firstElementSelector = "z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child"; 18 | browser.click(firstElementSelector); 19 | }); 20 | 21 | }); -------------------------------------------------------------------------------- /add-item-to-shopping-cart/js-webdriverio/initial/wdio.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | // 4 | // ================== 5 | // Specify Test Files 6 | // ================== 7 | // Define which test specs should run. The pattern is relative to the directory 8 | // from which `wdio` was called. Notice that, if you are calling `wdio` from an 9 | // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working 10 | // directory is where your package.json resides, so `wdio` will be called from there. 11 | // 12 | specs: [ 13 | './test/specs/**/*.js' 14 | ], 15 | // Patterns to exclude. 16 | exclude: [ 17 | // 'path/to/excluded/files' 18 | ], 19 | // 20 | // ============ 21 | // Capabilities 22 | // ============ 23 | // Define your capabilities here. WebdriverIO can run multiple capabilities at the same 24 | // time. Depending on the number of capabilities, WebdriverIO launches several test 25 | // sessions. Within your capabilities you can overwrite the spec and exclude options in 26 | // order to group specific specs to a specific capability. 27 | // 28 | // First, you can define how many instances should be started at the same time. Let's 29 | // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have 30 | // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec 31 | // files and you set maxInstances to 10, all spec files will get tested at the same time 32 | // and 30 processes will get spawned. The property handles how many capabilities 33 | // from the same test should run tests. 34 | // 35 | maxInstances: 10, 36 | // 37 | // If you have trouble getting all important capabilities together, check out the 38 | // Sauce Labs platform configurator - a great tool to configure your capabilities: 39 | // https://docs.saucelabs.com/reference/platforms-configurator 40 | // 41 | capabilities: [{ 42 | // maxInstances can get overwritten per capability. So if you have an in-house Selenium 43 | // grid with only 5 firefox instances available you can make sure that not more than 44 | // 5 instances get started at a time. 45 | maxInstances: 5, 46 | // 47 | browserName: 'chrome' 48 | }], 49 | // 50 | // =================== 51 | // Test Configurations 52 | // =================== 53 | // Define all options that are relevant for the WebdriverIO instance here 54 | // 55 | // By default WebdriverIO commands are executed in a synchronous way using 56 | // the wdio-sync package. If you still want to run your tests in an async way 57 | // e.g. using promises you can set the sync option to false. 58 | sync: true, 59 | // 60 | // Level of logging verbosity: silent | verbose | command | data | result | error 61 | logLevel: 'silent', 62 | // 63 | // Enables colors for log output. 64 | coloredLogs: true, 65 | // 66 | // Warns when a deprecated command is used 67 | deprecationWarnings: true, 68 | // 69 | // If you only want to run your tests until a specific amount of tests have failed use 70 | // bail (default is 0 - don't bail, run all tests). 71 | bail: 0, 72 | // 73 | // Saves a screenshot to a given path if a command fails. 74 | screenshotPath: './errorShots/', 75 | // 76 | // Set a base URL in order to shorten url command calls. If your `url` parameter starts 77 | // with `/`, the base url gets prepended, not including the path portion of your baseUrl. 78 | // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url 79 | // gets prepended directly. 80 | baseUrl: 'http://localhost', 81 | // 82 | // Default timeout for all waitFor* commands. 83 | waitforTimeout: 10000, 84 | // 85 | // Default timeout in milliseconds for request 86 | // if Selenium Grid doesn't send response 87 | connectionRetryTimeout: 90000, 88 | // 89 | // Default request retries count 90 | connectionRetryCount: 3, 91 | // 92 | // Initialize the browser instance with a WebdriverIO plugin. The object should have the 93 | // plugin name as key and the desired plugin options as properties. Make sure you have 94 | // the plugin installed before running any tests. The following plugins are currently 95 | // available: 96 | // WebdriverCSS: https://github.com/webdriverio/webdrivercss 97 | // WebdriverRTC: https://github.com/webdriverio/webdriverrtc 98 | // Browserevent: https://github.com/webdriverio/browserevent 99 | // plugins: { 100 | // webdrivercss: { 101 | // screenshotRoot: 'my-shots', 102 | // failedComparisonsRoot: 'diffs', 103 | // misMatchTolerance: 0.05, 104 | // screenWidth: [320,480,640,1024] 105 | // }, 106 | // webdriverrtc: {}, 107 | // browserevent: {} 108 | // }, 109 | // 110 | // Test runner services 111 | // Services take over a specific job you don't want to take care of. They enhance 112 | // your test setup with almost no effort. Unlike plugins, they don't add new 113 | // commands. Instead, they hook themselves up into the test process. 114 | // services: [],// 115 | // Framework you want to run your specs with. 116 | // The following are supported: Mocha, Jasmine, and Cucumber 117 | // see also: http://webdriver.io/guide/testrunner/frameworks.html 118 | // 119 | // Make sure you have the wdio adapter package for the specific framework installed 120 | // before running any tests. 121 | framework: 'mocha', 122 | // 123 | // Test reporter for stdout. 124 | // The only one supported by default is 'dot' 125 | // see also: http://webdriver.io/guide/reporters/dot.html 126 | reporters: ['allure'], 127 | 128 | // 129 | // Options to be passed to Mocha. 130 | // See the full list at http://mochajs.org/ 131 | mochaOpts: { 132 | ui: 'bdd', 133 | timeout: 60000 134 | }, 135 | // 136 | // ===== 137 | // Hooks 138 | // ===== 139 | // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance 140 | // it and to build services around it. You can either apply a single function or an array of 141 | // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got 142 | // resolved to continue. 143 | /** 144 | * Gets executed once before all workers get launched. 145 | * @param {Object} config wdio configuration object 146 | * @param {Array.} capabilities list of capabilities details 147 | */ 148 | // onPrepare: function (config, capabilities) { 149 | // }, 150 | /** 151 | * Gets executed just before initialising the webdriver session and test framework. It allows you 152 | * to manipulate configurations depending on the capability or spec. 153 | * @param {Object} config wdio configuration object 154 | * @param {Array.} capabilities list of capabilities details 155 | * @param {Array.} specs List of spec file paths that are to be run 156 | */ 157 | // beforeSession: function (config, capabilities, specs) { 158 | // }, 159 | /** 160 | * Gets executed before test execution begins. At this point you can access to all global 161 | * variables like `browser`. It is the perfect place to define custom commands. 162 | * @param {Array.} capabilities list of capabilities details 163 | * @param {Array.} specs List of spec file paths that are to be run 164 | */ 165 | // before: function (capabilities, specs) { 166 | // }, 167 | /** 168 | * Runs before a WebdriverIO command gets executed. 169 | * @param {String} commandName hook command name 170 | * @param {Array} args arguments that command would receive 171 | */ 172 | // beforeCommand: function (commandName, args) { 173 | // }, 174 | 175 | /** 176 | * Hook that gets executed before the suite starts 177 | * @param {Object} suite suite details 178 | */ 179 | // beforeSuite: function (suite) { 180 | // }, 181 | /** 182 | * Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts. 183 | * @param {Object} test test details 184 | */ 185 | // beforeTest: function (test) { 186 | // }, 187 | /** 188 | * Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling 189 | * beforeEach in Mocha) 190 | */ 191 | // beforeHook: function () { 192 | // }, 193 | /** 194 | * Hook that gets executed _after_ a hook within the suite ends (e.g. runs after calling 195 | * afterEach in Mocha) 196 | */ 197 | // afterHook: function () { 198 | // }, 199 | /** 200 | * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) ends. 201 | * @param {Object} test test details 202 | */ 203 | // afterTest: function (test) { 204 | // }, 205 | /** 206 | * Hook that gets executed after the suite has ended 207 | * @param {Object} suite suite details 208 | */ 209 | // afterSuite: function (suite) { 210 | // }, 211 | 212 | /** 213 | * Runs after a WebdriverIO command gets executed 214 | * @param {String} commandName hook command name 215 | * @param {Array} args arguments that command would receive 216 | * @param {Number} result 0 - command success, 1 - command error 217 | * @param {Object} error error object if any 218 | */ 219 | // afterCommand: function (commandName, args, result, error) { 220 | // }, 221 | /** 222 | * Gets executed after all tests are done. You still have access to all global variables from 223 | * the test. 224 | * @param {Number} result 0 - test pass, 1 - test fail 225 | * @param {Array.} capabilities list of capabilities details 226 | * @param {Array.} specs List of spec file paths that ran 227 | */ 228 | // after: function (result, capabilities, specs) { 229 | // }, 230 | /** 231 | * Gets executed right after terminating the webdriver session. 232 | * @param {Object} config wdio configuration object 233 | * @param {Array.} capabilities list of capabilities details 234 | * @param {Array.} specs List of spec file paths that ran 235 | */ 236 | // afterSession: function (config, capabilities, specs) { 237 | // }, 238 | /** 239 | * Gets executed after all workers got shut down and the process is about to exit. 240 | * @param {Object} exitCode 0 - success, 1 - fail 241 | * @param {Object} config wdio configuration object 242 | * @param {Array.} capabilities list of capabilities details 243 | */ 244 | // onComplete: function(exitCode, config, capabilities) { 245 | // } 246 | } 247 | -------------------------------------------------------------------------------- /first-test/README.md: -------------------------------------------------------------------------------- 1 | ### WebDriver test example in Java and JavaScript 2 | 3 | This is a simple test where a page is open, and then the title of the page is asserted vs. a expected value. 4 | 5 | Implemented in [Java with TestNG](https://github.com/diemol/frontend_testing/tree/master/first-test/java-testng) and [JavaScript with Mocha and Chai](https://github.com/diemol/frontend_testing/tree/master/first-test/js-mocha-chai). 6 | -------------------------------------------------------------------------------- /first-test/java-testng/README.md: -------------------------------------------------------------------------------- 1 | ### Selenium WebDriver example in Java with TestNG 2 | 3 | #### Environment Setup: 4 | 5 | Check your [Java](https://github.com/diemol/frontend_testing#java) and [Docker](https://github.com/diemol/frontend_testing#docker) setup. 6 | 7 | #### Steps to run it: 8 | 9 | 1. Clone the repo and go to the folder to execute the examples: 10 | 11 | ```sh 12 | git clone https://github.com/diemol/frontend_testing.git 13 | cd frontend_testing/first-test/java-testng 14 | ``` 15 | 1. Execute the code 16 | 17 | ```sh 18 | mvn test 19 | ``` 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /first-test/java-testng/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | first-webdriver-test-java-testng 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.testng 15 | testng 16 | 6.14.2 17 | test 18 | 19 | 20 | 21 | org.seleniumhq.selenium 22 | selenium-java 23 | 3.10.0 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /first-test/java-testng/src/test/java/FirstWebDriverTestJavaTestNGTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.WebDriver; 2 | import org.openqa.selenium.chrome.ChromeOptions; 3 | import org.openqa.selenium.remote.DesiredCapabilities; 4 | import org.openqa.selenium.remote.RemoteWebDriver; 5 | import org.testng.Assert; 6 | import org.testng.annotations.Test; 7 | 8 | import java.net.MalformedURLException; 9 | import java.net.URL; 10 | 11 | public class FirstWebDriverTestJavaTestNGTest { 12 | 13 | // Setting the url for the WebDriver 14 | private static final String URL = "http://localhost:4444/wd/hub"; 15 | 16 | @Test 17 | public void checkZalandoPageTitle() throws MalformedURLException { 18 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(new ChromeOptions()); 19 | 20 | // Create a new instance of the remote web driver 21 | WebDriver driver = new RemoteWebDriver(new URL(URL), desiredCapabilities); 22 | 23 | // Maximize the window 24 | driver.manage().window().maximize(); 25 | 26 | // Go to Zalando website 27 | driver.get("https://www.zalando.de/"); 28 | 29 | // Assert that the title is the expected one 30 | Assert.assertEquals(driver.getTitle(), "Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando", 31 | "Page title is not the expected one"); 32 | 33 | // Close the browser 34 | driver.quit(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /first-test/js-mocha-chai/.nvmrc: -------------------------------------------------------------------------------- 1 | 7.4.0 2 | -------------------------------------------------------------------------------- /first-test/js-mocha-chai/README.md: -------------------------------------------------------------------------------- 1 | ### Selenium WebDriver example in JavaScript with Mocha and Chai 2 | 3 | #### Environment Setup 4 | 5 | Check your [JavaScript](https://github.com/diemol/frontend_testing#javascript) and [Docker](https://github.com/diemol/frontend_testing#docker) setup. 6 | 7 | ### Steps to run it: 8 | 9 | 1. Clone the repo and go to the folder to execute the examples: 10 | 11 | ```sh 12 | git clone https://github.com/diemol/frontend_testing 13 | cd frontend_testing/first-test/js-mocha-chai 14 | ``` 15 | 1. Install Node dependencies (Selenium WebDriver, Mocha, and Chai): 16 | 17 | ```sh 18 | npm install 19 | ``` 20 | 1. Execute the code 21 | 22 | ```sh 23 | npm test 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /first-test/js-mocha-chai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-mocha-chai", 3 | "version": "1.0.0", 4 | "description": "First Test with Mocha and Chai", 5 | "main": "test/first-webdriver-test-js-mocha-chai.js", 6 | "scripts": { 7 | "test": "./node_modules/mocha/bin/mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing/tree/master/first-test/js-mocha-chai#readme", 19 | "dependencies": { 20 | "chai": "^4.1.2", 21 | "mocha": "^5.0.2", 22 | "npm": "^5.7.1", 23 | "selenium-webdriver": "^3.6.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /first-test/js-mocha-chai/test/first-webdriver-test-js-mocha-chai.js: -------------------------------------------------------------------------------- 1 | const {Builder, By, Key, until} = require('selenium-webdriver'); 2 | // Getting the Chai expect library for assertions 3 | const expect = require('chai').expect; 4 | 5 | // Selenium Grid url 6 | const seleniumGridUrl = 'http://localhost:4444/wd/hub'; 7 | 8 | // Create a new instance of WebDriver 9 | const webDriver = require('selenium-webdriver'); 10 | 11 | describe('First WebDriver Test in JavaScript and Mocha', function() { 12 | // Global timeout for Mocha to wait for the callback function to be invoked 13 | this.timeout(60000); 14 | 15 | // Test to check the page title 16 | it('Page title should be Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando', function(done) { 17 | 18 | // Use WebDriver to visit a search engine with Chrome 19 | let driver = new Builder() 20 | .forBrowser('chrome') 21 | .usingServer(seleniumGridUrl) 22 | .build(); 23 | 24 | // Maximize the window 25 | driver.manage().window().maximize(); 26 | 27 | // Go to Zalando website 28 | driver.get("https://www.zalando.de/"); 29 | 30 | // Assert the title to the expected value 31 | driver.getTitle().then(function(title) { 32 | expect(title).to.equal('Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando'); 33 | }); 34 | 35 | // Quitting the browser and invoking the callback function to tell Mocha that we are done 36 | driver.quit().then(done); 37 | }); 38 | 39 | }); 40 | 41 | -------------------------------------------------------------------------------- /page-objects/README.md: -------------------------------------------------------------------------------- 1 | ## WebDriver examples using the Page Object Model/Pattern 2 | 3 | You can find here examples written in Java and JavaScript that shows how 4 | [Page Objects](http://martinfowler.com/bliki/PageObject.html) can be used to write more readable tests. The folder 5 | structure is as follows: 6 | * [Java-Fluentlenium](https://github.com/diemol/frontend_testing/tree/master/page-objects/java-fluentlenium): Tests 7 | written in Java with [Fluentlenium](http://fluentlenium.org) as framework. The page object classes are located in a 8 | different location from the tests in a single package, nevertheless it could be more strict by separating the related 9 | objects in different packages. 10 | * [JS-WebDriverIO](https://github.com/diemol/frontend_testing/tree/master/page-objects/js-webdriverio): Tests written 11 | in JavaScript, using [WebDriverIO](http://webdriver.io). 12 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/README.md: -------------------------------------------------------------------------------- 1 | ### WebDriver Java Fluentlenium examples using PageObjects 2 | 3 | This is an example running a test written in Java, using Fluentlenium, and implementing [Page Objects](http://martinfowler.com/bliki/PageObject.html). 4 | 5 | #### Environment Setup: 6 | 7 | Check your [Java](https://github.com/diemol/frontend_testing#java) and [Docker](https://github.com/diemol/frontend_testing#docker) setup. 8 | 9 | #### Steps to run it: 10 | 11 | 1. Clone the repo: 12 | 13 | ```sh 14 | git clone https://github.com/diemol/frontend_testing.git 15 | cd frontend_testing/page-objects/java-fluentlenium/ 16 | ``` 17 | 1. Execute the code 18 | 19 | ```sh 20 | mvn test 21 | ``` 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/complete/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | page-objects-example-complete 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 16 | 17 | 18 | maven-compiler-plugin 19 | 3.6.0 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.fluentlenium 32 | fluentlenium-core 33 | 3.5.2 34 | 35 | 36 | 37 | org.fluentlenium 38 | fluentlenium-testng 39 | 3.5.2 40 | test 41 | 42 | 43 | 44 | org.fluentlenium 45 | fluentlenium-assertj 46 | 3.5.2 47 | 48 | 49 | 50 | org.testng 51 | testng 52 | 6.14.2 53 | test 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/complete/src/main/java/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.fluentlenium.core.FluentPage; 4 | import org.fluentlenium.core.annotation.Page; 5 | import org.openqa.selenium.By; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | @SuppressWarnings("unused") 10 | public class HomePage extends FluentPage { 11 | 12 | @Page 13 | private SearchResultsPage searchResultsPage; 14 | 15 | @Override 16 | public String getUrl() { 17 | return "https://www.zalando.de/"; 18 | } 19 | 20 | @Override 21 | public void isAt() { 22 | assertThat(window().title().toLowerCase()).contains("zalando"); 23 | } 24 | 25 | public SearchResultsPage search(String searchText) { 26 | find(By.cssSelector(".z-navicat-header_searchInput")).write(searchText).submit(); 27 | return searchResultsPage; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/complete/src/main/java/pages/ProductDetailPage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.fluentlenium.core.FluentPage; 4 | import org.fluentlenium.core.annotation.Page; 5 | import org.openqa.selenium.By; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | 9 | @SuppressWarnings("FieldCanBeLocal") 10 | public class ProductDetailPage extends FluentPage { 11 | 12 | @SuppressWarnings("unused") 13 | @Page 14 | private ShoppingCartPage shoppingCartPage; 15 | 16 | public String getProductBrand() { 17 | return find(By.cssSelector("h2[class*='h-color-black'][class*='detail']")).first().text(); 18 | } 19 | 20 | public String getProductName() { 21 | return find(By.cssSelector("h1[class*='h-text']")).first().text(); 22 | } 23 | 24 | public void selectFirstAvailableSize() { 25 | find(By.cssSelector(".h-container.h-dropdown-placeholder")).click(); 26 | String sizeSelector = "h5[class*='h-color-black'][class*='title-4'][class*='h-all-caps']"; 27 | await().atMost(5, TimeUnit.SECONDS).until(el(sizeSelector)).present(); 28 | find(By.cssSelector("h5[class*='h-color-black'][class*='title-4'][class*='h-all-caps']")).click(); 29 | } 30 | 31 | public void addToShoppingCart() { 32 | find(By.cssSelector("#z-pdp-topSection-addToCartButton")).click(); 33 | } 34 | 35 | public ShoppingCartPage goToShoppingCart() { 36 | String goToShoppingCartSelector = "a[class='z-navicat-header_navToolItemLink']"; 37 | await().atMost(5, TimeUnit.SECONDS).until(el(goToShoppingCartSelector)).present(); 38 | find(By.cssSelector("a[class='z-navicat-header_navToolItemLink']")).click(); 39 | return shoppingCartPage; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/complete/src/main/java/pages/SearchResultsPage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.fluentlenium.core.FluentPage; 4 | import org.fluentlenium.core.annotation.Page; 5 | import org.openqa.selenium.By; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | 9 | @SuppressWarnings("unused") 10 | public class SearchResultsPage extends FluentPage { 11 | 12 | @Page 13 | private ProductDetailPage productDetailPage; 14 | 15 | public ProductDetailPage clickOnFirstProduct() { 16 | find(By.cssSelector("z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child")).click(); 17 | return productDetailPage; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/complete/src/main/java/pages/ShoppingCartPage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.fluentlenium.core.FluentPage; 4 | import org.fluentlenium.core.domain.FluentList; 5 | import org.fluentlenium.core.domain.FluentWebElement; 6 | import org.openqa.selenium.By; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | public class ShoppingCartPage extends FluentPage { 11 | 12 | private final String PRODUCT_INFO = "z-coast-fjord_link"; 13 | 14 | public String getProductBrand() { 15 | return find(By.className(PRODUCT_INFO)).get(1).text(); 16 | } 17 | 18 | public String getProductName() { 19 | return find(By.className(PRODUCT_INFO)).last().text(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/complete/src/test/java/AddItemToShoppingCartTest.java: -------------------------------------------------------------------------------- 1 | import org.fluentlenium.adapter.testng.FluentTestNg; 2 | import org.fluentlenium.core.annotation.Page; 3 | import org.openqa.selenium.Capabilities; 4 | import org.openqa.selenium.chrome.ChromeOptions; 5 | import org.openqa.selenium.remote.DesiredCapabilities; 6 | import org.testng.annotations.Test; 7 | import pages.HomePage; 8 | import pages.ProductDetailPage; 9 | import pages.SearchResultsPage; 10 | import pages.ShoppingCartPage; 11 | 12 | import java.util.logging.Logger; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | 16 | @SuppressWarnings("unused") 17 | public class AddItemToShoppingCartTest extends FluentTestNg { 18 | 19 | private static final Logger LOG = Logger.getLogger(AddItemToShoppingCartTest.class.getName()); 20 | 21 | @Page 22 | private HomePage homePage; 23 | 24 | @Override 25 | public String getRemoteUrl() { 26 | return "http://localhost:4444/wd/hub"; 27 | } 28 | 29 | @Override 30 | public String getWebDriver() { 31 | return "remote"; 32 | } 33 | 34 | @Override 35 | public Capabilities getCapabilities() { 36 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(new ChromeOptions()); 37 | desiredCapabilities.setCapability("name", "searchArticleAndAddItToBag"); 38 | return desiredCapabilities; 39 | } 40 | 41 | /* 42 | Go to Zalando home page, search for "Nike", click on the first product, add it to the bag and 43 | assert that the product name and value is the correct one. 44 | */ 45 | @Test 46 | public void searchArticleAndAddItToBag() { 47 | 48 | // Go to the homepage 49 | LOG.info("Loading https://www.zalando.de/..."); 50 | window().maximize(); 51 | goTo(homePage); 52 | homePage.isAt(); 53 | 54 | LOG.info("Type Nike in the search field..."); 55 | SearchResultsPage searchResultsPage = homePage.search("Nike"); 56 | 57 | LOG.info("Click on the first item..."); 58 | ProductDetailPage productDetailPage = searchResultsPage.clickOnFirstProduct(); 59 | 60 | LOG.info("Get product brand and name..."); 61 | String expectedProductBrand = productDetailPage.getProductBrand(); 62 | String expectedProductName = productDetailPage.getProductName(); 63 | 64 | LOG.info("Click on the first available size..."); 65 | productDetailPage.selectFirstAvailableSize(); 66 | 67 | LOG.info("Add product to shopping cart..."); 68 | productDetailPage.addToShoppingCart(); 69 | 70 | LOG.info("Go to shopping cart..."); 71 | ShoppingCartPage shoppingCartPage = productDetailPage.goToShoppingCart(); 72 | 73 | LOG.info("Assert product brand and name..."); 74 | assertThat(shoppingCartPage.getProductBrand()).containsIgnoringCase(expectedProductBrand); 75 | assertThat(shoppingCartPage.getProductName()).containsIgnoringCase(expectedProductName); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/initial/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | page-objects-example-initial 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 16 | 17 | 18 | maven-compiler-plugin 19 | 3.6.0 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.fluentlenium 32 | fluentlenium-core 33 | 3.5.2 34 | 35 | 36 | 37 | org.fluentlenium 38 | fluentlenium-testng 39 | 3.5.2 40 | test 41 | 42 | 43 | 44 | org.fluentlenium 45 | fluentlenium-assertj 46 | 3.5.2 47 | 48 | 49 | 50 | org.testng 51 | testng 52 | 6.14.2 53 | test 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/initial/src/main/java/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.fluentlenium.core.FluentPage; 4 | import org.fluentlenium.core.annotation.Page; 5 | import org.openqa.selenium.By; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | @SuppressWarnings("unused") 10 | public class HomePage extends FluentPage { 11 | 12 | @Page 13 | private SearchResultsPage searchResultsPage; 14 | 15 | @Override 16 | public String getUrl() { 17 | return "https://www.zalando.de/"; 18 | } 19 | 20 | @Override 21 | public void isAt() { 22 | assertThat(window().title().toLowerCase()).contains("zalando"); 23 | } 24 | 25 | public SearchResultsPage search(String searchText) { 26 | find(By.cssSelector(".z-navicat-header_searchInput")).write(searchText).submit(); 27 | return searchResultsPage; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/initial/src/main/java/pages/SearchResultsPage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.fluentlenium.core.FluentPage; 4 | import org.openqa.selenium.By; 5 | 6 | public class SearchResultsPage extends FluentPage { 7 | 8 | public void clickOnFirstProduct() { 9 | find(By.cssSelector("z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child")).click(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /page-objects/java-fluentlenium/initial/src/test/java/AddItemToShoppingCartTest.java: -------------------------------------------------------------------------------- 1 | import org.fluentlenium.adapter.testng.FluentTestNg; 2 | import org.fluentlenium.core.annotation.Page; 3 | import org.openqa.selenium.Capabilities; 4 | import org.openqa.selenium.Platform; 5 | import org.openqa.selenium.chrome.ChromeOptions; 6 | import org.openqa.selenium.remote.CapabilityType; 7 | import org.openqa.selenium.remote.DesiredCapabilities; 8 | import org.testng.annotations.Test; 9 | import pages.HomePage; 10 | import pages.SearchResultsPage; 11 | 12 | import java.util.logging.Logger; 13 | 14 | @SuppressWarnings("unused") 15 | public class AddItemToShoppingCartTest extends FluentTestNg { 16 | 17 | private static final Logger LOG = Logger.getLogger(AddItemToShoppingCartTest.class.getName()); 18 | 19 | @Page 20 | private HomePage homePage; 21 | 22 | @Override 23 | public String getRemoteUrl() { 24 | return "http://localhost:4444/wd/hub"; 25 | } 26 | 27 | @Override 28 | public String getWebDriver() { 29 | return "remote"; 30 | } 31 | 32 | @Override 33 | public Capabilities getCapabilities() { 34 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(new ChromeOptions()); 35 | desiredCapabilities.setCapability(CapabilityType.PLATFORM_NAME, Platform.LINUX); 36 | return desiredCapabilities; 37 | } 38 | 39 | /* 40 | Go to Zalando home page, search for "Nike", click on the first product, add it to the bag and 41 | assert that the product name and value is the correct one. 42 | */ 43 | @Test 44 | public void searchArticleAndAddItToBag() { 45 | 46 | // Go to the homepage 47 | LOG.info("Loading https://www.zalando.de/..."); 48 | window().maximize(); 49 | goTo(homePage); 50 | homePage.isAt(); 51 | 52 | LOG.info("Type Nike in the search field..."); 53 | SearchResultsPage searchResultsPage = homePage.search("Nike"); 54 | 55 | LOG.info("Click on the first item..."); 56 | searchResultsPage.clickOnFirstProduct(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-webdriverio-complete", 3 | "version": "1.0.0", 4 | "description": "Add article to bad test with WebDriverIO, using PageObjects", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "wdio wdio.conf.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing#readme", 19 | "dependencies": { 20 | "chai": "^4.1.2", 21 | "webdriverio": "^4.11.0" 22 | }, 23 | "devDependencies": { 24 | "wdio-allure-reporter": "^0.3.3", 25 | "wdio-mocha-framework": "^0.5.12" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/pageobjects/home.page.js: -------------------------------------------------------------------------------- 1 | // home.page.js 2 | var Page = require('./page') 3 | var SearchResultsPage = require('./searchResults.page'); 4 | 5 | var HomePage = Object.create(Page, { 6 | /** 7 | * define elements 8 | */ 9 | searchField: { get: function () { return browser.element('.z-navicat-header_searchInput'); } }, 10 | 11 | /** 12 | * define or overwrite page methods 13 | */ 14 | open: { value: function() { 15 | Page.open.call(this, '/'); 16 | } }, 17 | 18 | search: { value: function(searchText) { 19 | this.searchField.setValue(searchText); 20 | this.searchField.click(); 21 | browser.keys('Enter'); 22 | return SearchResultsPage; 23 | } } 24 | }); 25 | 26 | module.exports = HomePage; -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/pageobjects/page.js: -------------------------------------------------------------------------------- 1 | function Page () { 2 | } 3 | 4 | Page.prototype.open = function (path) { 5 | browser.windowHandleMaximize(); 6 | browser.url(path); 7 | }; 8 | 9 | module.exports = new Page(); -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/pageobjects/productDetail.page.js: -------------------------------------------------------------------------------- 1 | // productDetail.page.js 2 | var Page = require('./page'); 3 | var ShoppingCartPage = require('./shoppingCart.page'); 4 | 5 | var ProductDetailPage = Object.create(Page, { 6 | /** 7 | * define elements 8 | */ 9 | sizeDropDown: { get: function () { return browser.element(".h-container.h-dropdown-placeholder"); } }, 10 | firstAvailableSize: { get: function () { return browser.element("h5[class*='h-color-black'][class*='title-4'][class*='h-all-caps']"); } }, 11 | addToShoppingCartButton: { get: function () { return browser.element("#z-pdp-topSection-addToCartButton"); } }, 12 | goToShoppingCartButton: { get: function () { 13 | var shoppingCartButtonSelector = "a[class='z-navicat-header_navToolItemLink']"; 14 | browser.waitForVisible(shoppingCartButtonSelector, 10000); 15 | return browser.element(shoppingCartButtonSelector); 16 | } }, 17 | productBrand: { get: function () { return browser.element("h2[class*='h-color-black'][class*='detail']"); } }, 18 | productName: { get: function () { return browser.element("h1[class*='h-text']"); } }, 19 | 20 | getProductBrand: { value: function() { 21 | return this.productBrand.getText(); 22 | } }, 23 | 24 | getProductName: { value: function() { 25 | return this.productName.getText(); 26 | } }, 27 | 28 | clickOnFirstAvailableSize: { value: function() { 29 | this.sizeDropDown.click(); 30 | this.firstAvailableSize.click(); 31 | } }, 32 | 33 | addToShoppingCart: { value: function() { 34 | this.addToShoppingCartButton.click(); 35 | } }, 36 | 37 | goToShoppingCart: { value: function() { 38 | this.goToShoppingCartButton.click(); 39 | return ShoppingCartPage; 40 | } } 41 | }); 42 | 43 | module.exports = ProductDetailPage; -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/pageobjects/searchResults.page.js: -------------------------------------------------------------------------------- 1 | // searchResults.page.js 2 | var Page = require('./page'); 3 | var ProductDetailPage = require('./productDetail.page'); 4 | 5 | var SearchResultsPage = Object.create(Page, { 6 | /** 7 | * define elements 8 | */ 9 | firstElement: { get: function () { return browser.element("z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child"); } }, 10 | 11 | clickOnFirstElement: { value: function() { 12 | this.firstElement.click(); 13 | return ProductDetailPage; 14 | } } 15 | }); 16 | 17 | module.exports = SearchResultsPage; -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/pageobjects/shoppingCart.page.js: -------------------------------------------------------------------------------- 1 | // shoppingCart.page.js 2 | var Page = require('./page'); 3 | 4 | var ShoppingCartPage = Object.create(Page, { 5 | /** 6 | * define elements 7 | */ 8 | productInfo: { get: function () { 9 | var productInfoSelector = ".z-coast-fjord_link"; 10 | browser.waitForVisible(productInfoSelector, 10000); 11 | return browser.elements(productInfoSelector); 12 | } }, 13 | 14 | getProductBrand: { value: function() { 15 | return this.productInfo.value[1].getText(); 16 | } }, 17 | 18 | getProductName: { value: function() { 19 | return this.productInfo.value[2].getText(); 20 | } } 21 | }); 22 | 23 | module.exports = ShoppingCartPage; -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/specs/addToShoppingCartTest.js: -------------------------------------------------------------------------------- 1 | var HomePage = require('../pageobjects/home.page'); 2 | var assert = require('chai').assert; 3 | 4 | describe('login form', function () { 5 | var SearchResultsPage; 6 | var ProductDetailPage; 7 | var ShoppingCartPage; 8 | var expectedProductBrand; 9 | var expectedProductName; 10 | 11 | 12 | it('Loading https://www.zalando.de/...', function () { 13 | HomePage.open(); 14 | }); 15 | 16 | it('Type Nike in the search field...', function () { 17 | SearchResultsPage = HomePage.search('Nike'); 18 | }); 19 | 20 | it('Click on the first item..."', function () { 21 | ProductDetailPage = SearchResultsPage.clickOnFirstElement(); 22 | }); 23 | 24 | it('Click on the first available size...', function () { 25 | ProductDetailPage.clickOnFirstAvailableSize(); 26 | expectedProductBrand = ProductDetailPage.getProductBrand(); 27 | expectedProductName = ProductDetailPage.getProductName(); 28 | }); 29 | 30 | it('Get product name and brand...', function () { 31 | expectedProductBrand = ProductDetailPage.getProductBrand(); 32 | expectedProductName = ProductDetailPage.getProductName(); 33 | }); 34 | 35 | it('Add product to shopping cart...', function () { 36 | ProductDetailPage.addToShoppingCart(); 37 | }); 38 | 39 | it('Go to shopping cart...', function () { 40 | ShoppingCartPage = ProductDetailPage.goToShoppingCart(); 41 | }); 42 | 43 | it('Get product brand and name...', function () { 44 | const productBrand = ShoppingCartPage.getProductBrand(); 45 | const productName = ShoppingCartPage.getProductName(); 46 | assert.include(productBrand, expectedProductBrand); 47 | assert.include(productName, expectedProductName); 48 | }); 49 | 50 | 51 | }); -------------------------------------------------------------------------------- /page-objects/js-webdriverio/complete/wdio.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | // 4 | // ================== 5 | // Specify Test Files 6 | // ================== 7 | // Define which test specs should run. The pattern is relative to the directory 8 | // from which `wdio` was called. Notice that, if you are calling `wdio` from an 9 | // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working 10 | // directory is where your package.json resides, so `wdio` will be called from there. 11 | // 12 | specs: [ 13 | './specs/**/*.js' 14 | ], 15 | // Patterns to exclude. 16 | exclude: [ 17 | // 'path/to/excluded/files' 18 | ], 19 | // 20 | // ============ 21 | // Capabilities 22 | // ============ 23 | // Define your capabilities here. WebdriverIO can run multiple capabilities at the same 24 | // time. Depending on the number of capabilities, WebdriverIO launches several test 25 | // sessions. Within your capabilities you can overwrite the spec and exclude options in 26 | // order to group specific specs to a specific capability. 27 | // 28 | // First, you can define how many instances should be started at the same time. Let's 29 | // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have 30 | // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec 31 | // files and you set maxInstances to 10, all spec files will get tested at the same time 32 | // and 30 processes will get spawned. The property handles how many capabilities 33 | // from the same test should run tests. 34 | // 35 | maxInstances: 10, 36 | // 37 | // If you have trouble getting all important capabilities together, check out the 38 | // Sauce Labs platform configurator - a great tool to configure your capabilities: 39 | // https://docs.saucelabs.com/reference/platforms-configurator 40 | // 41 | capabilities: [{ 42 | // maxInstances can get overwritten per capability. So if you have an in-house Selenium 43 | // grid with only 5 firefox instances available you can make sure that not more than 44 | // 5 instances get started at a time. 45 | maxInstances: 5, 46 | // 47 | browserName: 'chrome' 48 | }], 49 | // 50 | // =================== 51 | // Test Configurations 52 | // =================== 53 | // Define all options that are relevant for the WebdriverIO instance here 54 | // 55 | // By default WebdriverIO commands are executed in a synchronous way using 56 | // the wdio-sync package. If you still want to run your tests in an async way 57 | // e.g. using promises you can set the sync option to false. 58 | sync: true, 59 | // 60 | // Level of logging verbosity: silent | verbose | command | data | result | error 61 | logLevel: 'silent', 62 | // 63 | // Enables colors for log output. 64 | coloredLogs: true, 65 | // 66 | // Warns when a deprecated command is used 67 | deprecationWarnings: true, 68 | // 69 | // If you only want to run your tests until a specific amount of tests have failed use 70 | // bail (default is 0 - don't bail, run all tests). 71 | bail: 0, 72 | // 73 | // Saves a screenshot to a given path if a command fails. 74 | screenshotPath: './errorShots/', 75 | // 76 | // Set a base URL in order to shorten url command calls. If your `url` parameter starts 77 | // with `/`, the base url gets prepended, not including the path portion of your baseUrl. 78 | // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url 79 | // gets prepended directly. 80 | baseUrl: 'https://www.zalando.de', 81 | // 82 | // Default timeout for all waitFor* commands. 83 | waitforTimeout: 10000, 84 | // 85 | // Default timeout in milliseconds for request 86 | // if Selenium Grid doesn't send response 87 | connectionRetryTimeout: 90000, 88 | // 89 | // Default request retries count 90 | connectionRetryCount: 3, 91 | // 92 | // Initialize the browser instance with a WebdriverIO plugin. The object should have the 93 | // plugin name as key and the desired plugin options as properties. Make sure you have 94 | // the plugin installed before running any tests. The following plugins are currently 95 | // available: 96 | // WebdriverCSS: https://github.com/webdriverio/webdrivercss 97 | // WebdriverRTC: https://github.com/webdriverio/webdriverrtc 98 | // Browserevent: https://github.com/webdriverio/browserevent 99 | // plugins: { 100 | // webdrivercss: { 101 | // screenshotRoot: 'my-shots', 102 | // failedComparisonsRoot: 'diffs', 103 | // misMatchTolerance: 0.05, 104 | // screenWidth: [320,480,640,1024] 105 | // }, 106 | // webdriverrtc: {}, 107 | // browserevent: {} 108 | // }, 109 | // 110 | // Test runner services 111 | // Services take over a specific job you don't want to take care of. They enhance 112 | // your test setup with almost no effort. Unlike plugins, they don't add new 113 | // commands. Instead, they hook themselves up into the test process. 114 | // services: [],// 115 | // Framework you want to run your specs with. 116 | // The following are supported: Mocha, Jasmine, and Cucumber 117 | // see also: http://webdriver.io/guide/testrunner/frameworks.html 118 | // 119 | // Make sure you have the wdio adapter package for the specific framework installed 120 | // before running any tests. 121 | framework: 'mocha', 122 | // 123 | // Test reporter for stdout. 124 | // The only one supported by default is 'dot' 125 | // see also: http://webdriver.io/guide/reporters/dot.html 126 | reporters: ['allure'], 127 | 128 | // 129 | // Options to be passed to Mocha. 130 | // See the full list at http://mochajs.org/ 131 | mochaOpts: { 132 | ui: 'bdd', 133 | timeout: 60000 134 | }, 135 | // 136 | // ===== 137 | // Hooks 138 | // ===== 139 | // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance 140 | // it and to build services around it. You can either apply a single function or an array of 141 | // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got 142 | // resolved to continue. 143 | /** 144 | * Gets executed once before all workers get launched. 145 | * @param {Object} config wdio configuration object 146 | * @param {Array.} capabilities list of capabilities details 147 | */ 148 | // onPrepare: function (config, capabilities) { 149 | // }, 150 | /** 151 | * Gets executed just before initialising the webdriver session and test framework. It allows you 152 | * to manipulate configurations depending on the capability or spec. 153 | * @param {Object} config wdio configuration object 154 | * @param {Array.} capabilities list of capabilities details 155 | * @param {Array.} specs List of spec file paths that are to be run 156 | */ 157 | // beforeSession: function (config, capabilities, specs) { 158 | // }, 159 | /** 160 | * Gets executed before test execution begins. At this point you can access to all global 161 | * variables like `browser`. It is the perfect place to define custom commands. 162 | * @param {Array.} capabilities list of capabilities details 163 | * @param {Array.} specs List of spec file paths that are to be run 164 | */ 165 | // before: function (capabilities, specs) { 166 | // }, 167 | /** 168 | * Runs before a WebdriverIO command gets executed. 169 | * @param {String} commandName hook command name 170 | * @param {Array} args arguments that command would receive 171 | */ 172 | // beforeCommand: function (commandName, args) { 173 | // }, 174 | 175 | /** 176 | * Hook that gets executed before the suite starts 177 | * @param {Object} suite suite details 178 | */ 179 | // beforeSuite: function (suite) { 180 | // }, 181 | /** 182 | * Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts. 183 | * @param {Object} test test details 184 | */ 185 | // beforeTest: function (test) { 186 | // }, 187 | /** 188 | * Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling 189 | * beforeEach in Mocha) 190 | */ 191 | // beforeHook: function () { 192 | // }, 193 | /** 194 | * Hook that gets executed _after_ a hook within the suite ends (e.g. runs after calling 195 | * afterEach in Mocha) 196 | */ 197 | // afterHook: function () { 198 | // }, 199 | /** 200 | * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) ends. 201 | * @param {Object} test test details 202 | */ 203 | // afterTest: function (test) { 204 | // }, 205 | /** 206 | * Hook that gets executed after the suite has ended 207 | * @param {Object} suite suite details 208 | */ 209 | // afterSuite: function (suite) { 210 | // }, 211 | 212 | /** 213 | * Runs after a WebdriverIO command gets executed 214 | * @param {String} commandName hook command name 215 | * @param {Array} args arguments that command would receive 216 | * @param {Number} result 0 - command success, 1 - command error 217 | * @param {Object} error error object if any 218 | */ 219 | // afterCommand: function (commandName, args, result, error) { 220 | // }, 221 | /** 222 | * Gets executed after all tests are done. You still have access to all global variables from 223 | * the test. 224 | * @param {Number} result 0 - test pass, 1 - test fail 225 | * @param {Array.} capabilities list of capabilities details 226 | * @param {Array.} specs List of spec file paths that ran 227 | */ 228 | // after: function (result, capabilities, specs) { 229 | // }, 230 | /** 231 | * Gets executed right after terminating the webdriver session. 232 | * @param {Object} config wdio configuration object 233 | * @param {Array.} capabilities list of capabilities details 234 | * @param {Array.} specs List of spec file paths that ran 235 | */ 236 | // afterSession: function (config, capabilities, specs) { 237 | // }, 238 | /** 239 | * Gets executed after all workers got shut down and the process is about to exit. 240 | * @param {Object} exitCode 0 - success, 1 - fail 241 | * @param {Object} config wdio configuration object 242 | * @param {Array.} capabilities list of capabilities details 243 | */ 244 | // onComplete: function(exitCode, config, capabilities) { 245 | // } 246 | } 247 | -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-webdriverio-initial", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "5.5.2", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", 10 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", 11 | "requires": { 12 | "co": "4.6.0", 13 | "fast-deep-equal": "1.1.0", 14 | "fast-json-stable-stringify": "2.0.0", 15 | "json-schema-traverse": "0.3.1" 16 | } 17 | }, 18 | "allure-js-commons": { 19 | "version": "1.3.1", 20 | "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-1.3.1.tgz", 21 | "integrity": "sha512-crsz0jZuo9ZeQ8YCv5FTZ5oyvYy6TPBIDHa1QFLagcdkNnpdRLgUVVXpothFLEeUBZx7set6Ja55vcCxVAW4uA==", 22 | "dev": true, 23 | "requires": { 24 | "file-type": "4.4.0", 25 | "fs-extra": "3.0.1", 26 | "js2xmlparser": "3.0.0", 27 | "mime": "1.3.4", 28 | "object-assign": "4.1.1", 29 | "uuid": "3.2.1" 30 | } 31 | }, 32 | "amdefine": { 33 | "version": "1.0.1", 34 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 35 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" 36 | }, 37 | "ansi-escapes": { 38 | "version": "3.0.0", 39 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", 40 | "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==" 41 | }, 42 | "ansi-regex": { 43 | "version": "3.0.0", 44 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 45 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" 46 | }, 47 | "ansi-styles": { 48 | "version": "3.2.1", 49 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 50 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 51 | "requires": { 52 | "color-convert": "1.9.1" 53 | } 54 | }, 55 | "archiver": { 56 | "version": "2.1.1", 57 | "resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz", 58 | "integrity": "sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw=", 59 | "requires": { 60 | "archiver-utils": "1.3.0", 61 | "async": "2.6.0", 62 | "buffer-crc32": "0.2.13", 63 | "glob": "7.1.2", 64 | "lodash": "4.17.5", 65 | "readable-stream": "2.3.5", 66 | "tar-stream": "1.5.5", 67 | "zip-stream": "1.2.0" 68 | } 69 | }, 70 | "archiver-utils": { 71 | "version": "1.3.0", 72 | "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", 73 | "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", 74 | "requires": { 75 | "glob": "7.1.2", 76 | "graceful-fs": "4.1.11", 77 | "lazystream": "1.0.0", 78 | "lodash": "4.17.5", 79 | "normalize-path": "2.1.1", 80 | "readable-stream": "2.3.5" 81 | } 82 | }, 83 | "asn1": { 84 | "version": "0.2.3", 85 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", 86 | "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" 87 | }, 88 | "assert-plus": { 89 | "version": "1.0.0", 90 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 91 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 92 | }, 93 | "async": { 94 | "version": "2.6.0", 95 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", 96 | "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", 97 | "requires": { 98 | "lodash": "4.17.5" 99 | } 100 | }, 101 | "asynckit": { 102 | "version": "0.4.0", 103 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 104 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 105 | }, 106 | "atob": { 107 | "version": "1.1.3", 108 | "resolved": "https://registry.npmjs.org/atob/-/atob-1.1.3.tgz", 109 | "integrity": "sha1-lfE2KbEsOlGl0hWr3OKqnzL4B3M=" 110 | }, 111 | "aws-sign2": { 112 | "version": "0.7.0", 113 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 114 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 115 | }, 116 | "aws4": { 117 | "version": "1.6.0", 118 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 119 | "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" 120 | }, 121 | "babel-runtime": { 122 | "version": "6.26.0", 123 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 124 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 125 | "requires": { 126 | "core-js": "2.5.3", 127 | "regenerator-runtime": "0.11.1" 128 | } 129 | }, 130 | "balanced-match": { 131 | "version": "1.0.0", 132 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 133 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 134 | }, 135 | "bcrypt-pbkdf": { 136 | "version": "1.0.1", 137 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 138 | "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", 139 | "optional": true, 140 | "requires": { 141 | "tweetnacl": "0.14.5" 142 | } 143 | }, 144 | "bl": { 145 | "version": "1.2.1", 146 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", 147 | "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", 148 | "requires": { 149 | "readable-stream": "2.3.5" 150 | } 151 | }, 152 | "boom": { 153 | "version": "4.3.1", 154 | "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", 155 | "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", 156 | "requires": { 157 | "hoek": "4.2.1" 158 | } 159 | }, 160 | "brace-expansion": { 161 | "version": "1.1.11", 162 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 163 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 164 | "requires": { 165 | "balanced-match": "1.0.0", 166 | "concat-map": "0.0.1" 167 | } 168 | }, 169 | "browser-stdout": { 170 | "version": "1.3.0", 171 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 172 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 173 | "dev": true 174 | }, 175 | "buffer-crc32": { 176 | "version": "0.2.13", 177 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 178 | "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" 179 | }, 180 | "caseless": { 181 | "version": "0.12.0", 182 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 183 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 184 | }, 185 | "chalk": { 186 | "version": "2.3.2", 187 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", 188 | "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", 189 | "requires": { 190 | "ansi-styles": "3.2.1", 191 | "escape-string-regexp": "1.0.5", 192 | "supports-color": "5.3.0" 193 | }, 194 | "dependencies": { 195 | "supports-color": { 196 | "version": "5.3.0", 197 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", 198 | "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", 199 | "requires": { 200 | "has-flag": "3.0.0" 201 | } 202 | } 203 | } 204 | }, 205 | "chardet": { 206 | "version": "0.4.2", 207 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", 208 | "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" 209 | }, 210 | "cli-cursor": { 211 | "version": "2.1.0", 212 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 213 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 214 | "requires": { 215 | "restore-cursor": "2.0.0" 216 | } 217 | }, 218 | "cli-width": { 219 | "version": "2.2.0", 220 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 221 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" 222 | }, 223 | "co": { 224 | "version": "4.6.0", 225 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 226 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 227 | }, 228 | "color-convert": { 229 | "version": "1.9.1", 230 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", 231 | "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", 232 | "requires": { 233 | "color-name": "1.1.3" 234 | } 235 | }, 236 | "color-name": { 237 | "version": "1.1.3", 238 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 239 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 240 | }, 241 | "combined-stream": { 242 | "version": "1.0.6", 243 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", 244 | "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", 245 | "requires": { 246 | "delayed-stream": "1.0.0" 247 | } 248 | }, 249 | "commander": { 250 | "version": "2.11.0", 251 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 252 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 253 | "dev": true 254 | }, 255 | "compress-commons": { 256 | "version": "1.2.2", 257 | "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", 258 | "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", 259 | "requires": { 260 | "buffer-crc32": "0.2.13", 261 | "crc32-stream": "2.0.0", 262 | "normalize-path": "2.1.1", 263 | "readable-stream": "2.3.5" 264 | } 265 | }, 266 | "concat-map": { 267 | "version": "0.0.1", 268 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 269 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 270 | }, 271 | "core-js": { 272 | "version": "2.5.3", 273 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", 274 | "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" 275 | }, 276 | "core-util-is": { 277 | "version": "1.0.2", 278 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 279 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 280 | }, 281 | "crc": { 282 | "version": "3.5.0", 283 | "resolved": "https://registry.npmjs.org/crc/-/crc-3.5.0.tgz", 284 | "integrity": "sha1-mLi6fUiWZbo5efWbITgTdBAaGWQ=" 285 | }, 286 | "crc32-stream": { 287 | "version": "2.0.0", 288 | "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", 289 | "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", 290 | "requires": { 291 | "crc": "3.5.0", 292 | "readable-stream": "2.3.5" 293 | } 294 | }, 295 | "cryptiles": { 296 | "version": "3.1.2", 297 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", 298 | "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", 299 | "requires": { 300 | "boom": "5.2.0" 301 | }, 302 | "dependencies": { 303 | "boom": { 304 | "version": "5.2.0", 305 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 306 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 307 | "requires": { 308 | "hoek": "4.2.1" 309 | } 310 | } 311 | } 312 | }, 313 | "css": { 314 | "version": "2.2.1", 315 | "resolved": "https://registry.npmjs.org/css/-/css-2.2.1.tgz", 316 | "integrity": "sha1-c6TIHehdtmTU7mdPfUcIXjstVdw=", 317 | "requires": { 318 | "inherits": "2.0.3", 319 | "source-map": "0.1.43", 320 | "source-map-resolve": "0.3.1", 321 | "urix": "0.1.0" 322 | } 323 | }, 324 | "css-parse": { 325 | "version": "2.0.0", 326 | "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", 327 | "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", 328 | "requires": { 329 | "css": "2.2.1" 330 | } 331 | }, 332 | "css-value": { 333 | "version": "0.0.1", 334 | "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", 335 | "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=" 336 | }, 337 | "dashdash": { 338 | "version": "1.14.1", 339 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 340 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 341 | "requires": { 342 | "assert-plus": "1.0.0" 343 | } 344 | }, 345 | "debug": { 346 | "version": "3.1.0", 347 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 348 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 349 | "dev": true, 350 | "requires": { 351 | "ms": "2.0.0" 352 | } 353 | }, 354 | "deepmerge": { 355 | "version": "2.0.1", 356 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.0.1.tgz", 357 | "integrity": "sha512-VIPwiMJqJ13ZQfaCsIFnp5Me9tnjURiaIFxfz7EH0Ci0dTSQpZtSLrqOicXqEd/z2r+z+Klk9GzmnRsgpgbOsQ==" 358 | }, 359 | "define-properties": { 360 | "version": "1.1.2", 361 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", 362 | "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", 363 | "dev": true, 364 | "requires": { 365 | "foreach": "2.0.5", 366 | "object-keys": "1.0.11" 367 | } 368 | }, 369 | "delayed-stream": { 370 | "version": "1.0.0", 371 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 372 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 373 | }, 374 | "diff": { 375 | "version": "3.3.1", 376 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", 377 | "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", 378 | "dev": true 379 | }, 380 | "ecc-jsbn": { 381 | "version": "0.1.1", 382 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", 383 | "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", 384 | "optional": true, 385 | "requires": { 386 | "jsbn": "0.1.1" 387 | } 388 | }, 389 | "ejs": { 390 | "version": "2.5.7", 391 | "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", 392 | "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=" 393 | }, 394 | "end-of-stream": { 395 | "version": "1.4.1", 396 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", 397 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", 398 | "requires": { 399 | "once": "1.4.0" 400 | } 401 | }, 402 | "escape-string-regexp": { 403 | "version": "1.0.5", 404 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 405 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 406 | }, 407 | "extend": { 408 | "version": "3.0.1", 409 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 410 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" 411 | }, 412 | "external-editor": { 413 | "version": "2.1.0", 414 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", 415 | "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", 416 | "requires": { 417 | "chardet": "0.4.2", 418 | "iconv-lite": "0.4.19", 419 | "tmp": "0.0.33" 420 | } 421 | }, 422 | "extsprintf": { 423 | "version": "1.3.0", 424 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 425 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 426 | }, 427 | "fast-deep-equal": { 428 | "version": "1.1.0", 429 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", 430 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" 431 | }, 432 | "fast-json-stable-stringify": { 433 | "version": "2.0.0", 434 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 435 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 436 | }, 437 | "fibers": { 438 | "version": "2.0.0", 439 | "resolved": "https://registry.npmjs.org/fibers/-/fibers-2.0.0.tgz", 440 | "integrity": "sha512-sLxo4rZVk7xLgAjb/6zEzHJfSALx6u6coN1z61XCOF7i6CyTdJawF4+RdpjCSeS8AP66eR2InScbYAz9RAVOgA==", 441 | "dev": true 442 | }, 443 | "figures": { 444 | "version": "2.0.0", 445 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 446 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 447 | "requires": { 448 | "escape-string-regexp": "1.0.5" 449 | } 450 | }, 451 | "file-type": { 452 | "version": "4.4.0", 453 | "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", 454 | "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", 455 | "dev": true 456 | }, 457 | "foreach": { 458 | "version": "2.0.5", 459 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", 460 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", 461 | "dev": true 462 | }, 463 | "forever-agent": { 464 | "version": "0.6.1", 465 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 466 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 467 | }, 468 | "form-data": { 469 | "version": "2.3.2", 470 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", 471 | "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", 472 | "requires": { 473 | "asynckit": "0.4.0", 474 | "combined-stream": "1.0.6", 475 | "mime-types": "2.1.18" 476 | } 477 | }, 478 | "fs-extra": { 479 | "version": "3.0.1", 480 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", 481 | "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", 482 | "dev": true, 483 | "requires": { 484 | "graceful-fs": "4.1.11", 485 | "jsonfile": "3.0.1", 486 | "universalify": "0.1.1" 487 | } 488 | }, 489 | "fs.realpath": { 490 | "version": "1.0.0", 491 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 492 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 493 | }, 494 | "function-bind": { 495 | "version": "1.1.1", 496 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 497 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 498 | "dev": true 499 | }, 500 | "gaze": { 501 | "version": "1.1.2", 502 | "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", 503 | "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", 504 | "requires": { 505 | "globule": "1.2.0" 506 | } 507 | }, 508 | "getpass": { 509 | "version": "0.1.7", 510 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 511 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 512 | "requires": { 513 | "assert-plus": "1.0.0" 514 | } 515 | }, 516 | "glob": { 517 | "version": "7.1.2", 518 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 519 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 520 | "requires": { 521 | "fs.realpath": "1.0.0", 522 | "inflight": "1.0.6", 523 | "inherits": "2.0.3", 524 | "minimatch": "3.0.4", 525 | "once": "1.4.0", 526 | "path-is-absolute": "1.0.1" 527 | } 528 | }, 529 | "globule": { 530 | "version": "1.2.0", 531 | "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", 532 | "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", 533 | "requires": { 534 | "glob": "7.1.2", 535 | "lodash": "4.17.5", 536 | "minimatch": "3.0.4" 537 | } 538 | }, 539 | "graceful-fs": { 540 | "version": "4.1.11", 541 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 542 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 543 | }, 544 | "growl": { 545 | "version": "1.10.3", 546 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", 547 | "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", 548 | "dev": true 549 | }, 550 | "har-schema": { 551 | "version": "2.0.0", 552 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 553 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 554 | }, 555 | "har-validator": { 556 | "version": "5.0.3", 557 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", 558 | "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", 559 | "requires": { 560 | "ajv": "5.5.2", 561 | "har-schema": "2.0.0" 562 | } 563 | }, 564 | "has-flag": { 565 | "version": "3.0.0", 566 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 567 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 568 | }, 569 | "has-symbols": { 570 | "version": "1.0.0", 571 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 572 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 573 | "dev": true 574 | }, 575 | "hawk": { 576 | "version": "6.0.2", 577 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", 578 | "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", 579 | "requires": { 580 | "boom": "4.3.1", 581 | "cryptiles": "3.1.2", 582 | "hoek": "4.2.1", 583 | "sntp": "2.1.0" 584 | } 585 | }, 586 | "he": { 587 | "version": "1.1.1", 588 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 589 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 590 | "dev": true 591 | }, 592 | "hoek": { 593 | "version": "4.2.1", 594 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", 595 | "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" 596 | }, 597 | "http-signature": { 598 | "version": "1.2.0", 599 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 600 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 601 | "requires": { 602 | "assert-plus": "1.0.0", 603 | "jsprim": "1.4.1", 604 | "sshpk": "1.13.1" 605 | } 606 | }, 607 | "iconv-lite": { 608 | "version": "0.4.19", 609 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 610 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 611 | }, 612 | "inflight": { 613 | "version": "1.0.6", 614 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 615 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 616 | "requires": { 617 | "once": "1.4.0", 618 | "wrappy": "1.0.2" 619 | } 620 | }, 621 | "inherits": { 622 | "version": "2.0.3", 623 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 624 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 625 | }, 626 | "inquirer": { 627 | "version": "3.3.0", 628 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", 629 | "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", 630 | "requires": { 631 | "ansi-escapes": "3.0.0", 632 | "chalk": "2.3.2", 633 | "cli-cursor": "2.1.0", 634 | "cli-width": "2.2.0", 635 | "external-editor": "2.1.0", 636 | "figures": "2.0.0", 637 | "lodash": "4.17.5", 638 | "mute-stream": "0.0.7", 639 | "run-async": "2.3.0", 640 | "rx-lite": "4.0.8", 641 | "rx-lite-aggregates": "4.0.8", 642 | "string-width": "2.1.1", 643 | "strip-ansi": "4.0.0", 644 | "through": "2.3.8" 645 | } 646 | }, 647 | "is-fullwidth-code-point": { 648 | "version": "2.0.0", 649 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 650 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" 651 | }, 652 | "is-promise": { 653 | "version": "2.1.0", 654 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 655 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" 656 | }, 657 | "is-typedarray": { 658 | "version": "1.0.0", 659 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 660 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 661 | }, 662 | "isarray": { 663 | "version": "1.0.0", 664 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 665 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 666 | }, 667 | "isstream": { 668 | "version": "0.1.2", 669 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 670 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 671 | }, 672 | "js2xmlparser": { 673 | "version": "3.0.0", 674 | "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", 675 | "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", 676 | "dev": true, 677 | "requires": { 678 | "xmlcreate": "1.0.2" 679 | } 680 | }, 681 | "jsbn": { 682 | "version": "0.1.1", 683 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 684 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 685 | "optional": true 686 | }, 687 | "json-schema": { 688 | "version": "0.2.3", 689 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 690 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 691 | }, 692 | "json-schema-traverse": { 693 | "version": "0.3.1", 694 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", 695 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" 696 | }, 697 | "json-stringify-safe": { 698 | "version": "5.0.1", 699 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 700 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 701 | }, 702 | "jsonfile": { 703 | "version": "3.0.1", 704 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", 705 | "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", 706 | "dev": true, 707 | "requires": { 708 | "graceful-fs": "4.1.11" 709 | } 710 | }, 711 | "jsprim": { 712 | "version": "1.4.1", 713 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 714 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 715 | "requires": { 716 | "assert-plus": "1.0.0", 717 | "extsprintf": "1.3.0", 718 | "json-schema": "0.2.3", 719 | "verror": "1.10.0" 720 | } 721 | }, 722 | "lazystream": { 723 | "version": "1.0.0", 724 | "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", 725 | "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", 726 | "requires": { 727 | "readable-stream": "2.3.5" 728 | } 729 | }, 730 | "lodash": { 731 | "version": "4.17.5", 732 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", 733 | "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" 734 | }, 735 | "mime": { 736 | "version": "1.3.4", 737 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", 738 | "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", 739 | "dev": true 740 | }, 741 | "mime-db": { 742 | "version": "1.33.0", 743 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", 744 | "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" 745 | }, 746 | "mime-types": { 747 | "version": "2.1.18", 748 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", 749 | "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", 750 | "requires": { 751 | "mime-db": "1.33.0" 752 | } 753 | }, 754 | "mimic-fn": { 755 | "version": "1.2.0", 756 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 757 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" 758 | }, 759 | "minimatch": { 760 | "version": "3.0.4", 761 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 762 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 763 | "requires": { 764 | "brace-expansion": "1.1.11" 765 | } 766 | }, 767 | "minimist": { 768 | "version": "0.0.8", 769 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 770 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 771 | }, 772 | "mkdirp": { 773 | "version": "0.5.1", 774 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 775 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 776 | "requires": { 777 | "minimist": "0.0.8" 778 | } 779 | }, 780 | "mocha": { 781 | "version": "4.1.0", 782 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", 783 | "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", 784 | "dev": true, 785 | "requires": { 786 | "browser-stdout": "1.3.0", 787 | "commander": "2.11.0", 788 | "debug": "3.1.0", 789 | "diff": "3.3.1", 790 | "escape-string-regexp": "1.0.5", 791 | "glob": "7.1.2", 792 | "growl": "1.10.3", 793 | "he": "1.1.1", 794 | "mkdirp": "0.5.1", 795 | "supports-color": "4.4.0" 796 | }, 797 | "dependencies": { 798 | "has-flag": { 799 | "version": "2.0.0", 800 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 801 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 802 | "dev": true 803 | }, 804 | "supports-color": { 805 | "version": "4.4.0", 806 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", 807 | "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", 808 | "dev": true, 809 | "requires": { 810 | "has-flag": "2.0.0" 811 | } 812 | } 813 | } 814 | }, 815 | "ms": { 816 | "version": "2.0.0", 817 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 818 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 819 | "dev": true 820 | }, 821 | "mute-stream": { 822 | "version": "0.0.7", 823 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 824 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" 825 | }, 826 | "normalize-path": { 827 | "version": "2.1.1", 828 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", 829 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", 830 | "requires": { 831 | "remove-trailing-separator": "1.1.0" 832 | } 833 | }, 834 | "npm-install-package": { 835 | "version": "2.1.0", 836 | "resolved": "https://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", 837 | "integrity": "sha1-1+/jz816sAYUuJbqUxGdyaslkSU=" 838 | }, 839 | "oauth-sign": { 840 | "version": "0.8.2", 841 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 842 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" 843 | }, 844 | "object-assign": { 845 | "version": "4.1.1", 846 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 847 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 848 | "dev": true 849 | }, 850 | "object-keys": { 851 | "version": "1.0.11", 852 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", 853 | "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", 854 | "dev": true 855 | }, 856 | "object.assign": { 857 | "version": "4.1.0", 858 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 859 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 860 | "dev": true, 861 | "requires": { 862 | "define-properties": "1.1.2", 863 | "function-bind": "1.1.1", 864 | "has-symbols": "1.0.0", 865 | "object-keys": "1.0.11" 866 | } 867 | }, 868 | "once": { 869 | "version": "1.4.0", 870 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 871 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 872 | "requires": { 873 | "wrappy": "1.0.2" 874 | } 875 | }, 876 | "onetime": { 877 | "version": "2.0.1", 878 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 879 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 880 | "requires": { 881 | "mimic-fn": "1.2.0" 882 | } 883 | }, 884 | "optimist": { 885 | "version": "0.6.1", 886 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 887 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 888 | "requires": { 889 | "minimist": "0.0.8", 890 | "wordwrap": "0.0.3" 891 | } 892 | }, 893 | "os-tmpdir": { 894 | "version": "1.0.2", 895 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 896 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 897 | }, 898 | "path-is-absolute": { 899 | "version": "1.0.1", 900 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 901 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 902 | }, 903 | "performance-now": { 904 | "version": "2.1.0", 905 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 906 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 907 | }, 908 | "process-nextick-args": { 909 | "version": "2.0.0", 910 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 911 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 912 | }, 913 | "punycode": { 914 | "version": "1.4.1", 915 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 916 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 917 | }, 918 | "q": { 919 | "version": "1.5.1", 920 | "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", 921 | "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" 922 | }, 923 | "qs": { 924 | "version": "6.5.1", 925 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 926 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 927 | }, 928 | "querystring": { 929 | "version": "0.2.0", 930 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 931 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" 932 | }, 933 | "readable-stream": { 934 | "version": "2.3.5", 935 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", 936 | "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", 937 | "requires": { 938 | "core-util-is": "1.0.2", 939 | "inherits": "2.0.3", 940 | "isarray": "1.0.0", 941 | "process-nextick-args": "2.0.0", 942 | "safe-buffer": "5.1.1", 943 | "string_decoder": "1.0.3", 944 | "util-deprecate": "1.0.2" 945 | } 946 | }, 947 | "regenerator-runtime": { 948 | "version": "0.11.1", 949 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 950 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 951 | }, 952 | "remove-trailing-separator": { 953 | "version": "1.1.0", 954 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 955 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" 956 | }, 957 | "request": { 958 | "version": "2.83.0", 959 | "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", 960 | "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", 961 | "requires": { 962 | "aws-sign2": "0.7.0", 963 | "aws4": "1.6.0", 964 | "caseless": "0.12.0", 965 | "combined-stream": "1.0.6", 966 | "extend": "3.0.1", 967 | "forever-agent": "0.6.1", 968 | "form-data": "2.3.2", 969 | "har-validator": "5.0.3", 970 | "hawk": "6.0.2", 971 | "http-signature": "1.2.0", 972 | "is-typedarray": "1.0.0", 973 | "isstream": "0.1.2", 974 | "json-stringify-safe": "5.0.1", 975 | "mime-types": "2.1.18", 976 | "oauth-sign": "0.8.2", 977 | "performance-now": "2.1.0", 978 | "qs": "6.5.1", 979 | "safe-buffer": "5.1.1", 980 | "stringstream": "0.0.5", 981 | "tough-cookie": "2.3.4", 982 | "tunnel-agent": "0.6.0", 983 | "uuid": "3.2.1" 984 | } 985 | }, 986 | "resolve-url": { 987 | "version": "0.2.1", 988 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 989 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" 990 | }, 991 | "restore-cursor": { 992 | "version": "2.0.0", 993 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 994 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 995 | "requires": { 996 | "onetime": "2.0.1", 997 | "signal-exit": "3.0.2" 998 | } 999 | }, 1000 | "rgb2hex": { 1001 | "version": "0.1.0", 1002 | "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.0.tgz", 1003 | "integrity": "sha1-zNVfhgrgxcTqN1BLlY5ELY0SMls=" 1004 | }, 1005 | "run-async": { 1006 | "version": "2.3.0", 1007 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 1008 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 1009 | "requires": { 1010 | "is-promise": "2.1.0" 1011 | } 1012 | }, 1013 | "rx-lite": { 1014 | "version": "4.0.8", 1015 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", 1016 | "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" 1017 | }, 1018 | "rx-lite-aggregates": { 1019 | "version": "4.0.8", 1020 | "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", 1021 | "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", 1022 | "requires": { 1023 | "rx-lite": "4.0.8" 1024 | } 1025 | }, 1026 | "safe-buffer": { 1027 | "version": "5.1.1", 1028 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 1029 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 1030 | }, 1031 | "signal-exit": { 1032 | "version": "3.0.2", 1033 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1034 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 1035 | }, 1036 | "sntp": { 1037 | "version": "2.1.0", 1038 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", 1039 | "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", 1040 | "requires": { 1041 | "hoek": "4.2.1" 1042 | } 1043 | }, 1044 | "source-map": { 1045 | "version": "0.1.43", 1046 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", 1047 | "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", 1048 | "requires": { 1049 | "amdefine": "1.0.1" 1050 | } 1051 | }, 1052 | "source-map-resolve": { 1053 | "version": "0.3.1", 1054 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.3.1.tgz", 1055 | "integrity": "sha1-YQ9hIqRFuN1RU1oqcbeD38Ekh2E=", 1056 | "requires": { 1057 | "atob": "1.1.3", 1058 | "resolve-url": "0.2.1", 1059 | "source-map-url": "0.3.0", 1060 | "urix": "0.1.0" 1061 | } 1062 | }, 1063 | "source-map-url": { 1064 | "version": "0.3.0", 1065 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz", 1066 | "integrity": "sha1-fsrxO1e80J2opAxdJp2zN5nUqvk=" 1067 | }, 1068 | "sshpk": { 1069 | "version": "1.13.1", 1070 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", 1071 | "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", 1072 | "requires": { 1073 | "asn1": "0.2.3", 1074 | "assert-plus": "1.0.0", 1075 | "bcrypt-pbkdf": "1.0.1", 1076 | "dashdash": "1.14.1", 1077 | "ecc-jsbn": "0.1.1", 1078 | "getpass": "0.1.7", 1079 | "jsbn": "0.1.1", 1080 | "tweetnacl": "0.14.5" 1081 | } 1082 | }, 1083 | "string-width": { 1084 | "version": "2.1.1", 1085 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1086 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1087 | "requires": { 1088 | "is-fullwidth-code-point": "2.0.0", 1089 | "strip-ansi": "4.0.0" 1090 | } 1091 | }, 1092 | "string_decoder": { 1093 | "version": "1.0.3", 1094 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 1095 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 1096 | "requires": { 1097 | "safe-buffer": "5.1.1" 1098 | } 1099 | }, 1100 | "stringstream": { 1101 | "version": "0.0.5", 1102 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", 1103 | "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" 1104 | }, 1105 | "strip-ansi": { 1106 | "version": "4.0.0", 1107 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1108 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1109 | "requires": { 1110 | "ansi-regex": "3.0.0" 1111 | } 1112 | }, 1113 | "supports-color": { 1114 | "version": "5.0.1", 1115 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.0.1.tgz", 1116 | "integrity": "sha512-7FQGOlSQ+AQxBNXJpVDj8efTA/FtyB5wcNE1omXXJ0cq6jm1jjDwuROlYDbnzHqdNPqliWFhcioCWSyav+xBnA==", 1117 | "requires": { 1118 | "has-flag": "2.0.0" 1119 | }, 1120 | "dependencies": { 1121 | "has-flag": { 1122 | "version": "2.0.0", 1123 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 1124 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" 1125 | } 1126 | } 1127 | }, 1128 | "tar-stream": { 1129 | "version": "1.5.5", 1130 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", 1131 | "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", 1132 | "requires": { 1133 | "bl": "1.2.1", 1134 | "end-of-stream": "1.4.1", 1135 | "readable-stream": "2.3.5", 1136 | "xtend": "4.0.1" 1137 | } 1138 | }, 1139 | "through": { 1140 | "version": "2.3.8", 1141 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1142 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 1143 | }, 1144 | "tmp": { 1145 | "version": "0.0.33", 1146 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1147 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1148 | "requires": { 1149 | "os-tmpdir": "1.0.2" 1150 | } 1151 | }, 1152 | "tough-cookie": { 1153 | "version": "2.3.4", 1154 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 1155 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 1156 | "requires": { 1157 | "punycode": "1.4.1" 1158 | } 1159 | }, 1160 | "tunnel-agent": { 1161 | "version": "0.6.0", 1162 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1163 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1164 | "requires": { 1165 | "safe-buffer": "5.1.1" 1166 | } 1167 | }, 1168 | "tweetnacl": { 1169 | "version": "0.14.5", 1170 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1171 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 1172 | "optional": true 1173 | }, 1174 | "universalify": { 1175 | "version": "0.1.1", 1176 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", 1177 | "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", 1178 | "dev": true 1179 | }, 1180 | "urix": { 1181 | "version": "0.1.0", 1182 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 1183 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" 1184 | }, 1185 | "url": { 1186 | "version": "0.11.0", 1187 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", 1188 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", 1189 | "requires": { 1190 | "punycode": "1.3.2", 1191 | "querystring": "0.2.0" 1192 | }, 1193 | "dependencies": { 1194 | "punycode": { 1195 | "version": "1.3.2", 1196 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 1197 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" 1198 | } 1199 | } 1200 | }, 1201 | "util-deprecate": { 1202 | "version": "1.0.2", 1203 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1204 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1205 | }, 1206 | "uuid": { 1207 | "version": "3.2.1", 1208 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", 1209 | "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" 1210 | }, 1211 | "verror": { 1212 | "version": "1.10.0", 1213 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1214 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1215 | "requires": { 1216 | "assert-plus": "1.0.0", 1217 | "core-util-is": "1.0.2", 1218 | "extsprintf": "1.3.0" 1219 | } 1220 | }, 1221 | "wdio-allure-reporter": { 1222 | "version": "0.3.3", 1223 | "resolved": "https://registry.npmjs.org/wdio-allure-reporter/-/wdio-allure-reporter-0.3.3.tgz", 1224 | "integrity": "sha512-AhzavWn9xjPymfpgly9HzSRCzMlsFm8pe8QvsMzFtgyVlG415nKSIiFDzjGcztCUEDoxPqyAs0AdmCAnaml+Fw==", 1225 | "dev": true, 1226 | "requires": { 1227 | "allure-js-commons": "1.3.1", 1228 | "babel-runtime": "6.26.0" 1229 | } 1230 | }, 1231 | "wdio-dot-reporter": { 1232 | "version": "0.0.9", 1233 | "resolved": "https://registry.npmjs.org/wdio-dot-reporter/-/wdio-dot-reporter-0.0.9.tgz", 1234 | "integrity": "sha1-kpsq2v1J1rBTT9oGjocxm0fjj+U=" 1235 | }, 1236 | "wdio-mocha-framework": { 1237 | "version": "0.5.12", 1238 | "resolved": "https://registry.npmjs.org/wdio-mocha-framework/-/wdio-mocha-framework-0.5.12.tgz", 1239 | "integrity": "sha512-PHqomnVFjNUU+TS4e9lb/DanlaUlobRa3UlIdRMKvsHdsfaCh2oAc7V9OU1rHANNYS9AqKedHDM+GvvGh1VZgA==", 1240 | "dev": true, 1241 | "requires": { 1242 | "babel-runtime": "6.26.0", 1243 | "mocha": "4.1.0", 1244 | "wdio-sync": "0.7.1" 1245 | } 1246 | }, 1247 | "wdio-sync": { 1248 | "version": "0.7.1", 1249 | "resolved": "https://registry.npmjs.org/wdio-sync/-/wdio-sync-0.7.1.tgz", 1250 | "integrity": "sha512-7BTWoBbDZsIVR67mx3cqkYiE3gZid5OJPBcjje1SlC28uXJA73YVxKPBR3SzY+iQy4dk0vSyqUcGkuQBjUNQew==", 1251 | "dev": true, 1252 | "requires": { 1253 | "babel-runtime": "6.26.0", 1254 | "fibers": "2.0.0", 1255 | "object.assign": "4.1.0" 1256 | } 1257 | }, 1258 | "webdriverio": { 1259 | "version": "4.11.0", 1260 | "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-4.11.0.tgz", 1261 | "integrity": "sha1-KJuq4iVzAdlc/s797CA4pqprlMU=", 1262 | "requires": { 1263 | "archiver": "2.1.1", 1264 | "babel-runtime": "6.26.0", 1265 | "css-parse": "2.0.0", 1266 | "css-value": "0.0.1", 1267 | "deepmerge": "2.0.1", 1268 | "ejs": "2.5.7", 1269 | "gaze": "1.1.2", 1270 | "glob": "7.1.2", 1271 | "inquirer": "3.3.0", 1272 | "json-stringify-safe": "5.0.1", 1273 | "mkdirp": "0.5.1", 1274 | "npm-install-package": "2.1.0", 1275 | "optimist": "0.6.1", 1276 | "q": "1.5.1", 1277 | "request": "2.83.0", 1278 | "rgb2hex": "0.1.0", 1279 | "safe-buffer": "5.1.1", 1280 | "supports-color": "5.0.1", 1281 | "url": "0.11.0", 1282 | "wdio-dot-reporter": "0.0.9", 1283 | "wgxpath": "1.0.0" 1284 | } 1285 | }, 1286 | "wgxpath": { 1287 | "version": "1.0.0", 1288 | "resolved": "https://registry.npmjs.org/wgxpath/-/wgxpath-1.0.0.tgz", 1289 | "integrity": "sha1-7vikudVYzEla06mit1FZfs2a9pA=" 1290 | }, 1291 | "wordwrap": { 1292 | "version": "0.0.3", 1293 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 1294 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" 1295 | }, 1296 | "wrappy": { 1297 | "version": "1.0.2", 1298 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1299 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1300 | }, 1301 | "xmlcreate": { 1302 | "version": "1.0.2", 1303 | "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", 1304 | "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", 1305 | "dev": true 1306 | }, 1307 | "xtend": { 1308 | "version": "4.0.1", 1309 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 1310 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 1311 | }, 1312 | "zip-stream": { 1313 | "version": "1.2.0", 1314 | "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", 1315 | "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", 1316 | "requires": { 1317 | "archiver-utils": "1.3.0", 1318 | "compress-commons": "1.2.2", 1319 | "lodash": "4.17.5", 1320 | "readable-stream": "2.3.5" 1321 | } 1322 | } 1323 | } 1324 | } 1325 | -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-webdriverio-initial", 3 | "version": "1.0.0", 4 | "description": "Add article to bad test with WebDriverIO, using PageObjects", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "wdio wdio.conf.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing#readme", 19 | "dependencies": { 20 | "webdriverio": "^4.11.0" 21 | }, 22 | "devDependencies": { 23 | "wdio-allure-reporter": "^0.3.3", 24 | "wdio-mocha-framework": "^0.5.12" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/pageobjects/home.page.js: -------------------------------------------------------------------------------- 1 | // home.page.js 2 | var Page = require('./page') 3 | var SearchResultsPage = require('./searchResults.page'); 4 | 5 | var HomePage = Object.create(Page, { 6 | /** 7 | * define elements 8 | */ 9 | searchField: { get: function () { return browser.element('.z-navicat-header_searchInput'); } }, 10 | 11 | /** 12 | * define or overwrite page methods 13 | */ 14 | open: { value: function() { 15 | Page.open.call(this, '/'); 16 | } }, 17 | 18 | search: { value: function(searchText) { 19 | this.searchField.setValue(searchText); 20 | this.searchField.click(); 21 | browser.keys('Enter'); 22 | return SearchResultsPage; 23 | } } 24 | }); 25 | 26 | module.exports = HomePage; -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/pageobjects/page.js: -------------------------------------------------------------------------------- 1 | function Page () { 2 | } 3 | 4 | Page.prototype.open = function (path) { 5 | browser.windowHandleMaximize(); 6 | browser.url(path); 7 | }; 8 | 9 | module.exports = new Page(); -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/pageobjects/searchResults.page.js: -------------------------------------------------------------------------------- 1 | // searchResults.page.js 2 | var Page = require('./page'); 3 | 4 | var SearchResultsPage = Object.create(Page, { 5 | /** 6 | * define elements 7 | */ 8 | firstElement: { get: function () { return browser.element("z-grid[class='z-nvg-cognac_articles'] > z-grid-item:first-child"); } }, 9 | 10 | clickOnFirstElement: { value: function() { 11 | this.firstElement.click(); 12 | } } 13 | }); 14 | 15 | module.exports = SearchResultsPage; -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/specs/addToShoppingCartTest.js: -------------------------------------------------------------------------------- 1 | var HomePage = require('../pageobjects/home.page'); 2 | 3 | describe('login form', function () { 4 | var SearchResultsPage; 5 | 6 | it('Loading https://www.zalando.de/...', function () { 7 | HomePage.open(); 8 | }); 9 | 10 | it('Type Nike in the search field...', function () { 11 | SearchResultsPage = HomePage.search('Nike'); 12 | }); 13 | 14 | it('Click on the first item..."', function () { 15 | SearchResultsPage.clickOnFirstElement(); 16 | }); 17 | }); -------------------------------------------------------------------------------- /page-objects/js-webdriverio/initial/wdio.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | // 4 | // ================== 5 | // Specify Test Files 6 | // ================== 7 | // Define which test specs should run. The pattern is relative to the directory 8 | // from which `wdio` was called. Notice that, if you are calling `wdio` from an 9 | // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working 10 | // directory is where your package.json resides, so `wdio` will be called from there. 11 | // 12 | specs: [ 13 | './specs/**/*.js' 14 | ], 15 | // Patterns to exclude. 16 | exclude: [ 17 | // 'path/to/excluded/files' 18 | ], 19 | // 20 | // ============ 21 | // Capabilities 22 | // ============ 23 | // Define your capabilities here. WebdriverIO can run multiple capabilities at the same 24 | // time. Depending on the number of capabilities, WebdriverIO launches several test 25 | // sessions. Within your capabilities you can overwrite the spec and exclude options in 26 | // order to group specific specs to a specific capability. 27 | // 28 | // First, you can define how many instances should be started at the same time. Let's 29 | // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have 30 | // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec 31 | // files and you set maxInstances to 10, all spec files will get tested at the same time 32 | // and 30 processes will get spawned. The property handles how many capabilities 33 | // from the same test should run tests. 34 | // 35 | maxInstances: 10, 36 | // 37 | // If you have trouble getting all important capabilities together, check out the 38 | // Sauce Labs platform configurator - a great tool to configure your capabilities: 39 | // https://docs.saucelabs.com/reference/platforms-configurator 40 | // 41 | capabilities: [{ 42 | // maxInstances can get overwritten per capability. So if you have an in-house Selenium 43 | // grid with only 5 firefox instances available you can make sure that not more than 44 | // 5 instances get started at a time. 45 | maxInstances: 5, 46 | // 47 | browserName: 'chrome' 48 | }], 49 | // 50 | // =================== 51 | // Test Configurations 52 | // =================== 53 | // Define all options that are relevant for the WebdriverIO instance here 54 | // 55 | // By default WebdriverIO commands are executed in a synchronous way using 56 | // the wdio-sync package. If you still want to run your tests in an async way 57 | // e.g. using promises you can set the sync option to false. 58 | sync: true, 59 | // 60 | // Level of logging verbosity: silent | verbose | command | data | result | error 61 | logLevel: 'silent', 62 | // 63 | // Enables colors for log output. 64 | coloredLogs: true, 65 | // 66 | // Warns when a deprecated command is used 67 | deprecationWarnings: true, 68 | // 69 | // If you only want to run your tests until a specific amount of tests have failed use 70 | // bail (default is 0 - don't bail, run all tests). 71 | bail: 0, 72 | // 73 | // Saves a screenshot to a given path if a command fails. 74 | screenshotPath: './errorShots/', 75 | // 76 | // Set a base URL in order to shorten url command calls. If your `url` parameter starts 77 | // with `/`, the base url gets prepended, not including the path portion of your baseUrl. 78 | // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url 79 | // gets prepended directly. 80 | baseUrl: 'https://www.zalando.de', 81 | // 82 | // Default timeout for all waitFor* commands. 83 | waitforTimeout: 10000, 84 | // 85 | // Default timeout in milliseconds for request 86 | // if Selenium Grid doesn't send response 87 | connectionRetryTimeout: 90000, 88 | // 89 | // Default request retries count 90 | connectionRetryCount: 3, 91 | // 92 | // Initialize the browser instance with a WebdriverIO plugin. The object should have the 93 | // plugin name as key and the desired plugin options as properties. Make sure you have 94 | // the plugin installed before running any tests. The following plugins are currently 95 | // available: 96 | // WebdriverCSS: https://github.com/webdriverio/webdrivercss 97 | // WebdriverRTC: https://github.com/webdriverio/webdriverrtc 98 | // Browserevent: https://github.com/webdriverio/browserevent 99 | // plugins: { 100 | // webdrivercss: { 101 | // screenshotRoot: 'my-shots', 102 | // failedComparisonsRoot: 'diffs', 103 | // misMatchTolerance: 0.05, 104 | // screenWidth: [320,480,640,1024] 105 | // }, 106 | // webdriverrtc: {}, 107 | // browserevent: {} 108 | // }, 109 | // 110 | // Test runner services 111 | // Services take over a specific job you don't want to take care of. They enhance 112 | // your test setup with almost no effort. Unlike plugins, they don't add new 113 | // commands. Instead, they hook themselves up into the test process. 114 | // services: [],// 115 | // Framework you want to run your specs with. 116 | // The following are supported: Mocha, Jasmine, and Cucumber 117 | // see also: http://webdriver.io/guide/testrunner/frameworks.html 118 | // 119 | // Make sure you have the wdio adapter package for the specific framework installed 120 | // before running any tests. 121 | framework: 'mocha', 122 | // 123 | // Test reporter for stdout. 124 | // The only one supported by default is 'dot' 125 | // see also: http://webdriver.io/guide/reporters/dot.html 126 | reporters: ['allure'], 127 | 128 | // 129 | // Options to be passed to Mocha. 130 | // See the full list at http://mochajs.org/ 131 | mochaOpts: { 132 | ui: 'bdd', 133 | timeout: 60000 134 | }, 135 | // 136 | // ===== 137 | // Hooks 138 | // ===== 139 | // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance 140 | // it and to build services around it. You can either apply a single function or an array of 141 | // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got 142 | // resolved to continue. 143 | /** 144 | * Gets executed once before all workers get launched. 145 | * @param {Object} config wdio configuration object 146 | * @param {Array.} capabilities list of capabilities details 147 | */ 148 | // onPrepare: function (config, capabilities) { 149 | // }, 150 | /** 151 | * Gets executed just before initialising the webdriver session and test framework. It allows you 152 | * to manipulate configurations depending on the capability or spec. 153 | * @param {Object} config wdio configuration object 154 | * @param {Array.} capabilities list of capabilities details 155 | * @param {Array.} specs List of spec file paths that are to be run 156 | */ 157 | // beforeSession: function (config, capabilities, specs) { 158 | // }, 159 | /** 160 | * Gets executed before test execution begins. At this point you can access to all global 161 | * variables like `browser`. It is the perfect place to define custom commands. 162 | * @param {Array.} capabilities list of capabilities details 163 | * @param {Array.} specs List of spec file paths that are to be run 164 | */ 165 | // before: function (capabilities, specs) { 166 | // }, 167 | /** 168 | * Runs before a WebdriverIO command gets executed. 169 | * @param {String} commandName hook command name 170 | * @param {Array} args arguments that command would receive 171 | */ 172 | // beforeCommand: function (commandName, args) { 173 | // }, 174 | 175 | /** 176 | * Hook that gets executed before the suite starts 177 | * @param {Object} suite suite details 178 | */ 179 | // beforeSuite: function (suite) { 180 | // }, 181 | /** 182 | * Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts. 183 | * @param {Object} test test details 184 | */ 185 | // beforeTest: function (test) { 186 | // }, 187 | /** 188 | * Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling 189 | * beforeEach in Mocha) 190 | */ 191 | // beforeHook: function () { 192 | // }, 193 | /** 194 | * Hook that gets executed _after_ a hook within the suite ends (e.g. runs after calling 195 | * afterEach in Mocha) 196 | */ 197 | // afterHook: function () { 198 | // }, 199 | /** 200 | * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) ends. 201 | * @param {Object} test test details 202 | */ 203 | // afterTest: function (test) { 204 | // }, 205 | /** 206 | * Hook that gets executed after the suite has ended 207 | * @param {Object} suite suite details 208 | */ 209 | // afterSuite: function (suite) { 210 | // }, 211 | 212 | /** 213 | * Runs after a WebdriverIO command gets executed 214 | * @param {String} commandName hook command name 215 | * @param {Array} args arguments that command would receive 216 | * @param {Number} result 0 - command success, 1 - command error 217 | * @param {Object} error error object if any 218 | */ 219 | // afterCommand: function (commandName, args, result, error) { 220 | // }, 221 | /** 222 | * Gets executed after all tests are done. You still have access to all global variables from 223 | * the test. 224 | * @param {Number} result 0 - test pass, 1 - test fail 225 | * @param {Array.} capabilities list of capabilities details 226 | * @param {Array.} specs List of spec file paths that ran 227 | */ 228 | // after: function (result, capabilities, specs) { 229 | // }, 230 | /** 231 | * Gets executed right after terminating the webdriver session. 232 | * @param {Object} config wdio configuration object 233 | * @param {Array.} capabilities list of capabilities details 234 | * @param {Array.} specs List of spec file paths that ran 235 | */ 236 | // afterSession: function (config, capabilities, specs) { 237 | // }, 238 | /** 239 | * Gets executed after all workers got shut down and the process is about to exit. 240 | * @param {Object} exitCode 0 - success, 1 - fail 241 | * @param {Object} config wdio configuration object 242 | * @param {Array.} capabilities list of capabilities details 243 | */ 244 | // onComplete: function(exitCode, config, capabilities) { 245 | // } 246 | } 247 | -------------------------------------------------------------------------------- /running-in-parallel/README.md: -------------------------------------------------------------------------------- 1 | ## WebDriver examples running in parallel 2 | 3 | You can find here examples written in Java and JavaScript that show how tests can be executed in parallel, the folder 4 | structure is as follows: 5 | * [Java-TestNG](https://github.com/diemol/frontend_testing/tree/master/running-in-parallel/java-testng): Tests written 6 | in Java with [TestNG](http://testng.org/doc/index.html) as framework, and using the [Surefire plugin](https://maven.apache.org/surefire/maven-surefire-plugin/) to configure the parallelism values and to pass them to TestNG. 7 | * [JS-Mocha-Chai](https://github.com/diemol/frontend_testing/tree/master/running-in-parallel/js-mocha-chai): Tests 8 | written in JavaScript, using [Mocha](http://mochajs.org/) to execute them and [Chai](http://chaijs.com/) to perform 9 | assertions. [Mocha-Parallel-Tests](https://www.npmjs.com/package/mocha-parallel-tests) is used to split the tests in 10 | different threads. 11 | 12 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/README.md: -------------------------------------------------------------------------------- 1 | ### Java TestNG examples with the [Surefire Plugin](https://maven.apache.org/surefire/maven-surefire-plugin/) 2 | 3 | These examples are running a few tests written in Java and using TestNG. The Surefire Plugin is in charge of passing 4 | the parallelism options to TestNG. 5 | 6 | The implementation is running the tests in a number of configurable threads and you can also configure the browser 7 | and platform combinations. 8 | 9 | Both implementations are made to run on [SauceLabs](https://saucelabs.com/) 10 | 11 | #### Environment Setup: 12 | 13 | 1. Check your [Java](https://github.com/diemol/frontend_testing#java) and 14 | [Docker](https://github.com/diemol/frontend_testing#docker) setup. 15 | 16 | #### Steps to run it: 17 | 18 | 1. Clone the repo and go to the folder: 19 | 20 | ```sh 21 | git clone https://github.com/diemol/frontend_testing.git 22 | cd frontend_testing/running-in-parallel/java-testng/ 23 | ``` 24 | 1. Execute the code 25 | 26 | ```sh 27 | mvn test 28 | ``` 29 | 30 | #### How does parallelism work in this example? 31 | 32 | The parallelism configuration for [TestNG](http://testng.org/doc/index.html) is configured via the [Surefire 33 | Plugin](https://maven.apache.org/surefire/maven-surefire-plugin/). 34 | 35 | Two different configurations can be used in the pom.xml to setup the parallelism. 36 | 37 | With: 38 | 39 | ``` 40 | methods 41 | 2 42 | ``` 43 | The `parallel` value can take `classes`, `methods` or `classesAndMethods`. And `threadCount` takes any positive integer, 44 | the limitation for it is given by your infrastructure. 45 | 46 | 47 | Or: 48 | 49 | ``` 50 | 51 | 52 | parallel 53 | methods 54 | 55 | 56 | dataproviderthreadcount 57 | 3 58 | 59 | 60 | ``` 61 | The first two properties work in the same way as described before, for the third one, a great explanation can be seen 62 | [here](http://beust.com/weblog2/archives/000513.html). 63 | 64 | 65 | #### Important to note 66 | Something very important to be noted is how the `webDriver` variable is created, different from the single-threaded 67 | examples, the `webDriver` variable needs to be threadsafe because each session must be exclusive to avoid 68 | interference between tests. This example uses a `ThreadLocal`, which is a common practice to keep the 69 | WebDriver session threadsafe. 70 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/complete/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | running-in-parallel-example-complete 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.testng 15 | testng 16 | 6.14.2 17 | test 18 | 19 | 20 | 21 | org.seleniumhq.selenium 22 | selenium-java 23 | 3.11.0 24 | 25 | 26 | 27 | org.apache.commons 28 | commons-lang3 29 | 3.5 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-compiler-plugin 38 | 3.5.1 39 | 40 | 1.8 41 | 1.8 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-surefire-plugin 47 | 2.19.1 48 | 49 | 61 | methods 62 | 2 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/complete/src/test/java/BaseTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.Platform; 2 | import org.openqa.selenium.WebDriver; 3 | import org.openqa.selenium.remote.BrowserType; 4 | import org.openqa.selenium.remote.CapabilityType; 5 | import org.openqa.selenium.remote.DesiredCapabilities; 6 | import org.openqa.selenium.remote.RemoteWebDriver; 7 | import org.testng.annotations.AfterMethod; 8 | import org.testng.annotations.BeforeMethod; 9 | import org.testng.annotations.DataProvider; 10 | 11 | import java.lang.reflect.Method; 12 | import java.net.MalformedURLException; 13 | import java.net.URL; 14 | 15 | public class BaseTest { 16 | 17 | private static final String SELENIUM_GRID_URL = "http://localhost:4444/wd/hub"; 18 | 19 | // We need a thread safe environment to handle the webDriver variable in each thread separately 20 | private ThreadLocal webDriver = new ThreadLocal<>(); 21 | 22 | // Data provider which returns the browsers that will be used to run the tests 23 | @DataProvider(name = "browsersAndPlatforms", parallel = true) 24 | public static Object[][] browsersAndPlatformsProvider() { 25 | return new Object[][] { 26 | new Object[]{BrowserType.CHROME, Platform.LINUX}, 27 | new Object[]{BrowserType.FIREFOX, Platform.LINUX} 28 | }; 29 | } 30 | 31 | @BeforeMethod 32 | public void startWebDriverAndGetBaseUrl(Method method, Object[] testArgs) throws MalformedURLException { 33 | String browserType = testArgs[0].toString(); 34 | Platform platform = (Platform) testArgs[1]; 35 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); 36 | desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, browserType); 37 | desiredCapabilities.setCapability(CapabilityType.PLATFORM_NAME, platform); 38 | desiredCapabilities.setCapability("name", method.getName()); 39 | 40 | webDriver.set(new RemoteWebDriver(new URL(SELENIUM_GRID_URL), desiredCapabilities)); 41 | 42 | webDriver.get().manage().window().maximize(); 43 | } 44 | 45 | @AfterMethod 46 | public void quitBrowser() { 47 | webDriver.get().quit(); 48 | } 49 | 50 | // Returns the webDriver for the current thread 51 | @SuppressWarnings("WeakerAccess") 52 | public WebDriver getWebDriver() { 53 | return webDriver.get(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/complete/src/test/java/EcommSitesTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.Platform; 2 | import org.testng.Assert; 3 | import org.testng.annotations.Test; 4 | 5 | public class EcommSitesTest extends BaseTest { 6 | 7 | @Test(dataProvider = "browsersAndPlatforms") 8 | public void loadZalandoPageAndCheckTitle(String browserType, Platform platform) { 9 | 10 | // Go to the homepage 11 | getWebDriver().get("http://www.zalando.de"); 12 | 13 | // Assert that the title is the expected one 14 | Assert.assertEquals(getWebDriver().getTitle(), "Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando", 15 | "Page title is not the expected one"); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/complete/src/test/java/SearchEnginesTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.Platform; 2 | import org.testng.Assert; 3 | import org.testng.annotations.Test; 4 | 5 | public class SearchEnginesTest extends BaseTest { 6 | 7 | @Test(dataProvider = "browsersAndPlatforms") 8 | public void loadGooglePageAndCheckTitle(String browserType, Platform platform) { 9 | 10 | // Go to the homepage 11 | getWebDriver().get("http://www.google.com"); 12 | 13 | // Assert that the title is the expected one 14 | Assert.assertEquals(getWebDriver().getTitle(), "Google", "Page title is not the expected one"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/initial/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.frontend.example 8 | running-in-parallel-example-initial 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.testng 15 | testng 16 | 6.14.2 17 | test 18 | 19 | 20 | 21 | org.seleniumhq.selenium 22 | selenium-java 23 | 3.11.0 24 | 25 | 26 | 27 | org.apache.commons 28 | commons-lang3 29 | 3.5 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-compiler-plugin 38 | 3.6.1 39 | 40 | 1.8 41 | 1.8 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-surefire-plugin 47 | 2.19.1 48 | 49 | classes 50 | 2 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/initial/src/test/java/EcommSitesTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.Platform; 2 | import org.openqa.selenium.WebDriver; 3 | import org.openqa.selenium.remote.BrowserType; 4 | import org.openqa.selenium.remote.CapabilityType; 5 | import org.openqa.selenium.remote.DesiredCapabilities; 6 | import org.openqa.selenium.remote.RemoteWebDriver; 7 | import org.testng.Assert; 8 | import org.testng.annotations.AfterMethod; 9 | import org.testng.annotations.BeforeMethod; 10 | import org.testng.annotations.Test; 11 | 12 | import java.lang.reflect.Method; 13 | import java.net.MalformedURLException; 14 | import java.net.URL; 15 | 16 | public class EcommSitesTest { 17 | private static final String SELENIUM_GRID_URL = "http://localhost:4444/wd/hub"; 18 | 19 | private WebDriver webDriver; 20 | 21 | @BeforeMethod 22 | public void startWebDriver(Method method) throws MalformedURLException { 23 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); 24 | desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.CHROME); 25 | desiredCapabilities.setCapability(CapabilityType.PLATFORM, Platform.LINUX); 26 | desiredCapabilities.setCapability("name", method.getName()); 27 | 28 | webDriver = new RemoteWebDriver(new URL(SELENIUM_GRID_URL), desiredCapabilities); 29 | 30 | webDriver.manage().window().maximize(); 31 | } 32 | 33 | @AfterMethod 34 | public void quitBrowser() { 35 | webDriver.quit(); 36 | } 37 | 38 | @Test 39 | public void loadZalandoPageAndCheckTitle() { 40 | 41 | // Go to the homepage 42 | webDriver.get("http://www.zalando.de"); 43 | 44 | // Assert that the title is the expected one 45 | Assert.assertEquals(webDriver.getTitle(), "Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando", 46 | "Page title is not the expected one"); 47 | } 48 | 49 | @Test 50 | public void loadAmazonPageAndCheckTitle() { 51 | 52 | // Go to the homepage 53 | webDriver.get("http://www.amazon.de"); 54 | 55 | // Assert that the title is the expected one 56 | Assert.assertEquals(webDriver.getTitle(), "Amazon.de: Günstige Preise für Elektronik & Foto, Filme, " + 57 | "Musik, Bücher, Games, Spielzeug & mehr"); 58 | } 59 | 60 | @Test 61 | public void loadOttoPageAndCheckTitle() { 62 | 63 | // Go to the homepage 64 | webDriver.get("http://www.otto.de"); 65 | 66 | // Assert that the title is the expected one 67 | Assert.assertEquals(webDriver.getTitle(), "OTTO - Mode, Möbel & Technik » Zum Online-Shop", 68 | "Page title is not the expected one"); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /running-in-parallel/java-testng/initial/src/test/java/SearchEnginesTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.*; 2 | import org.openqa.selenium.remote.BrowserType; 3 | import org.openqa.selenium.remote.CapabilityType; 4 | import org.openqa.selenium.remote.DesiredCapabilities; 5 | import org.openqa.selenium.remote.RemoteWebDriver; 6 | import org.testng.Assert; 7 | import org.testng.annotations.AfterMethod; 8 | import org.testng.annotations.BeforeMethod; 9 | import org.testng.annotations.Test; 10 | 11 | import java.lang.reflect.Method; 12 | import java.net.MalformedURLException; 13 | import java.net.URL; 14 | 15 | public class SearchEnginesTest { 16 | 17 | private static final String SELENIUM_GRID_URL = "http://localhost:4444/wd/hub"; 18 | 19 | private WebDriver webDriver; 20 | 21 | @BeforeMethod 22 | public void startWebDriver(Method method) throws MalformedURLException { 23 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); 24 | desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.CHROME); 25 | desiredCapabilities.setCapability(CapabilityType.PLATFORM, Platform.LINUX); 26 | desiredCapabilities.setCapability("name", method.getName()); 27 | 28 | webDriver = new RemoteWebDriver(new URL(SELENIUM_GRID_URL), desiredCapabilities); 29 | 30 | webDriver.manage().window().maximize(); 31 | } 32 | 33 | @AfterMethod 34 | public void quitBrowser() { 35 | webDriver.quit(); 36 | } 37 | 38 | @Test 39 | public void loadGooglePageAndCheckTitle() { 40 | 41 | // Go to the homepage 42 | webDriver.get("http://www.google.com"); 43 | 44 | // Assert that the title is the expected one 45 | Assert.assertEquals(webDriver.getTitle(), "Google", "Page title is not the expected one"); 46 | } 47 | 48 | @Test 49 | public void loadBingPageAndCheckTitle() { 50 | 51 | // Go to the homepage 52 | webDriver.get("http://www.bing.com"); 53 | 54 | // Assert that the title is the expected one 55 | Assert.assertEquals(webDriver.getTitle(), "Bing", "Page title is not the expected one"); 56 | } 57 | 58 | @Test 59 | public void loadDuckDuckGoPageAndCheckTitle() { 60 | 61 | // Go to the homepage 62 | webDriver.get("http://www.duckduckgo.com"); 63 | 64 | // Assert that the title is the expected one 65 | Assert.assertEquals(webDriver.getTitle(), "DuckDuckGo Search Engine", "Page title is not the expected one"); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/README.md: -------------------------------------------------------------------------------- 1 | ## WebDriver examples in JavaScript with Mocha and Chai running in parallel 2 | 3 | These examples are running a few simple tests written in JavaScript using the [Mocha](https://mochajs.org/) test 4 | framework. The tests are executed in parallel with [Mocha-Parallel-Tests](https://www.npmjs.com/package/mocha-parallel-tests). 5 | 6 | ### Environment Setup 7 | 8 | 1. Check your [JavaScript](https://github.com/diemol/frontend_testing#javascript) and 9 | [Docker](https://github.com/diemol/frontend_testing#docker) setup. 10 | 11 | ### Steps to run it: 12 | 13 | 1. Clone the repo and go to the folder: 14 | 15 | ```sh 16 | git clone https://github.com/diemol/frontend_testing 17 | cd frontend_testing/running-in-parallel/js-mocha-chai/ 18 | ``` 19 | 1. Install Node dependencies: 20 | 21 | ```sh 22 | npm install 23 | ``` 24 | 1. Execute the code: 25 | 26 | ```sh 27 | npm test 28 | ``` 29 | 30 | ### How is parallelism working in these examples? 31 | 32 | _For the initial status of the example_ 33 | 34 | The tests are executed in several threads using the mocha-parallel-tests. This `npm` package grabs every JS file in 35 | the `test` folder and runs it in its own thread. In addition, you can change the `--max-parallel` value in the 36 | [package.json](https://github.com/diemol/frontend_testing/blob/master/running-in-parallel/js-mocha-chai/initial/package.json#L7) file to increase the number of threads if needed. 37 | 38 | _For the complete status of the example_ 39 | 40 | When more than one browser is used, the project is wrapped in several Grunt tasks and then executed in parallel. 41 | 42 | 43 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/complete/.nvmrc: -------------------------------------------------------------------------------- 1 | 5.8.0 2 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/complete/Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var os = require('os'); 3 | 4 | module.exports = function (grunt) { 5 | // configure tasks 6 | grunt.initConfig({ 7 | mocha_parallel: { 8 | options: { 9 | args: function(suiteName) { 10 | return []; 11 | }, 12 | env: function(suiteName) { 13 | process.env.BROWSER = grunt.option('browser'); 14 | process.env.PLATFORM = grunt.option('platform'); 15 | return process.env; 16 | }, 17 | report: function(suite, code, stdout, stderr) { 18 | if (stdout.length) { 19 | process.stdout.write(stdout); 20 | } 21 | if (stderr.length) { 22 | process.stderr.write(stderr); 23 | } 24 | }, 25 | done: function(success, results) { 26 | }, 27 | mocha: './node_modules/.bin/mocha', 28 | //this is the default concurrency, change as needed. 29 | concurrency: os.cpus().length * 1.5 30 | } 31 | }, 32 | 33 | parallel: { 34 | assets: { 35 | options: { 36 | grunt: true 37 | }, 38 | tasks: ['run_LINUX_firefox', 'run_LINUX_chrome'] 39 | } 40 | } 41 | }); 42 | 43 | // load tasks 44 | grunt.loadNpmTasks('grunt-mocha-parallel'); 45 | grunt.loadNpmTasks('grunt-parallel'); 46 | 47 | grunt.registerTask('LINUX_chrome', function(n) { 48 | grunt.option('browser', 'chrome'); 49 | grunt.option('platform', "LINUX"); 50 | }); 51 | 52 | grunt.registerTask('LINUX_firefox', function(n) { 53 | grunt.option('browser', 'firefox'); 54 | grunt.option('platform', "LINUX"); 55 | }); 56 | 57 | // register tasks 58 | grunt.registerTask('default', ['parallel']); 59 | 60 | grunt.registerTask('run_LINUX_firefox', ['LINUX_firefox', 'mocha_parallel']); 61 | grunt.registerTask('run_LINUX_chrome', ['LINUX_chrome', 'mocha_parallel']); 62 | }; -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/complete/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-mocha-chai-parallel", 3 | "version": "1.0.0", 4 | "description": "WebDriver examples running in parallel, using Mocha and Chai", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/grunt" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing#readme", 19 | "dependencies": { 20 | "chai": "^3.5.0", 21 | "grunt": "^1.0.1", 22 | "grunt-cli": "^1.2.0", 23 | "grunt-mocha-parallel": "^0.1.7", 24 | "grunt-parallel": "^0.5.1", 25 | "mocha": "^3.2.0", 26 | "selenium-webdriver": "^3.0.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/complete/test/base.js: -------------------------------------------------------------------------------- 1 | // Create a new instance of WebDriver 2 | var webDriver = require('selenium-webdriver'); 3 | 4 | function createDriver(testTitle) { 5 | // Retrieve the userName and accessKey from the environment 6 | var seleniumGridUrl = "http://localhost:4444/wd/hub"; 7 | 8 | // We declare that we want to run the test on Chrome + Linux 9 | var desiredCaps = { 10 | 'browserName': process.env.BROWSER, 11 | 'platform': process.env.PLATFORM, 12 | 'name': testTitle 13 | }; 14 | 15 | // Create the connection through WebDriver to the Selenium Grid 16 | var driver = new webDriver.Builder() 17 | .withCapabilities(desiredCaps) 18 | .usingServer(seleniumGridUrl) 19 | .build(); 20 | 21 | driver.manage().window().maximize(); 22 | return driver; 23 | } 24 | 25 | exports.createDriver = createDriver; 26 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/complete/test/ecomm-sites.js: -------------------------------------------------------------------------------- 1 | // Getting the Chai expect library for assertions 2 | var expect = require('chai').expect; 3 | 4 | // Create a new instance of WebDriver and other helpful methods from WebDriver 5 | var driver; 6 | 7 | var createDriver = require('./base').createDriver; 8 | 9 | const mochaTimeOut = 100000; //ms 10 | const waitTime = 1000 * 15; 11 | 12 | describe('Check Ecomm Sites Test', function() { 13 | this.timeout(mochaTimeOut); 14 | 15 | beforeEach(function() { 16 | 17 | driver = createDriver(this.currentTest.title); 18 | 19 | driver.manage().window().maximize(); 20 | }); 21 | 22 | it('Load Zalando Page And Check Title', function(done) { 23 | 24 | // Go to the homepage 25 | driver.get("http://www.zalando.de"); 26 | 27 | driver.sleep(waitTime); 28 | 29 | // Assert the title to the expected value 30 | driver.getTitle().then(function(title) { 31 | expect(title).to.equal('Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando'); 32 | done(); 33 | }); 34 | 35 | }); 36 | 37 | it('Load Amazon Page And Check Title', function(done) { 38 | 39 | // Go to the homepage 40 | driver.get("http://www.amazon.de"); 41 | 42 | driver.sleep(waitTime); 43 | 44 | // Assert the title to the expected value 45 | driver.getTitle().then(function(title) { 46 | expect(title).to.equal('Amazon.de: Günstige Preise für Elektronik & Foto, Filme, Musik, Bücher, ' + 47 | 'Games, Spielzeug & mehr'); 48 | done(); 49 | }); 50 | 51 | }); 52 | 53 | it('Load Otto Page And Check Title', function(done) { 54 | 55 | // Go to the homepage 56 | driver.get("http://www.otto.de"); 57 | 58 | driver.sleep(waitTime); 59 | 60 | // Assert the title to the expected value 61 | driver.getTitle().then(function(title) { 62 | expect(title).to.equal('OTTO - Mode, Möbel & Technik » Zum Online-Shop'); 63 | done(); 64 | }); 65 | 66 | }); 67 | 68 | afterEach(function(done) { 69 | // Quitting the browser 70 | driver.quit().then(done); 71 | }); 72 | }); 73 | 74 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/complete/test/search-engines.js: -------------------------------------------------------------------------------- 1 | // Getting the Chai expect library for assertions 2 | var expect = require('chai').expect; 3 | 4 | // Create a new instance of WebDriver and other helpful methods from WebDriver 5 | var driver; 6 | 7 | var createDriver = require('./base').createDriver; 8 | 9 | const mochaTimeOut = 100000; //ms 10 | const waitTime = 1000 * 15; 11 | 12 | describe('Search Engines Test', function() { 13 | this.timeout(mochaTimeOut); 14 | 15 | beforeEach(function() { 16 | 17 | driver = createDriver(this.currentTest.title); 18 | 19 | driver.manage().window().maximize(); 20 | }); 21 | 22 | it('Load Google Page And Check Title', function(done) { 23 | 24 | // Go to the homepage 25 | driver.get("http://www.google.com"); 26 | 27 | driver.sleep(waitTime); 28 | 29 | // Assert the title to the expected value 30 | driver.getTitle().then(function(title) { 31 | expect(title).to.equal('Google'); 32 | done(); 33 | }); 34 | 35 | }); 36 | 37 | it('Load Bing Page And Check Title', function(done) { 38 | 39 | // Go to the homepage 40 | driver.get("http://www.bing.com"); 41 | 42 | driver.sleep(waitTime); 43 | 44 | // Assert the title to the expected value 45 | driver.getTitle().then(function(title) { 46 | expect(title).to.equal('Bing'); 47 | done(); 48 | }); 49 | 50 | }); 51 | 52 | it('Load DuckDuckGo Page And Check Title', function(done) { 53 | 54 | // Go to the homepage 55 | driver.get("http://www.duckduckgo.com"); 56 | 57 | driver.sleep(waitTime); 58 | 59 | // Assert the title to the expected value 60 | driver.getTitle().then(function(title) { 61 | expect(title).to.equal('DuckDuckGo Search Engine'); 62 | done(); 63 | }); 64 | 65 | }); 66 | 67 | afterEach(function(done) { 68 | // Quitting the browser 69 | driver.quit().then(done); 70 | }); 71 | }); 72 | 73 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/initial/.nvmrc: -------------------------------------------------------------------------------- 1 | 7.4.0 -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/initial/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-mocha-chai-parallel", 3 | "version": "1.0.0", 4 | "description": "WebDriver examples running in parallel, using Mocha and Chai", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/mocha-parallel-tests --max-parallel 1 ./test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/diemol/frontend_testing.git" 12 | }, 13 | "author": "https://github.com/diemol", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/diemol/frontend_testing/issues" 17 | }, 18 | "homepage": "https://github.com/diemol/frontend_testing#readme", 19 | "dependencies": { 20 | "mocha-parallel-tests": "^1.2.5", 21 | "chai": "^3.5.0", 22 | "mocha": "^3.2.0", 23 | "selenium-webdriver": "^3.0.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/initial/test/ecomm-sites.js: -------------------------------------------------------------------------------- 1 | // Retrieve the userName and accessKey from the environment Sauce Labs 2 | var seleniumGridUrl = "http://localhost:4444/wd/hub"; 3 | var driver; 4 | 5 | // Create a new instance of WebDriver 6 | var webDriver = require('selenium-webdriver'); 7 | 8 | // Getting the Chai expect library for assertions 9 | var expect = require('chai').expect; 10 | 11 | const mochaTimeOut = 100000; //ms 12 | const waitTime = 1000 * 15; 13 | 14 | // For today's date; 15 | Date.prototype.today = function () { 16 | return ((this.getDate() < 10)?"0":"") + this.getDate() +"/"+(((this.getMonth()+1) < 10)?"0":"") + 17 | (this.getMonth()+1) +"/"+ this.getFullYear(); 18 | }; 19 | 20 | // For the time now 21 | Date.prototype.timeNow = function () { 22 | return ((this.getHours() < 10)?"0":"") + this.getHours() +":"+ ((this.getMinutes() < 10)?"0":"") + 23 | this.getMinutes() +":"+ ((this.getSeconds() < 10)?"0":"") + this.getSeconds(); 24 | }; 25 | 26 | describe('Check Ecomm Sites Test', function() { 27 | this.timeout(mochaTimeOut); 28 | 29 | beforeEach(function() { 30 | // We declare that we want to run the test on Chrome + Linux 31 | var capabilities = { 32 | 'browserName': webDriver.Browser.CHROME, 33 | 'platform': 'LINUX', 34 | 'name': this.currentTest.title 35 | }; 36 | 37 | var datetime = "LastSync: " + new Date().today() + " @ " + new Date().timeNow(); 38 | console.log("START " + datetime + " -> " + this.currentTest.title); 39 | 40 | driver = new webDriver.Builder() 41 | .withCapabilities(capabilities) 42 | .usingServer(seleniumGridUrl) 43 | .build(); 44 | 45 | driver.manage().window().maximize(); 46 | }); 47 | 48 | it('Load Zalando Page And Check Title', function(done) { 49 | 50 | // Go to the homepage 51 | driver.get("http://www.zalando.de"); 52 | 53 | driver.sleep(waitTime); 54 | 55 | // Assert the title to the expected value 56 | driver.getTitle().then(function(title) { 57 | expect(title).to.equal('Schuhe, Mode und Accessoires online kaufen | Schnelle Lieferung von Zalando'); 58 | done(); 59 | }); 60 | 61 | }); 62 | 63 | it('Load Amazon Page And Check Title', function(done) { 64 | 65 | // Go to the homepage 66 | driver.get("http://www.amazon.de"); 67 | 68 | driver.sleep(waitTime); 69 | 70 | // Assert the title to the expected value 71 | driver.getTitle().then(function(title) { 72 | expect(title).to.equal('Amazon.de: Günstige Preise für Elektronik & Foto, Filme, Musik, Bücher, ' + 73 | 'Games, Spielzeug & mehr'); 74 | done(); 75 | }); 76 | 77 | }); 78 | 79 | it('Load Otto Page And Check Title', function(done) { 80 | 81 | // Go to the homepage 82 | driver.get("http://www.otto.de"); 83 | 84 | driver.sleep(waitTime); 85 | 86 | // Assert the title to the expected value 87 | driver.getTitle().then(function(title) { 88 | expect(title).to.equal('OTTO - Mode, Möbel & Technik » Zum Online-Shop'); 89 | done(); 90 | }); 91 | 92 | }); 93 | 94 | afterEach(function(done) { 95 | var datetime = "LastSync: " + new Date().today() + " @ " + new Date().timeNow(); 96 | console.log("FINISH " + datetime + " -> " + this.currentTest.title); 97 | // Quitting the browser 98 | driver.quit().then(done); 99 | }); 100 | }); 101 | 102 | -------------------------------------------------------------------------------- /running-in-parallel/js-mocha-chai/initial/test/search-engines.js: -------------------------------------------------------------------------------- 1 | // Retrieve the userName and accessKey from the environment Sauce Labs 2 | var seleniumGridUrl = "http://localhost:4444/wd/hub"; 3 | var driver; 4 | 5 | // Create a new instance of WebDriver 6 | var webDriver = require('selenium-webdriver'); 7 | 8 | // Getting the Chai expect library for assertions 9 | var expect = require('chai').expect; 10 | 11 | const mochaTimeOut = 100000; //ms 12 | const waitTime = 1000 * 15; 13 | 14 | // For today's date; 15 | Date.prototype.today = function () { 16 | return ((this.getDate() < 10)?"0":"") + this.getDate() +"/"+(((this.getMonth()+1) < 10)?"0":"") + 17 | (this.getMonth()+1) +"/"+ this.getFullYear(); 18 | }; 19 | 20 | // For the time now 21 | Date.prototype.timeNow = function () { 22 | return ((this.getHours() < 10)?"0":"") + this.getHours() +":"+ ((this.getMinutes() < 10)?"0":"") + 23 | this.getMinutes() +":"+ ((this.getSeconds() < 10)?"0":"") + this.getSeconds(); 24 | }; 25 | 26 | describe('Search Engines Test', function() { 27 | this.timeout(mochaTimeOut); 28 | 29 | beforeEach(function() { 30 | // We declare that we want to run the test on Chrome + Linux 31 | var capabilities = { 32 | 'browserName': webDriver.Browser.CHROME, 33 | 'platform': 'LINUX', 34 | 'name': this.currentTest.title 35 | }; 36 | 37 | var datetime = "LastSync: " + new Date().today() + " @ " + new Date().timeNow(); 38 | console.log("START " + datetime + " -> " + this.currentTest.title); 39 | 40 | driver = new webDriver.Builder() 41 | .withCapabilities(capabilities) 42 | .usingServer(seleniumGridUrl) 43 | .build(); 44 | 45 | driver.manage().window().maximize(); 46 | }); 47 | 48 | it('Load Google Page And Check Title', function(done) { 49 | 50 | // Go to the homepage 51 | driver.get("http://www.google.com"); 52 | 53 | driver.sleep(waitTime); 54 | 55 | // Assert the title to the expected value 56 | driver.getTitle().then(function(title) { 57 | expect(title).to.equal('Google'); 58 | done(); 59 | }); 60 | }); 61 | 62 | it('Load Bing Page And Check Title', function(done) { 63 | 64 | // Go to the homepage 65 | driver.get("http://www.bing.com"); 66 | 67 | driver.sleep(waitTime); 68 | 69 | // Assert the title to the expected value 70 | driver.getTitle().then(function(title) { 71 | expect(title).to.equal('Bing'); 72 | done(); 73 | }); 74 | 75 | }); 76 | 77 | it('Load DuckDuckGo Page And Check Title', function(done) { 78 | 79 | // Go to the homepage 80 | driver.get("http://www.duckduckgo.com"); 81 | 82 | driver.sleep(waitTime); 83 | 84 | // Assert the title to the expected value 85 | driver.getTitle().then(function(title) { 86 | expect(title).to.equal('DuckDuckGo Search Engine'); 87 | done(); 88 | }); 89 | 90 | }); 91 | 92 | 93 | afterEach(function(done) { 94 | var datetime = "LastSync: " + new Date().today() + " @ " + new Date().timeNow(); 95 | console.log("FINISH " + datetime + " -> " + this.currentTest.title); 96 | // Quitting the browser 97 | driver.quit().then(done); 98 | }); 99 | 100 | }); 101 | 102 | --------------------------------------------------------------------------------