├── .gitignore ├── src └── test │ └── java │ └── selenium │ ├── SearchPage.java │ ├── step2 │ ├── elements │ │ ├── Element.java │ │ ├── Button.java │ │ ├── TextField.java │ │ └── impl │ │ │ ├── ButtonImpl.java │ │ │ ├── AbstractElement.java │ │ │ ├── TextFieldImpl.java │ │ │ └── DefaultElementFactory.java │ ├── ElementFactory.java │ ├── ExtendedSearchPage.java │ └── ExtendedFieldDecorator.java │ ├── Page.java │ ├── step3 │ ├── Container.java │ ├── ContainerFactory.java │ ├── AbstractContainer.java │ ├── SearchForm.java │ ├── SearchPageWithSearchForm.java │ └── DefaultContainerFactory.java │ ├── initial │ └── SimpleSearchPage.java │ ├── step1 │ └── AnnotatedSearchPage.java │ └── SearchTest.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.ipr 2 | *.iws 3 | *.iml 4 | .idea/ 5 | target/ -------------------------------------------------------------------------------- /src/test/java/selenium/SearchPage.java: -------------------------------------------------------------------------------- 1 | package selenium; 2 | 3 | public interface SearchPage extends Page { 4 | void search(String query); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/Element.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements; 2 | 3 | public interface Element { 4 | boolean isDisplayed(); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/Button.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements; 2 | 3 | public interface Button extends Element { 4 | void click(); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/selenium/Page.java: -------------------------------------------------------------------------------- 1 | package selenium; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | 5 | public interface Page { 6 | void init(WebDriver driver); 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/TextField.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements; 2 | 3 | public interface TextField extends Element { 4 | void type(String text); 5 | 6 | void clear(); 7 | 8 | void clearAndType(String text); 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/selenium/step3/Container.java: -------------------------------------------------------------------------------- 1 | package selenium.step3; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import selenium.step2.elements.Element; 5 | 6 | public interface Container extends Element { 7 | void init(WebElement wrappedElement); 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/selenium/step3/ContainerFactory.java: -------------------------------------------------------------------------------- 1 | package selenium.step3; 2 | 3 | import org.openqa.selenium.WebElement; 4 | 5 | public interface ContainerFactory { 6 | C create(Class containerClass, WebElement wrappedElement); 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/ElementFactory.java: -------------------------------------------------------------------------------- 1 | package selenium.step2; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import selenium.step2.elements.Element; 5 | 6 | public interface ElementFactory { 7 | E create(Class elementClass, WebElement wrappedElement); 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/impl/ButtonImpl.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements.impl; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import selenium.step2.elements.Button; 5 | 6 | class ButtonImpl extends AbstractElement implements Button { 7 | protected ButtonImpl(final WebElement wrappedElement) { 8 | super(wrappedElement); 9 | } 10 | 11 | @Override 12 | public void click() { 13 | wrappedElement.click(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/selenium/step3/AbstractContainer.java: -------------------------------------------------------------------------------- 1 | package selenium.step3; 2 | 3 | import org.openqa.selenium.WebElement; 4 | 5 | public abstract class AbstractContainer implements Container { 6 | private WebElement wrappedElement; 7 | 8 | @Override 9 | public final void init(final WebElement wrappedElement) { 10 | this.wrappedElement = wrappedElement; 11 | } 12 | 13 | @Override 14 | public boolean isDisplayed() { 15 | return wrappedElement.isDisplayed(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/impl/AbstractElement.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements.impl; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import selenium.step2.elements.Element; 5 | 6 | abstract class AbstractElement implements Element { 7 | protected final WebElement wrappedElement; 8 | 9 | protected AbstractElement(final WebElement wrappedElement) { 10 | this.wrappedElement = wrappedElement; 11 | } 12 | 13 | @Override 14 | public boolean isDisplayed() { 15 | return wrappedElement.isDisplayed(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/selenium/step3/SearchForm.java: -------------------------------------------------------------------------------- 1 | package selenium.step3; 2 | 3 | import org.openqa.selenium.support.FindBy; 4 | import selenium.step2.elements.Button; 5 | import selenium.step2.elements.TextField; 6 | 7 | public class SearchForm extends AbstractContainer { 8 | @FindBy(id = "text") 9 | private TextField searchField; 10 | 11 | @FindBy(css = "input[type=\"submit\"]") 12 | private Button searchButton; 13 | 14 | public void search(final String query) { 15 | searchField.clearAndType(query); 16 | searchButton.click(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/selenium/initial/SimpleSearchPage.java: -------------------------------------------------------------------------------- 1 | package selenium.initial; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | import selenium.SearchPage; 6 | 7 | public class SimpleSearchPage implements SearchPage { 8 | private WebDriver driver; 9 | 10 | @Override 11 | public void search(final String query) { 12 | driver.findElement(By.id("text")).sendKeys(query); 13 | driver.findElement(By.cssSelector("input[type=\"submit\"]")).click(); 14 | } 15 | 16 | @Override 17 | public void init(final WebDriver driver) { 18 | this.driver = driver; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/selenium/step3/SearchPageWithSearchForm.java: -------------------------------------------------------------------------------- 1 | package selenium.step3; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.support.FindBy; 5 | import org.openqa.selenium.support.PageFactory; 6 | import selenium.SearchPage; 7 | import selenium.step2.ExtendedFieldDecorator; 8 | 9 | public class SearchPageWithSearchForm implements SearchPage { 10 | @FindBy(tagName = "form") 11 | private SearchForm searchForm; 12 | 13 | @Override 14 | public void search(final String query) { 15 | searchForm.search(query); 16 | } 17 | 18 | @Override 19 | public void init(final WebDriver driver) { 20 | PageFactory.initElements(new ExtendedFieldDecorator(driver), this); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/impl/TextFieldImpl.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements.impl; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import selenium.step2.elements.TextField; 5 | 6 | class TextFieldImpl extends AbstractElement implements TextField { 7 | protected TextFieldImpl(final WebElement wrappedElement) { 8 | super(wrappedElement); 9 | } 10 | 11 | @Override 12 | public void type(final String text) { 13 | wrappedElement.sendKeys(text); 14 | } 15 | 16 | @Override 17 | public void clear() { 18 | wrappedElement.clear(); 19 | } 20 | 21 | @Override 22 | public void clearAndType(final String text) { 23 | clear(); 24 | type(text); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/selenium/step3/DefaultContainerFactory.java: -------------------------------------------------------------------------------- 1 | package selenium.step3; 2 | 3 | import org.openqa.selenium.WebElement; 4 | 5 | public class DefaultContainerFactory implements ContainerFactory { 6 | @Override 7 | public C create(final Class containerClass, final WebElement wrappedElement) { 8 | final C container = createInstanceOf(containerClass); 9 | container.init(wrappedElement); 10 | return container; 11 | } 12 | 13 | private C createInstanceOf(final Class containerClass) { 14 | try { 15 | return containerClass.newInstance(); 16 | } catch (InstantiationException e) { 17 | throw new RuntimeException(e); 18 | } catch (IllegalAccessException e) { 19 | throw new RuntimeException(e); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/ExtendedSearchPage.java: -------------------------------------------------------------------------------- 1 | package selenium.step2; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.support.FindBy; 5 | import org.openqa.selenium.support.PageFactory; 6 | import selenium.SearchPage; 7 | import selenium.step2.elements.Button; 8 | import selenium.step2.elements.TextField; 9 | 10 | public class ExtendedSearchPage implements SearchPage { 11 | @FindBy(id = "text") 12 | private TextField searchField; 13 | 14 | @FindBy(css = "input[type=\"submit\"]") 15 | private Button searchButton; 16 | 17 | @Override 18 | public void search(final String query) { 19 | searchField.clearAndType(query); 20 | searchButton.click(); 21 | } 22 | 23 | @Override 24 | public void init(final WebDriver driver) { 25 | PageFactory.initElements(new ExtendedFieldDecorator(driver), this); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/selenium/step1/AnnotatedSearchPage.java: -------------------------------------------------------------------------------- 1 | package selenium.step1; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.CacheLookup; 6 | import org.openqa.selenium.support.FindBy; 7 | import org.openqa.selenium.support.PageFactory; 8 | import selenium.SearchPage; 9 | 10 | public class AnnotatedSearchPage implements SearchPage { 11 | @FindBy(id = "text") 12 | private WebElement searchField; 13 | 14 | @FindBy(css = "input[type=\"submit\"]") 15 | @CacheLookup 16 | private WebElement searchButton; 17 | 18 | @Override 19 | public void search(final String query) { 20 | searchField.sendKeys(query); 21 | searchButton.click(); 22 | } 23 | 24 | @Override 25 | public void init(final WebDriver driver) { 26 | PageFactory.initElements(driver, this); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/selenium/SearchTest.java: -------------------------------------------------------------------------------- 1 | package selenium; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.openqa.selenium.firefox.FirefoxProfile; 6 | import org.testng.annotations.AfterClass; 7 | import org.testng.annotations.BeforeClass; 8 | import org.testng.annotations.DataProvider; 9 | import org.testng.annotations.Test; 10 | import selenium.initial.SimpleSearchPage; 11 | import selenium.step1.AnnotatedSearchPage; 12 | import selenium.step2.ExtendedSearchPage; 13 | import selenium.step3.SearchPageWithSearchForm; 14 | 15 | public class SearchTest { 16 | @Test(dataProvider = "pageObjects") 17 | public void testSearch(final SearchPage searchPage) { 18 | searchPage.init(driver); 19 | driver.get("http://ya.ru"); 20 | searchPage.search("Bolek i Lolek"); 21 | } 22 | 23 | @DataProvider 24 | private Object[][] pageObjects() { 25 | return new Object[][]{ 26 | {new SimpleSearchPage()}, 27 | {new AnnotatedSearchPage()}, 28 | {new ExtendedSearchPage()}, 29 | {new SearchPageWithSearchForm()} 30 | }; 31 | } 32 | 33 | private WebDriver driver; 34 | 35 | @BeforeClass 36 | public void beforeClass() { 37 | driver = new FirefoxDriver(); 38 | } 39 | 40 | @AfterClass 41 | public void afterClass() { 42 | driver.quit(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/elements/impl/DefaultElementFactory.java: -------------------------------------------------------------------------------- 1 | package selenium.step2.elements.impl; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import selenium.step2.ElementFactory; 5 | import selenium.step2.elements.Button; 6 | import selenium.step2.elements.Element; 7 | import selenium.step2.elements.TextField; 8 | 9 | import java.lang.reflect.InvocationTargetException; 10 | 11 | import static java.text.MessageFormat.format; 12 | 13 | public class DefaultElementFactory implements ElementFactory { 14 | @Override 15 | public E create(final Class elementClass, final WebElement wrappedElement) { 16 | try { 17 | return findImplementationFor(elementClass) 18 | .getDeclaredConstructor(WebElement.class) 19 | .newInstance(wrappedElement); 20 | } catch (InstantiationException e) { 21 | throw new RuntimeException(e); 22 | } catch (IllegalAccessException e) { 23 | throw new RuntimeException(e); 24 | } catch (InvocationTargetException e) { 25 | throw new RuntimeException(e); 26 | } catch (NoSuchMethodException e) { 27 | throw new RuntimeException(e); 28 | } 29 | } 30 | 31 | private Class findImplementationFor(final Class elementClass) { 32 | try { 33 | return (Class) Class.forName(format("{0}.{1}Impl", getClass().getPackage().getName(), elementClass.getSimpleName())); 34 | } catch (ClassNotFoundException e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/test/java/selenium/step2/ExtendedFieldDecorator.java: -------------------------------------------------------------------------------- 1 | package selenium.step2; 2 | 3 | import org.openqa.selenium.SearchContext; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.PageFactory; 6 | import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; 7 | import org.openqa.selenium.support.pagefactory.DefaultFieldDecorator; 8 | import org.openqa.selenium.support.pagefactory.ElementLocator; 9 | import selenium.step2.elements.Element; 10 | import selenium.step2.elements.impl.DefaultElementFactory; 11 | import selenium.step3.Container; 12 | import selenium.step3.ContainerFactory; 13 | import selenium.step3.DefaultContainerFactory; 14 | 15 | import java.lang.reflect.Field; 16 | 17 | public class ExtendedFieldDecorator extends DefaultFieldDecorator { 18 | private ElementFactory elementFactory = new DefaultElementFactory(); 19 | private ContainerFactory containerFactory = new DefaultContainerFactory(); 20 | 21 | public ExtendedFieldDecorator(final SearchContext searchContext) { 22 | super(new DefaultElementLocatorFactory(searchContext)); 23 | } 24 | 25 | @Override 26 | public Object decorate(final ClassLoader loader, final Field field) { 27 | if (Container.class.isAssignableFrom(field.getType())) { 28 | return decorateContainer(loader, field); 29 | } 30 | if (Element.class.isAssignableFrom(field.getType())) { 31 | return decorateElement(loader, field); 32 | } 33 | return super.decorate(loader, field); 34 | } 35 | 36 | private Object decorateElement(final ClassLoader loader, final Field field) { 37 | final WebElement wrappedElement = proxyForLocator(loader, createLocator(field)); 38 | return elementFactory.create((Class) field.getType(), wrappedElement); 39 | } 40 | 41 | private ElementLocator createLocator(final Field field) { 42 | return factory.createLocator(field); 43 | } 44 | 45 | private Object decorateContainer(final ClassLoader loader, final Field field) { 46 | final WebElement wrappedElement = proxyForLocator(loader, createLocator(field)); 47 | final Container container = containerFactory.create((Class) field.getType(), wrappedElement); 48 | 49 | PageFactory.initElements(new ExtendedFieldDecorator(wrappedElement), container); 50 | return container; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | selenium_habr 8 | selenium_habr 9 | 1.0 10 | 11 | 12 | 13 | 14 | org.apache.maven.plugins 15 | maven-compiler-plugin 16 | 3.1 17 | 18 | 1.6 19 | 1.6 20 | UTF-8 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.testng 29 | testng 30 | 6.8.7 31 | test 32 | 33 | 34 | junit 35 | junit 36 | 37 | 38 | 39 | 40 | org.seleniumhq.selenium 41 | selenium-java 42 | 2.37.1 43 | test 44 | 45 | 46 | org.seleniumhq.selenium 47 | selenium-ie-driver 48 | 49 | 50 | org.seleniumhq.selenium 51 | selenium-chrome-driver 52 | 53 | 54 | org.seleniumhq.selenium 55 | selenium-htmlunit-driver 56 | 57 | 58 | org.seleniumhq.selenium 59 | selenium-safari-driver 60 | 61 | 62 | org.seleniumhq.selenium 63 | selenium-android-driver 64 | 65 | 66 | org.seleniumhq.selenium 67 | selenium-iphone-driver 68 | 69 | 70 | org.webbitserver 71 | webbit 72 | 73 | 74 | 75 | 76 | --------------------------------------------------------------------------------