org.assertj.swing.fixture.AbstractComponentFixture Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of assertj-swing Show documentation
Show all versions of assertj-swing Show documentation
Fluent interface for functional GUI testing
/**
* 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.
*
* Copyright 2012-2015 the original author or authors.
*/
package org.assertj.swing.fixture;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.swing.driver.ComponentDriver.propertyName;
import static org.assertj.swing.format.Formatting.format;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.assertj.swing.core.KeyPressInfo;
import org.assertj.swing.core.MouseButton;
import org.assertj.swing.core.MouseClickInfo;
import org.assertj.swing.core.Robot;
import org.assertj.swing.driver.ComponentDriver;
import org.assertj.swing.query.ComponentEnabledQuery;
import org.assertj.swing.timing.Timeout;
/**
* Supports functional testing of AWT and Swing {@code Component}s.
*
* @param used to simulate "self types." For more information please read "Emulating 'self types' using Java Generics to simplify fluent API implementation."
* @param the type of {@code Component} that this fixture can manage.
* @param the type of {@link ComponentDriver} that this fixture uses internally.
*
* @author Alex Ruiz
* @author Yvonne Wang
*/
public abstract class AbstractComponentFixture implements
MouseInputSimulationFixture {
/** Name of the property "font". */
protected static final String FONT_PROPERTY = "font";
/** Name of the property "background". */
protected static final String BACKGROUND_PROPERTY = "background";
/** Name of the property "foreground". */
protected static final String FOREGROUND_PROPERTY = "foreground";
/** Performs simulation of user events on {@link #target} */
private final Robot robot;
private final C target;
private final S myself;
private D driver;
/**
* Creates a new {@link AbstractComponentFixture}.
*
* @param selfType the "self type."
* @param robot performs simulation of user events on a {@code Component}.
* @param type the type of the {@code Component} to find using the given {@code Robot}.
* @throws NullPointerException if {@code robot} is {@code null}.
* @throws NullPointerException if {@code type} is {@code null}.
* @throws org.assertj.swing.exception.ComponentLookupException if a matching component could not be found.
* @throws org.assertj.swing.exception.ComponentLookupException if more than one matching component is found.
*/
public AbstractComponentFixture(@Nonnull Class selfType, @Nonnull Robot robot, @Nonnull Class extends C> type) {
this(selfType, robot, findTarget(robot, type));
}
private static @Nonnull C findTarget(@Nonnull Robot robot, @Nonnull Class extends C> type) {
checkNotNull(robot);
checkNotNull(type);
return robot.finder().findByType(type, requireShowing(robot));
}
/**
* Creates a new {@link AbstractComponentFixture}.
*
* @param selfType the "self type."
* @param robot performs simulation of user events on a {@code Component}.
* @param name the name of the {@code Component} to find using the given {@code Robot}.
* @param type the type of the {@code Component} to find using the given {@code Robot}.
* @throws NullPointerException if {@code robot} is {@code null}.
* @throws NullPointerException if {@code type} is {@code null}.
* @throws org.assertj.swing.exception.ComponentLookupException if a matching component could not be found.
* @throws org.assertj.swing.exception.ComponentLookupException if more than one matching component is found.
*/
public AbstractComponentFixture(@Nonnull Class selfType, @Nonnull Robot robot, @Nullable String name,
@Nonnull Class extends C> type) {
this(selfType, robot, findTarget(robot, name, type));
}
private static @Nonnull C findTarget(@Nonnull Robot robot, @Nullable String name,
@Nonnull Class extends C> type) {
checkNotNull(robot);
checkNotNull(type);
return robot.finder().findByName(name, type, requireShowing(robot));
}
/**
* Creates a new {@link AbstractComponentFixture}.
*
* @param selfType the "self type."
* @param robot performs simulation of user events on the given {@code Component}.
* @param target the {@code Component} to be managed by this fixture.
* @throws NullPointerException if {@code selfType} is {@code null}.
* @throws NullPointerException if {@code robot} is {@code null}.
* @throws NullPointerException if {@code target} is {@code null}.
*/
public AbstractComponentFixture(@Nonnull Class selfType, @Nonnull Robot robot, @Nonnull C target) {
myself = checkNotNull(selfType).cast(this);
this.robot = checkNotNull(robot);
this.target = checkNotNull(target);
replaceDriverWith(createDriver(robot));
}
protected abstract @Nonnull D createDriver(@Nonnull Robot robot);
protected final @Nonnull D driver() {
return driver;
}
public final void replaceDriverWith(@Nonnull D driver) {
this.driver = checkNotNull(driver);
}
/**
* Simulates a user clicking this fixture's {@code Component}.
*
* @return this fixture.
* @throws IllegalStateException if {@link Settings#clickOnDisabledComponentsAllowed()} is false
and this
* fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
*/
@Override
public final @Nonnull S click() {
driver.click(target());
return myself();
}
/**
* Simulates a user clicking this fixture's {@code Component}.
*
* @param button the button to click.
* @return this fixture.
* @throws NullPointerException if the given {@code MouseButton} is {@code null}.
* @throws IllegalStateException if {@link Settings#clickOnDisabledComponentsAllowed()} is false
and this
* fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
*/
@Override
public final @Nonnull S click(@Nonnull MouseButton button) {
driver.click(target(), button);
return myself();
}
/**
* Simulates a user clicking this fixture's {@code Component}.
*
* @param mouseClickInfo specifies the button to click and the times the button should be clicked.
* @return this fixture.
* @throws NullPointerException if the given {@code MouseClickInfo} is {@code null}.
* @throws IllegalStateException if {@link Settings#clickOnDisabledComponentsAllowed()} is false
and this
* fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
*/
@Override
public final @Nonnull S click(@Nonnull MouseClickInfo mouseClickInfo) {
driver.click(target(), mouseClickInfo);
return myself();
}
/**
* Simulates a user double-clicking this fixture's {@code Component}.
*
* @return this fixture.
* @throws IllegalStateException if {@link Settings#clickOnDisabledComponentsAllowed()} is false
and this
* fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
*/
@Override
public final @Nonnull S doubleClick() {
driver.doubleClick(target());
return myself();
}
/**
* Simulates a user right-clicking this fixture's {@code Component}.
*
* @return this fixture.
* @throws IllegalStateException if {@link Settings#clickOnDisabledComponentsAllowed()} is false
and this
* fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
*/
@Override
public final @Nonnull S rightClick() {
driver.rightClick(target());
return myself();
}
/**
* Gives input focus to this fixture's {@code Component}.
*
* @return this fixture.
* @throws IllegalStateException if this fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
*/
public final @Nonnull S focus() {
driver.focus(target());
return myself();
}
/**
* Simulates a user pressing given key with the given modifiers on this fixture's {@code Component}. Modifiers is a
* mask from the available AWT {@code InputEvent} masks.
*
* @param keyPressInfo specifies the key and modifiers to press.
* @return this fixture.
* @throws NullPointerException if the given {@code KeyPressInfo} is {@code null}.
* @throws IllegalArgumentException if the given code is not a valid key code.
* @throws IllegalStateException if this fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
* @see KeyPressInfo
*/
public final @Nonnull S pressAndReleaseKey(@Nonnull KeyPressInfo keyPressInfo) {
driver.pressAndReleaseKey(target(), keyPressInfo);
return myself();
}
/**
* Simulates a user pressing and releasing the given keys on this fixture's {@code Component}.
*
* @param keyCodes one or more codes of the keys to press.
* @return this fixture.
* @throws NullPointerException if the given array of codes is {@code null}.
* @throws IllegalArgumentException if any of the given code is not a valid key code.
* @throws IllegalStateException if this fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
* @see java.awt.event.KeyEvent
*/
public final @Nonnull S pressAndReleaseKeys(@Nonnull int... keyCodes) {
driver.pressAndReleaseKeys(target(), keyCodes);
return myself();
}
/**
* Simulates a user pressing the given key on this fixture's {@code Component}.
*
* @param keyCode the code of the key to press.
* @return this fixture.
* @throws IllegalArgumentException if any of the given code is not a valid key code.
* @throws IllegalStateException if this fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
* @see #pressKeyWhileRunning(int, Runnable)
* @see java.awt.event.KeyEvent
*/
public final @Nonnull S pressKey(int keyCode) {
driver.pressKey(target(), keyCode);
return myself();
}
/**
* Simulates a user pressing the given key on this fixture's {@code Component}, running the given runnable and
* releasing the key again.
*
* @param keyCode the code of the key to press.
* @return this fixture.
* @throws IllegalArgumentException if any of the given code is not a valid key code.
* @throws IllegalStateException if this fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
* @see #pressKey(int)
* @see java.awt.event.KeyEvent
*/
public final @Nonnull S pressKeyWhileRunning(int keyCode, @Nonnull Runnable runnable) {
driver.pressKeyWhileRunning(target(), keyCode, runnable);
return myself();
}
/**
* Simulates a user releasing the given key on this fixture's {@code Component}.
*
* @param keyCode the code of the key to release.
* @return this fixture.
* @throws IllegalArgumentException if any of the given code is not a valid key code.
* @throws IllegalStateException if this fixture's {@code Component} is disabled.
* @throws IllegalStateException if this fixture's {@code Component} is not showing on the screen.
* @see java.awt.event.KeyEvent
*/
public final @Nonnull S releaseKey(int keyCode) {
driver.releaseKey(target(), keyCode);
return myself();
}
/**
* Asserts that this fixture's {@code Component} has input focus.
*
* @return this fixture.
* @throws AssertionError if this fixture's {@code Component} does not have input focus.
*/
public final @Nonnull S requireFocused() {
driver.requireFocused(target());
return myself();
}
/**
* Asserts that this fixture's {@code Component} is enabled.
*
* @return this fixture.
* @throws AssertionError if this fixture's {@code Component} is disabled.
*/
public final @Nonnull S requireEnabled() {
driver.requireEnabled(target());
return myself();
}
/**
* Asserts that this fixture's {@code Component} is enabled.
*
* @param timeout the time this fixture will wait for the component to be enabled.
* @return this fixture.
* @throws org.assertj.swing.exception.WaitTimedOutError if this fixture's {@code Component} is never enabled.
*/
public final @Nonnull S requireEnabled(@Nonnull Timeout timeout) {
driver.requireEnabled(target(), timeout);
return myself();
}
/**
* Asserts that this fixture's {@code Component} is disabled.
*
* @return this fixture.
* @throws AssertionError if this fixture's {@code Component} is enabled.
*/
public final @Nonnull S requireDisabled() {
driver.requireDisabled(target());
return myself();
}
/**
* Asserts that this fixture's {@code Component} is visible.
*
* @return this fixture.
* @throws AssertionError if this fixture's {@code Component} is not visible.
*/
public final @Nonnull S requireVisible() {
driver.requireVisible(target());
return myself();
}
/**
* Asserts that this fixture's {@code Component} is not visible.
*
* @return this fixture.
* @throws AssertionError if this fixture's {@code Component} is visible.
*/
public final @Nonnull S requireNotVisible() {
driver.requireNotVisible(target());
return myself();
}
/**
* Returns whether showing components are the only ones participating in a component lookup. The returned value is
* obtained from the {@link org.assertj.swing.core.Settings#componentLookupScope() component lookup scope} stored in
* this fixture's {@link Robot}.
*
* @return {@code true} if only showing components can participate in a component lookup, {@code false} otherwise.
*/
protected boolean requireShowing() {
return requireShowing(robot());
}
private static boolean requireShowing(@Nonnull Robot robot) {
return robot.settings().componentLookupScope().requireShowing();
}
/**
* @return a fixture that checks properties of the font of this fixture's {@code Component}.
*/
public final @Nonnull FontFixture font() {
Font font = driver.fontOf(target);
return new FontFixture(font, propertyName(target(), FONT_PROPERTY));
}
/**
* @return a fixture that checks properties of the background color of this fixture's {@code Component}.
*/
public final @Nonnull ColorFixture background() {
Color background = driver.backgroundOf(target);
return new ColorFixture(background, propertyName(target(), BACKGROUND_PROPERTY));
}
/**
* @return a fixture that checks properties of the foreground color of this fixture's {@code Component}.
*/
public final @Nonnull ColorFixture foreground() {
Color foreground = driver.foregroundOf(target);
return new ColorFixture(foreground, propertyName(target(), FOREGROUND_PROPERTY));
}
/**
* Indicates whether this fixture's {@code Component} is enabled.
*
* @return {@code true} if this fixture's {@code Component} is enabled; {@code false} otherwise.
*/
public final boolean isEnabled() {
return ComponentEnabledQuery.isEnabled(target());
}
/**
* Returns this fixture's {@code Component} casted to the given sub-type.
*
* @param the type that the managed {@code Component} will be casted to.
* @param type the class for the type of component.
* @return this fixture's {@code Component} casted to the given sub-type.
* @throws AssertionError if this fixture's {@code Component} is not an instance of the given type.
*/
public final @Nonnull T targetCastedTo(@Nonnull Class type) {
assertThat(target).as(format(target)).isInstanceOf(type);
return type.cast(target);
}
/**
*
* Returns the GUI component in this fixture.
*
*
* Note: Access to the GUI component returned by this method must be executed in the event
* dispatch thread (EDT). To do so, please execute a {@link org.assertj.swing.edt.GuiQuery GuiQuery} or
* {@link org.assertj.swing.edt.GuiTask GuiTask} (depending on what you need to do), inside a
* {@link org.assertj.swing.edt.GuiActionRunner}. To learn more about Swing threading, please read the Swing
* Threading Policy.
*
*
* @return the GUI component in this fixture.
*/
public final @Nonnull C target() {
return target;
}
/** @return the {@link Robot} that simulates user events on {@link #target()}. */
protected final @Nonnull Robot robot() {
return robot;
}
/**
* @return {@code this} casted to the "self type".
*/
protected final @Nonnull S myself() {
return myself;
}
}