diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index c5fded7..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,30 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: circleci/openjdk:8-jdk-stretch-node-browsers - - working_directory: ~/repo - - environment: - # Customize the JVM maximum heap limit - MAVEN_OPTS: -Xmx3200m - - steps: - - checkout - - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "pom.xml" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - - run: mvn dependency:go-offline - - - save_cache: - paths: - - ~/.m2 - key: v1-dependencies-{{ checksum "pom.xml" }} - - - run: mvn clean test -Dprofile=local \ No newline at end of file diff --git a/README.md b/README.md index eea226c..29bb5a0 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,6 @@ We use interfaces where is possible, so you can implement your own version of ta 1. To start work with this package, simply add the dependency to your pom.xml: ``` - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://repo1.maven.org/maven2/ - - - com.github.aquality-automation aquality-selenium @@ -39,17 +28,20 @@ Browser browser = BrowserManager.getBrowser(); ```java browser.maximize(); browser.goTo("https://wikipedia.org"); -browser.waitForPageToLoad() +browser.waitForPageToLoad(); ``` 4. Use ElementFactory class's methods to get an instance of each element. ```java -ITextBox txbEmail = new ElementFactory().getTextBox(By.id("email_create"), "Email"); +ElementFactory elementFactory = new ElementFactory(); +ITextBox txbSearch = elementFactory.getTextBox(By.id("searchInput"), "Search"); +txbSearch.submit(); +browser.waitForPageToLoad(); ``` 5. Call element's methods to perform action with element: ```java -txbEmail.type("email@domain.com"); +txbSearch.type("quality assurance"); ``` 6. Quit browser at the end @@ -57,6 +49,8 @@ txbEmail.type("email@domain.com"); browser.quit(); ``` +See full example [here](./src/test/java/tests/usecases/QuickStartExample.java) + ### Documentation To get more details please look at documentation: - [In English](./Documentation.en.md) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 23efa78..dbfb903 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,6 +10,9 @@ pool: vmImage: 'windows-latest' steps: +- task: ScreenResolutionUtility@1 + inputs: + displaySettings: 'optimal' - task: Maven@3 inputs: mavenPomFile: 'pom.xml' @@ -19,4 +22,4 @@ steps: jdkArchitectureOption: 'x64' publishJUnitResults: true testResultsFiles: '**/surefire-reports/TEST-*.xml' - goals: 'clean test' + goals: 'clean test -DdriverSettings.chrome.webDriverVersion=75.0.3770.140 -Dprofile=local' diff --git a/pom.xml b/pom.xml index edef694..b7ae786 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.aquality-automation aquality-selenium - 1.1 + 1.1.1 jar Aquality Selenium @@ -45,8 +45,24 @@ - aquality-automation - aquality-automation + DmitryBogatko + Dmitry Bogatko + + + pavelanihimovsky + Pavel Anihimovsky + + + Nikikuzi + Nikita Kuznetsov + + + mialeska + Alaksiej Mialeška + + + sunigos + Igor Sontsa @@ -147,12 +163,10 @@ 2.20 ${surefireArgLine} -Dfile.encoding=UTF-8 - methods - 10 false - - **/*Test*.java - + + src/test/resources/TestSuite.xml + diff --git a/src/main/java/aquality/selenium/elements/ElementFactory.java b/src/main/java/aquality/selenium/elements/ElementFactory.java index 000e4bf..776ce17 100644 --- a/src/main/java/aquality/selenium/elements/ElementFactory.java +++ b/src/main/java/aquality/selenium/elements/ElementFactory.java @@ -4,6 +4,7 @@ import aquality.selenium.browser.BrowserManager; import aquality.selenium.browser.JavaScript; import aquality.selenium.configuration.Configuration; +import aquality.selenium.configuration.ITimeoutConfiguration; import aquality.selenium.elements.interfaces.*; import aquality.selenium.localization.LocalizationManager; import aquality.selenium.logger.Logger; @@ -101,18 +102,21 @@ private List findElementsCore(By locator, IElementSuppl List elements = new ArrayList<>(); switch (count) { case ZERO: + ConditionalWait.waitFor(driver -> driver.findElements(locator).stream() + .noneMatch(webElement -> state == ElementState.EXISTS_IN_ANY_STATE || webElement.isDisplayed()), + String.format(LocalizationManager.getInstance().getValue("loc.elements.found.but.should.not"), + locator.toString())); break; case MORE_THEN_ZERO: ConditionalWait.waitFor(driver -> !driver.findElements(locator).isEmpty(), - String.format(LocalizationManager.getInstance().getValue("loc.no.elements.found.in.state"), - locator.toString(), - state.toString(), - Configuration.getInstance().getTimeoutConfiguration().getCondition())); + String.format(LocalizationManager.getInstance().getValue("loc.no.elements.found.by.locator"), + locator.toString())); break; default: throw new IllegalArgumentException("No such expected value:".concat(count.toString())); } - List webElements = getBrowser().getDriver().findElements(locator); + + List webElements = ElementFinder.getInstance().findElements(locator, getTimeoutConfig().getCondition(), state); int index = 1; for (WebElement webElement : webElements) { try { @@ -180,5 +184,9 @@ private Type convertElementClassToType(Class clazz){ private Browser getBrowser(){ return BrowserManager.getBrowser(); } + + private ITimeoutConfiguration getTimeoutConfig(){ + return Configuration.getInstance().getTimeoutConfiguration(); + } } diff --git a/src/main/resources/localization/en.json b/src/main/resources/localization/en.json index 85bc2df..99c4eb1 100644 --- a/src/main/resources/localization/en.json +++ b/src/main/resources/localization/en.json @@ -63,5 +63,6 @@ "loc.waitnotexists" : "Wait until element does not exist in DOM during %1$s seconds", "loc.no.elements.found.in.state" : "no elements with locator '%1$s' found in state '%2$s' during %3$s seconds", "loc.no.elements.found.by.locator" : "No elements were found by locator '%1$s'", - "loc.elements.were.found.but.not.in.state" : "Elements were found by locator '%1$s'. But %2$s" + "loc.elements.were.found.but.not.in.state" : "Elements were found by locator '%1$s' but not in desired state. %2$s", + "loc.elements.found.but.should.not": "No elements should be found by locator '%1$s'" } \ No newline at end of file diff --git a/src/main/resources/localization/ru.json b/src/main/resources/localization/ru.json index 2cedf91..20f07e9 100644 --- a/src/main/resources/localization/ru.json +++ b/src/main/resources/localization/ru.json @@ -63,5 +63,6 @@ "loc.waitnotexists" : "Ожидаем исчезновения элемента из DOM в течении %1$s", "loc.no.elements.found.in.state" : "не удалось найти элементов по локатору '%1$s' в состоянии '%2$s' на протяжении %3$s секунд", "loc.no.elements.found.by.locator" : "Не удалось найти элементов по локатору '%1$s'", - "loc.elements.were.found.but.not.in.state" : "Удалось найти элементы по локатору '%1$s'. Но %2$s" + "loc.elements.were.found.but.not.in.state" : "Удалось найти элементы по локатору '%1$s',но они не в желаемом состоянии. %2$s", + "loc.elements.found.but.should.not": "Не должно быть найдено элементов по локатору '%1$s'" } \ No newline at end of file diff --git a/src/test/java/aquality/selenium/utils/ElementActionRetrierTests.java b/src/test/java/aquality/selenium/utils/ElementActionRetrierTests.java index bf25f4f..1a79e3d 100644 --- a/src/test/java/aquality/selenium/utils/ElementActionRetrierTests.java +++ b/src/test/java/aquality/selenium/utils/ElementActionRetrierTests.java @@ -1,24 +1,31 @@ package aquality.selenium.utils; import aquality.selenium.configuration.Configuration; +import aquality.selenium.logger.Logger; +import org.apache.commons.lang3.time.StopWatch; import org.openqa.selenium.InvalidArgumentException; import org.openqa.selenium.InvalidElementStateException; import org.openqa.selenium.StaleElementReferenceException; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import utils.Timer; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Date; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; public class ElementActionRetrierTests { - private static final int attemptsCount = Configuration.getInstance().getRetryConfiguration().getNumber(); + private static final int retriesCount = Configuration.getInstance().getRetryConfiguration().getNumber(); private static final long pollingInterval = Configuration.getInstance().getRetryConfiguration().getPollingInterval(); + @DataProvider private Object[][] handledExceptions() { return new Object[][] { @@ -36,7 +43,8 @@ public void testRetrierShouldWorkOnceIfMethodSucceeded() { @Test(dataProvider = "handledExceptions") public void testRetrierShouldWaitPollingTimeBetweenMethodsCall(RuntimeException handledException) { - Date startTime = new Date(); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); AtomicBoolean isThrowException = new AtomicBoolean(true); ElementActionRetrier.doWithRetry(() -> { if (isThrowException.get()) { @@ -44,8 +52,11 @@ public void testRetrierShouldWaitPollingTimeBetweenMethodsCall(RuntimeException throw handledException; } }); - long duration = new Date().getTime() - startTime.getTime(); - assertTrue(duration >= pollingInterval && duration < 2 * pollingInterval); + stopWatch.stop(); + + long duration = stopWatch.getTime(TimeUnit.MILLISECONDS); + assertTrue(duration >= pollingInterval, "duration should be more than polling interval. actual is " + duration + " milliseconds"); + assertTrue(duration <= 2 * pollingInterval, "duration should be less than doubled polling interval. actual is " + duration + " milliseconds"); } @Test(expectedExceptions = InvalidArgumentException.class) @@ -57,16 +68,16 @@ public void testRetrierShouldThrowUnhandledException() { @Test(dataProvider = "handledExceptions") public void testRetrierShouldWorkCorrectTimes(RuntimeException handledException) { - Date startTime = new Date(); + AtomicInteger actualAttempts = new AtomicInteger(0); try { ElementActionRetrier.doWithRetry(() -> { + Logger.getInstance().info("current attempt is " + actualAttempts.incrementAndGet()); throw handledException; }); } catch (RuntimeException e) { assertTrue(handledException.getClass().isInstance(e)); } - long duration = new Date().getTime() - startTime.getTime(); - assertTrue(duration >= pollingInterval * attemptsCount && duration < pollingInterval * (attemptsCount + 1)); + assertEquals(actualAttempts.get(), retriesCount + 1, "actual attempts count is not match to expected"); } @Test(expectedExceptions = IllegalAccessException.class) diff --git a/src/test/java/automationpractice/forms/ProductListForm.java b/src/test/java/automationpractice/forms/ProductListForm.java index 8d3729c..1b8bc68 100644 --- a/src/test/java/automationpractice/forms/ProductListForm.java +++ b/src/test/java/automationpractice/forms/ProductListForm.java @@ -28,7 +28,7 @@ public List getProductContainerLabels(){ return getElementFactory().findElements(By.xpath(XPATH_PRODUCT_CONTAINER), ElementType.LABEL, ElementState.DISPLAYED, ElementsCount.MORE_THEN_ZERO); } - public ILabel getLblFirstProduct(){ + private ILabel getLblFirstProduct(){ return getElementFactory().getLabel(By.xpath(XPATH_PRODUCT.concat("[1]")), "First product"); } @@ -36,8 +36,15 @@ public ILabel getLblLastProduct(){ return getElementFactory().getLabel(By.id("homefeatured"), "home featured").findChildElement(By.xpath("//li".concat("[last()]")), ILabel.class); } - public IButton getBtnLastProductMore(){ - return getLblLastProduct().findChildElement(By.xpath(".//a[contains(@class, 'lnk_view')]"), ElementType.BUTTON); + public IButton getBtnLastProductMoreFocused() { + getLblFirstProduct().getMouseActions().moveMouseToElement(); + getLblLastProduct().getMouseActions().moveMouseToElement(); + IButton btnLastProductMore = getLblLastProduct().findChildElement(By.xpath(".//a[contains(@class, 'lnk_view')]"), ElementType.BUTTON); + if(!btnLastProductMore.state().isDisplayed()) { + getLblLastProduct().getMouseActions().moveMouseFromElement(); + getLblLastProduct().getMouseActions().moveMouseToElement(); + } + return btnLastProductMore; } public void addToCardRandomProduct(){ diff --git a/src/test/java/tests/integration/ActionTests.java b/src/test/java/tests/integration/ActionTests.java index d825db3..28a9ece 100644 --- a/src/test/java/tests/integration/ActionTests.java +++ b/src/test/java/tests/integration/ActionTests.java @@ -43,18 +43,14 @@ public void testScrollIntoView() { @Test public void testMoveMouseToElement() { - ProductListForm productListForm = new ProductListForm(); - productListForm.getLblFirstProduct().getMouseActions().moveMouseToElement(); - productListForm.getLblLastProduct().getMouseActions().moveMouseToElement(); - IButton button = productListForm.getBtnLastProductMore(); + IButton button = new ProductListForm().getBtnLastProductMoreFocused(); Assert.assertTrue(button.getText().contains("More"), "element is not focused after moveMouseToElement()"); } @Test public void testMoveMouseFromElement() { ProductListForm productListForm = new ProductListForm(); - productListForm.getLblLastProduct().getMouseActions().moveMouseToElement(); - IButton button = productListForm.getBtnLastProductMore(); + IButton button = productListForm.getBtnLastProductMoreFocused(); Assert.assertTrue(button.getText().contains("More"), "element is not focused after moveMouseToElement()"); productListForm.getLblLastProduct().getMouseActions().moveMouseFromElement(); Assert.assertFalse(button.state().isDisplayed(), "element is still focused after moveMouseFromElement()"); @@ -62,20 +58,14 @@ public void testMoveMouseFromElement() { @Test public void testGetElementText() { - ProductListForm productListForm = new ProductListForm(); - productListForm.getLblFirstProduct().getMouseActions().moveMouseToElement(); - productListForm.getLblLastProduct().getMouseActions().moveMouseToElement(); - IButton button = productListForm.getBtnLastProductMore(); + IButton button = new ProductListForm().getBtnLastProductMoreFocused(); Assert.assertEquals(button.getText().trim(), button.getJsActions().getElementText().trim(), "element text got via JsActions is not match to expected"); } @Test public void testSetFocus() { - ProductListForm productListForm = new ProductListForm(); - productListForm.getLblFirstProduct().getMouseActions().moveMouseToElement(); - productListForm.getLblLastProduct().getMouseActions().moveMouseToElement(); - productListForm.getBtnLastProductMore().getJsActions().clickAndWait(); + new ProductListForm().getBtnLastProductMoreFocused().getJsActions().clickAndWait(); ITextBox txbQuantity = new ProductForm().getTxbQuantity(); txbQuantity.getJsActions().setFocus(); @@ -87,10 +77,7 @@ public void testSetFocus() { @Test public void testSetValue() { - ProductListForm productListForm = new ProductListForm(); - productListForm.getLblFirstProduct().getMouseActions().moveMouseToElement(); - productListForm.getLblLastProduct().getMouseActions().moveMouseToElement(); - productListForm.getBtnLastProductMore().getJsActions().clickAndWait(); + new ProductListForm().getBtnLastProductMoreFocused().getJsActions().clickAndWait(); ProductForm productForm = new ProductForm(); ITextBox txbQuantity = productForm.getTxbQuantity(); diff --git a/src/test/java/tests/integration/BrowserTests.java b/src/test/java/tests/integration/BrowserTests.java index e21609b..fe385a0 100644 --- a/src/test/java/tests/integration/BrowserTests.java +++ b/src/test/java/tests/integration/BrowserTests.java @@ -16,8 +16,6 @@ import java.io.IOException; import java.io.UncheckedIOException; -import java.util.ArrayList; -import java.util.List; import static automationpractice.Constants.URL_AUTOMATIONPRACTICE; import static utils.FileUtil.getResourceFileByName; @@ -204,15 +202,7 @@ public void testShouldBePossibleToSetImplicitWait(){ @Test public void testShouldBePossibleToGetDownloadDir(){ - List listOfDownloadDirs = new ArrayList<>(); - listOfDownloadDirs.add("//home//selenium//downloads"); - listOfDownloadDirs.add("/Users/username/Downloads"); - listOfDownloadDirs.add("target//downloads"); - listOfDownloadDirs.add("/home/circleci/repo/target/downloads"); - - boolean isDirFound = listOfDownloadDirs.stream() - .anyMatch(dir -> getBrowser().getDownloadDirectory().toLowerCase().contains(dir.toLowerCase())); - Assert.assertTrue(isDirFound, "Browser download directory is not correct " + getBrowser().getDownloadDirectory()); + Assert.assertFalse(getBrowser().getDownloadDirectory().isEmpty(), "Browser download directory should not be empty " + getBrowser().getDownloadDirectory()); } private JsonFile getSettings() { diff --git a/src/test/java/tests/integration/ElementStateTests.java b/src/test/java/tests/integration/ElementStateTests.java index fe3f744..8952120 100644 --- a/src/test/java/tests/integration/ElementStateTests.java +++ b/src/test/java/tests/integration/ElementStateTests.java @@ -16,7 +16,7 @@ public class ElementStateTests extends BaseTest { - private final double operationTime = 2; + private final double operationTime = 5; private final long customWaitTime = 2L; private final ElementFactory elementFactory = new ElementFactory(); private final ILabel lblNotExists = elementFactory.getLabel(By.xpath("//div[@class='not exist element']"), "not exist element"); diff --git a/src/test/java/tests/integration/HiddenElementsTests.java b/src/test/java/tests/integration/HiddenElementsTests.java index 8dda321..00fe5a3 100644 --- a/src/test/java/tests/integration/HiddenElementsTests.java +++ b/src/test/java/tests/integration/HiddenElementsTests.java @@ -35,9 +35,8 @@ public void testHiddenElementsExist() { } @Test - public void testNotHiddenElementsNotDisplayed() { - List listElements = new SliderForm().getListElements(ElementState.DISPLAYED, ElementsCount.MORE_THEN_ZERO); - Assert.assertFalse(listElements.isEmpty()); - Assert.assertFalse(listElements.stream().anyMatch(label -> label.state().waitForDisplayed(1L))); + public void testFindDisplayedElementsShouldReturnNoElementsIfTheyAreNotDisplayed() { + List listElements = new SliderForm().getListElements(ElementState.DISPLAYED, ElementsCount.ZERO); + Assert.assertTrue(listElements.isEmpty()); } } diff --git a/src/test/java/tests/usecases/BrowserFactoryTests.java b/src/test/java/tests/usecases/BrowserFactoryTests.java index 849dd47..3735f42 100644 --- a/src/test/java/tests/usecases/BrowserFactoryTests.java +++ b/src/test/java/tests/usecases/BrowserFactoryTests.java @@ -37,7 +37,8 @@ public class BrowserFactoryTests { private final JsonFile jsonProfile; public BrowserFactoryTests() { - this.jsonProfile = new JsonFile("settings.json"); + String settingsProfile = System.getProperty("profile") == null ? "settings.json" : "settings." + System.getProperty("profile") + ".json"; + this.jsonProfile = new JsonFile(settingsProfile); } @Test diff --git a/src/test/java/tests/usecases/QuickStartExample.java b/src/test/java/tests/usecases/QuickStartExample.java new file mode 100644 index 0000000..55b8319 --- /dev/null +++ b/src/test/java/tests/usecases/QuickStartExample.java @@ -0,0 +1,28 @@ +package tests.usecases; + +import aquality.selenium.browser.Browser; +import aquality.selenium.browser.BrowserManager; +import aquality.selenium.elements.ElementFactory; +import aquality.selenium.elements.interfaces.ITextBox; +import org.openqa.selenium.By; +import org.testng.annotations.Test; + +public class QuickStartExample { + + @Test + public void test(){ + Browser browser = BrowserManager.getBrowser(); + + browser.maximize(); + browser.goTo("https://wikipedia.org"); + browser.waitForPageToLoad(); + + ElementFactory elementFactory = new ElementFactory(); + ITextBox txbSearch = elementFactory.getTextBox(By.id("searchInput"), "Search"); + txbSearch.type("quality assurance"); + txbSearch.submit(); + browser.waitForPageToLoad(); + + browser.quit(); + } +} diff --git a/src/test/resources/TestSuite.xml b/src/test/resources/TestSuite.xml index 1704580..213e913 100644 --- a/src/test/resources/TestSuite.xml +++ b/src/test/resources/TestSuite.xml @@ -10,7 +10,6 @@ - @@ -23,11 +22,12 @@ - + + \ No newline at end of file diff --git a/src/test/resources/settings.local.json b/src/test/resources/settings.local.json index ed81881..857f583 100644 --- a/src/test/resources/settings.local.json +++ b/src/test/resources/settings.local.json @@ -22,6 +22,7 @@ }, "firefox": { "webDriverVersion": "latest", + "systemArchitecture": "X32", "capabilities": { "enableVNC": true }, @@ -56,7 +57,7 @@ "timeoutImplicit" : 0, "timeoutCondition" : 30, "timeoutScript" : 10, - "timeoutPageLoad" : 15, + "timeoutPageLoad" : 30, "timeoutPollingInterval": 300, "timeoutCommand": 120 },