/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.runtime; import com.windowtester.runtime.condition.ICondition; import com.windowtester.runtime.condition.IConditionHandler; import com.windowtester.runtime.condition.IConditionMonitor; import com.windowtester.runtime.condition.IHandler; import com.windowtester.runtime.condition.IUICondition; import com.windowtester.runtime.locator.ILocator; import com.windowtester.runtime.locator.IMenuItemLocator; import com.windowtester.runtime.locator.IWidgetLocator; import com.windowtester.runtime.locator.WidgetReference; /** * The main point of entry for interaction with the UI during test * playback. * <p> * <b>IUIContext</b> instances are used to perform actions on the User Interface. * Actions are primarily performed on <code>Widget<code>s. For example, * </p> * <pre> * IUIContext ui = getUIContext(); * IWidgetLocator widget = [a widget]; * ui.click(widget); * </pre> * <p> * causes the widget <code>widget</code> to be clicked. * <p> * More commonly, widgets are handled <em>indirectly</em> by way of widget locators. * For instance, the following snippet clicks a button labeled "OK". * </p> * <pre> * IUIContext ui = getUIContext(); * ui.click(new ButtonLocator("OK")); * </pre> * <p> * @see ILocator */ public interface IUIContext { // ///////////////////////////////////////////////////////////////////////// // // Adapter interface // // ///////////////////////////////////////////////////////////////////////// /** * Returns an object which is an instance of the given class associated with this * object. Returns <code>null</code> if no such object can be found. * * @param adapter the adapter class to look up * @return an object castable to the given class, or <code>null</code> if this * object does not have an adapter for the given class */ Object getAdapter(Class<?> adapter); // ///////////////////////////////////////////////////////////////////////// // // Click actions // // ///////////////////////////////////////////////////////////////////////// /** * Click the given component, identified by locator. * For example: * <pre> * ui.click(new MenuLocator("File/New/Project...")); * ui.click(new TreeItemLocator(new WidgetLocator(new ViewLocator("Navigator"), Tree.class), "MyProject/src/package1"))); * ui.click(new XYLocator(new WidgetLocator(Canvas.class), 2, -2)); * ui.click(new WidgetLocator(Button.class, "OK")); * </pre> * This is fully equivalent to * <pre> * ui.click(1, locator, WT.NONE); * </pre> * * @param locator the locator identifying where the click should occur * @return the clicked widget * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator click(ILocator locator) throws WidgetSearchException; /** * Click the given component, identified by locator. * This is fully equivalent to * <pre> * ui.click(clickCount, locator, WT.NONE); * </pre> * See {@link #click(ILocator)} for examples * * @param clickCount the number of times the widget should be clicked * @param locator the locator identifying where the click should occur * @return the clicked widget * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator click(int clickCount, ILocator locator) throws WidgetSearchException; /** * Click the given component, identified by locator. * See {@link #click(ILocator)} for examples * * @param clickCount the number of times the widget should be clicked * @param locator the locator identifying where the click should occur * @param modifierMask the modifier mask to use in the click (e.g. {@link WT#SHIFT}) * @return the clicked widget */ IWidgetLocator click(int clickCount, ILocator locator, int modifierMask) throws WidgetSearchException; /** * Context click the given widget and select the menu item described by this path. * For example: * <pre> * ui.contextClick( * TreeItemLocator("MyProject/src/package1", new ViewLocator("Navigator")), * new MenuLocator("New/File...")); * </pre> * This is fully equivalent to * <pre> * ui.contextClick(locator, path, WT.NONE); * </pre> * * @param locator the locator identifying where the click should occur * @param menuItem the locator identifying the menu item to be selected * @return the widget identified by the locator argument * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator contextClick(ILocator locator, IMenuItemLocator menuItem) throws WidgetSearchException; /** * Context click the given widget and select the menu item described by this path. * See {@link #contextClick(ILocator, IMenuItemLocator)} for examples. * * @param locator the locator identifying where the click should occur * @param menuItem the locator identifying the menu item to be selected * @param modifierMask the modifier mask to use in the click (e.g. {@link WT#SHIFT}) * @return the widget identified by the locator argument * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator contextClick(ILocator locator, IMenuItemLocator menuItem, int modifierMask) throws WidgetSearchException; /** * Context click the given widget and select the menu item described by this path. * For example: * <pre> * ui.contextClick( * new TreeItemLocator("MyProject/src/package1", new ViewLocator("Navigator")), * "New/File"); * </pre> * * @param locator the locator identifying where the click should occur * @param menuItem the locator identifying the menu item to be selected * @return the widget identified by the locator argument * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator contextClick(ILocator locator, String menuItem) throws WidgetSearchException; /** * Context click the given widget and select the menu item described by this String path. * * @param locator the locator identifying where the click should occur * @param menuItem the locator identifying the menu item to be selected * @param modifierMask the modifier mask to use in the click (e.g. {@link WT#SHIFT}) * @return the widget identified by the locator argument */ IWidgetLocator contextClick(ILocator locator, String menuItem, int modifierMask) throws WidgetSearchException; // ///////////////////////////////////////////////////////////////////////// // // Drag and drop actions // // ///////////////////////////////////////////////////////////////////////// /** * Move the mouse to hover over the specified location * For example: * <pre> * ui.mouseMove(new TreeItemLocator(new WidgetLocator(new ViewLocator("Navigator"), Tree.class), "MyProject/src/package1"))); * ui.mouseMove(new XYLocator(new WidgetLocator(Canvas.class), 2, -2, WT.LEFT | WT.BOTTOM)); * ui.mouseMove(new WidgetLocator(Button.class, "OK")); * </pre> * * @param locator the locator identifying where the spot over which the mouse should hover * @return the widget over which the mouse is hovering * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator mouseMove(ILocator locator) throws WidgetSearchException; /** * Perform a drag operation (starting at the current hover position of the mouse) to * the specified location and drop. * For example: * <pre> * ui.dragTo(new TreeItemLocator(new WidgetLocator(new ViewLocator("Navigator"), Tree.class), "MyProject/src/package1"))); * ui.dragTo(new XYLocator(new WidgetLocator(Canvas.class), 2, -2, WT.LEFT | WT.BOTTOM)); * </pre> * This is fully equivalent to * <pre> * ui.dragTo(locator, WT.NONE); * </pre> * * @param locator the locator identifying where the drop should occur * @return the widget where the drop occurred * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator dragTo(ILocator locator) throws WidgetSearchException; /** * Perform a drag operation (starting at the current hover position of the mouse) to * the specified location and drop. * See {@link #dragTo(ILocator)} for examples. * * @param locator the locator identifying where the drop should occur * @param modifierMask the modifier mask to use during the drag and drop * operation (e.g. {@link WT#SHIFT}) * @return the widget where the drop occurred * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found */ IWidgetLocator dragTo(ILocator locator, int modifierMask) throws WidgetSearchException; // ///////////////////////////////////////////////////////////////////////// // // Text entry actions // // ///////////////////////////////////////////////////////////////////////// /** * Enter the given text. */ void enterText(String txt); /** * Click the given key (by constant). * <p> * Composite key clicks can be specified by bitwise or-ing key constants. * For example: * * <pre> ui.keyClick(WT.CTRL | WT.HOME) </pre> * * specifies a combined key click of the <em>Control</em> and <em>Home</em> keys. */ void keyClick(int key); /** * Click the given key. */ void keyClick(char key); /** * Click the given keystroke. * * @param modifierMask the modifier mask to use in the click (e.g. {@link WT#SHIFT}) */ public void keyClick(int modifierMask, char c); // ///////////////////////////////////////////////////////////////////////// // // Meta actions // // ///////////////////////////////////////////////////////////////////////// /** * Close the specified window in the same way it would be closed when the user * clicks on the "close box" or performs some other platform specific key * or mouse combination that indicates the window should be closed. * For example: * <pre> * ui.close(new WidgetLocator(Shell.class, "My SWT Window")); * ui.close(new WidgetLocator(JFrame.class, "My Swing Window")); * </pre> * * @param locator the locator identifying window that should be closed. * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found * @deprecated prefer {@link #ensureThat(IConditionHandler)} instead */ void close(IWidgetLocator locator) throws WidgetSearchException; // /** // * Ensure that the specified widget has keyboard focus. // * For example: // * <pre> // * ui.setFocus(new LabeledWidgetLocator(Text.class, "Name:")); // * </pre> // * // * @param locator the locator identifying widget to have focus // * @return the widget that received focus // * @throws WidgetSearchException if the locator is a widget locator and the widget cannot be found // */ // IWidgetLocator setFocus(IWidgetLocator locator) throws WidgetSearchException; // ////////////////////////////////////////////////////////////////////// // // Condition-handling // // ////////////////////////////////////////////////////////////////////// /** * Assert that the given condition either is true or becomes true in a reasonable amount of time. * Some examples include: * <pre> * ui.assertThat(new IsEnabledCondition(new ButtonLocator("OK"), false)); * ui.assertThat(new HasTextCondition(new WizardErrorMessageLocator(), "File extension is missing")); * </pre> * * @param condition the condition to assert * @throws WaitTimedOutException if the default timeout (3 seconds) is exceeded. */ void assertThat(ICondition condition) throws WaitTimedOutException; /** * Assert that the given condition either is true or becomes true in a reasonable amount of time. * Some examples include: * <pre> * ui.assertThat(new IsEnabledCondition(new ButtonLocator("OK"), false)); * ui.assertThat(new HasTextCondition(new WizardErrorMessageLocator(), "File extension is missing")); * </pre> * * @param message the message displayed if the condition is not and does not become <code>true</code> * @param condition the condition to assert (not null) * @throws WaitTimedOutException if the default timeout (3 seconds) is exceeded. */ void assertThat(String message, ICondition condition) throws WaitTimedOutException; /** * Ensure that the given condition either is true or becomes true in a reasonable amount of time. If the condition * is not true within the default timeout (of 3 seconds), the condition's associated handler * ({@link IConditionHandler#handle(IUIContext)} is called. * <p/> * For example, suppose we have a condition/handler defined like this: * <pre> * class IntroPageUnzoomedCondition implements IConditionHandler { * public boolean testUI(IUIContext ui) { * ... test zoom state ... * } * public void handle(IUIContext ui) throws Exception { * ... unzoom intro ... * } * } * </pre> * * then a call like this: * * <pre> * ui.ensureThat(new IntroPageUnzoomedCondition()); * </pre> * * tests to see if the Welcome page is dismissed. If it is, the call returns immediately. If not, a {@link #wait(ICondition)} * is performed with the same timeout as assertions ({@link #assertThat(ICondition)}. If it is not dismissed in that interval, * then {@link IConditionHandler#handle(IUIContext)} is called. Finally {@link #assertThat(ICondition)} is called to ensure * the handler succeeded. * * @param conditionHandler the condition to test and handle * @throws WaitTimedOutException if the default timeout (3 seconds) is exceeded. * @throws Exception if an exception occurs during the call to {@link IHandler#handle(IUIContext)} * * @since 3.7.1 */ void ensureThat(IConditionHandler conditionHandler) throws WaitTimedOutException, Exception; /** * Wait for the given condition to evaluate to true. Some examples include: * * <pre> * ui.wait(new IdleCondition()); * ui.wait(new ShellShowingCondition("My SWT Window Title")); * ui.wait(new WindowDisposed(JFrame.class, "My Swing Window Title")); * </pre> * * This is fully equivalent to * * <pre> * ui.wait(condition, WT.DEFAULT_TIMEOUT, WT.DEFAULT_INTERVAL); * </pre> * * If this context detects that an {@link ICondition} implements {@link IUICondition}, * then {@link IConditionMonitor} calls {@link #testUI(IUIContext)} rather than * {@link ICondition#test()}. * * @param condition the condition to wait for * @throws WaitTimedOutException if the default timeout (30 seconds) is exceeded. */ void wait(ICondition condition) throws WaitTimedOutException; /** * Wait for the given Condition to return true, waiting for timeout ms. This is fully * equivalent to * * <pre> * ui.wait(condition, timeout, WT.DEFAULT_INTERVAL); * </pre> * * See {@link #wait(ICondition)} for examples. * <p> * If this context detects that an {@link ICondition} implements {@link IUICondition}, * then {@link IConditionMonitor} calls {@link #testUI(IUIContext)} rather than * {@link ICondition#test()}. * * @param condition the condition to wait for * @param timeout the number of milliseconds to wait for the condition to become true * @throws WaitTimedOutException if the timeout is exceeded. */ void wait(ICondition condition, long timeout) throws WaitTimedOutException; /** * Wait for the given Condition to return true, waiting for timeout ms, polling at the * given interval. See {@link #wait(ICondition)} for examples. * <p> * If this context detects that an {@link ICondition} implements {@link IUICondition}, * then {@link IConditionMonitor} calls {@link #testUI(IUIContext)} rather than * {@link ICondition#test()}. * * @param condition the condition to wait for * @param timeout the number of milliseconds to wait for the condition to become true * @param interval the number of milliseconds to sleep between condition checks * @throws WaitTimedOutException if the timeout is exceeded. */ void wait(ICondition condition, long timeout, int interval) throws WaitTimedOutException; /** * Check for any active conditions and handle them. If a condition is handled, * original hover context will be restored post condition handling. * * @return one of the following flags indicating what was processed: * {@link IConditionMonitor#PROCESS_NONE} if conditions were processed but no conditions were satisfied, * {@link IConditionMonitor#PROCESS_ONE_OR_MORE} if conditions were processed and at least on condition was satisfied, * {@link IConditionMonitor#PROCESS_RECURSIVE} if conditions were already being processed and no additional action was taken. */ public int handleConditions(); /** * Get this UI's {@link IConditionMonitor}. * * @return the UI's Condition Monitor * @since 3.6.2 */ public IConditionMonitor getConditionMonitor(); // ///////////////////////////////////////////////////////////////////////// // // Timing // // ///////////////////////////////////////////////////////////////////////// /** * Pause for a given number of milliseconds. * <p> * As a general rule pauses are discouraged in UI tests. Instead waiting for an * appropriate {@link ICondition} is preferred. For example, if a pause has been * inserted in order for the test to sync up with an application that is performing a * long-running operation, a condition that tests if the operation is complete should * be used instead. In eclipse, long operations are often wrapped in platform * <code>Job</code>s so the following wait is a good substitute for a pause: * <p> * <code> * ui.wait(new JobsCompleteCondition()); * </code> * </p> * In the rare case where a pause for a set period of time really is desirable, * a {@link TimeElapsedCondition} should be used instead. * * </p> * @param ms the number of milliseconds to wait * * @deprecated Use {@link #wait(ICondition)} instead. */ void pause(int ms); // ///////////////////////////////////////////////////////////////////////// // // Widget finding convenience // // ///////////////////////////////////////////////////////////////////////// /** * Find the specified widget. * <p> * If the widget locator is known to * resolve to a basic widget (such as a tree, button, tab, etc.), it is * safe to cast the returned locator to an instance of {@link WidgetReference}. * From this reference, the target widget can be obtained: * <pre> * WidgetReference ref = (WidgetReference)ui.find(myLocator); * Widget foundWidget = (Widget)ref.getWidget(); * </pre> * * * @param locator the locator specifying the widget to be found. */ IWidgetLocator find(IWidgetLocator locator) throws WidgetSearchException; /** * Find all widgets matching the specified criteria * * @param locator the locator specifying the widget to be found. * This can be an IWidgetLocator indicating which widget * or an IXYLocator specifying a point within the widget's bounds. */ IWidgetLocator[] findAll(IWidgetLocator locator); /** * Answer the current window being manipulated during playback. * * @return the window (e.g. Shell, JFrame, ...) or <code>null</code> if none. */ Object getActiveWindow(); }