├── automating ├── src │ └── test │ │ └── java │ │ └── uk │ │ └── co │ │ └── compendiumdev │ │ └── libraryexamples │ │ ├── cucumber │ │ ├── RunCukesTest.java │ │ ├── people.feature │ │ └── swapi │ │ │ └── SwapiSteps.java │ │ ├── restassured │ │ ├── LoggingUsageTest.java │ │ ├── SwapiAPIUsageTest.java │ │ └── DownloadAFileExampleTest.java │ │ ├── hamcrest │ │ └── HamcrestAssertionOnSwapiDataUsageTest.java │ │ ├── jsoup │ │ └── SwapiApiFromJsoupUsageTest.java │ │ ├── gson │ │ └── GsonParsingSwapiApiData.java │ │ └── webdriver │ │ └── SwapiGUIFormUsageTest.java └── pom.xml ├── .gitignore ├── pom.xml ├── README.md ├── LICENSE └── charting ├── pom.xml └── src └── test └── java ├── xchart └── XchartExamplesTest.java └── jfreechart └── JFreeChartExamplesTest.java /automating/src/test/java/uk/co/compendiumdev/libraryexamples/cucumber/RunCukesTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.cucumber; 2 | 3 | import cucumber.api.CucumberOptions; 4 | import cucumber.api.junit.Cucumber; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(Cucumber.class) 8 | @CucumberOptions(plugin={"pretty", "html:target/cucumber"}) 9 | public class RunCukesTest { 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | /target 24 | /.idea 25 | /library-examples.iml 26 | 27 | downloads 28 | /charting/output/ 29 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | uk.co.compendiumdev 8 | library-examples 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | charting 13 | automating 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libraryexamples 2 | 3 | Simple examples of using Java Libraries. 4 | 5 | Used in "Java For Testers" classroom training. 6 | 7 | Examples include: 8 | 9 | - [WebDriver](http://www.seleniumhq.org/projects/webdriver/) 10 | - [Gson](https://github.com/google/gson) 11 | - [RestAssured](http://rest-assured.io/) 12 | - JsonPath 13 | - [on github](https://github.com/rest-assured/rest-assured) 14 | - [JSoup](https://jsoup.org/) 15 | - [Hamcrest](http://hamcrest.org/) 16 | - [Cucumber JVM](https://cucumber.io/docs/reference/jvm) 17 | 18 | Examples are using the [Swapi.co](https://swapi.co/) public API and JSON data from Swapi.co. 19 | 20 | For more information on Swapi.co visit: 21 | 22 | - https://swapi.co/ 23 | - https://github.com/phalt/swapi 24 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/cucumber/people.feature: -------------------------------------------------------------------------------- 1 | Feature: Can find Star Wars People Using API 2 | 3 | Background: API allows us to access people 4 | 5 | We want the to make sure some common people are in the API 6 | 7 | Scenario: Get Luke from the API 8 | Given a user ID "1" 9 | When a call to the "people" api is made 10 | Then the name of the person is "Luke Skywalker" 11 | 12 | 13 | Scenario: Get C3PO from the API 14 | Given a user ID "2" 15 | When a call to the "people" api is made 16 | Then the name of the person is "C-3PO" 17 | 18 | 19 | Scenario Outline: 20 | 21 | * Users exist with the following "" and "" 22 | 23 | Examples: 24 | | userid | name | 25 | | 1 | Luke Skywalker | 26 | | 2 | C-3PO | 27 | | 3 | R2-D2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Alan Richardson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/restassured/LoggingUsageTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.restassured; 2 | 3 | import io.restassured.RestAssured; 4 | import io.restassured.filter.log.RequestLoggingFilter; 5 | import io.restassured.filter.log.ResponseLoggingFilter; 6 | import org.junit.Test; 7 | 8 | import java.io.*; 9 | 10 | import static org.hamcrest.core.IsEqual.equalTo; 11 | 12 | public class LoggingUsageTest { 13 | 14 | @Test 15 | public void canGetLukeLoggingToConsole(){ 16 | 17 | // configuring logging to console out 18 | RestAssured.filters(new RequestLoggingFilter(), 19 | new ResponseLoggingFilter()); 20 | 21 | RestAssured.get("https://swapi.dev/api/people/1/?format=json"). 22 | then(). 23 | assertThat(). 24 | body("name", 25 | equalTo("Luke Skywalker")); 26 | } 27 | 28 | @Test 29 | public void canGetLukeLoggingToFile() throws IOException { 30 | 31 | final String currentDir = System.getProperty("user.dir"); 32 | File outputFile = new File(currentDir, 33 | "restassured" + System.currentTimeMillis()+".log"); 34 | System.out.println("log to file:" + outputFile.getAbsolutePath().toString()); 35 | FileOutputStream fileOutput = new FileOutputStream(outputFile); 36 | PrintStream printToFile = new PrintStream(fileOutput); 37 | 38 | // configuring logging to console out 39 | RestAssured.filters(new RequestLoggingFilter(printToFile), 40 | new ResponseLoggingFilter(printToFile)); 41 | 42 | RestAssured.get("https://swapi.dev/api/people/1/?format=json"). 43 | then(). 44 | assertThat(). 45 | body("name", 46 | equalTo("Luke Skywalker")); 47 | 48 | fileOutput.close(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/cucumber/swapi/SwapiSteps.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.cucumber.swapi; 2 | 3 | import cucumber.api.java.en.Given; 4 | import cucumber.api.java.en.Then; 5 | import cucumber.api.java.en.When; 6 | import io.restassured.RestAssured; 7 | import io.restassured.path.json.JsonPath; 8 | import io.restassured.response.Response; 9 | import org.junit.Assert; 10 | 11 | import static org.hamcrest.core.IsEqual.equalTo; 12 | 13 | 14 | public class SwapiSteps { 15 | 16 | private String userId; 17 | private String endpoint; 18 | private Response response; 19 | 20 | @Given("^a user ID \"([^\"]*)\"$") 21 | public void aUserID(String userId) throws Throwable { 22 | this.userId = userId; 23 | } 24 | 25 | @When("^a call to the \"([^\"]*)\" api is made$") 26 | public void aCallToTheApiIsMade(String apiendpoint) throws Throwable { 27 | this.endpoint = apiendpoint; 28 | response = RestAssured.get( 29 | "https://swapi.dev/api/" + apiendpoint + "/" + this.userId + "/?format=json"). 30 | andReturn(); 31 | } 32 | 33 | @Then("^the name of the person is \"([^\"]*)\"$") 34 | public void theNameOfThePersonIs(String givenName) throws Throwable { 35 | String json = response.getBody().asString(); 36 | JsonPath jsonPath = new JsonPath(json); 37 | Assert.assertEquals( 38 | givenName, 39 | jsonPath.getString("name")); 40 | } 41 | 42 | 43 | @Given("^Users exist with the following \\\"([^\\\"]*)\\\" and \\\"([^\\\"]*)\\\"$") 44 | public void users_exist_with_the_following(String anid, String name) throws Throwable { 45 | RestAssured.get( 46 | "https://swapi.dev/api/people/" + anid + "/?format=json"). 47 | then(). 48 | assertThat(). 49 | body("name", equalTo(name)); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/hamcrest/HamcrestAssertionOnSwapiDataUsageTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.hamcrest; 2 | 3 | import io.restassured.path.json.JsonPath; 4 | import org.junit.Test; 5 | 6 | import static org.hamcrest.CoreMatchers.not; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | import static org.hamcrest.Matchers.greaterThan; 9 | import static org.hamcrest.core.Is.is; 10 | import static org.hamcrest.core.IsEqual.equalTo; 11 | 12 | public class HamcrestAssertionOnSwapiDataUsageTest { 13 | 14 | // JSON Data from Swapi.io 15 | String swapidata = "{\"name\":\"C-3PO\",\"height\":\"167\",\"mass\":\"75\",\"hair_color\":\"n/a\",\"skin_color\":\"gold\",\"eye_color\":\"yellow\",\"birth_year\":\"112BBY\",\"gender\":\"n/a\",\"homeworld\":\"https://swapi.dev/api/planets/1/\",\"films\":[\"https://swapi.dev/api/films/2/\",\"https://swapi.dev/api/films/5/\",\"https://swapi.dev/api/films/4/\",\"https://swapi.dev/api/films/6/\",\"https://swapi.dev/api/films/3/\",\"https://swapi.dev/api/films/1/\"],\"species\":[\"https://swapi.dev/api/species/2/\"],\"vehicles\":[],\"starships\":[],\"created\":\"2014-12-10T15:10:51.357000Z\",\"edited\":\"2014-12-20T21:17:50.309000Z\",\"url\":\"https://swapi.dev/api/people/2/\"}\n"; 16 | 17 | 18 | // http://hamcrest.org/JavaHamcrest/ 19 | 20 | @Test 21 | public void canAssertWithHamcrest(){ 22 | 23 | // using RestAssured JsonPath to parse the Json Data 24 | JsonPath json = new JsonPath(swapidata); 25 | 26 | String name = json.getString("name"); 27 | int mass = json.getInt("mass"); 28 | 29 | // using C-3PO data 30 | assertThat(name, is(equalTo("C-3PO"))); 31 | assertThat(name, is(not(equalTo("R2-D2")))); 32 | assertThat(mass, is(greaterThan(74))); 33 | 34 | } 35 | 36 | 37 | /* 38 | 39 | You can easily view the JSON used by visiting the Swapi.co site 40 | https://swapi.dev/api/people/2/?format=api 41 | 42 | Exercise: 43 | - Use Json path to extract more values from JSON 44 | - Experiment with Hamcrest matchers to assert on the values from Json 45 | - Expand Json Path to extract to an object and assert on object fields or 'get' methods 46 | - see `SwapoAPIUsageTest` 47 | */ 48 | 49 | } 50 | -------------------------------------------------------------------------------- /charting/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | library-examples 7 | uk.co.compendiumdev 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | charting 13 | 14 | 15 | 5.6.2 16 | 17 | 18 | 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter-api 23 | ${junit.jupiter.version} 24 | test 25 | 26 | 27 | org.junit.jupiter 28 | junit-jupiter-engine 29 | ${junit.jupiter.version} 30 | test 31 | 32 | 33 | 34 | 35 | org.jfree 36 | jfreechart 37 | 1.5.0 38 | 39 | 40 | 41 | 42 | org.jfree 43 | org.jfree.svg 44 | 4.1 45 | 46 | 47 | 48 | 49 | 50 | org.knowm.xchart 51 | xchart 52 | 3.6.5 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.apache.maven.plugins 61 | maven-compiler-plugin 62 | 3.8.0 63 | 64 | 12 65 | UTF-8 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/jsoup/SwapiApiFromJsoupUsageTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.jsoup; 2 | 3 | import org.jsoup.Jsoup; 4 | import org.jsoup.nodes.Document; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | 10 | 11 | public class SwapiApiFromJsoupUsageTest { 12 | 13 | @Test 14 | public void canGetLuke() throws IOException { 15 | 16 | // have to ignore content type or it throws exception if not text/*, application/xml, or application/xhtml+xml 17 | Document doc = Jsoup.connect("https://swapi.dev/api/people/1/?format=json").ignoreContentType(true).get(); 18 | 19 | String json = doc.text(); 20 | System.out.println(json); 21 | 22 | // JSoup does not supply JSON parsing routines 23 | Assert.assertTrue(json.contains("Luke Skywalker")); 24 | 25 | } 26 | 27 | @Test 28 | public void canGetC3PO() throws IOException { 29 | 30 | Document doc = Jsoup.connect("https://swapi.dev/api/people/2/?format=json").ignoreContentType(true).get(); 31 | 32 | String json = doc.text(); 33 | System.out.println(json); 34 | 35 | // JSoup does not supply JSON parsing routines 36 | Assert.assertTrue(json.contains("C-3PO")); 37 | } 38 | 39 | 40 | /* JSOUP API Exercises 41 | 42 | - make sure your URL call is always upto date by getting the url from the root api 43 | - make a call to https://swapi.dev/api/?format=json and use the url for people in the returned array 44 | 45 | - automate more of the Swapi API e.g. planets etc. 46 | 47 | - Create an abstraction layer for the Swapi 48 | - e.g. 49 | 50 | ~~~~~~~~ 51 | Swapi swapi = new Swapi(); 52 | String json = swapi.getPersonJson(1); 53 | ~~~~~~~~ 54 | 55 | - extend the abstraction layer to have a Person object which models the star wars person as an object 56 | - see Gson example of RestAssured JsonPath example for how to do this 57 | 58 | - e.g. 59 | 60 | ~~~~~~~~ 61 | Person luke = swapi.getPerson(1); 62 | Assert.assertTrue("Luke Skywalker",luke.getName()); 63 | ~~~~~~~~ 64 | 65 | - add dependency injection to the Swapi so you have different implementations 66 | 67 | ~~~~~~~~ 68 | Swapi swapi = new Swapi(new JsoupBackedSwapi()); 69 | Swapi swapi = new Swapi(new RestAssuredBackedSwapi()); 70 | Swapi swapi = new Swapi(new WebDriverBackedSwapi()); 71 | ~~~~~~~~ 72 | 73 | 74 | */ 75 | } 76 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/gson/GsonParsingSwapiApiData.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.gson; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import java.util.Map; 9 | 10 | public class GsonParsingSwapiApiData { 11 | 12 | // JSON Data from Swapi.io 13 | String swapidata = "{\"name\":\"C-3PO\",\"height\":\"167\",\"mass\":\"75\",\"hair_color\":\"n/a\",\"skin_color\":\"gold\",\"eye_color\":\"yellow\",\"birth_year\":\"112BBY\",\"gender\":\"n/a\",\"homeworld\":\"https://swapi.dev/api/planets/1/\",\"films\":[\"https://swapi.dev/api/films/2/\",\"https://swapi.dev/api/films/5/\",\"https://swapi.dev/api/films/4/\",\"https://swapi.dev/api/films/6/\",\"https://swapi.dev/api/films/3/\",\"https://swapi.dev/api/films/1/\"],\"species\":[\"https://swapi.dev/api/species/2/\"],\"vehicles\":[],\"starships\":[],\"created\":\"2014-12-10T15:10:51.357000Z\",\"edited\":\"2014-12-20T21:17:50.309000Z\",\"url\":\"https://swapi.dev/api/people/2/\"}\n"; 14 | 15 | 16 | // https://github.com/google/gson 17 | 18 | // Simple and generic way to parse JSON quickly 19 | // - convert it to a Map 20 | // this can get your code up and running fast but 21 | // probably isn't best for long term maintenance 22 | @Test 23 | public void canParseWithGSon(){ 24 | 25 | // generic parsing with Gson 26 | Gson gson = new Gson(); 27 | Map m = gson.fromJson(swapidata, Map.class); 28 | 29 | String name = (String)m.get("name"); 30 | int mass = Integer.parseInt((String)m.get("mass")); 31 | 32 | // using C-3PO data 33 | Assert.assertEquals("C-3PO", name); 34 | Assert.assertNotEquals("R2-D2", name); 35 | //Assert.assertTrue(mass > 74); 36 | Assert.assertTrue("expected " + mass + " to be greater than 74", 37 | mass > 74); 38 | } 39 | 40 | 41 | // longterm use is probably better to create a class to 42 | // represent the payload 43 | // and convert the JSON into the payload with fromJson 44 | private class Person{ 45 | public String name; 46 | public int mass; 47 | } 48 | 49 | @Test 50 | public void canParseWithGSonAndObject(){ 51 | 52 | // generic parsing with Gson 53 | Gson gson = new Gson(); 54 | Person c3po = gson.fromJson(swapidata, Person.class); 55 | 56 | // using C-3PO data 57 | Assert.assertEquals("C-3PO", c3po.name); 58 | Assert.assertNotEquals("R2-D2", c3po.mass); 59 | //Assert.assertTrue(mass > 74); 60 | int mass = c3po.mass; 61 | Assert.assertTrue("expected " + mass + " to be greater than 74", 62 | mass > 74); 63 | 64 | } 65 | 66 | /* Exercises: 67 | 68 | You can easily view the JSON used by visiting the Swapi.co site 69 | https://swapi.dev/api/people/2/?format=api 70 | 71 | - Create a Person object that represents all the attributes of the Swapi.co format 72 | - and parse the string using GSON fromJson in the Person object 73 | 74 | - There are many ways to convert a Json string to objects 75 | - https://stackoverflow.com/questions/4110664/gson-directly-convert-string-to-jsonobject-no-pojo 76 | - Try parsing and using Json Objects the `new JsonParser().parse(swapidata).getAsJsonObject()` 77 | 78 | */ 79 | } 80 | -------------------------------------------------------------------------------- /automating/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | library-examples 7 | uk.co.compendiumdev 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | automating 13 | 14 | 15 | 16 | 19 | 20 | org.seleniumhq.selenium 21 | selenium-java 22 | 3.141.59 23 | 24 | 25 | 28 | 29 | org.seleniumhq.selenium 30 | htmlunit-driver 31 | 2.33.3 32 | 33 | 34 | 35 | 36 | io.rest-assured 37 | rest-assured 38 | 3.2.0 39 | 40 | 41 | 42 | 43 | 44 | org.jsoup 45 | jsoup 46 | 1.11.2 47 | 48 | 49 | 50 | 53 | 54 | 55 | org.hamcrest 56 | hamcrest-all 57 | 1.3 58 | 59 | 60 | 61 | 64 | 65 | 66 | com.google.code.gson 67 | gson 68 | 2.8.5 69 | 70 | 71 | 72 | 79 | 80 | 81 | io.cucumber 82 | cucumber-java 83 | 4.2.0 84 | test 85 | 86 | 87 | io.cucumber 88 | cucumber-junit 89 | 4.2.0 90 | test 91 | 92 | 93 | 94 | junit 95 | junit 96 | 4.12 97 | test 98 | 99 | 100 | 101 | 102 | 104 | 105 | 106 | 107 | org.apache.maven.plugins 108 | maven-compiler-plugin 109 | 3.1 110 | 111 | 1.8 112 | 1.8 113 | UTF-8 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /charting/src/test/java/xchart/XchartExamplesTest.java: -------------------------------------------------------------------------------- 1 | package xchart; 2 | 3 | import org.junit.jupiter.api.BeforeAll; 4 | import org.junit.jupiter.api.Test; 5 | import org.knowm.xchart.*; 6 | import org.knowm.xchart.style.lines.SeriesLines; 7 | import org.knowm.xchart.style.markers.SeriesMarkers; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.time.LocalDate; 12 | import java.time.ZoneId; 13 | import java.util.ArrayList; 14 | import java.util.Date; 15 | import java.util.List; 16 | 17 | public class XchartExamplesTest { 18 | 19 | /* 20 | Useful Links: 21 | 22 | - https://knowm.org/open-source/xchart/ 23 | - https://github.com/knowm/XChart 24 | - https://knowm.org/open-source/xchart/xchart-example-code/ 25 | 26 | */ 27 | static List xData = new ArrayList(); 28 | static List yData = new ArrayList(); 29 | 30 | static File outputPath; 31 | 32 | @BeforeAll 33 | static void dataSetup(){ 34 | // JFreeChart will order dates, xChart displays data in the order provided 35 | for(int sample=1; sample < 10; sample++){ 36 | LocalDate localDate = LocalDate.now().withDayOfMonth(sample); 37 | int year = localDate.getYear(); 38 | int month = localDate.getMonthValue(); 39 | int day = localDate.getDayOfMonth(); 40 | int value = Long.valueOf(1000 + Math.round(Math.random()*100)).intValue(); 41 | 42 | System.out.println(String.format("%d/%02d/%02d - %d", year, month, day, value)); 43 | 44 | xData.add(Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant())); 45 | yData.add(value); 46 | } 47 | 48 | outputPath = new File(System.getProperty("user.dir"), "/output/images"); 49 | outputPath.mkdirs(); 50 | 51 | } 52 | 53 | @Test 54 | void exampleXYGraph() throws IOException { 55 | 56 | XYChart xchart = new XYChartBuilder(). 57 | width(600).height(400). 58 | title("Values at Date"). 59 | xAxisTitle("Date").yAxisTitle("Values"). 60 | build(); 61 | 62 | xchart.getStyler().setLegendVisible(false); 63 | xchart.getStyler().setDatePattern("dd-MMM"); 64 | 65 | XYSeries xseries = xchart.addSeries("Values", xData, yData); 66 | xseries.setMarker(SeriesMarkers.CIRCLE); 67 | xseries.setLineStyle(SeriesLines.SOLID); 68 | 69 | File svg = new File(outputPath, "xchartxychart.svg"); 70 | VectorGraphicsEncoder.saveVectorGraphic( 71 | xchart, 72 | svg.getAbsolutePath(), 73 | VectorGraphicsEncoder.VectorGraphicsFormat.SVG); 74 | 75 | File png = new File(outputPath, "xchartxychart.png"); 76 | BitmapEncoder.saveBitmap( 77 | xchart, 78 | png.getAbsolutePath(), 79 | BitmapEncoder.BitmapFormat.PNG); 80 | 81 | } 82 | 83 | @Test 84 | void exampleBarGraph() throws IOException { 85 | 86 | CategoryChart barchart = new CategoryChartBuilder(). 87 | width(600).height(400). 88 | title("Values at Date") 89 | .xAxisTitle("Date").yAxisTitle("Values"). 90 | build(); 91 | 92 | // Customize Chart 93 | barchart.getStyler().setLegendVisible(false); 94 | barchart.getStyler().setHasAnnotations(true); 95 | barchart.getStyler().setDatePattern("dd-MMM"); 96 | 97 | // Series 98 | barchart.addSeries("values",xData, yData); 99 | 100 | File svg = new File(outputPath, "xchartbarchart.svg"); 101 | VectorGraphicsEncoder.saveVectorGraphic( 102 | barchart, 103 | svg.getAbsolutePath(), 104 | VectorGraphicsEncoder.VectorGraphicsFormat.SVG); 105 | 106 | File png = new File(outputPath, "xchartbarchart.png"); 107 | BitmapEncoder.saveBitmap( 108 | barchart, 109 | png.getAbsolutePath(), 110 | BitmapEncoder.BitmapFormat.PNG); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /charting/src/test/java/jfreechart/JFreeChartExamplesTest.java: -------------------------------------------------------------------------------- 1 | package jfreechart; 2 | 3 | import org.jfree.chart.ChartFactory; 4 | import org.jfree.chart.ChartUtils; 5 | import org.jfree.chart.JFreeChart; 6 | import org.jfree.data.category.CategoryDataset; 7 | import org.jfree.data.category.DefaultCategoryDataset; 8 | import org.jfree.data.time.Day; 9 | import org.jfree.data.time.TimeSeries; 10 | import org.jfree.data.time.TimeSeriesCollection; 11 | import org.jfree.svg.SVGGraphics2D; 12 | import org.jfree.svg.SVGUtils; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.Test; 15 | 16 | 17 | import java.awt.*; 18 | import java.awt.image.BufferedImage; 19 | import java.io.File; 20 | import java.io.IOException; 21 | import java.time.LocalDate; 22 | 23 | 24 | public class JFreeChartExamplesTest { 25 | 26 | /* 27 | Useful links: 28 | - http://www.jfree.org/forum 29 | - http://www.jfree.org/jfreechart/ 30 | - https://github.com/jfree/jfreechart 31 | - https://github.com/jfree/jfree-demos 32 | */ 33 | 34 | static TimeSeries series = new TimeSeries("Values"); 35 | 36 | static File outputPath; 37 | 38 | @BeforeAll 39 | static void dataSetup(){ 40 | // JFreeChart will order dates, xChart displays data in the order provided 41 | for(int sample=1; sample < 10; sample++){ 42 | LocalDate localDate = LocalDate.now().withDayOfMonth(sample); 43 | int year = localDate.getYear(); 44 | int month = localDate.getMonthValue(); 45 | int day = localDate.getDayOfMonth(); 46 | int value = Long.valueOf(1000 + Math.round(Math.random()*100)).intValue(); 47 | 48 | System.out.println(String.format("%d/%02d/%02d - %d", year, month, day, value)); 49 | 50 | series.add(new Day(day, month, year), 51 | Integer.valueOf(value).doubleValue()); 52 | 53 | } 54 | 55 | outputPath = new File(System.getProperty("user.dir"), "/output/images"); 56 | outputPath.mkdirs(); 57 | 58 | } 59 | 60 | @Test 61 | void exampleXYGraph() throws IOException { 62 | 63 | TimeSeriesCollection dataset = new TimeSeriesCollection(); 64 | 65 | dataset.addSeries(series); 66 | 67 | JFreeChart chart = ChartFactory.createTimeSeriesChart( 68 | "Values at Date", 69 | "Date", "Values", dataset); 70 | 71 | 72 | SVGGraphics2D g2 = new SVGGraphics2D(600, 400); 73 | g2.setRenderingHint(JFreeChart.KEY_SUPPRESS_SHADOW_GENERATION, true); 74 | Rectangle r = new Rectangle(0, 0, 600, 400); 75 | chart.draw(g2, r); 76 | 77 | File svg = new File(outputPath, "jfreechartxychart.svg"); 78 | SVGUtils.writeToSVG(svg, g2.getSVGElement()); 79 | 80 | BufferedImage image = new BufferedImage(600, 400, BufferedImage.TYPE_INT_ARGB); 81 | Graphics2D bmp = image.createGraphics(); 82 | 83 | bmp.setRenderingHint(JFreeChart.KEY_SUPPRESS_SHADOW_GENERATION, true); 84 | r = new Rectangle(0, 0, 600, 400); 85 | chart.draw(bmp, r); 86 | 87 | File png = new File(outputPath, "jfreechartxychart.png"); 88 | ChartUtils.saveChartAsPNG(png, chart, 600, 400); 89 | } 90 | 91 | @Test 92 | void exampleBarGraph() throws IOException { 93 | 94 | TimeSeriesCollection dataset = new TimeSeriesCollection(); 95 | 96 | dataset.addSeries(series); 97 | 98 | JFreeChart chart = ChartFactory.createXYBarChart( 99 | "Values at Date", 100 | "Date", true, "Values", dataset); 101 | 102 | 103 | SVGGraphics2D g2 = new SVGGraphics2D(600, 400); 104 | g2.setRenderingHint(JFreeChart.KEY_SUPPRESS_SHADOW_GENERATION, true); 105 | Rectangle r = new Rectangle(0, 0, 600, 400); 106 | chart.draw(g2, r); 107 | 108 | File svg = new File(outputPath, "jfreechartbarchart.svg"); 109 | SVGUtils.writeToSVG(svg, g2.getSVGElement()); 110 | 111 | 112 | BufferedImage image = new BufferedImage(600, 400, BufferedImage.TYPE_INT_ARGB); 113 | Graphics2D bmp = image.createGraphics(); 114 | 115 | bmp.setRenderingHint(JFreeChart.KEY_SUPPRESS_SHADOW_GENERATION, true); 116 | r = new Rectangle(0, 0, 600, 400); 117 | chart.draw(bmp, r); 118 | 119 | File png = new File(outputPath, "jfreechartbarchart.png"); 120 | ChartUtils.saveChartAsPNG(png, chart, 600, 400); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/restassured/SwapiAPIUsageTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.restassured; 2 | 3 | 4 | import io.restassured.RestAssured; 5 | import io.restassured.path.json.JsonPath; 6 | import io.restassured.response.Response; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import static org.hamcrest.core.IsEqual.equalTo; 11 | 12 | public class SwapiAPIUsageTest { 13 | 14 | 15 | /* 16 | 17 | - REST/HTTP abstraction layer 18 | - https://code.google.com/p/rest-assured/ 19 | - Easier and more reliable than apache http client 20 | - https://hc.apache.org/ 21 | - see also http://www.compendiumdev.co.uk/page/tracksrestapibook 22 | 23 | 24 | 25 | */ 26 | 27 | // use basic RestAssured to get a JSON object form url 28 | // and parse with the in built assertions using Hamcrest matchers 29 | @Test 30 | public void canGetLuke(){ 31 | 32 | RestAssured.get("https://swapi.dev/api/people/1/?format=json"). 33 | then(). 34 | assertThat(). 35 | body("name", 36 | equalTo("Luke Skywalker")); 37 | } 38 | 39 | // use RestAssured to make call then return the Response 40 | // use JsonPath to parse the JSON in response 41 | // JsonPath can be imported and used separately from RestAssured if required 42 | @Test 43 | public void canGetC3POandParseWithJsonPath(){ 44 | 45 | // use RestAssured to make an HTML Call 46 | Response response = RestAssured.get( 47 | "https://swapi.dev/api/people/2/?format=json"). 48 | andReturn(); 49 | 50 | String json = response.getBody().asString(); 51 | System.out.println(json); 52 | 53 | // Use the JsonPath parsing library of RestAssured to Parse the JSON 54 | 55 | JsonPath jsonPath = new JsonPath(json); 56 | Assert.assertEquals( 57 | "C-3PO", 58 | jsonPath.getString("name")); 59 | 60 | } 61 | 62 | 63 | /* 64 | 65 | Assert that Luke Skywalker is male 66 | Assert that C-3PO gender is n/a 67 | 68 | 69 | Exercise 70 | - read the RestAssured documentation https://github.com/rest-assured/rest-assured/wiki/Usage 71 | - read the Swapi Documentation - https://swapi.co/documentation 72 | - Experiment with the API 73 | 74 | */ 75 | 76 | 77 | private class Person{ 78 | public String name; 79 | public int mass; 80 | } 81 | 82 | 83 | // JsonPath can parse Json directly into an object, like Gson can 84 | @Test 85 | public void canGetC3POandParseWithJsonPathIntoObject(){ 86 | 87 | // use RestAssured to make an HTML Call 88 | Response response = RestAssured.get( 89 | "https://swapi.dev/api/people/2/?format=json"). 90 | andReturn(); 91 | 92 | String json = response.getBody().asString(); 93 | System.out.println(json); 94 | 95 | // Use the JsonPath parsing library of RestAssured to Parse the JSON into an object 96 | 97 | Person c3po = new JsonPath(json).getObject("$", Person.class); 98 | Assert.assertEquals( 99 | "C-3PO", 100 | c3po.name); 101 | 102 | } 103 | 104 | 105 | 106 | /* Exercises: 107 | 108 | You can easily view the JSON used by visiting the Swapi.co site 109 | https://swapi.dev/api/people/2/?format=api 110 | 111 | - automate more of the Swapi API e.g. planets etc. 112 | 113 | - Create a Person object that represents all the attributes of the Swapi.co format 114 | - and parse the string using JsonPath into the Person object 115 | 116 | - Create an abstraction layer for the Swapi 117 | - e.g. 118 | 119 | ~~~~~~~~ 120 | Swapi swapi = new Swapi(); 121 | String json = swapi.getPersonJson(1); 122 | ~~~~~~~~ 123 | 124 | - extend the abstraction layer to have a Person object which models the star wars person as an object 125 | - see Gson example of RestAssured JsonPath example for how to do this 126 | 127 | - e.g. 128 | 129 | ~~~~~~~~ 130 | Person luke = swapi.getPerson(1); 131 | Assert.assertTrue("Luke Skywalker",luke.getName()); 132 | ~~~~~~~~ 133 | 134 | - add dependency injection to the Swapi so you have different implementations 135 | - create a `SwapiApi` Interface to support different implementations 136 | 137 | ~~~~~~~~ 138 | Swapi swapi = new Swapi(new JsoupBackedSwapi()); 139 | Swapi swapi = new Swapi(new RestAssuredBackedSwapi()); 140 | Swapi swapi = new Swapi(new WebDriverBackedSwapi()); 141 | ~~~~~~~~ 142 | 143 | */ 144 | 145 | 146 | } 147 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/restassured/DownloadAFileExampleTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.restassured; 2 | 3 | import io.restassured.RestAssured; 4 | import io.restassured.filter.log.UrlDecoder; 5 | import io.restassured.response.Response; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | import java.io.File; 10 | import java.io.FileOutputStream; 11 | import java.io.IOException; 12 | import java.io.OutputStream; 13 | import java.nio.charset.Charset; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.UUID; 17 | 18 | public class DownloadAFileExampleTest { 19 | 20 | /** 21 | This example shows how to download a file with RESTAssured 22 | 23 | This will download the file as binary so can be used for images, zip files etc. 24 | 25 | The example is coded to download a source file from github, but you can download anything. 26 | 27 | I sometimes use this during GUI automating to download files. 28 | 29 | Also I use this when interacting with sites that don't provide an API. 30 | */ 31 | @Test 32 | public void canDownloadFilesWithRestAssured() throws IOException { 33 | 34 | // By default this is going to be a subfolder in your project, you can change this to an 35 | // absolute path or resources if you want to. I kept it simple for the example 36 | String downloadFolder = "downloads"; 37 | File outputPath = new File(downloadFolder); 38 | 39 | // create the folder structure if it does not exist 40 | outputPath.mkdirs(); 41 | 42 | // sometimes we might be bypassing login or need login credentials created by cookies 43 | // we can create a hashmap of cookies if we need to 44 | Map cookies = new HashMap(); 45 | // e.g. if I needed to inject a session cookie 46 | //cookies.put("session_id", Secret.SESSION_ID); 47 | 48 | // sometimes our access controls might be via headers so I might need to set those up 49 | // we can create a hashmap of headers if we need to 50 | Map headers = new HashMap(); 51 | //cookies.put("X-AUTH-CODE", Secret.AUTH_CODE_HEADER); 52 | 53 | // if your url was extracted from a json respose in another message then you might need to decode it first 54 | // to make sure it is a completely valid URL e.g. doesn't have any \u0026 type values 55 | String urlToDownload="https://avatars3.githubusercontent.com/u/2621217?s=40&v=4"; 56 | //String urlToDownload="https://raw.githubusercontent.com/eviltester/libraryexamples/master/src/test/java/uk/co/compendiumdev/libraryexamples/restassured/SwapiAPIUsageTest.java"; 57 | urlToDownload = UrlDecoder.urlDecode(urlToDownload, Charset.defaultCharset(), false); 58 | 59 | 60 | // Sometimes I add a timestamp to the file e.g. 61 | //String downloadFileName = "downloadedFile_" + System.currentTimeMillis() + "_.txt"; 62 | 63 | // Sometimes I add a GUID to the file e.g. 64 | //String downloadFileName = "downloadedFile_" + UUID.randomUUID() + "_.txt"; 65 | 66 | // the point is, control the filename so you know what you are downloading 67 | String downloadFileName = "downloadedFile.png"; 68 | 69 | 70 | // For the purpose of the test, if the file already exists then I will delete it 71 | 72 | File checkDownloaded = new File(outputPath.getPath(), downloadFileName); 73 | if(checkDownloaded.exists()) { 74 | checkDownloaded.delete(); 75 | } 76 | 77 | // get image using RestAssured 78 | downloadUrlAsFile(cookies, headers, urlToDownload, outputPath, downloadFileName); 79 | 80 | 81 | // Added an assert to check if file exists 82 | checkDownloaded = new File(outputPath.getPath(), downloadFileName); 83 | Assert.assertTrue(checkDownloaded.exists()); 84 | 85 | 86 | } 87 | 88 | private void downloadUrlAsFile(final Map cookies, final Map headers, final String urlToDownload, final File outputPath, final String filename) throws IOException { 89 | 90 | File outputFile = new File(outputPath.getPath(), filename); 91 | 92 | 93 | final Response response = RestAssured.given().headers(headers).cookies(cookies).when().get(urlToDownload).andReturn(); 94 | 95 | // check if the URL actually exists 96 | if(response.getStatusCode() == 200){ 97 | 98 | // I am choosing to delete the file if it already exists and write it again 99 | // if it already exists you might choose to return and not overwrite it 100 | if (outputFile.exists()) { 101 | outputFile.delete(); 102 | } 103 | 104 | // I might choose to use the mime type of the file to control the file extension 105 | // here I am just outputting it to the console to demonstrate how to get the type 106 | System.out.println("Downloaded an " + response.getHeader("Content-Type")); 107 | 108 | // get the contents of the file 109 | byte[] fileContents = response.getBody().asByteArray(); 110 | 111 | // output contents to file 112 | OutputStream outStream=null; 113 | 114 | try { 115 | 116 | outStream = new FileOutputStream(outputFile); 117 | outStream.write(fileContents); 118 | 119 | }catch(Exception e){ 120 | 121 | System.out.println("Error writing file " + outputFile.getAbsolutePath()); 122 | 123 | }finally { 124 | 125 | if(outStream!=null){ 126 | outStream.close(); 127 | } 128 | } 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /automating/src/test/java/uk/co/compendiumdev/libraryexamples/webdriver/SwapiGUIFormUsageTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.compendiumdev.libraryexamples.webdriver; 2 | 3 | 4 | import com.gargoylesoftware.htmlunit.BrowserVersion; 5 | import org.junit.Assert; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | import org.openqa.selenium.By; 9 | import org.openqa.selenium.WebDriver; 10 | import org.openqa.selenium.WebElement; 11 | import org.openqa.selenium.chrome.ChromeDriver; 12 | import org.openqa.selenium.htmlunit.HtmlUnitDriver; 13 | import org.openqa.selenium.safari.SafariDriver; 14 | import org.openqa.selenium.support.ui.ExpectedConditions; 15 | import org.openqa.selenium.support.ui.WebDriverWait; 16 | 17 | import java.util.List; 18 | 19 | @Ignore("You need to amend for your setup and operating system to use this e.g. did you install a ChromeDriver? Are you on Mac for SafariDriver?") 20 | public class SwapiGUIFormUsageTest { 21 | 22 | /* 23 | This example uses WebDriver from http://www.seleniumhq.org/ 24 | see also http://SeleniumSimplified.com 25 | 26 | // mac: 27 | // brew install chromedriver 28 | 29 | // mac: to use SafariDriver remember to configure safari to allow remote execution - follow instructions in the error message if you have not 30 | 31 | // windows: 32 | // choco install chromedriver 33 | 34 | */ 35 | 36 | private WebDriver getDefaultDriver(){ 37 | 38 | WebDriver driver; 39 | 40 | // comment out the lines you want to get the driver you need 41 | 42 | //driver = new HtmlUnitDriver(BrowserVersion.BEST_SUPPORTED, true); 43 | //((HtmlUnitDriver)driver).setJavascriptEnabled(true); 44 | 45 | //driver = new ChromeDriver(); 46 | 47 | driver = new SafariDriver(); 48 | 49 | return driver; 50 | } 51 | 52 | @Test 53 | public void canGetSwapiGUIPage(){ 54 | 55 | WebDriver driver; 56 | driver = getDefaultDriver(); 57 | 58 | //driver = new HtmlUnitDriver(BrowserVersion.BEST_SUPPORTED, true); 59 | //driver = new ChromeDriver(); 60 | 61 | // On mac SafariDriver is built in 62 | //driver = new SafariDriver(); 63 | 64 | driver.get("https://swapi.co/"); 65 | 66 | Assert.assertTrue(driver.getTitle().contains("Star Wars")); 67 | 68 | driver.quit(); 69 | 70 | } 71 | 72 | 73 | 74 | @Test 75 | public void usePersonApiGUIForLuke(){ 76 | 77 | WebDriver driver; 78 | 79 | driver = getDefaultDriver(); 80 | 81 | // this does actually work on HtmlUnitDriver 82 | //driver = new HtmlUnitDriver(BrowserVersion.CHROME, true); 83 | //((HtmlUnitDriver)driver).setJavascriptEnabled(true); 84 | //driver = new SafariDriver(); 85 | //driver = new ChromeDriver(); 86 | 87 | driver.get("https://swapi.dev/api/people/1/?format=api"); 88 | 89 | WebElement response = driver.findElement(By.cssSelector("div.response-info > pre")); 90 | 91 | String json = response.getText(); 92 | 93 | System.out.println(json); 94 | Assert.assertTrue(json.contains("Luke Skywalker")); 95 | 96 | driver.quit(); 97 | 98 | } 99 | 100 | @Test 101 | public void usePersonApiGUIForC3PO(){ 102 | 103 | WebDriver driver; 104 | 105 | driver = getDefaultDriver(); 106 | 107 | // this does actually work on HtmlUnitDriver 108 | //driver = new HtmlUnitDriver(BrowserVersion.CHROME, true); 109 | //((HtmlUnitDriver)driver).setJavascriptEnabled(true); 110 | //driver = new SafariDriver(); 111 | 112 | driver.get("https://swapi.dev/api/people/2/?format=api"); 113 | 114 | WebElement response = driver.findElement(By.cssSelector("div.response-info > pre")); 115 | 116 | String json = response.getText(); 117 | 118 | System.out.println(json); 119 | Assert.assertTrue(json.contains("C-3PO")); 120 | 121 | driver.quit(); 122 | 123 | } 124 | 125 | 126 | 127 | @Test 128 | public void canSubmitFormFromGUIPage(){ 129 | 130 | // this doesn't actually work on HtmlUnitDriver since the JavaScript is not interpreted properly 131 | WebDriver driver; 132 | driver = getDefaultDriver(); 133 | 134 | //driver = new HtmlUnitDriver(BrowserVersion.CHROME, true); 135 | //((HtmlUnitDriver)driver).setJavascriptEnabled(true); 136 | 137 | //driver = new SafariDriver(); 138 | //driver = new ChromeDriver(); 139 | 140 | driver.get("https://swapi.co/"); 141 | 142 | WebElement inputfield = driver.findElement(By.id("interactive")); 143 | 144 | inputfield.sendKeys("people/2/"); 145 | 146 | driver.findElement(By.className("btn-primary")).click(); 147 | 148 | new WebDriverWait(driver, 10). 149 | until( 150 | ExpectedConditions. 151 | textToBePresentInElementLocated(By.id("interactive_output"), "C-3PO")); 152 | 153 | WebElement output = driver.findElement(By.id("interactive_output")); 154 | String json = output.getText(); 155 | 156 | Assert.assertTrue(json.contains("C-3PO")); 157 | 158 | driver.quit(); 159 | 160 | } 161 | 162 | 163 | /* Exercise search for C-3PO instead of Luke Skywalker: 164 | If you are on Mac then you can uncomment out the SafariDriver lines and run the tests in Safari 165 | - you don't need to download ChromeDriver - although you can if you want to 166 | 167 | On windows you will need to download a Driver - currently recommend ChromeDriver 168 | 169 | Download ChromeDriver from https://sites.google.com/a/chromium.org/chromedriver/ 170 | And add the chromedriver executable to your path 171 | comment out the usage of HtmlUnitDriver and enable use of ChromeDriver 172 | Search for "people/2/" 173 | Assert on the name "C-3PO" 174 | */ 175 | 176 | 177 | @Test 178 | public void canClickSearchLink(){ 179 | 180 | // this doesn't actually work on HtmlUnitDriver since the JavaScript is not interpreted properly 181 | WebDriver driver; 182 | driver = getDefaultDriver(); 183 | 184 | //driver = new HtmlUnitDriver(BrowserVersion.CHROME, true); 185 | //((HtmlUnitDriver)driver).setJavascriptEnabled(true); 186 | //driver = new SafariDriver(); 187 | //driver = new ChromeDriver(); 188 | 189 | driver.get("https://swapi.co/"); 190 | 191 | List links = driver.findElements(By.cssSelector("small > a")); 192 | 193 | links.get(0).click(); 194 | 195 | WebElement output = driver.findElement(By.id("interactive_output")); 196 | String json = output.getText(); 197 | 198 | System.out.println(json); 199 | Assert.assertTrue(json.contains("Luke Skywalker")); 200 | 201 | driver.quit(); 202 | 203 | } 204 | 205 | /* Exercise search for C-3PO instead of Luke Skywalker: 206 | Download ChromeDriver from https://sites.google.com/a/chromium.org/chromedriver/ 207 | And add the chromedriver executable to your path 208 | comment out the usage of HtmlUnitDriver and enable use of ChromeDriver 209 | click on the second link (1) 210 | Assert on the name "Yavin IV" 211 | */ 212 | 213 | /* for a real 'hack' 214 | 215 | create a SwapiApi implementation that uses WebDriver and parses the Json from the GUI 216 | 217 | - ugh it is horrible but you will learn how to parse Strings 218 | - and there will a come a time when you have to automate like this 219 | */ 220 | 221 | } 222 | --------------------------------------------------------------------------------