package net.sf.sahi.client; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import net.sf.sahi.config.Configuration; import net.sf.sahi.test.ProcessHelper; import net.sf.sahi.util.Utils; import org.apache.log4j.Logger; /** * Sahi - Web Automation and Test Tool * * Copyright 2006 V Narayan Raman * * 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. */ /** * Browser is the main driver class for Sahi.<br/> * It performs various actions on the browser and is also a factory for ElementStubs which are a representation * of various elements on the browser DOM.<br/> * A Browser instance is associated with a specific session on the Sahi proxy. * <p/> * <pre> * Eg. * * String sahiBasePath = "D:\\path\\to\\sahi_dir"; * Sting userDataDirectory = "D:\\path\\to\\userdata_dir"; // userdata_dir is in sahiBasePath/userdata by default * * net.sf.sahi.config.Configuration.initJava(sahiBasePath, userDataDirectory); * * String browserName = "ie"; // default values are "ie", "firefox", "safari", "chrome", "opera" - specified in userdata/config/browser_types.xml * Browser browser = new Browser(browserName); * browser.open(); * browser.navigateTo("http://www.google.com"); * browser.textbox("q").setValue("sahi forums"); * browser.submit("Google Search").click(); * browser.link("Sahi - Web Automation and Test Tool").click(); * browser.link("Login").click(); * assertTrue(browser.textbox("req_username").exists()); * * browser.close(); * * * </pre> */ public class Browser extends BrowserElements { private String sessionId = null; private boolean opened = false; private String popupName; private String host = "localhost"; private int port = 9999; private String domainName; private String browserName; private String browserPath; private String browserOption; private String browserProcessName; private static Logger logger = Logger.getLogger(Browser.class); /** * Constructs a Browser object and associates it with a session on Sahi Proxy * * @param browserName - Name of the browser as it is in browser_types.xml */ public Browser(String browserName) { this(browserName, "localhost", Configuration.getPort()); } /** * Constructs a Browser object and associates it with a session on Sahi Proxy * * @param browserPath The browser executable path * @param browserProcessName The process name to look for to run a kill command * @param browserOption Any browser options. Leave blank if not required. */ public Browser(String browserPath, String browserProcessName, String browserOption) { this(browserPath, browserProcessName, browserOption, "localhost", Configuration.getPort()); } /** * Constructs a Browser object and associates it with a session on Sahi Proxy * * @param browserPath The browser executable path * @param browserProcessName The process name to look for to run a kill command * @param browserOption Any browser options. Leave blank if not required. */ public Browser(String browserPath, String browserProcessName, String browserOption, String host, int port) { this.host = host; this.port = port; this.browserPath = browserPath; this.browserOption = browserOption; this.browserProcessName = browserProcessName; sessionId = Utils.generateId(); super.browser = this; } public Browser(String browserName, String host, int port) { this.browserName = browserName; this.host = host; this.port = port; sessionId = Utils.generateId(); super.browser = this; } public Browser() { super.browser = this; } private String getProxyURL(String command, QueryStringBuilder qs) { if (qs == null) qs = new QueryStringBuilder(); qs.add("sahisid", sessionId); return "http://" + host + ":" + port + "/_s_/dyn/Driver_" + command + qs.toString(); } /** * Re-initializes proxy for playback if proxy is restarted.<br/> * Should be invoked if proxy is started as a different process and * needs a restart. <br/> * For NTLM/Windows authentication, java stores the first supplied valid <br/> * credentials. To logout of such a system, the proxy needs to be restarted <br/> * and then browser.restartPlayback() needs to be called. <br/> */ public void restartPlayback() { String url = getProxyURL("restart", new QueryStringBuilder()); Utils.readURL(url); } private String execCommand(String command) { return execCommand(command, null); } private String execCommand(String command, QueryStringBuilder qs) { return new String(Utils.readURL(getProxyURL(command, qs))); } /** * Navigates to the given URL * * @param url * @throws ExecutionException */ public void navigateTo(String url) throws ExecutionException { navigateTo(url, false); } /** * Navigates to the given URL * * @param url * @param forceReload boolean forces reload * @throws ExecutionException */ public void navigateTo(String url, boolean forceReload) throws ExecutionException { executeStep("_sahi._navigateTo(\"" + url + "\", " + forceReload + ")"); fetch("_sahi.loaded"); } /** * Sahi waits for AJAX readyStates 1,2 and 3. * Some applications may have an AJAX request open at state 1 for long periods of time. * Sahi should be asked to ignore readyState 1. _setXHRReadyStatesToWaitFor(2,3?) can be called in this case. * $waitStates is just a string of comma separated readyStates (1,2,3? or 2? or 2,3? etc.). * * @param s */ public void setXHRReadyStatesToWaitFor(String s) { execute("_sahi._setXHRReadyStatesToWaitFor(" + quoted(s) + ")"); } /** * Executes any javascript on the browser. * * @param step * @throws ExecutionException */ public void execute(String step) throws ExecutionException { String prefix = ""; if (isDomain()) prefix = "_sahi._domain(\"" + domainName.replaceAll("\"", "\\\"") + "\")."; if (isPopup()) prefix += "_sahi._popup(\"" + popupName.replaceAll("\"", "\\\"") + "\")."; step = prefix + step; executeStep(step); } private boolean isPopup() { return popupName != null; } private boolean isDomain() { return domainName != null; } public void executeStep(String step) throws ExecutionException { QueryStringBuilder qs = new QueryStringBuilder(); logger.debug("executeStep: " + step); qs.add("step", step); execCommand("setStep", qs); int i = 0; while (i < 4000) { try { Thread.sleep(Configuration.getTimeBetweenSteps()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } i++; String checkDone = execCommand("doneStep"); boolean done = "true".equals(checkDone); logger.debug(checkDone); boolean error = checkDone.startsWith("error:"); if (done) return; if (error) { logger.debug(checkDone); throw new ExecutionException(checkDone); } } } // public void reset() { // try { // navigateTo(getResetURL()); // } catch (ExecutionException e) { // e.printStackTrace(); // } // } /** * Opens a browser instance and associates with a session on Sahi proxy. */ public void open() { if (opened) return; openURL(); int i = 0; while (i < 500) { i++; String isReady = execCommand("isReady"); logger.debug("isReady: " +isReady); if ("true".equals(isReady)) { opened = true; ProcessHelper.setProcessStarted(); return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } opened = true; } private void openURL() { QueryStringBuilder qs = new QueryStringBuilder(); if (this.browserName != null) { qs.add("browserType", this.browserName); qs.add("startUrl", "http://" + Configuration.getCommonDomain() + "/_s_/dyn/Driver_initialized"); execCommand("launchPreconfiguredBrowser", qs); } else { qs.add("browser", this.browserPath); qs.add("browserOption", this.browserOption); qs.add("browserProcessName", this.browserProcessName); qs.add("startUrl", "http://" + Configuration.getCommonDomain() + "/_s_/dyn/Driver_initialized"); execCommand("launchAndPlayback", qs); } } /* private String getInitialURL(){ QueryStringBuilder qs = new QueryStringBuilder(); qs.add("sahisid", this.sessionId); String url = "http://" + Configuration.getCommonDomain() + "/_s_/dyn/Driver_initialized" + qs.toString(); return url; }*/ /*private String getResetURL() { QueryStringBuilder qs = new QueryStringBuilder().add("startUrl", "http://" + Configuration.getCommonDomain() + "/_s_/dyn/Driver_initialized"); qs.add("sahisid", this.sessionId); String url = "http://" + Configuration.getCommonDomain() + "/_s_/dyn/Driver_start" + qs.toString(); return url; }*/ void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Closes the browser instance. * If called on a popup it works */ public void close() { if (isPopup()) { execute("_sahi._closeWindow()"); } else kill(); } /** * Kills the browser instance */ public void kill() { execCommand("kill"); } /** * Sets the value in a form element * * @param textbox * @param value * @throws ExecutionException */ public void setValue(ElementStub textbox, String value) throws ExecutionException { execute("_sahi._setValue(" + textbox + ", " + quoted(value) + ")"); } /** * Sets the file to be posted to the server via a file input field. * This method instructs the proxy to inject the file contents directly in the request. * The browser's input field will not be populated, though data will be submitted. * * @param elementStub * @param value * @throws ExecutionException */ public void setFile(ElementStub textbox, String value) throws ExecutionException { execute("_sahi._setFile(" + textbox + ", " + quoted(value) + ")"); } /** * Sets the file to be posted to the server via a file input field. * This method instructs the proxy to inject the file contents directly in the request. * The browser's input field will not be populated, though data will be submitted. * * @param elementStub * @param value * @param url String The form "action" url pattern to which this upload request is submitted * @throws ExecutionException */ public void setFile(ElementStub textbox, String value, String URL) throws ExecutionException { execute("_sahi._setFile(" + textbox + ", " + quoted(value) + ", " + quoted(URL) + ")"); } /** * Simulates a key down event on the given element with a combo value ie. ALT/CTRL/SHIFT etc. * * @param element * @param keysequence Key to be pressed down * @param combo String can be "ALT", "META", "SHIFT", "CTRL" or a combination of these with | as the separator * eg. "ALT|SHIFT" or "CTRL|ALT|SHIFT" * @throws ExecutionException */ public void keyDown(ElementStub elementStub, String keySequence, String combo) throws ExecutionException { execute("_sahi._keyDown(" + elementStub + ", " + quoted(keySequence) + ", " + quoted(combo) + ")"); } /** * Simulates a key down event on the given element with a combo value ie. ALT/CTRL/SHIFT etc. * * @param element * @param keysequence Key to be pressed down * @param combo String can be "ALT", "META", "SHIFT", "CTRL" or a combination of these with | as the separator * eg. "ALT|SHIFT" or "CTRL|ALT|SHIFT" * @throws ExecutionException */ public void keyDown(ElementStub elementStub, String keySequence) throws ExecutionException { execute("_sahi._keyDown(" + elementStub + ", " + quoted(keySequence) + ")"); } /** * Highlights the given element * * @param element * @throws ExecutionException */ public void highlight(ElementStub element) throws ExecutionException { execute("_sahi._highlight(" + element + ")"); } /** * Simulates a key press event on the given element with a combo value ie. ALT/CTRL/SHIFT etc. * * @param element * @param keysequence Key to be pressed * @param combo String can be "ALT", "META", "SHIFT", "CTRL" or a combination of these with | as the separator * eg. "ALT|SHIFT" or "CTRL|ALT|SHIFT" * @throws ExecutionException */ public void keyPress(ElementStub elementStub, String keySequence, String combo) throws ExecutionException { execute("_sahi._keyPress(" + elementStub + ", " + quoted(keySequence) + ", " + quoted(combo) + ")"); } /** * Simulates a key press event on the given element. * * @param element * @param keysequence Key to be pressed * @throws ExecutionException */ public void keyPress(ElementStub elementStub, String keySequence) throws ExecutionException { execute("_sahi._keyPress(" + elementStub + ", " + quoted(keySequence) + ")"); } /** * Clicks the given element * * @param element * @throws ExecutionException */ public void click(ElementStub element) throws ExecutionException { execute("_sahi._click(" + element + ")"); } /** * Simulates a blur event on the element * * @param elementStub */ public void blur(ElementStub elementStub) { execute("_sahi._blur(" + elementStub + ")"); } public String getAttribute(ElementStub el, String attribute) throws ExecutionException { return fetch("_sahi._getAttribute(" + el + ", " + quoted(attribute) + ")"); } /** * Double clicks the given element * * @param element * @throws ExecutionException */ public void doubleClick(ElementStub element) throws ExecutionException { execute("_sahi._doubleClick(" + element + ")"); } /** * Right clicks the given element * * @param element * @throws ExecutionException */ public void rightClick(ElementStub element) throws ExecutionException { execute("_sahi._rightClick(" + element + ")"); } /** * Checks the given checkbox or radio only if it is unchecked. * * @param element * @throws ExecutionException */ public void check(ElementStub element) throws ExecutionException { execute("_sahi._check(" + element + ")"); } /** * Unchecks the given checkbox only if it is checked. * * @param element * @throws ExecutionException */ public void uncheck(ElementStub element) throws ExecutionException { execute("_sahi._uncheck(" + element + ")"); } /** * Brings focus on the element. * * @param element * @throws ExecutionException */ public void focus(ElementStub element) throws ExecutionException { execute("_sahi._focus(" + element + ")"); } /** * Removes focus from the element. * * @param element * @throws ExecutionException */ public void removeFocus(ElementStub element) throws ExecutionException { execute("_sahi._removeFocus(" + element + ")"); } /** * Simulates a mouse over on the given element * * @param element * @throws ExecutionException */ public void mouseOver(ElementStub element) throws ExecutionException { execute("_sahi._mouseOver(" + element + ")"); } /** * Simulates a mouse down on the given element * * @param element * @throws ExecutionException */ public void mouseDown(ElementStub element) throws ExecutionException { execute("_sahi._mouseDown(" + element + ")"); } /** * Simulates a mouse up on the given element * * @param element * @throws ExecutionException */ public void mouseUp(ElementStub element) throws ExecutionException { execute("_sahi._mouseUp(" + element + ")"); } /** * Simulates a drag and drop event * * @param dragElement Element to drag * @param dropElement Element to drop on * @throws ExecutionException */ public void dragDrop(ElementStub dragElement, ElementStub dropElement) throws ExecutionException { execute("_sahi._dragDrop(" + dragElement + ", " + dropElement + ")"); } /** * Simulates a drag and drop event * * @param dragElement Element to drag * @param x X coordinate * @param y Y coordinate * @throws ExecutionException */ public void dragDropXY(ElementStub dragElement, int x, int y) throws ExecutionException { execute("_sahi._dragDropXY(" + dragElement + ", " + x + "," + y + ")"); } /** * Fetches the value of any DOM property * * @param expression * @return * @throws ExecutionException */ public String fetch(String expression) throws ExecutionException { Date d = new Date(); String key = "___lastValue___" + d.toString(); execute("_sahi.setServerVarPlain('" + key + "', " + expression + ")"); return execCommand("getVariable", new QueryStringBuilder().add("key", key)); } /** * Fetches the string value of an element stub by performing an eval on the browser * * @param element * @return * @throws ExecutionException */ public String fetch(ElementStub el) throws ExecutionException { return fetch(el.toString()); } /** * Returns the inner text of given element from the browser * * @param el * @return * @throws ExecutionException */ public String getText(ElementStub el) throws ExecutionException { return fetch("_sahi._getText(" + el + ")"); } /** * Returns the value of given form element from the browser * * @param el * @return * @throws ExecutionException */ public String getValue(ElementStub el) throws ExecutionException { return fetch(el + ".value"); } /** * Returns true if the element exists on the browser * Retries a few times if the return value is false. This can be controlled with script.max_reattempts_on_error in sahi.properties. * Use exists(el, true) to return in a single try. * * @param elementStub * @return */ public boolean exists(ElementStub el) { return exists(el, false); } /** * Returns true if the element exists on the browser<br/> * Retries a few times if optimistic is false. Retry count can be controlled with script.max_reattempts_on_error in sahi.properties. <br/> * Use exists(el, true) to return in a single try. * * @param elementStub * @param optimistic boolean. If true returns in a single try. If false, retries a few times. * @return */ public boolean exists(ElementStub el, boolean optimistic) { if (optimistic) return exists1(el); else { for (int i = 0; i < Configuration.getMaxReAttemptsOnError(); i++) { if (exists1(el)) return true; } return false; } } private boolean exists1(ElementStub el) { try { String fetched = fetch("_sahi._exists(" + el + ")"); return ("true".equals(fetched)); } catch (ExecutionException e) { return false; } } /** * Returns true if the element is visible on the browser * * @param elementStub * @return */ public boolean isVisible(ElementStub el) throws ExecutionException { return isVisible(el, false); } private boolean isVisible1(ElementStub el) throws ExecutionException { return "true".equals(fetch("_sahi._isVisible(" + el + ")")); } /** * Returns true if the element is visible on the browser<br/> * Retries a few times if optimistic is false. Retry count can be controlled with script.max_reattempts_on_error in sahi.properties.<br/> * Use exists(el, true) to return in a single try. * * @param elementStub * @param optimistic boolean. If true returns in a single try. If false, retries a few times. * @return */ public boolean isVisible(ElementStub el, boolean optimistic) throws ExecutionException { if (optimistic) return isVisible1(el); else { for (int i = 0; i < Configuration.getMaxReAttemptsOnError(); i++) { if (isVisible1(el)) return true; } return false; } } /** * Returns the selected text visible in a select box (<select> tag) * * @param selectElement * @return */ public String getSelectedText(ElementStub el) throws ExecutionException { return fetch("_sahi._getSelectedText(" + el + ")"); } /** * Represents a popup window. * The name is either the window name or the title of the window. * * @param popupName * @return */ public Browser popup(String popupName) { return copy(popupName, this.domainName); } private Browser copy(String popupName, String domainName) { Browser newWin = new Browser(); newWin.host = host; newWin.port = port; newWin.sessionId = sessionId; newWin.popupName = popupName; newWin.domainName = domainName; return newWin; } /** * Represents a portion of the page which is from a different domain. * * @param domainName * @return */ public Browser domain(String domainName) { return copy(this.popupName, domainName); } /** * Waits till timeout milliseconds * * @param timeout in milliseconds */ public void waitFor(long timeout) { try { Thread.sleep(timeout); } catch (InterruptedException e) { e.printStackTrace(); } } /** * Waits till the condition is satisfied or till timeout * * @param condition BrowserCondition * @param timeout in milliseconds * <p/> * <blockquote> * BrowserCondition condition = new BrowserCondition(browser){@Override * public boolean test() throws ExecutionException { * return "populated".equals(browser.textbox("t1").value()); * }}; * browser.waitFor(condition, 5000); * </blockquote> * <p/> * The above code will make the browser wait till the textbox's value becomes "populated". * If it does not become "populated", the browser will wait for max 5000 ms * before moving to the next step */ public void waitFor(BrowserCondition condition, int timeout) { int total = 0; int interval = 500; while (total < timeout) { waitFor(interval); total += interval; try { if (condition.test()) return; } catch (ExecutionException e) { } } return; } /** * Chooses the given option in a select box (<select> tag). * * @param selectElement * @param value * @param append: if true, option is selected without unselecting previous option in multi-select box * @throws ExecutionException */ public void choose(ElementStub elementStub, String value, boolean append) throws ExecutionException { execute("_sahi._setSelected(" + elementStub + ", " + quoted(value) + ", " + append + ")"); } /** * Chooses the given options in a multi select box (<select> tag). * * @param selectElement * @param values * @param append: if true, options are selected without unselecting previous options in multi-select box * @throws ExecutionException */ public void choose(ElementStub elementStub, String[] values, boolean append) throws ExecutionException { execute("_sahi._setSelected(" + elementStub + ", " + Utils.toJSON(values) + ", " + append + ")"); } /** * Starts recording. * It tells the browser to record events and post the steps * which will be available via getRecordedSteps() */ public void startRecording() { execCommand("startRecording"); } /** * Stops recording. * Tells the browser to stop monitoring events. */ public void stopRecording() { execCommand("stopRecording"); } /** * Gets the recorded steps from the last time getRecordedSteps() was called. * * @return String array of recorded steps */ public String[] getRecordedSteps() { return execCommand("getRecordedSteps").split("__xxSAHIDIVIDERxx__"); } /** * Returns the last alert message from browser<br/> * Alert messages are generated via window.alert(message) in javascript. * * @return String the last alerted message * @throws ExecutionException */ public String lastAlert() throws ExecutionException { return new ElementStub("lastAlert", this).fetch(); } /** * Returns the last confirm message from browser<br/> * Confirm messages are generated via window.confirm(message) in javascript. * * @return String the last confirm message * @throws ExecutionException */ public String lastConfirm() throws ExecutionException { return new ElementStub("lastConfirm", this).fetch(); } /** * Sets the input value of a prompt dialog with given message.<br/> * This needs to be set before a prompt is expected.<br/> * Prompts are generated in javascript via window.prompt(message) * * @param message String visible message prompted by the browser * @param input String input to enter in the prompt dialog * @throws ExecutionException */ public void expectPrompt(String message, String input) throws ExecutionException { execute("_sahi._expectPrompt(" + quoted(message) + ", " + quoted(input) + ")"); } /** * Sets the input value of a confirm dialog with given message.<br/> * This needs to be set before a confirm is expected.<br/> * Prompts are generated in javascript via window.confirm(message) * * @param message String visible message prompted by the browser * @param input boolean true to click on 'OK', false to click on 'Cancel' * @throws ExecutionException */ public void expectConfirm(String message, boolean input) throws ExecutionException { execute("_sahi._expectConfirm(" + quoted(message) + ", " + input + ")"); } /** * Returns the last prompt message from browser<br/> * Alert messages are generated via window.prompt(message) in javascript. * Use expectPrompt to set value to prompt. * * @return String the last prompt message * @throws ExecutionException */ public String lastPrompt() throws ExecutionException { return new ElementStub("lastPrompt", this).fetch(); } /** * Clears the lastAlert message * * @throws ExecutionException */ public void clearLastAlert() throws ExecutionException { execute("_sahi._clearLastAlert()"); } /** * Clears the lastPrompt message * * @throws ExecutionException */ public void clearLastPrompt() throws ExecutionException { execute("_sahi._clearLastPrompt()"); } /** * Clears the lastConfirm message * * @throws ExecutionException */ public void clearLastConfirm() throws ExecutionException { execute("_sahi._clearLastConfirm()"); } public String title() throws ExecutionException { return fetch("_sahi._title()"); } private String quoted(String s) { return "\"" + Utils.escapeDoubleQuotesAndBackSlashes(s).replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r") + "\""; } /** * Returns true if the element is checked. Is meaningful only for radio buttons and checkboxes<br/> * * @param el * @return * @throws ExecutionException */ public boolean checked(ElementStub el) throws ExecutionException { return "true".equals(fetch(el + ".checked")); } /** * Force Sahi to return a canned response for specific URL patterns * The response is found in sahi/htdocs/spr/simpleMock.htm and can be modified * * @param urlPattern a javascript regular expression as a string */ public void addURLMock(String urlPattern) { execute("_sahi._addMock(" + quoted(urlPattern) + ")"); } /** * Force Sahi to return a dynamic response returned by responseClass.methodName * * @param urlPattern a javascript regular expression as a string * @param responseClass_method The class which will respond to matching requests */ public void addURLMock(String urlPattern, String responseClass_method) { execute("_sahi._addMock(" + quoted(urlPattern) + ", " + quoted(responseClass_method) + ")"); } /** * Removes any mocks associated with given pattern * * @param urlPattern */ public void removeURLMock(String urlPattern) { execute("_sahi._removeMock(" + quoted(urlPattern) + ")"); } /** * Sahi automatically downloads files into sahi/userdata/temp/download directory.<br/> * If a file was downloaded as a result of a click, its fileName will be accessible for assertion * * @return fileName of last downloaded file */ public String lastDownloadedFileName() { return new ElementStub("lastDownloadedFileName", this).fetch(); } /** * Resets the lastDownloadedFileName to null */ public void clearLastDownloadedFileName() { execute("_sahi._clearLastDownloadedFileName()"); } /** * Saves the last downloaded file to required location.<br/> * Can be used to save file to some location and then verify contents by reading it. * * @param newFilePath */ public void saveDownloadedAs(String newFilePath) { execute("_sahi._saveDownloadedAs(" + quoted(newFilePath) + ")"); } /** * Sets the speed of playback.<br/> * Some applications do not trigger AJAX requests on response to events, but use a small delay before execution.<br/> * It is useful to tweak this parameter (eg. increase to 200 milliseconds) * The default is picked from "script.time_between_steps" in userdata.properties (or sahi.properties) * * @param interval time in milliseconds */ public void setSpeed(int interval) { execCommand("setSpeed", new QueryStringBuilder().add("speed", "" + interval)); } /** * Sets strict visibility check.<br/> * If true, Sahi APIs will ignore hidden elements.<br/> * Useful when similar widgets are generated but only one widget is displayed at any time <br/> * <p/> * Can set to true globally from sahi.properties/userdata.properties by setting <br/> * element.visibility_check.strict=true<br/> * * @param boolean */ public void setStrictVisibilityCheck(boolean check) { execute("_sahi._setStrictVisibilityCheck(" + check + ")"); } /** * Returns true if the element contains the input text * * @param el * @param text * @return true if the element contains the input text */ public boolean containsText(ElementStub el, String text) { return "true".equals(fetch("_sahi._containsText(" + el + ", " + (quoted(text)) + ")")); } // private String quoteIfString(String text) { // return isRegExp(text) ? text : quoted(text); // } // // private boolean isRegExp(String text) { // return text.charAt(0) == '/' && text.charAt(text.length()-1) == '/'; // } /** * Returns true if the element's innerHTML contains the input html * * @param el * @param html * @return true if the element's innerHTML contains the input html */ public boolean containsHTML(ElementStub el, String html) { return "true".equals(fetch("_sahi._containsHTML(" + el + ", " + quoted(html) + ")")); } /** * Returns the computed css style <br/> * * @param el * @param attribute * @return the computed css style */ public String style(ElementStub el, String attribute) { return fetch("_sahi._style(" + el + ", " + quoted(attribute) + ")"); } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public String sessionId() { return sessionId; } /** * Sets the value in a Rich Text Editor (RTE) * * @param rte * @param value * @throws ExecutionException */ public void rteWrite(ElementStub rte, String value) { execute("_sahi._rteWrite(" + rte + ", " + quoted(value) + ")"); } /** * Allows given javascript to be injected into the browser.<br/> * Custom functions or stubbed functions can be passed through this <br/> * The given javascript will be available to every web page in this session <br/> * Equivalent to adding <browser> blocks in Sahi Script <br/> * <br/> * Eg.<br/> * <code> * browser.setBrowserJS("function myFinderFn(i){return document.links[i];}");<br/> * // The above code defines a function myFinderFn, which will be available on each page of the application.<br/> * <p/> * browser.setBrowserJS("function checkFileFieldIsPopulated(){return true}");<br/> * // The above code will redefine checkFileFieldIsPopulated function so that it will always return true<br/> * </code> * * @param browserJS */ public void setBrowserJS(String browserJS) { QueryStringBuilder qs = new QueryStringBuilder(); qs.add("browserJS", browserJS); execCommand("setBrowserJS", qs); } /** * Checks for Google Chrome browser * * @return */ public boolean isChrome() { return "true".equals(fetch("_sahi._isChrome()")); } /** * Checks for Firefox browser * * @return */ public boolean isFirefox() { return "true".equals(fetch("_sahi._isFF()")); } /** * Checks for Firefox browser * * @return */ public boolean isFF() { return "true".equals(fetch("_sahi._isFF()")); } /** * Checks for Internet Explorer browser * * @return */ public boolean isIE() { return "true".equals(fetch("_sahi._isIE()")); } /** * Checks for Safari browser * * @return */ public boolean isSafari() { return "true".equals(fetch("_sahi._isSafari()")); } /** * Checks for Opera browser * * @return */ public boolean isOpera() { return "true".equals(fetch("_sahi._isOpera()")); } /** * Returns a count of all matching elements <br/><br/> * <p/> * Eg.<br/> * <p/> * <pre> * browser.count("div", "css-class-name") * </pre> * * @param args * @return count of elements matching criteria */ public int count(Object... args) { final String countStr = new ElementStub("count", this, args).fetch(); return Integer.parseInt(countStr); } public void keyDown(ElementStub element, int keyCode, int charCode) { execute("_sahi._keyDown(" + element + ", [" + keyCode + ", " + charCode + "])"); } public void keyUp(ElementStub element, int keyCode, int charCode) { execute("_sahi._keyUp(" + element + ", [" + keyCode + ", " + charCode + "])"); } /** * Clears the window print statement i.e. resets the value of _printCalled * * @return */ public String clearPrintCalled() { return fetch("_sahi._clearPrintCalled()"); } /** * Returns true if window print statement was executed * * @return */ public Boolean printCalled() { String fetched = fetch("_sahi._printCalled()"); if ("true".equals(fetched)) { return true; } else return false; } } class QueryStringBuilder { Map<String, String> map = new LinkedHashMap<String, String>(); public QueryStringBuilder add(String key, String value) { map.put(key, value); return this; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("?"); boolean start = true; Set<String> keySet = map.keySet(); for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext(); ) { if (!start) sb.append("&"); start = false; String key = iterator.next(); String value = map.get(key); sb.append(key); sb.append("="); try { value = URLEncoder.encode(value, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } sb.append(value); } return sb.toString(); } }