{"id":1097,"date":"2012-04-17T13:00:00","date_gmt":"2012-04-17T13:00:00","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/2012\/10\/integration-testing-with-selenium.html"},"modified":"2012-10-21T23:31:13","modified_gmt":"2012-10-21T23:31:13","slug":"integration-testing-with-selenium","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html","title":{"rendered":"Integration Testing with Selenium"},"content":{"rendered":"<div dir=\"ltr\" style=\"text-align: left\"><strong>Overview <\/strong><\/p>\n<p>I&#8217;ve been using this for sometime and I&#8217;ve come across a few things that appear to make life easier. I thought I&#8217;d share this as a tutorial, so I&#8217;ll walk you through these parts: <\/p>\n<ol style=\"text-align: left\">\n<li>Setting up a web project using Maven, configuring Selenium to run as an integration test on a C.I.<\/li>\n<li>Look into good ways to model the pages in your site using &#8220;page objects&#8221; and other ways to create points of protected-variation.<\/li>\n<li>Use JPA and Hibernate to perform CRUD operations on a database, and have Maven perform integration tests on them, without any of the costly and often undocumented set-up that this sometimes entails.&nbsp;<\/li>\n<\/ol>\n<p>This post assumes you&#8217;re comfortable with Java, Spring, Maven 2 and, of course, HTML. You&#8217;ll also want Firefox installed on you computer. This tutorial is intended to be otherwise technology agnostic.  <\/p>\n<p><strong>Creating a Webapp  <\/strong><\/p>\n<p>Firstly we&#8217;ll need a webapp to test. Create an project using the maven-webapp-archetype and call it &#8220;selenuim-tutorial&#8221;.  <\/p>\n<p>To run integration tests (ITs) we&#8217;re going to use the Cargo plugin. This starts and stops containers such as Jetty and Tomcat. You can use Cargo to start your site using Jetty (its default) in one command without any changes: <\/p>\n<pre class=\"brush:bash\">mvn cargo:run\r\n<\/pre>\n<p>And check it in you browser at: <\/p>\n<p><a href=\"http:\/\/localhost:8080\/selenuim-tutorial\">http:\/\/localhost:8080\/selenuim-tutorial <\/a><\/p>\n<p>You&#8217;ll get a 404 without welcome file set-up, so add that to the web.xml file:   <\/p>\n<pre class=\"brush:xml\">&lt;welcome-file-list&gt;\r\n &lt;welcome-file&gt;\/index.jsp&lt;\/welcome-file&gt;\r\n&lt;\/welcome-file-list&gt;\r\n <\/pre>\n<p>If you run cargo:run again you&#8217;ll now see the &#8220;Hello World!&#8221; page that was created by Maven.  <\/p>\n<p><strong>Configuring Cargo  <\/strong><\/p>\n<p>We can set-up Cargo to start a Jetty container prior to running the tests, and then stop it afterwards. This will allow us to start our site, run the integration tests, and then stop it afterwards.   <\/p>\n<pre class=\"brush:xml\">&lt;plugin&gt;\r\n &lt;groupId&gt;org.codehaus.cargo&lt;\/groupId&gt;\r\n &lt;artifactId&gt;cargo-maven2-plugin&lt;\/artifactId&gt;\r\n &lt;version&gt;1.2.0&lt;\/version&gt;\r\n &lt;executions&gt;\r\n  &lt;execution&gt;\r\n   &lt;id&gt;start&lt;\/id&gt;\r\n   &lt;phase&gt;pre-integration-test&lt;\/phase&gt;\r\n   &lt;goals&gt;\r\n    &lt;goal&gt;start&lt;\/goal&gt;\r\n   &lt;\/goals&gt;\r\n  &lt;\/execution&gt;\r\n  &lt;execution&gt;\r\n   &lt;id&gt;stop&lt;\/id&gt;\r\n   &lt;phase&gt;post-integration-test&lt;\/phase&gt;\r\n   &lt;goals&gt;\r\n    &lt;goal&gt;stop&lt;\/goal&gt;\r\n   &lt;\/goals&gt;\r\n  &lt;\/execution&gt;\r\n &lt;\/executions&gt;\r\n&lt;\/plugin&gt;\r\n <\/pre>\n<p>You can test this work with:   <\/p>\n<pre class=\"brush:bash\">mvn verify\r\n <\/pre>\n<p>One thing to note at this point is that Cargo runs on port 8080. If you&#8217;ve already got a process listening on that port you might see an error similar to this:   <\/p>\n<pre class=\"brush:bash\">java.net.BindException: Address already in use\r\n <\/pre>\n<p>This might be because you&#8217;re already running another container on this port. If you want to run this on a C.I. (which may itself run on port 8080), this is likely to be something you&#8217;ll want to change. Add these lines to the plugin set-up:  <\/p>\n<pre class=\"brush:xml\">&lt;configuration&gt;\r\n &lt;type&gt;standalone&lt;\/type&gt;\r\n &lt;configuration&gt;\r\n  &lt;properties&gt;\r\n   &lt;cargo.servlet.port&gt;10001&lt;\/cargo.servlet.port&gt;\r\n  &lt;\/properties&gt;\r\n &lt;\/configuration&gt;\r\n&lt;\/configuration&gt;\r\n <\/pre>\n<p>Now the app will be here:  <\/p>\n<p><a href=\"http:\/\/localhost:10001\/selenuim-tutorial\/\">http:\/\/localhost:10001\/selenuim-tutorial\/ <\/a><\/p>\n<p><strong>Setting-up Integration Test Phase  <\/strong><\/p>\n<p>Next, we need to be able to run the integration tests. This requires the Maven failsafe plugin with appropriate goals added to your pom:   <\/p>\n<pre class=\"brush:xml\">&lt;plugin&gt;\r\n &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\r\n &lt;artifactId&gt;maven-failsafe-plugin&lt;\/artifactId&gt;\r\n &lt;version&gt;2.12&lt;\/version&gt;\r\n &lt;executions&gt;\r\n  &lt;execution&gt;\r\n   &lt;id&gt;default&lt;\/id&gt;\r\n   &lt;goals&gt;\r\n    &lt;goal&gt;integration-test&lt;\/goal&gt;\r\n    &lt;goal&gt;verify&lt;\/goal&gt;\r\n   &lt;\/goals&gt;\r\n  &lt;\/execution&gt;\r\n &lt;\/executions&gt;\r\n&lt;\/plugin&gt;\r\n <\/pre>\n<p>By default Failsafe expects tests to match the pattern &#8220;src\/test\/java\/*\/*IT.java&#8221;. Let&#8217;s create a test to demonstrate this. Note that I haven&#8217;t changed from Junit 3.8.1 yet. I&#8217;ll explain to why later on.  <\/p>\n<p>Here&#8217;s a basic, incomplete test:   <\/p>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport junit.framework.TestCase;\r\n \r\npublic class IndexPageIT extends TestCase {\r\n \r\n @Override\r\n protected void setUp() throws Exception {\r\n  super.setUp();\r\n }\r\n \r\n @Override\r\n protected void tearDown() throws Exception {\r\n  super.tearDown();\r\n }\r\n \r\n public void testWeSeeHelloWorld() {\r\n  fail();\r\n }\r\n}\r\n <\/pre>\n<p>Test that works:    <\/p>\n<pre class=\"brush:bash\">mvn verify<\/pre>\n<p>You should see a single test failure. <\/p>\n<p> To test using Selenium you&#8217;ll need to add a test-scoped dependency to pom.xml:   <\/p>\n<pre class=\"brush:xml\">&lt;dependency&gt;\r\n &lt;groupId&gt;org.seleniumhq.selenium&lt;\/groupId&gt;\r\n &lt;artifactId&gt;selenium-firefox-driver&lt;\/artifactId&gt;\r\n &lt;version&gt;2.19.0&lt;\/version&gt;\r\n &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n <\/pre>\n<p>We can now make a couple of changes to our test:   <\/p>\n<pre class=\"brush:bash\">import org.openqa.selenium.WebDriver;\r\nimport org.openqa.selenium.firefox.FirefoxDriver;\r\n \r\n\u2026\r\n \r\n private URI siteBase;\r\n private WebDriver drv;\r\n \r\n @Override\r\n protected void setUp() throws Exception {\r\n  super.setUp();\r\n \r\n  siteBase = new URI(\"http:\/\/localhost:10001\/selenuim-tutorial\/\");\r\n  drv = new FirefoxDriver();\r\n }\r\n \r\n...\r\n \r\n public void testWeSeeHelloWorld() {\r\n  drv.get(siteBase.toString());\r\n  assertTrue(drv.getPageSource().contains(\"Hello World\"));\r\n }\r\n <\/pre>\n<p>We&#8217;ll remove these hard coded values later on.  <\/p>\n<p>Run it again:   <\/p>\n<pre class=\"brush:bash\">mvn verify\r\n <\/pre>\n<p>You shouldn&#8217;t see any failures. What you will have is a lingering Firefox. It won&#8217;t have closed. Run this test 100 times and you&#8217;ll have 100 Firefoxs running. This will quickly become a problem. We can resolve this by adding this initialisation block to our test:  <\/p>\n<pre class=\"brush:java\"> {\r\n  Runtime.getRuntime().addShutdownHook(new Thread() {\r\n   @Override\r\n   public void run() {\r\n    drv.close();\r\n   }\r\n  });\r\n }\r\n <\/pre>\n<p>Naturally, if we create another test, we&#8217;ll soon be violating DRY principles. We&#8217;ll come to that in the next part, as well as looking at what happens when we require a database connection, and some other ways to make sure that your tests are simple to write and easy to maintain. <div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p><strong>Spring Context  <\/strong><\/p>\n<p>In the previous example, the URI for the app, and the driver used were both hard coded. Assuming you&#8217;re familiar with Spring context, this is a pretty straight forward to change these. Firstly we&#8217;ll add the correct dependencies: <\/p>\n<pre class=\"brush:xml\">&lt;dependency&gt;\r\n &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n &lt;artifactId&gt;spring-context&lt;\/artifactId&gt;\r\n &lt;version&gt;3.1.1.RELEASE&lt;\/version&gt;\r\n &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n <\/pre>\n<p>This will allow us to use and application context to inject dependencies. But we&#8217;ll also need the correct Junit runner to test this, which can be found in the spring-test package:   <\/p>\n<pre class=\"brush:xml\">&lt;dependency&gt;\r\n &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n &lt;artifactId&gt;spring-test&lt;\/artifactId&gt;\r\n &lt;version&gt;3.1.1.RELEASE&lt;\/version&gt;\r\n &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n <\/pre>\n<p>We can now update our test to use this. Firstly we&#8217;ll need to create src\/test\/resources\/applicationContext-test.xml   <\/p>\n<pre class=\"brush:xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;beans xmlns=\"http:\/\/www.springframework.org\/schema\/beans\"\r\n xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n xsi:schemaLocation=\"http:\/\/www.springframework.org\/schema\/beans\r\n           http:\/\/www.springframework.org\/schema\/beans\/spring-beans-2.5.xsd\"&gt;\r\n \r\n &lt;bean id=\"siteBase\" class=\"java.net.URI\"&gt;\r\n  &lt;constructor-arg value=\"http:\/\/localhost:10001\/selenuim-tutorial\/\" \/&gt;\r\n &lt;\/bean&gt;\r\n \r\n &lt;bean id=\"drv\" class=\"org.openqa.selenium.firefox.FirefoxDriver\" destroy-method=\"quit\"\/&gt;\r\n&lt;\/beans&gt;\r\n <\/pre>\n<p>Spring will clear up the browser when it finishes, so we can remove the shutdown hook from AbstractIT. This is more robust than having the test case do this.  <\/p>\n<p>The spring-test doesn&#8217;t work with JUnit 3, it needs at least JUnit 4.5. Lets update to version 4.10 in our pom.xml:   <\/p>\n<pre class=\"brush:xml\">&lt;dependency&gt;\r\n &lt;groupId&gt;junit&lt;\/groupId&gt;\r\n &lt;artifactId&gt;junit&lt;\/artifactId&gt;\r\n &lt;version&gt;4.10&lt;\/version&gt;\r\n &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n <\/pre>\n<p>Finally, we need to update our test to work with both Spring and JUnit 4.x:    <\/p>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport static org.junit.Assert.assertTrue;\r\n \r\nimport java.net.URI;\r\n \r\nimport org.junit.Test;\r\nimport org.junit.runner.RunWith;\r\nimport org.openqa.selenium.WebDriver;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.test.context.ContextConfiguration;\r\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\r\n \r\n@RunWith(SpringJUnit4ClassRunner.class)\r\n@ContextConfiguration(locations = { \"\/applicationContext-test.xml\" })\r\npublic class IndexPageIT {\r\n \r\n @Autowired\r\n private URI siteBase;\r\n \r\n @Autowired\r\n private WebDriver drv;\r\n \r\n @Test\r\n public void testWeSeeHelloWorld() {\r\n...\r\n <\/pre>\n<p>These changes moved the configuration from hard coded values into XML config. We can now change the location we are testing, e.g. to a different host, and change the web driver we&#8217;re using, which is left as an exercise for the user.  <\/p>\n<p>A quick note on browsers. I&#8217;ve found that after a browser update, tests often start failing. There appears to be two solutions to this: <\/p>\n<ul style=\"text-align: left\">\n<li>Upgrade to the latest version of the web driver.<\/li>\n<li>Don&#8217;t upgrade the browser.&nbsp;<\/li>\n<\/ul>\n<p>I suspect the first option is the best in most cases, for security reasons  <\/p>\n<p><strong>Abstract IT  <\/strong><\/p>\n<p>Currently, you&#8217;ll need to duplicate all the code for IoC. A simple refactoring can sort this out. We&#8217;ll create a super-class for all tests, and pull-up common features. This refactoring uses inheritance rather than composition, for reasons I&#8217;ll cover later.   <\/p>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport java.net.URI;\r\n \r\nimport org.junit.runner.RunWith;\r\nimport org.openqa.selenium.WebDriver;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.test.context.ContextConfiguration;\r\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\r\n \r\n@RunWith(SpringJUnit4ClassRunner.class)\r\n@ContextConfiguration(locations = { \"\/applicationContext-test.xml\" })\r\npublic abstract class AbstractIT {\r\n \r\n @Autowired\r\n private URI siteBase;\r\n \r\n @Autowired\r\n private WebDriver drv;\r\n \r\n public URI getSiteBase() {\r\n  return siteBase;\r\n }\r\n \r\n public WebDriver getDrv() {\r\n  return drv;\r\n }\r\n}\r\n \r\n<\/pre>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport static org.junit.Assert.assertTrue;\r\n \r\nimport org.junit.Test;\r\n \r\npublic class IndexPageIT extends AbstractIT {\r\n \r\n @Test\r\n public void testWeSeeHelloWorld() {\r\n  getDrv().get(getSiteBase().toString());\r\n  assertTrue(getDrv().getPageSource().contains(\"Hello World\"));\r\n }\r\n}\r\n <\/pre>\n<p><strong>Page Objects  <\/strong><\/p>\n<p>A &#8220;page object&#8221; is an object that encapsulates a single instance of a page, and provides a programatic API to that instance. A basic page might be:   <\/p>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport java.net.URI;\r\n \r\nimport org.openqa.selenium.WebDriver;\r\n \r\npublic class IndexPage {\r\n \r\n \/**\r\n  * @param drv\r\n  *            A web driver.\r\n  * @param siteBase\r\n  *            The root URI of a the expected site.\r\n  * @return Whether or not the driver is at the index page of the site.\r\n  *\/\r\n public static boolean isAtIndexPage(WebDriver drv, URI siteBase) {\r\n  return drv.getCurrentUrl().equals(siteBase);\r\n }\r\n \r\n private final WebDriver drv;\r\n private final URI siteBase;\r\n \r\n public IndexPage(WebDriver drv, URI siteBase) {\r\n  if (!isAtIndexPage(drv, siteBase)) { throw new IllegalStateException(); }\r\n  this.drv = drv;\r\n  this.siteBase = siteBase;\r\n }\r\n}\r\n <\/pre>\n<p>Note that I&#8217;ve provided a static method to return whether or we are at the index page, and I&#8217;ve commented it (debatably unnecessarily for such a self-documating method); page objects form an API and can be worthwhile documenting. You&#8217;ll also see that we throw an exception if the URL is incorrect. It&#8217;s worth considering what condition you use to identify pages. Anything that might change (e.g. the page title, which could change between languages) is probably a poor choice. Something unchanging and machine readable (e.g. the page&#8217;s path) are good choices; if you want to change the path, then you&#8217;ll need to change test.  <\/p>\n<p>Now lets create ourself a problem. I&#8217;d like to add this to index.jsp, but the HTML produced is un-parsable:    <\/p>\n<pre class=\"brush:xml\">&lt;% throw new RuntimeException(); %&gt;\r\n<\/pre>\n<p>Instead we&#8217;ll create a new servlet, but first we&#8217;ll need to add the servlet-api to the pom.xml:   <\/p>\n<pre class=\"brush:xml\">&lt;dependency&gt;\r\n &lt;groupId&gt;javax.servlet&lt;\/groupId&gt;\r\n &lt;artifactId&gt;servlet-api&lt;\/artifactId&gt;\r\n &lt;version&gt;2.5&lt;\/version&gt;\r\n &lt;scope&gt;provided&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n<\/pre>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport java.io.IOException;\r\nimport javax.servlet.ServletException;\r\nimport javax.servlet.http.HttpServlet;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport javax.servlet.http.HttpServletResponse;\r\n \r\npublic class IndexServlet extends HttpServlet {\r\n private static final long serialVersionUID = 1L;\r\n \r\n protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n  throw new RuntimeException();\r\n }\r\n}\r\n <\/pre>\n<p>Add it to the web.xml and remove the now unnecessary welcome page:   <\/p>\n<pre class=\"brush:xml\">&lt;!DOCTYPE web-app PUBLIC\r\n \"-\/\/Sun Microsystems, Inc.\/\/DTD Web Application 2.3\/\/EN\"\r\n \"http:\/\/java.sun.com\/dtd\/web-app_2_3.dtd\" &gt;\r\n&lt;web-app&gt;\r\n &lt;servlet&gt;\r\n  &lt;servlet-name&gt;IndexServlet&lt;\/servlet-name&gt;\r\n  &lt;servlet-class&gt;tutorial.IndexServlet&lt;\/servlet-class&gt;\r\n &lt;\/servlet&gt;\r\n &lt;servlet-mapping&gt;\r\n  &lt;servlet-name&gt;IndexServlet&lt;\/servlet-name&gt;\r\n  &lt;url-pattern&gt;\/&lt;\/url-pattern&gt;\r\n &lt;\/servlet-mapping&gt;\r\n&lt;\/web-app&gt;\r\n <\/pre>\n<p>Update IndexPageIT:  <\/p>\n<pre class=\"brush:java\"> @Test\r\n public void testWeSeeHelloWorld() {\r\n  getDrv().get(getSiteBase().toString());\r\n \r\n  new IndexPage(getDrv(), getSiteBase());\r\n }\r\n <\/pre>\n<p>Run the test again. It passes. This might not be the behaviour you want. Selenium does not provide a way to check the HTTP status code via a WebDriver instance. Nor is the default error page sufficiently consistent between containers (compare this to what happens if you run on Tomcat for example); we cannot make assumptions about the error page&#8217;s content to figure out if an error occurred.  <\/p>\n<p>Our index page currently does not have any machine readable features that allow us to tell it from an error page.  <\/p>\n<p>To tidy up, modify the servlet to display index.jsp:   <\/p>\n<pre class=\"brush:java\"> protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n  getServletContext().getRequestDispatcher(\"\/index.jsp\").forward(request, response);\r\n }\r\n <\/pre>\n<p>Currently index.jsp is a little too simple. Create a new page named create-order.jsp alongside index.jsp, and create a link on index.jsp to that page. We can create a new class for the order page, and a method that navigates us from the index page to the order page.  <\/p>\n<p>Add the following to index.jsp:   <\/p>\n<pre class=\"brush:xml\">&lt;a href=\"create-order.jsp\"&gt;Create an order&lt;\/a&gt;\r\n <\/pre>\n<p>create-order.jsp can be blank for now. We can also create a page object for it:   <\/p>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport java.net.URI;\r\n \r\nimport org.openqa.selenium.WebDriver;\r\n \r\npublic class CreateOrderPage {\r\n public static boolean isAtCreateOrderPage(WebDriver drv, URI siteBase) {\r\n  return drv.getCurrentUrl().equals(siteBase.toString() + \"create-order.jsp\");\r\n }\r\n \r\n private final WebDriver drv;\r\n private final URI siteBase;\r\n \r\n public CreateOrderPage(WebDriver drv, URI siteBase) {\r\n  if (!isAtCreateOrderPage(drv, siteBase)) { throw new IllegalStateException(); }\r\n  this.drv = drv;\r\n  this.siteBase = siteBase;\r\n }\r\n}\r\n <\/pre>\n<p>Add the following dependency to pom.xml which will give us some useful annotations:   <\/p>\n<pre class=\"brush:xml\">&lt;dependency&gt;\r\n &lt;groupId&gt;org.seleniumhq.selenium&lt;\/groupId&gt;\r\n &lt;artifactId&gt;selenium-support&lt;\/artifactId&gt;\r\n &lt;version&gt;2.19.0&lt;\/version&gt;\r\n &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n <\/pre>\n<p>We can flesh out IndexPage now:   <\/p>\n<pre class=\"brush:java\"> @FindBy(css = \"a[href='create-order.jsp']\")\r\n private WebElement createOrderLink;\r\n \r\n public IndexPage(WebDriver drv, URI siteBase) {\r\n  if (!isAtIndexPage(drv, siteBase)) { throw new IllegalStateException(); }\r\n  PageFactory.initElements(drv, this);\r\n  this.drv = drv;\r\n  this.siteBase = siteBase;\r\n }\r\n <\/pre>\n<p>This call to PageFactory.initElements will populate fields annotated with @FindBy with the object matching the element on the web page. Note the use of a CSS selector, it&#8217;s to target the link in way that is unlikely to change. Other methods include matching elements on the page using the link text (which might change for different languages).  <\/p>\n<p>We can now create a method on IndexPages which navigates to CreateOrderPages.   <\/p>\n<pre class=\"brush:java\"> public CreateOrderPage createOrder() {\r\n  createOrderLink.click();\r\n  return new CreateOrderPage(drv, siteBase);\r\n }\r\n <\/pre>\n<p>Finally we can create a test for this link in IndexPageIT:   <\/p>\n<pre class=\"brush:java\"> @Test\r\n public void testCreateOrder() {\r\n  getDrv().get(getSiteBase().toString());\r\n \r\n  new IndexPage(getDrv(), getSiteBase()).createOrder();\r\n \r\n  assertTrue(CreateOrderPage.isAtCreateOrderPage(getDrv(), getSiteBase()));\r\n }\r\n <\/pre>\n<p>Execute mvn verify and you should find the new test passes. At this point we have two tests that do not clean up between them. They use the same WebDriver instance for both tests, the last page will still be open and any cookies that were set will remain so. There are pros and cons of creating a single instance of a WebDriver for several tests. The main pro being reducing time cost of opening and closing browsers, but a con being that the browser is effectively left dirty after each test, cookies set, pop-ups open. We can make sure it is clean before each test with a suitable setUp method in AbstractIT:    <\/p>\n<pre class=\"brush:java\"> @Before\r\n public void setUp() {\r\n  getDrv().manage().deleteAllCookies();\r\n  getDrv().get(siteBase.toString());\r\n }\r\n<\/pre>\n<p>There are alternative approaches to this, I&#8217;ll leave it up to you to look into ways of creating a new WebDriver instance prior the each test. <\/p>\n<p>The @FindBy annotation is especially useful when used on forms. Add a new form to create-order.jsp:    <\/p>\n<pre class=\"brush:xml\"> &lt;form method=\"post\" name=\"create-order\"&gt;\r\n  Item: &lt;input name=\"item\"\/&gt; &lt;br\/&gt;\r\n  Amount: &lt;input name=\"amount\"\/&gt;&lt;br\/&gt;\r\n  &lt;input type=\"submit\"\/&gt;\r\n &lt;\/form&gt;\r\n <\/pre>\n<p>Add those WebElements to CreateOrderPage , and a method to submit the form:    <\/p>\n<pre class=\"brush:java\"> @FindBy(css = \"form[name='create-order'] input[name='item']\")\r\n private WebElement itemInput;\r\n \r\n @FindBy(css = \"form[name='create-order'] input[name='amount']\")\r\n private WebElement amountInput;\r\n \r\n @FindBy(css = \"form[name='create-order'] input[type='submit']\")\r\n private WebElement submit;\r\n \r\n public CreateOrderPage(WebDriver drv, URI siteBase) {\r\n  if (!isAtCreateOrderPage(drv, siteBase)) { throw new IllegalStateException(); }\r\n  PageFactory.initElements(drv, this);\r\n  this.drv = drv;\r\n  this.siteBase = siteBase;\r\n }\r\n \r\n public CreateOrderPage submit(String item, String amount) {\r\n  itemInput.sendKeys(item);\r\n  amountInput.sendKeys(amount);\r\n  submit.click();\r\n  return new CreateOrderPage(drv, siteBase);\r\n }\r\n<\/pre>\n<p>Finally we can create a test for this:   <\/p>\n<pre class=\"brush:java\">package tutorial;\r\n \r\nimport static org.junit.Assert.*;\r\n \r\nimport org.junit.Test;\r\n \r\npublic class CreateOrderPageIT extends AbstractIT {\r\n \r\n @Test\r\n public void testSubmit() {\r\n  new IndexPage(getDrv(), getSiteBase()).createOrder().submit(\"foo\", \"1.0\");\r\n }\r\n}\r\n <\/pre>\n<p><strong>Conclusion <\/strong> <\/p>\n<p>One thing you might note is that the submit method doesn&#8217;t require the amount to be a number as you might expect. You could create a test to see that submitting a string instead of a number. Integration tests can be time consuming to write and vulnerable to breaking as a result of changes to things such as the ID of an element, or name of an input. As a result the greatest benefit to be gained from creating them is initially create them just on business critical paths within your site, for example, product ordering, customer registration processes and payments.  <\/p>\n<p>In the next part of this tutorial, we&#8217;ll looking at backing the tests with some data, and the challenges this engenders. <\/p>\n<p><strong><i>Reference: <\/i><\/strong><a href=\"http:\/\/www.alexecollins.com\/?q=content\/tutorial-integration-testing-selenium-part-1\">Tutorial: Integration Testing with Selenium &#8211; Part 1 <\/a>,<a href=\"http:\/\/www.alexecollins.com\/?q=content\/tutorial-integration-testing-selenium-part-2\">Tutorial: Integration Testing with Selenium &#8211; Part 2 <\/a>from our <a href=\"http:\/\/www.javacodegeeks.com\/p\/jcg.html\">JCG partner<\/a> Alex Collins  at the <a href=\"http:\/\/www.alexecollins.com\/\">Alex Collins &#8216;s<\/a> blog. <\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Overview I&#8217;ve been using this for sometime and I&#8217;ve come across a few things that appear to make life easier. I thought I&#8217;d share this as a tutorial, so I&#8217;ll walk you through these parts: Setting up a web project using Maven, configuring Selenium to run as an integration test on a C.I. Look into &hellip;<\/p>\n","protected":false},"author":202,"featured_media":231,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[287,273],"class_list":["post-1097","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-selenium","tag-testing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Integration Testing with Selenium - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Overview I&#039;ve been using this for sometime and I&#039;ve come across a few things that appear to make life easier. I thought I&#039;d share this as a tutorial, so\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Integration Testing with Selenium - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Overview I&#039;ve been using this for sometime and I&#039;ve come across a few things that appear to make life easier. I thought I&#039;d share this as a tutorial, so\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2012-04-17T13:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2012-10-21T23:31:13+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/selenium-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Alex Collins\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alex Collins\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html\"},\"author\":{\"name\":\"Alex Collins\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/d8297de25c5373886136a5d9bd8e3f02\"},\"headline\":\"Integration Testing with Selenium\",\"datePublished\":\"2012-04-17T13:00:00+00:00\",\"dateModified\":\"2012-10-21T23:31:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html\"},\"wordCount\":1711,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/selenium-logo.jpg\",\"keywords\":[\"Selenium\",\"Testing\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html\",\"name\":\"Integration Testing with Selenium - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/selenium-logo.jpg\",\"datePublished\":\"2012-04-17T13:00:00+00:00\",\"dateModified\":\"2012-10-21T23:31:13+00:00\",\"description\":\"Overview I've been using this for sometime and I've come across a few things that appear to make life easier. I thought I'd share this as a tutorial, so\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/selenium-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/selenium-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2012\\\/04\\\/integration-testing-with-selenium.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Integration Testing with Selenium\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/d8297de25c5373886136a5d9bd8e3f02\",\"name\":\"Alex Collins\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/51ce4c7aceacb45e0ca4ae9d90c010b8b72f7aeaca8bba26b7828d5cfe36622c?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/51ce4c7aceacb45e0ca4ae9d90c010b8b72f7aeaca8bba26b7828d5cfe36622c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/51ce4c7aceacb45e0ca4ae9d90c010b8b72f7aeaca8bba26b7828d5cfe36622c?s=96&d=mm&r=g\",\"caption\":\"Alex Collins\"},\"sameAs\":[\"http:\\\/\\\/www.alexecollins.com\\\/\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/Alex-Collins\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Integration Testing with Selenium - Java Code Geeks","description":"Overview I've been using this for sometime and I've come across a few things that appear to make life easier. I thought I'd share this as a tutorial, so","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html","og_locale":"en_US","og_type":"article","og_title":"Integration Testing with Selenium - Java Code Geeks","og_description":"Overview I've been using this for sometime and I've come across a few things that appear to make life easier. I thought I'd share this as a tutorial, so","og_url":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2012-04-17T13:00:00+00:00","article_modified_time":"2012-10-21T23:31:13+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/selenium-logo.jpg","type":"image\/jpeg"}],"author":"Alex Collins","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Alex Collins","Est. reading time":"15 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html"},"author":{"name":"Alex Collins","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/d8297de25c5373886136a5d9bd8e3f02"},"headline":"Integration Testing with Selenium","datePublished":"2012-04-17T13:00:00+00:00","dateModified":"2012-10-21T23:31:13+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html"},"wordCount":1711,"commentCount":4,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/selenium-logo.jpg","keywords":["Selenium","Testing"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html","url":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html","name":"Integration Testing with Selenium - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/selenium-logo.jpg","datePublished":"2012-04-17T13:00:00+00:00","dateModified":"2012-10-21T23:31:13+00:00","description":"Overview I've been using this for sometime and I've come across a few things that appear to make life easier. I thought I'd share this as a tutorial, so","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/selenium-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/selenium-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2012\/04\/integration-testing-with-selenium.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Integration Testing with Selenium"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/d8297de25c5373886136a5d9bd8e3f02","name":"Alex Collins","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/51ce4c7aceacb45e0ca4ae9d90c010b8b72f7aeaca8bba26b7828d5cfe36622c?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/51ce4c7aceacb45e0ca4ae9d90c010b8b72f7aeaca8bba26b7828d5cfe36622c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/51ce4c7aceacb45e0ca4ae9d90c010b8b72f7aeaca8bba26b7828d5cfe36622c?s=96&d=mm&r=g","caption":"Alex Collins"},"sameAs":["http:\/\/www.alexecollins.com\/"],"url":"https:\/\/www.javacodegeeks.com\/author\/Alex-Collins"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/1097","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/202"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=1097"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/1097\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/231"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=1097"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=1097"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=1097"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}