diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index ba50ab1b523..e1dd18c0b47 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -84,6 +84,7 @@
2.3.13
2.4.7.Final
2.3.3
+ 2.19
4.1.1
4.5.1
4.4.4
@@ -124,6 +125,7 @@
9.4.1208.jre7
2.0.7.RELEASE
2.0.7.RELEASE
+ 2.52.0
2.2.2
3.1.0
1.1.1
@@ -932,6 +934,11 @@
ehcache
${ehcache.version}
+
+ net.sourceforge.htmlunit
+ htmlunit
+ ${htmlunit.version}
+
net.sourceforge.jtds
jtds
@@ -1758,6 +1765,11 @@
lombok
${lombok.version}
+
+ org.seleniumhq.selenium
+ selenium-htmlunit-driver
+ ${selenium.version}
+
org.skyscreamer
jsonassert
diff --git a/spring-boot-test/pom.xml b/spring-boot-test/pom.xml
index a8331732a4a..05373404345 100644
--- a/spring-boot-test/pom.xml
+++ b/spring-boot-test/pom.xml
@@ -75,6 +75,11 @@
jsonassert
true
+
+ org.seleniumhq.selenium
+ selenium-htmlunit-driver
+ true
+
org.springframework
spring-test
@@ -86,8 +91,8 @@
true
- junit
- junit
+ net.sourceforge.htmlunit
+ htmlunit
true
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/LocalHostWebClient.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/LocalHostWebClient.java
new file mode 100644
index 00000000000..88395bbebe2
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/LocalHostWebClient.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.test.web.htmlunit;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
+import com.gargoylesoftware.htmlunit.Page;
+import com.gargoylesoftware.htmlunit.WebClient;
+
+import org.springframework.core.env.Environment;
+import org.springframework.util.Assert;
+
+/**
+ * {@link WebClient} will automatically prefix relative URLs with
+ * localhost:${local.server.port}
.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ */
+public class LocalHostWebClient extends WebClient {
+
+ private final Environment environment;
+
+ public LocalHostWebClient(Environment environment) {
+ Assert.notNull(environment, "Environment must not be null");
+ this.environment = environment;
+ }
+
+ @Override
+ public
P getPage(String url)
+ throws IOException, FailingHttpStatusCodeException, MalformedURLException {
+ if (url.startsWith("/")) {
+ String port = this.environment.getProperty("local.server.port", "8080");
+ url = "http://localhost:" + port + url;
+ }
+ return super.getPage(url);
+ }
+
+}
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/package-info.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/package-info.java
new file mode 100644
index 00000000000..e9c6daa040c
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * HtmlUnit support classes.
+ */
+package org.springframework.boot.test.web.htmlunit;
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriver.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriver.java
new file mode 100644
index 00000000000..d2c265e0083
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriver.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.test.web.htmlunit.webdriver;
+
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import org.openqa.selenium.Capabilities;
+
+import org.springframework.core.env.Environment;
+import org.springframework.test.web.servlet.htmlunit.webdriver.WebConnectionHtmlUnitDriver;
+import org.springframework.util.Assert;
+
+/**
+ * {@link LocalHostWebConnectionHtmlUnitDriver} will automatically prefix relative URLs
+ * with localhost:${local.server.port}
.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ */
+public class LocalHostWebConnectionHtmlUnitDriver extends WebConnectionHtmlUnitDriver {
+
+ private final Environment environment;
+
+ public LocalHostWebConnectionHtmlUnitDriver(Environment environment) {
+ Assert.notNull(environment, "Environment must not be null");
+ this.environment = environment;
+ }
+
+ public LocalHostWebConnectionHtmlUnitDriver(Environment environment,
+ boolean enableJavascript) {
+ super(enableJavascript);
+ Assert.notNull(environment, "Environment must not be null");
+ this.environment = environment;
+ }
+
+ public LocalHostWebConnectionHtmlUnitDriver(Environment environment,
+ BrowserVersion browserVersion) {
+ super(browserVersion);
+ Assert.notNull(environment, "Environment must not be null");
+ this.environment = environment;
+ }
+
+ public LocalHostWebConnectionHtmlUnitDriver(Environment environment,
+ Capabilities capabilities) {
+ super(capabilities);
+ Assert.notNull(environment, "Environment must not be null");
+ this.environment = environment;
+ }
+
+ @Override
+ public void get(String url) {
+ if (url.startsWith("/")) {
+ String port = this.environment.getProperty("local.server.port", "8080");
+ url = "http://localhost:" + port + url;
+ }
+ super.get(url);
+ }
+
+}
diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/webdriver/package-info.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/webdriver/package-info.java
new file mode 100644
index 00000000000..a80565858e8
--- /dev/null
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/webdriver/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Selenium support classes.
+ */
+package org.springframework.boot.test.web.htmlunit.webdriver;
diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/LocalHostWebClientTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/LocalHostWebClientTests.java
new file mode 100644
index 00000000000..47157812397
--- /dev/null
+++ b/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/LocalHostWebClientTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.test.web.htmlunit;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import com.gargoylesoftware.htmlunit.StringWebResponse;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.WebConnection;
+import com.gargoylesoftware.htmlunit.WebRequest;
+import com.gargoylesoftware.htmlunit.WebResponse;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.MockitoAnnotations;
+
+import org.springframework.mock.env.MockEnvironment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link LocalHostWebClient}.
+ *
+ * @author Phillip Webb
+ */
+@SuppressWarnings("resource")
+public class LocalHostWebClientTests {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Captor
+ private ArgumentCaptor requestCaptor;
+
+ public LocalHostWebClientTests() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void createWhenEnvironmentIsNullWillThrowException() throws Exception {
+ this.thrown.expect(IllegalArgumentException.class);
+ this.thrown.expectMessage("Environment must not be null");
+ new LocalHostWebClient(null);
+ }
+
+ @Test
+ public void getPageWhenUrlIsRelativeAndNoPortWillUseLocalhost8080() throws Exception {
+ MockEnvironment environment = new MockEnvironment();
+ WebClient client = new LocalHostWebClient(environment);
+ WebConnection connection = mockConnection();
+ client.setWebConnection(connection);
+ client.getPage("/test");
+ verify(connection).getResponse(this.requestCaptor.capture());
+ assertThat(this.requestCaptor.getValue().getUrl())
+ .isEqualTo(new URL("http://localhost:8080/test"));
+ }
+
+ @Test
+ public void getPageWhenUrlIsRelativeAndHasPortWillUseLocalhostPort()
+ throws Exception {
+ MockEnvironment environment = new MockEnvironment();
+ environment.setProperty("local.server.port", "8181");
+ WebClient client = new LocalHostWebClient(environment);
+ WebConnection connection = mockConnection();
+ client.setWebConnection(connection);
+ client.getPage("/test");
+ verify(connection).getResponse(this.requestCaptor.capture());
+ assertThat(this.requestCaptor.getValue().getUrl())
+ .isEqualTo(new URL("http://localhost:8181/test"));
+ }
+
+ private WebConnection mockConnection() throws MalformedURLException, IOException {
+ WebConnection connection = mock(WebConnection.class);
+ WebResponse response = new StringWebResponse("test", new URL("http://localhost"));
+ given(connection.getResponse((WebRequest) any())).willReturn(response);
+ return connection;
+ }
+
+}
diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java
new file mode 100644
index 00000000000..7e4ee7c6024
--- /dev/null
+++ b/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.test.web.htmlunit.webdriver;
+
+import java.net.URL;
+
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.WebClientOptions;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openqa.selenium.Capabilities;
+
+import org.springframework.core.env.Environment;
+import org.springframework.mock.env.MockEnvironment;
+
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link LocalHostWebConnectionHtmlUnitDriver}.
+ *
+ * @author Phillip Webb
+ */
+public class LocalHostWebConnectionHtmlUnitDriverTests {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Mock
+ private WebClient webClient;
+
+ public LocalHostWebConnectionHtmlUnitDriverTests() {
+ MockitoAnnotations.initMocks(this);
+ given(this.webClient.getOptions()).willReturn(new WebClientOptions());
+ }
+
+ @Test
+ public void createWhenEnvironmentIsNullWillThrowException() throws Exception {
+ this.thrown.expect(IllegalArgumentException.class);
+ this.thrown.expectMessage("Environment must not be null");
+ new LocalHostWebConnectionHtmlUnitDriver(null);
+ }
+
+ @Test
+ public void createWithJavascriptFlagWhenEnvironmentIsNullWillThrowException()
+ throws Exception {
+ this.thrown.expect(IllegalArgumentException.class);
+ this.thrown.expectMessage("Environment must not be null");
+ new LocalHostWebConnectionHtmlUnitDriver(null, true);
+ }
+
+ @Test
+ public void createWithBrowserVersionWhenEnvironmentIsNullWillThrowException()
+ throws Exception {
+ this.thrown.expect(IllegalArgumentException.class);
+ this.thrown.expectMessage("Environment must not be null");
+ new LocalHostWebConnectionHtmlUnitDriver(null, BrowserVersion.CHROME);
+ }
+
+ @Test
+ public void createWithCapabilitiesWhenEnvironmentIsNullWillThrowException()
+ throws Exception {
+ this.thrown.expect(IllegalArgumentException.class);
+ this.thrown.expectMessage("Environment must not be null");
+ new LocalHostWebConnectionHtmlUnitDriver(null, mock(Capabilities.class));
+ }
+
+ @Test
+ public void getPageWhenUrlIsRelativeAndNoPortWillUseLocalhost8080() throws Exception {
+ MockEnvironment environment = new MockEnvironment();
+ LocalHostWebConnectionHtmlUnitDriver driver = new TestLocalHostWebConnectionHtmlUnitDriver(
+ environment);
+ driver.get("/test");
+ verify(this.webClient).getPage(new URL("http://localhost:8080/test"));
+ }
+
+ @Test
+ public void getWhenUrlIsRelativeAndHasPortWillUseLocalhostPort() throws Exception {
+ MockEnvironment environment = new MockEnvironment();
+ environment.setProperty("local.server.port", "8181");
+ LocalHostWebConnectionHtmlUnitDriver driver = new TestLocalHostWebConnectionHtmlUnitDriver(
+ environment);
+ driver.get("/test");
+ verify(this.webClient).getPage(new URL("http://localhost:8181/test"));
+ }
+
+ public class TestLocalHostWebConnectionHtmlUnitDriver
+ extends LocalHostWebConnectionHtmlUnitDriver {
+
+ public TestLocalHostWebConnectionHtmlUnitDriver(Environment environment) {
+ super(environment);
+ }
+
+ @Override
+ public WebClient getWebClient() {
+ return LocalHostWebConnectionHtmlUnitDriverTests.this.webClient;
+ }
+
+ }
+
+}