001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.test.web.servlet.htmlunit.webdriver;
018
019import com.gargoylesoftware.htmlunit.BrowserVersion;
020import com.gargoylesoftware.htmlunit.WebClient;
021import org.openqa.selenium.htmlunit.HtmlUnitDriver;
022
023import org.springframework.lang.Nullable;
024import org.springframework.test.web.servlet.MockMvc;
025import org.springframework.test.web.servlet.htmlunit.MockMvcWebConnectionBuilderSupport;
026import org.springframework.test.web.servlet.htmlunit.WebRequestMatcher;
027import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
028import org.springframework.util.Assert;
029import org.springframework.web.context.WebApplicationContext;
030
031/**
032 * {@code MockMvcHtmlUnitDriverBuilder} simplifies the building of an
033 * {@link HtmlUnitDriver} that delegates to {@link MockMvc} and optionally
034 * delegates to an actual connection for specific requests.
035 *
036 * <p>By default, the driver will delegate to {@code MockMvc} to handle
037 * requests to {@code localhost} and to a {@link WebClient} to handle any
038 * other URL (i.e. to perform an actual HTTP request).
039 *
040 * @author Rob Winch
041 * @author Sam Brannen
042 * @since 4.2
043 * @see #mockMvcSetup(MockMvc)
044 * @see #webAppContextSetup(WebApplicationContext)
045 * @see #webAppContextSetup(WebApplicationContext, MockMvcConfigurer)
046 * @see #javascriptEnabled(boolean)
047 * @see #withDelegate(WebConnectionHtmlUnitDriver)
048 * @see #build()
049 */
050public class MockMvcHtmlUnitDriverBuilder extends MockMvcWebConnectionBuilderSupport<MockMvcHtmlUnitDriverBuilder> {
051
052        @Nullable
053        private HtmlUnitDriver driver;
054
055        private boolean javascriptEnabled = true;
056
057
058        protected MockMvcHtmlUnitDriverBuilder(MockMvc mockMvc) {
059                super(mockMvc);
060        }
061
062        protected MockMvcHtmlUnitDriverBuilder(WebApplicationContext context) {
063                super(context);
064        }
065
066        protected MockMvcHtmlUnitDriverBuilder(WebApplicationContext context, MockMvcConfigurer configurer) {
067                super(context, configurer);
068        }
069
070
071        /**
072         * Create a new {@code MockMvcHtmlUnitDriverBuilder} based on the supplied
073         * {@link MockMvc} instance.
074         * @param mockMvc the {@code MockMvc} instance to use (never {@code null})
075         * @return the MockMvcHtmlUnitDriverBuilder to customize
076         */
077        public static MockMvcHtmlUnitDriverBuilder mockMvcSetup(MockMvc mockMvc) {
078                Assert.notNull(mockMvc, "MockMvc must not be null");
079                return new MockMvcHtmlUnitDriverBuilder(mockMvc);
080        }
081
082        /**
083         * Create a new {@code MockMvcHtmlUnitDriverBuilder} based on the supplied
084         * {@link WebApplicationContext}.
085         * @param context the {@code WebApplicationContext} to create a {@link MockMvc}
086         * instance from (never {@code null})
087         * @return the MockMvcHtmlUnitDriverBuilder to customize
088         */
089        public static MockMvcHtmlUnitDriverBuilder webAppContextSetup(WebApplicationContext context) {
090                Assert.notNull(context, "WebApplicationContext must not be null");
091                return new MockMvcHtmlUnitDriverBuilder(context);
092        }
093
094        /**
095         * Create a new {@code MockMvcHtmlUnitDriverBuilder} based on the supplied
096         * {@link WebApplicationContext} and {@link MockMvcConfigurer}.
097         * @param context the {@code WebApplicationContext} to create a {@link MockMvc}
098         * instance from (never {@code null})
099         * @param configurer the {@code MockMvcConfigurer} to apply (never {@code null})
100         * @return the MockMvcHtmlUnitDriverBuilder to customize
101         */
102        public static MockMvcHtmlUnitDriverBuilder webAppContextSetup(WebApplicationContext context,
103                        MockMvcConfigurer configurer) {
104
105                Assert.notNull(context, "WebApplicationContext must not be null");
106                Assert.notNull(configurer, "MockMvcConfigurer must not be null");
107                return new MockMvcHtmlUnitDriverBuilder(context, configurer);
108        }
109
110        /**
111         * Specify whether JavaScript should be enabled.
112         * <p>Default is {@code true}.
113         * @param javascriptEnabled {@code true} if JavaScript should be enabled
114         * @return this builder for further customizations
115         * @see #build()
116         */
117        public MockMvcHtmlUnitDriverBuilder javascriptEnabled(boolean javascriptEnabled) {
118                this.javascriptEnabled = javascriptEnabled;
119                return this;
120        }
121
122        /**
123         * Supply the {@code WebConnectionHtmlUnitDriver} that the driver
124         * {@linkplain #build built} by this builder should delegate to when
125         * processing non-{@linkplain WebRequestMatcher matching} requests.
126         * @param driver the {@code WebConnectionHtmlUnitDriver} to delegate to
127         * for requests that do not match (never {@code null})
128         * @return this builder for further customizations
129         * @see #build()
130         */
131        public MockMvcHtmlUnitDriverBuilder withDelegate(WebConnectionHtmlUnitDriver driver) {
132                Assert.notNull(driver, "HtmlUnitDriver must not be null");
133                driver.setJavascriptEnabled(this.javascriptEnabled);
134                driver.setWebConnection(createConnection(driver.getWebClient()));
135                this.driver = driver;
136                return this;
137        }
138
139        /**
140         * Build the {@link HtmlUnitDriver} configured via this builder.
141         * <p>The returned driver will use the configured {@link MockMvc} instance
142         * for processing any {@linkplain WebRequestMatcher matching} requests
143         * and a delegate {@code HtmlUnitDriver} for all other requests.
144         * <p>If a {@linkplain #withDelegate delegate} has been explicitly configured,
145         * it will be used; otherwise, a default {@code WebConnectionHtmlUnitDriver}
146         * with the {@link BrowserVersion} set to {@link BrowserVersion#CHROME CHROME}
147         * will be configured as the delegate.
148         * @return the {@code HtmlUnitDriver} to use
149         * @see #withDelegate(WebConnectionHtmlUnitDriver)
150         */
151        public HtmlUnitDriver build() {
152                return (this.driver != null ? this.driver :
153                                withDelegate(new WebConnectionHtmlUnitDriver(BrowserVersion.CHROME)).build());
154        }
155
156}