001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
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 *     http://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 * Contributors:
017 *     bstefanescu
018 */
019package org.nuxeo.runtime.test.runner.web;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.util.function.UnaryOperator;
024
025import org.openqa.selenium.WebDriver;
026import org.openqa.selenium.WebDriverException;
027import org.openqa.selenium.chrome.ChromeDriver;
028import org.openqa.selenium.firefox.FirefoxDriver;
029import org.openqa.selenium.firefox.FirefoxProfile;
030import org.openqa.selenium.htmlunit.HtmlUnitDriver;
031import org.openqa.selenium.ie.InternetExplorerDriver;
032import org.openqa.selenium.remote.DesiredCapabilities;
033
034import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
035import com.gargoylesoftware.htmlunit.Page;
036import com.gargoylesoftware.htmlunit.WebClient;
037import com.gargoylesoftware.htmlunit.WebResponse;
038import com.gargoylesoftware.htmlunit.attachment.AttachmentHandler;
039
040/**
041 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
042 */
043public enum BrowserFamily {
044
045    FIREFOX, IE, CHROME, HTML_UNIT, HTML_UNIT_JS;
046
047    public DriverFactory getDriverFactory() {
048        switch (this) {
049        case FIREFOX:
050            return new FirefoxDriverFactory();
051        case IE:
052            return new IEDriverFactory();
053        case CHROME:
054            return new ChromeDriverFactory();
055        case HTML_UNIT:
056            return new HtmlUnitDriverFactory();
057        case HTML_UNIT_JS:
058        default:
059            return new HtmlUnitJsDriverFactory();
060        }
061    }
062
063    class FirefoxDriverFactory implements DriverFactory {
064        @Override
065        public WebDriver createDriver() {
066            FirefoxProfile profile = new FirefoxProfile();
067            String dir = "target/downloads";
068            profile.setPreference("browser.download.defaultFolder", dir);
069            profile.setPreference("browser.download.downloadDir", dir);
070            profile.setPreference("browser.download.lastDir", dir);
071            profile.setPreference("browser.download.dir", dir);
072            profile.setPreference("browser.download.useDownloadDir", "true");
073            profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "text/json");
074            profile.setPreference("browser.download.folderList", 2);
075            profile.setPreference("browser.download manager.useWindow", "false");
076            DesiredCapabilities dc = DesiredCapabilities.firefox();
077            dc.setCapability(FirefoxDriver.PROFILE, profile);
078            return new FirefoxDriver(dc);
079        }
080
081        @Override
082        public void disposeDriver(WebDriver driver) {
083        }
084
085        @Override
086        public BrowserFamily getBrowserFamily() {
087            return BrowserFamily.this;
088        }
089
090    }
091
092    class ChromeDriverFactory implements DriverFactory {
093        @Override
094        public WebDriver createDriver() {
095            ChromeDriver ff = new ChromeDriver();
096            // ff.manage().setSpeed(Speed.FAST);
097            return ff;
098        }
099
100        @Override
101        public void disposeDriver(WebDriver driver) {
102        }
103
104        @Override
105        public BrowserFamily getBrowserFamily() {
106            return BrowserFamily.this;
107        }
108
109    }
110
111    class IEDriverFactory implements DriverFactory {
112        @Override
113        public WebDriver createDriver() {
114            InternetExplorerDriver driver = new InternetExplorerDriver();
115            // driver.manage().setSpeed(Speed.FAST);
116            return driver;
117        }
118
119        @Override
120        public void disposeDriver(WebDriver driver) {
121        }
122
123        @Override
124        public BrowserFamily getBrowserFamily() {
125            return BrowserFamily.this;
126        }
127
128    }
129
130    class HtmlUnitDriverFactory implements DriverFactory {
131
132        Attachment attachment;
133
134        final AttachmentHandler attachmentHandler = new AttachmentHandler() {
135
136            @Override
137            public void handleAttachment(Page page) {
138                attachment = new Attachment() {
139                    @Override
140                    public String getFilename() {
141                        String filename = getSuggestedFilename();
142                        if (filename != null) {
143                            return filename;
144                        }
145                        String path = page.getUrl().getPath();
146                        return path.substring(path.lastIndexOf('/') + 1);
147                    }
148
149                    @Override
150                    public InputStream getContent() throws IOException {
151                        return page.getWebResponse().getContentAsStream();
152                    }
153
154                    public String getSuggestedFilename() {
155                        final WebResponse response = page.getWebResponse();
156                        final String disp = response.getResponseHeaderValue("Content-Disposition");
157                        int start = disp.indexOf("filename=");
158                        if (start == -1) {
159                            return null;
160                        }
161                        start += "filename=".length();
162                        int end = disp.indexOf(';', start);
163                        if (end == -1) {
164                            end = disp.length();
165                        }
166                        if (disp.charAt(start) == '"' && disp.charAt(end - 1) == '"') {
167                            start++;
168                            end--;
169                        }
170                        return disp.substring(start, end);
171                    }
172                };
173            }
174        };
175
176        UnaryOperator<WebClient> customizer() {
177            return client -> {
178                client.setAttachmentHandler(attachmentHandler);
179                return client;
180            };
181        }
182
183        boolean jsEnabled() {
184            return false;
185        }
186
187        class CustomizableHtmlUnitDriver extends HtmlUnitDriver implements TakesAttachment {
188
189            @Override
190            public WebClient getWebClient() {
191                return super.getWebClient();
192            }
193
194            protected CustomizableHtmlUnitDriver() {
195                super(jsEnabled());
196            }
197
198            @Override
199            protected WebClient modifyWebClient(WebClient client) {
200                return customizer().apply(client);
201            }
202
203            @Override
204            public Attachment getAttachment() throws WebDriverException {
205                return attachment;
206            }
207
208        }
209
210        @Override
211        public WebDriver createDriver() {
212            return new CustomizableHtmlUnitDriver();
213        }
214
215        @Override
216        public void disposeDriver(WebDriver driver) {
217        }
218
219        @Override
220        public BrowserFamily getBrowserFamily() {
221            return BrowserFamily.this;
222        }
223
224        @Override
225        public void waitForAjax(WebDriver driver) {
226            return;
227        }
228
229    }
230
231    class HtmlUnitJsDriverFactory extends HtmlUnitDriverFactory {
232        @Override
233        boolean jsEnabled() {
234            return true;
235        }
236
237        @Override
238        UnaryOperator<WebClient> customizer() {
239            UnaryOperator<WebClient> setJavascript = client -> {
240                client.getOptions().setThrowExceptionOnScriptError(false);
241                client.setAjaxController(new NicelyResynchronizingAjaxController());
242                return client;
243            };
244            return client -> setJavascript.apply(super.customizer().apply(client));
245        }
246
247        @Override
248        public void waitForAjax(WebDriver driver) {
249            ((CustomizableHtmlUnitDriver) driver).getWebClient().waitForBackgroundJavaScript(30000);
250        }
251
252    }
253
254}